mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-18 10:54:09 +00:00
Compare commits
73 Commits
ExtHashMap
...
missing_ar
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
140ec40b6c | ||
|
|
a912652b7d | ||
|
|
3af9ab64ed | ||
|
|
a6dd6a4656 | ||
|
|
1e752b0a01 | ||
|
|
11f7d6da39 | ||
|
|
e2fc9ba92e | ||
|
|
c1866a7b7e | ||
|
|
03e905d994 | ||
|
|
383f68f806 | ||
|
|
41c2ae12f3 | ||
|
|
9982bab93e | ||
|
|
be513656b0 | ||
|
|
bdbb659765 | ||
|
|
2a1354b3cc | ||
|
|
a54872f5f6 | ||
|
|
2b0b1e013f | ||
|
|
1f000feb80 | ||
|
|
d5060e9e66 | ||
|
|
38ca310fb7 | ||
|
|
3dd12f85f0 | ||
|
|
0f8618f842 | ||
|
|
acdef6e04b | ||
|
|
7b80cd24a9 | ||
|
|
21846ebdf8 | ||
|
|
9ea4946560 | ||
|
|
3b205505ef | ||
|
|
6afa8208ec | ||
|
|
65a5d0cb9d | ||
|
|
fc3c82b1c7 | ||
|
|
8fc94c5c90 | ||
|
|
96b81f3cc1 | ||
|
|
44ff70020d | ||
|
|
ae1ab94992 | ||
|
|
5e40f4af52 | ||
|
|
2594a8edad | ||
|
|
b24e232a7a | ||
|
|
9ad3974314 | ||
|
|
b31bf4e645 | ||
|
|
c8d245a08f | ||
|
|
4eccb5b479 | ||
|
|
0a43c138ac | ||
|
|
1138062a70 | ||
|
|
ebf455a137 | ||
|
|
87cc330489 | ||
|
|
47a1355fc4 | ||
|
|
79254d039c | ||
|
|
c28b052576 | ||
|
|
a541b8e75e | ||
|
|
a9a069a0ef | ||
|
|
8753239226 | ||
|
|
f4ee72b18c | ||
|
|
8535a2268b | ||
|
|
d8e7ca2355 | ||
|
|
8e0870beec | ||
|
|
3790f8c78e | ||
|
|
3bf95e9b58 | ||
|
|
bc21b57396 | ||
|
|
6395d69140 | ||
|
|
4ba72aeef7 | ||
|
|
e984473886 | ||
|
|
88f6439955 | ||
|
|
fc8f290347 | ||
|
|
423b31755d | ||
|
|
d1ec806834 | ||
|
|
b93231f97e | ||
|
|
f40d72ea47 | ||
|
|
10fdfc54cb | ||
|
|
943a9c6a43 | ||
|
|
a8a6f71abb | ||
|
|
9ad4414642 | ||
|
|
efe2ab4c04 | ||
|
|
831026bcf4 |
24
.github/workflows/awaiting-mathlib.yml
vendored
24
.github/workflows/awaiting-mathlib.yml
vendored
@@ -10,11 +10,29 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check awaiting-mathlib label
|
||||
id: check-awaiting-mathlib-label
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { labels } = context.payload.pull_request;
|
||||
if (labels.some(label => label.name == "awaiting-mathlib") && !labels.some(label => label.name == "builds-mathlib")) {
|
||||
core.setFailed('PR is marked "awaiting-mathlib" but "builds-mathlib" label has not been applied yet by the bot');
|
||||
const { labels, number: prNumber } = context.payload.pull_request;
|
||||
const hasAwaiting = labels.some(label => label.name == "awaiting-mathlib");
|
||||
const hasBreaks = labels.some(label => label.name == "breaks-mathlib");
|
||||
const hasBuilds = labels.some(label => label.name == "builds-mathlib");
|
||||
|
||||
if (hasAwaiting && hasBreaks) {
|
||||
core.setFailed('PR has both "awaiting-mathlib" and "breaks-mathlib" labels.');
|
||||
} else if (hasAwaiting && !hasBreaks && !hasBuilds) {
|
||||
core.info('PR is marked "awaiting-mathlib" but neither "breaks-mathlib" nor "builds-mathlib" labels are present.');
|
||||
core.setOutput('awaiting', 'true');
|
||||
}
|
||||
|
||||
- name: Wait for mathlib compatibility
|
||||
if: github.event_name == 'pull_request' && steps.check-awaiting-mathlib-label.outputs.awaiting == 'true'
|
||||
run: |
|
||||
echo "::notice title=Awaiting mathlib::PR is marked 'awaiting-mathlib' but neither 'breaks-mathlib' nor 'builds-mathlib' labels are present."
|
||||
echo "This check will remain in progress until the PR is updated with appropriate mathlib compatibility labels."
|
||||
# Keep the job running indefinitely to show "in progress" status
|
||||
while true; do
|
||||
sleep 3600 # Sleep for 1 hour at a time
|
||||
done
|
||||
|
||||
38
.github/workflows/update-stage0.yml
vendored
38
.github/workflows/update-stage0.yml
vendored
@@ -40,34 +40,24 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name "Lean stage0 autoupdater"
|
||||
git config --global user.email "<>"
|
||||
# Would be nice, but does not work yet:
|
||||
# https://github.com/DeterminateSystems/magic-nix-cache/issues/39
|
||||
# This action does not run that often and building runs in a few minutes, so ok for now
|
||||
#- if: env.should_update_stage0 == 'yes'
|
||||
# uses: DeterminateSystems/magic-nix-cache-action@v2
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
name: Restore Build Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: nix-store-cache
|
||||
key: Nix Linux-nix-store-cache-${{ github.sha }}
|
||||
# fall back to (latest) previous cache
|
||||
restore-keys: |
|
||||
Nix Linux-nix-store-cache
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
name: Further Set Up Nix Cache
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: |
|
||||
# Nix seems to mutate the cache, so make a copy
|
||||
cp -r nix-store-cache nix-store-cache-copy || true
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
with:
|
||||
extra-conf: |
|
||||
substituters = file://${{ github.workspace }}/nix-store-cache-copy?priority=10&trusted=true https://cache.nixos.org
|
||||
- name: Open Nix shell once
|
||||
if: env.should_update_stage0 == 'yes'
|
||||
run: true
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- name: Set up NPROC
|
||||
if: env.should_update_stage0 == 'yes'
|
||||
run: |
|
||||
echo "NPROC=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)" >> $GITHUB_ENV
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: nix run .#update-stage0-commit
|
||||
run: cmake --preset release
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
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
|
||||
- if: env.should_update_stage0 == 'yes' && github.event_name == 'push'
|
||||
|
||||
9
doc/std/README.md
Normal file
9
doc/std/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# The Lean standard library
|
||||
|
||||
This directory contains development information about the Lean standard library. The user-facing documentation of the standard library
|
||||
is part of the [Lean Language Reference](https://lean-lang.org/doc/reference/latest/).
|
||||
|
||||
Here you will find
|
||||
* the [standard library vision document](./vision.md), including the call for contributions,
|
||||
* the [standard library style guide](./style.md), and
|
||||
* the [standard library naming conventions](./naming.md).
|
||||
3
doc/std/naming-tree.svg
Normal file
3
doc/std/naming-tree.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 68 KiB |
260
doc/std/naming.md
Normal file
260
doc/std/naming.md
Normal file
@@ -0,0 +1,260 @@
|
||||
# Standard library naming conventions
|
||||
|
||||
The easiest way to access a result in the standard library is to correctly guess the name of the declaration (possibly with the help of identifier autocompletion). This is faster and has lower friction than more sophisticated search tools, so easily guessable names (which are still reasonably short) make Lean users more productive.
|
||||
|
||||
The guide that follows contains very few hard rules, many heuristics and a selection of examples. It cannot and does not present a deterministic algorithm for choosing good names in all situations. It is intended as a living document that gets clarified and expanded as situations arise during code reviews for the standard library. If applying one of the suggestions in this guide leads to nonsensical results in a certain situation, it is
|
||||
probably safe to ignore the suggestion (or even better, suggest a way to improve the suggestion).
|
||||
|
||||
## Prelude
|
||||
|
||||
Identifiers use a mix of `UpperCamelCase`, `lowerCamelCase` and `snake_case`, used for types, data, and theorems, respectively.
|
||||
|
||||
Structure fields should be named such that the projections have the correct names.
|
||||
|
||||
## Naming convention for types
|
||||
|
||||
When defining a type, i.e., a (possibly 0-ary) function whose codomain is Sort u for some u, it should be named in UpperCamelCase. Examples include `List`, and `List.IsPrefix`.
|
||||
|
||||
When defining a predicate, prefix the name by `Is`, like in `List.IsPrefix`. The `Is` prefix may be omitted if
|
||||
* the resulting name would be ungrammatical, or
|
||||
* the predicate depends on additional data in a way where the `Is` prefix would be confusing (like `List.Pairwise`), or
|
||||
* the name is an adjective (like `Std.Time.Month.Ordinal.Valid`)
|
||||
|
||||
## Namespaces and generalized projection notation
|
||||
|
||||
Almost always, definitions and theorems relating to a type should be placed in a namespace with the same name as the type. For example, operations and theorems about lists should be placed in the `List` namespace, and operations and theorems about `Std.Time.PlainDate` should be placed in the `Std.Time.PlainDate` namespace.
|
||||
|
||||
Declarations in the root namespace will be relatively rare. The most common type of declaration in the root namespace are declarations about data and properties exported by notation type classes, as long as they are not about a specific type implementing that type class. For example, we have
|
||||
|
||||
```lean
|
||||
theorem beq_iff_eq [BEq α] [LawfulBEq α] {a b : α} : a == b ↔ a = b := sorry
|
||||
```
|
||||
|
||||
in the root namespace, but
|
||||
|
||||
```lean
|
||||
theorem List.cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
```
|
||||
|
||||
belongs in the `List` namespace.
|
||||
|
||||
Subtleties arise when multiple namespaces are in play. Generally, place your theorem in the most specific namespace that appears in one of the hypotheses of the theorem. The following names are both correct according to this convention:
|
||||
|
||||
```lean
|
||||
theorem List.Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse := sorry
|
||||
theorem List.reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ := sorry
|
||||
```
|
||||
|
||||
Notice that the second theorem does not have a hypothesis of type `List.Sublist l` for some `l`, so the name `List.Sublist.reverse_iff` would be incorrect.
|
||||
|
||||
The advantage of placing results in a namespace like `List.Sublist` is that it enables generalized projection notation, i.e., given `h : l₁ <+ l₂`,
|
||||
one can write `h.reverse` to obtain a proof of `l₁.reverse <+ l₂.reverse`. Thinking about which dot notations are convenient can act as a guideline
|
||||
for deciding where to place a theorem, and is, on occasion, a good reason to duplicate a theorem into multiple namespaces.
|
||||
|
||||
### The `Std` namespace
|
||||
|
||||
New types that are added will usually be placed in the `Std` namespace and in the `Std/` source directory, unless there are good reasons to place
|
||||
them elsewhere.
|
||||
|
||||
Inside the `Std` namespace, all internal declarations should be `private` or else have a name component that clearly marks them as internal, preferably
|
||||
`Internal`.
|
||||
|
||||
|
||||
## Naming convention for data
|
||||
|
||||
When defining data, i.e., a (possibly 0-ary) function whose codomain is not Sort u, but has type Type u for some u, it should be named in lowerCamelCase. Examples include `List.append` and `List.isPrefixOf`.
|
||||
If your data is morally fully specified by its type, then use the naming procedure for theorems described below and convert the result to lower camel case.
|
||||
|
||||
If your function returns an `Option`, consider adding `?` as a suffix. If your function may panic, consider adding `!` as a suffix. In many cases, there will be multiple variants of a function; one returning an option, one that may panic and possibly one that takes a proof argument.
|
||||
|
||||
## Naming algorithm for theorems and some definitions
|
||||
|
||||
There is, in principle, a general algorithm for naming a theorem. The problem with this algorithm is that it produces very long and unwieldy names which need to be shortened. So choosing a name for a declaration can be thought of as consisting of a mechanical part and a creative part.
|
||||
|
||||
Usually the first part is to decide which namespace the result should live in, according to the guidelines described above.
|
||||
|
||||
Next, consider the type of your declaration as a tree. Inner nodes of this tree are function types or function applications. Leaves of the tree are 0-ary functions or bound variables.
|
||||
|
||||
As an example, consider the following result from the standard library:
|
||||
|
||||
```lean
|
||||
example {α : Type u} {β : Type v} [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α]
|
||||
[Inhabited β] {m : Std.HashMap α β} {a : α} {h' : a ∈ m} : m[a]? = some (m[a]'h') :=
|
||||
sorry
|
||||
```
|
||||
|
||||
The correct namespace is clearly `Std.HashMap`. The corresponding tree looks like this:
|
||||
|
||||

|
||||
|
||||
The preferred spelling of a notation can be looked up by hovering over the notation.
|
||||
|
||||
Now traverse the tree and build a name according to the following rules:
|
||||
|
||||
* When encountering a function type, first turn the result type into a name, then all of the argument types from left to right, and join the names using `_of_`.
|
||||
* When encountering a function that is neither an infix notation nor a structure projection, first put the function name and then the arguments, joined by an underscore.
|
||||
* When encountering an infix notation, join the arguments using the name of the notation, separated by underscores.
|
||||
* When encountering a structure projection, proceed as for normal functions, but put the name of the projection last.
|
||||
* When encountering a name, put it in lower camel case.
|
||||
* Skip bound variables and proofs.
|
||||
* Type class arguments are also generally skipped.
|
||||
|
||||
When encountering namespaces names, concatenate them in lower camel case.
|
||||
|
||||
Applying this algorithm to our example yields the name `Std.HashMap.getElem?_eq_optionSome_getElem_of_mem`.
|
||||
|
||||
From there, the name should be shortened, using the following heuristics:
|
||||
|
||||
* The namespace of functions can be omitted if it is clear from context or if the namespace is the current one. This is almost always the case.
|
||||
* For infix operators, it is possible to leave out the RHS or the name of the notation and the RHS if they are clear from context.
|
||||
* Hypotheses can be left out if it is clear that they are required or if they appear in the conclusion.
|
||||
|
||||
Based on this, here are some possible names for our example:
|
||||
|
||||
1. `Std.HashMap.getElem?_eq`
|
||||
2. `Std.HashMap.getElem?_eq_of_mem`
|
||||
3. `Std.HashMap.getElem?_eq_some`
|
||||
4. `Std.HashMap.getElem?_eq_some_of_mem`
|
||||
5. `Std.HashMap.getElem?_eq_some_getElem`
|
||||
6. `Std.Hashmap.getElem?_eq_some_getElem_of_mem`
|
||||
|
||||
Choosing a good name among these then requires considering the context of the lemma. In this case it turns out that the first four options are underspecified as there is also a lemma relating `m[a]?` and `m[a]!` which could have the same name. This leaves the last two options, the first of which is shorter, and this is how the lemma is called in the Lean standard library.
|
||||
|
||||
Here are some additional examples:
|
||||
|
||||
```lean
|
||||
example {x y : List α} (h : x <+: y) (hx : x ≠ []) :
|
||||
x.head hx = y.head (h.ne_nil hx) := sorry
|
||||
```
|
||||
|
||||
Since we have an `IsPrefix` parameter, this should live in the `List.IsPrefix` namespace, and the algorithm suggests `List.IsPrefix.head_eq_head_of_ne_nil`, which is shortened to `List.IsPrefix.head`. Note here the difference between the namespace name (`IsPrefix`) and the recommended spelling of the corresponding notation (`prefix`).
|
||||
|
||||
```lean
|
||||
example : l₁ <+: l₂ → reverse l₁ <:+ reverse l₂ := sorry
|
||||
```
|
||||
|
||||
Again, this result should be in the `List.IsPrefix` namespace; the algorithm suggests `List.IsPrefix.reverse_prefix_reverse`, which becomes `List.IsPrefix.reverse`.
|
||||
|
||||
The following examples show how the traversal order often matters.
|
||||
|
||||
```lean
|
||||
theorem Nat.mul_zero (n : Nat) : n * 0 = 0 := sorry
|
||||
theorem Nat.zero_mul (n : Nat) : 0 * n = 0 := sorry
|
||||
```
|
||||
|
||||
Here we see that one name may be a prefix of another name:
|
||||
|
||||
```lean
|
||||
theorem Int.mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 := sorry
|
||||
theorem Int.mul_ne_zero_iff {a b : Int} : a * b ≠ 0 ↔ a ≠ 0 ∧ b ≠ 0 := sorry
|
||||
```
|
||||
|
||||
It is usually a good idea to include the `iff` in a theorem name even if the name would still be unique without the name. For example,
|
||||
|
||||
```lean
|
||||
theorem List.head?_eq_none_iff : l.head? = none ↔ l = [] := sorry
|
||||
```
|
||||
|
||||
is a good name: if the lemma was simply called `List.head?_eq_none`, users might try to `apply` it when the goal is `l.head? = none`, leading
|
||||
to confusion.
|
||||
|
||||
The more common you expect (or want) a theorem to be, the shorter you should try to make the name. For example, we have both
|
||||
|
||||
```lean
|
||||
theorem Std.HashMap.getElem?_eq_none_of_contains_eq_false {a : α} : m.contains a = false → m[a]? = none := sorry
|
||||
theorem Std.HashMap.getElem?_eq_none {a : α} : ¬a ∈ m → m[a]? = none := sorry
|
||||
```
|
||||
|
||||
As users of the hash map are encouraged to use ∈ rather than contains, the second lemma gets the shorter name.
|
||||
|
||||
## Special cases
|
||||
|
||||
There are certain special “keywords” that may appear in identifiers.
|
||||
|
||||
| Keyword | Meaning | Example |
|
||||
| :---- | :---- | :---- |
|
||||
| `def` | Unfold a definition. Avoid this for public APIs. | `Nat.max_def` |
|
||||
| `refl` | Theorems of the form `a R a`, where R is a reflexive relation and `a` is an explicit parameter | `Nat.le_refl` |
|
||||
| `rfl` | Like `refl`, but with `a` implicit | `Nat.le_rfl` |
|
||||
| `irrefl` | Theorems of the form `¬a R a`, where R is an irreflexive relation | `Nat.lt_irrefl` |
|
||||
| `symm` | Theorems of the form `a R b → b R a`, where R is a symmetric relation (compare `comm` below) | `Eq.symm` |
|
||||
| `trans` | Theorems of the form `a R b → b R c → a R c`, where R is a transitive relation (R may carry data) | `Eq.trans` |
|
||||
| `antisymmm` | Theorems of the form `a R b → b R a → a = b`, where R is an antisymmetric relation | `Nat.le_antisymm` |
|
||||
| `congr` | Theorems of the form `a R b → f a S f b`, where R and S are usually equivalence relations | `Std.HashMap.mem_congr` |
|
||||
| `comm` | Theorems of the form `f a b = f b a` (compare `symm` above) | `Eq.comm`, `Nat.add_comm` |
|
||||
| `assoc` | Theorems of the form `g (f a b) c = f a (g b c)` (note the order! In most cases, we have f = g) | `Nat.add_sub_assoc` |
|
||||
| `distrib` | Theorems of the form `f (g a b) = g (f a) (f b)` | `Nat.add_left_distrib` |
|
||||
| `self` | May be used if a variable appears multiple times in the conclusion | `List.mem_cons_self` |
|
||||
| `inj` | Theorems of the form `f a = f b ↔ a = b`. | `Int.neg_inj`, `Nat.add_left_inj` |
|
||||
| `cancel` | Theorems which have one of the forms `f a = f b → a = b` or `g (f a) = a`, where `f` and `g` usually involve a binary operator | `Nat.add_sub_cancel` |
|
||||
| `cancel_iff` | Same as `inj`, but with different conventions for left and right (see below) | `Nat.add_right_cancel_iff` |
|
||||
| `ext` | Theorems of the form `f a = f b → a = b`, where `f` usually involves some kind of projection | `List.ext_getElem`
|
||||
| `mono` | Theorems of the form `a R b → f a R f b`, where `R` is a transitive relation | `List.countP_mono_left`
|
||||
|
||||
### Left and right
|
||||
|
||||
The keywords left and right are useful to disambiguate symmetric variants of theorems.
|
||||
|
||||
```lean
|
||||
theorem imp_congr_left (h : a ↔ b) : (a → c) ↔ (b → c) := sorry
|
||||
theorem imp_congr_right (h : a → (b ↔ c)) : (a → b) ↔ (a → c) := sorry
|
||||
```
|
||||
|
||||
It is not always obvious which version of a theorem should be “left” and which should be “right”.
|
||||
Heuristically, the theorem should name the side which is “more variable”, but there are exceptions. For some of the special keywords discussed in this section, there are conventions which should be followed, as laid out in the following examples:
|
||||
|
||||
```lean
|
||||
theorem Nat.left_distrib (n m k : Nat) : n * (m + k) = n * m + n * k := sorry
|
||||
theorem Nat.right_distrib (n m k : Nat) : (n + m) * k = n * k + m * k := sorry
|
||||
theorem Nat.add_left_cancel {n m k : Nat} : n + m = n + k → m = k := sorry
|
||||
theorem Nat.add_right_cancel {n m k : Nat} : n + m = k + m → n = k := sorry
|
||||
theorem Nat.add_left_cancel_iff {m k n : Nat} : n + m = n + k ↔ m = k := sorry
|
||||
theorem Nat.add_right_cancel_iff {m k n : Nat} : m + n = k + n ↔ m = k := sorry
|
||||
theorem Nat.add_left_inj {m k n : Nat} : m + n = k + n ↔ m = k := sorry
|
||||
theorem Nat.add_right_inj {m k n : Nat} : n + m = n + k ↔ m = k := sorry
|
||||
```
|
||||
|
||||
Note in particular that the convention is opposite for `cancel_iff` and `inj`.
|
||||
|
||||
```lean
|
||||
theorem Nat.add_sub_self_left (a b : Nat) : (a + b) - a = b := sorry
|
||||
theorem Nat.add_sub_self_right (a b : Nat) : (a + b) - b = a := sorry
|
||||
theorem Nat.add_sub_cancel (n m : Nat) : (n + m) - m = n := sorry
|
||||
```
|
||||
|
||||
## Primed names
|
||||
|
||||
Avoid disambiguating variants of a concept by appending the `'` character (e.g., introducing both `BitVec.sshiftRight` and `BitVec.sshiftRight'`), as it is impossible to tell the difference without looking at the type signature, the documentation or even the code, and even if you know what the two variants are there is no way to tell which is which. Prefer descriptive pairs `BitVec.sshiftRightNat`/`BitVec.sshiftRight`.
|
||||
|
||||
## Acronyms
|
||||
|
||||
For acronyms which are three letters or shorter, all letters should use the same case as dictated by the convention. For example, `IO` is a correct name for a type and the name `IO.Ref` may become `IORef` when used as part of a definition name and `ioRef` when used as part of a theorem name.
|
||||
|
||||
For acronyms which are at least four letters long, switch to lower case starting from the second letter. For example, `Json` is a correct name for a type, as is `JsonRPC`.
|
||||
|
||||
If an acronym is typically spelled using mixed case, this mixed spelling may be used in identifiers (for example `Std.Net.IPv4Addr`).
|
||||
|
||||
## Simp sets
|
||||
|
||||
Simp sets centered around a conversion function should be called `source_to_target`. For example, a simp set for the `BitVec.toNat` function, which goes from `BitVec` to
|
||||
`Nat`, should be called `bitvec_to_nat`.
|
||||
|
||||
## Variable names
|
||||
|
||||
We make the following recommendations for variable names, but without insisting on them:
|
||||
* Simple hypotheses should be named `h`, `h'`, or using a numerical sequence `h₁`, `h₂`, etc.
|
||||
* Another common name for a simple hypothesis is `w` (for "witness").
|
||||
* `List`s should be named `l`, `l'`, `l₁`, etc, or `as`, `bs`, etc.
|
||||
(Use of `as`, `bs` is encouraged when the lists are of different types, e.g. `as : List α` and `bs : List β`.)
|
||||
`xs`, `ys`, `zs` are allowed, but it is better if these are reserved for `Array` and `Vector`.
|
||||
A list of lists may be named `L`.
|
||||
* `Array`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the arrays are of different types, e.g. `as : Array α` and `bs : Array β`.
|
||||
An array of arrays may be named `xss`.
|
||||
* `Vector`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the vectors are of different types, e.g. `as : Vector α n` and `bs : Vector β n`.
|
||||
A vector of vectors may be named `xss`.
|
||||
* A common exception for `List` / `Array` / `Vector` is to use `acc` for an accumulator in a recursive function.
|
||||
* `i`, `j`, `k` are preferred for numerical indices.
|
||||
Descriptive names such as `start`, `stop`, `lo`, and `hi` are encouraged when they increase readability.
|
||||
* `n`, `m` are preferred for sizes, e.g. in `Vector α n` or `xs.size = n`.
|
||||
* `w` is preferred for the width of a `BitVec`.
|
||||
522
doc/std/style.md
Normal file
522
doc/std/style.md
Normal file
@@ -0,0 +1,522 @@
|
||||
# Standard library style
|
||||
|
||||
Please take some time to familiarize yourself with the stylistic conventions of
|
||||
the project and the specific part of the library you are planning to contribute
|
||||
to. While the Lean compiler may not enforce strict formatting rules,
|
||||
consistently formatted code is much easier for others to read and maintain.
|
||||
Attention to formatting is more than a cosmetic concern—it reflects the same
|
||||
level of precision and care required to meet the deeper standards of the Lean 4
|
||||
standard library.
|
||||
|
||||
Below we will give specific formatting prescriptions for various language constructs. Note that this style guide only applies to the Lean standard library, even though some examples in the guide are taken from other parts of the Lean code base.
|
||||
|
||||
## Basic whitespace rules
|
||||
|
||||
Syntactic elements (like `:`, `:=`, `|`, `::`) are surrounded by single spaces, with the exception of `,` and `;`, which are followed by a space but not preceded by one. Delimiters (like `()`, `{}`) do not have spaces on the inside, with the exceptions of subtype notation and structure instance notation.
|
||||
|
||||
Examples of correctly formatted function parameters:
|
||||
|
||||
* `{α : Type u}`
|
||||
* `[BEq α]`
|
||||
* `(cmp : α → α → Ordering)`
|
||||
* `(hab : a = b)`
|
||||
* `{d : { l : List ((n : Nat) × Vector Nat n) // l.length % 2 = 0 }}`
|
||||
|
||||
Examples of correctly formatted terms:
|
||||
|
||||
* `1 :: [2, 3]`
|
||||
* `letI : Ord α := ⟨cmp⟩; True`
|
||||
* `(⟨2, 3⟩ : Nat × Nat)`
|
||||
* `((2, 3) : Nat × Nat)`
|
||||
* `{ x with fst := f (4 + f 0), snd := 4, .. }`
|
||||
* `match 1 with | 0 => 0 | _ => 0`
|
||||
* `fun ⟨a, b⟩ _ _ => by cases hab <;> apply id; rw [hbc]`
|
||||
|
||||
Configure your editor to remove trailing whitespace. If you have set up Visual Studio Code for Lean development in the recommended way then the correct setting is applied automatically.
|
||||
|
||||
## Splitting terms across multiple lines
|
||||
|
||||
When splitting a term across multiple lines, increase indentation by two spaces starting from the second line. When splitting a function application, try to split at argument boundaries. If an argument itself needs to be split, increase indentation further as appropriate.
|
||||
|
||||
When splitting at an infix operator, the operator goes at the end of the first line, not at the beginning of the second line. When splitting at an infix operator, you may or may not increase indentation depth, depending on what is more readable.
|
||||
|
||||
When splitting an `if`-`then`-`else` expression, the `then` keyword wants to stay with the condition and the `else` keyword wants to stay with the alternative term. Otherwise, indent as if the `if` and `else` keywords were arguments to the same function.
|
||||
|
||||
When splitting a comma-separated bracketed sequence (i.e., anonymous constructor application, list/array/vector literal, tuple) it is allowed to indent subsequent lines for alignment, but indenting by two spaces is also allowed.
|
||||
|
||||
Do not orphan parentheses.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def MacroScopesView.isPrefixOf (v₁ v₂ : MacroScopesView) : Bool :=
|
||||
v₁.name.isPrefixOf v₂.name &&
|
||||
v₁.scopes == v₂.scopes &&
|
||||
v₁.mainModule == v₂.mainModule &&
|
||||
v₁.imported == v₂.imported
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem eraseP_eq_iff {p} {l : List α} :
|
||||
l.eraseP p = l' ↔
|
||||
((∀ a ∈ l, ¬ p a) ∧ l = l') ∨
|
||||
∃ a l₁ l₂, (∀ b ∈ l₁, ¬ p b) ∧ p a ∧
|
||||
l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ :=
|
||||
sorry
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Nat :=
|
||||
functionWithAVeryLongNameSoThatSomeArgumentsWillNotFit firstArgument secondArgument
|
||||
(firstArgumentWithAnEquallyLongNameAndThatFunctionDoesHaveMoreArguments firstArgument
|
||||
secondArgument)
|
||||
secondArgument
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem size_alter [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} (h : m.WF) :
|
||||
(m.alter k f).size =
|
||||
if m.contains k && (f (m.get? k)).isNone then
|
||||
m.size - 1
|
||||
else if !m.contains k && (f (m.get? k)).isSome then
|
||||
m.size + 1
|
||||
else
|
||||
m.size := by
|
||||
simp_to_raw using Raw₀.size_alter
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem get?_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} (h : m.WF) :
|
||||
(m.alter k f).get? k' =
|
||||
if h : k == k' then
|
||||
cast (congrArg (Option ∘ β) (eq_of_beq h)) (f (m.get? k))
|
||||
else m.get? k' := by
|
||||
simp_to_raw using Raw₀.get?_alter
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Nat × Nat :=
|
||||
⟨imagineThisWasALongTerm,
|
||||
imagineThisWasAnotherLongTerm⟩
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Nat × Nat :=
|
||||
⟨imagineThisWasALongTerm,
|
||||
imagineThisWasAnotherLongTerm⟩
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Vector Nat :=
|
||||
#v[imagineThisWasALongTerm,
|
||||
imagineThisWasAnotherLongTerm]
|
||||
```
|
||||
|
||||
## Basic file structure
|
||||
|
||||
Every file should start with a copyright header, imports (in the standard library, this always includes a `prelude` declaration) and a module documentation string. There should not be a blank line between the copyright header and the imports. There should be a blank line between the imports and the module documentation string.
|
||||
|
||||
If you explicitly declare universe variables, do so at the top of the file, after the module documentation.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
/-
|
||||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro,
|
||||
Yury Kudryashov
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Pairwise
|
||||
import Init.Data.List.Find
|
||||
|
||||
/-!
|
||||
**# Lemmas about `List.eraseP` and `List.erase`.**
|
||||
-/
|
||||
|
||||
universe u u'
|
||||
```
|
||||
|
||||
Syntax that is not supposed to be user-facing must be scoped. New public syntax must always be discussed explicitly in an RFC.
|
||||
|
||||
## Top-level commands and declarations
|
||||
|
||||
All top-level commands are unindented. Sectioning commands like `section` and `namespace` do not increase the indentation level.
|
||||
|
||||
Attributes may be placed on the same line as the rest of the command or on a separate line.
|
||||
|
||||
Multi-line declaration headers are indented by four spaces starting from the second line. The colon that indicates the type of a declaration may not be placed at the start of a line or on its own line.
|
||||
|
||||
Declaration bodies are indented by two spaces. Short declaration bodies may be placed on the same line as the declaration type.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem eraseP_eq_iff {p} {l : List α} :
|
||||
l.eraseP p = l' ↔
|
||||
((∀ a ∈ l, ¬ p a) ∧ l = l') ∨
|
||||
∃ a l₁ l₂, (∀ b ∈ l₁, ¬ p b) ∧ p a ∧
|
||||
l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ :=
|
||||
sorry
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[simp]
|
||||
theorem eraseP_nil : [].eraseP p = [] := rfl
|
||||
```
|
||||
|
||||
### Documentation comments
|
||||
|
||||
Note to external contributors: this is a section where the Lean style and the mathlib style are different.
|
||||
|
||||
Declarations should be documented as required by the `docBlame` linter, which may be activated in a file using
|
||||
`set_option linter.missingDocs true` (we allow these to stay in the file).
|
||||
|
||||
Single-line documentation comments should go on the same line as `/--`/`-/`, while multi-line documentation strings
|
||||
should have these delimiters on their own line, with the documentation comment itself unindented.
|
||||
|
||||
Documentation comments must be written in the indicative mood. Use American orthography.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
/-- Carries out a monadic action on each mapping in the hash map in some order. -/
|
||||
@[inline] def forM (f : (a : α) → β a → m PUnit) (b : Raw α β) : m PUnit :=
|
||||
b.buckets.forM (AssocList.forM f)
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
/--
|
||||
Monadically computes a value by folding the given function over the mappings in the hash
|
||||
map in some order.
|
||||
-/
|
||||
@[inline] def foldM (f : δ → (a : α) → β a → m δ) (init : δ) (b : Raw α β) : m δ :=
|
||||
b.buckets.foldlM (fun acc l => l.foldlM f acc) init
|
||||
```
|
||||
|
||||
### Where clauses
|
||||
|
||||
The `where` keyword should be unindented, and all declarations bound by it should be indented with two spaces.
|
||||
|
||||
Blank lines before and after `where` and between declarations bound by `where` are optional and should be chosen
|
||||
to maximize readability.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[simp] 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) =
|
||||
(as.reverse ++ filter p l, bs.reverse ++ filter (not ∘ p) l) :=
|
||||
match l with
|
||||
| [] => by simp [partition.loop, filter]
|
||||
| a :: l => by cases pa : p a <;> simp [partition.loop, pa, aux, filter, append_assoc]
|
||||
```
|
||||
|
||||
### Termination arguments
|
||||
|
||||
The `termination_by`, `decreasing_by`, `partial_fixpoint` keywords should be unindented. The associated terms should be indented like declaration bodies.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[inline] def multiShortOption (handle : Char → m PUnit) (opt : String) : m PUnit := do
|
||||
let rec loop (p : String.Pos) := do
|
||||
if h : opt.atEnd p then
|
||||
return
|
||||
else
|
||||
handle (opt.get' p h)
|
||||
loop (opt.next' p h)
|
||||
termination_by opt.utf8ByteSize - p.byteIdx
|
||||
decreasing_by
|
||||
simp [String.atEnd] at h
|
||||
apply Nat.sub_lt_sub_left h
|
||||
simp [String.lt_next opt p]
|
||||
loop ⟨1⟩
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def substrEq (s1 : String) (off1 : String.Pos) (s2 : String) (off2 : String.Pos) (sz : Nat) : Bool :=
|
||||
off1.byteIdx + sz ≤ s1.endPos.byteIdx && off2.byteIdx + sz ≤ s2.endPos.byteIdx && loop off1 off2 { byteIdx := off1.byteIdx + sz }
|
||||
where
|
||||
loop (off1 off2 stop1 : Pos) :=
|
||||
if _h : off1.byteIdx < stop1.byteIdx then
|
||||
let c₁ := s1.get off1
|
||||
let c₂ := s2.get off2
|
||||
c₁ == c₂ && loop (off1 + c₁) (off2 + c₂) stop1
|
||||
else true
|
||||
termination_by stop1.1 - off1.1
|
||||
decreasing_by
|
||||
have := Nat.sub_lt_sub_left _h (Nat.add_lt_add_left c₁.utf8Size_pos off1.1)
|
||||
decreasing_tactic
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem div_add_mod (m n : Nat) : n * (m / n) + m % n = m := by
|
||||
rw [div_eq, mod_eq]
|
||||
have h : Decidable (0 < n ∧ n ≤ m) := inferInstance
|
||||
cases h with
|
||||
| isFalse h => simp [h]
|
||||
| isTrue h =>
|
||||
simp [h]
|
||||
have ih := div_add_mod (m - n) n
|
||||
rw [Nat.left_distrib, Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, ih, Nat.add_comm, Nat.sub_add_cancel h.2]
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
```
|
||||
|
||||
### Deriving
|
||||
|
||||
The `deriving` clause should be unindented.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
structure Iterator where
|
||||
array : ByteArray
|
||||
idx : Nat
|
||||
deriving Inhabited
|
||||
```
|
||||
|
||||
## Notation and Unicode
|
||||
|
||||
We generally prefer to use notation as available. We usually prefer the Unicode versions of notations over non-Unicode alternatives.
|
||||
|
||||
There are some rules and exceptions regarding specific notations which are listed below:
|
||||
|
||||
* Sigma types: use `(a : α) × β a` instead of `Σ a, β a` or `Sigma β`.
|
||||
* Function arrows: use `fun a => f x` instead of `fun x ↦ f x` or `λ x => f x` or any other variant.
|
||||
|
||||
## Language constructs
|
||||
|
||||
### Pattern matching, induction etc.
|
||||
|
||||
Match arms are indented at the indentation level that the match statement would have if it was on its own line. If the match is implicit, then the arms should be indented as if the match was explicitly given. The content of match arms is indented two spaces, so that it appears on the same level as the match pattern.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def alter [BEq α] {β : Type v} (a : α) (f : Option β → Option β) :
|
||||
AssocList α (fun _ => β) → AssocList α (fun _ => β)
|
||||
| nil => match f none with
|
||||
| none => nil
|
||||
| some b => AssocList.cons a b nil
|
||||
| cons k v l =>
|
||||
if k == a then
|
||||
match f v with
|
||||
| none => l
|
||||
| some b => cons a b l
|
||||
else
|
||||
cons k v (alter a f l)
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
|
||||
∃ as bs, xs = as ++ a :: bs ∧ a ∉ as := by
|
||||
induction xs with
|
||||
| nil => cases h
|
||||
| cons x xs ih =>
|
||||
simp at h
|
||||
cases h with
|
||||
| inl h => exact ⟨[], xs, by simp_all⟩
|
||||
| inr h =>
|
||||
by_cases h' : a = x
|
||||
· subst h'
|
||||
exact ⟨[], xs, by simp⟩
|
||||
· obtain ⟨as, bs, rfl, h⟩ := ih h
|
||||
exact ⟨x :: as, bs, rfl, by simp_all⟩
|
||||
```
|
||||
|
||||
Aligning match arms is allowed, but not required.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
|
||||
match h₁?, h₂? with
|
||||
| none, none => return none
|
||||
| none, some h => return h
|
||||
| some h, none => return h
|
||||
| some h₁, some h₂ => mkEqTrans h₁ h₂
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
|
||||
match h₁?, h₂? with
|
||||
| none, none => return none
|
||||
| none, some h => return h
|
||||
| some h, none => return h
|
||||
| some h₁, some h₂ => mkEqTrans h₁ h₂
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
|
||||
match h₁?, h₂? with
|
||||
| none, none => return none
|
||||
| none, some h => return h
|
||||
| some h, none => return h
|
||||
| some h₁, some h₂ => mkEqTrans h₁ h₂
|
||||
```
|
||||
|
||||
### Structures
|
||||
|
||||
Note to external contributors: this is a section where the Lean style and the mathlib style are different.
|
||||
|
||||
When using structure instance syntax over multiple lines, the opening brace should go on the preceding line, while the closing brace should go on its own line. The rest of the syntax should be indented by one level. During structure updates, the `with` clause goes on the same line as the opening brace. Aligning at the assignment symbol is allowed but not required.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (reportExts := true) :
|
||||
IO AddConstAsyncResult := do
|
||||
let sigPromise ← IO.Promise.new
|
||||
let infoPromise ← IO.Promise.new
|
||||
let extensionsPromise ← IO.Promise.new
|
||||
let checkedEnvPromise ← IO.Promise.new
|
||||
let asyncConst := {
|
||||
constInfo := {
|
||||
name := constName
|
||||
kind
|
||||
sig := sigPromise.result
|
||||
constInfo := infoPromise.result
|
||||
}
|
||||
exts? := guard reportExts *> some extensionsPromise.result
|
||||
}
|
||||
return {
|
||||
constName, kind
|
||||
mainEnv := { env with
|
||||
asyncConsts := env.asyncConsts.add asyncConst
|
||||
checked := checkedEnvPromise.result }
|
||||
asyncEnv := { env with
|
||||
asyncCtx? := some { declPrefix := privateToUserName constName.eraseMacroScopes }
|
||||
}
|
||||
sigPromise, infoPromise, extensionsPromise, checkedEnvPromise
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
instance [Inhabited α] : Inhabited (Descr α β σ) where
|
||||
default := {
|
||||
name := default
|
||||
mkInitial := default
|
||||
ofOLeanEntry := default
|
||||
toOLeanEntry := default
|
||||
addEntry := fun s _ => s
|
||||
}
|
||||
```
|
||||
|
||||
### Declaring structures
|
||||
|
||||
When defining structure types, do not parenthesize structure fields.
|
||||
|
||||
When declaring a structure type with a custom constructor name, put the custom name on its own line, indented like the
|
||||
structure fields, and add a documentation comment.
|
||||
|
||||
Correct:
|
||||
|
||||
```lean
|
||||
/--
|
||||
A bitvector of the specified width.
|
||||
|
||||
This is represented as the underlying `Nat` number in both the runtime
|
||||
and the kernel, inheriting all the special support for `Nat`.
|
||||
-/
|
||||
structure BitVec (w : Nat) where
|
||||
/--
|
||||
Constructs a `BitVec w` from a number less than `2^w`.
|
||||
O(1), because we use `Fin` as the internal representation of a bitvector.
|
||||
-/
|
||||
ofFin ::
|
||||
/--
|
||||
Interprets a bitvector as a number less than `2^w`.
|
||||
O(1), because we use `Fin` as the internal representation of a bitvector.
|
||||
-/
|
||||
toFin : Fin (2 ^ w)
|
||||
```
|
||||
|
||||
## Tactic proofs
|
||||
|
||||
Tactic proofs are the most common thing to break during any kind of upgrade, so it is important to write them in a way that minimizes the likelihood of proofs breaking and that makes it easy to debug breakages if they do occur.
|
||||
|
||||
If there are multiple goals, either use a tactic combinator (like `all_goals`) to operate on all of them or a clearly specified subset, or use focus dots to work on goals one at a time. Using structured proofs (e.g., `induction … with`) is encouraged but not mandatory.
|
||||
|
||||
Squeeze non-terminal `simp`s (i.e., calls to `simp` which do not close the goal). Squeezing terminal `simp`s is generally discouraged, although there are exceptions (for example if squeezing yields a noticeable performance improvement).
|
||||
|
||||
Do not over-golf proofs in ways that are likely to lead to hard-to-debug breakage. Examples of things to avoid include complex multi-goal manipulation using lots of tactic combinators, complex uses of the substitution operator (`▸`) and clever point-free expressions (possibly involving anonymous function notation for multiple arguments).
|
||||
|
||||
Do not under-golf proofs: for routine tasks, use the most powerful tactics available.
|
||||
|
||||
Do not use `erw`. Avoid using `rfl` after `simp` or `rw`, as this usually indicates a missing lemma that should be used instead of `rfl`.
|
||||
|
||||
Use `(d)simp` or `rw` instead of `delta` or `unfold`. Use `refine` instead of `refine’`. Use `haveI` and `letI` only if they are actually required.
|
||||
|
||||
Prefer highly automated tactics (like `grind` and `omega`) over low-level proofs, unless the automated tactic requires unacceptable additional imports or has bad performance. If you decide against using a highly automated tactic, leave a comment explaining the decision.
|
||||
|
||||
## `do` notation
|
||||
|
||||
The `do` keyword goes on the same line as the corresponding `:=` (or `=>`, or similar). `Id.run do` should be treated as if it was a bare `do`.
|
||||
|
||||
Use early `return` statements to reduce nesting depth and make the non-exceptional control flow of a function easier to see.
|
||||
|
||||
Alternatives for `let` matches may be placed in the same line or in the next line, indented by two spaces. If the term that is
|
||||
being matched on is itself more than one line and there is an alternative present, consider breaking immediately after `←` and indent
|
||||
as far as necessary to ensure readability.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
|
||||
let some decl ← findFunDecl? fvarId | throwError "unknown local function {fvarId.name}"
|
||||
return decl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
|
||||
let some decl ←
|
||||
findFunDecl? fvarId
|
||||
| throwError "unknown local function {fvarId.name}"
|
||||
return decl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
|
||||
let some decl ← findFunDecl?
|
||||
fvarId
|
||||
| throwError "unknown local function {fvarId.name}"
|
||||
return decl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def tagUntaggedGoals (parentTag : Name) (newSuffix : Name) (newGoals : List MVarId) : TacticM Unit := do
|
||||
let mctx ← getMCtx
|
||||
let mut numAnonymous := 0
|
||||
for g in newGoals do
|
||||
if mctx.isAnonymousMVar g then
|
||||
numAnonymous := numAnonymous + 1
|
||||
modifyMCtx fun mctx => Id.run do
|
||||
let mut mctx := mctx
|
||||
let mut idx := 1
|
||||
for g in newGoals do
|
||||
if mctx.isAnonymousMVar g then
|
||||
if numAnonymous == 1 then
|
||||
mctx := mctx.setMVarUserName g parentTag
|
||||
else
|
||||
mctx := mctx.setMVarUserName g (parentTag ++ newSuffix.appendIndexAfter idx)
|
||||
idx := idx + 1
|
||||
pure mctx
|
||||
```
|
||||
|
||||
98
doc/std/vision.md
Normal file
98
doc/std/vision.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# The Lean 4 standard library
|
||||
|
||||
Maintainer team (in alphabetical order): Henrik Böving, Markus Himmel
|
||||
(community contact & external contribution coordinator), Kim Morrison, Paul
|
||||
Reichert, Sofia Rodrigues.
|
||||
|
||||
The Lean 4 standard library is a core part of the Lean distribution, providing
|
||||
essential building blocks for functional programming, verified software
|
||||
development, and software verification. Unlike the standard libraries of most
|
||||
other languages, many of its components are formally verified and can be used
|
||||
as part of verified applications.
|
||||
|
||||
The standard library is a public API that contains the components listed in the
|
||||
standard library outline below. Not all public APIs in the Lean distribution
|
||||
are part of the standard library, and the standard library does not correspond
|
||||
to a certain directory within the Lean source repository (like `Std`). For
|
||||
example, the metaprogramming framework is not part of the standard library, but
|
||||
basic types like `True` and `Nat` are.
|
||||
|
||||
The standard library is under active development. Our guiding principles are:
|
||||
|
||||
* Provide comprehensive, verified building blocks for real-world software.
|
||||
* Build a public API of the highest quality with excellent internal consistency.
|
||||
* Carefully optimize components that may be used in performance-critical software.
|
||||
* Ensure smooth adoption and maintenance for users.
|
||||
* Offer excellent documentation, example projects, and guides.
|
||||
* Provide a reliable and extensible basis that libraries for software
|
||||
development, software verification and mathematics can build on.
|
||||
|
||||
The standard library is principally developed by the Lean FRO. Community
|
||||
contributions are welcome. If you would like to contribute, please refer to the
|
||||
call for contributions below.
|
||||
|
||||
### Standard library outline
|
||||
|
||||
1. Core types and operations
|
||||
1. Basic types
|
||||
2. Numeric types, including floating point numbers
|
||||
3. Containers
|
||||
4. Strings and formatting
|
||||
2. Language constructs
|
||||
1. Ranges and iterators
|
||||
2. Comparison, ordering, hashing and related type classes
|
||||
3. Basic monad infrastructure
|
||||
3. Libraries
|
||||
1. Random numbers
|
||||
2. Dates and times
|
||||
4. Operating system abstractions
|
||||
1. Concurrency and parallelism primitives
|
||||
2. Asynchronous I/O
|
||||
3. FFI helpers
|
||||
4. Environment, file system, processes
|
||||
5. Locales
|
||||
|
||||
The material covered in the first three sections (core types and operations,
|
||||
language constructs and libraries) will be verified, with the exception of
|
||||
floating point numbers and the parts of the libraries that interface with the
|
||||
operating system (e.g., sources of operating system randomness or time zone
|
||||
database access).
|
||||
|
||||
### Call for contributions
|
||||
|
||||
Thank you for taking interest in contributing to the Lean standard library\!
|
||||
There are two main ways for community members to contribute to the Lean
|
||||
standard library: by contributing experience reports or by contributing code
|
||||
and lemmas.
|
||||
|
||||
**If you are using Lean for software verification or verified software
|
||||
development:** hearing about your experiences using Lean and its standard
|
||||
library for software verification is extremely valuable to us. We are committed
|
||||
to building a standard library suitable for real-world applications and your
|
||||
input will directly influence the continued evolution of the Lean standard
|
||||
library. Please reach out to the standard library maintainer team via Zulip
|
||||
(either in a public thread in the \#lean4 channel or via direct message). Even
|
||||
just a link to your code helps. Thanks\!
|
||||
|
||||
**If you have code that you believe could enhance the Lean 4 standard
|
||||
library:** we encourage you to initiate a discussion in the \#lean4 channel on
|
||||
Zulip. This is the most effective way to receive preliminary feedback on your
|
||||
contribution. The Lean standard library has a very precise scope and it has
|
||||
very high quality standards, so at the moment we are mostly interested in
|
||||
contributions that expand upon existing material rather than introducing novel
|
||||
concepts.
|
||||
|
||||
**If you would like to contribute code to the standard library but don’t know
|
||||
what to work on:** we are always excited to meet motivated community members
|
||||
who would like to contribute, and there is always impactful work that is
|
||||
suitable for new contributors. Please reach out to Markus Himmel on Zulip to
|
||||
discuss possible contributions.
|
||||
|
||||
As laid out in the [project-wide External Contribution
|
||||
Guidelines](../../CONTRIBUTING.md),
|
||||
PRs are much more likely to be merged if they are preceded by an RFC or if you
|
||||
discussed your planned contribution with a member of the standard library
|
||||
maintainer team. When in doubt, introducing yourself is always a good idea.
|
||||
|
||||
All code in the standard library is expected to strictly adhere to the
|
||||
[standard library coding conventions](./style.md).
|
||||
@@ -107,8 +107,8 @@ noncomputable def epsilon {α : Sort u} [h : Nonempty α] (p : α → Prop) : α
|
||||
theorem epsilon_spec_aux {α : Sort u} (h : Nonempty α) (p : α → Prop) : (∃ y, p y) → p (@epsilon α h p) :=
|
||||
(strongIndefiniteDescription p h).property
|
||||
|
||||
theorem epsilon_spec {α : Sort u} {p : α → Prop} (hex : ∃ y, p y) : p (@epsilon α (nonempty_of_exists hex) p) :=
|
||||
epsilon_spec_aux (nonempty_of_exists hex) p hex
|
||||
theorem epsilon_spec {α : Sort u} {p : α → Prop} (hex : ∃ y, p y) : p (@epsilon α hex.nonempty p) :=
|
||||
epsilon_spec_aux hex.nonempty p hex
|
||||
|
||||
theorem epsilon_singleton {α : Sort u} (x : α) : @epsilon α ⟨x⟩ (fun y => y = x) = x :=
|
||||
@epsilon_spec α (fun y => y = x) ⟨x, rfl⟩
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Ext
|
||||
import Init.SimpLemmas
|
||||
import Init.Meta
|
||||
|
||||
@@ -241,13 +242,23 @@ theorem LawfulMonad.mk' (m : Type u → Type v) [Monad m]
|
||||
|
||||
namespace Id
|
||||
|
||||
@[simp] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
|
||||
@[simp] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
|
||||
@[simp] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
||||
@[ext] theorem ext {x y : Id α} (h : x.run = y.run) : x = y := h
|
||||
|
||||
instance : LawfulMonad Id := by
|
||||
refine LawfulMonad.mk' _ ?_ ?_ ?_ <;> intros <;> rfl
|
||||
|
||||
@[simp] theorem run_map (x : Id α) (f : α → β) : (f <$> x).run = f x.run := rfl
|
||||
@[simp] theorem run_bind (x : Id α) (f : α → Id β) : (x >>= f).run = (f x.run).run := rfl
|
||||
@[simp] theorem run_pure (a : α) : (pure a : Id α).run = a := rfl
|
||||
@[simp] theorem run_seqRight (x y : Id α) : (x *> y).run = y.run := rfl
|
||||
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
|
||||
@[simp] theorem run_seq (f : Id (α → β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
|
||||
|
||||
-- These lemmas are bad as they abuse the defeq of `Id α` and `α`
|
||||
@[deprecated run_map (since := "2025-03-05")] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
|
||||
@[deprecated run_bind (since := "2025-03-05")] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
|
||||
@[deprecated run_pure (since := "2025-03-05")] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
||||
|
||||
end Id
|
||||
|
||||
/-! # Option -/
|
||||
|
||||
@@ -1212,10 +1212,7 @@ abbrev noConfusionEnum {α : Sort u} {β : Sort v} [inst : DecidableEq β] (f :
|
||||
instance : Inhabited Prop where
|
||||
default := True
|
||||
|
||||
deriving instance Inhabited for NonScalar, PNonScalar, True, ForInStep
|
||||
|
||||
theorem nonempty_of_exists {α : Sort u} {p : α → Prop} : Exists (fun x => p x) → Nonempty α
|
||||
| ⟨w, _⟩ => ⟨w⟩
|
||||
deriving instance Inhabited for NonScalar, PNonScalar, True
|
||||
|
||||
/-! # Subsingleton -/
|
||||
|
||||
@@ -1389,16 +1386,7 @@ instance Sum.nonemptyLeft [h : Nonempty α] : Nonempty (Sum α β) :=
|
||||
instance Sum.nonemptyRight [h : Nonempty β] : Nonempty (Sum α β) :=
|
||||
Nonempty.elim h (fun b => ⟨Sum.inr b⟩)
|
||||
|
||||
instance {α : Type u} {β : Type v} [DecidableEq α] [DecidableEq β] : DecidableEq (Sum α β) := fun a b =>
|
||||
match a, b with
|
||||
| Sum.inl a, Sum.inl b =>
|
||||
if h : a = b then isTrue (h ▸ rfl)
|
||||
else isFalse fun h' => Sum.noConfusion h' fun h' => absurd h' h
|
||||
| Sum.inr a, Sum.inr b =>
|
||||
if h : a = b then isTrue (h ▸ rfl)
|
||||
else isFalse fun h' => Sum.noConfusion h' fun h' => absurd h' h
|
||||
| Sum.inr _, Sum.inl _ => isFalse fun h => Sum.noConfusion h
|
||||
| Sum.inl _, Sum.inr _ => isFalse fun h => Sum.noConfusion h
|
||||
deriving instance DecidableEq for Sum
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -69,11 +69,11 @@ well-founded recursion mechanism to prove that the function terminates.
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem toList_attachWith {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs, P x} :
|
||||
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList] using H) := by
|
||||
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList_iff] using H) := by
|
||||
simp [attachWith]
|
||||
|
||||
@[simp] theorem toList_attach {xs : Array α} :
|
||||
xs.attach.toList = xs.toList.attachWith (· ∈ xs) (by simp [mem_toList]) := by
|
||||
xs.attach.toList = xs.toList.attachWith (· ∈ xs) (by simp [mem_toList_iff]) := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem toList_pmap {xs : Array α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ xs, P a} :
|
||||
@@ -574,9 +574,12 @@ state, the right approach is usually the tactic `simp [Array.unattach, -Array.ma
|
||||
-/
|
||||
def unattach {α : Type _} {p : α → Prop} (xs : Array { x // p x }) : Array α := xs.map (·.val)
|
||||
|
||||
@[simp] theorem unattach_nil {p : α → Prop} : (#[] : Array { x // p x }).unattach = #[] := by
|
||||
@[simp] theorem unattach_empty {p : α → Prop} : (#[] : Array { x // p x }).unattach = #[] := by
|
||||
simp [unattach]
|
||||
|
||||
@[deprecated unattach_empty (since := "2025-05-26")]
|
||||
abbrev unattach_nil := @unattach_empty
|
||||
|
||||
@[simp] theorem unattach_push {p : α → Prop} {a : { x // p x }} {xs : Array { x // p x }} :
|
||||
(xs.push a).unattach = xs.unattach.push a.1 := by
|
||||
simp only [unattach, Array.map_push]
|
||||
|
||||
@@ -112,6 +112,10 @@ theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
|
||||
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
|
||||
|
||||
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
|
||||
|
||||
end Array
|
||||
|
||||
namespace List
|
||||
@@ -334,6 +338,8 @@ def ofFn {n} (f : Fin n → α) : Array α := go 0 (emptyWithCapacity n) where
|
||||
if h : i < n then go (i+1) (acc.push (f ⟨i, h⟩)) else acc
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
-- See also `Array.ofFnM` defined in `Init.Data.Array.OfFn`.
|
||||
|
||||
/--
|
||||
Constructs an array that contains all the numbers from `0` to `n`, exclusive.
|
||||
|
||||
@@ -538,7 +544,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def modify (xs : Array α) (i : Nat) (f : α → α) : Array α :=
|
||||
Id.run <| modifyM xs i f
|
||||
Id.run <| modifyM xs i (pure <| f ·)
|
||||
|
||||
set_option linter.indexVariables false in -- Changing `idx` causes bootstrapping issues, haven't investigated.
|
||||
/--
|
||||
@@ -1053,7 +1059,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Array α) (start := 0) (stop := as.size) : β :=
|
||||
Id.run <| as.foldlM f init start stop
|
||||
Id.run <| as.foldlM (pure <| f · ·) init start stop
|
||||
|
||||
/--
|
||||
Folds a function over an array from the right, accumulating a value starting with `init`. The
|
||||
@@ -1070,7 +1076,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def foldr {α : Type u} {β : Type v} (f : α → β → β) (init : β) (as : Array α) (start := as.size) (stop := 0) : β :=
|
||||
Id.run <| as.foldrM f init start stop
|
||||
Id.run <| as.foldrM (pure <| f · ·) init start stop
|
||||
|
||||
/--
|
||||
Computes the sum of the elements of an array.
|
||||
@@ -1118,7 +1124,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def map {α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β :=
|
||||
Id.run <| as.mapM f
|
||||
Id.run <| as.mapM (pure <| f ·)
|
||||
|
||||
instance : Functor Array where
|
||||
map := map
|
||||
@@ -1133,7 +1139,7 @@ valid.
|
||||
-/
|
||||
@[inline]
|
||||
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → β) : Array β :=
|
||||
Id.run <| as.mapFinIdxM f
|
||||
Id.run <| as.mapFinIdxM (pure <| f · · ·)
|
||||
|
||||
/--
|
||||
Applies a function to each element of the array along with the index at which that element is found,
|
||||
@@ -1144,7 +1150,7 @@ is valid.
|
||||
-/
|
||||
@[inline]
|
||||
def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) : Array β :=
|
||||
Id.run <| as.mapIdxM f
|
||||
Id.run <| as.mapIdxM (pure <| f · ·)
|
||||
|
||||
/--
|
||||
Pairs each element of an array with its index, optionally starting from an index other than `0`.
|
||||
@@ -1192,7 +1198,7 @@ some 10
|
||||
-/
|
||||
@[inline]
|
||||
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeM? f
|
||||
Id.run <| as.findSomeM? (pure <| f ·)
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying the function `f` to each element of the
|
||||
@@ -1226,7 +1232,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def findSomeRev? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeRevM? f
|
||||
Id.run <| as.findSomeRevM? (pure <| f ·)
|
||||
|
||||
/--
|
||||
Returns the last element of the array for which the predicate `p` returns `true`, or `none` if no
|
||||
@@ -1238,7 +1244,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def findRev? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run <| as.findRevM? p
|
||||
Id.run <| as.findRevM? (pure <| p ·)
|
||||
|
||||
/--
|
||||
Returns the index of the first element for which `p` returns `true`, or `none` if there is no such
|
||||
@@ -1377,7 +1383,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.anyM p start stop
|
||||
Id.run <| as.anyM (pure <| p ·) start stop
|
||||
|
||||
/--
|
||||
Returns `true` if `p` returns `true` for every element of `as`.
|
||||
@@ -1395,7 +1401,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.allM p start stop
|
||||
Id.run <| as.allM (pure <| p ·) start stop
|
||||
|
||||
/--
|
||||
Checks whether `a` is an element of `as`, using `==` to compare elements.
|
||||
@@ -1664,7 +1670,7 @@ Example:
|
||||
-/
|
||||
@[inline]
|
||||
def filterMap (f : α → Option β) (as : Array α) (start := 0) (stop := as.size) : Array β :=
|
||||
Id.run <| as.filterMapM f (start := start) (stop := stop)
|
||||
Id.run <| as.filterMapM (pure <| f ·) (start := start) (stop := stop)
|
||||
|
||||
/--
|
||||
Returns the largest element of the array, as determined by the comparison `lt`, or `none` if
|
||||
|
||||
@@ -88,4 +88,4 @@ pointer equality, and does not allocate a new array if the result of each functi
|
||||
pointer-equal to its argument.
|
||||
-/
|
||||
@[inline] def Array.mapMono (as : Array α) (f : α → α) : Array α :=
|
||||
Id.run <| as.mapMonoM f
|
||||
Id.run <| as.mapMonoM (pure <| f ·)
|
||||
|
||||
@@ -129,6 +129,6 @@ Examples:
|
||||
* `#[].binInsert (· < ·) 1 = #[1]`
|
||||
-/
|
||||
@[inline] def binInsert {α : Type u} (lt : α → α → Bool) (as : Array α) (k : α) : Array α :=
|
||||
Id.run <| binInsertM lt (fun _ => k) (fun _ => k) as k
|
||||
Id.run <| binInsertM lt (fun _ => pure k) (fun _ => pure k) as k
|
||||
|
||||
end Array
|
||||
|
||||
@@ -89,9 +89,13 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] {f : α → β → m β} {init
|
||||
xs.toList.foldr f init = xs.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_toList ..
|
||||
|
||||
@[simp, grind =] theorem push_toList {xs : Array α} {a : α} : (xs.push a).toList = xs.toList ++ [a] := by
|
||||
@[simp, grind =] theorem toList_push {xs : Array α} {x : α} : (xs.push x).toList = xs.toList ++ [x] := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [push, List.concat_eq_append]
|
||||
|
||||
@[deprecated toList_push (since := "2025-05-26")]
|
||||
abbrev push_toList := @toList_push
|
||||
|
||||
@[simp, grind =] theorem toListAppend_eq {xs : Array α} {l : List α} : xs.toListAppend l = xs.toList ++ l := by
|
||||
simp [toListAppend, ← foldr_toList]
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ theorem countP_push {a : α} {xs : Array α} : countP p (xs.push a) = countP p x
|
||||
rcases xs with ⟨xs⟩
|
||||
simp_all
|
||||
|
||||
@[simp] theorem countP_singleton {a : α} : countP p #[a] = if p a then 1 else 0 := by
|
||||
simp [countP_push]
|
||||
theorem countP_singleton {a : α} : countP p #[a] = if p a then 1 else 0 := by
|
||||
simp
|
||||
|
||||
theorem size_eq_countP_add_countP {xs : Array α} : xs.size = countP p xs + countP (fun a => ¬p a) xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
|
||||
@@ -24,7 +24,7 @@ open Nat
|
||||
|
||||
/-! ### eraseP -/
|
||||
|
||||
@[simp] theorem eraseP_empty : #[].eraseP p = #[] := by simp
|
||||
theorem eraseP_empty : #[].eraseP p = #[] := by simp
|
||||
|
||||
theorem eraseP_of_forall_mem_not {xs : Array α} (h : ∀ a, a ∈ xs → ¬p a) : xs.eraseP p = xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
|
||||
@@ -238,11 +238,9 @@ theorem extract_append_left {as bs : Array α} :
|
||||
(as ++ bs).extract 0 as.size = as.extract 0 as.size := by
|
||||
simp
|
||||
|
||||
@[simp] theorem extract_append_right {as bs : Array α} :
|
||||
theorem extract_append_right {as bs : Array α} :
|
||||
(as ++ bs).extract as.size (as.size + i) = bs.extract 0 i := by
|
||||
simp only [extract_append, extract_size_left, Nat.sub_self, empty_append]
|
||||
congr 1
|
||||
omega
|
||||
simp
|
||||
|
||||
@[simp] theorem map_extract {as : Array α} {i j : Nat} :
|
||||
(as.extract i j).map f = (as.map f).extract i j := by
|
||||
|
||||
@@ -142,9 +142,9 @@ abbrev findSome?_mkArray_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
@[simp] theorem find?_empty : find? p #[] = none := rfl
|
||||
|
||||
@[simp] theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].find? p = if p a then some a else none := by
|
||||
simp [singleton_eq_toArray_singleton]
|
||||
simp
|
||||
|
||||
@[simp] theorem findRev?_push_of_pos {xs : Array α} (h : p a) :
|
||||
findRev? p (xs.push a) = some a := by
|
||||
@@ -347,7 +347,8 @@ theorem find?_eq_some_iff_getElem {xs : Array α} {p : α → Bool} {b : α} :
|
||||
|
||||
/-! ### findIdx -/
|
||||
|
||||
@[simp] theorem findIdx_empty : findIdx p #[] = 0 := rfl
|
||||
theorem findIdx_empty : findIdx p #[] = 0 := rfl
|
||||
|
||||
theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx p = if p a then 0 else 1 := by
|
||||
simp
|
||||
@@ -600,7 +601,8 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α → Bo
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
@[simp] theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p #[] = none := by simp
|
||||
theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p #[] = none := by simp
|
||||
|
||||
theorem findFinIdx?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findFinIdx? p = if p a then some ⟨0, by simp⟩ else none := by
|
||||
simp
|
||||
@@ -699,7 +701,7 @@ The verification API for `idxOf?` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx?` (and proved using them).
|
||||
-/
|
||||
|
||||
@[simp] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := by simp
|
||||
theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := by simp
|
||||
|
||||
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf? a = none ↔ a ∉ xs := by
|
||||
@@ -712,14 +714,10 @@ theorem isSome_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.idxOf? a).isNone = ¬ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
|
||||
|
||||
/-! ### finIdxOf?
|
||||
|
||||
The verification API for `finIdxOf?` is still incomplete.
|
||||
@@ -730,7 +728,7 @@ theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
|
||||
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
|
||||
|
||||
@[simp] theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by simp
|
||||
theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by simp
|
||||
|
||||
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.finIdxOf? a = none ↔ a ∉ xs := by
|
||||
@@ -748,10 +746,8 @@ theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isNone = ¬ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
@@ -61,14 +61,9 @@ theorem toArray_eq : List.toArray as = xs ↔ as = xs.toList := by
|
||||
|
||||
@[grind] theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
|
||||
@[simp] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
|
||||
|
||||
@[deprecated emptyWithCapacity_eq (since := "2025-03-12")]
|
||||
theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
|
||||
|
||||
/-! ### size -/
|
||||
|
||||
@[grind →] theorem eq_empty_of_size_eq_zero (h : xs.size = 0) : xs = #[] := by
|
||||
theorem eq_empty_of_size_eq_zero (h : xs.size = 0) : xs = #[] := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
@@ -80,7 +75,6 @@ theorem ne_empty_of_size_pos (h : 0 < xs.size) : xs ≠ #[] := by
|
||||
cases xs
|
||||
simpa using List.ne_nil_of_length_pos h
|
||||
|
||||
@[grind]
|
||||
theorem size_eq_zero_iff : xs.size = 0 ↔ xs = #[] :=
|
||||
⟨eq_empty_of_size_eq_zero, fun h => h ▸ rfl⟩
|
||||
|
||||
@@ -122,14 +116,11 @@ abbrev size_eq_one := @size_eq_one_iff
|
||||
|
||||
/-! ## L[i] and L[i]? -/
|
||||
|
||||
@[simp] theorem getElem?_eq_none_iff {xs : Array α} : xs[i]? = none ↔ xs.size ≤ i := by
|
||||
by_cases h : i < xs.size
|
||||
· simp [getElem?_pos, h]
|
||||
· rw [getElem?_neg xs i h]
|
||||
simp_all
|
||||
theorem getElem?_eq_none_iff {xs : Array α} : xs[i]? = none ↔ xs.size ≤ i := by
|
||||
simp
|
||||
|
||||
@[simp] theorem none_eq_getElem?_iff {xs : Array α} {i : Nat} : none = xs[i]? ↔ xs.size ≤ i := by
|
||||
simp [eq_comm (a := none)]
|
||||
theorem none_eq_getElem?_iff {xs : Array α} {i : Nat} : none = xs[i]? ↔ xs.size ≤ i := by
|
||||
simp
|
||||
|
||||
theorem getElem?_eq_none {xs : Array α} (h : xs.size ≤ i) : xs[i]? = none := by
|
||||
simp [getElem?_eq_none_iff, h]
|
||||
@@ -139,8 +130,8 @@ grind_pattern Array.getElem?_eq_none => xs.size ≤ i, xs[i]?
|
||||
@[simp] theorem getElem?_eq_getElem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i] :=
|
||||
getElem?_pos ..
|
||||
|
||||
theorem getElem?_eq_some_iff {xs : Array α} : xs[i]? = some b ↔ ∃ h : i < xs.size, xs[i] = b := by
|
||||
simp [getElem?_def]
|
||||
theorem getElem?_eq_some_iff {xs : Array α} : xs[i]? = some b ↔ ∃ h : i < xs.size, xs[i] = b :=
|
||||
_root_.getElem?_eq_some_iff
|
||||
|
||||
@[grind →]
|
||||
theorem getElem_of_getElem? {xs : Array α} : xs[i]? = some a → ∃ h : i < xs.size, xs[i] = a :=
|
||||
@@ -149,13 +140,13 @@ theorem getElem_of_getElem? {xs : Array α} : xs[i]? = some a → ∃ h : i < xs
|
||||
theorem some_eq_getElem?_iff {xs : Array α} : some b = xs[i]? ↔ ∃ h : i < xs.size, xs[i] = b := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem?_iff (xs : Array α) (i : Nat) (h : i < xs.size) :
|
||||
theorem some_getElem_eq_getElem?_iff (xs : Array α) (i : Nat) (h : i < xs.size) :
|
||||
(some xs[i] = xs[i]?) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff (xs : Array α) (i : Nat) (h : i < xs.size) :
|
||||
theorem getElem?_eq_some_getElem_iff (xs : Array α) (i : Nat) (h : i < xs.size) :
|
||||
(xs[i]? = some xs[i]) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
theorem getElem_eq_iff {xs : Array α} {i : Nat} {h : i < xs.size} : xs[i] = x ↔ xs[i]? = some x := by
|
||||
simp only [getElem?_eq_some_iff]
|
||||
@@ -191,16 +182,15 @@ theorem getElem_push {xs : Array α} {x : α} {i : Nat} (h : i < (xs.push x).siz
|
||||
· simp at h
|
||||
simp [getElem_push_lt, Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')]
|
||||
|
||||
theorem getElem?_push {xs : Array α} {x} : (xs.push x)[i]? = if i = xs.size then some x else xs[i]? := by
|
||||
@[grind =] theorem getElem?_push {xs : Array α} {x} : (xs.push x)[i]? = if i = xs.size then some x else xs[i]? := by
|
||||
simp [getElem?_def, getElem_push]
|
||||
(repeat' split) <;> first | rfl | omega
|
||||
|
||||
@[simp] theorem getElem?_push_size {xs : Array α} {x} : (xs.push x)[xs.size]? = some x := by
|
||||
simp [getElem?_push]
|
||||
theorem getElem?_push_size {xs : Array α} {x} : (xs.push x)[xs.size]? = some x := by
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : #[a][i] = a :=
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : #[a][i] = a := by
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : #[a][i]? = if i = 0 then some a else none := by
|
||||
@@ -247,6 +237,8 @@ theorem back?_pop {xs : Array α} :
|
||||
|
||||
/-! ### push -/
|
||||
|
||||
@[simp] theorem push_empty : #[].push x = #[x] := rfl
|
||||
|
||||
@[simp] theorem push_ne_empty {a : α} {xs : Array α} : xs.push a ≠ #[] := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -426,8 +418,7 @@ theorem eq_empty_iff_forall_not_mem {xs : Array α} : xs = #[] ↔ ∀ a, a ∉
|
||||
theorem eq_of_mem_singleton (h : a ∈ #[b]) : a = b := by
|
||||
simpa using h
|
||||
|
||||
@[simp] theorem mem_singleton {a b : α} : a ∈ #[b] ↔ a = b :=
|
||||
⟨eq_of_mem_singleton, (by simp [·])⟩
|
||||
theorem mem_singleton {a b : α} : a ∈ #[b] ↔ a = b := by simp
|
||||
|
||||
theorem forall_mem_push {p : α → Prop} {xs : Array α} {a : α} :
|
||||
(∀ x, x ∈ xs.push a → p x) ↔ p a ∧ ∀ x, x ∈ xs → p x := by
|
||||
@@ -612,13 +603,13 @@ theorem anyM_loop_cons [Monad m] {p : α → m Bool} {a : α} {as : List α} {st
|
||||
|
||||
-- Auxiliary for `any_iff_exists`.
|
||||
theorem anyM_loop_iff_exists {p : α → Bool} {as : Array α} {start stop} (h : stop ≤ as.size) :
|
||||
anyM.loop (m := Id) p as stop h start = true ↔
|
||||
(anyM.loop (m := Id) (pure <| p ·) as stop h start).run = true ↔
|
||||
∃ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop ∧ p as[i] = true := by
|
||||
unfold anyM.loop
|
||||
split <;> rename_i h₁
|
||||
· dsimp
|
||||
split <;> rename_i h₂
|
||||
· simp only [true_iff]
|
||||
· simp only [true_iff, Id.run_pure]
|
||||
refine ⟨start, by omega, by omega, by omega, h₂⟩
|
||||
· rw [anyM_loop_iff_exists]
|
||||
constructor
|
||||
@@ -635,9 +626,9 @@ termination_by stop - start
|
||||
-- This could also be proved from `SatisfiesM_anyM_iff_exists` in `Batteries.Data.Array.Init.Monadic`
|
||||
theorem any_iff_exists {p : α → Bool} {as : Array α} {start stop} :
|
||||
as.any p start stop ↔ ∃ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop ∧ p as[i] := by
|
||||
dsimp [any, anyM, Id.run]
|
||||
dsimp [any, anyM]
|
||||
split
|
||||
· rw [anyM_loop_iff_exists]
|
||||
· rw [anyM_loop_iff_exists (p := p)]
|
||||
· rw [anyM_loop_iff_exists]
|
||||
constructor
|
||||
· rintro ⟨i, hi, ge, _, h⟩
|
||||
@@ -871,8 +862,8 @@ theorem elem_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
xs.contains a = decide (a ∈ xs) := by rw [← elem_eq_contains, elem_eq_mem]
|
||||
|
||||
@[simp, grind] theorem any_empty [BEq α] {p : α → Bool} : (#[] : Array α).any p = false := by simp
|
||||
@[simp, grind] theorem all_empty [BEq α] {p : α → Bool} : (#[] : Array α).all p = true := by simp
|
||||
@[grind] theorem any_empty [BEq α] {p : α → Bool} : (#[] : Array α).any p = false := by simp
|
||||
@[grind] theorem all_empty [BEq α] {p : α → Bool} : (#[] : Array α).all p = true := by simp
|
||||
|
||||
/-- Variant of `any_push` with a side condition on `stop`. -/
|
||||
@[simp, grind] theorem any_push' [BEq α] {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
@@ -1231,7 +1222,7 @@ where
|
||||
@[simp] theorem mapM_empty [Monad m] (f : α → m β) : mapM f #[] = pure #[] := by
|
||||
rw [mapM, mapM.map]; rfl
|
||||
|
||||
@[simp, grind] theorem map_empty {f : α → β} : map f #[] = #[] := mapM_empty f
|
||||
@[grind] theorem map_empty {f : α → β} : map f #[] = #[] := by simp
|
||||
|
||||
@[simp, grind] theorem map_push {f : α → β} {as : Array α} {x : α} :
|
||||
(as.push x).map f = (as.map f).push (f x) := by
|
||||
@@ -1369,17 +1360,17 @@ theorem mapM_eq_mapM_toList [Monad m] [LawfulMonad m] {f : α → m β} {xs : Ar
|
||||
|
||||
@[deprecated "Use `mapM_eq_foldlM` instead" (since := "2025-01-08")]
|
||||
theorem mapM_map_eq_foldl {as : Array α} {f : α → β} {i : Nat} :
|
||||
mapM.map (m := Id) f as i b = as.foldl (start := i) (fun acc a => acc.push (f a)) b := by
|
||||
mapM.map (m := Id) (pure <| f ·) as i b = pure (as.foldl (start := i) (fun acc a => acc.push (f a)) b) := by
|
||||
unfold mapM.map
|
||||
split <;> rename_i h
|
||||
· simp only [Id.bind_eq]
|
||||
dsimp [foldl, Id.run, foldlM]
|
||||
· ext : 1
|
||||
dsimp [foldl, foldlM]
|
||||
rw [mapM_map_eq_foldl, dif_pos (by omega), foldlM.loop, dif_pos h]
|
||||
-- Calling `split` here gives a bad goal.
|
||||
have : size as - i = Nat.succ (size as - i - 1) := by omega
|
||||
rw [this]
|
||||
simp [foldl, foldlM, Id.run, Nat.sub_add_eq]
|
||||
· dsimp [foldl, Id.run, foldlM]
|
||||
simp [foldl, foldlM, Nat.sub_add_eq]
|
||||
· dsimp [foldl, foldlM]
|
||||
rw [dif_pos (by omega), foldlM.loop, dif_neg h]
|
||||
rfl
|
||||
termination_by as.size - i
|
||||
@@ -1601,8 +1592,8 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
as.toList ++ List.filterMap f xs := ?_
|
||||
exact this #[]
|
||||
induction xs
|
||||
· simp_all [Id.run]
|
||||
· simp_all [Id.run, List.filterMap_cons]
|
||||
· simp_all
|
||||
· simp_all [List.filterMap_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[grind] theorem toList_filterMap {f : α → Option β} {xs : Array α} :
|
||||
@@ -1816,7 +1807,8 @@ theorem toArray_append {xs : List α} {ys : Array α} :
|
||||
|
||||
theorem singleton_eq_toArray_singleton {a : α} : #[a] = [a].toArray := rfl
|
||||
|
||||
@[simp] theorem empty_append_fun : ((#[] : Array α) ++ ·) = id := by
|
||||
@[deprecated empty_append (since := "2025-05-26")]
|
||||
theorem empty_append_fun : ((#[] : Array α) ++ ·) = id := by
|
||||
funext ⟨l⟩
|
||||
simp
|
||||
|
||||
@@ -1967,8 +1959,8 @@ theorem append_left_inj {xs₁ xs₂ : Array α} (ys) : xs₁ ++ ys = xs₂ ++ y
|
||||
theorem eq_empty_of_append_eq_empty {xs ys : Array α} (h : xs ++ ys = #[]) : xs = #[] ∧ ys = #[] :=
|
||||
append_eq_empty_iff.mp h
|
||||
|
||||
@[simp] theorem empty_eq_append_iff {xs ys : Array α} : #[] = xs ++ ys ↔ xs = #[] ∧ ys = #[] := by
|
||||
rw [eq_comm, append_eq_empty_iff]
|
||||
theorem empty_eq_append_iff {xs ys : Array α} : #[] = xs ++ ys ↔ xs = #[] ∧ ys = #[] := by
|
||||
simp
|
||||
|
||||
theorem append_ne_empty_of_left_ne_empty {xs ys : Array α} (h : xs ≠ #[]) : xs ++ ys ≠ #[] := by
|
||||
simp_all
|
||||
@@ -2036,7 +2028,7 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
|
||||
simp only [List.append_toArray, List.set_toArray, List.set_append]
|
||||
split <;> simp
|
||||
|
||||
@[simp] theorem set_append_left {xs ys : Array α} {i : Nat} {x : α} (h : i < xs.size) :
|
||||
@[simp] theorem set_append_left {xs ys : Array α} {i : Nat} {x : α} (h : i < xs.size) :
|
||||
(xs ++ ys).set i x (by simp; omega) = xs.set i x ++ ys := by
|
||||
simp [set_append, h]
|
||||
|
||||
@@ -2111,14 +2103,13 @@ theorem append_eq_map_iff {f : α → β} :
|
||||
| nil => simp
|
||||
| cons as => induction as.toList <;> simp [*]
|
||||
|
||||
@[simp] theorem flatten_map_toArray {L : List (List α)} :
|
||||
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
|
||||
@[simp] theorem flatten_toArray_map {L : List (List α)} :
|
||||
(L.map List.toArray).toArray.flatten = L.flatten.toArray := by
|
||||
apply ext'
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp] theorem flatten_toArray_map {L : List (List α)} :
|
||||
(L.map List.toArray).toArray.flatten = L.flatten.toArray := by
|
||||
rw [← flatten_map_toArray]
|
||||
theorem flatten_map_toArray {L : List (List α)} :
|
||||
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
|
||||
simp
|
||||
|
||||
-- We set this to lower priority so that `flatten_toArray_map` is applied first when relevant.
|
||||
@@ -2146,8 +2137,8 @@ theorem mem_flatten : ∀ {xss : Array (Array α)}, a ∈ xss.flatten ↔ ∃ xs
|
||||
induction xss using array₂_induction
|
||||
simp
|
||||
|
||||
@[simp] theorem empty_eq_flatten_iff {xss : Array (Array α)} : #[] = xss.flatten ↔ ∀ xs ∈ xss, xs = #[] := by
|
||||
rw [eq_comm, flatten_eq_empty_iff]
|
||||
theorem empty_eq_flatten_iff {xss : Array (Array α)} : #[] = xss.flatten ↔ ∀ xs ∈ xss, xs = #[] := by
|
||||
simp
|
||||
|
||||
theorem flatten_ne_empty_iff {xss : Array (Array α)} : xss.flatten ≠ #[] ↔ ∃ xs, xs ∈ xss ∧ xs ≠ #[] := by
|
||||
simp
|
||||
@@ -2287,15 +2278,9 @@ theorem eq_iff_flatten_eq {xss₁ xss₂ : Array (Array α)} :
|
||||
rw [List.map_inj_right]
|
||||
simp +contextual
|
||||
|
||||
@[simp] theorem flatten_toArray_map_toArray {xss : List (List α)} :
|
||||
theorem flatten_toArray_map_toArray {xss : List (List α)} :
|
||||
(xss.map List.toArray).toArray.flatten = xss.flatten.toArray := by
|
||||
simp [flatten]
|
||||
suffices ∀ as, List.foldl (fun acc bs => acc ++ bs) as (List.map List.toArray xss) = as ++ xss.flatten.toArray by
|
||||
simpa using this #[]
|
||||
intro as
|
||||
induction xss generalizing as with
|
||||
| nil => simp
|
||||
| cons xs xss ih => simp [ih]
|
||||
simp
|
||||
|
||||
/-! ### flatMap -/
|
||||
|
||||
@@ -2325,13 +2310,9 @@ theorem flatMap_toArray_cons {β} {f : α → Array β} {a : α} {as : List α}
|
||||
intro cs
|
||||
induction as generalizing cs <;> simp_all
|
||||
|
||||
@[simp, grind =] theorem flatMap_toArray {β} {f : α → Array β} {as : List α} :
|
||||
theorem flatMap_toArray {β} {f : α → Array β} {as : List α} :
|
||||
as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
apply ext'
|
||||
simp [ih, flatMap_toArray_cons]
|
||||
simp
|
||||
|
||||
@[simp] theorem flatMap_id {xss : Array (Array α)} : xss.flatMap id = xss.flatten := by simp [flatMap_def]
|
||||
|
||||
@@ -2797,7 +2778,7 @@ theorem reverse_eq_iff {xs ys : Array α} : xs.reverse = ys ↔ xs = ys.reverse
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[grind _=_]theorem filterMap_reverse {f : α → Option β} {xs : Array α} : (xs.reverse.filterMap f) = (xs.filterMap f).reverse := by
|
||||
@[grind _=_] theorem filterMap_reverse {f : α → Option β} {xs : Array α} : (xs.reverse.filterMap f) = (xs.filterMap f).reverse := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -3033,19 +3014,21 @@ theorem take_size {xs : Array α} : xs.take xs.size = xs := by
|
||||
| succ n ih =>
|
||||
simp [shrink.loop, ih]
|
||||
|
||||
@[simp] theorem size_shrink {xs : Array α} {i : Nat} : (xs.shrink i).size = min i xs.size := by
|
||||
-- This doesn't need to be a simp lemma, as shortly we will simplify `shrink` to `take`.
|
||||
theorem size_shrink {xs : Array α} {i : Nat} : (xs.shrink i).size = min i xs.size := by
|
||||
simp [shrink]
|
||||
omega
|
||||
|
||||
@[simp] theorem getElem_shrink {xs : Array α} {i j : Nat} (h : j < (xs.shrink i).size) :
|
||||
(xs.shrink i)[j] = xs[j]'(by simp at h; omega) := by
|
||||
-- This doesn't need to be a simp lemma, as shortly we will simplify `shrink` to `take`.
|
||||
theorem getElem_shrink {xs : Array α} {i j : Nat} (h : j < (xs.shrink i).size) :
|
||||
(xs.shrink i)[j] = xs[j]'(by simp [size_shrink] at h; omega) := by
|
||||
simp [shrink]
|
||||
|
||||
@[simp] theorem toList_shrink {xs : Array α} {i : Nat} : (xs.shrink i).toList = xs.toList.take i := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem shrink_eq_take {xs : Array α} {i : Nat} : xs.shrink i = xs.take i := by
|
||||
ext <;> simp
|
||||
ext <;> simp [size_shrink, getElem_shrink]
|
||||
|
||||
theorem toList_shrink {xs : Array α} {i : Nat} : (xs.shrink i).toList = xs.toList.take i := by
|
||||
simp
|
||||
|
||||
/-! ### foldlM and foldrM -/
|
||||
|
||||
@@ -3214,18 +3197,16 @@ theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Array α} {a : α} {f : β
|
||||
rw [foldr, foldrM_start_stop, ← foldrM_toList, List.foldrM_pure, foldr_toList, foldr, ← foldrM_start_stop]
|
||||
|
||||
theorem foldl_eq_foldlM {f : β → α → β} {b} {xs : Array α} {start stop : Nat} :
|
||||
xs.foldl f b start stop = xs.foldlM (m := Id) f b start stop := by
|
||||
simp [foldl, Id.run]
|
||||
xs.foldl f b start stop = (xs.foldlM (m := Id) (pure <| f · ·) b start stop).run := rfl
|
||||
|
||||
theorem foldr_eq_foldrM {f : α → β → β} {b} {xs : Array α} {start stop : Nat} :
|
||||
xs.foldr f b start stop = xs.foldrM (m := Id) f b start stop := by
|
||||
simp [foldr, Id.run]
|
||||
xs.foldr f b start stop = (xs.foldrM (m := Id) (pure <| f · ·) b start stop).run := rfl
|
||||
|
||||
@[simp] theorem id_run_foldlM {f : β → α → Id β} {b} {xs : Array α} {start stop : Nat} :
|
||||
Id.run (xs.foldlM f b start stop) = xs.foldl f b start stop := foldl_eq_foldlM.symm
|
||||
Id.run (xs.foldlM f b start stop) = xs.foldl (f · · |>.run) b start stop := rfl
|
||||
|
||||
@[simp] theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Array α} {start stop : Nat} :
|
||||
Id.run (xs.foldrM f b start stop) = xs.foldr f b start stop := foldr_eq_foldrM.symm
|
||||
Id.run (xs.foldrM f b start stop) = xs.foldr (f · · |>.run) b start stop := rfl
|
||||
|
||||
/-- Variant of `foldlM_reverse` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem foldlM_reverse' [Monad m] {xs : Array α} {f : β → α → m β} {b} {stop : Nat}
|
||||
@@ -3254,7 +3235,7 @@ theorem foldrM_reverse [Monad m] {xs : Array α} {f : α → β → m β} {b} :
|
||||
|
||||
theorem foldrM_push [Monad m] {f : α → β → m β} {init : β} {xs : Array α} {a : α} :
|
||||
(xs.push a).foldrM f init = f a init >>= xs.foldrM f := by
|
||||
simp only [foldrM_eq_reverse_foldlM_toList, push_toList, List.reverse_append, List.reverse_cons,
|
||||
simp only [foldrM_eq_reverse_foldlM_toList, toList_push, List.reverse_append, List.reverse_cons,
|
||||
List.reverse_nil, List.nil_append, List.singleton_append, List.foldlM_cons, List.foldlM_reverse]
|
||||
|
||||
/--
|
||||
@@ -3266,6 +3247,22 @@ rather than `(arr.push a).size` as the argument.
|
||||
(xs.push a).foldrM f init start = f a init >>= xs.foldrM f := by
|
||||
simp [← foldrM_push, h]
|
||||
|
||||
@[simp, grind] theorem _root_.List.foldrM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldrM (fun x xs => xs.push <$> f x) xs = do return xs ++ (← l.reverse.mapM f).toArray := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp [ih]
|
||||
congr 1
|
||||
funext l'
|
||||
congr 1
|
||||
funext x
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem _root_.List.foldlM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldlM (fun xs x => xs.push <$> f x) xs = do return xs ++ (← l.mapM f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
/-! ### foldl / foldr -/
|
||||
|
||||
@[grind] theorem foldl_empty {f : β → α → β} {init : β} : (#[].foldl f init) = init := rfl
|
||||
@@ -3362,6 +3359,32 @@ rather than `(arr.push a).size` as the argument.
|
||||
rcases as with ⟨as⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem _root_.List.foldr_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldr (fun x xs => xs.push (f x)) xs = xs ++ (l.reverse.map f).toArray := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
/-- Variant of `List.foldr_push_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
|
||||
l.foldr (fun x xs => xs.push x) xs = xs ++ l.reverse.toArray := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem _root_.List.foldl_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldl (fun xs x => xs.push (f x)) xs = xs ++ (l.map f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
/-- Variant of `List.foldl_push_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
|
||||
l.foldl (fun xs x => xs.push x) xs = xs ++ l.toArray := by
|
||||
simpa using List.foldl_push_eq_append (f := id)
|
||||
|
||||
@[deprecated _root_.List.foldl_push_eq_append' (since := "2025-05-18")]
|
||||
theorem _root_.List.foldl_push {l : List α} {as : Array α} : l.foldl Array.push as = as ++ l.toArray := by
|
||||
induction l generalizing as <;> simp [*]
|
||||
|
||||
@[deprecated _root_.List.foldr_push_eq_append' (since := "2025-05-18")]
|
||||
theorem _root_.List.foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
|
||||
rw [List.foldr_eq_foldl_reverse, List.foldl_push_eq_append']
|
||||
|
||||
@[simp, grind] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -3483,17 +3506,16 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
|
||||
|
||||
@[simp] theorem foldr_append' {f : α → β → β} {b} {xs ys : Array α} {start : Nat}
|
||||
(w : start = xs.size + ys.size) :
|
||||
(xs ++ ys).foldr f b start 0 = xs.foldr f (ys.foldr f b) := by
|
||||
subst w
|
||||
simp [foldr_eq_foldrM]
|
||||
(xs ++ ys).foldr f b start 0 = xs.foldr f (ys.foldr f b) :=
|
||||
foldrM_append' w
|
||||
|
||||
@[grind _=_]theorem foldl_append {β : Type _} {f : β → α → β} {b} {xs ys : Array α} :
|
||||
(xs ++ ys).foldl f b = ys.foldl f (xs.foldl f b) := by
|
||||
simp [foldl_eq_foldlM]
|
||||
@[grind _=_] theorem foldl_append {β : Type _} {f : β → α → β} {b} {xs ys : Array α} :
|
||||
(xs ++ ys).foldl f b = ys.foldl f (xs.foldl f b) :=
|
||||
foldlM_append
|
||||
|
||||
@[grind _=_] theorem foldr_append {f : α → β → β} {b} {xs ys : Array α} :
|
||||
(xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b) := by
|
||||
simp [foldr_eq_foldrM]
|
||||
(xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b) :=
|
||||
foldrM_append
|
||||
|
||||
@[simp] theorem foldl_flatten' {f : β → α → β} {b} {xss : Array (Array α)} {stop : Nat}
|
||||
(w : stop = xss.flatten.size) :
|
||||
@@ -3522,21 +3544,22 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
|
||||
/-- Variant of `foldl_reverse` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem foldl_reverse' {xs : Array α} {f : β → α → β} {b} {stop : Nat}
|
||||
(w : stop = xs.size) :
|
||||
xs.reverse.foldl f b 0 stop = xs.foldr (fun x y => f y x) b := by
|
||||
simp [w, foldl_eq_foldlM, foldr_eq_foldrM]
|
||||
xs.reverse.foldl f b 0 stop = xs.foldr (fun x y => f y x) b :=
|
||||
foldlM_reverse' w
|
||||
|
||||
/-- Variant of `foldr_reverse` with a side condition for the `start` argument. -/
|
||||
@[simp] theorem foldr_reverse' {xs : Array α} {f : α → β → β} {b} {start : Nat}
|
||||
(w : start = xs.size) :
|
||||
xs.reverse.foldr f b start 0 = xs.foldl (fun x y => f y x) b := by
|
||||
simp [w, foldl_eq_foldlM, foldr_eq_foldrM]
|
||||
xs.reverse.foldr f b start 0 = xs.foldl (fun x y => f y x) b :=
|
||||
foldrM_reverse' w
|
||||
|
||||
@[grind] theorem foldl_reverse {xs : Array α} {f : β → α → β} {b} :
|
||||
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b := by simp [foldl_eq_foldlM, foldr_eq_foldrM]
|
||||
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
|
||||
foldlM_reverse
|
||||
|
||||
@[grind] theorem foldr_reverse {xs : Array α} {f : α → β → β} {b} :
|
||||
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
foldrM_reverse
|
||||
|
||||
theorem foldl_eq_foldr_reverse {xs : Array α} {f : β → α → β} {b} :
|
||||
xs.foldl f b = xs.reverse.foldr (fun x y => f y x) b := by simp
|
||||
@@ -3617,7 +3640,7 @@ theorem foldr_rel {xs : Array α} {f g : α → β → β} {a b : β} {r : β
|
||||
theorem back?_eq_some_iff {xs : Array α} {a : α} :
|
||||
xs.back? = some a ↔ ∃ ys : Array α, xs = ys.push a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.back?_toArray, List.getLast?_eq_some_iff, toArray_eq, push_toList]
|
||||
simp only [List.back?_toArray, List.getLast?_eq_some_iff, toArray_eq, toList_push]
|
||||
constructor
|
||||
· rintro ⟨ys, rfl⟩
|
||||
exact ⟨ys.toArray, by simp⟩
|
||||
@@ -3742,7 +3765,7 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Array α} {a : α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.contains_iff_exists_mem_beq]
|
||||
|
||||
@[grind]
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.contains a ↔ a ∈ xs := by
|
||||
simp
|
||||
@@ -4051,15 +4074,16 @@ abbrev all_mkArray := @all_replicate
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp] theorem size_modify {xs : Array α} {i : Nat} {f : α → α} : (xs.modify i f).size = xs.size := by
|
||||
unfold modify modifyM Id.run
|
||||
unfold modify modifyM
|
||||
split <;> simp
|
||||
|
||||
theorem getElem_modify {xs : Array α} {j i} (h : i < (xs.modify j f).size) :
|
||||
(xs.modify j f)[i] = if j = i then f (xs[i]'(by simpa using h)) else xs[i]'(by simpa using h) := by
|
||||
simp only [modify, modifyM, Id.run, Id.pure_eq]
|
||||
simp only [modify, modifyM]
|
||||
split
|
||||
· simp only [Id.bind_eq, getElem_set]; split <;> simp [*]
|
||||
· rw [if_neg (mt (by rintro rfl; exact h) (by simp_all))]
|
||||
· simp only [getElem_set, Id.run_pure, Id.run_bind]; split <;> simp [*]
|
||||
· simp only [Id.run_pure]
|
||||
rw [if_neg (mt (by rintro rfl; exact h) (by simp_all))]
|
||||
|
||||
@[simp] theorem toList_modify {xs : Array α} {f : α → α} {i : Nat} :
|
||||
(xs.modify i f).toList = xs.toList.modify i f := by
|
||||
@@ -4387,7 +4411,8 @@ theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i
|
||||
|
||||
/-! # mem -/
|
||||
|
||||
@[simp, grind =] theorem mem_toList {a : α} {xs : Array α} : a ∈ xs.toList ↔ a ∈ xs := mem_def.symm
|
||||
@[deprecated mem_toList_iff (since := "2025-05-26")]
|
||||
theorem mem_toList {a : α} {xs : Array α} : a ∈ xs.toList ↔ a ∈ xs := mem_def.symm
|
||||
|
||||
@[deprecated not_mem_empty (since := "2025-03-25")]
|
||||
theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
|
||||
@@ -4436,7 +4461,7 @@ theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem forIn'_toList [Monad m] {xs : Array α} {b : β} {f : (a : α) → a ∈ xs.toList → β → m (ForInStep β)} :
|
||||
forIn' xs.toList b f = forIn' xs b (fun a m b => f a (mem_toList.mpr m) b) := by
|
||||
forIn' xs.toList b f = forIn' xs b (fun a m b => f a (mem_toList_iff.mpr m) b) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -4533,8 +4558,8 @@ Our goal is to have `simp` "pull `List.toArray` outwards" as much as possible.
|
||||
|
||||
theorem toListRev_toArray {l : List α} : l.toArray.toListRev = l.reverse := by simp
|
||||
|
||||
@[simp, grind =] theorem take_toArray {l : List α} {i : Nat} : l.toArray.take i = (l.take i).toArray := by
|
||||
apply Array.ext <;> simp
|
||||
@[grind =] theorem take_toArray {l : List α} {i : Nat} : l.toArray.take i = (l.take i).toArray := by
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem mapM_toArray [Monad m] [LawfulMonad m] {f : α → m β} {l : List α} :
|
||||
l.toArray.mapM f = List.toArray <$> l.mapM f := by
|
||||
@@ -4600,12 +4625,12 @@ namespace Array
|
||||
@[simp] theorem findSomeRev?_eq_findSome?_reverse {f : α → Option β} {xs : Array α} :
|
||||
xs.findSomeRev? f = xs.reverse.findSome? f := by
|
||||
cases xs
|
||||
simp [findSomeRev?, Id.run]
|
||||
simp [findSomeRev?]
|
||||
|
||||
@[simp] theorem findRev?_eq_find?_reverse {f : α → Bool} {xs : Array α} :
|
||||
xs.findRev? f = xs.reverse.find? f := by
|
||||
cases xs
|
||||
simp [findRev?, Id.run]
|
||||
simp [findRev?]
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
|
||||
@@ -29,16 +29,12 @@ protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {xs ys
|
||||
Decidable.not_not
|
||||
|
||||
@[simp] theorem lex_empty [BEq α] {lt : α → α → Bool} {xs : Array α} : xs.lex #[] lt = false := by
|
||||
simp [lex, Id.run]
|
||||
|
||||
@[simp] theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #[a].lex #[b] lt = lt a b := by
|
||||
simp only [lex, List.getElem_toArray, List.getElem_singleton]
|
||||
cases lt a b <;> cases a != b <;> simp [Id.run]
|
||||
simp [lex]
|
||||
|
||||
private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs ys : Array α} :
|
||||
(#[a] ++ xs).lex (#[b] ++ ys) lt =
|
||||
(lt a b || a == b && xs.lex ys lt) := by
|
||||
simp only [lex, Id.run]
|
||||
simp only [lex]
|
||||
simp only [Std.Range.forIn'_eq_forIn'_range', size_append, List.size_toArray, List.length_singleton,
|
||||
Nat.add_comm 1]
|
||||
simp [Nat.add_min_add_right, List.range'_succ, getElem_append_left, List.range'_succ_left,
|
||||
@@ -51,13 +47,16 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
@[simp, grind =] theorem _root_.List.lex_toArray [BEq α] {lt : α → α → Bool} {l₁ l₂ : List α} :
|
||||
l₁.toArray.lex l₂.toArray lt = l₁.lex l₂ lt := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil => cases l₂ <;> simp [lex, Id.run]
|
||||
| nil => cases l₂ <;> simp [lex]
|
||||
| cons x l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex, Id.run]
|
||||
| nil => simp [lex]
|
||||
| cons y l₂ =>
|
||||
rw [List.toArray_cons, List.toArray_cons y, cons_lex_cons, List.lex, ih]
|
||||
|
||||
theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #[a].lex #[b] lt = lt a b := by
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem lex_toList [BEq α] {lt : α → α → Bool} {xs ys : Array α} :
|
||||
xs.toList.lex ys.toList lt = xs.lex ys lt := by
|
||||
cases xs <;> cases ys <;> simp
|
||||
|
||||
@@ -27,7 +27,7 @@ theorem mapFinIdx_induction (xs : Array α) (f : (i : Nat) → α → (h : i < x
|
||||
motive xs.size ∧ ∃ eq : (Array.mapFinIdx xs f).size = xs.size,
|
||||
∀ i h, p i ((Array.mapFinIdx xs f)[i]) h := by
|
||||
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p i bs[i] h) (hm : motive j) :
|
||||
let as : Array β := Array.mapFinIdxM.map (m := Id) xs f i j h bs
|
||||
let as : Array β := Id.run <| Array.mapFinIdxM.map xs (pure <| f · · ·) i j h bs
|
||||
motive xs.size ∧ ∃ eq : as.size = xs.size, ∀ i h, p i as[i] h := by
|
||||
induction i generalizing j bs with simp [mapFinIdxM.map]
|
||||
| zero =>
|
||||
|
||||
@@ -25,15 +25,29 @@ open Nat
|
||||
|
||||
/-! ## Monadic operations -/
|
||||
|
||||
theorem map_toList_inj [Monad m] [LawfulMonad m]
|
||||
{xs : m (Array α)} {ys : m (Array α)} :
|
||||
toList <$> xs = toList <$> ys ↔ xs = ys := by
|
||||
simp
|
||||
|
||||
/-! ### mapM -/
|
||||
|
||||
@[simp] theorem mapM_pure [Monad m] [LawfulMonad m] {xs : Array α} {f : α → β} :
|
||||
xs.mapM (m := m) (pure <| f ·) = pure (xs.map f) := by
|
||||
induction xs; simp_all
|
||||
|
||||
@[simp] theorem mapM_id {xs : Array α} {f : α → Id β} : xs.mapM f = xs.map f :=
|
||||
@[simp] theorem idRun_mapM {xs : Array α} {f : α → Id β} : (xs.mapM f).run = xs.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[deprecated idRun_mapM (since := "2025-05-21")]
|
||||
theorem mapM_id {xs : Array α} {f : α → Id β} : xs.mapM f = xs.map f :=
|
||||
mapM_pure
|
||||
|
||||
@[simp] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {xs : Array α} :
|
||||
(xs.map f).mapM g = xs.mapM (g ∘ f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {xs ys : Array α} :
|
||||
(xs ++ ys).mapM f = (return (← xs.mapM f) ++ (← ys.mapM f)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -181,12 +195,18 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
theorem idRun_forIn'_yield_eq_foldl
|
||||
{xs : Array α} (f : (a : α) → a ∈ xs → β → Id β) (init : β) :
|
||||
(forIn' xs init (fun a m b => .yield <$> f a m b)).run =
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated idRun_forIn'_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn'_yield_eq_foldl
|
||||
{xs : Array α} (f : (a : α) → a ∈ xs → β → β) (init : β) :
|
||||
forIn' (m := Id) xs init (fun a m b => .yield (f a m b)) =
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.foldl_map]
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} (g : α → β) (f : (b : β) → b ∈ xs.map g → γ → m (ForInStep γ)) :
|
||||
@@ -223,12 +243,18 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
theorem idRun_forIn_yield_eq_foldl
|
||||
{xs : Array α} (f : α → β → Id β) (init : β) :
|
||||
(forIn xs init (fun a b => .yield <$> f a b)).run =
|
||||
xs.foldl (fun b a => f a b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated idRun_forIn_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn_yield_eq_foldl
|
||||
{xs : Array α} (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) xs init (fun a b => .yield (f a b)) =
|
||||
xs.foldl (fun b a => f a b) init := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.foldl_map]
|
||||
xs.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} {g : α → β} {f : β → γ → m (ForInStep γ)} :
|
||||
|
||||
@@ -8,7 +8,9 @@ module
|
||||
prelude
|
||||
import all Init.Data.Array.Basic
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Monadic
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.List.FinRange
|
||||
|
||||
/-!
|
||||
# Theorems about `Array.ofFn`
|
||||
@@ -19,6 +21,8 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
||||
|
||||
namespace Array
|
||||
|
||||
/-! ### ofFn -/
|
||||
|
||||
@[simp] theorem ofFn_zero {f : Fin 0 → α} : ofFn f = #[] := by
|
||||
simp [ofFn, ofFn.go]
|
||||
|
||||
@@ -32,12 +36,23 @@ theorem ofFn_succ {f : Fin (n+1) → α} :
|
||||
intro h₃
|
||||
simp only [show i = n by omega]
|
||||
|
||||
theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
ofFn f = (ofFn (fun i => f (i.castLE (Nat.le_add_right n m)))) ++ (ofFn (fun i => f (i.natAdd n))) := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => simp [ofFn_succ, ih]
|
||||
|
||||
@[simp] theorem _root_.List.toArray_ofFn {f : Fin n → α} : (List.ofFn f).toArray = Array.ofFn f := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem toList_ofFn {f : Fin n → α} : (Array.ofFn f).toList = List.ofFn f := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
theorem ofFn_succ' {f : Fin (n+1) → α} :
|
||||
ofFn f = #[f 0] ++ ofFn (fun i => f i.succ) := by
|
||||
apply Array.toList_inj.mp
|
||||
simp [List.ofFn_succ]
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_empty_iff {f : Fin n → α} : ofFn f = #[] ↔ n = 0 := by
|
||||
rw [← Array.toList_inj]
|
||||
@@ -52,4 +67,70 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
/-! ### ofFnM -/
|
||||
|
||||
/-- Construct (in a monadic context) an array by applying a monadic function to each index. -/
|
||||
def ofFnM {n} [Monad m] (f : Fin n → m α) : m (Array α) :=
|
||||
Fin.foldlM n (fun xs i => xs.push <$> f i) (Array.emptyWithCapacity n)
|
||||
|
||||
@[simp]
|
||||
theorem ofFnM_zero [Monad m] {f : Fin 0 → m α} : ofFnM f = pure #[] := by
|
||||
simp [ofFnM]
|
||||
|
||||
theorem ofFnM_succ' {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let a ← f 0
|
||||
let as ← ofFnM fun i => f i.succ
|
||||
pure (#[a] ++ as)) := by
|
||||
simp [ofFnM, Fin.foldlM_eq_foldlM_finRange, List.foldlM_push_eq_append, List.finRange_succ, Function.comp_def]
|
||||
|
||||
theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i => f i.castSucc
|
||||
let a ← f (Fin.last n)
|
||||
pure (as.push a)) := by
|
||||
simp [ofFnM, Fin.foldlM_succ_last]
|
||||
|
||||
theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i : Fin n => f (i.castLE (Nat.le_add_right n k))
|
||||
let bs ← ofFnM fun i : Fin k => f (i.natAdd n)
|
||||
pure (as ++ bs)) := by
|
||||
induction k with
|
||||
| zero => simp
|
||||
| succ k ih =>
|
||||
simp only [ofFnM_succ, Nat.add_eq, ih, Fin.castSucc_castLE, Fin.castSucc_natAdd, bind_pure_comp,
|
||||
bind_assoc, bind_map_left, Fin.natAdd_last, map_bind, Functor.map_map]
|
||||
congr 1
|
||||
funext xs
|
||||
congr 1
|
||||
funext ys
|
||||
congr 1
|
||||
funext x
|
||||
simp
|
||||
|
||||
@[simp] theorem toList_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
toList <$> ofFnM f = List.ofFnM f := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ofFnM_succ, List.ofFnM_succ_last, ← ih]
|
||||
|
||||
@[simp]
|
||||
theorem ofFnM_pure_comp [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (pure ∘ f) = (pure (ofFn f) : m (Array α)) := by
|
||||
apply Array.map_toList_inj.mp
|
||||
simp
|
||||
|
||||
-- Variant of `ofFnM_pure_comp` using a lambda.
|
||||
-- This is not marked a `@[simp]` as it would match on every occurrence of `ofFnM`.
|
||||
theorem ofFnM_pure [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (fun i => pure (f i)) = (pure (ofFn f) : m (Array α)) :=
|
||||
ofFnM_pure_comp
|
||||
|
||||
@[simp, grind =] theorem idRun_ofFnM {f : Fin n → Id α} :
|
||||
Id.run (ofFnM f) = ofFn (fun i => Id.run (f i)) := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ofFnM_succ', ofFn_succ', ih]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -27,23 +27,27 @@ Internal implementation of `Array.qsort`.
|
||||
|
||||
It does so by first swapping the elements at indices `lo`, `mid := (lo + hi) / 2`, and `hi`
|
||||
if necessary so that the middle (pivot) element is at index `hi`.
|
||||
We then iterate from `j = lo` to `j = hi`, with a pointer `i` starting at `lo`, and
|
||||
We then iterate from `k = lo` to `k = hi`, with a pointer `i` starting at `lo`, and
|
||||
swapping each element which is less than the pivot to position `i`, and then incrementing `i`.
|
||||
-/
|
||||
def qpartition {n} (as : Vector α n) (lt : α → α → Bool) (lo hi : Nat)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) : {m : Nat // lo ≤ m ∧ m < n} × Vector α n :=
|
||||
def qpartition {n} (as : Vector α n) (lt : α → α → Bool) (lo hi : Nat) (w : lo ≤ hi := by omega)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) : {m : Nat // lo ≤ m ∧ m ≤ hi} × Vector α n :=
|
||||
let mid := (lo + hi) / 2
|
||||
let as := if lt as[mid] as[lo] then as.swap lo mid else as
|
||||
let as := if lt as[hi] as[lo] then as.swap lo hi else as
|
||||
let as := if lt as[mid] as[hi] then as.swap mid hi else as
|
||||
let pivot := as[hi]
|
||||
let rec loop (as : Vector α n) (i j : Nat)
|
||||
(ilo : lo ≤ i := by omega) (jh : j < n := by omega) (w : i ≤ j := by omega) :=
|
||||
if h : j < hi then
|
||||
if lt as[j] pivot then
|
||||
loop (as.swap i j) (i+1) (j+1)
|
||||
-- During this loop, elements below in `[lo, i)` are less than `pivot`,
|
||||
-- elements in `[i, k)` are greater than or equal to `pivot`,
|
||||
-- elements in `[k, hi)` are unexamined,
|
||||
-- while `as[hi]` is (by definition) the pivot.
|
||||
let rec loop (as : Vector α n) (i k : Nat)
|
||||
(ilo : lo ≤ i := by omega) (ik : i ≤ k := by omega) (w : k ≤ hi := by omega) :=
|
||||
if h : k < hi then
|
||||
if lt as[k] pivot then
|
||||
loop (as.swap i k) (i+1) (k+1)
|
||||
else
|
||||
loop as i (j+1)
|
||||
loop as i (k+1)
|
||||
else
|
||||
(⟨i, ilo, by omega⟩, as.swap i hi)
|
||||
loop as lo lo
|
||||
@@ -51,25 +55,28 @@ def qpartition {n} (as : Vector α n) (lt : α → α → Bool) (lo hi : Nat)
|
||||
/--
|
||||
In-place quicksort.
|
||||
|
||||
`qsort as lt low high` sorts the subarray `as[low:high+1]` in-place using `lt` to compare elements.
|
||||
`qsort as lt lo hi` sorts the subarray `as[lo:hi+1]` in-place using `lt` to compare elements.
|
||||
-/
|
||||
@[inline] def qsort (as : Array α) (lt : α → α → Bool := by exact (· < ·))
|
||||
(low := 0) (high := as.size - 1) : Array α :=
|
||||
let rec @[specialize] sort {n} (as : Vector α n) (lo hi : Nat)
|
||||
(lo := 0) (hi := as.size - 1) : Array α :=
|
||||
let rec @[specialize] sort {n} (as : Vector α n) (lo hi : Nat) (w : lo ≤ hi := by omega)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) :=
|
||||
if h₁ : lo < hi then
|
||||
let ⟨⟨mid, hmid⟩, as⟩ := qpartition as lt lo hi
|
||||
if h₂ : mid ≥ hi then
|
||||
-- This only occurs when `hi ≤ lo`,
|
||||
-- and thus `as[lo:hi+1]` is trivially already sorted.
|
||||
as
|
||||
else
|
||||
-- Otherwise, we recursively sort the two subarrays.
|
||||
sort (sort as lo mid) (mid+1) hi
|
||||
else as
|
||||
if h : as.size = 0 then
|
||||
as
|
||||
else
|
||||
let low := min low (as.size - 1)
|
||||
let high := min high (as.size - 1)
|
||||
sort as.toVector low high |>.toArray
|
||||
let lo := min lo (as.size - 1)
|
||||
let hi := max lo (min hi (as.size - 1))
|
||||
sort as.toVector lo hi |>.toArray
|
||||
|
||||
set_option linter.unusedVariables.funArgs false in
|
||||
/--
|
||||
|
||||
@@ -290,7 +290,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Subarray α) : β :=
|
||||
Id.run <| as.foldlM f (init := init)
|
||||
Id.run <| as.foldlM (pure <| f · ·) (init := init)
|
||||
|
||||
/--
|
||||
Folds an operation from right to left over the elements in a subarray.
|
||||
@@ -304,7 +304,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def foldr {α : Type u} {β : Type v} (f : α → β → β) (init : β) (as : Subarray α) : β :=
|
||||
Id.run <| as.foldrM f (init := init)
|
||||
Id.run <| as.foldrM (pure <| f · ·) (init := init)
|
||||
|
||||
/--
|
||||
Checks whether any of the elements in a subarray satisfy a Boolean predicate.
|
||||
@@ -314,7 +314,7 @@ an element that satisfies the predicate is found.
|
||||
-/
|
||||
@[inline]
|
||||
def any {α : Type u} (p : α → Bool) (as : Subarray α) : Bool :=
|
||||
Id.run <| as.anyM p
|
||||
Id.run <| as.anyM (pure <| p ·)
|
||||
|
||||
/--
|
||||
Checks whether all of the elements in a subarray satisfy a Boolean predicate.
|
||||
@@ -324,7 +324,7 @@ an element that does not satisfy the predicate is found.
|
||||
-/
|
||||
@[inline]
|
||||
def all {α : Type u} (p : α → Bool) (as : Subarray α) : Bool :=
|
||||
Id.run <| as.allM p
|
||||
Id.run <| as.allM (pure <| p ·)
|
||||
|
||||
/--
|
||||
Applies a monadic function to each element in a subarray in reverse order, stopping at the first
|
||||
@@ -394,7 +394,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def findRev? {α : Type} (as : Subarray α) (p : α → Bool) : Option α :=
|
||||
Id.run <| as.findRevM? p
|
||||
Id.run <| as.findRevM? (pure <| p ·)
|
||||
|
||||
end Subarray
|
||||
|
||||
|
||||
@@ -334,11 +334,13 @@ abbrev zipWithAll_mkArray := @zipWithAll_replicate
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[simp] theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
induction l <;> simp_all
|
||||
@[deprecated fst_unzip (since := "2025-05-26")]
|
||||
theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
simp
|
||||
|
||||
@[simp] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
induction l <;> simp_all
|
||||
@[deprecated snd_unzip (since := "2025-05-26")]
|
||||
theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
simp
|
||||
|
||||
theorem unzip_eq_map {xs : Array (α × β)} : unzip xs = (xs.map Prod.fst, xs.map Prod.snd) := by
|
||||
cases xs
|
||||
@@ -371,7 +373,7 @@ theorem unzip_zip {as : Array α} {bs : Array β} (h : as.size = bs.size) :
|
||||
|
||||
theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl : xs.map Prod.fst = as)
|
||||
(hr : xs.map Prod.snd = bs) : xs = as.zip bs := by
|
||||
rw [← hl, ← hr, ← zip_unzip xs, ← unzip_fst, ← unzip_snd, zip_unzip, zip_unzip]
|
||||
rw [← hl, ← hr, ← zip_unzip xs, ← fst_unzip, ← snd_unzip, zip_unzip, zip_unzip]
|
||||
|
||||
@[simp] theorem unzip_replicate {n : Nat} {a : α} {b : β} :
|
||||
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
|
||||
|
||||
@@ -68,11 +68,11 @@ theorem lt_of_getMsbD {x : BitVec w} {i : Nat} : getMsbD x i = true → i < w :=
|
||||
@[simp] theorem getElem?_eq_getElem {l : BitVec w} {n} (h : n < w) : l[n]? = some l[n] := by
|
||||
simp only [getElem?_def, h, ↓reduceDIte]
|
||||
|
||||
theorem getElem?_eq_some_iff {l : BitVec w} : l[n]? = some a ↔ ∃ h : n < w, l[n] = a := by
|
||||
simp only [getElem?_def]
|
||||
split
|
||||
· simp_all
|
||||
· simp; omega
|
||||
theorem getElem?_eq_some_iff {l : BitVec w} : l[n]? = some a ↔ ∃ h : n < w, l[n] = a :=
|
||||
_root_.getElem?_eq_some_iff
|
||||
|
||||
theorem some_eq_getElem?_iff {l : BitVec w} : some a = l[n]? ↔ ∃ h : n < w, l[n] = a :=
|
||||
_root_.some_eq_getElem?_iff
|
||||
|
||||
theorem getElem_of_getElem? {l : BitVec w} : l[n]? = some a → ∃ h : n < w, l[n] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
@@ -81,11 +81,11 @@ set_option linter.missingDocs false in
|
||||
@[deprecated getElem?_eq_some_iff (since := "2025-02-17")]
|
||||
abbrev getElem?_eq_some := @getElem?_eq_some_iff
|
||||
|
||||
@[simp] theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none ↔ w ≤ n := by
|
||||
simp only [getElem?_def]
|
||||
split
|
||||
· simp_all
|
||||
· simp; omega
|
||||
theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none ↔ w ≤ n := by
|
||||
simp
|
||||
|
||||
theorem none_eq_getElem?_iff {l : BitVec w} : none = l[n]? ↔ w ≤ n := by
|
||||
simp
|
||||
|
||||
theorem getElem?_eq_none {l : BitVec w} (h : w ≤ n) : l[n]? = none := getElem?_eq_none_iff.mpr h
|
||||
|
||||
@@ -93,13 +93,13 @@ theorem getElem?_eq (l : BitVec w) (i : Nat) :
|
||||
l[i]? = if h : i < w then some l[i] else none := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem? (l : BitVec w) (i : Nat) (h : i < w) :
|
||||
theorem some_getElem_eq_getElem? (l : BitVec w) (i : Nat) (h : i < w) :
|
||||
(some l[i] = l[i]?) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_eq_some_getElem (l : BitVec w) (i : Nat) (h : i < w) :
|
||||
theorem getElem?_eq_some_getElem (l : BitVec w) (i : Nat) (h : i < w) :
|
||||
(l[i]? = some l[i]) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
theorem getElem_eq_iff {l : BitVec w} {n : Nat} {h : n < w} : l[n] = x ↔ l[n]? = some x := by
|
||||
simp only [getElem?_eq_some_iff]
|
||||
@@ -505,7 +505,7 @@ theorem getLsbD_ofBool (b : Bool) (i : Nat) : (ofBool b).getLsbD i = ((i = 0) &&
|
||||
· simp only [ofBool, ofNat_eq_ofNat, cond_true, getLsbD_ofNat, Bool.and_true]
|
||||
by_cases hi : i = 0 <;> simp [hi] <;> omega
|
||||
|
||||
@[simp] theorem getElem_ofBool_zero {b : Bool} : (ofBool b)[0] = b := by simp
|
||||
theorem getElem_ofBool_zero {b : Bool} : (ofBool b)[0] = b := by simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem_ofBool {b : Bool} {h : i < 1}: (ofBool b)[i] = b := by
|
||||
@@ -3179,12 +3179,12 @@ theorem getElem_concat (x : BitVec w) (b : Bool) (i : Nat) (h : i < w + 1) :
|
||||
· simp [Nat.mod_eq_of_lt b.toNat_lt]
|
||||
· simp [Nat.div_eq_of_lt b.toNat_lt, Nat.testBit_add_one]
|
||||
|
||||
@[simp] theorem getLsbD_concat_zero : (concat x b).getLsbD 0 = b := by
|
||||
simp [getElem_concat]
|
||||
|
||||
@[simp] theorem getElem_concat_zero : (concat x b)[0] = b := by
|
||||
simp [getElem_concat]
|
||||
|
||||
theorem getLsbD_concat_zero : (concat x b).getLsbD 0 = b := by
|
||||
simp
|
||||
|
||||
@[simp] theorem getLsbD_concat_succ : (concat x b).getLsbD (i + 1) = x.getLsbD i := by
|
||||
simp [getLsbD_concat]
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 →
|
||||
|
||||
@[inline]
|
||||
def foldl {β : Type v} (f : β → UInt8 → β) (init : β) (as : ByteArray) (start := 0) (stop := as.size) : β :=
|
||||
Id.run <| as.foldlM f init start stop
|
||||
Id.run <| as.foldlM (pure <| f · ·) init start stop
|
||||
|
||||
/-- Iterator over the bytes (`UInt8`) of a `ByteArray`.
|
||||
|
||||
|
||||
@@ -100,6 +100,11 @@ Fin.foldrM n f xₙ = do
|
||||
|
||||
/-! ### foldlM -/
|
||||
|
||||
@[congr] theorem foldlM_congr [Monad m] {n k : Nat} (w : n = k) (f : α → Fin n → m α) :
|
||||
foldlM n f = foldlM k (fun x i => f x (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
|
||||
foldlM.loop n f x i = f x ⟨i, h⟩ >>= (foldlM.loop n f . (i+1)) := by
|
||||
rw [foldlM.loop, dif_pos h]
|
||||
@@ -120,14 +125,49 @@ theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1)
|
||||
rw [foldlM_loop_eq, foldlM_loop_eq]
|
||||
termination_by n - i
|
||||
|
||||
@[simp] theorem foldlM_zero [Monad m] (f : α → Fin 0 → m α) (x) : foldlM 0 f x = pure x :=
|
||||
foldlM_loop_eq ..
|
||||
@[simp] theorem foldlM_zero [Monad m] (f : α → Fin 0 → m α) : foldlM 0 f = pure := by
|
||||
funext x
|
||||
exact foldlM_loop_eq ..
|
||||
|
||||
theorem foldlM_succ [Monad m] (f : α → Fin (n+1) → m α) (x) :
|
||||
foldlM (n+1) f x = f x 0 >>= foldlM n (fun x j => f x j.succ) := foldlM_loop ..
|
||||
theorem foldlM_succ [Monad m] (f : α → Fin (n+1) → m α) :
|
||||
foldlM (n+1) f = fun x => f x 0 >>= foldlM n (fun x j => f x j.succ) := by
|
||||
funext x
|
||||
exact foldlM_loop ..
|
||||
|
||||
/-- Variant of `foldlM_succ` that splits off `Fin.last n` rather than `0`. -/
|
||||
theorem foldlM_succ_last [Monad m] [LawfulMonad m] (f : α → Fin (n+1) → m α) :
|
||||
foldlM (n+1) f = fun x => foldlM n (fun x j => f x j.castSucc) x >>= (f · (Fin.last n)) := by
|
||||
funext x
|
||||
induction n generalizing x with
|
||||
| zero =>
|
||||
simp [foldlM_succ]
|
||||
| succ n ih =>
|
||||
rw [foldlM_succ]
|
||||
conv => rhs; rw [foldlM_succ]
|
||||
simp only [castSucc_zero, castSucc_succ, bind_assoc]
|
||||
congr 1
|
||||
funext x
|
||||
rw [ih]
|
||||
simp
|
||||
|
||||
theorem foldlM_add [Monad m] [LawfulMonad m] (f : α → Fin (n + k) → m α) :
|
||||
foldlM (n + k) f =
|
||||
fun x => foldlM n (fun x i => f x (i.castLE (Nat.le_add_right n k))) x >>= foldlM k (fun x i => f x (i.natAdd n)) := by
|
||||
induction k with
|
||||
| zero =>
|
||||
funext x
|
||||
simp
|
||||
| succ k ih =>
|
||||
funext x
|
||||
simp [foldlM_succ_last, ← Nat.add_assoc, ih]
|
||||
|
||||
/-! ### foldrM -/
|
||||
|
||||
@[congr] theorem foldrM_congr [Monad m] {n k : Nat} (w : n = k) (f : Fin n → α → m α) :
|
||||
foldrM n f = foldrM k (fun i => f (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
|
||||
foldrM.loop n f ⟨0, Nat.zero_le _⟩ x = pure x := by
|
||||
rw [foldrM.loop]
|
||||
@@ -145,19 +185,47 @@ theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x
|
||||
conv => rhs; rw [←bind_pure (f 0 x)]
|
||||
congr
|
||||
funext
|
||||
try simp only [foldrM.loop] -- the try makes this proof work with and without opaque wf rec
|
||||
simp [foldrM_loop_zero]
|
||||
| succ i ih =>
|
||||
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
||||
congr; funext; exact ih ..
|
||||
|
||||
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 → α → m α) (x) : foldrM 0 f x = pure x :=
|
||||
foldrM_loop_zero ..
|
||||
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 → α → m α) : foldrM 0 f = pure := by
|
||||
funext x
|
||||
exact foldrM_loop_zero ..
|
||||
|
||||
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) :
|
||||
foldrM (n+1) f x = foldrM n (fun i => f i.succ) x >>= f 0 := foldrM_loop ..
|
||||
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) :
|
||||
foldrM (n+1) f = fun x => foldrM n (fun i => f i.succ) x >>= f 0 := by
|
||||
funext x
|
||||
exact foldrM_loop ..
|
||||
|
||||
theorem foldrM_succ_last [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) :
|
||||
foldrM (n+1) f = fun x => f (Fin.last n) x >>= foldrM n (fun i => f i.castSucc) := by
|
||||
funext x
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldrM_succ]
|
||||
| succ n ih =>
|
||||
rw [foldrM_succ]
|
||||
conv => rhs; rw [foldrM_succ]
|
||||
simp [ih]
|
||||
|
||||
theorem foldrM_add [Monad m] [LawfulMonad m] (f : Fin (n + k) → α → m α) :
|
||||
foldrM (n + k) f =
|
||||
fun x => foldrM k (fun i => f (i.natAdd n)) x >>= foldrM n (fun i => f (i.castLE (Nat.le_add_right n k))) := by
|
||||
induction k with
|
||||
| zero =>
|
||||
simp
|
||||
| succ k ih =>
|
||||
funext x
|
||||
simp [foldrM_succ_last, ← Nat.add_assoc, ih]
|
||||
|
||||
/-! ### foldl -/
|
||||
|
||||
@[congr] theorem foldl_congr {n k : Nat} (w : n = k) (f : α → Fin n → α) :
|
||||
foldl n f = foldl k (fun x i => f x (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
|
||||
foldl.loop n f x i = foldl.loop n f (f x ⟨i, h⟩) (i+1) := by
|
||||
rw [foldl.loop, dif_pos h]
|
||||
@@ -187,14 +255,34 @@ theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) :
|
||||
rw [foldl_succ]
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldl_succ, Fin.last]
|
||||
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp [succ_castSucc]
|
||||
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp
|
||||
|
||||
theorem foldl_add (f : α → Fin (n + m) → α) (x) :
|
||||
foldl (n + m) f x =
|
||||
foldl m (fun x i => f x (i.natAdd n))
|
||||
(foldl n (fun x i => f x (i.castLE (Nat.le_add_right n m))) x):= by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => simp [foldl_succ_last, ih, ← Nat.add_assoc]
|
||||
|
||||
theorem foldl_eq_foldlM (f : α → Fin n → α) (x) :
|
||||
foldl n f x = foldlM (m:=Id) n f x := by
|
||||
foldl n f x = (foldlM (m := Id) n (pure <| f · ·) x).run := by
|
||||
induction n generalizing x <;> simp [foldl_succ, foldlM_succ, *]
|
||||
|
||||
-- This is not marked `@[simp]` as it would match on every occurrence of `foldlM`.
|
||||
theorem foldlM_pure [Monad m] [LawfulMonad m] {n} {f : α → Fin n → α} :
|
||||
foldlM n (fun x i => pure (f x i)) x = (pure (foldl n f x) : m α) := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih => simp [foldlM_succ, foldl_succ, ih]
|
||||
|
||||
/-! ### foldr -/
|
||||
|
||||
@[congr] theorem foldr_congr {n k : Nat} (w : n = k) (f : Fin n → α → α) :
|
||||
foldr n f = foldr k (fun i => f (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
foldr.loop n f 0 (Nat.zero_le _) x = x := by
|
||||
rw [foldr.loop]
|
||||
@@ -220,10 +308,18 @@ theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) :
|
||||
foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldr_succ, Fin.last]
|
||||
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp [succ_castSucc]
|
||||
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp
|
||||
|
||||
theorem foldr_add (f : Fin (n + m) → α → α) (x) :
|
||||
foldr (n + m) f x =
|
||||
foldr n (fun i => f (i.castLE (Nat.le_add_right n m)))
|
||||
(foldr m (fun i => f (i.natAdd n)) x) := by
|
||||
induction m generalizing x with
|
||||
| zero => simp
|
||||
| succ m ih => simp [foldr_succ_last, ih, ← Nat.add_assoc]
|
||||
|
||||
theorem foldr_eq_foldrM (f : Fin n → α → α) (x) :
|
||||
foldr n f x = foldrM (m:=Id) n f x := by
|
||||
foldr n f x = (foldrM (m := Id) n (pure <| f · ·) x).run := by
|
||||
induction n <;> simp [foldr_succ, foldrM_succ, *]
|
||||
|
||||
theorem foldl_rev (f : Fin n → α → α) (x) :
|
||||
@@ -238,4 +334,11 @@ theorem foldr_rev (f : α → Fin n → α) (x) :
|
||||
| zero => simp
|
||||
| succ n ih => rw [foldl_succ_last, foldr_succ, ← ih]; simp [rev_succ]
|
||||
|
||||
-- This is not marked `@[simp]` as it would match on every occurrence of `foldrM`.
|
||||
theorem foldrM_pure [Monad m] [LawfulMonad m] {n} {f : Fin n → α → α} :
|
||||
foldrM n (fun i x => pure (f i x)) x = (pure (foldr n f x) : m α) := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih => simp [foldrM_succ, foldr_succ, ih]
|
||||
|
||||
end Fin
|
||||
|
||||
@@ -646,6 +646,20 @@ theorem rev_castSucc (k : Fin n) : rev (castSucc k) = succ (rev k) := k.rev_cast
|
||||
|
||||
theorem rev_succ (k : Fin n) : rev (succ k) = castSucc (rev k) := k.rev_addNat 1
|
||||
|
||||
@[simp, grind _=_]
|
||||
theorem castSucc_succ (i : Fin n) : i.succ.castSucc = i.castSucc.succ := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
theorem castLE_refl (h : n ≤ n) (i : Fin n) : i.castLE h = i := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
theorem castSucc_castLE (h : n ≤ m) (i : Fin n) :
|
||||
(i.castLE h).castSucc = i.castLE (by omega) := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
theorem castSucc_natAdd (n : Nat) (i : Fin k) :
|
||||
(i.natAdd n).castSucc = (i.castSucc).natAdd n := rfl
|
||||
|
||||
/-! ### pred -/
|
||||
|
||||
@[simp] theorem coe_pred (j : Fin (n + 1)) (h : j ≠ 0) : (j.pred h : Nat) = j - 1 := rfl
|
||||
|
||||
@@ -161,8 +161,7 @@ This function does not reduce in the kernel. It is compiled to the C inequality
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => floatSpec.decLe a b
|
||||
|
||||
instance floatDecLt (a b : Float) : Decidable (a < b) := Float.decLt a b
|
||||
instance floatDecLe (a b : Float) : Decidable (a ≤ b) := Float.decLe a b
|
||||
attribute [instance] Float.decLt Float.decLe
|
||||
|
||||
/--
|
||||
Converts a floating-point number to a string.
|
||||
|
||||
@@ -145,7 +145,7 @@ Compares two floating point numbers for strict inequality.
|
||||
|
||||
This function does not reduce in the kernel. It is compiled to the C inequality operator.
|
||||
-/
|
||||
@[extern "lean_float32_decLt"] opaque Float32.decLt (a b : Float32) : Decidable (a < b) :=
|
||||
@[extern "lean_float32_decLt", instance] opaque Float32.decLt (a b : Float32) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => float32Spec.decLt a b
|
||||
|
||||
@@ -154,13 +154,10 @@ Compares two floating point numbers for non-strict inequality.
|
||||
|
||||
This function does not reduce in the kernel. It is compiled to the C inequality operator.
|
||||
-/
|
||||
@[extern "lean_float32_decLe"] opaque Float32.decLe (a b : Float32) : Decidable (a ≤ b) :=
|
||||
@[extern "lean_float32_decLe", instance] opaque Float32.decLe (a b : Float32) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => float32Spec.decLe a b
|
||||
|
||||
instance float32DecLt (a b : Float32) : Decidable (a < b) := Float32.decLt a b
|
||||
instance float32DecLe (a b : Float32) : Decidable (a ≤ b) := Float32.decLe a b
|
||||
|
||||
/--
|
||||
Converts a floating-point number to a string.
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → Float →
|
||||
|
||||
@[inline]
|
||||
def foldl {β : Type v} (f : β → Float → β) (init : β) (as : FloatArray) (start := 0) (stop := as.size) : β :=
|
||||
Id.run <| as.foldlM f init start stop
|
||||
Id.run <| as.foldlM (pure <| f · ·) init start stop
|
||||
|
||||
end FloatArray
|
||||
|
||||
|
||||
@@ -57,9 +57,6 @@ instance : Hashable UInt64 where
|
||||
instance : Hashable USize where
|
||||
hash n := n.toUInt64
|
||||
|
||||
instance : Hashable ByteArray where
|
||||
hash as := as.foldl (fun r a => mixHash r (hash a)) 7
|
||||
|
||||
instance : Hashable (Fin n) where
|
||||
hash v := v.val.toUInt64
|
||||
|
||||
|
||||
@@ -264,8 +264,8 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_emod_self_left]
|
||||
|
||||
@[simp] theorem emod_emod (a b : Int) : (a % b) % b = a % b := by
|
||||
conv => rhs; rw [← emod_add_ediv a b, add_mul_emod_self_left]
|
||||
theorem emod_emod (a b : Int) : (a % b) % b = a % b := by
|
||||
simp
|
||||
|
||||
theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
|
||||
apply (emod_add_cancel_right b).mp
|
||||
|
||||
@@ -1410,8 +1410,7 @@ theorem mul_tmod (a b n : Int) : (a * b).tmod n = (a.tmod n * b.tmod n).tmod n :
|
||||
norm_cast at h
|
||||
rw [Nat.mod_mod_of_dvd _ h]
|
||||
|
||||
@[simp] theorem tmod_tmod (a b : Int) : (a.tmod b).tmod b = a.tmod b :=
|
||||
tmod_tmod_of_dvd a (Int.dvd_refl b)
|
||||
theorem tmod_tmod (a b : Int) : (a.tmod b).tmod b = a.tmod b := by simp
|
||||
|
||||
theorem tmod_eq_zero_of_dvd : ∀ {a b : Int}, a ∣ b → tmod b a = 0
|
||||
| _, _, ⟨_, rfl⟩ => mul_tmod_right ..
|
||||
@@ -1469,9 +1468,8 @@ protected theorem tdiv_mul_cancel {a b : Int} (H : b ∣ a) : a.tdiv b * b = a :
|
||||
protected theorem mul_tdiv_cancel' {a b : Int} (H : a ∣ b) : a * b.tdiv a = b := by
|
||||
rw [Int.mul_comm, Int.tdiv_mul_cancel H]
|
||||
|
||||
@[simp] theorem neg_tmod_self (a : Int) : (-a).tmod a = 0 := by
|
||||
rw [← dvd_iff_tmod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_refl a
|
||||
theorem neg_tmod_self (a : Int) : (-a).tmod a = 0 := by
|
||||
simp
|
||||
|
||||
theorem lt_tdiv_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.tdiv b + 1) * b := by
|
||||
rw [Int.add_mul, Int.one_mul, Int.mul_comm]
|
||||
@@ -1568,13 +1566,11 @@ theorem dvd_tmod_sub_self {x m : Int} : m ∣ x.tmod m - x := by
|
||||
theorem dvd_self_sub_tmod {x m : Int} : m ∣ x - x.tmod m :=
|
||||
Int.dvd_neg.1 (by simpa only [Int.neg_sub] using dvd_tmod_sub_self)
|
||||
|
||||
@[simp] theorem neg_mul_tmod_right (a b : Int) : (-(a * b)).tmod a = 0 := by
|
||||
rw [← dvd_iff_tmod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_mul_right a b
|
||||
theorem neg_mul_tmod_right (a b : Int) : (-(a * b)).tmod a = 0 := by
|
||||
simp
|
||||
|
||||
@[simp] theorem neg_mul_tmod_left (a b : Int) : (-(a * b)).tmod b = 0 := by
|
||||
rw [← dvd_iff_tmod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_mul_left a b
|
||||
theorem neg_mul_tmod_left (a b : Int) : (-(a * b)).tmod b = 0 := by
|
||||
simp
|
||||
|
||||
@[simp] protected theorem tdiv_one : ∀ a : Int, a.tdiv 1 = a
|
||||
| (n:Nat) => congrArg ofNat (Nat.div_one _)
|
||||
@@ -2193,8 +2189,8 @@ theorem mul_fmod (a b n : Int) : (a * b).fmod n = (a.fmod n * b.fmod n).fmod n :
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_fmod_self_left]
|
||||
|
||||
@[simp] theorem fmod_fmod (a b : Int) : (a.fmod b).fmod b = a.fmod b :=
|
||||
fmod_fmod_of_dvd _ (Int.dvd_refl b)
|
||||
theorem fmod_fmod (a b : Int) : (a.fmod b).fmod b = a.fmod b := by
|
||||
simp
|
||||
|
||||
theorem sub_fmod (a b n : Int) : (a - b).fmod n = (a.fmod n - b.fmod n).fmod n := by
|
||||
apply (fmod_add_cancel_right b).mp
|
||||
|
||||
@@ -121,7 +121,7 @@ theorem toNat_lt_toNat {n m : Int} (hn : 0 < m) : n.toNat < m.toNat ↔ n < m :=
|
||||
/-! ### min and max -/
|
||||
|
||||
@[simp] protected theorem min_assoc : ∀ (a b c : Int), min (min a b) c = min a (min b c) := by omega
|
||||
instance : Std.Associative (α := Nat) min := ⟨Nat.min_assoc⟩
|
||||
instance : Std.Associative (α := Int) min := ⟨Int.min_assoc⟩
|
||||
|
||||
@[simp] protected theorem min_self_assoc {m n : Int} : min m (min m n) = min m n := by
|
||||
rw [← Int.min_assoc, Int.min_self]
|
||||
@@ -130,7 +130,7 @@ instance : Std.Associative (α := Nat) min := ⟨Nat.min_assoc⟩
|
||||
rw [Int.min_comm m n, ← Int.min_assoc, Int.min_self]
|
||||
|
||||
@[simp] protected theorem max_assoc (a b c : Int) : max (max a b) c = max a (max b c) := by omega
|
||||
instance : Std.Associative (α := Nat) max := ⟨Nat.max_assoc⟩
|
||||
instance : Std.Associative (α := Int) max := ⟨Int.max_assoc⟩
|
||||
|
||||
@[simp] protected theorem max_self_assoc {m n : Int} : max m (max m n) = max m n := by
|
||||
rw [← Int.max_assoc, Int.max_self]
|
||||
|
||||
@@ -254,7 +254,7 @@ pointer-equal to its argument.
|
||||
For verification purposes, `List.mapMono = List.map`.
|
||||
-/
|
||||
def mapMono (as : List α) (f : α → α) : List α :=
|
||||
Id.run <| as.mapMonoM f
|
||||
Id.run <| as.mapMonoM (pure <| f ·)
|
||||
|
||||
/-! ## Additional lemmas required for bootstrapping `Array`. -/
|
||||
|
||||
|
||||
@@ -348,9 +348,16 @@ theorem findM?_pure {m} [Monad m] [LawfulMonad m] (p : α → Bool) (as : List
|
||||
| false => simp [ih]
|
||||
|
||||
@[simp]
|
||||
theorem findM?_id (p : α → Bool) (as : List α) : findM? (m := Id) p as = as.find? p :=
|
||||
theorem idRun_findM? (p : α → Id Bool) (as : List α) :
|
||||
(findM? p as).run = as.find? (p · |>.run) :=
|
||||
findM?_pure _ _
|
||||
|
||||
@[deprecated idRun_findM? (since := "2025-05-21")]
|
||||
theorem findM?_id (p : α → Id Bool) (as : List α) :
|
||||
findM? (m := Id) p as = as.find? p :=
|
||||
findM?_pure _ _
|
||||
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying the monadic function `f` to each element of the
|
||||
list, in order. Returns `none` if `f` returns `none` for all elements.
|
||||
@@ -394,7 +401,13 @@ theorem findSomeM?_pure [Monad m] [LawfulMonad m] {f : α → Option β} {as : L
|
||||
| none => simp [ih]
|
||||
|
||||
@[simp]
|
||||
theorem findSomeM?_id {f : α → Option β} {as : List α} : findSomeM? (m := Id) f as = as.findSome? f :=
|
||||
theorem idRun_findSomeM? (f : α → Id (Option β)) (as : List α) :
|
||||
(findSomeM? f as).run = as.findSome? (f · |>.run) :=
|
||||
findSomeM?_pure
|
||||
|
||||
@[deprecated idRun_findSomeM? (since := "2025-05-21")]
|
||||
theorem findSomeM?_id (f : α → Id (Option β)) (as : List α) :
|
||||
findSomeM? (m := Id) f as = as.findSome? f :=
|
||||
findSomeM?_pure
|
||||
|
||||
theorem findM?_eq_findSomeM? [Monad m] [LawfulMonad m] {p : α → m Bool} {as : List α} :
|
||||
|
||||
@@ -6,7 +6,8 @@ Authors: François G. Dorais
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.List.OfFn
|
||||
import all Init.Data.List.OfFn
|
||||
import Init.Data.List.Monadic
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
@@ -57,3 +58,50 @@ theorem finRange_reverse {n} : (finRange n).reverse = (finRange n).map Fin.rev :
|
||||
simp [Fin.rev_succ]
|
||||
|
||||
end List
|
||||
|
||||
namespace Fin
|
||||
|
||||
theorem foldlM_eq_foldlM_finRange [Monad m] (f : α → Fin n → m α) (x : α) :
|
||||
foldlM n f x = (List.finRange n).foldlM f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp [foldlM_succ, List.finRange_succ, List.foldlM_cons]
|
||||
congr 1
|
||||
funext y
|
||||
simp [ih, List.foldlM_map]
|
||||
|
||||
theorem foldrM_eq_foldrM_finRange [Monad m] [LawfulMonad m] (f : Fin n → α → m α) (x : α) :
|
||||
foldrM n f x = (List.finRange n).foldrM f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp [foldrM_succ, List.finRange_succ, ih, List.foldrM_map]
|
||||
|
||||
theorem foldl_eq_finRange_foldl (f : α → Fin n → α) (x : α) :
|
||||
foldl n f x = (List.finRange n).foldl f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp [foldl_succ, List.finRange_succ, ih, List.foldl_map]
|
||||
|
||||
theorem foldr_eq_finRange_foldr (f : Fin n → α → α) (x : α) :
|
||||
foldr n f x = (List.finRange n).foldr f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp [foldr_succ, List.finRange_succ, ih, List.foldr_map]
|
||||
|
||||
end Fin
|
||||
|
||||
namespace List
|
||||
|
||||
theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let a ← f 0
|
||||
let as ← ofFnM fun i => f i.succ
|
||||
pure (a :: as)) := by
|
||||
simp [ofFnM, Fin.foldlM_eq_foldlM_finRange, List.finRange_succ, List.foldlM_cons_eq_append,
|
||||
List.foldlM_map]
|
||||
|
||||
end List
|
||||
|
||||
@@ -1108,14 +1108,9 @@ theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
simp only [finIdxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
@[simp]
|
||||
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.finIdxOf? a).isNone = ¬ a ∈ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [finIdxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
simp
|
||||
|
||||
/-! ### idxOf?
|
||||
|
||||
@@ -1154,15 +1149,9 @@ theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
simp only [idxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
@[simp]
|
||||
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.idxOf? a).isNone = ¬ a ∈ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [idxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
simp
|
||||
|
||||
/-! ### lookup -/
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ Example:
|
||||
let rec go : ∀ as acc, filterMapTR.go f as acc = acc.toList ++ as.filterMap f
|
||||
| [], acc => by simp [filterMapTR.go, filterMap]
|
||||
| a::as, acc => by
|
||||
simp only [filterMapTR.go, go as, Array.push_toList, append_assoc, singleton_append,
|
||||
simp only [filterMapTR.go, go as, Array.toList_push, append_assoc, singleton_append,
|
||||
filterMap]
|
||||
split <;> simp [*]
|
||||
exact (go l #[]).symm
|
||||
|
||||
@@ -272,13 +272,13 @@ theorem getElem_of_getElem? {l : List α} : l[i]? = some a → ∃ h : i < l.len
|
||||
theorem some_eq_getElem?_iff {l : List α} : some a = l[i]? ↔ ∃ h : i < l.length, l[i] = a := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem?_iff {xs : List α} {i : Nat} (h : i < xs.length) :
|
||||
theorem some_getElem_eq_getElem?_iff {xs : List α} {i : Nat} (h : i < xs.length) :
|
||||
(some xs[i] = xs[i]?) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff {xs : List α} {i : Nat} (h : i < xs.length) :
|
||||
theorem getElem?_eq_some_getElem_iff {xs : List α} {i : Nat} (h : i < xs.length) :
|
||||
(xs[i]? = some xs[i]) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
theorem getElem_eq_iff {l : List α} {i : Nat} (h : i < l.length) : l[i] = x ↔ l[i]? = some x := by
|
||||
simp only [getElem?_eq_some_iff]
|
||||
@@ -296,7 +296,7 @@ theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
|
||||
have p : i ≥ l.length := Nat.le_of_not_gt h
|
||||
simp [getElem?_eq_none p, h]
|
||||
|
||||
@[simp] theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : [a][i] = a :=
|
||||
@[simp] theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : [a][i] = a := by
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
|
||||
@@ -434,8 +434,8 @@ theorem eq_nil_iff_forall_not_mem {l : List α} : l = [] ↔ ∀ a, a ∉ l := b
|
||||
theorem eq_of_mem_singleton : a ∈ [b] → a = b
|
||||
| .head .. => rfl
|
||||
|
||||
@[simp] theorem mem_singleton {a b : α} : a ∈ [b] ↔ a = b :=
|
||||
⟨eq_of_mem_singleton, (by simp [·])⟩
|
||||
theorem mem_singleton {a b : α} : a ∈ [b] ↔ a = b := by
|
||||
simp
|
||||
|
||||
theorem forall_mem_cons {p : α → Prop} {a : α} {l : List α} :
|
||||
(∀ x, x ∈ a :: l → p x) ↔ p a ∧ ∀ x, x ∈ l → p x :=
|
||||
@@ -1685,8 +1685,8 @@ theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp
|
||||
|
||||
@[deprecated append_eq_nil_iff (since := "2025-01-13")] abbrev append_eq_nil := @append_eq_nil_iff
|
||||
|
||||
@[simp] theorem nil_eq_append_iff : [] = a ++ b ↔ a = [] ∧ b = [] := by
|
||||
rw [eq_comm, append_eq_nil_iff]
|
||||
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₂ = [] :=
|
||||
@@ -1897,8 +1897,8 @@ theorem eq_nil_or_concat : ∀ l : List α, l = [] ∨ ∃ l' b, l = concat l' b
|
||||
@[simp] theorem flatten_eq_nil_iff {L : List (List α)} : L.flatten = [] ↔ ∀ l ∈ L, l = [] := by
|
||||
induction L <;> simp_all
|
||||
|
||||
@[simp] theorem nil_eq_flatten_iff {L : List (List α)} : [] = L.flatten ↔ ∀ l ∈ L, l = [] := by
|
||||
rw [eq_comm, flatten_eq_nil_iff]
|
||||
theorem nil_eq_flatten_iff {L : List (List α)} : [] = L.flatten ↔ ∀ l ∈ L, l = [] := by
|
||||
simp
|
||||
|
||||
theorem flatten_ne_nil_iff {xss : List (List α)} : xss.flatten ≠ [] ↔ ∃ xs, xs ∈ xss ∧ xs ≠ [] := by
|
||||
simp
|
||||
@@ -2541,17 +2541,25 @@ theorem flatten_reverse {L : List (List α)} :
|
||||
induction l generalizing b <;> simp [*]
|
||||
|
||||
theorem foldl_eq_foldlM {f : β → α → β} {b : β} {l : List α} :
|
||||
l.foldl f b = l.foldlM (m := Id) f b := by
|
||||
induction l generalizing b <;> simp [*, foldl]
|
||||
l.foldl f b = (l.foldlM (m := Id) (pure <| f · ·) b).run := by
|
||||
simp
|
||||
|
||||
theorem foldr_eq_foldrM {f : α → β → β} {b : β} {l : List α} :
|
||||
l.foldr f b = l.foldrM (m := Id) f b := by
|
||||
induction l <;> simp [*, foldr]
|
||||
l.foldr f b = (l.foldrM (m := Id) (pure <| f · ·) b).run := by
|
||||
simp
|
||||
|
||||
@[simp] theorem id_run_foldlM {f : β → α → Id β} {b : β} {l : List α} :
|
||||
theorem idRun_foldlM {f : β → α → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldlM f b) = l.foldl (f · · |>.run) b := foldl_eq_foldlM.symm
|
||||
|
||||
@[deprecated idRun_foldlM (since := "2025-05-21")]
|
||||
theorem id_run_foldlM {f : β → α → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldlM f b) = l.foldl f b := foldl_eq_foldlM.symm
|
||||
|
||||
@[simp] theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
|
||||
theorem idRun_foldrM {f : α → β → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldrM f b) = l.foldr (f · · |>.run) b := foldr_eq_foldrM.symm
|
||||
|
||||
@[deprecated idRun_foldrM (since := "2025-05-21")]
|
||||
theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldrM f b) = l.foldr f b := foldr_eq_foldrM.symm
|
||||
|
||||
@[simp] theorem foldlM_reverse [Monad m] {l : List α} {f : β → α → m β} {b : β} :
|
||||
@@ -2576,6 +2584,11 @@ theorem foldr_eq_foldrM {f : α → β → β} {b : β} {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`. -/
|
||||
@[grind] theorem foldl_flip_cons_eq_append' {l l' : List α} :
|
||||
l.foldl (fun xs y => y :: xs) l' = l.reverse ++ l' := by
|
||||
simp
|
||||
|
||||
@[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 [*]
|
||||
@@ -2641,10 +2654,10 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp, grind _=_] theorem foldl_append {β : Type _} {f : β → α → β} {b : β} {l l' : List α} :
|
||||
(l ++ l').foldl f b = l'.foldl f (l.foldl f b) := by simp [foldl_eq_foldlM]
|
||||
(l ++ l').foldl f b = l'.foldl f (l.foldl f b) := by simp [foldl_eq_foldlM, -foldlM_pure]
|
||||
|
||||
@[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]
|
||||
(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 α)} :
|
||||
(flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b := by
|
||||
@@ -2655,7 +2668,8 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
induction L <;> simp_all
|
||||
|
||||
@[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]
|
||||
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 : β} :
|
||||
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
|
||||
@@ -2938,7 +2952,7 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ ∃ a' ∈ l, a == a' := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[grind]
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ a ∈ l := by
|
||||
simp
|
||||
@@ -3413,8 +3427,8 @@ variable [LawfulBEq α]
|
||||
| Or.inr h' => exact h'
|
||||
else rw [insert_of_not_mem h, mem_cons]
|
||||
|
||||
@[simp] theorem mem_insert_self {a : α} {l : List α} : a ∈ l.insert a :=
|
||||
mem_insert_iff.2 (Or.inl rfl)
|
||||
theorem mem_insert_self {a : α} {l : List α} : a ∈ l.insert a := by
|
||||
simp
|
||||
|
||||
theorem mem_insert_of_mem {l : List α} (h : a ∈ l) : a ∈ l.insert b :=
|
||||
mem_insert_iff.2 (Or.inr h)
|
||||
|
||||
@@ -348,7 +348,7 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {acc : Array β} {i : Nat},
|
||||
split <;> split
|
||||
· simp only [Option.some.injEq]
|
||||
rw [← Array.getElem_toList]
|
||||
simp only [Array.push_toList]
|
||||
simp only [Array.toList_push]
|
||||
rw [getElem_append_left, ← Array.getElem_toList]
|
||||
· have : i = acc.size := by omega
|
||||
simp_all
|
||||
|
||||
@@ -8,6 +8,8 @@ module
|
||||
prelude
|
||||
import Init.Data.List.TakeDrop
|
||||
import Init.Data.List.Attach
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.Array.Bootstrap
|
||||
import all Init.Data.List.Control
|
||||
|
||||
/-!
|
||||
@@ -66,16 +68,24 @@ theorem mapM'_eq_mapM [Monad m] [LawfulMonad m] {f : α → m β} {l : List α}
|
||||
l.mapM (m := m) (pure <| f ·) = pure (l.map f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem mapM_id {l : List α} {f : α → Id β} : l.mapM f = l.map f :=
|
||||
@[simp] theorem idRun_mapM {l : List α} {f : α → Id β} : (l.mapM f).run = l.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[deprecated idRun_mapM (since := "2025-05-21")]
|
||||
theorem mapM_id {l : List α} {f : α → Id β} : (l.mapM f).run = l.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[simp] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {l : List α} :
|
||||
(l.map f).mapM g = l.mapM (g ∘ f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).mapM f = (return (← l₁.mapM f) ++ (← l₂.mapM f)) := by induction l₁ <;> simp [*]
|
||||
|
||||
/-- Auxiliary lemma for `mapM_eq_reverse_foldlM_cons`. -/
|
||||
theorem foldlM_cons_eq_append [Monad m] [LawfulMonad m] {f : α → m β} {as : List α} {b : β} {bs : List β} :
|
||||
(as.foldlM (init := b :: bs) fun acc a => return ((← f a) :: acc)) =
|
||||
(· ++ b :: bs) <$> as.foldlM (init := []) fun acc a => return ((← f a) :: acc) := by
|
||||
(as.foldlM (init := b :: bs) fun acc a => (· :: acc) <$> f a) =
|
||||
(· ++ b :: bs) <$> as.foldlM (init := []) fun acc a => (· :: acc) <$> f a := by
|
||||
induction as generalizing b bs with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
@@ -83,7 +93,7 @@ theorem foldlM_cons_eq_append [Monad m] [LawfulMonad m] {f : α → m β} {as :
|
||||
simp [ih, _root_.map_bind, Functor.map_map, Function.comp_def]
|
||||
|
||||
theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] {f : α → m β} {l : List α} :
|
||||
mapM f l = reverse <$> (l.foldlM (fun acc a => return ((← f a) :: acc)) []) := by
|
||||
mapM f l = reverse <$> (l.foldlM (fun acc a => (· :: acc) <$> f a) []) := by
|
||||
rw [← mapM'_eq_mapM]
|
||||
induction l with
|
||||
| nil => simp
|
||||
@@ -339,12 +349,18 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
simp only [forIn'_eq_foldlM]
|
||||
induction l.attach generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
@[simp] theorem idRun_forIn'_yield_eq_foldl
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → Id β) (init : β) :
|
||||
(forIn' l init (fun a m b => .yield <$> f a m b)).run =
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b |>.run) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[deprecated idRun_forIn'_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn'_yield_eq_foldl
|
||||
{l : List α} (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
simp only [forIn'_eq_foldlM]
|
||||
induction l.attach generalizing init <;> simp_all
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{l : List α} (g : α → β) (f : (b : β) → b ∈ l.map g → γ → m (ForInStep γ)) :
|
||||
@@ -392,12 +408,18 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
@[simp] theorem idRun_forIn_yield_eq_foldl
|
||||
(l : List α) (f : α → β → Id β) (init : β) :
|
||||
(forIn l init (fun a b => .yield <$> f a b)).run =
|
||||
l.foldl (fun b a => f a b |>.run) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[deprecated idRun_forIn_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn_yield_eq_foldl
|
||||
{l : List α} (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) l init (fun a b => .yield (f a b)) =
|
||||
l.foldl (fun b a => f a b) init := by
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
l.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{l : List α} {g : α → β} {f : β → γ → m (ForInStep γ)} :
|
||||
|
||||
@@ -56,7 +56,7 @@ theorem getElem?_take_eq_none {l : List α} {i j : Nat} (h : i ≤ j) :
|
||||
(l.take i)[j]? = none :=
|
||||
getElem?_eq_none <| Nat.le_trans (length_take_le _ _) h
|
||||
|
||||
@[grind =]theorem getElem?_take {l : List α} {i j : Nat} :
|
||||
@[grind =] theorem getElem?_take {l : List α} {i j : Nat} :
|
||||
(l.take i)[j]? = if j < i then l[j]? else none := by
|
||||
split
|
||||
· next h => exact getElem?_take_of_lt h
|
||||
|
||||
@@ -27,6 +27,13 @@ Examples:
|
||||
-/
|
||||
def ofFn {n} (f : Fin n → α) : List α := Fin.foldr n (f · :: ·) []
|
||||
|
||||
/--
|
||||
Creates a list wrapped in a monad by applying the monadic function `f : Fin n → m α`
|
||||
to each potential index in order, starting at `0`.
|
||||
-/
|
||||
def ofFnM {n} [Monad m] (f : Fin n → m α) : m (List α) :=
|
||||
List.reverse <$> Fin.foldlM n (fun xs i => (· :: xs) <$> f i) []
|
||||
|
||||
@[simp]
|
||||
theorem length_ofFn {f : Fin n → α} : (ofFn f).length = n := by
|
||||
simp only [ofFn]
|
||||
@@ -49,7 +56,8 @@ protected theorem getElem_ofFn {f : Fin n → α} (h : i < (ofFn f).length) :
|
||||
simp_all
|
||||
|
||||
@[simp]
|
||||
protected theorem getElem?_ofFn {f : Fin n → α} : (ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none :=
|
||||
protected theorem getElem?_ofFn {f : Fin n → α} :
|
||||
(ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none :=
|
||||
if h : i < (ofFn f).length
|
||||
then by
|
||||
rw [getElem?_eq_getElem h, List.getElem_ofFn]
|
||||
@@ -60,8 +68,8 @@ protected theorem getElem?_ofFn {f : Fin n → α} : (ofFn f)[i]? = if h : i < n
|
||||
|
||||
/-- `ofFn` on an empty domain is the empty list. -/
|
||||
@[simp]
|
||||
theorem ofFn_zero {f : Fin 0 → α} : ofFn f = [] :=
|
||||
ext_get (by simp) (fun i hi₁ hi₂ => by contradiction)
|
||||
theorem ofFn_zero {f : Fin 0 → α} : ofFn f = [] := by
|
||||
rw [ofFn, Fin.foldr_zero]
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_succ {n} {f : Fin (n + 1) → α} : ofFn f = f 0 :: ofFn fun i => f i.succ :=
|
||||
@@ -70,6 +78,22 @@ theorem ofFn_succ {n} {f : Fin (n + 1) → α} : ofFn f = f 0 :: ofFn fun i => f
|
||||
· simp
|
||||
· simp)
|
||||
|
||||
theorem ofFn_succ_last {n} {f : Fin (n + 1) → α} :
|
||||
ofFn f = (ofFn fun i => f i.castSucc) ++ [f (Fin.last n)] := by
|
||||
induction n with
|
||||
| zero => simp [ofFn_succ]
|
||||
| succ n ih =>
|
||||
rw [ofFn_succ]
|
||||
conv => rhs; rw [ofFn_succ]
|
||||
rw [ih]
|
||||
simp
|
||||
|
||||
theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
ofFn f = (ofFn fun i => f (i.castLE (Nat.le_add_right n m))) ++ (ofFn fun i => f (i.natAdd n)) := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => simp [-ofFn_succ, ofFn_succ_last, ih]
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_nil_iff {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
|
||||
cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq]
|
||||
@@ -92,4 +116,65 @@ theorem getLast_ofFn {n} {f : Fin n → α} (h : ofFn f ≠ []) :
|
||||
(ofFn f).getLast h = f ⟨n - 1, Nat.sub_one_lt (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
simp [getLast_eq_getElem, length_ofFn, List.getElem_ofFn]
|
||||
|
||||
/-- `ofFnM` on an empty domain is the empty list. -/
|
||||
@[simp]
|
||||
theorem ofFnM_zero [Monad m] [LawfulMonad m] {f : Fin 0 → m α} : ofFnM f = pure [] := by
|
||||
simp [ofFnM]
|
||||
|
||||
/-! See `Init.Data.List.FinRange` for the `ofFnM_succ` variant. -/
|
||||
|
||||
theorem ofFnM_succ_last {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i => f i.castSucc
|
||||
let a ← f (Fin.last n)
|
||||
pure (as ++ [a])) := by
|
||||
simp [ofFnM, Fin.foldlM_succ_last]
|
||||
|
||||
theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i : Fin n => f (i.castLE (Nat.le_add_right n k))
|
||||
let bs ← ofFnM fun i : Fin k => f (i.natAdd n)
|
||||
pure (as ++ bs)) := by
|
||||
induction k with
|
||||
| zero => simp
|
||||
| succ k ih => simp [ofFnM_succ_last, ih]
|
||||
|
||||
|
||||
end List
|
||||
|
||||
namespace Fin
|
||||
|
||||
theorem foldl_cons_eq_append {f : Fin n → α} {xs : List α} :
|
||||
Fin.foldl n (fun xs i => f i :: xs) xs = (List.ofFn f).reverse ++ xs := by
|
||||
induction n generalizing xs with
|
||||
| zero => simp
|
||||
| succ n ih => simp [Fin.foldl_succ, List.ofFn_succ, ih]
|
||||
|
||||
theorem foldr_cons_eq_append {f : Fin n → α} {xs : List α} :
|
||||
Fin.foldr n (fun i xs => f i :: xs) xs = List.ofFn f ++ xs:= by
|
||||
induction n generalizing xs with
|
||||
| zero => simp
|
||||
| succ n ih => simp [Fin.foldr_succ, List.ofFn_succ, ih]
|
||||
|
||||
end Fin
|
||||
|
||||
namespace List
|
||||
|
||||
@[simp]
|
||||
theorem ofFnM_pure_comp [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (pure ∘ f) = (pure (ofFn f) : m (List α)) := by
|
||||
simp [ofFnM, Fin.foldlM_pure, Fin.foldl_cons_eq_append]
|
||||
|
||||
-- Variant of `ofFnM_pure_comp` using a lambda.
|
||||
-- This is not marked a `@[simp]` as it would match on every occurrence of `ofFnM`.
|
||||
theorem ofFnM_pure [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (fun i => pure (f i)) = (pure (ofFn f) : m (List α)) :=
|
||||
ofFnM_pure_comp
|
||||
|
||||
@[simp, grind =] theorem idRun_ofFnM {f : Fin n → Id α} :
|
||||
Id.run (ofFnM f) = ofFn (fun i => Id.run (f i)) := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [-ofFn_succ, ofFnM_succ_last, ofFn_succ_last, ih]
|
||||
|
||||
end List
|
||||
|
||||
@@ -24,7 +24,7 @@ open Nat
|
||||
|
||||
/-! ### Pairwise -/
|
||||
|
||||
theorem Pairwise.sublist : l₁ <+ l₂ → l₂.Pairwise R → l₁.Pairwise R
|
||||
@[grind →] theorem Pairwise.sublist : l₁ <+ l₂ → l₂.Pairwise R → l₁.Pairwise R
|
||||
| .slnil, h => h
|
||||
| .cons _ s, .cons _ h₂ => h₂.sublist s
|
||||
| .cons₂ _ s, .cons h₁ h₂ => (h₂.sublist s).cons fun _ h => h₁ _ (s.subset h)
|
||||
@@ -37,11 +37,11 @@ theorem Pairwise.imp {α R S} (H : ∀ {a b}, R a b → S a b) :
|
||||
theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l → R a a' :=
|
||||
(pairwise_cons.1 p).1 _
|
||||
|
||||
theorem Pairwise.of_cons (p : (a :: l).Pairwise R) : Pairwise R l :=
|
||||
@[grind →] theorem Pairwise.of_cons (p : (a :: l).Pairwise R) : Pairwise R l :=
|
||||
(pairwise_cons.1 p).2
|
||||
|
||||
set_option linter.unusedVariables false in
|
||||
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
|
||||
|
||||
@@ -101,11 +101,11 @@ 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
|
||||
|
||||
theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
@[grind] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
|
||||
theorem pairwise_pair {a b : α} : Pairwise R [a, b] ↔ R a b := by simp
|
||||
@[grind =] theorem pairwise_pair {a b : α} : Pairwise R [a, b] ↔ R a b := by simp
|
||||
|
||||
theorem pairwise_map {l : List α} :
|
||||
@[grind =] theorem pairwise_map {l : List α} :
|
||||
(l.map f).Pairwise R ↔ l.Pairwise fun a b => R (f a) (f b) := by
|
||||
induction l
|
||||
· simp
|
||||
@@ -115,11 +115,11 @@ 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 _ _)
|
||||
|
||||
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 _ _)
|
||||
|
||||
theorem pairwise_filterMap {f : β → Option α} {l : List β} :
|
||||
@[grind =] theorem pairwise_filterMap {f : β → Option α} {l : List β} :
|
||||
Pairwise R (filterMap f l) ↔ Pairwise (fun a a' : β => ∀ b, f a = some b → ∀ b', f a' = some b' → R b b') l := by
|
||||
let _S (a a' : β) := ∀ b, f a = some b → ∀ b', f a' = some b' → R b b'
|
||||
induction l with
|
||||
@@ -134,20 +134,20 @@ theorem pairwise_filterMap {f : β → Option α} {l : List β} :
|
||||
simpa [IH, e] using fun _ =>
|
||||
⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩
|
||||
|
||||
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 _ _)
|
||||
|
||||
theorem pairwise_filter {p : α → Prop} [DecidablePred p] {l : List α} :
|
||||
@[grind =] theorem pairwise_filter {p : α → Bool} {l : List α} :
|
||||
Pairwise R (filter p l) ↔ Pairwise (fun x y => p x → p y → R x y) l := by
|
||||
rw [← filterMap_eq_filter, pairwise_filterMap]
|
||||
simp
|
||||
|
||||
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
|
||||
|
||||
theorem pairwise_append {l₁ l₂ : List α} :
|
||||
@[grind =] theorem pairwise_append {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).Pairwise R ↔ l₁.Pairwise R ∧ l₂.Pairwise R ∧ ∀ a ∈ l₁, ∀ b ∈ l₂, R a b := by
|
||||
induction l₁ <;> simp [*, or_imp, forall_and, and_assoc, and_left_comm]
|
||||
|
||||
@@ -157,13 +157,13 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
(x : α) (xm : x ∈ l₂) (y : α) (ym : y ∈ l₁) : R x y := s (H y ym x xm)
|
||||
simp only [pairwise_append, and_left_comm]; rw [Iff.intro (this l₁ l₂) (this l₂ l₁)]
|
||||
|
||||
theorem pairwise_middle {R : α → α → Prop} (s : ∀ {x y}, R x y → R y x) {a : α} {l₁ l₂ : List α} :
|
||||
@[grind =] theorem pairwise_middle {R : α → α → Prop} (s : ∀ {x y}, R x y → R y x) {a : α} {l₁ l₂ : List α} :
|
||||
Pairwise R (l₁ ++ a :: l₂) ↔ Pairwise R (a :: (l₁ ++ l₂)) := by
|
||||
show Pairwise R (l₁ ++ ([a] ++ l₂)) ↔ Pairwise R ([a] ++ l₁ ++ l₂)
|
||||
rw [← append_assoc, pairwise_append, @pairwise_append _ _ ([a] ++ l₁), pairwise_append_comm s]
|
||||
simp only [mem_append, or_comm]
|
||||
|
||||
theorem pairwise_flatten {L : List (List α)} :
|
||||
@[grind =] theorem pairwise_flatten {L : List (List α)} :
|
||||
Pairwise R (flatten L) ↔
|
||||
(∀ l ∈ L, Pairwise R l) ∧ Pairwise (fun l₁ l₂ => ∀ x ∈ l₁, ∀ y ∈ l₂, R x y) L := by
|
||||
induction L with
|
||||
@@ -174,16 +174,16 @@ theorem pairwise_flatten {L : List (List α)} :
|
||||
rw [and_comm, and_congr_left_iff]
|
||||
intros; exact ⟨fun h l' b c d e => h c d e l' b, fun h c d e l' b => h l' b c d e⟩
|
||||
|
||||
theorem pairwise_flatMap {R : β → β → Prop} {l : List α} {f : α → List β} :
|
||||
@[grind =] theorem pairwise_flatMap {R : β → β → Prop} {l : List α} {f : α → List β} :
|
||||
List.Pairwise R (l.flatMap f) ↔
|
||||
(∀ a ∈ l, Pairwise R (f a)) ∧ Pairwise (fun a₁ a₂ => ∀ x ∈ f a₁, ∀ y ∈ f a₂, R x y) l := by
|
||||
simp [List.flatMap, pairwise_flatten, pairwise_map]
|
||||
|
||||
theorem pairwise_reverse {l : List α} :
|
||||
@[grind =] theorem pairwise_reverse {l : List α} :
|
||||
l.reverse.Pairwise R ↔ l.Pairwise (fun a b => R b a) := by
|
||||
induction l <;> simp [*, pairwise_append, and_comm]
|
||||
|
||||
@[simp] theorem pairwise_replicate {n : Nat} {a : α} :
|
||||
@[simp, grind =] theorem pairwise_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).Pairwise R ↔ n ≤ 1 ∨ R a a := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
@@ -205,10 +205,10 @@ theorem pairwise_reverse {l : List α} :
|
||||
simp
|
||||
· exact ⟨fun _ => h, Or.inr h⟩
|
||||
|
||||
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 _ _)
|
||||
|
||||
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 _ _)
|
||||
|
||||
theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l → R a b) := by
|
||||
@@ -247,7 +247,7 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
intro a b hab
|
||||
apply h <;> (apply hab.subset; simp)
|
||||
|
||||
theorem pairwise_pmap {p : β → Prop} {f : ∀ b, p b → α} {l : List β} (h : ∀ x ∈ l, p x) :
|
||||
@[grind =] theorem pairwise_pmap {p : β → Prop} {f : ∀ b, p b → α} {l : List β} (h : ∀ x ∈ l, p x) :
|
||||
Pairwise R (l.pmap f h) ↔
|
||||
Pairwise (fun b₁ b₂ => ∀ (h₁ : p b₁) (h₂ : p b₂), R (f b₁ h₁) (f b₂ h₂)) l := by
|
||||
induction l with
|
||||
@@ -259,7 +259,7 @@ theorem pairwise_pmap {p : β → Prop} {f : ∀ b, p b → α} {l : List β} (h
|
||||
rintro H _ b hb rfl
|
||||
exact H b hb _ _
|
||||
|
||||
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
|
||||
@@ -268,15 +268,15 @@ theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f :
|
||||
|
||||
/-! ### Nodup -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem nodup_nil : @Nodup α [] :=
|
||||
Pairwise.nil
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) ↔ a ∉ l ∧ Nodup l := by
|
||||
simp only [Nodup, pairwise_cons, forall_mem_ne]
|
||||
|
||||
theorem Nodup.sublist : l₁ <+ l₂ → Nodup l₂ → Nodup l₁ :=
|
||||
@[grind →] theorem Nodup.sublist : l₁ <+ l₂ → Nodup l₂ → Nodup l₁ :=
|
||||
Pairwise.sublist
|
||||
|
||||
theorem Sublist.nodup : l₁ <+ l₂ → Nodup l₂ → Nodup l₁ :=
|
||||
@@ -303,7 +303,7 @@ theorem getElem?_inj {xs : List α}
|
||||
rw [mem_iff_getElem?]
|
||||
exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩
|
||||
|
||||
@[simp] theorem nodup_replicate {n : Nat} {a : α} :
|
||||
@[simp, grind =] theorem nodup_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).Nodup ↔ n ≤ 1 := by simp [Nodup]
|
||||
|
||||
end List
|
||||
|
||||
@@ -31,6 +31,11 @@ theorem take_cons {l : List α} (h : 0 < i) : (a :: l).take i = a :: l.take (i -
|
||||
| zero => exact absurd h (Nat.lt_irrefl _)
|
||||
| succ i => rfl
|
||||
|
||||
theorem drop_cons {l : List α} (h : 0 < i) : (a :: l).drop i = l.drop (i - 1) := by
|
||||
cases i with
|
||||
| zero => exact absurd h (Nat.lt_irrefl _)
|
||||
| succ i => rfl
|
||||
|
||||
@[simp]
|
||||
theorem drop_one : ∀ {l : List α}, l.drop 1 = l.tail
|
||||
| [] | _ :: _ => rfl
|
||||
|
||||
@@ -210,12 +210,6 @@ theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp] theorem foldl_push {l : List α} {as : Array α} : l.foldl Array.push as = as ++ l.toArray := by
|
||||
induction l generalizing as <;> simp [*]
|
||||
|
||||
@[simp] theorem foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
|
||||
rw [foldr_eq_foldl_reverse, foldl_push]
|
||||
|
||||
@[simp, grind =] theorem findSomeM?_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α) :
|
||||
l.toArray.findSomeM? f = l.findSomeM? f := by
|
||||
rw [Array.findSomeM?]
|
||||
@@ -262,16 +256,16 @@ theorem findRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : Lis
|
||||
|
||||
@[simp, grind =] theorem findSome?_toArray (f : α → Option β) (l : List α) :
|
||||
l.toArray.findSome? f = l.findSome? f := by
|
||||
rw [Array.findSome?, ← findSomeM?_id, findSomeM?_toArray, Id.run]
|
||||
rw [Array.findSome?, findSomeM?_toArray, findSomeM?_pure, Id.run_pure]
|
||||
|
||||
@[simp, grind =] theorem find?_toArray (f : α → Bool) (l : List α) :
|
||||
l.toArray.find? f = l.find? f := by
|
||||
rw [Array.find?]
|
||||
simp only [Id.run, Id, Id.pure_eq, Id.bind_eq, forIn_toArray]
|
||||
simp only [forIn_toArray]
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [forIn_cons, Id.pure_eq, Id.bind_eq, find?]
|
||||
simp only [forIn_cons, find?]
|
||||
by_cases f a <;> simp_all
|
||||
|
||||
private theorem findFinIdx?_loop_toArray (w : l' = l.drop j) :
|
||||
|
||||
@@ -150,7 +150,7 @@ theorem add_one (n : Nat) : n + 1 = succ n :=
|
||||
@[simp] theorem succ_eq_add_one (n : Nat) : succ n = n + 1 :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem add_one_ne_zero (n : Nat) : n + 1 ≠ 0 := nofun
|
||||
theorem add_one_ne_zero (n : Nat) : n + 1 ≠ 0 := nofun
|
||||
theorem zero_ne_add_one (n : Nat) : 0 ≠ n + 1 := by simp
|
||||
|
||||
protected theorem add_comm : ∀ (n m : Nat), n + m = m + n
|
||||
@@ -731,13 +731,12 @@ theorem exists_eq_add_one_of_ne_zero : ∀ {n}, n ≠ 0 → Exists fun k => n =
|
||||
theorem ctor_eq_zero : Nat.zero = 0 :=
|
||||
rfl
|
||||
|
||||
@[simp] protected theorem one_ne_zero : 1 ≠ (0 : Nat) :=
|
||||
fun h => Nat.noConfusion h
|
||||
protected theorem one_ne_zero : 1 ≠ (0 : Nat) := by simp
|
||||
|
||||
@[simp] protected theorem zero_ne_one : 0 ≠ (1 : Nat) :=
|
||||
fun h => Nat.noConfusion h
|
||||
|
||||
@[simp] theorem succ_ne_zero (n : Nat) : succ n ≠ 0 := by simp
|
||||
theorem succ_ne_zero (n : Nat) : succ n ≠ 0 := by simp
|
||||
|
||||
instance instNeZeroSucc {n : Nat} : NeZero (n + 1) := ⟨succ_ne_zero n⟩
|
||||
|
||||
|
||||
@@ -197,6 +197,8 @@ theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bo
|
||||
omega
|
||||
go n 0 f
|
||||
|
||||
/-! ### `fold` -/
|
||||
|
||||
@[simp] theorem fold_zero {α : Type u} (f : (i : Nat) → i < 0 → α → α) (init : α) :
|
||||
fold 0 f init = init := by simp [fold]
|
||||
|
||||
@@ -210,6 +212,8 @@ theorem fold_eq_finRange_foldl {α : Type u} (n : Nat) (f : (i : Nat) → i < n
|
||||
| succ n ih =>
|
||||
simp [ih, List.finRange_succ_last, List.foldl_map]
|
||||
|
||||
/-! ### `foldRev` -/
|
||||
|
||||
@[simp] theorem foldRev_zero {α : Type u} (f : (i : Nat) → i < 0 → α → α) (init : α) :
|
||||
foldRev 0 f init = init := by simp [foldRev]
|
||||
|
||||
@@ -223,10 +227,12 @@ theorem foldRev_eq_finRange_foldr {α : Type u} (n : Nat) (f : (i : Nat) → i <
|
||||
| zero => simp
|
||||
| succ n ih => simp [ih, List.finRange_succ_last, List.foldr_map]
|
||||
|
||||
/-! ### `any` -/
|
||||
|
||||
@[simp] theorem any_zero {f : (i : Nat) → i < 0 → Bool} : any 0 f = false := by simp [any]
|
||||
|
||||
@[simp] theorem any_succ {n : Nat} (f : (i : Nat) → i < n + 1 → Bool) :
|
||||
any (n + 1) f = (any n (fun i h => f i (by omega)) || f n (by omega)) := by simp [any]
|
||||
any (n + 1) f = (any n (fun i h => f i (by omega)) || f n (by omega)) := by simp [any]
|
||||
|
||||
theorem any_eq_finRange_any {n : Nat} (f : (i : Nat) → i < n → Bool) :
|
||||
any n f = (List.finRange n).any (fun ⟨i, h⟩ => f i h) := by
|
||||
@@ -234,10 +240,12 @@ theorem any_eq_finRange_any {n : Nat} (f : (i : Nat) → i < n → Bool) :
|
||||
| zero => simp
|
||||
| succ n ih => simp [ih, List.finRange_succ_last, List.any_map, Function.comp_def]
|
||||
|
||||
/-! ### `all` -/
|
||||
|
||||
@[simp] theorem all_zero {f : (i : Nat) → i < 0 → Bool} : all 0 f = true := by simp [all]
|
||||
|
||||
@[simp] theorem all_succ {n : Nat} (f : (i : Nat) → i < n + 1 → Bool) :
|
||||
all (n + 1) f = (all n (fun i h => f i (by omega)) && f n (by omega)) := by simp [all]
|
||||
all (n + 1) f = (all n (fun i h => f i (by omega)) && f n (by omega)) := by simp [all]
|
||||
|
||||
theorem all_eq_finRange_all {n : Nat} (f : (i : Nat) → i < n → Bool) :
|
||||
all n f = (List.finRange n).all (fun ⟨i, h⟩ => f i h) := by
|
||||
@@ -250,7 +258,7 @@ end Nat
|
||||
namespace Prod
|
||||
|
||||
/--
|
||||
Combines an initial value with each natural number from in a range, in increasing order.
|
||||
Combines an initial value with each natural number from a range, in increasing order.
|
||||
|
||||
In particular, `(start, stop).foldI f init` applies `f`on all the numbers
|
||||
from `start` (inclusive) to `stop` (exclusive) in increasing order:
|
||||
@@ -260,7 +268,7 @@ Examples:
|
||||
* `(5, 8).foldI (fun j _ _ xs => xs.push j) #[] = #[5, 6, 7]`
|
||||
* `(5, 8).foldI (fun j _ _ xs => toString j :: xs) [] = ["7", "6", "5"]`
|
||||
-/
|
||||
@[inline] def foldI {α : Type u} (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → α → α) (init : α) : α :=
|
||||
@[inline, simp] def foldI {α : Type u} (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → α → α) (init : α) : α :=
|
||||
(i.2 - i.1).fold (fun j _ => f (i.1 + j) (by omega) (by omega)) init
|
||||
|
||||
/--
|
||||
@@ -274,7 +282,7 @@ Examples:
|
||||
* `(5, 8).anyI (fun j _ _ => j % 2 = 0) = true`
|
||||
* `(6, 6).anyI (fun j _ _ => j % 2 = 0) = false`
|
||||
-/
|
||||
@[inline] def anyI (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → Bool) : Bool :=
|
||||
@[inline, simp] def anyI (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → Bool) : Bool :=
|
||||
(i.2 - i.1).any (fun j _ => f (i.1 + j) (by omega) (by omega))
|
||||
|
||||
/--
|
||||
@@ -288,7 +296,7 @@ Examples:
|
||||
* `(5, 8).allI (fun j _ _ => j % 2 = 0) = false`
|
||||
* `(6, 7).allI (fun j _ _ => j % 2 = 0) = true`
|
||||
-/
|
||||
@[inline] def allI (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → Bool) : Bool :=
|
||||
@[inline, simp] def allI (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → Bool) : Bool :=
|
||||
(i.2 - i.1).all (fun j _ => f (i.1 + j) (by omega) (by omega))
|
||||
|
||||
end Prod
|
||||
|
||||
@@ -415,7 +415,7 @@ theorem succ_min_succ (x y) : min (succ x) (succ y) = succ (min x y) := by
|
||||
| inl h => rw [Nat.min_eq_left h, Nat.min_eq_left (Nat.succ_le_succ h)]
|
||||
| inr h => rw [Nat.min_eq_right h, Nat.min_eq_right (Nat.succ_le_succ h)]
|
||||
|
||||
@[simp] protected theorem min_self (a : Nat) : min a a = a := Nat.min_eq_left (Nat.le_refl _)
|
||||
protected theorem min_self (a : Nat) : min a a = a := by simp
|
||||
instance : Std.IdempotentOp (α := Nat) min := ⟨Nat.min_self⟩
|
||||
|
||||
@[simp] protected theorem min_assoc : ∀ (a b c : Nat), min (min a b) c = min a (min b c)
|
||||
@@ -431,16 +431,14 @@ instance : Std.Associative (α := Nat) min := ⟨Nat.min_assoc⟩
|
||||
@[simp] protected theorem min_self_assoc' {m n : Nat} : min n (min m n) = min n m := by
|
||||
rw [Nat.min_comm m n, ← Nat.min_assoc, Nat.min_self]
|
||||
|
||||
@[simp] theorem min_add_left_self {a b : Nat} : min a (b + a) = a := by
|
||||
rw [Nat.min_def]
|
||||
theorem min_add_left_self {a b : Nat} : min a (b + a) = a := by
|
||||
simp
|
||||
@[simp] theorem min_add_right_self {a b : Nat} : min a (a + b) = a := by
|
||||
rw [Nat.min_def]
|
||||
theorem min_add_right_self {a b : Nat} : min a (a + b) = a := by
|
||||
simp
|
||||
theorem add_left_min_self {a b : Nat} : min (b + a) a = a := by
|
||||
simp
|
||||
theorem add_right_min_self {a b : Nat} : min (a + b) a = a := by
|
||||
simp
|
||||
@[simp] theorem add_left_min_self {a b : Nat} : min (b + a) a = a := by
|
||||
rw [Nat.min_comm, min_add_left_self]
|
||||
@[simp] theorem add_right_min_self {a b : Nat} : min (a + b) a = a := by
|
||||
rw [Nat.min_comm, min_add_right_self]
|
||||
|
||||
protected theorem sub_sub_eq_min : ∀ (a b : Nat), a - (a - b) = min a b
|
||||
| 0, _ => by rw [Nat.zero_sub, Nat.zero_min]
|
||||
@@ -462,7 +460,7 @@ protected theorem succ_max_succ (x y) : max (succ x) (succ y) = succ (max x y) :
|
||||
| inl h => rw [Nat.max_eq_right h, Nat.max_eq_right (Nat.succ_le_succ h)]
|
||||
| inr h => rw [Nat.max_eq_left h, Nat.max_eq_left (Nat.succ_le_succ h)]
|
||||
|
||||
@[simp] protected theorem max_self (a : Nat) : max a a = a := Nat.max_eq_right (Nat.le_refl _)
|
||||
protected theorem max_self (a : Nat) : max a a = a := by simp
|
||||
instance : Std.IdempotentOp (α := Nat) max := ⟨Nat.max_self⟩
|
||||
|
||||
instance : Std.LawfulIdentity (α := Nat) max 0 where
|
||||
@@ -476,16 +474,14 @@ instance : Std.LawfulIdentity (α := Nat) max 0 where
|
||||
| _+1, _+1, _+1 => by simp only [Nat.succ_max_succ]; exact congrArg succ <| Nat.max_assoc ..
|
||||
instance : Std.Associative (α := Nat) max := ⟨Nat.max_assoc⟩
|
||||
|
||||
@[simp] theorem max_add_left_self {a b : Nat} : max a (b + a) = b + a := by
|
||||
rw [Nat.max_def]
|
||||
theorem max_add_left_self {a b : Nat} : max a (b + a) = b + a := by
|
||||
simp
|
||||
@[simp] theorem max_add_right_self {a b : Nat} : max a (a + b) = a + b := by
|
||||
rw [Nat.max_def]
|
||||
theorem max_add_right_self {a b : Nat} : max a (a + b) = a + b := by
|
||||
simp
|
||||
theorem add_left_max_self {a b : Nat} : max (b + a) a = b + a := by
|
||||
simp
|
||||
theorem add_right_max_self {a b : Nat} : max (a + b) a = a + b := by
|
||||
simp
|
||||
@[simp] theorem add_left_max_self {a b : Nat} : max (b + a) a = b + a := by
|
||||
rw [Nat.max_comm, max_add_left_self]
|
||||
@[simp] theorem add_right_max_self {a b : Nat} : max (a + b) a = a + b := by
|
||||
rw [Nat.max_comm, max_add_right_self]
|
||||
|
||||
protected theorem sub_add_eq_max (a b : Nat) : a - b + b = max a b := by
|
||||
match Nat.le_total a b with
|
||||
@@ -814,10 +810,8 @@ theorem sub_mul_mod {x k n : Nat} (h₁ : n*k ≤ x) : (x - n*k) % n = x % n :=
|
||||
simp [mul_succ, Nat.add_comm] at h₁; simp [h₁]
|
||||
rw [mul_succ, ← Nat.sub_sub, ← mod_eq_sub_mod h₄, sub_mul_mod h₂]
|
||||
|
||||
@[simp] theorem mod_mod (a n : Nat) : (a % n) % n = a % n :=
|
||||
match eq_zero_or_pos n with
|
||||
| .inl n0 => by simp [n0, mod_zero]
|
||||
| .inr npos => Nat.mod_eq_of_lt (mod_lt _ npos)
|
||||
theorem mod_mod (a n : Nat) : (a % n) % n = a % n := by
|
||||
simp
|
||||
|
||||
theorem mul_mod (a b n : Nat) : a * b % n = (a % n) * (b % n) % n := by
|
||||
rw (occs := [1]) [← mod_add_div a n]
|
||||
|
||||
@@ -8,14 +8,42 @@ module
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Option.List
|
||||
import all Init.Data.Option.Instances
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp]
|
||||
@[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 β)) :
|
||||
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 β)) :
|
||||
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 α) :
|
||||
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 α) :
|
||||
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 : α → β → α) :
|
||||
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 : β → α → α) :
|
||||
o.toArray.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem toList_toArray {o : Option α} : o.toArray.toList = o.toList := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem toArray_toList {o : Option α} : o.toList.toArray = o.toArray := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -23,4 +51,47 @@ theorem toArray_filter {o : Option α} {p : α → Bool} :
|
||||
(o.filter p).toArray = o.toArray.filter p := by
|
||||
rw [← toArray_toList, toList_filter, ← List.filter_toArray, toArray_toList]
|
||||
|
||||
theorem toArray_bind {o : Option α} {f : α → Option β} :
|
||||
(o.bind f).toArray = o.toArray.flatMap (Option.toArray ∘ f) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toArray_join {o : Option (Option α)} : o.join.toArray = o.toArray.flatMap Option.toArray := by
|
||||
simp [toArray_bind, ← bind_id_eq_join]
|
||||
|
||||
theorem toArray_map {o : Option α} {f : α → β} : (o.map f).toArray = o.toArray.map f := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toArray_min [Min α] {o o' : Option α} :
|
||||
(min o o').toArray = o.toArray.zipWith min o'.toArray := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem size_toArray_le {o : Option α} : o.toArray.size ≤ 1 := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem size_toArray {o : Option α} :
|
||||
o.toArray.size = if o.isSome then 1 else 0 := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem toArray_eq_empty_iff {o : Option α} : o.toArray = #[] ↔ o = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem toArray_eq_singleton_iff {o : Option α} : o.toArray = #[a] ↔ o = some a := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem size_toArray_eq_zero_iff {o : Option α} :
|
||||
o.toArray.size = 0 ↔ o = none := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem size_toArray_eq_one_iff {o : Option α} :
|
||||
o.toArray.size = 1 ↔ o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem size_toArray_choice_eq_one [Nonempty α] : (choice α).toArray.size = 1 := by
|
||||
simp
|
||||
|
||||
end Option
|
||||
|
||||
@@ -8,11 +8,16 @@ module
|
||||
prelude
|
||||
import Init.Data.Option.Basic
|
||||
import Init.Data.Option.List
|
||||
import Init.Data.Option.Array
|
||||
import Init.Data.Array.Attach
|
||||
import Init.Data.List.Attach
|
||||
import Init.BinderPredicates
|
||||
|
||||
namespace Option
|
||||
|
||||
instance {o : Option α} : Subsingleton { x // o = some x } where
|
||||
allEq a b := Subtype.ext (Option.some.inj (a.property.symm.trans b.property))
|
||||
|
||||
/--
|
||||
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||
`Option {x // P x}` is the same as the input `Option α`.
|
||||
@@ -46,12 +51,12 @@ terminates.
|
||||
-/
|
||||
@[inline] def attach (xs : Option α) : Option {x // xs = some x} := xs.attachWith _ fun _ => id
|
||||
|
||||
@[simp] theorem attach_none : (none : Option α).attach = none := rfl
|
||||
@[simp] theorem attachWith_none : (none : Option α).attachWith P H = none := rfl
|
||||
@[simp, grind =] theorem attach_none : (none : Option α).attach = none := rfl
|
||||
@[simp, grind =] theorem attachWith_none : (none : Option α).attachWith P H = none := rfl
|
||||
|
||||
@[simp] theorem attach_some {x : α} :
|
||||
@[simp, grind =] theorem attach_some {x : α} :
|
||||
(some x).attach = some ⟨x, rfl⟩ := rfl
|
||||
@[simp] theorem attachWith_some {x : α} {P : α → Prop} (h : ∀ (b : α), some x = some b → P b) :
|
||||
@[simp, grind =] theorem attachWith_some {x : α} {P : α → Prop} (h : ∀ (b : α), some x = some b → P b) :
|
||||
(some x).attachWith P h = some ⟨x, by simpa using h⟩ := rfl
|
||||
|
||||
theorem attach_congr {o₁ o₂ : Option α} (h : o₁ = o₂) :
|
||||
@@ -71,7 +76,7 @@ theorem attach_map_val (o : Option α) (f : α → β) :
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
theorem attach_map_subtype_val (o : Option α) :
|
||||
@[simp, grind =]theorem attach_map_subtype_val (o : Option α) :
|
||||
o.attach.map Subtype.val = o :=
|
||||
(attach_map_val _ _).trans (congrFun Option.map_id _)
|
||||
|
||||
@@ -82,28 +87,28 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (o : Option α) (H
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
@[simp, grind =] theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
(o.attachWith p H).map Subtype.val = o :=
|
||||
(attachWith_map_val _ _ _).trans (congrFun Option.map_id _)
|
||||
|
||||
theorem attach_eq_some : ∀ (o : Option a) (x : {x // o = some x}), o.attach = some x
|
||||
theorem attach_eq_some : ∀ (o : Option α) (x : {x // o = some x}), o.attach = some x
|
||||
| none, ⟨x, h⟩ => by simp at h
|
||||
| some a, ⟨x, h⟩ => by simpa using h
|
||||
|
||||
theorem mem_attach : ∀ (o : Option α) (x : {x // o = some x}), x ∈ o.attach :=
|
||||
attach_eq_some
|
||||
|
||||
@[simp] theorem isNone_attach (o : Option α) : o.attach.isNone = o.isNone := by
|
||||
@[simp, grind =] theorem isNone_attach (o : Option α) : o.attach.isNone = o.isNone := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem isNone_attachWith {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
@[simp, grind =] theorem isNone_attachWith {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
(o.attachWith p H).isNone = o.isNone := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem isSome_attach (o : Option α) : o.attach.isSome = o.isSome := by
|
||||
@[simp, grind =] theorem isSome_attach (o : Option α) : o.attach.isSome = o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem isSome_attachWith {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
@[simp, grind =] theorem isSome_attachWith {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
(o.attachWith p H).isSome = o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -122,43 +127,67 @@ theorem mem_attach : ∀ (o : Option α) (x : {x // o = some x}), x ∈ o.attach
|
||||
o.attachWith p H = some x ↔ o = some x.val := by
|
||||
cases o <;> cases x <;> simp
|
||||
|
||||
@[simp] theorem get_attach {o : Option α} (h : o.attach.isSome = true) :
|
||||
o.attach.get h = ⟨o.get (by simpa using h), by simp⟩ := by
|
||||
cases o
|
||||
· simp at h
|
||||
· simp [get_some]
|
||||
@[simp, grind =] theorem get_attach {o : Option α} (h : o.attach.isSome = true) :
|
||||
o.attach.get h = ⟨o.get (by simpa using h), by simp⟩ :=
|
||||
Subsingleton.elim _ _
|
||||
|
||||
@[simp] theorem get_attachWith {p : α → Prop} {o : Option α} (H : ∀ a, o = some a → p a) (h : (o.attachWith p H).isSome) :
|
||||
@[simp, grind =] theorem getD_attach {o : Option α} {fallback} :
|
||||
o.attach.getD fallback = fallback :=
|
||||
Subsingleton.elim _ _
|
||||
|
||||
@[simp, grind =] theorem get!_attach {o : Option α} [Inhabited { x // o = some x }] :
|
||||
o.attach.get! = default :=
|
||||
Subsingleton.elim _ _
|
||||
|
||||
@[simp, grind =] theorem get_attachWith {p : α → Prop} {o : Option α} (H : ∀ a, o = some a → p a) (h : (o.attachWith p H).isSome) :
|
||||
(o.attachWith p H).get h = ⟨o.get (by simpa using h), H _ (by simp)⟩ := by
|
||||
cases o
|
||||
· simp at h
|
||||
· simp [get_some]
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem getD_attachWith {p : α → Prop} {o : Option α} {h} {fallback} :
|
||||
(o.attachWith p h).getD fallback =
|
||||
⟨o.getD fallback.val, by
|
||||
cases o
|
||||
· exact fallback.property
|
||||
· exact h _ (by simp)⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toList_attach (o : Option α) :
|
||||
o.attach.toList = o.toList.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases o <;> simp [toList]
|
||||
o.attach.toList = o.toList.attach.map fun x => ⟨x.1, by simpa using x.2⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toList_attachWith {p : α → Prop} {o : Option α} {h} :
|
||||
(o.attachWith p h).toList = o.toList.attach.map fun x => ⟨x.1, h _ (by simpa using x.2)⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toArray_attach (o : Option α) :
|
||||
o.attach.toArray = o.toArray.attach.map fun x => ⟨x.1, by simpa using x.2⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toArray_attachWith {p : α → Prop} {o : Option α} {h} :
|
||||
(o.attachWith p h).toArray = o.toArray.attach.map fun x => ⟨x.1, h _ (by simpa using x.2)⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem attach_toList (o : Option α) :
|
||||
o.toList.attach = (o.attach.map fun ⟨a, h⟩ => ⟨a, by simpa using h⟩).toList := by
|
||||
cases o <;> simp [toList]
|
||||
|
||||
theorem attach_map {o : Option α} (f : α → β) :
|
||||
@[grind =] theorem attach_map {o : Option α} (f : α → β) :
|
||||
(o.map f).attach = o.attach.map (fun ⟨x, h⟩ => ⟨f x, map_eq_some_iff.2 ⟨_, h, rfl⟩⟩) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem attachWith_map {o : Option α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), o.map f = some b → P b} :
|
||||
@[grind =] theorem attachWith_map {o : Option α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), o.map f = some b → P b} :
|
||||
(o.map f).attachWith P H = (o.attachWith (P ∘ f) (fun _ h => H _ (map_eq_some_iff.2 ⟨_, h, rfl⟩))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem map_attach_eq_pmap {o : Option α} (f : { x // o = some x } → β) :
|
||||
@[grind =] theorem map_attach_eq_pmap {o : Option α} (f : { x // o = some x } → β) :
|
||||
o.attach.map f = o.pmap (fun a (h : o = some a) => f ⟨a, h⟩) (fun _ h => h) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[simp] theorem map_attachWith {l : Option α} {P : α → Prop} {H : ∀ (a : α), l = some a → P a}
|
||||
@[simp, grind =] theorem map_attachWith {l : Option α} {P : α → Prop} {H : ∀ (a : α), l = some a → P a}
|
||||
(f : { x // P x } → β) :
|
||||
(l.attachWith P H).map f = l.attach.map fun ⟨x, h⟩ => f ⟨x, H _ h⟩ := by
|
||||
cases l <;> simp_all
|
||||
@@ -174,12 +203,12 @@ theorem map_attach_eq_attachWith {o : Option α} {p : α → Prop} (f : ∀ a, o
|
||||
o.attach.map (fun x => ⟨x.1, f x.1 x.2⟩) = o.attachWith p f := by
|
||||
cases o <;> simp_all [Function.comp_def]
|
||||
|
||||
theorem attach_bind {o : Option α} {f : α → Option β} :
|
||||
@[grind =] theorem attach_bind {o : Option α} {f : α → Option β} :
|
||||
(o.bind f).attach =
|
||||
o.attach.bind fun ⟨x, h⟩ => (f x).attach.map fun ⟨y, h'⟩ => ⟨y, bind_eq_some_iff.2 ⟨_, h, h'⟩⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem bind_attach {o : Option α} {f : {x // o = some x} → Option β} :
|
||||
@[grind =] theorem bind_attach {o : Option α} {f : {x // o = some x} → Option β} :
|
||||
o.attach.bind f = o.pbind fun a h => f ⟨a, h⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -187,7 +216,7 @@ theorem pbind_eq_bind_attach {o : Option α} {f : (a : α) → o = some a → Op
|
||||
o.pbind f = o.attach.bind fun ⟨x, h⟩ => f x h := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem attach_filter {o : Option α} {p : α → Bool} :
|
||||
@[grind =] theorem attach_filter {o : Option α} {p : α → Bool} :
|
||||
(o.filter p).attach =
|
||||
o.attach.bind fun ⟨x, h⟩ => if h' : p x then some ⟨x, by simp_all⟩ else none := by
|
||||
cases o with
|
||||
@@ -203,7 +232,12 @@ theorem attach_filter {o : Option α} {p : α → Bool} :
|
||||
· rintro ⟨h, rfl⟩
|
||||
simp [h]
|
||||
|
||||
theorem filter_attach {o : Option α} {p : {x // o = some x} → Bool} :
|
||||
@[grind =] theorem filter_attachWith {P : α → Prop} {o : Option α} {h : ∀ x, o = some x → P x} {q : α → Bool} :
|
||||
(o.attachWith P h).filter q =
|
||||
(o.filter q).attachWith P (fun _ h' => h _ (eq_some_of_filter_eq_some h')) := by
|
||||
cases o <;> simp [filter_some] <;> split <;> simp
|
||||
|
||||
@[grind =] theorem filter_attach {o : Option α} {p : {x // o = some x} → Bool} :
|
||||
o.attach.filter p = o.pbind fun a h => if p ⟨a, h⟩ then some ⟨a, h⟩ else none := by
|
||||
cases o <;> simp [filter_some]
|
||||
|
||||
@@ -211,6 +245,64 @@ theorem toList_pbind {o : Option α} {f : (a : α) → o = some a → Option β}
|
||||
(o.pbind f).toList = o.attach.toList.flatMap (fun ⟨x, h⟩ => (f x h).toList) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toArray_pbind {o : Option α} {f : (a : α) → o = some a → Option β} :
|
||||
(o.pbind f).toArray = o.attach.toArray.flatMap (fun ⟨x, h⟩ => (f x h).toArray) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toList_pfilter {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
(o.pfilter p).toList = (o.toList.attach.filter (fun x => p x.1 (by simpa using x.2))).unattach := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [pfilter_some, toList_some, List.attach_cons, List.attach_nil, List.map_nil]
|
||||
split <;> rename_i h
|
||||
· rw [List.filter_cons_of_pos h]; simp
|
||||
· rw [List.filter_cons_of_neg h]; simp
|
||||
|
||||
theorem toArray_pfilter {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
(o.pfilter p).toArray = (o.toArray.attach.filter (fun x => p x.1 (by simpa using x.2))).unattach := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [pfilter_some, toArray_some, List.attach_toArray, List.attachWith_mem_toArray,
|
||||
List.attach_cons, List.attach_nil, List.map_nil, List.map_cons, List.size_toArray,
|
||||
List.length_cons, List.length_nil, Nat.zero_add, List.filter_toArray', List.unattach_toArray]
|
||||
split <;> rename_i h
|
||||
· rw [List.filter_cons_of_pos h]; simp
|
||||
· rw [List.filter_cons_of_neg h]; simp
|
||||
|
||||
theorem toList_pmap {p : α → Prop} {o : Option α} {f : (a : α) → p a → β}
|
||||
(h : ∀ a, o = some a → p a) :
|
||||
(o.pmap f h).toList = o.attach.toList.map (fun x => f x.1 (h _ x.2)) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toArray_pmap {p : α → Prop} {o : Option α} {f : (a : α) → p a → β}
|
||||
(h : ∀ a, o = some a → p a) :
|
||||
(o.pmap f h).toArray = o.attach.toArray.map (fun x => f x.1 (h _ x.2)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind =] theorem attach_pfilter {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
(o.pfilter p).attach =
|
||||
o.attach.pbind fun x h => if h' : p x (by simp_all) then
|
||||
some ⟨x.1, by simpa [pfilter_eq_some_iff] using ⟨_, h'⟩⟩ else none := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [attach_some, eq_mp_eq_cast, id_eq, pbind_some]
|
||||
rw [attach_congr pfilter_some]
|
||||
split <;> simp [*]
|
||||
|
||||
theorem attach_guard {p : α → Bool} {x : α} :
|
||||
(guard p x).attach = if h : p x then some ⟨x, by simp_all⟩ else none := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [*]
|
||||
|
||||
theorem attachWith_guard {q : α → Bool} {x : α} {P : α → Prop}
|
||||
{h : ∀ a, guard q x = some a → P a} :
|
||||
(guard q x).attachWith P h = if h' : q x then some ⟨x, h _ (by simp_all)⟩ else none := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [*]
|
||||
|
||||
/-! ## unattach
|
||||
|
||||
`Option.unattach` is the (one-sided) inverse of `Option.attach`. It is a synonym for `Option.map Subtype.val`.
|
||||
@@ -255,6 +347,29 @@ def unattach {α : Type _} {p : α → Prop} (o : Option { x // p x }) := o.map
|
||||
(o.attachWith p H).unattach = o := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem unattach_eq_some_iff {p : α → Prop} {o : Option { x // p x }} {x : α} :
|
||||
o.unattach = some x ↔ ∃ h, o = some ⟨x, h⟩ :=
|
||||
match o with
|
||||
| none => by simp
|
||||
| some ⟨y, h⟩ => by simpa using fun h' => h' ▸ h
|
||||
|
||||
@[simp]
|
||||
theorem unattach_eq_none_iff {p : α → Prop} {o : Option { x // p x }} :
|
||||
o.unattach = none ↔ o = none := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem get_unattach {p : α → Prop} {o : Option { x // p x }} {h} :
|
||||
o.unattach.get h = (o.get (by simpa using h)).1 := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toList_unattach {p : α → Prop} {o : Option { x // p x }} :
|
||||
o.unattach.toList = o.toList.unattach := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toArray_unattach {p : α → Prop} {o : Option { x // p x }} :
|
||||
o.unattach.toArray = o.toArray.unattach := by
|
||||
cases o <;> simp
|
||||
|
||||
/-! ### Recognizing higher order functions on subtypes using a function that only depends on the value. -/
|
||||
|
||||
/--
|
||||
@@ -279,4 +394,51 @@ and simplifies these to the function directly taking the value.
|
||||
· simp only [filter_some, hf, unattach_some]
|
||||
split <;> simp
|
||||
|
||||
@[simp] theorem unattach_guard {p : α → Prop} {q : { x // p x } → Bool} {r : α → Bool}
|
||||
(hq : ∀ x h, q ⟨x, h⟩ = r x) {x : { x // p x }} :
|
||||
(guard q x).unattach = guard r x.1 := by
|
||||
simp only [guard]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem unattach_pfilter {p : α → Prop} {o : Option { x // p x }}
|
||||
{f : (a : { x // p x }) → o = some a → Bool}
|
||||
{g : (a : α) → o.unattach = some a → Bool} (hf : ∀ x h h', f ⟨x, h⟩ h' = g x (by simp_all)) :
|
||||
(o.pfilter f).unattach = o.unattach.pfilter g := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [hf, pfilter_some, unattach_some]
|
||||
split <;> simp
|
||||
|
||||
@[simp] theorem unattach_merge {p : α → Prop} {f : { x // p x } → { x // p x } → { x // p x }}
|
||||
{g : α → α → α} (hf : ∀ x h y h', (f ⟨x, h⟩ ⟨y, h'⟩).1 = g x y) {o o' : Option { x // p x }} :
|
||||
(o.merge f o').unattach = o.unattach.merge g o'.unattach := by
|
||||
cases o <;> cases o' <;> simp [*]
|
||||
|
||||
theorem any_attach {p : α → Bool} {o : Option α} {q : { x // o = some x } → Bool}
|
||||
(h : ∀ x h, q ⟨x, h⟩ = p x) : o.attach.any q = o.any p := by
|
||||
cases o <;> simp [*]
|
||||
|
||||
theorem any_attachWith {p : α → Bool} {o : Option α} {r : α → Prop} (hr : ∀ x, o = some x → r x)
|
||||
{q : { x // r x } → Bool}
|
||||
(h : ∀ x h, q ⟨x, h⟩ = p x) : (o.attachWith r hr).any q = o.any p := by
|
||||
cases o <;> simp [*]
|
||||
|
||||
theorem any_unattach {p : α → Prop} {o : Option { x // p x }} {q : α → Bool} :
|
||||
o.unattach.any q = o.any (q ∘ Subtype.val) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem all_attach {p : α → Bool} {o : Option α} {q : { x // o = some x } → Bool}
|
||||
(h : ∀ x h, q ⟨x, h⟩ = p x) : o.attach.all q = o.all p := by
|
||||
cases o <;> simp [*]
|
||||
|
||||
theorem all_attachWith {p : α → Bool} {o : Option α} {r : α → Prop} (hr : ∀ x, o = some x → r x)
|
||||
{q : { x // r x } → Bool}
|
||||
(h : ∀ x h, q ⟨x, h⟩ = p x) : (o.attachWith r hr).all q = o.all p := by
|
||||
cases o <;> simp [*]
|
||||
|
||||
theorem all_unattach {p : α → Prop} {o : Option { x // p x }} {q : α → Bool} :
|
||||
o.unattach.all q = o.all (q ∘ Subtype.val) := by
|
||||
cases o <;> simp
|
||||
|
||||
end Option
|
||||
|
||||
@@ -102,11 +102,9 @@ From the perspective of `Option` as a collection with at most one element, the m
|
||||
is applied to the element if present, and the final result is empty if either the initial or the
|
||||
resulting collections are empty.
|
||||
-/
|
||||
@[inline] protected def bindM [Monad m] (f : α → m (Option β)) (o : Option α) : m (Option β) := do
|
||||
if let some a := o then
|
||||
return (← f a)
|
||||
else
|
||||
return none
|
||||
@[inline] protected def bindM [Pure m] (f : α → m (Option β)) : Option α → m (Option β)
|
||||
| none => pure none
|
||||
| some a => f a
|
||||
|
||||
/--
|
||||
Applies a function in some applicative functor to an optional value, returning `none` with no
|
||||
|
||||
@@ -14,6 +14,8 @@ import Init.Ext
|
||||
|
||||
namespace Option
|
||||
|
||||
@[grind =] theorem default_eq_none : (default : Option α) = none := rfl
|
||||
|
||||
@[deprecated mem_def (since := "2025-04-07")]
|
||||
theorem mem_iff {a : α} {b : Option α} : a ∈ b ↔ b = some a := .rfl
|
||||
|
||||
@@ -149,6 +151,22 @@ theorem not_isSome_iff_eq_none : ¬o.isSome ↔ o = none := by
|
||||
|
||||
theorem ne_none_iff_isSome : o ≠ none ↔ o.isSome := by cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem any_true {o : Option α} : o.any (fun _ => true) = o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem any_false {o : Option α} : o.any (fun _ => false) = false := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem all_true {o : Option α} : o.all (fun _ => true) = true := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem all_false {o : Option α} : o.all (fun _ => false) = o.isNone := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem ne_none_iff_exists : o ≠ none ↔ ∃ x, some x = o := by cases o <;> simp
|
||||
|
||||
theorem ne_none_iff_exists' : o ≠ none ↔ ∃ x, o = some x :=
|
||||
@@ -176,8 +194,6 @@ abbrev ball_ne_none := @forall_ne_none
|
||||
|
||||
@[simp, grind] theorem bind_eq_bind : bind = @Option.bind α β := rfl
|
||||
|
||||
@[simp, grind] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
|
||||
|
||||
@[simp, grind] theorem bind_fun_some (x : Option α) : x.bind some = x := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem bind_fun_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
|
||||
@@ -238,10 +254,18 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α →
|
||||
(isSome_apply_of_isSome_bind h) := by
|
||||
cases x <;> trivial
|
||||
|
||||
theorem join_eq_bind_id {x : Option (Option α)} : x.join = x.bind id := rfl
|
||||
@[grind =] theorem any_bind {p : β → Bool} {f : α → Option β} {o : Option α} :
|
||||
(o.bind f).any p = o.any (Option.any p ∘ f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind =] theorem all_bind {p : β → Bool} {f : α → Option β} {o : Option α} :
|
||||
(o.bind f).all p = o.all (Option.all p ∘ f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind] theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
|
||||
|
||||
theorem join_eq_some_iff : x.join = some a ↔ x = some (some a) := by
|
||||
simp [join_eq_bind_id, bind_eq_some_iff]
|
||||
simp [← bind_id_eq_join, bind_eq_some_iff]
|
||||
|
||||
@[deprecated join_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev join_eq_some := @join_eq_some_iff
|
||||
@@ -253,12 +277,14 @@ theorem join_ne_none' : ¬x.join = none ↔ ∃ z, x = some (some z) :=
|
||||
join_ne_none
|
||||
|
||||
theorem join_eq_none_iff : o.join = none ↔ o = none ∨ o = some none :=
|
||||
match o with | none | some none | some (some _) => by simp [join_eq_bind_id]
|
||||
match o with | none | some none | some (some _) => by simp [bind_id_eq_join]
|
||||
|
||||
@[deprecated join_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev join_eq_none := @join_eq_none_iff
|
||||
|
||||
@[grind] theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
|
||||
theorem bind_join {f : α → Option β} {o : Option (Option α)} :
|
||||
o.join.bind f = o.bind (·.bind f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem map_eq_map : Functor.map f = Option.map f := rfl
|
||||
|
||||
@@ -395,11 +421,17 @@ theorem mem_filter_iff {p : α → Bool} {a : α} {o : Option α} :
|
||||
a ∈ o.filter p ↔ a ∈ o ∧ p a := by
|
||||
simp
|
||||
|
||||
theorem filter_eq_bind (x : Option α) (p : α → Bool) :
|
||||
x.filter p = x.bind (Option.guard p) := by
|
||||
@[grind]
|
||||
theorem bind_guard (x : Option α) (p : α → Bool) :
|
||||
x.bind (Option.guard p) = x.filter p := by
|
||||
cases x <;> rfl
|
||||
|
||||
@[simp] theorem any_filter : (o : Option α) →
|
||||
@[deprecated bind_guard (since := "2025-05-15")]
|
||||
theorem filter_eq_bind (x : Option α) (p : α → Bool) :
|
||||
x.filter p = x.bind (Option.guard p) :=
|
||||
(bind_guard x p).symm
|
||||
|
||||
@[simp, grind =] theorem any_filter : (o : Option α) →
|
||||
(Option.filter p o).any q = Option.any (fun a => p a && q a) o
|
||||
| none => rfl
|
||||
| some a =>
|
||||
@@ -407,7 +439,7 @@ theorem filter_eq_bind (x : Option α) (p : α → Bool) :
|
||||
| false => by simp [filter_some_neg h, h]
|
||||
| true => by simp [filter_some_pos h, h]
|
||||
|
||||
@[simp] theorem all_filter : (o : Option α) →
|
||||
@[simp, grind =] theorem all_filter : (o : Option α) →
|
||||
(Option.filter p o).all q = Option.all (fun a => !p a || q a) o
|
||||
| none => rfl
|
||||
| some a =>
|
||||
@@ -415,7 +447,7 @@ theorem filter_eq_bind (x : Option α) (p : α → Bool) :
|
||||
| false => by simp [filter_some_neg h, h]
|
||||
| true => by simp [filter_some_pos h, h]
|
||||
|
||||
@[simp] theorem isNone_filter :
|
||||
@[simp, grind =] theorem isNone_filter :
|
||||
Option.isNone (Option.filter p o) = Option.all (fun a => !p a) o :=
|
||||
match o with
|
||||
| none => rfl
|
||||
@@ -436,7 +468,7 @@ theorem filter_eq_bind (x : Option α) (p : α → Bool) :
|
||||
Option.filter q (Option.filter p o) = Option.filter (fun x => p x && q x) o := by
|
||||
cases o <;> repeat (simp_all [filter_some]; try split)
|
||||
|
||||
theorem filter_bind {f : α → Option β} :
|
||||
@[grind =] theorem filter_bind {f : α → Option β} :
|
||||
(Option.bind x f).filter p = (x.filter (fun a => (f a).any p)).bind f := by
|
||||
cases x with
|
||||
| none => simp
|
||||
@@ -451,16 +483,16 @@ theorem filter_bind {f : α → Option β} :
|
||||
theorem eq_some_of_filter_eq_some {o : Option α} {a : α} (h : o.filter p = some a) : o = some a :=
|
||||
filter_eq_some_iff.1 h |>.1
|
||||
|
||||
theorem filter_map {f : α → β} {p : β → Bool} :
|
||||
@[grind =] theorem filter_map {f : α → β} {p : β → Bool} :
|
||||
(Option.map f x).filter p = (x.filter (p ∘ f)).map f := by
|
||||
cases x <;> simp [filter_some]
|
||||
|
||||
@[simp, grind] theorem all_guard (a : α) :
|
||||
@[simp] theorem all_guard (a : α) :
|
||||
Option.all q (guard p a) = (!p a || q a) := by
|
||||
simp only [guard]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind] theorem any_guard (a : α) : Option.any q (guard p a) = (p a && q a) := by
|
||||
@[simp] theorem any_guard (a : α) : Option.any q (guard p a) = (p a && q a) := by
|
||||
simp only [guard]
|
||||
split <;> simp_all
|
||||
|
||||
@@ -499,6 +531,10 @@ theorem any_eq_false_iff_get (p : α → Bool) (x : Option α) :
|
||||
theorem isSome_of_any {x : Option α} {p : α → Bool} (h : x.any p) : x.isSome := by
|
||||
cases x <;> trivial
|
||||
|
||||
theorem get_of_any_eq_true (p : α → Bool) (x : Option α) (h : x.any p = true) :
|
||||
p (x.get (isSome_of_any h)) :=
|
||||
any_eq_true_iff_get p x |>.1 h |>.2
|
||||
|
||||
@[grind]
|
||||
theorem any_map {α β : Type _} {x : Option α} {f : α → β} {p : β → Bool} :
|
||||
(x.map f).any p = x.any (fun a => p (f a)) := by
|
||||
@@ -527,41 +563,54 @@ theorem bind_map_comm {α β} {x : Option (Option α)} {f : α → β} :
|
||||
theorem mem_of_mem_join {a : α} {x : Option (Option α)} (h : a ∈ x.join) : some a ∈ x :=
|
||||
h.symm ▸ join_eq_some_iff.1 h
|
||||
|
||||
@[deprecated orElse_some (since := "2025-05-03")]
|
||||
theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
|
||||
|
||||
@[deprecated orElse_none (since := "2025-05-03")]
|
||||
theorem none_orElse (f : Unit → Option α) : none.orElse f = f () := rfl
|
||||
|
||||
@[simp] theorem orElse_fun_none (x : Option α) : x.orElse (fun _ => none) = x := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem orElse_fun_some (x : Option α) (a : α) :
|
||||
x.orElse (fun _ => some a) = some (x.getD a) := by
|
||||
@[grind _=_] theorem any_join {p : α → Bool} {x : Option (Option α)} :
|
||||
x.join.any p = x.any (Option.any p) := by
|
||||
cases x <;> simp
|
||||
|
||||
theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
|
||||
(o.orElse f) = some x ↔ o = some x ∨ o = none ∧ f () = some x := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem orElse_eq_none_iff (o : Option α) (f) : (o.orElse f) = none ↔ o = none ∧ f () = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind] theorem map_orElse {x : Option α} {y} :
|
||||
(x.orElse y).map f = (x.map f).orElse (fun _ => (y ()).map f) := by
|
||||
@[grind _=_] theorem all_join {p : α → Bool} {x : Option (Option α)} :
|
||||
x.join.all p = x.all (Option.all p) := by
|
||||
cases x <;> simp
|
||||
|
||||
@[grind =] theorem isNone_join {x : Option (Option α)} : x.join.isNone = x.all Option.isNone := by
|
||||
cases x <;> simp
|
||||
|
||||
@[grind =]theorem isSome_join {x : Option (Option α)} : x.join.isSome = x.any Option.isSome := by
|
||||
cases x <;> simp
|
||||
|
||||
@[grind =] theorem get_join {x : Option (Option α)} {h} : x.join.get h =
|
||||
(x.get (Option.isSome_of_any (Option.isSome_join ▸ h))).get (get_of_any_eq_true _ _ (Option.isSome_join ▸ h)) := by
|
||||
cases x with
|
||||
| none => simp at h
|
||||
| some _ => simp
|
||||
|
||||
theorem join_eq_get {x : Option (Option α)} {h} : x.join = x.get h := by
|
||||
cases x with
|
||||
| none => simp at h
|
||||
| some _ => simp
|
||||
|
||||
@[grind =] theorem getD_join {x : Option (Option α)} {default : α} :
|
||||
x.join.getD default = (x.getD (some default)).getD default := by
|
||||
cases x <;> simp
|
||||
|
||||
@[grind =] theorem get!_join [Inhabited α] {x : Option (Option α)} :
|
||||
x.join.get! = x.get!.get! := by
|
||||
cases x <;> simp [default_eq_none]
|
||||
|
||||
@[simp] theorem guard_eq_some_iff : guard p a = some b ↔ a = b ∧ p a :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@[deprecated guard_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev guard_eq_some := @guard_eq_some_iff
|
||||
|
||||
@[simp] theorem isSome_guard : (Option.guard p a).isSome = p a :=
|
||||
@[simp, grind =] theorem isSome_guard : (Option.guard p a).isSome = p a :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@[deprecated isSome_guard (since := "2025-03-18")]
|
||||
abbrev guard_isSome := @isSome_guard
|
||||
|
||||
@[simp, grind =] theorem isNone_guard : (Option.guard p a).isNone = !p a := by
|
||||
rw [← not_isSome, isSome_guard]
|
||||
|
||||
@[simp] theorem guard_eq_none_iff : Option.guard p a = none ↔ p a = false :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@@ -587,19 +636,27 @@ theorem guard_comp {p : α → Bool} {f : β → α} :
|
||||
ext1 b
|
||||
simp [guard]
|
||||
|
||||
@[grind] theorem bind_guard (x : Option α) (p : α → Bool) :
|
||||
x.bind (Option.guard p) = x.filter p := by
|
||||
simp only [Option.filter_eq_bind, decide_eq_true_eq]
|
||||
theorem get_none (a : α) {h} : none.get h = a := by
|
||||
simp at h
|
||||
|
||||
theorem guard_eq_map (p : α → Bool) :
|
||||
Option.guard p = fun x => Option.map (fun _ => x) (if p x then some x else none) := by
|
||||
funext x
|
||||
simp [Option.guard]
|
||||
@[simp]
|
||||
theorem get_none_eq_iff_true {h} : (none : Option α).get h = a ↔ True := by
|
||||
simp at h
|
||||
|
||||
@[simp, grind =] theorem get_guard : (guard p a).get h = a := by
|
||||
simp only [guard]
|
||||
split <;> simp
|
||||
|
||||
@[grind]
|
||||
theorem guard_def (p : α → Bool) :
|
||||
Option.guard p = fun x => if p x then some x else none := rfl
|
||||
|
||||
@[deprecated guard_def (since := "2025-05-15")]
|
||||
theorem guard_eq_map (p : α → Bool) :
|
||||
Option.guard p = fun x => Option.map (fun _ => x) (if p x then some x else none) := by
|
||||
funext x
|
||||
simp [Option.guard]
|
||||
|
||||
theorem guard_eq_ite {p : α → Bool} {x : α} :
|
||||
Option.guard p x = if p x then some x else none := rfl
|
||||
|
||||
@@ -611,7 +668,11 @@ theorem guard_eq_filter {p : α → Bool} {x : α} :
|
||||
rw [guard_eq_ite]
|
||||
split <;> simp_all [filter_some, guard_eq_ite]
|
||||
|
||||
theorem join_filter {p : Option α → Bool} : {o : Option (Option α)} →
|
||||
theorem map_guard {p : α → Bool} {f : α → β} {x : α} :
|
||||
(Option.guard p x).map f = if p x then some (f x) else none := by
|
||||
simp [guard_eq_ite]
|
||||
|
||||
@[grind =] theorem join_filter {p : Option α → Bool} : {o : Option (Option α)} →
|
||||
(o.filter p).join = o.join.filter (fun a => p (some a))
|
||||
| none => by simp
|
||||
| some none => by
|
||||
@@ -621,7 +682,7 @@ theorem join_filter {p : Option α → Bool} : {o : Option (Option α)} →
|
||||
simp only [join_some, filter_some]
|
||||
split <;> simp
|
||||
|
||||
theorem filter_join {p : α → Bool} : {o : Option (Option α)} →
|
||||
@[grind =] theorem filter_join {p : α → Bool} : {o : Option (Option α)} →
|
||||
o.join.filter p = (o.filter (Option.any p)).join
|
||||
| none => by simp
|
||||
| some none => by
|
||||
@@ -680,11 +741,49 @@ instance lawfulIdentity_merge (f : α → α → α) : Std.LawfulIdentity (merge
|
||||
left_id a := by cases a <;> simp [merge]
|
||||
right_id a := by cases a <;> simp [merge]
|
||||
|
||||
theorem merge_join {o o' : Option (Option α)} {f : α → α → α} :
|
||||
o.join.merge f o'.join = (o.merge (Option.merge f) o').join := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
theorem merge_eq_some_iff {o o' : Option α} {f : α → α → α} {a : α} :
|
||||
o.merge f o' = some a ↔ (o = some a ∧ o' = none) ∨ (o = none ∧ o' = some a) ∨
|
||||
(∃ b c, o = some b ∧ o' = some c ∧ f b c = a) := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem merge_eq_none_iff {o o' : Option α} : o.merge f o' = none ↔ o = none ∧ o' = none := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem any_merge {p : α → Bool} {f : α → α → α} (hpf : ∀ a b, p (f a b) = (p a || p b))
|
||||
{o o' : Option α} : (o.merge f o').any p = (o.any p || o'.any p) := by
|
||||
cases o <;> cases o' <;> simp [*]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem all_merge {p : α → Bool} {f : α → α → α} (hpf : ∀ a b, p (f a b) = (p a && p b))
|
||||
{o o' : Option α} : (o.merge f o').all p = (o.all p && o'.all p) := by
|
||||
cases o <;> cases o' <;> simp [*]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isSome_merge {o o' : Option α} {f : α → α → α} :
|
||||
(o.merge f o').isSome = (o.isSome || o'.isSome) := by
|
||||
simp [← any_true]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isNone_merge {o o' : Option α} {f : α → α → α} :
|
||||
(o.merge f o').isNone = (o.isNone && o'.isNone) := by
|
||||
simp [← all_false]
|
||||
|
||||
@[simp]
|
||||
theorem get_merge {o o' : Option α} {f : α → α → α} {i : α} [Std.LawfulIdentity f i] {h} :
|
||||
(o.merge f o').get h = f (o.getD i) (o'.getD i) := by
|
||||
cases o <;> cases o' <;> simp [Std.LawfulLeftIdentity.left_id, Std.LawfulRightIdentity.right_id]
|
||||
|
||||
@[simp, grind] theorem elim_none (x : β) (f : α → β) : none.elim x f = x := rfl
|
||||
|
||||
@[simp, grind] theorem elim_some (x : β) (f : α → β) (a : α) : (some a).elim x f = f a := rfl
|
||||
|
||||
theorem elim_filter {o : Option α} {b : β} :
|
||||
@[grind =] theorem elim_filter {o : Option α} {b : β} :
|
||||
Option.elim (Option.filter p o) b f = Option.elim o b (fun a => if p a then f a else b) :=
|
||||
match o with
|
||||
| none => rfl
|
||||
@@ -693,6 +792,13 @@ theorem elim_filter {o : Option α} {b : β} :
|
||||
| false => by simp [filter_some_neg h, h]
|
||||
| true => by simp [filter_some_pos, h]
|
||||
|
||||
@[grind =] theorem elim_join {o : Option (Option α)} {b : β} {f : α → β} :
|
||||
o.join.elim b f = o.elim b (·.elim b f) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem elim_guard : (guard p a).elim b f = if p a then f a else b := by
|
||||
cases h : p a <;> simp [*, guard]
|
||||
|
||||
@[simp, grind] theorem getD_map (f : α → β) (x : α) (o : Option α) :
|
||||
(o.map f).getD (f x) = f (getD o x) := by cases o <;> rfl
|
||||
|
||||
@@ -724,14 +830,35 @@ theorem choice_eq_default [Subsingleton α] [Inhabited α] : choice α = some de
|
||||
theorem choice_eq_none_iff_not_nonempty : choice α = none ↔ ¬Nonempty α := by
|
||||
simp [choice]
|
||||
|
||||
theorem isNone_choice_iff_not_nonempty : (choice α).isNone ↔ ¬Nonempty α := by
|
||||
rw [isNone_iff_eq_none, choice_eq_none_iff_not_nonempty]
|
||||
|
||||
grind_pattern isNone_choice_iff_not_nonempty => (choice α).isNone
|
||||
|
||||
theorem isSome_choice_iff_nonempty : (choice α).isSome ↔ Nonempty α :=
|
||||
⟨fun h => ⟨(choice α).get h⟩, fun h => by simp only [choice, dif_pos h, isSome_some]⟩
|
||||
|
||||
grind_pattern isSome_choice_iff_nonempty => (choice α).isSome
|
||||
|
||||
@[simp]
|
||||
theorem isSome_choice [Nonempty α] : (choice α).isSome :=
|
||||
isSome_choice_iff_nonempty.2 inferInstance
|
||||
|
||||
@[deprecated isSome_choice_iff_nonempty (since := "2025-03-18")]
|
||||
abbrev choice_isSome_iff_nonempty := @isSome_choice_iff_nonempty
|
||||
|
||||
theorem isNone_choice_iff_not_nonempty : (choice α).isNone ↔ ¬Nonempty α := by
|
||||
rw [isNone_iff_eq_none, choice_eq_none_iff_not_nonempty]
|
||||
@[simp]
|
||||
theorem isNone_choice_eq_false [Nonempty α] : (choice α).isNone = false := by
|
||||
simp [← not_isSome]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem getD_choice {a} :
|
||||
(choice α).getD a = (choice α).get (isSome_choice_iff_nonempty.2 ⟨a⟩) := by
|
||||
rw [get_eq_getD]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem get!_choice [Inhabited α] : (choice α).get! = (choice α).get isSome_choice := by
|
||||
rw [get_eq_get!]
|
||||
|
||||
end choice
|
||||
|
||||
@@ -796,9 +923,6 @@ theorem or_self : or o o = o := by
|
||||
cases o <;> rfl
|
||||
instance : Std.IdempotentOp (or (α := α)) := ⟨@or_self _⟩
|
||||
|
||||
theorem or_eq_orElse : or o o' = o.orElse (fun _ => o') := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[grind _=_] theorem map_or : (or o o').map f = (o.map f).or (o'.map f) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@@ -813,15 +937,59 @@ theorem or_of_isNone {o o' : Option α} (h : o.isNone) : o.or o' = o' := by
|
||||
match o, h with
|
||||
| none, _ => simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getD_or {o o' : Option α} {fallback : α} :
|
||||
(o.or o').getD fallback = o.getD (o'.getD fallback) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem filter_or_filter {o o' : Option α} {f : α → Bool} :
|
||||
@[simp, grind =]
|
||||
theorem get!_or {o o' : Option α} [Inhabited α] : (o.or o').get! = o.getD o'.get! := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem filter_or_filter {o o' : Option α} {f : α → Bool} :
|
||||
(o.or (o'.filter f)).filter f = (o.or o').filter f := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
theorem guard_or_guard : (guard p a).or (guard q a) = guard (fun x => p x || q x) a := by
|
||||
simp only [guard]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### `orElse` -/
|
||||
|
||||
/-- The `simp` normal form of `o <|> o'` is `o.or o'` via `orElse_eq_orElse` and `orElse_eq_or`. -/
|
||||
@[simp, grind] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
|
||||
|
||||
theorem or_eq_orElse : or o o' = o.orElse (fun _ => o') := by
|
||||
cases o <;> rfl
|
||||
|
||||
/-- The `simp` normal form of `o.orElse f` is o.or (f ())`. -/
|
||||
@[simp, grind] theorem orElse_eq_or {o : Option α} {f} : o.orElse f = o.or (f ()) := by
|
||||
simp [or_eq_orElse]
|
||||
|
||||
@[deprecated or_some (since := "2025-05-03")]
|
||||
theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
|
||||
|
||||
@[deprecated or_none (since := "2025-05-03")]
|
||||
theorem none_orElse (f : Unit → Option α) : none.orElse f = f () := rfl
|
||||
|
||||
@[deprecated or_none (since := "2025-05-13")]
|
||||
theorem orElse_fun_none (x : Option α) : x.orElse (fun _ => none) = x := by simp
|
||||
|
||||
@[deprecated or_some (since := "2025-05-13")]
|
||||
theorem orElse_fun_some (x : Option α) (a : α) :
|
||||
x.orElse (fun _ => some a) = some (x.getD a) := by simp
|
||||
|
||||
@[deprecated or_eq_some_iff (since := "2025-05-13")]
|
||||
theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
|
||||
(o.orElse f) = some x ↔ o = some x ∨ o = none ∧ f () = some x := by simp
|
||||
|
||||
@[deprecated or_eq_none_iff (since := "2025-05-13")]
|
||||
theorem orElse_eq_none_iff (o : Option α) (f) : (o.orElse f) = none ↔ o = none ∧ f () = none := by simp
|
||||
|
||||
@[deprecated map_or (since := "2025-05-13")]
|
||||
theorem map_orElse {x : Option α} {y} :
|
||||
(x.orElse y).map f = (x.map f).orElse (fun _ => (y ()).map f) := by simp [map_or]
|
||||
|
||||
/-! ### beq -/
|
||||
|
||||
section beq
|
||||
@@ -860,6 +1028,42 @@ variable [BEq α]
|
||||
· intro h
|
||||
infer_instance
|
||||
|
||||
@[simp] theorem beq_none {o : Option α} : (o == none) = o.isNone := by cases o <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem filter_beq_self [ReflBEq α] {p : α → Bool} {o : Option α} : (o.filter p == o) = o.all p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem self_beq_filter [ReflBEq α] {p : α → Bool} {o : Option α} : (o == o.filter p) = o.all p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [*]
|
||||
|
||||
theorem join_beq_some {o : Option (Option α)} {a : α} : (o.join == some a) = (o == some (some a)) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem join_beq_none {o : Option (Option α)} : (o.join == none) = (o == none || o == some none) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem guard_beq_some [ReflBEq α] {x : α} {p : α → Bool} : (guard p x == some x) = p x := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [*]
|
||||
|
||||
theorem guard_beq_none {x : α} {p : α → Bool} : (guard p x == none) = !p x := by
|
||||
simp
|
||||
|
||||
theorem merge_beq_none {o o' : Option α} {f : α → α → α} :
|
||||
(o.merge f o' == none) = (o == none && o' == none) := by
|
||||
simp [beq_none]
|
||||
|
||||
end beq
|
||||
|
||||
/-! ### ite -/
|
||||
@@ -897,6 +1101,9 @@ section ite
|
||||
some a = (if p then b else none) ↔ p ∧ some a = b := by
|
||||
split <;> simp_all
|
||||
|
||||
theorem ite_some_none_eq_some {p : Prop} {_ : Decidable p} {a b : α} :
|
||||
(if p then some a else none) = some b ↔ p ∧ a = b := by simp
|
||||
|
||||
theorem mem_dite_none_left {x : α} {_ : Decidable p} {l : ¬ p → Option α} :
|
||||
(x ∈ if h : p then none else l h) ↔ ∃ h : ¬ p, x ∈ l h := by
|
||||
simp
|
||||
@@ -988,6 +1195,10 @@ theorem isSome_pbind_iff {o : Option α} {f : (a : α) → o = some a → Option
|
||||
(o.pbind f).isSome ↔ ∃ a h, (f a h).isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isNone_pbind_iff {o : Option α} {f : (a : α) → o = some a → Option β} :
|
||||
(o.pbind f).isNone ↔ o = none ∨ ∃ a h, f a h = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated "isSome_pbind_iff" (since := "2025-04-01")]
|
||||
theorem pbind_isSome {o : Option α} {f : (a : α) → o = some a → Option β} :
|
||||
(o.pbind f).isSome = ∃ a h, (f a h).isSome := by
|
||||
@@ -997,6 +1208,25 @@ theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → o = some a → Optio
|
||||
o.pbind f = some b ↔ ∃ a h, f a h = some b := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind =] theorem pbind_join {o : Option (Option α)} {f : (a : α) → o.join = some a → Option β} :
|
||||
o.join.pbind f = o.pbind (fun o' ho' => o'.pbind (fun a ha => f a (by simp_all))) := by
|
||||
cases o <;> simp <;> congr
|
||||
|
||||
theorem isSome_of_isSome_pbind {o : Option α} {f : (a : α) → o = some a → Option β} :
|
||||
(o.pbind f).isSome → o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isSome_get_of_isSome_pbind {o : Option α} {f : (a : α) → o = some a → Option β}
|
||||
(h : (o.pbind f).isSome) : (f (o.get (isSome_of_isSome_pbind h)) (by simp)).isSome := by
|
||||
cases o with
|
||||
| none => simp at h
|
||||
| some a => simp [← h]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem get_pbind {o : Option α} {f : (a : α) → o = some a → Option β} {h} :
|
||||
(o.pbind f).get h = (f (o.get (isSome_of_isSome_pbind h)) (by simp)).get (isSome_get_of_isSome_pbind h) := by
|
||||
cases o <;> simp
|
||||
|
||||
/-! ### pmap -/
|
||||
|
||||
@[simp, grind] theorem pmap_none {p : α → Prop} {f : ∀ (a : α), p a → β} {h} :
|
||||
@@ -1030,7 +1260,7 @@ theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → o = some a → Optio
|
||||
· rintro ⟨h, rfl⟩
|
||||
rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp]
|
||||
theorem pmap_eq_map (p : α → Prop) (f : α → β) (o : Option α) (H) :
|
||||
@pmap _ _ p (fun a _ => f a) o H = Option.map f o := by
|
||||
cases o <;> simp
|
||||
@@ -1073,12 +1303,24 @@ theorem pmap_congr {α : Type u} {β : Type v}
|
||||
· dsimp
|
||||
rw [hf]
|
||||
|
||||
theorem pmap_guard {q : α → Bool} {p : α → Prop} (f : (x : α) → p x → β) {x : α}
|
||||
(h : ∀ (a : α), guard q x = some a → p a) :
|
||||
(guard q x).pmap f h = if h' : q x then some (f x (h _ (by simp_all))) else none := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind =]
|
||||
theorem get_pmap {p : α → Bool} {f : (x : α) → p x → β} {o : Option α}
|
||||
{h : ∀ a, o = some a → p a} {h'} :
|
||||
(o.pmap f h).get h' = f (o.get (by simpa using h')) (h _ (by simp)) := by
|
||||
cases o <;> simp
|
||||
|
||||
/-! ### pelim -/
|
||||
|
||||
@[simp, grind] theorem pelim_none : pelim none b f = b := rfl
|
||||
@[simp, grind] theorem pelim_some : pelim (some a) b f = f a rfl := rfl
|
||||
|
||||
@[simp, grind] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
|
||||
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem elim_pmap {p : α → Prop} (f : (a : α) → p a → β) (o : Option α)
|
||||
@@ -1091,7 +1333,7 @@ theorem pelim_congr_left {o o' : Option α } {b : β} {f : (a : α) → (a ∈ o
|
||||
pelim o b f = pelim o' b (fun a ha => f a (h ▸ ha)) := by
|
||||
cases h; rfl
|
||||
|
||||
theorem pelim_filter {o : Option α} {b : β} {f : (a : α) → a ∈ o.filter p → β} :
|
||||
@[grind =] theorem pelim_filter {o : Option α} {b : β} {f : (a : α) → a ∈ o.filter p → β} :
|
||||
Option.pelim (Option.filter p o) b f =
|
||||
Option.pelim o b (fun a h => if hp : p a then f a (Option.mem_filter_iff.2 ⟨h, hp⟩) else b) :=
|
||||
match o with
|
||||
@@ -1101,6 +1343,22 @@ theorem pelim_filter {o : Option α} {b : β} {f : (a : α) → a ∈ o.filter p
|
||||
| false => by simp [pelim_congr_left (filter_some_neg h), h]
|
||||
| true => by simp [pelim_congr_left (filter_some_pos h), h]
|
||||
|
||||
@[grind =] theorem pelim_join {o : Option (Option α)} {b : β} {f : (a : α) → a ∈ o.join → β} :
|
||||
o.join.pelim b f = o.pelim b (fun o' ho' => o'.pelim b (fun a ha => f a (by simp_all))) := by
|
||||
cases o <;> simp <;> congr
|
||||
|
||||
@[congr]
|
||||
theorem pelim_congr {o o' : Option α} {b b' : β}
|
||||
{f : (a : α) → o = some a → β} {g : (a : α) → o' = some a → β}
|
||||
(ho : o = o') (hb : b = b') (hf : ∀ a ha, f a (ho.trans ha) = g a ha) :
|
||||
o.pelim b f = o'.pelim b' g := by
|
||||
cases ho; cases hb; cases o <;> apply_assumption
|
||||
|
||||
theorem pelim_guard {a : α} {f : (a' : α) → guard p a = some a' → β} :
|
||||
(guard p a).pelim b f = if h : p a then f a (by simpa) else b := by
|
||||
simp only [guard]
|
||||
split <;> simp
|
||||
|
||||
/-! ### pfilter -/
|
||||
|
||||
@[congr]
|
||||
@@ -1132,6 +1390,15 @@ theorem isSome_of_isSome_pfilter {α : Type _} {o : Option α} {p : (a : α) →
|
||||
(h : (o.pfilter p).isSome) : o.isSome :=
|
||||
(isSome_pfilter_iff_get.mp h).1
|
||||
|
||||
theorem isNone_pfilter_iff {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
(o.pfilter p).isNone ↔ ∀ (a : α) (ha : o = some a), p a ha = false := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [pfilter_some, isNone_iff_eq_none, ite_eq_right_iff, reduceCtorEq, imp_false,
|
||||
Bool.not_eq_true, some.injEq]
|
||||
exact ⟨fun h _ h' => h' ▸ h, fun h => h _ rfl⟩
|
||||
|
||||
@[simp, grind] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) → o = some a → Bool}
|
||||
(h : (o.pfilter p).isSome) :
|
||||
(o.pfilter p).get h = o.get (isSome_of_isSome_pfilter h) := by
|
||||
@@ -1154,7 +1421,7 @@ theorem eq_some_of_pfilter_eq_some {o : Option α} {p : (a : α) → o = some a
|
||||
{a : α} (h : o.pfilter p = some a) : o = some a :=
|
||||
pfilter_eq_some_iff.1 h |>.1
|
||||
|
||||
theorem filter_pbind {f : (a : α) → o = some a → Option β} :
|
||||
@[grind =] theorem filter_pbind {f : (a : α) → o = some a → Option β} :
|
||||
(Option.pbind o f).filter p =
|
||||
(o.pfilter (fun a h => (f a h).any p)).pbind (fun a h => f a (eq_some_of_pfilter_eq_some h)) := by
|
||||
cases o with
|
||||
@@ -1166,7 +1433,7 @@ theorem filter_pbind {f : (a : α) → o = some a → Option β} :
|
||||
· simp only [h, filter_some, any_some]
|
||||
split <;> simp [h]
|
||||
|
||||
@[simp, grind] theorem pfilter_eq_filter {α : Type _} {o : Option α} {p : α → Bool} :
|
||||
@[simp] theorem pfilter_eq_filter {α : Type _} {o : Option α} {p : α → Bool} :
|
||||
o.pfilter (fun a _ => p a) = o.filter p := by
|
||||
cases o with
|
||||
| none => rfl
|
||||
@@ -1205,18 +1472,171 @@ theorem pfilter_eq_pbind_ite {α : Type _} {o : Option α}
|
||||
· rfl
|
||||
· simp only [Option.pfilter, Bool.cond_eq_ite, Option.pbind_some]
|
||||
|
||||
@[grind =] theorem filter_pmap {p : α → Prop} {f : (a : α) → p a → β} {h : ∀ (a : α), o = some a → p a}
|
||||
{q : β → Bool} : (o.pmap f h).filter q = (o.pfilter (fun a h' => q (f a (h _ h')))).pmap f
|
||||
(fun _ h' => h _ (eq_some_of_pfilter_eq_some h')) := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [pmap_some, filter_some, pfilter_some]
|
||||
split <;> simp
|
||||
|
||||
@[grind =] theorem pfilter_join {o : Option (Option α)} {p : (a : α) → o.join = some a → Bool} :
|
||||
o.join.pfilter p = (o.pfilter (fun o' h => o'.pelim false (fun a ha => p a (by simp_all)))).join := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some o' =>
|
||||
cases o' with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [join_some, pfilter_some, pelim_some]
|
||||
split <;> simp
|
||||
|
||||
@[grind =] theorem join_pfilter {o : Option (Option α)} {p : (o' : Option α) → o = some o' → Bool} :
|
||||
(o.pfilter p).join = o.pbind (fun o' ho' => if p o' ho' then o' else none) := by
|
||||
cases o <;> simp <;> split <;> simp
|
||||
|
||||
@[grind =] theorem elim_pfilter {o : Option α} {b : β} {f : α → β} {p : (a : α) → o = some a → Bool} :
|
||||
(o.pfilter p).elim b f = o.pelim b (fun a ha => if p a ha then f a else b) := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [pfilter_some, pelim_some]
|
||||
split <;> simp
|
||||
|
||||
@[grind =] theorem pelim_pfilter {o : Option α} {b : β} {p : (a : α) → o = some a → Bool}
|
||||
{f : (a : α) → o.pfilter p = some a → β} :
|
||||
(o.pfilter p).pelim b f = o.pelim b
|
||||
(fun a ha => if hp : p a ha then f a (pfilter_eq_some_iff.2 ⟨_, hp⟩) else b) := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [pfilter_some, pelim_some]
|
||||
split <;> simp
|
||||
|
||||
theorem pfilter_guard {a : α} {p : α → Bool} {q : (a' : α) → guard p a = some a' → Bool} :
|
||||
(guard p a).pfilter q = if ∃ (h : p a), q a (by simp [h]) then some a else none := by
|
||||
simp only [guard]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### LT and LE -/
|
||||
|
||||
@[simp, grind] theorem not_lt_none [LT α] {a : Option α} : ¬ a < none := by cases a <;> simp [LT.lt, Option.lt]
|
||||
@[simp, grind] theorem none_lt_some [LT α] {a : α} : none < some a := by simp [LT.lt, Option.lt]
|
||||
@[simp] theorem none_lt [LT α] {a : Option α} : none < a ↔ a.isSome := by cases a <;> simp
|
||||
@[grind] theorem none_lt_some [LT α] {a : α} : none < some a := by simp [LT.lt, Option.lt]
|
||||
@[simp] theorem none_lt [LT α] {a : Option α} : none < a ↔ a.isSome := by cases a <;> simp [none_lt_some]
|
||||
@[simp, grind] theorem some_lt_some [LT α] {a b : α} : some a < some b ↔ a < b := by simp [LT.lt, Option.lt]
|
||||
|
||||
@[simp, grind] theorem none_le [LE α] {a : Option α} : none ≤ a := by cases a <;> simp [LE.le, Option.le]
|
||||
@[simp, grind] theorem not_some_le_none [LE α] {a : α} : ¬ some a ≤ none := by simp [LE.le, Option.le]
|
||||
@[simp] theorem le_none [LE α] {a : Option α} : a ≤ none ↔ a = none := by cases a <;> simp
|
||||
@[grind] theorem not_some_le_none [LE α] {a : α} : ¬ some a ≤ none := by simp [LE.le, Option.le]
|
||||
@[simp] theorem le_none [LE α] {a : Option α} : a ≤ none ↔ a = none := by cases a <;> simp [not_some_le_none]
|
||||
@[simp, grind] theorem some_le_some [LE α] {a b : α} : some a ≤ some b ↔ a ≤ b := by simp [LE.le, Option.le]
|
||||
|
||||
@[simp]
|
||||
theorem filter_le [LE α] (le_refl : ∀ x : α, x ≤ x) {o : Option α} {p : α → Bool} : o.filter p ≤ o := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [le_refl]
|
||||
|
||||
@[simp]
|
||||
theorem filter_lt [LT α] (lt_irrefl : ∀ x : α, ¬x < x) {o : Option α} {p : α → Bool} : o.filter p < o ↔ o.any (fun a => !p a) := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp]
|
||||
theorem le_filter [LE α] (le_refl : ∀ x : α, x ≤ x) {o : Option α} {p : α → Bool} : o ≤ o.filter p ↔ o.all p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp]
|
||||
theorem not_lt_filter [LT α] (lt_irrefl : ∀ x : α, ¬x < x) {o : Option α} {p : α → Bool} : ¬o < o.filter p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [lt_irrefl]
|
||||
|
||||
@[simp]
|
||||
theorem pfilter_le [LE α] (le_refl : ∀ x : α, x ≤ x) {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
o.pfilter p ≤ o := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [pfilter_some]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp]
|
||||
theorem not_lt_pfilter [LT α] (lt_irrefl : ∀ x : α, ¬x < x) {o : Option α}
|
||||
{p : (a : α) → o = some a → Bool} : ¬o < o.pfilter p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [pfilter_some]
|
||||
split <;> simp [lt_irrefl]
|
||||
|
||||
theorem join_le [LE α] {o : Option (Option α)} {o' : Option α} : o.join ≤ o' ↔ o ≤ some o' := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem guard_le_some [LE α] (le_refl : ∀ x : α, x ≤ x) {x : α} {p : α → Bool} : guard p x ≤ some x := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [le_refl]
|
||||
|
||||
@[simp]
|
||||
theorem guard_lt_some [LT α] (lt_irrefl : ∀ x : α, ¬x < x) {x : α} {p : α → Bool} :
|
||||
guard p x < some x ↔ p x = false := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [*]
|
||||
|
||||
theorem left_le_of_merge_le [LE α] {f : α → α → α} (hf : ∀ a b c, f a b ≤ c → a ≤ c)
|
||||
{o₁ o₂ o₃ : Option α} : o₁.merge f o₂ ≤ o₃ → o₁ ≤ o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> try (simp; done)
|
||||
simpa using hf _ _ _
|
||||
|
||||
theorem right_le_of_merge_le [LE α] {f : α → α → α} (hf : ∀ a b c, f a b ≤ c → b ≤ c)
|
||||
{o₁ o₂ o₃ : Option α} : o₁.merge f o₂ ≤ o₃ → o₂ ≤ o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> try (simp; done)
|
||||
simpa using hf _ _ _
|
||||
|
||||
theorem merge_le [LE α] {f : α → α → α} {o₁ o₂ o₃ : Option α}
|
||||
(hf : ∀ a b c, a ≤ c → b ≤ c → f a b ≤ c) : o₁ ≤ o₃ → o₂ ≤ o₃ → o₁.merge f o₂ ≤ o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> try (simp; done)
|
||||
simpa using hf _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem merge_le_iff [LE α] {f : α → α → α} {o₁ o₂ o₃ : Option α}
|
||||
(hf : ∀ a b c, f a b ≤ c ↔ a ≤ c ∧ b ≤ c) :
|
||||
o₁.merge f o₂ ≤ o₃ ↔ o₁ ≤ o₃ ∧ o₂ ≤ o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> simp [*]
|
||||
|
||||
theorem left_lt_of_merge_lt [LT α] {f : α → α → α} (hf : ∀ a b c, f a b < c → a < c)
|
||||
{o₁ o₂ o₃ : Option α} : o₁.merge f o₂ < o₃ → o₁ < o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> try (simp; done)
|
||||
simpa using hf _ _ _
|
||||
|
||||
theorem right_lt_of_merge_lt [LT α] {f : α → α → α} (hf : ∀ a b c, f a b < c → b < c)
|
||||
{o₁ o₂ o₃ : Option α} : o₁.merge f o₂ < o₃ → o₂ < o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> try (simp; done)
|
||||
simpa using hf _ _ _
|
||||
|
||||
theorem merge_lt [LT α] {f : α → α → α} {o₁ o₂ o₃ : Option α}
|
||||
(hf : ∀ a b c, a < c → b < c → f a b < c) : o₁ < o₃ → o₂ < o₃ → o₁.merge f o₂ < o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> try (simp; done)
|
||||
simpa using hf _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem merge_lt_iff [LT α] {f : α → α → α} {o₁ o₂ o₃ : Option α}
|
||||
(hf : ∀ a b c, f a b < c ↔ a < c ∧ b < c) :
|
||||
o₁.merge f o₂ < o₃ ↔ o₁ < o₃ ∧ o₂ < o₃ := by
|
||||
cases o₁ <;> cases o₂ <;> cases o₃ <;> simp [*]
|
||||
|
||||
/-! ### Rel -/
|
||||
|
||||
@[simp] theorem rel_some_some {r : α → β → Prop} : Rel r (some a) (some b) ↔ r a b :=
|
||||
@@ -1298,4 +1718,192 @@ theorem merge_max [Max α] : merge (α := α) max = max := by
|
||||
instance [Max α] : Std.LawfulIdentity (α := Option α) max none := by
|
||||
rw [← merge_max]; infer_instance
|
||||
|
||||
instance [Max α] [Std.IdempotentOp (α := α) max] : Std.IdempotentOp (α := Option α) max where
|
||||
idempotent o := by cases o <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem max_filter_left [Max α] [Std.IdempotentOp (α := α) max] {p : α → Bool} {o : Option α} :
|
||||
max (o.filter p) o = o := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem max_filter_right [Max α] [Std.IdempotentOp (α := α) max] {p : α → Bool} {o : Option α} :
|
||||
max o (o.filter p) = o := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem min_filter_left [Min α] [Std.IdempotentOp (α := α) min] {p : α → Bool} {o : Option α} :
|
||||
min (o.filter p) o = o.filter p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem min_filter_right [Min α] [Std.IdempotentOp (α := α) min] {p : α → Bool} {o : Option α} :
|
||||
min o (o.filter p) = o.filter p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [filter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem max_pfilter_left [Max α] [Std.IdempotentOp (α := α) max] {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
max (o.pfilter p) o = o := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [pfilter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem max_pfilter_right [Max α] [Std.IdempotentOp (α := α) max] {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
max o (o.pfilter p) = o := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [pfilter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem min_pfilter_left [Min α] [Std.IdempotentOp (α := α) min] {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
min (o.pfilter p) o = o.pfilter p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [pfilter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem min_pfilter_right [Min α] [Std.IdempotentOp (α := α) min] {o : Option α} {p : (a : α) → o = some a → Bool} :
|
||||
min o (o.pfilter p) = o.pfilter p := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some _ =>
|
||||
simp only [pfilter_some]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isSome_max [Max α] {o o' : Option α} : (max o o').isSome = (o.isSome || o'.isSome) := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isNone_max [Max α] {o o' : Option α} : (max o o').isNone = (o.isNone && o'.isNone) := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isSome_min [Min α] {o o' : Option α} : (min o o').isSome = (o.isSome && o'.isSome) := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isNone_min [Min α] {o o' : Option α} : (min o o').isNone = (o.isNone || o'.isNone) := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
theorem max_join_left [Max α] {o : Option (Option α)} {o' : Option α} :
|
||||
max o.join o' = (max o (some o')).get (by simp) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem max_join_right [Max α] {o : Option α} {o' : Option (Option α)} :
|
||||
max o o'.join = (max (some o) o').get (by simp) := by
|
||||
cases o' <;> simp
|
||||
|
||||
@[grind _=_] theorem join_max [Max α] {o o' : Option (Option α)} :
|
||||
(max o o').join = max o.join o'.join := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
theorem min_join_left [Min α] {o : Option (Option α)} {o' : Option α} :
|
||||
min o.join o' = (min o (some o')).join := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem min_join_right [Min α] {o : Option α} {o' : Option (Option α)} :
|
||||
min o o'.join = (min (some o) o').join := by
|
||||
cases o' <;> simp
|
||||
|
||||
@[grind _=_] theorem join_min [Min α] {o o' : Option (Option α)} :
|
||||
(min o o').join = min o.join o'.join := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem min_guard_some [Min α] [Std.IdempotentOp (α := α) min] {x : α} {p : α → Bool} :
|
||||
min (guard p x) (some x) = guard p x := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem min_some_guard [Min α] [Std.IdempotentOp (α := α) min] {x : α} {p : α → Bool} :
|
||||
min (some x) (guard p x) = guard p x := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem max_guard_some [Max α] [Std.IdempotentOp (α := α) max] {x : α} {p : α → Bool} :
|
||||
max (guard p x) (some x) = some x := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp]
|
||||
theorem max_some_guard [Max α] [Std.IdempotentOp (α := α) max] {x : α} {p : α → Bool} :
|
||||
max (some x) (guard p x) = some x := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp [Std.IdempotentOp.idempotent]
|
||||
|
||||
theorem max_eq_some_iff [Max α] {o o' : Option α} {a : α} :
|
||||
max o o' = some a ↔ (o = some a ∧ o' = none) ∨ (o = none ∧ o' = some a) ∨
|
||||
(∃ b c, o = some b ∧ o' = some c ∧ max b c = a) := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem max_eq_none_iff [Max α] {o o' : Option α} :
|
||||
max o o' = none ↔ o = none ∧ o' = none := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem min_eq_some_iff [Min α] {o o' : Option α} {a : α} :
|
||||
min o o' = some a ↔ ∃ b c, o = some b ∧ o' = some c ∧ min b c = a := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem min_eq_none_iff [Min α] {o o' : Option α} :
|
||||
min o o' = none ↔ o = none ∨ o' = none := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem any_max [Max α] {o o' : Option α} {p : α → Bool} (hp : ∀ a b, p (max a b) = (p a || p b)) :
|
||||
(max o o').any p = (o.any p || o'.any p) := by
|
||||
cases o <;> cases o' <;> simp [hp]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem all_min [Min α] {o o' : Option α} {p : α → Bool} (hp : ∀ a b, p (min a b) = (p a || p b)) :
|
||||
(min o o').all p = (o.all p || o'.all p) := by
|
||||
cases o <;> cases o' <;> simp [hp]
|
||||
|
||||
theorem isSome_left_of_isSome_min [Min α] {o o' : Option α} : (min o o').isSome → o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isSome_right_of_isSome_min [Min α] {o o' : Option α} : (min o o').isSome → o'.isSome := by
|
||||
cases o' <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem get_min [Min α] {o o' : Option α} {h} :
|
||||
(min o o').get h = min (o.get (isSome_left_of_isSome_min h)) (o'.get (isSome_right_of_isSome_min h)) := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
theorem map_max [Max α] [Max β] {o o' : Option α} {f : α → β} (hf : ∀ x y, f (max x y) = max (f x) (f y)) :
|
||||
(max o o').map f = max (o.map f) (o'.map f) := by
|
||||
cases o <;> cases o' <;> simp [*]
|
||||
|
||||
theorem map_min [Min α] [Min β] {o o' : Option α} {f : α → β} (hf : ∀ x y, f (min x y) = min (f x) (f y)) :
|
||||
(min o o').map f = min (o.map f) (o'.map f) := by
|
||||
cases o <;> cases o' <;> simp [*]
|
||||
|
||||
end Option
|
||||
|
||||
@@ -60,6 +60,42 @@ theorem toList_bind {o : Option α} {f : α → Option β} :
|
||||
cases o <;> simp
|
||||
|
||||
theorem toList_join {o : Option (Option α)} : o.join.toList = o.toList.flatMap Option.toList := by
|
||||
simp [toList_bind, join_eq_bind_id]
|
||||
simp [toList_bind, ← bind_id_eq_join]
|
||||
|
||||
theorem toList_map {o : Option α} {f : α → β} : (o.map f).toList = o.toList.map f := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem toList_min [Min α] {o o' : Option α} :
|
||||
(min o o').toList = o.toList.zipWith min o'.toList := by
|
||||
cases o <;> cases o' <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem length_toList_le {o : Option α} : o.toList.length ≤ 1 := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem length_toList {o : Option α} :
|
||||
o.toList.length = if o.isSome then 1 else 0 := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem toList_eq_nil_iff {o : Option α} : o.toList = [] ↔ o = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem toList_eq_singleton_iff {o : Option α} : o.toList = [a] ↔ o = some a := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem length_toList_eq_zero_iff {o : Option α} :
|
||||
o.toList.length = 0 ↔ o = none := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem length_toList_eq_one_iff {o : Option α} :
|
||||
o.toList.length = 1 ↔ o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem length_toList_choice_eq_one [Nonempty α] : (choice α).toList.length = 1 := by
|
||||
simp
|
||||
|
||||
end Option
|
||||
|
||||
@@ -13,8 +13,8 @@ import Init.Control.Lawful.Basic
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind] theorem bindM_none [Monad m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
|
||||
@[simp, grind] theorem bindM_some [Monad m] [LawfulMonad 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`.
|
||||
@@ -30,6 +30,10 @@ namespace Option
|
||||
forM (o.map g) f = forM o (fun a => f (g a)) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α → m PUnit) :
|
||||
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 β)) :
|
||||
forIn' none b f = pure b := by
|
||||
rfl
|
||||
@@ -86,17 +90,31 @@ theorem forIn'_eq_pelim [Monad m] [LawfulMonad m]
|
||||
pure (f := m) (o.pelim b (fun a h => f a h b)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem forIn'_id_yield_eq_pelim
|
||||
@[simp] theorem idRun_forIn'_yield_eq_pelim
|
||||
(o : Option α) (f : (a : α) → a ∈ o → β → Id β) (b : β) :
|
||||
(forIn' o b (fun a m b => .yield <$> f a m b)).run =
|
||||
o.pelim b (fun a h => f a h b |>.run) :=
|
||||
forIn'_pure_yield_eq_pelim _ _ _
|
||||
|
||||
@[deprecated idRun_forIn'_yield_eq_pelim (since := "2025-05-21")]
|
||||
theorem forIn'_id_yield_eq_pelim
|
||||
(o : Option α) (f : (a : α) → a ∈ o → β → β) (b : β) :
|
||||
forIn' (m := Id) o b (fun a m b => .yield (f a m b)) =
|
||||
o.pelim b (fun a h => f a h b) := by
|
||||
cases o <;> simp
|
||||
o.pelim b (fun a h => f a h b) :=
|
||||
forIn'_pure_yield_eq_pelim _ _ _
|
||||
|
||||
@[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
|
||||
|
||||
theorem forIn'_join [Monad m] [LawfulMonad m] (b : β) (o : Option (Option α))
|
||||
(f : (a : α) → a ∈ o.join → β → m (ForInStep β)) :
|
||||
forIn' o.join b f = forIn' o b (fun o' ho' b => ForInStep.yield <$> forIn' o' b (fun a ha b' => f a (by simp_all [join_eq_some_iff]) b')) := by
|
||||
cases o with
|
||||
| none => simp
|
||||
| some a => simpa using forIn'_congr rfl rfl (by simp)
|
||||
|
||||
theorem forIn_eq_elim [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (f : (a : α) → β → m (ForInStep β)) (b : β) :
|
||||
forIn o b f =
|
||||
@@ -115,40 +133,66 @@ theorem forIn_eq_elim [Monad m] [LawfulMonad m]
|
||||
pure (f := m) (o.elim b (fun a => f a b)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem forIn_id_yield_eq_elim
|
||||
@[simp] theorem idRun_forIn_yield_eq_elim
|
||||
(o : Option α) (f : (a : α) → β → Id β) (b : β) :
|
||||
(forIn o b (fun a b => .yield <$> f a b)).run =
|
||||
o.elim b (fun a => f a b |>.run) :=
|
||||
forIn_pure_yield_eq_elim _ _ _
|
||||
|
||||
@[deprecated idRun_forIn_yield_eq_elim (since := "2025-05-21")]
|
||||
theorem forIn_id_yield_eq_elim
|
||||
(o : Option α) (f : (a : α) → β → β) (b : β) :
|
||||
forIn (m := Id) o b (fun a b => .yield (f a b)) =
|
||||
o.elim b (fun a => f a b) := by
|
||||
cases o <;> simp
|
||||
o.elim b (fun a => f a b) :=
|
||||
forIn_pure_yield_eq_elim _ _ _
|
||||
|
||||
@[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
|
||||
|
||||
@[simp] theorem elimM_pure [Monad m] [LawfulMonad m] (x : Option α) (y : m β) (z : α → m β) :
|
||||
theorem forIn_join [Monad m] [LawfulMonad m]
|
||||
(o : Option (Option α)) (f : α → β → m (ForInStep β)) :
|
||||
forIn o.join init f = forIn o init (fun o' b => ForInStep.yield <$> forIn o' b f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem elimM_pure [Monad m] [LawfulMonad m] (x : Option α) (y : m β) (z : α → m β) :
|
||||
Option.elimM (pure x : m (Option α)) y z = x.elim y z := by
|
||||
simp [Option.elimM]
|
||||
|
||||
@[simp] theorem elimM_bind [Monad m] [LawfulMonad m] (x : m α) (f : α → m (Option β))
|
||||
@[simp, grind =] theorem elimM_bind [Monad m] [LawfulMonad m] (x : m α) (f : α → m (Option β))
|
||||
(y : m γ) (z : β → m γ) : Option.elimM (x >>= f) y z = (do Option.elimM (f (← x)) y z) := by
|
||||
simp [Option.elimM]
|
||||
|
||||
@[simp] theorem elimM_map [Monad m] [LawfulMonad m] (x : m α) (f : α → Option β)
|
||||
@[simp, grind =] theorem elimM_map [Monad m] [LawfulMonad m] (x : m α) (f : α → Option β)
|
||||
(y : m γ) (z : β → m γ) : Option.elimM (f <$> x) y z = (do Option.elim (f (← x)) y z) := by
|
||||
simp [Option.elimM]
|
||||
|
||||
@[simp] theorem tryCatch_none (alternative : Unit → Option α) :
|
||||
(tryCatch none alternative) = alternative () := rfl
|
||||
@[simp, grind =] theorem tryCatch_eq_or (o : Option α) (alternative : Unit → Option α) :
|
||||
tryCatch o alternative = o.or (alternative ()) := by cases o <;> rfl
|
||||
|
||||
@[simp] theorem tryCatch_some (a : α) (alternative : Unit → Option α) :
|
||||
(tryCatch (some a) alternative) = some a := rfl
|
||||
@[simp, grind =] theorem throw_eq_none : throw () = (none : Option α) := rfl
|
||||
|
||||
@[simp] theorem throw_eq_none : throw () = (none : Option α) := rfl
|
||||
|
||||
@[simp, grind] theorem filterM_none [Applicative m] (p : α → m Bool) :
|
||||
@[simp, grind =] theorem filterM_none [Applicative m] (p : α → m Bool) :
|
||||
none.filterM p = pure none := rfl
|
||||
theorem filterM_some [Applicative m] (p : α → m Bool) (a : α) :
|
||||
@[grind =] theorem filterM_some [Applicative m] (p : α → m Bool) (a : α) :
|
||||
(some a).filterM p = (fun b => if b then some a else none) <$> p a := rfl
|
||||
|
||||
theorem sequence_join [Applicative m] [LawfulApplicative m] {o : Option (Option (m α))} :
|
||||
o.join.sequence = join <$> sequence (o.map sequence) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem bindM_join [Pure m] {f : α → m (Option β)} {o : Option (Option α)} :
|
||||
o.join.bindM f = o.bindM (·.bindM f) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem mapM_join [Applicative m] [LawfulApplicative m] {f : α → m β} {o : Option (Option α)} :
|
||||
o.join.mapM f = join <$> o.mapM (Option.mapM f) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem mapM_guard [Applicative m] {x : α} {p : α → Bool} {f : α → m β} :
|
||||
(guard p x).mapM f = if p x then some <$> f x else pure none := by
|
||||
simp only [guard_eq_ite]
|
||||
split <;> simp
|
||||
|
||||
end Option
|
||||
|
||||
@@ -3,7 +3,6 @@ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Dany Fabian, Sebastian Ullrich
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
@@ -21,13 +20,13 @@ The relationship between the compared items may be:
|
||||
* `Ordering.gt`: greater than
|
||||
-/
|
||||
inductive Ordering where
|
||||
| /-- Less than. -/
|
||||
lt
|
||||
| /-- Equal. -/
|
||||
eq
|
||||
| /-- Greater than. -/
|
||||
gt
|
||||
deriving Inhabited, DecidableEq
|
||||
/-- Less than. -/
|
||||
| lt
|
||||
/-- Equal. -/
|
||||
| eq
|
||||
/-- Greater than. -/
|
||||
| gt
|
||||
deriving Inhabited, DecidableEq, Repr
|
||||
|
||||
namespace Ordering
|
||||
|
||||
@@ -39,6 +38,7 @@ Examples:
|
||||
* `Ordering.eq.swap = Ordering.eq`
|
||||
* `Ordering.gt.swap = Ordering.lt`
|
||||
-/
|
||||
@[inline]
|
||||
def swap : Ordering → Ordering
|
||||
| .lt => .gt
|
||||
| .eq => .eq
|
||||
@@ -96,6 +96,7 @@ Ordering.lt
|
||||
/--
|
||||
Checks whether the ordering is `eq`.
|
||||
-/
|
||||
@[inline]
|
||||
def isEq : Ordering → Bool
|
||||
| eq => true
|
||||
| _ => false
|
||||
@@ -103,6 +104,7 @@ def isEq : Ordering → Bool
|
||||
/--
|
||||
Checks whether the ordering is not `eq`.
|
||||
-/
|
||||
@[inline]
|
||||
def isNe : Ordering → Bool
|
||||
| eq => false
|
||||
| _ => true
|
||||
@@ -110,6 +112,7 @@ def isNe : Ordering → Bool
|
||||
/--
|
||||
Checks whether the ordering is `lt` or `eq`.
|
||||
-/
|
||||
@[inline]
|
||||
def isLE : Ordering → Bool
|
||||
| gt => false
|
||||
| _ => true
|
||||
@@ -117,6 +120,7 @@ def isLE : Ordering → Bool
|
||||
/--
|
||||
Checks whether the ordering is `lt`.
|
||||
-/
|
||||
@[inline]
|
||||
def isLT : Ordering → Bool
|
||||
| lt => true
|
||||
| _ => false
|
||||
@@ -124,6 +128,7 @@ def isLT : Ordering → Bool
|
||||
/--
|
||||
Checks whether the ordering is `gt`.
|
||||
-/
|
||||
@[inline]
|
||||
def isGT : Ordering → Bool
|
||||
| gt => true
|
||||
| _ => false
|
||||
@@ -131,203 +136,158 @@ def isGT : Ordering → Bool
|
||||
/--
|
||||
Checks whether the ordering is `gt` or `eq`.
|
||||
-/
|
||||
@[inline]
|
||||
def isGE : Ordering → Bool
|
||||
| lt => false
|
||||
| _ => true
|
||||
|
||||
section Lemmas
|
||||
|
||||
@[simp]
|
||||
theorem isLT_lt : lt.isLT := rfl
|
||||
protected theorem «forall» {p : Ordering → Prop} : (∀ o, p o) ↔ p .lt ∧ p .eq ∧ p .gt := by
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨h _, h _, h _⟩
|
||||
· rintro ⟨h₁, h₂, h₃⟩ (_ | _ | _) <;> assumption
|
||||
|
||||
@[simp]
|
||||
theorem isLE_lt : lt.isLE := rfl
|
||||
protected theorem «exists» {p : Ordering → Prop} : (∃ o, p o) ↔ p .lt ∨ p .eq ∨ p .gt := by
|
||||
constructor
|
||||
· rintro ⟨(_ | _ | _), h⟩
|
||||
· exact .inl h
|
||||
· exact .inr (.inl h)
|
||||
· exact .inr (.inr h)
|
||||
· rintro (h | h | h) <;> exact ⟨_, h⟩
|
||||
|
||||
@[simp]
|
||||
theorem isEq_lt : lt.isEq = false := rfl
|
||||
instance [DecidablePred p] : Decidable (∀ o : Ordering, p o) :=
|
||||
decidable_of_decidable_of_iff Ordering.«forall».symm
|
||||
|
||||
@[simp]
|
||||
theorem isNe_lt : lt.isNe = true := rfl
|
||||
instance [DecidablePred p] : Decidable (∃ o : Ordering, p o) :=
|
||||
decidable_of_decidable_of_iff Ordering.«exists».symm
|
||||
|
||||
@[simp]
|
||||
theorem isGE_lt : lt.isGE = false := rfl
|
||||
@[simp] theorem isLT_lt : lt.isLT := rfl
|
||||
@[simp] theorem isLE_lt : lt.isLE := rfl
|
||||
@[simp] theorem isEq_lt : lt.isEq = false := rfl
|
||||
@[simp] theorem isNe_lt : lt.isNe = true := rfl
|
||||
@[simp] theorem isGE_lt : lt.isGE = false := rfl
|
||||
@[simp] theorem isGT_lt : lt.isGT = false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem isGT_lt : lt.isGT = false := rfl
|
||||
@[simp] theorem isLT_eq : eq.isLT = false := rfl
|
||||
@[simp] theorem isLE_eq : eq.isLE := rfl
|
||||
@[simp] theorem isEq_eq : eq.isEq := rfl
|
||||
@[simp] theorem isNe_eq : eq.isNe = false := rfl
|
||||
@[simp] theorem isGE_eq : eq.isGE := rfl
|
||||
@[simp] theorem isGT_eq : eq.isGT = false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem isLT_eq : eq.isLT = false := rfl
|
||||
@[simp] theorem isLT_gt : gt.isLT = false := rfl
|
||||
@[simp] theorem isLE_gt : gt.isLE = false := rfl
|
||||
@[simp] theorem isEq_gt : gt.isEq = false := rfl
|
||||
@[simp] theorem isNe_gt : gt.isNe = true := rfl
|
||||
@[simp] theorem isGE_gt : gt.isGE := rfl
|
||||
@[simp] theorem isGT_gt : gt.isGT := rfl
|
||||
|
||||
@[simp]
|
||||
theorem isLE_eq : eq.isLE := rfl
|
||||
@[simp] theorem lt_beq_eq : (lt == eq) = false := rfl
|
||||
@[simp] theorem lt_beq_gt : (lt == gt) = false := rfl
|
||||
@[simp] theorem eq_beq_lt : (eq == lt) = false := rfl
|
||||
@[simp] theorem eq_beq_gt : (eq == gt) = false := rfl
|
||||
@[simp] theorem gt_beq_lt : (gt == lt) = false := rfl
|
||||
@[simp] theorem gt_beq_eq : (gt == eq) = false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem isEq_eq : eq.isEq := rfl
|
||||
@[simp] theorem swap_lt : lt.swap = .gt := rfl
|
||||
@[simp] theorem swap_eq : eq.swap = .eq := rfl
|
||||
@[simp] theorem swap_gt : gt.swap = .lt := rfl
|
||||
|
||||
@[simp]
|
||||
theorem isNe_eq : eq.isNe = false := rfl
|
||||
theorem eq_eq_of_isLE_of_isLE_swap : ∀ {o : Ordering}, o.isLE → o.swap.isLE → o = .eq := by decide
|
||||
theorem eq_eq_of_isGE_of_isGE_swap : ∀ {o : Ordering}, o.isGE → o.swap.isGE → o = .eq := by decide
|
||||
theorem eq_eq_of_isLE_of_isGE : ∀ {o : Ordering}, o.isLE → o.isGE → o = .eq := by decide
|
||||
theorem eq_swap_iff_eq_eq : ∀ {o : Ordering}, o = o.swap ↔ o = .eq := by decide
|
||||
theorem eq_eq_of_eq_swap : ∀ {o : Ordering}, o = o.swap → o = .eq := eq_swap_iff_eq_eq.mp
|
||||
|
||||
@[simp]
|
||||
theorem isGE_eq : eq.isGE := rfl
|
||||
@[simp] theorem isLE_eq_false : ∀ {o : Ordering}, o.isLE = false ↔ o = .gt := by decide
|
||||
@[simp] theorem isGE_eq_false : ∀ {o : Ordering}, o.isGE = false ↔ o = .lt := by decide
|
||||
@[simp] theorem isNe_eq_false : ∀ {o : Ordering}, o.isNe = false ↔ o = .eq := by decide
|
||||
@[simp] theorem isEq_eq_false : ∀ {o : Ordering}, o.isEq = false ↔ ¬o = .eq := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isGT_eq : eq.isGT = false := rfl
|
||||
@[simp] theorem swap_eq_gt : ∀ {o : Ordering}, o.swap = .gt ↔ o = .lt := by decide
|
||||
@[simp] theorem swap_eq_lt : ∀ {o : Ordering}, o.swap = .lt ↔ o = .gt := by decide
|
||||
@[simp] theorem swap_eq_eq : ∀ {o : Ordering}, o.swap = .eq ↔ o = .eq := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isLT_gt : gt.isLT = false := rfl
|
||||
@[simp] theorem isLT_swap : ∀ {o : Ordering}, o.swap.isLT = o.isGT := by decide
|
||||
@[simp] theorem isLE_swap : ∀ {o : Ordering}, o.swap.isLE = o.isGE := by decide
|
||||
@[simp] theorem isEq_swap : ∀ {o : Ordering}, o.swap.isEq = o.isEq := by decide
|
||||
@[simp] theorem isNe_swap : ∀ {o : Ordering}, o.swap.isNe = o.isNe := by decide
|
||||
@[simp] theorem isGE_swap : ∀ {o : Ordering}, o.swap.isGE = o.isLE := by decide
|
||||
@[simp] theorem isGT_swap : ∀ {o : Ordering}, o.swap.isGT = o.isLT := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isLE_gt : gt.isLE = false := rfl
|
||||
theorem isLE_of_eq_lt : ∀ {o : Ordering}, o = .lt → o.isLE := by decide
|
||||
theorem isLE_of_eq_eq : ∀ {o : Ordering}, o = .eq → o.isLE := by decide
|
||||
theorem isGE_of_eq_gt : ∀ {o : Ordering}, o = .gt → o.isGE := by decide
|
||||
theorem isGE_of_eq_eq : ∀ {o : Ordering}, o = .eq → o.isGE := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isEq_gt : gt.isEq = false := rfl
|
||||
theorem ne_eq_of_eq_lt : ∀ {o : Ordering}, o = .lt → o ≠ .eq := by decide
|
||||
theorem ne_eq_of_eq_gt : ∀ {o : Ordering}, o = .gt → o ≠ .eq := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isNe_gt : gt.isNe = true := rfl
|
||||
@[simp] theorem isLT_iff_eq_lt : ∀ {o : Ordering}, o.isLT ↔ o = .lt := by decide
|
||||
@[simp] theorem isGT_iff_eq_gt : ∀ {o : Ordering}, o.isGT ↔ o = .gt := by decide
|
||||
@[simp] theorem isEq_iff_eq_eq : ∀ {o : Ordering}, o.isEq ↔ o = .eq := by decide
|
||||
@[simp] theorem isNe_iff_ne_eq : ∀ {o : Ordering}, o.isNe ↔ ¬o = .eq := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isGE_gt : gt.isGE := rfl
|
||||
theorem isLE_iff_ne_gt : ∀ {o : Ordering}, o.isLE ↔ ¬o = .gt := by decide
|
||||
theorem isGE_iff_ne_lt : ∀ {o : Ordering}, o.isGE ↔ ¬o = .lt := by decide
|
||||
theorem isLE_iff_eq_lt_or_eq_eq : ∀ {o : Ordering}, o.isLE ↔ o = .lt ∨ o = .eq := by decide
|
||||
theorem isGE_iff_eq_gt_or_eq_eq : ∀ {o : Ordering}, o.isGE ↔ o = .gt ∨ o = .eq := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isGT_gt : gt.isGT := rfl
|
||||
theorem isLT_eq_beq_lt : ∀ {o : Ordering}, o.isLT = (o == .lt) := by decide
|
||||
theorem isLE_eq_not_beq_gt : ∀ {o : Ordering}, o.isLE = (!o == .gt) := by decide
|
||||
theorem isLE_eq_isLT_or_isEq : ∀ {o : Ordering}, o.isLE = (o.isLT || o.isEq) := by decide
|
||||
theorem isGT_eq_beq_gt : ∀ {o : Ordering}, o.isGT = (o == .gt) := by decide
|
||||
theorem isGE_eq_not_beq_lt : ∀ {o : Ordering}, o.isGE = (!o == .lt) := by decide
|
||||
theorem isGE_eq_isGT_or_isEq : ∀ {o : Ordering}, o.isGE = (o.isGT || o.isEq) := by decide
|
||||
theorem isEq_eq_beq_eq : ∀ {o : Ordering}, o.isEq = (o == .eq) := by decide
|
||||
theorem isNe_eq_not_beq_eq : ∀ {o : Ordering}, o.isNe = (!o == .eq) := by decide
|
||||
theorem isNe_eq_isLT_or_isGT : ∀ {o : Ordering}, o.isNe = (o.isLT || o.isGT) := by decide
|
||||
|
||||
@[simp]
|
||||
theorem swap_lt : lt.swap = .gt := rfl
|
||||
@[simp] theorem not_isLT_eq_isGE : ∀ {o : Ordering}, !o.isLT = o.isGE := by decide
|
||||
@[simp] theorem not_isLE_eq_isGT : ∀ {o : Ordering}, !o.isLE = o.isGT := by decide
|
||||
@[simp] theorem not_isGT_eq_isLE : ∀ {o : Ordering}, !o.isGT = o.isLE := by decide
|
||||
@[simp] theorem not_isGE_eq_isLT : ∀ {o : Ordering}, !o.isGE = o.isLT := by decide
|
||||
@[simp] theorem not_isNe_eq_isEq : ∀ {o : Ordering}, !o.isNe = o.isEq := by decide
|
||||
theorem not_isEq_eq_isNe : ∀ {o : Ordering}, !o.isEq = o.isNe := by decide
|
||||
|
||||
@[simp]
|
||||
theorem swap_eq : eq.swap = .eq := rfl
|
||||
theorem ne_lt_iff_isGE : ∀ {o : Ordering}, ¬o = .lt ↔ o.isGE := by decide
|
||||
theorem ne_gt_iff_isLE : ∀ {o : Ordering}, ¬o = .gt ↔ o.isLE := by decide
|
||||
|
||||
@[simp]
|
||||
theorem swap_gt : gt.swap = .lt := rfl
|
||||
@[simp] theorem swap_swap : ∀ {o : Ordering}, o.swap.swap = o := by decide
|
||||
@[simp] theorem swap_inj : ∀ {o₁ o₂ : Ordering}, o₁.swap = o₂.swap ↔ o₁ = o₂ := by decide
|
||||
|
||||
theorem eq_eq_of_isLE_of_isLE_swap {o : Ordering} : o.isLE → o.swap.isLE → o = .eq := by
|
||||
cases o <;> simp
|
||||
theorem swap_then : ∀ (o₁ o₂ : Ordering), (o₁.then o₂).swap = o₁.swap.then o₂.swap := by decide
|
||||
|
||||
theorem eq_eq_of_isGE_of_isGE_swap {o : Ordering} : o.isGE → o.swap.isGE → o = .eq := by
|
||||
cases o <;> simp
|
||||
theorem then_eq_lt : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = lt ↔ o₁ = lt ∨ o₁ = eq ∧ o₂ = lt := by decide
|
||||
theorem then_eq_gt : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = gt ↔ o₁ = gt ∨ o₁ = eq ∧ o₂ = gt := by decide
|
||||
@[simp] theorem then_eq_eq : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = eq ↔ o₁ = eq ∧ o₂ = eq := by decide
|
||||
|
||||
theorem eq_eq_of_isLE_of_isGE {o : Ordering} : o.isLE → o.isGE → o = .eq := by
|
||||
cases o <;> simp
|
||||
theorem isLT_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLT = (o₁.isLT || o₁.isEq && o₂.isLT) := by decide
|
||||
theorem isEq_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isEq = (o₁.isEq && o₂.isEq) := by decide
|
||||
theorem isNe_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isNe = (o₁.isNe || o₂.isNe) := by decide
|
||||
theorem isGT_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isGT = (o₁.isGT || o₁.isEq && o₂.isGT) := by decide
|
||||
|
||||
theorem eq_swap_iff_eq_eq {o : Ordering} : o = o.swap ↔ o = .eq := by
|
||||
cases o <;> simp
|
||||
@[simp] theorem lt_then {o : Ordering} : lt.then o = lt := rfl
|
||||
@[simp] theorem gt_then {o : Ordering} : gt.then o = gt := rfl
|
||||
@[simp] theorem eq_then {o : Ordering} : eq.then o = o := rfl
|
||||
|
||||
theorem eq_eq_of_eq_swap {o : Ordering} : o = o.swap → o = .eq :=
|
||||
eq_swap_iff_eq_eq.mp
|
||||
@[simp] theorem then_eq : ∀ {o : Ordering}, o.then eq = o := by decide
|
||||
@[simp] theorem then_self : ∀ {o : Ordering}, o.then o = o := by decide
|
||||
theorem then_assoc : ∀ (o₁ o₂ o₃ : Ordering), (o₁.then o₂).then o₃ = o₁.then (o₂.then o₃) := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isLE_eq_false {o : Ordering} : o.isLE = false ↔ o = .gt := by
|
||||
cases o <;> simp
|
||||
theorem isLE_then_iff_or : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE ↔ o₁ = lt ∨ (o₁ = eq ∧ o₂.isLE) := by decide
|
||||
theorem isLE_then_iff_and : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE ↔ o₁.isLE ∧ (o₁ = lt ∨ o₂.isLE) := by decide
|
||||
theorem isLE_left_of_isLE_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE → o₁.isLE := by decide
|
||||
theorem isGE_left_of_isGE_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isGE → o₁.isGE := by decide
|
||||
|
||||
@[simp]
|
||||
theorem isGE_eq_false {o : Ordering} : o.isGE = false ↔ o = .lt := by
|
||||
cases o <;> simp
|
||||
instance : Std.Associative Ordering.then := ⟨then_assoc⟩
|
||||
instance : Std.IdempotentOp Ordering.then := ⟨fun _ => then_self⟩
|
||||
|
||||
@[simp]
|
||||
theorem swap_eq_gt {o : Ordering} : o.swap = .gt ↔ o = .lt := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem swap_eq_lt {o : Ordering} : o.swap = .lt ↔ o = .gt := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem swap_eq_eq {o : Ordering} : o.swap = .eq ↔ o = .eq := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem isLT_swap {o : Ordering} : o.swap.isLT = o.isGT := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem isLE_swap {o : Ordering} : o.swap.isLE = o.isGE := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem isEq_swap {o : Ordering} : o.swap.isEq = o.isEq := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem isNe_swap {o : Ordering} : o.swap.isNe = o.isNe := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem isGE_swap {o : Ordering} : o.swap.isGE = o.isLE := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem isGT_swap {o : Ordering} : o.swap.isGT = o.isLT := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isLT_iff_eq_lt {o : Ordering} : o.isLT ↔ o = .lt := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isLE_iff_eq_lt_or_eq_eq {o : Ordering} : o.isLE ↔ o = .lt ∨ o = .eq := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isLE_of_eq_lt {o : Ordering} : o = .lt → o.isLE := by
|
||||
rintro rfl; rfl
|
||||
|
||||
theorem isLE_of_eq_eq {o : Ordering} : o = .eq → o.isLE := by
|
||||
rintro rfl; rfl
|
||||
|
||||
theorem isEq_iff_eq_eq {o : Ordering} : o.isEq ↔ o = .eq := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isNe_iff_ne_eq {o : Ordering} : o.isNe ↔ o ≠ .eq := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isGE_iff_eq_gt_or_eq_eq {o : Ordering} : o.isGE ↔ o = .gt ∨ o = .eq := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem isGE_of_eq_gt {o : Ordering} : o = .gt → o.isGE := by
|
||||
rintro rfl; rfl
|
||||
|
||||
theorem isGE_of_eq_eq {o : Ordering} : o = .eq → o.isGE := by
|
||||
rintro rfl; rfl
|
||||
|
||||
theorem isGT_iff_eq_gt {o : Ordering} : o.isGT ↔ o = .gt := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem swap_swap {o : Ordering} : o.swap.swap = o := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem swap_inj {o₁ o₂ : Ordering} : o₁.swap = o₂.swap ↔ o₁ = o₂ :=
|
||||
⟨fun h => by simpa using congrArg swap h, congrArg _⟩
|
||||
|
||||
theorem swap_then (o₁ o₂ : Ordering) : (o₁.then o₂).swap = o₁.swap.then o₂.swap := by
|
||||
cases o₁ <;> rfl
|
||||
|
||||
theorem then_eq_lt {o₁ o₂ : Ordering} : o₁.then o₂ = lt ↔ o₁ = lt ∨ o₁ = eq ∧ o₂ = lt := by
|
||||
cases o₁ <;> cases o₂ <;> decide
|
||||
|
||||
theorem then_eq_eq {o₁ o₂ : Ordering} : o₁.then o₂ = eq ↔ o₁ = eq ∧ o₂ = eq := by
|
||||
cases o₁ <;> simp [«then»]
|
||||
|
||||
theorem then_eq_gt {o₁ o₂ : Ordering} : o₁.then o₂ = gt ↔ o₁ = gt ∨ o₁ = eq ∧ o₂ = gt := by
|
||||
cases o₁ <;> cases o₂ <;> decide
|
||||
|
||||
@[simp]
|
||||
theorem lt_then {o : Ordering} : lt.then o = lt := rfl
|
||||
|
||||
@[simp]
|
||||
theorem gt_then {o : Ordering} : gt.then o = gt := rfl
|
||||
|
||||
@[simp]
|
||||
theorem eq_then {o : Ordering} : eq.then o = o := rfl
|
||||
|
||||
theorem isLE_then_iff_or {o₁ o₂ : Ordering} : (o₁.then o₂).isLE ↔ o₁ = lt ∨ (o₁ = eq ∧ o₂.isLE) := by
|
||||
cases o₁ <;> simp
|
||||
|
||||
theorem isLE_then_iff_and {o₁ o₂ : Ordering} : (o₁.then o₂).isLE ↔ o₁.isLE ∧ (o₁ = lt ∨ o₂.isLE) := by
|
||||
cases o₁ <;> simp
|
||||
|
||||
theorem isLE_left_of_isLE_then {o₁ o₂ : Ordering} (h : (o₁.then o₂).isLE) : o₁.isLE := by
|
||||
cases o₁ <;> simp_all
|
||||
|
||||
theorem isGE_left_of_isGE_then {o₁ o₂ : Ordering} (h : (o₁.then o₂).isGE) : o₁.isGE := by
|
||||
cases o₁ <;> simp_all
|
||||
instance : Std.LawfulIdentity Ordering.then eq where
|
||||
left_id _ := eq_then
|
||||
right_id _ := then_eq
|
||||
|
||||
end Lemmas
|
||||
|
||||
@@ -375,7 +335,7 @@ section Lemmas
|
||||
@[simp]
|
||||
theorem compareLex_eq_eq {α} {cmp₁ cmp₂} {a b : α} :
|
||||
compareLex cmp₁ cmp₂ a b = .eq ↔ cmp₁ a b = .eq ∧ cmp₂ a b = .eq := by
|
||||
simp [compareLex, Ordering.then_eq_eq]
|
||||
simp [compareLex]
|
||||
|
||||
theorem compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne {α : Type u} [LT α] [DecidableLT α] [DecidableEq α]
|
||||
(h : ∀ x y : α, x < y ↔ ¬ y < x ∧ x ≠ y) {x y : α} :
|
||||
@@ -384,14 +344,14 @@ theorem compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne {α : Type u} [LT α]
|
||||
split
|
||||
· rename_i h'
|
||||
rw [h] at h'
|
||||
simp only [h'.1, h'.2.symm, reduceIte, Ordering.swap_gt]
|
||||
simp only [h'.1, h'.2.symm, ↓reduceIte, Ordering.swap_gt]
|
||||
· split
|
||||
· rename_i h'
|
||||
have : ¬ y < y := Not.imp (·.2 rfl) <| (h y y).mp
|
||||
simp only [h', this, reduceIte, Ordering.swap_eq]
|
||||
simp only [h', this, ↓reduceIte, Ordering.swap_eq]
|
||||
· rename_i h' h''
|
||||
replace h' := (h y x).mpr ⟨h', Ne.symm h''⟩
|
||||
simp only [h', Ne.symm h'', reduceIte, Ordering.swap_lt]
|
||||
simp only [h', Ne.symm h'', ↓reduceIte, Ordering.swap_lt]
|
||||
|
||||
theorem lt_iff_not_gt_and_ne_of_antisymm_of_total_of_not_le
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α]
|
||||
@@ -478,13 +438,13 @@ but this is not enforced by the typeclass.
|
||||
There is a derive handler, so appending `deriving Ord` to an inductive type or structure
|
||||
will attempt to create an `Ord` instance.
|
||||
-/
|
||||
@[ext]
|
||||
class Ord (α : Type u) where
|
||||
/-- Compare two elements in `α` using the comparator contained in an `[Ord α]` instance. -/
|
||||
compare : α → α → Ordering
|
||||
|
||||
export Ord (compare)
|
||||
|
||||
set_option linter.unusedVariables false in -- allow specifying `ord` explicitly
|
||||
/--
|
||||
Compares two values by comparing the results of applying a function.
|
||||
|
||||
@@ -764,6 +724,13 @@ end Vector
|
||||
def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
compare := compareLex (compareOn (·.1)) (compareOn (·.2))
|
||||
|
||||
/--
|
||||
Constructs an `BEq` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.eq`.
|
||||
-/
|
||||
@[expose] def beqOfOrd [Ord α] : BEq α where
|
||||
beq a b := (compare a b).isEq
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.lt`.
|
||||
@@ -771,8 +738,9 @@ Constructs an `LT` instance from an `Ord` instance that asserts that the result
|
||||
@[expose] def ltOfOrd [Ord α] : LT α where
|
||||
lt a b := compare a b = Ordering.lt
|
||||
|
||||
instance [Ord α] : DecidableRel (@LT.lt α ltOfOrd) :=
|
||||
inferInstanceAs (DecidableRel (fun a b => compare a b = Ordering.lt))
|
||||
@[inline]
|
||||
instance [Ord α] : DecidableRel (@LT.lt α ltOfOrd) := fun a b =>
|
||||
decidable_of_bool (compare a b).isLT Ordering.isLT_iff_eq_lt
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare`
|
||||
@@ -781,35 +749,29 @@ satisfies `Ordering.isLE`.
|
||||
@[expose] def leOfOrd [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
instance [Ord α] : DecidableRel (@LE.le α leOfOrd) :=
|
||||
inferInstanceAs (DecidableRel (fun a b => (compare a b).isLE))
|
||||
@[inline]
|
||||
instance [Ord α] : DecidableRel (@LE.le α leOfOrd) := fun _ _ => instDecidableEqBool ..
|
||||
|
||||
namespace Ord
|
||||
|
||||
/--
|
||||
Constructs a `BEq` instance from an `Ord` instance.
|
||||
-/
|
||||
protected def toBEq (ord : Ord α) : BEq α where
|
||||
beq x y := ord.compare x y == .eq
|
||||
@[expose] protected abbrev toBEq (ord : Ord α) : BEq α :=
|
||||
beqOfOrd
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected def toLT (ord : Ord α) : LT α :=
|
||||
@[expose] protected abbrev toLT (ord : Ord α) : LT α :=
|
||||
ltOfOrd
|
||||
|
||||
instance [i : Ord α] : DecidableRel (@LT.lt _ (Ord.toLT i)) :=
|
||||
inferInstanceAs (DecidableRel (fun a b => compare a b = Ordering.lt))
|
||||
|
||||
/--
|
||||
Constructs an `LE` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected def toLE (ord : Ord α) : LE α :=
|
||||
@[expose] protected abbrev toLE (ord : Ord α) : LE α :=
|
||||
leOfOrd
|
||||
|
||||
instance [i : Ord α] : DecidableRel (@LE.le _ (Ord.toLE i)) :=
|
||||
inferInstanceAs (DecidableRel (fun a b => (compare a b).isLE))
|
||||
|
||||
/--
|
||||
Inverts the order of an `Ord` instance.
|
||||
|
||||
@@ -833,7 +795,7 @@ protected def on (_ : Ord β) (f : α → β) : Ord α where
|
||||
/--
|
||||
Constructs the lexicographic order on products `α × β` from orders for `α` and `β`.
|
||||
-/
|
||||
protected def lex (_ : Ord α) (_ : Ord β) : Ord (α × β) :=
|
||||
protected abbrev lex (_ : Ord α) (_ : Ord β) : Ord (α × β) :=
|
||||
lexOrd
|
||||
|
||||
/--
|
||||
@@ -849,13 +811,4 @@ comparisons.
|
||||
protected def lex' (ord₁ ord₂ : Ord α) : Ord α where
|
||||
compare := compareLex ord₁.compare ord₂.compare
|
||||
|
||||
/--
|
||||
Constructs an order which compares elements of an `Array` in lexicographic order.
|
||||
-/
|
||||
protected def arrayOrd [a : Ord α] : Ord (Array α) where
|
||||
compare x y :=
|
||||
let _ : LT α := a.toLT
|
||||
let _ : BEq α := a.toBEq
|
||||
if List.lex x.toList y.toList then .lt else if x == y then .eq else .gt
|
||||
|
||||
end Ord
|
||||
|
||||
@@ -429,8 +429,8 @@ Examples:
|
||||
def Int8.decLe (a b : Int8) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int8) : Decidable (a < b) := Int8.decLt a b
|
||||
instance (a b : Int8) : Decidable (a ≤ b) := Int8.decLe a b
|
||||
attribute [instance] Int8.decLt Int8.decLe
|
||||
|
||||
instance : Max Int8 := maxOfLe
|
||||
instance : Min Int8 := minOfLe
|
||||
|
||||
@@ -800,8 +800,8 @@ Examples:
|
||||
def Int16.decLe (a b : Int16) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int16) : Decidable (a < b) := Int16.decLt a b
|
||||
instance (a b : Int16) : Decidable (a ≤ b) := Int16.decLe a b
|
||||
attribute [instance] Int16.decLt Int16.decLe
|
||||
|
||||
instance : Max Int16 := maxOfLe
|
||||
instance : Min Int16 := minOfLe
|
||||
|
||||
@@ -1187,8 +1187,8 @@ Examples:
|
||||
def Int32.decLe (a b : Int32) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int32) : Decidable (a < b) := Int32.decLt a b
|
||||
instance (a b : Int32) : Decidable (a ≤ b) := Int32.decLe a b
|
||||
attribute [instance] Int32.decLt Int32.decLe
|
||||
|
||||
instance : Max Int32 := maxOfLe
|
||||
instance : Min Int32 := minOfLe
|
||||
|
||||
@@ -1593,8 +1593,8 @@ Examples:
|
||||
def Int64.decLe (a b : Int64) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int64) : Decidable (a < b) := Int64.decLt a b
|
||||
instance (a b : Int64) : Decidable (a ≤ b) := Int64.decLe a b
|
||||
attribute [instance] Int64.decLt Int64.decLe
|
||||
|
||||
instance : Max Int64 := maxOfLe
|
||||
instance : Min Int64 := minOfLe
|
||||
|
||||
@@ -1986,7 +1986,7 @@ Examples:
|
||||
def ISize.decLe (a b : ISize) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : ISize) : Decidable (a < b) := ISize.decLt a b
|
||||
instance (a b : ISize) : Decidable (a ≤ b) := ISize.decLe a b
|
||||
attribute [instance] ISize.decLt ISize.decLe
|
||||
|
||||
instance : Max ISize := maxOfLe
|
||||
instance : Min ISize := minOfLe
|
||||
|
||||
@@ -32,22 +32,4 @@ protected theorem ne_of_lt {a b : String} (h : a < b) : a ≠ b := by
|
||||
have := String.lt_irrefl a
|
||||
intro h; subst h; contradiction
|
||||
|
||||
instance ltIrrefl : Std.Irrefl (· < · : Char → Char → Prop) where
|
||||
irrefl := Char.lt_irrefl
|
||||
|
||||
instance leRefl : Std.Refl (· ≤ · : Char → Char → Prop) where
|
||||
refl := Char.le_refl
|
||||
|
||||
instance leTrans : Trans (· ≤ · : Char → Char → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans := Char.le_trans
|
||||
|
||||
instance leAntisymm : Std.Antisymm (· ≤ · : Char → Char → Prop) where
|
||||
antisymm _ _ := Char.le_antisymm
|
||||
|
||||
instance ltAsymm : Std.Asymm (· < · : Char → Char → Prop) where
|
||||
asymm _ _ := Char.lt_asymm
|
||||
|
||||
instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
|
||||
total := Char.le_total
|
||||
|
||||
end String
|
||||
|
||||
@@ -44,7 +44,6 @@ universe signature in consequence. The `Prop` version is `Or`.
|
||||
|
||||
namespace Sum
|
||||
|
||||
deriving instance DecidableEq for Sum
|
||||
deriving instance BEq for Sum
|
||||
|
||||
section get
|
||||
|
||||
@@ -222,8 +222,8 @@ Examples:
|
||||
def UInt8.decLe (a b : UInt8) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec ≤ b.toBitVec))
|
||||
|
||||
instance (a b : UInt8) : Decidable (a < b) := UInt8.decLt a b
|
||||
instance (a b : UInt8) : Decidable (a ≤ b) := UInt8.decLe a b
|
||||
attribute [instance] UInt8.decLt UInt8.decLe
|
||||
|
||||
instance : Max UInt8 := maxOfLe
|
||||
instance : Min UInt8 := minOfLe
|
||||
|
||||
@@ -438,8 +438,8 @@ Examples:
|
||||
def UInt16.decLe (a b : UInt16) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec ≤ b.toBitVec))
|
||||
|
||||
instance (a b : UInt16) : Decidable (a < b) := UInt16.decLt a b
|
||||
instance (a b : UInt16) : Decidable (a ≤ b) := UInt16.decLe a b
|
||||
attribute [instance] UInt16.decLt UInt16.decLe
|
||||
|
||||
instance : Max UInt16 := maxOfLe
|
||||
instance : Min UInt16 := minOfLe
|
||||
|
||||
@@ -586,8 +586,7 @@ set_option linter.deprecated false in
|
||||
instance : HMod UInt32 Nat UInt32 := ⟨UInt32.modn⟩
|
||||
|
||||
instance : Div UInt32 := ⟨UInt32.div⟩
|
||||
instance : LT UInt32 := ⟨UInt32.lt⟩
|
||||
instance : LE UInt32 := ⟨UInt32.le⟩
|
||||
-- `LT` and `LE` are already defined in `Init.Prelude`
|
||||
|
||||
/--
|
||||
Bitwise complement, also known as bitwise negation, for 32-bit unsigned integers. Usually accessed
|
||||
@@ -832,8 +831,8 @@ Examples:
|
||||
def UInt64.decLe (a b : UInt64) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec ≤ b.toBitVec))
|
||||
|
||||
instance (a b : UInt64) : Decidable (a < b) := UInt64.decLt a b
|
||||
instance (a b : UInt64) : Decidable (a ≤ b) := UInt64.decLe a b
|
||||
attribute [instance] UInt64.decLt UInt64.decLe
|
||||
|
||||
instance : Max UInt64 := maxOfLe
|
||||
instance : Min UInt64 := minOfLe
|
||||
|
||||
|
||||
@@ -437,5 +437,4 @@ Examples:
|
||||
def USize.decLe (a b : USize) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec ≤ b.toBitVec))
|
||||
|
||||
instance (a b : USize) : Decidable (a < b) := USize.decLt a b
|
||||
instance (a b : USize) : Decidable (a ≤ b) := USize.decLe a b
|
||||
attribute [instance] USize.decLt USize.decLe
|
||||
|
||||
@@ -474,7 +474,10 @@ If not, usually the right approach is `simp [Vector.unattach, -Vector.map_subtyp
|
||||
-/
|
||||
def unattach {α : Type _} {p : α → Prop} (xs : Vector { x // p x } n) : Vector α n := xs.map (·.val)
|
||||
|
||||
@[simp] theorem unattach_nil {p : α → Prop} : (#v[] : Vector { x // p x } 0).unattach = #v[] := by simp
|
||||
theorem unattach_empty {p : α → Prop} : (#v[] : Vector { x // p x } 0).unattach = #v[] := by simp
|
||||
|
||||
@[deprecated unattach_empty (since := "2025-05-26")]
|
||||
abbrev unattach_nil := @unattach_empty
|
||||
|
||||
@[simp] theorem unattach_push {p : α → Prop} {a : { x // p x }} {xs : Vector { x // p x } n} :
|
||||
(xs.push a).unattach = xs.unattach.push a.1 := by
|
||||
|
||||
@@ -198,6 +198,8 @@ result is empty. If `stop` is greater than the size of the vector, the size is u
|
||||
/--
|
||||
Extract the first `i` elements of a vector. If `i` is greater than or equal to the size of the
|
||||
vector then the vector is returned unchanged.
|
||||
|
||||
We immediately simplify this to the `extract` operation, so there is no verification API for this function.
|
||||
-/
|
||||
@[inline] def take (xs : Vector α n) (i : Nat) : Vector α (min i n) :=
|
||||
⟨xs.toArray.take i, by simp⟩
|
||||
@@ -207,16 +209,22 @@ vector then the vector is returned unchanged.
|
||||
/--
|
||||
Deletes the first `i` elements of a vector. If `i` is greater than or equal to the size of the
|
||||
vector then the empty vector is returned.
|
||||
|
||||
We immediately simplify this to the `extract` operation, so there is no verification API for this function.
|
||||
-/
|
||||
@[inline] def drop (xs : Vector α n) (i : Nat) : Vector α (n - i) :=
|
||||
⟨xs.toArray.drop i, by simp⟩
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
@[simp] theorem drop_eq_cast_extract (xs : Vector α n) (i : Nat) :
|
||||
xs.drop i = (xs.extract i n).cast (by simp) := by
|
||||
xs.drop i = (xs.extract i).cast (by simp) := by
|
||||
simp [drop, extract, Vector.cast]
|
||||
|
||||
/-- Shrinks a vector to the first `m` elements, by repeatedly popping the last element. -/
|
||||
/--
|
||||
Shrinks a vector to the first `m` elements, by repeatedly popping the last element.
|
||||
|
||||
We immediately simplify this to the `extract` operation, so there is no verification API for this function.
|
||||
-/
|
||||
@[inline] def shrink (xs : Vector α n) (i : Nat) : Vector α (min i n) :=
|
||||
⟨xs.toArray.shrink i, by simp⟩
|
||||
|
||||
@@ -307,6 +315,8 @@ abbrev zipWithIndex := @zipIdx
|
||||
@[inline] def ofFn (f : Fin n → α) : Vector α n :=
|
||||
⟨Array.ofFn f, by simp⟩
|
||||
|
||||
/-! See also `Vector.ofFnM` defined in `Init.Data.Vector.OfFn`. -/
|
||||
|
||||
/--
|
||||
Swap two elements of a vector using `Fin` indices.
|
||||
|
||||
@@ -392,12 +402,17 @@ instance [BEq α] : BEq (Vector α n) where
|
||||
have : Inhabited (Vector α (n+1)) := ⟨xs.push x⟩
|
||||
panic! "index out of bounds"
|
||||
|
||||
/-- Delete the first element of a vector. Returns the empty vector if the input vector is empty. -/
|
||||
@[inline] def tail (xs : Vector α n) : Vector α (n-1) :=
|
||||
if _ : 0 < n then
|
||||
xs.eraseIdx 0
|
||||
else
|
||||
xs.cast (by omega)
|
||||
/--
|
||||
Delete the first element of a vector. Returns the empty vector if the input vector is empty.
|
||||
|
||||
We immediately simplify this to the `extract` operation, so there is no verification API for this function.
|
||||
-/
|
||||
@[inline]
|
||||
def tail (xs : Vector α n) : Vector α (n-1) :=
|
||||
(xs.extract 1).cast (by omega)
|
||||
|
||||
@[simp] theorem tail_eq_cast_extract (xs : Vector α n) :
|
||||
xs.tail = (xs.extract 1).cast (by omega) := rfl
|
||||
|
||||
/--
|
||||
Finds the first index of a given value in a vector using `==` for comparison. Returns `none` if the
|
||||
|
||||
@@ -40,8 +40,8 @@ theorem countP_push {a : α} {xs : Vector α n} : countP p (xs.push a) = countP
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.countP_push]
|
||||
|
||||
@[simp] theorem countP_singleton {a : α} : countP p #v[a] = if p a then 1 else 0 := by
|
||||
simp [countP_push]
|
||||
theorem countP_singleton {a : α} : countP p #v[a] = if p a then 1 else 0 := by
|
||||
simp
|
||||
|
||||
theorem size_eq_countP_add_countP {xs : Vector α n} : n = countP p xs + countP (fun a => ¬p a) xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -44,25 +44,22 @@ theorem isEqv_self [DecidableEq α] (xs : Vector α n) : Vector.isEqv xs xs (·
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.isEqv_self]
|
||||
|
||||
instance [DecidableEq α] : DecidableEq (Vector α n) :=
|
||||
fun xs ys =>
|
||||
match h:isEqv xs ys (fun x y => x = y) with
|
||||
| true => isTrue (eq_of_isEqv xs ys h)
|
||||
| false => isFalse fun h' => by subst h'; rw [isEqv_self] at h; contradiction
|
||||
|
||||
theorem beq_eq_decide [BEq α] (xs ys : Vector α n) :
|
||||
(xs == ys) = decide (∀ (i : Nat) (h' : i < n), xs[i] == ys[i]) := by
|
||||
simp [BEq.beq, isEqv_eq_decide]
|
||||
|
||||
@[simp] theorem beq_mk [BEq α] (xs ys : Array α) (ha : xs.size = n) (hb : ys.size = n) :
|
||||
@[deprecated mk_beq_mk (since := "2025-05-26")]
|
||||
theorem beq_mk [BEq α] (xs ys : Array α) (ha : xs.size = n) (hb : ys.size = n) :
|
||||
(mk xs ha == mk ys hb) = (xs == ys) := by
|
||||
simp [BEq.beq]
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem beq_toArray [BEq α] (xs ys : Vector α n) : (xs.toArray == ys.toArray) = (xs == ys) := by
|
||||
simp [beq_eq_decide, Array.beq_eq_decide]
|
||||
@[deprecated toArray_beq_toArray (since := "2025-05-26")]
|
||||
theorem beq_toArray [BEq α] (xs ys : Vector α n) : (xs.toArray == ys.toArray) = (xs == ys) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem beq_toList [BEq α] (xs ys : Vector α n) : (xs.toList == ys.toList) = (xs == ys) := by
|
||||
simp [beq_eq_decide, List.beq_eq_decide]
|
||||
@[deprecated toList_beq_toList (since := "2025-05-26")]
|
||||
theorem beq_toList [BEq α] (xs ys : Vector α n) : (xs.toList == ys.toList) = (xs == ys) := by
|
||||
simp
|
||||
|
||||
instance [BEq α] [ReflBEq α] : ReflBEq (Vector α n) where
|
||||
rfl := by simp [BEq.beq, isEqv_self_beq]
|
||||
|
||||
@@ -144,7 +144,7 @@ abbrev findSome?_mkVector_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
@[simp] theorem find?_empty : find? p #v[] = none := rfl
|
||||
|
||||
@[simp] theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
#v[a].find? p = if p a then some a else none := by
|
||||
simp
|
||||
|
||||
@@ -291,7 +291,8 @@ theorem find?_eq_some_iff_getElem {xs : Vector α n} {p : α → Bool} {b : α}
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
@[simp] theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p (#v[] : Vector α 0) = none := by simp
|
||||
theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p (#v[] : Vector α 0) = none := by simp
|
||||
|
||||
theorem findFinIdx?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findFinIdx? p = if p a then some ⟨0, by simp⟩ else none := by
|
||||
simp
|
||||
|
||||
@@ -53,9 +53,9 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
|
||||
(Vector.mk xs size).contains a = xs.contains a := by
|
||||
simp [contains]
|
||||
|
||||
@[simp] theorem push_mk {xs : Array α} {size : xs.size = n} {x : α} :
|
||||
(Vector.mk xs size).push x =
|
||||
Vector.mk (xs.push x) (by simp [size, Nat.succ_eq_add_one]) := rfl
|
||||
@[simp] theorem push_mk {xs : Array α} {size : xs.size = n} :
|
||||
(Vector.mk xs size).push =
|
||||
fun x => Vector.mk (xs.push x) (by simp [size, Nat.succ_eq_add_one]) := rfl
|
||||
|
||||
@[simp] theorem pop_mk {xs : Array α} {size : xs.size = n} :
|
||||
(Vector.mk xs size).pop = Vector.mk xs.pop (by simp [size]) := rfl
|
||||
@@ -486,7 +486,7 @@ abbrev toArray_mkVector := @toArray_replicate
|
||||
`Vector.ext` is an extensionality theorem.
|
||||
Vectors `a` and `b` are equal to each other if their elements are equal for each valid index.
|
||||
-/
|
||||
@[ext]
|
||||
@[ext, grind ext]
|
||||
protected theorem ext {xs ys : Vector α n} (h : (i : Nat) → (_ : i < n) → xs[i] = ys[i]) : xs = ys := by
|
||||
apply Vector.toArray_inj.1
|
||||
apply Array.ext
|
||||
@@ -684,8 +684,7 @@ abbrev toList_eq_empty_iff {α n} (xs) := @toList_eq_nil_iff α n xs
|
||||
|
||||
/-! ### empty -/
|
||||
|
||||
@[simp] theorem empty_eq {xs : Vector α 0} : #v[] = xs ↔ xs = #v[] := by
|
||||
cases xs
|
||||
theorem empty_eq {xs : Vector α 0} : #v[] = xs ↔ xs = #v[] := by
|
||||
simp
|
||||
|
||||
/-- A vector of length `0` is the empty vector. -/
|
||||
@@ -816,14 +815,11 @@ abbrev mkVector_eq_mk_mkArray := @replicate_eq_mk_replicate
|
||||
|
||||
/-! ## L[i] and L[i]? -/
|
||||
|
||||
@[simp] theorem getElem?_eq_none_iff {xs : Vector α n} : xs[i]? = none ↔ n ≤ i := by
|
||||
by_cases h : i < n
|
||||
· simp [getElem?_pos, h]
|
||||
· rw [getElem?_neg xs i h]
|
||||
simp_all
|
||||
theorem getElem?_eq_none_iff {xs : Vector α n} : xs[i]? = none ↔ n ≤ i := by
|
||||
simp
|
||||
|
||||
@[simp] theorem none_eq_getElem?_iff {xs : Vector α n} {i : Nat} : none = xs[i]? ↔ n ≤ i := by
|
||||
simp [eq_comm (a := none)]
|
||||
theorem none_eq_getElem?_iff {xs : Vector α n} {i : Nat} : none = xs[i]? ↔ n ≤ i := by
|
||||
simp
|
||||
|
||||
theorem getElem?_eq_none {xs : Vector α n} (h : n ≤ i) : xs[i]? = none := by
|
||||
simp [getElem?_eq_none_iff, h]
|
||||
@@ -835,23 +831,23 @@ grind_pattern Vector.getElem?_eq_none => n ≤ i, xs[i]?
|
||||
@[simp] theorem getElem?_eq_getElem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i]? = some xs[i] :=
|
||||
getElem?_pos ..
|
||||
|
||||
theorem getElem?_eq_some_iff {xs : Vector α n} : xs[i]? = some b ↔ ∃ h : i < n, xs[i] = b := by
|
||||
simp [getElem?_def]
|
||||
theorem getElem?_eq_some_iff {xs : Vector α n} : xs[i]? = some b ↔ ∃ h : i < n, xs[i] = b :=
|
||||
_root_.getElem?_eq_some_iff
|
||||
|
||||
@[grind →]
|
||||
theorem getElem_of_getElem? {xs : Vector α n} : xs[i]? = some a → ∃ h : i < n, xs[i] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
theorem some_eq_getElem?_iff {xs : Vector α n} : some b = xs[i]? ↔ ∃ h : i < n, xs[i] = b := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
theorem some_eq_getElem?_iff {xs : Vector α n} : some b = xs[i]? ↔ ∃ h : i < n, xs[i] = b :=
|
||||
_root_.some_eq_getElem?_iff
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem?_iff {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
theorem some_getElem_eq_getElem?_iff {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
(some xs[i] = xs[i]?) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
theorem getElem?_eq_some_getElem_iff {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
(xs[i]? = some xs[i]) ↔ True := by
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
theorem getElem_eq_iff {xs : Vector α n} {i : Nat} {h : i < n} : xs[i] = x ↔ xs[i]? = some x := by
|
||||
simp only [getElem?_eq_some_iff]
|
||||
@@ -891,12 +887,11 @@ theorem getElem?_push {xs : Vector α n} {x : α} {i : Nat} : (xs.push x)[i]? =
|
||||
(repeat' split) <;> first | rfl | omega
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
@[simp] theorem getElem?_push_size {xs : Vector α n} {x : α} : (xs.push x)[n]? = some x := by
|
||||
simp [getElem?_push]
|
||||
theorem getElem?_push_size {xs : Vector α n} {x : α} : (xs.push x)[n]? = some x := by
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem_singleton {a : α} (h : i < 1) : #v[a][i] = a :=
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
theorem getElem_singleton {a : α} (h : i < 1) : #v[a][i] = a := by
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : #v[a][i]? = if i = 0 then some a else none := by
|
||||
@@ -908,7 +903,7 @@ theorem getElem?_singleton {a : α} {i : Nat} : #v[a][i]? = if i = 0 then some a
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem not_mem_empty (a : α) : ¬ a ∈ #v[] := nofun
|
||||
theorem not_mem_empty (a : α) : ¬ a ∈ #v[] := nofun
|
||||
|
||||
@[simp] theorem mem_push {xs : Vector α n} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -957,8 +952,7 @@ theorem size_zero_iff_forall_not_mem {xs : Vector α n} : n = 0 ↔ ∀ a, a ∉
|
||||
theorem eq_of_mem_singleton (h : a ∈ #v[b]) : a = b := by
|
||||
simpa using h
|
||||
|
||||
@[simp] theorem mem_singleton {a b : α} : a ∈ #v[b] ↔ a = b :=
|
||||
⟨eq_of_mem_singleton, (by simp [·])⟩
|
||||
theorem mem_singleton {a b : α} : a ∈ #v[b] ↔ a = b := by simp
|
||||
|
||||
theorem forall_mem_push {p : α → Prop} {xs : Vector α n} {a : α} :
|
||||
(∀ x, x ∈ xs.push a → p x) ↔ p a ∧ ∀ x, x ∈ xs → p x := by
|
||||
@@ -1444,10 +1438,9 @@ theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by
|
||||
simp
|
||||
|
||||
/-- The empty vector maps to the empty vector. -/
|
||||
@[simp, grind]
|
||||
@[grind]
|
||||
theorem map_empty {f : α → β} : map f #v[] = #v[] := by
|
||||
rw [map, mk.injEq]
|
||||
exact Array.map_empty
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem map_push {f : α → β} {as : Vector α n} {x : α} :
|
||||
(as.push x).map f = (as.map f).push (f x) := by
|
||||
@@ -1524,9 +1517,8 @@ theorem map_eq_push_iff {f : α → β} {xs : Vector α (n + 1)} {ys : Vector β
|
||||
· rintro ⟨xs', a, h₁, h₂, rfl⟩
|
||||
refine ⟨xs'.toArray, a, by simp_all⟩
|
||||
|
||||
@[simp] theorem map_eq_singleton_iff {f : α → β} {xs : Vector α 1} {b : β} :
|
||||
theorem map_eq_singleton_iff {f : α → β} {xs : Vector α 1} {b : β} :
|
||||
map f xs = #v[b] ↔ ∃ a, xs = #v[a] ∧ f a = b := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
theorem map_eq_map_iff {f g : α → β} {xs : Vector α n} :
|
||||
@@ -1660,12 +1652,12 @@ 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]
|
||||
|
||||
@[grind]
|
||||
@[simp, grind]
|
||||
theorem empty_append {xs : Vector α n} : (#v[] : Vector α 0) ++ xs = xs.cast (by omega) := by
|
||||
rcases xs with ⟨as, rfl⟩
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[simp, grind]
|
||||
theorem append_empty {xs : Vector α n} : xs ++ (#v[] : Vector α 0) = xs := by
|
||||
rw [← toArray_inj, toArray_append, Array.append_empty]
|
||||
|
||||
@@ -2105,7 +2097,7 @@ abbrev forall_mem_mkVector := @forall_mem_replicate
|
||||
@[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")]
|
||||
@@ -2361,13 +2353,13 @@ set_option linter.indexVariables false in
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem foldlM_empty [Monad m] {f : β → α → m β} {init : β} :
|
||||
theorem foldlM_empty [Monad m] {f : β → α → m β} {init : β} :
|
||||
foldlM f init #v[] = return init := by
|
||||
simp [foldlM]
|
||||
simp
|
||||
|
||||
@[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 [foldrM]
|
||||
simp
|
||||
|
||||
@[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
|
||||
@@ -2385,19 +2377,23 @@ theorem foldrM_pure [Monad m] [LawfulMonad m] {f : α → β → β} {b} {xs : V
|
||||
Array.foldrM_pure
|
||||
|
||||
theorem foldl_eq_foldlM {f : β → α → β} {b} {xs : Vector α n} :
|
||||
xs.foldl f b = xs.foldlM (m := Id) f b := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.foldl_eq_foldlM]
|
||||
xs.foldl f b = (xs.foldlM (m := Id) (pure <| f · ·) b).run := rfl
|
||||
|
||||
theorem foldr_eq_foldrM {f : α → β → β} {b} {xs : Vector α n} :
|
||||
xs.foldr f b = xs.foldrM (m := Id) f b := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.foldr_eq_foldrM]
|
||||
xs.foldr f b = (xs.foldrM (m := Id) (pure <| f · ·) b).run := rfl
|
||||
|
||||
@[simp] theorem id_run_foldlM {f : β → α → Id β} {b} {xs : Vector α n} :
|
||||
@[simp] theorem idRun_foldlM {f : β → α → Id β} {b} {xs : Vector α n} :
|
||||
Id.run (xs.foldlM f b) = xs.foldl (f · · |>.run) b := foldl_eq_foldlM.symm
|
||||
|
||||
@[deprecated idRun_foldlM (since := "2025-05-21")]
|
||||
theorem id_run_foldlM {f : β → α → Id β} {b} {xs : Vector α n} :
|
||||
Id.run (xs.foldlM f b) = xs.foldl f b := foldl_eq_foldlM.symm
|
||||
|
||||
@[simp] theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Vector α n} :
|
||||
@[simp] theorem idRun_foldrM {f : α → β → Id β} {b} {xs : Vector α n} :
|
||||
Id.run (xs.foldrM f b) = xs.foldr (f · · |>.run) b := foldr_eq_foldrM.symm
|
||||
|
||||
@[deprecated idRun_foldrM (since := "2025-05-21")]
|
||||
theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Vector α n} :
|
||||
Id.run (xs.foldrM f b) = xs.foldr f b := foldr_eq_foldrM.symm
|
||||
|
||||
@[simp] theorem foldlM_reverse [Monad m] {xs : Vector α n} {f : β → α → m β} {b} :
|
||||
@@ -2485,10 +2481,10 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
simp
|
||||
|
||||
@[simp, grind _=_] theorem foldl_append {β : Type _} {f : β → α → β} {b} {xs : Vector α n} {ys : Vector α k} :
|
||||
(xs ++ ys).foldl f b = ys.foldl f (xs.foldl f b) := by simp [foldl_eq_foldlM]
|
||||
(xs ++ ys).foldl f b = ys.foldl f (xs.foldl f b) := foldlM_append
|
||||
|
||||
@[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) := by simp [foldr_eq_foldrM]
|
||||
(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} :
|
||||
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
|
||||
@@ -2501,7 +2497,8 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
simp [Array.foldr_flatten', Array.foldr_map']
|
||||
|
||||
@[simp, grind] theorem foldl_reverse {xs : Vector α n} {f : β → α → β} {b} :
|
||||
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b := by simp [foldl_eq_foldlM, foldr_eq_foldrM]
|
||||
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} :
|
||||
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
|
||||
@@ -2680,7 +2677,7 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Vector α n} {a : α} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.contains_iff_exists_mem_beq]
|
||||
|
||||
@[grind]
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Vector α n} {a : α} :
|
||||
xs.contains a ↔ a ∈ xs := by
|
||||
simp
|
||||
@@ -3053,8 +3050,7 @@ end replace
|
||||
/-! Content below this point has not yet been aligned with `List` and `Array`. -/
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
@[simp] theorem getElem_push_last {xs : Vector α n} {x : α} : (xs.push x)[n] = x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
theorem getElem_push_last {xs : Vector α n} {x : α} : (xs.push x)[n] = x := by
|
||||
simp
|
||||
|
||||
@[simp] theorem push_pop_back (xs : Vector α (n + 1)) : xs.pop.push xs.back = xs := by
|
||||
@@ -3086,8 +3082,7 @@ set_option linter.indexVariables false in
|
||||
/-! ### take -/
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
@[simp] theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
|
||||
simp
|
||||
|
||||
/-! ### swap -/
|
||||
@@ -3136,9 +3131,8 @@ theorem swap_comm {xs : Vector α n} {i j : Nat} (hi hj) :
|
||||
|
||||
/-! ### drop -/
|
||||
|
||||
@[simp, grind =] theorem getElem_drop {xs : Vector α n} {j : Nat} (hi : i < n - j) :
|
||||
@[grind =] theorem getElem_drop {xs : Vector α n} {j : Nat} (hi : i < n - j) :
|
||||
(xs.drop j)[i] = xs[j + i] := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-! ### Decidable quantifiers. -/
|
||||
|
||||
@@ -58,9 +58,8 @@ protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {xs ys
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
@[simp] theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #v[a].lex #v[b] lt = lt a b := by
|
||||
simp only [lex, getElem_mk, List.getElem_toArray, List.getElem_singleton]
|
||||
cases lt a b <;> cases a != b <;> simp [Id.run]
|
||||
theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #v[a].lex #v[b] lt = lt a b := by
|
||||
simp
|
||||
|
||||
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] (xs : Vector α n) : ¬ xs < xs :=
|
||||
Array.lt_irrefl xs.toArray
|
||||
|
||||
@@ -295,9 +295,8 @@ theorem mapIdx_eq_push_iff {xs : Vector α (n + 1)} {b : β} :
|
||||
· rintro ⟨a, zs, rfl, rfl, rfl⟩
|
||||
exact ⟨zs, a, rfl, by simp⟩
|
||||
|
||||
@[simp] theorem mapIdx_eq_singleton_iff {xs : Vector α 1} {f : Nat → α → β} {b : β} :
|
||||
theorem mapIdx_eq_singleton_iff {xs : Vector α 1} {f : Nat → α → β} {b : β} :
|
||||
mapIdx f xs = #v[b] ↔ ∃ (a : α), xs = #v[a] ∧ f 0 a = b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
theorem mapIdx_eq_append_iff {xs : Vector α (n + m)} {f : Nat → α → β} {ys : Vector β n} {zs : Vector β m} :
|
||||
|
||||
@@ -25,10 +25,10 @@ open Nat
|
||||
|
||||
/-! ## Monadic operations -/
|
||||
|
||||
@[simp] theorem map_toArray_inj [Monad m] [LawfulMonad m]
|
||||
theorem map_toArray_inj [Monad m] [LawfulMonad m]
|
||||
{xs : m (Vector α n)} {ys : m (Vector α n)} :
|
||||
toArray <$> xs = toArray <$> ys ↔ xs = ys :=
|
||||
_root_.map_inj_right (by simp)
|
||||
toArray <$> xs = toArray <$> ys ↔ xs = ys := by
|
||||
simp
|
||||
|
||||
/-! ### mapM -/
|
||||
|
||||
@@ -38,6 +38,11 @@ theorem mapM_pure [Monad m] [LawfulMonad m] {xs : Vector α n} (f : α → β) :
|
||||
apply map_toArray_inj.mp
|
||||
simp
|
||||
|
||||
@[simp] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {xs : Vector α n} :
|
||||
(xs.map f).mapM g = xs.mapM (g ∘ f) := by
|
||||
apply map_toArray_inj.mp
|
||||
simp
|
||||
|
||||
@[congr] theorem mapM_congr [Monad m] {xs ys : Vector α n} (w : xs = ys)
|
||||
{f : α → m β} :
|
||||
xs.mapM f = ys.mapM f := by
|
||||
@@ -143,12 +148,18 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.forIn'_pure_yield_eq_foldl, Array.foldl_map]
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
theorem idRun_forIn'_yield_eq_foldl
|
||||
{xs : Vector α n} (f : (a : α) → a ∈ xs → β → Id β) (init : β) :
|
||||
(forIn' xs init (fun a m b => .yield <$> f a m b)).run =
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated forIn'_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn'_yield_eq_foldl
|
||||
{xs : Vector α n} (f : (a : α) → a ∈ xs → β → β) (init : β) :
|
||||
forIn' (m := Id) xs init (fun a m b => .yield (f a m b)) =
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [List.foldl_map]
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{xs : Vector α n} (g : α → β) (f : (b : β) → b ∈ xs.map g → γ → m (ForInStep γ)) :
|
||||
@@ -185,12 +196,18 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.forIn_pure_yield_eq_foldl, Array.foldl_map]
|
||||
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
theorem idRun_forIn_yield_eq_foldl
|
||||
{xs : Vector α n} (f : α → β → Id β) (init : β) :
|
||||
(forIn xs init (fun a b => .yield <$> f a b)).run =
|
||||
xs.foldl (fun b a => f a b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated idRun_forIn_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn_yield_eq_foldl
|
||||
{xs : Vector α n} (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) xs init (fun a b => .yield (f a b)) =
|
||||
xs.foldl (fun b a => f a b) init := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
xs.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{xs : Vector α n} (g : α → β) (f : β → γ → m (ForInStep γ)) :
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
import all Init.Data.Vector.Basic
|
||||
import Init.Data.Vector.Lemmas
|
||||
import Init.Data.Vector.Monadic
|
||||
import Init.Data.Array.OfFn
|
||||
|
||||
/-!
|
||||
@@ -40,4 +41,121 @@ theorem back_ofFn {n} [NeZero n] {f : Fin n → α} :
|
||||
(ofFn f).back = f ⟨n - 1, by have := NeZero.ne n; omega⟩ := by
|
||||
simp [back]
|
||||
|
||||
theorem ofFn_succ {f : Fin (n+1) → α} :
|
||||
ofFn f = (ofFn (fun (i : Fin n) => f i.castSucc)).push (f ⟨n, by omega⟩) := by
|
||||
ext i h
|
||||
· simp only [getElem_ofFn, getElem_push, Fin.castSucc_mk, left_eq_dite_iff]
|
||||
intro h'
|
||||
have : i = n := by omega
|
||||
simp_all
|
||||
|
||||
theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
ofFn f = (ofFn (fun i => f (i.castLE (Nat.le_add_right n m)))) ++ (ofFn (fun i => f (i.natAdd n))) := by
|
||||
apply Vector.toArray_inj.mp
|
||||
simp [Array.ofFn_add]
|
||||
|
||||
theorem ofFn_succ' {f : Fin (n+1) → α} :
|
||||
ofFn f = (#v[f 0] ++ ofFn (fun i => f i.succ)).cast (by omega) := by
|
||||
apply Vector.toArray_inj.mp
|
||||
simp [Array.ofFn_succ']
|
||||
|
||||
/-! ### ofFnM -/
|
||||
|
||||
/-- Construct (in a monadic context) a vector by applying a monadic function to each index. -/
|
||||
def ofFnM {n} [Monad m] (f : Fin n → m α) : m (Vector α n) :=
|
||||
go 0 (by omega) (Array.emptyWithCapacity n) rfl where
|
||||
/-- Auxiliary for `ofFn`. `ofFn.go f i acc = acc ++ #v[f i, ..., f(n - 1)]` -/
|
||||
go (i : Nat) (h' : i ≤ n) (acc : Array α) (w : acc.size = i) : m (Vector α n) := do
|
||||
if h : i < n then
|
||||
go (i+1) (by omega) (acc.push (← f ⟨i, h⟩)) (by simp [w])
|
||||
else
|
||||
pure ⟨acc, by omega⟩
|
||||
|
||||
@[simp]
|
||||
theorem ofFnM_zero [Monad m] {f : Fin 0 → m α} : Vector.ofFnM f = pure #v[] := by
|
||||
simp [ofFnM, ofFnM.go]
|
||||
|
||||
private theorem ofFnM_go_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α}
|
||||
(hi : i ≤ n := by omega) {h : xs.size = i} :
|
||||
ofFnM.go f i (by omega) xs h = (do
|
||||
let as ← ofFnM.go (fun i => f i.castSucc) i hi xs h
|
||||
let a ← f (Fin.last n)
|
||||
pure (as.push a)) := by
|
||||
fun_induction ofFnM.go f i (by omega) xs h
|
||||
case case1 acc h' h ih =>
|
||||
if h : acc.size = n then
|
||||
unfold ofFnM.go
|
||||
rw [dif_neg (by omega)]
|
||||
have h : ¬ acc.size + 1 < n + 1 := by omega
|
||||
have : Fin.last n = ⟨acc.size, by omega⟩ := by ext; simp; omega
|
||||
simp [*]
|
||||
else
|
||||
have : acc.size + 1 ≤ n := by omega
|
||||
simp only [ih, this]
|
||||
conv => rhs; unfold ofFnM.go
|
||||
rw [dif_pos (by omega)]
|
||||
simp
|
||||
case case2 =>
|
||||
omega
|
||||
|
||||
theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i => f i.castSucc
|
||||
let a ← f (Fin.last n)
|
||||
pure (as.push a)) := by
|
||||
simp [ofFnM, ofFnM_go_succ]
|
||||
|
||||
theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM (fun i => f (i.castLE (Nat.le_add_right n k)))
|
||||
let bs ← ofFnM (fun i => f (i.natAdd n))
|
||||
pure (as ++ bs)) := by
|
||||
induction k with
|
||||
| zero => simp
|
||||
| succ k ih => simp [ofFnM_succ, ih, ← push_append]
|
||||
|
||||
@[simp, grind] theorem toArray_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
toArray <$> ofFnM f = Array.ofFnM f := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ofFnM_succ, Array.ofFnM_succ, ← ih]
|
||||
|
||||
@[simp, grind] theorem toList_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
toList <$> Vector.ofFnM f = List.ofFnM f := by
|
||||
unfold toList
|
||||
suffices Array.toList <$> (toArray <$> ofFnM f) = List.ofFnM f by
|
||||
simpa [-toArray_ofFnM]
|
||||
simp
|
||||
|
||||
theorem ofFnM_succ' {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let a ← f 0
|
||||
let as ← ofFnM fun i => f i.succ
|
||||
pure ((#v[a] ++ as).cast (by omega))) := by
|
||||
apply Vector.map_toArray_inj.mp
|
||||
simp only [toArray_ofFnM, Array.ofFnM_succ', bind_pure_comp, map_bind, Functor.map_map,
|
||||
toArray_cast, toArray_append]
|
||||
congr 1
|
||||
funext x
|
||||
have : (fun xs : Vector α n => #[x] ++ xs.toArray) = (#[x] ++ ·) ∘ toArray := by funext xs; simp
|
||||
simp [this, comp_map]
|
||||
|
||||
@[simp]
|
||||
theorem ofFnM_pure_comp [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (pure ∘ f) = (pure (ofFn f) : m (Vector α n)) := by
|
||||
apply Vector.map_toArray_inj.mp
|
||||
simp
|
||||
|
||||
-- Variant of `ofFnM_pure_comp` using a lambda.
|
||||
-- This is not marked a `@[simp]` as it would match on every occurrence of `ofFnM`.
|
||||
theorem ofFnM_pure [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (fun i => pure (f i)) = (pure (ofFn f) : m (Vector α n)) :=
|
||||
ofFnM_pure_comp
|
||||
|
||||
@[simp, grind =] theorem idRun_ofFnM {f : Fin n → Id α} :
|
||||
Id.run (ofFnM f) = ofFn (fun i => Id.run (f i)) := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ofFnM_succ', ofFn_succ', ih]
|
||||
|
||||
end Vector
|
||||
|
||||
@@ -82,6 +82,8 @@ end Lean
|
||||
attribute [ext] Prod PProd Sigma PSigma
|
||||
attribute [ext] funext propext Subtype.eq Array.ext
|
||||
|
||||
attribute [grind ext] Array.ext
|
||||
|
||||
@[ext] protected theorem PUnit.ext (x y : PUnit) : x = y := rfl
|
||||
protected theorem Unit.ext (x y : Unit) : x = y := rfl
|
||||
|
||||
|
||||
@@ -198,6 +198,58 @@ theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem d
|
||||
simp only [getElem?_def]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem none_eq_getElem?_iff [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) [Decidable (dom c i)] : none = c[i]? ↔ ¬dom c i := by
|
||||
simp only [getElem?_def]
|
||||
split <;> simp_all
|
||||
|
||||
theorem of_getElem?_eq_some [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
{c : cont} {i : idx} [Decidable (dom c i)] (h : c[i]? = some e) : dom c i := by
|
||||
simp only [getElem?_def] at h
|
||||
split at h <;> rename_i h'
|
||||
case isTrue =>
|
||||
exact h'
|
||||
case isFalse =>
|
||||
simp at h
|
||||
|
||||
theorem getElem?_eq_some_iff [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
{c : cont} {i : idx} [Decidable (dom c i)] : c[i]? = some e ↔ Exists fun h : dom c i => c[i] = e := by
|
||||
simp only [getElem?_def]
|
||||
split <;> rename_i h
|
||||
case isTrue =>
|
||||
constructor
|
||||
case mp =>
|
||||
intro w
|
||||
refine ⟨h, ?_⟩
|
||||
simpa using w
|
||||
case mpr =>
|
||||
intro ⟨h, w⟩
|
||||
simpa using w
|
||||
case isFalse =>
|
||||
simp only [reduceCtorEq, false_iff]
|
||||
intro ⟨w, w'⟩
|
||||
exact h w
|
||||
|
||||
theorem some_eq_getElem?_iff [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
{c : cont} {i : idx} [Decidable (dom c i)] : some e = c[i]? ↔ Exists fun h : dom c i => c[i] = e := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
theorem getElem_of_getElem? [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
{c : cont} {i : idx} [Decidable (dom c i)] (h : c[i]? = some e) : Exists fun h : dom c i => c[i] = e :=
|
||||
getElem?_eq_some_iff.mp h
|
||||
|
||||
grind_pattern getElem_of_getElem? => c[i]?, some e
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem?_iff [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
{c : cont} {i : idx} [Decidable (dom c i)] (h : dom c i):
|
||||
(some c[i] = c[i]?) ↔ True := by
|
||||
simpa [some_eq_getElem?_iff, h] using ⟨h, trivial⟩
|
||||
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
{c : cont} {i : idx} [Decidable (dom c i)] (h : dom c i):
|
||||
(c[i]? = some c[i]) ↔ True := by
|
||||
simpa [getElem?_eq_some_iff, h] using ⟨h, trivial⟩
|
||||
|
||||
@[deprecated getElem?_eq_none_iff (since := "2025-02-17")]
|
||||
abbrev getElem?_eq_none := @getElem?_eq_none_iff
|
||||
|
||||
@@ -296,7 +348,8 @@ instance : GetElem? (List α) Nat α fun as i => i < as.length where
|
||||
| zero => rfl
|
||||
| succ i => exact ih ..
|
||||
|
||||
@[simp] theorem getElem?_eq_none_iff : l[i]? = none ↔ length l ≤ i :=
|
||||
-- This is only needed locally; after the `LawfulGetElem` instance the general `getElem?_eq_none_iff` lemma applies.
|
||||
@[local simp] theorem getElem?_eq_none_iff : l[i]? = none ↔ length l ≤ i :=
|
||||
match l with
|
||||
| [] => by simp; rfl
|
||||
| _ :: l => by
|
||||
@@ -306,7 +359,7 @@ instance : GetElem? (List α) Nat α fun as i => i < as.length where
|
||||
simp only [length_cons, Nat.add_le_add_iff_right]
|
||||
exact getElem?_eq_none_iff (l := l) (i := i)
|
||||
|
||||
@[simp] theorem none_eq_getElem?_iff {l : List α} {i : Nat} : none = l[i]? ↔ length l ≤ i := by
|
||||
theorem none_eq_getElem?_iff {l : List α} {i : Nat} : none = l[i]? ↔ length l ≤ i := by
|
||||
simp [eq_comm (a := none)]
|
||||
|
||||
theorem getElem?_eq_none (h : length l ≤ i) : l[i]? = none := getElem?_eq_none_iff.mpr h
|
||||
|
||||
@@ -15,4 +15,6 @@ import Init.Grind.Util
|
||||
import Init.Grind.Offset
|
||||
import Init.Grind.PP
|
||||
import Init.Grind.CommRing
|
||||
import Init.Grind.Module
|
||||
import Init.Grind.Ordered
|
||||
import Init.Grind.Ext
|
||||
|
||||
@@ -9,5 +9,5 @@ prelude
|
||||
import Init.Core
|
||||
import Init.Grind.Tactics
|
||||
|
||||
attribute [grind cases eager] And Prod False Empty True Unit Exists Subtype
|
||||
attribute [grind cases eager] And Prod False Empty True PUnit Exists Subtype
|
||||
attribute [grind cases] Or
|
||||
|
||||
@@ -13,3 +13,4 @@ import Init.Grind.CommRing.SInt
|
||||
import Init.Grind.CommRing.Fin
|
||||
import Init.Grind.CommRing.BitVec
|
||||
import Init.Grind.CommRing.Poly
|
||||
import Init.Grind.CommRing.Field
|
||||
|
||||
@@ -10,6 +10,7 @@ import Init.Data.Zero
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Data.Int.Pow
|
||||
import Init.TacticsExtra
|
||||
import Init.Grind.Module.Basic
|
||||
|
||||
/-!
|
||||
# A monolithic commutative ring typeclass for internal use in `grind`.
|
||||
@@ -103,11 +104,35 @@ 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 pow_one (a : α) : a ^ 1 = a := by
|
||||
rw [pow_succ, pow_zero, one_mul]
|
||||
|
||||
theorem pow_two (a : α) : a ^ 2 = a * a := by
|
||||
rw [pow_succ, pow_one]
|
||||
|
||||
theorem pow_add (a : α) (k₁ k₂ : Nat) : a ^ (k₁ + k₂) = a^k₁ * a^k₂ := by
|
||||
induction k₂
|
||||
next => simp [pow_zero, mul_one]
|
||||
next k₂ ih => rw [Nat.add_succ, pow_succ, pow_succ, ih, mul_assoc]
|
||||
|
||||
instance : NatModule α where
|
||||
hMul a x := a * x
|
||||
add_zero := by simp [add_zero]
|
||||
zero_add := by simp [zero_add]
|
||||
add_assoc := by simp [add_assoc]
|
||||
add_comm := by simp [add_comm]
|
||||
zero_hmul := by simp [natCast_zero, zero_mul]
|
||||
one_hmul := by simp [natCast_one, one_mul]
|
||||
add_hmul := by simp [natCast_add, right_distrib]
|
||||
hmul_zero := by simp [mul_zero]
|
||||
hmul_add := by simp [left_distrib]
|
||||
mul_hmul := by simp [natCast_mul, mul_assoc]
|
||||
|
||||
theorem hmul_eq_natCast_mul {α} [Semiring α] {k : Nat} {a : α} : HMul.hMul (α := Nat) k a = (k : α) * a := rfl
|
||||
|
||||
theorem hmul_eq_ofNat_mul {α} [Semiring α] {k : Nat} {a : α} : HMul.hMul (α := Nat) k a = OfNat.ofNat k * a := by
|
||||
simp [ofNat_eq_natCast, hmul_eq_natCast_mul]
|
||||
|
||||
end Semiring
|
||||
|
||||
namespace Ring
|
||||
@@ -243,6 +268,23 @@ theorem intCast_pow (x : Int) (k : Nat) : ((x ^ k : Int) : α) = (x : α) ^ k :=
|
||||
next => simp [pow_zero, Int.pow_zero, intCast_one]
|
||||
next k ih => simp [pow_succ, Int.pow_succ, intCast_mul, *]
|
||||
|
||||
instance : IntModule α where
|
||||
hMul a x := a * x
|
||||
add_zero := by simp [add_zero]
|
||||
zero_add := by simp [zero_add]
|
||||
add_assoc := by simp [add_assoc]
|
||||
add_comm := by simp [add_comm]
|
||||
zero_hmul := by simp [intCast_zero, zero_mul]
|
||||
one_hmul := by simp [intCast_one, one_mul]
|
||||
add_hmul := by simp [intCast_add, right_distrib]
|
||||
hmul_zero := by simp [mul_zero]
|
||||
hmul_add := by simp [left_distrib]
|
||||
mul_hmul := by simp [intCast_mul, mul_assoc]
|
||||
neg_add_cancel := by simp [neg_add_cancel]
|
||||
sub_eq_add_neg := by simp [sub_eq_add_neg]
|
||||
|
||||
theorem hmul_eq_intCast_mul {α} [Ring α] {k : Int} {a : α} : HMul.hMul (α := Int) k a = (k : α) * a := rfl
|
||||
|
||||
end Ring
|
||||
|
||||
namespace CommSemiring
|
||||
@@ -347,14 +389,7 @@ theorem natCast_eq_iff_of_lt {x y : Nat} (h₁ : x < p) (h₂ : y < p) :
|
||||
|
||||
end IsCharP
|
||||
|
||||
/--
|
||||
Special case of Mathlib's `NoZeroSMulDivisors Nat α`.
|
||||
-/
|
||||
class NoNatZeroDivisors (α : Type u) [Ring α] where
|
||||
no_nat_zero_divisors : ∀ (k : Nat) (a : α), k ≠ 0 → OfNat.ofNat (α := α) k * a = 0 → a = 0
|
||||
|
||||
export NoNatZeroDivisors (no_nat_zero_divisors)
|
||||
|
||||
-- TODO: This should be generalizable to any `IntModule α`, not just `Ring α`.
|
||||
theorem no_int_zero_divisors {α : Type u} [Ring α] [NoNatZeroDivisors α] {k : Int} {a : α}
|
||||
: k ≠ 0 → k * a = 0 → a = 0 := by
|
||||
match k with
|
||||
@@ -362,13 +397,12 @@ theorem no_int_zero_divisors {α : Type u} [Ring α] [NoNatZeroDivisors α] {k :
|
||||
simp [intCast_natCast]
|
||||
intro h₁ h₂
|
||||
replace h₁ : k ≠ 0 := by intro h; simp [h] at h₁
|
||||
rw [← ofNat_eq_natCast] at h₂
|
||||
exact no_nat_zero_divisors k a h₁ h₂
|
||||
| -(k+1 : Nat) =>
|
||||
rw [Int.natCast_add, ← Int.natCast_add, intCast_neg, intCast_natCast]
|
||||
intro _ h
|
||||
replace h := congrArg (-·) h; simp at h
|
||||
rw [← neg_mul, neg_neg, neg_zero, ← ofNat_eq_natCast] at h
|
||||
rw [← neg_mul, neg_neg, neg_zero, ← hmul_eq_natCast_mul] at h
|
||||
exact no_nat_zero_divisors (k+1) a (Nat.succ_ne_zero _) h
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
91
src/Init/Grind/CommRing/Field.lean
Normal file
91
src/Init/Grind/CommRing/Field.lean
Normal file
@@ -0,0 +1,91 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.CommRing.Basic
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
class Field (α : Type u) extends CommRing α, Inv α, Div α where
|
||||
div_eq_mul_inv : ∀ a b : α, a / b = a * b⁻¹
|
||||
zero_ne_one : (0 : α) ≠ 1
|
||||
inv_zero : (0 : α)⁻¹ = 0
|
||||
mul_inv_cancel : ∀ {a : α}, a ≠ 0 → a * a⁻¹ = 1
|
||||
|
||||
attribute [instance 100] Field.toInv Field.toDiv
|
||||
|
||||
namespace Field
|
||||
|
||||
variable [Field α] {a : α}
|
||||
|
||||
theorem inv_mul_cancel (h : a ≠ 0) : a⁻¹ * a = 1 := by
|
||||
rw [CommSemiring.mul_comm, mul_inv_cancel h]
|
||||
|
||||
theorem eq_inv_of_mul_eq_one (h : a * b = 1) : a = b⁻¹ := by
|
||||
by_cases h' : b = 0
|
||||
· subst h'
|
||||
rw [Semiring.mul_zero] at h
|
||||
exfalso
|
||||
exact zero_ne_one h
|
||||
· replace h := congrArg (fun x => x * b⁻¹) h
|
||||
simpa [Semiring.mul_assoc, mul_inv_cancel h', Semiring.mul_one, Semiring.one_mul] using h
|
||||
|
||||
theorem inv_one : (1 : α)⁻¹ = 1 :=
|
||||
(eq_inv_of_mul_eq_one (Semiring.mul_one 1)).symm
|
||||
|
||||
theorem inv_inv (a : α) : a⁻¹⁻¹ = a := by
|
||||
by_cases h : a = 0
|
||||
· subst h
|
||||
simp [Field.inv_zero]
|
||||
· symm
|
||||
apply eq_inv_of_mul_eq_one
|
||||
exact mul_inv_cancel h
|
||||
|
||||
theorem inv_neg (a : α) : (-a)⁻¹ = -a⁻¹ := by
|
||||
by_cases h : a = 0
|
||||
· subst h
|
||||
simp [Field.inv_zero, Ring.neg_zero]
|
||||
· symm
|
||||
apply eq_inv_of_mul_eq_one
|
||||
simp [Ring.neg_mul, Ring.mul_neg, Ring.neg_neg, Field.inv_mul_cancel h]
|
||||
|
||||
theorem inv_eq_zero_iff {a : α} : a⁻¹ = 0 ↔ a = 0 := by
|
||||
constructor
|
||||
· intro w
|
||||
by_cases h : a = 0
|
||||
· subst h
|
||||
rfl
|
||||
· have := congrArg (fun x => x * a) w
|
||||
dsimp at this
|
||||
rw [Semiring.zero_mul, inv_mul_cancel h] at this
|
||||
exfalso
|
||||
exact zero_ne_one this.symm
|
||||
· intro w
|
||||
subst w
|
||||
simp [Field.inv_zero]
|
||||
|
||||
theorem zero_eq_inv_iff {a : α} : 0 = a⁻¹ ↔ 0 = a := by
|
||||
rw [eq_comm, inv_eq_zero_iff, eq_comm]
|
||||
|
||||
instance [IsCharP α 0] : NoNatZeroDivisors α where
|
||||
no_nat_zero_divisors := by
|
||||
intro a b h w
|
||||
have := IsCharP.natCast_eq_zero_iff (α := α) 0 a
|
||||
simp only [Nat.mod_zero, h, iff_false] at this
|
||||
if h : b = 0 then
|
||||
exact h
|
||||
else
|
||||
rw [Semiring.ofNat_eq_natCast] at w
|
||||
replace w := congrArg (fun x => x * b⁻¹) w
|
||||
dsimp only [] at w
|
||||
rw [Semiring.hmul_eq_ofNat_mul, Semiring.mul_assoc, Field.mul_inv_cancel h, Semiring.mul_one,
|
||||
Semiring.natCast_zero, Semiring.zero_mul, Semiring.ofNat_eq_natCast] at w
|
||||
contradiction
|
||||
|
||||
end Field
|
||||
|
||||
end Lean.Grind
|
||||
@@ -104,7 +104,11 @@ instance (n : Nat) [NeZero n] : CommRing (Fin n) where
|
||||
intCast_neg := Fin.intCast_neg
|
||||
|
||||
instance (n : Nat) [NeZero n] : IsCharP (Fin n) n where
|
||||
ofNat_eq_zero_iff x := by simp only [OfNat.ofNat, Fin.ofNat']; simp
|
||||
ofNat_eq_zero_iff x := by
|
||||
change Fin.ofNat' _ _ = Fin.ofNat' _ _ ↔ _
|
||||
simp only [Fin.ofNat']
|
||||
simp only [Nat.zero_mod]
|
||||
simp only [Fin.mk.injEq]
|
||||
|
||||
end Fin
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ def Mon.grevlex (m₁ m₂ : Mon) : Ordering :=
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Mon) (p : Poly)
|
||||
deriving BEq, Inhabited, Hashable
|
||||
deriving BEq, Repr, Inhabited, Hashable
|
||||
|
||||
instance : LawfulBEq Poly where
|
||||
eq_of_beq {a} := by
|
||||
|
||||
9
src/Init/Grind/Module.lean
Normal file
9
src/Init/Grind/Module.lean
Normal file
@@ -0,0 +1,9 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.Module.Basic
|
||||
114
src/Init/Grind/Module/Basic.lean
Normal file
114
src/Init/Grind/Module/Basic.lean
Normal file
@@ -0,0 +1,114 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.Int.Order
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
class NatModule (M : Type u) extends Zero M, Add M, HMul Nat M M where
|
||||
add_zero : ∀ a : M, a + 0 = a
|
||||
zero_add : ∀ a : M, 0 + a = a
|
||||
add_comm : ∀ a b : M, a + b = b + a
|
||||
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
|
||||
zero_hmul : ∀ a : M, 0 * a = 0
|
||||
one_hmul : ∀ a : M, 1 * a = a
|
||||
add_hmul : ∀ n m : Nat, ∀ a : M, (n + m) * a = n * a + m * a
|
||||
hmul_zero : ∀ n : Nat, n * (0 : M) = 0
|
||||
hmul_add : ∀ n : Nat, ∀ a b : M, n * (a + b) = n * a + n * b
|
||||
mul_hmul : ∀ n m : Nat, ∀ a : M, (n * m) * a = n * (m * a)
|
||||
|
||||
attribute [instance 100] NatModule.toZero NatModule.toAdd NatModule.toHMul
|
||||
|
||||
class IntModule (M : Type u) extends Zero M, Add M, Neg M, Sub M, HMul Int M M where
|
||||
add_zero : ∀ a : M, a + 0 = a
|
||||
zero_add : ∀ a : M, 0 + a = a
|
||||
add_comm : ∀ a b : M, a + b = b + a
|
||||
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
|
||||
zero_hmul : ∀ a : M, (0 : Int) * a = 0
|
||||
one_hmul : ∀ a : M, (1 : Int) * a = a
|
||||
add_hmul : ∀ n m : Int, ∀ a : M, (n + m) * a = n * a + m * a
|
||||
hmul_zero : ∀ n : Int, n * (0 : M) = 0
|
||||
hmul_add : ∀ n : Int, ∀ a b : M, n * (a + b) = n * a + n * b
|
||||
mul_hmul : ∀ n m : Int, ∀ a : M, (n * m) * a = n * (m * a)
|
||||
neg_add_cancel : ∀ a : M, -a + a = 0
|
||||
sub_eq_add_neg : ∀ a b : M, a - b = a + -b
|
||||
|
||||
namespace IntModule
|
||||
|
||||
attribute [instance 100] IntModule.toZero IntModule.toAdd IntModule.toNeg IntModule.toSub IntModule.toHMul
|
||||
|
||||
instance toNatModule (M : Type u) [i : IntModule M] : NatModule M :=
|
||||
{ i with
|
||||
hMul a x := (a : Int) * x
|
||||
hmul_zero := by simp [IntModule.hmul_zero]
|
||||
add_hmul := by simp [IntModule.add_hmul]
|
||||
hmul_add := by simp [IntModule.hmul_add]
|
||||
mul_hmul := by simp [IntModule.mul_hmul] }
|
||||
|
||||
variable {M : Type u} [IntModule M]
|
||||
|
||||
theorem add_neg_cancel (a : M) : a + -a = 0 := by
|
||||
rw [add_comm, neg_add_cancel]
|
||||
|
||||
theorem add_left_inj {a b : M} (c : M) : a + c = b + c ↔ a = b :=
|
||||
⟨fun h => by simpa [add_assoc, add_neg_cancel, add_zero] using (congrArg (· + -c) h),
|
||||
fun g => congrArg (· + c) g⟩
|
||||
|
||||
theorem add_right_inj (a b c : M) : a + b = a + c ↔ b = c := by
|
||||
rw [add_comm a b, add_comm a c, add_left_inj]
|
||||
|
||||
theorem neg_zero : (-0 : M) = 0 := by
|
||||
rw [← add_left_inj 0, neg_add_cancel, add_zero]
|
||||
|
||||
theorem neg_neg (a : M) : -(-a) = a := by
|
||||
rw [← add_left_inj (-a), neg_add_cancel, add_neg_cancel]
|
||||
|
||||
theorem neg_eq_zero (a : M) : -a = 0 ↔ a = 0 :=
|
||||
⟨fun h => by
|
||||
replace h := congrArg (-·) h
|
||||
simpa [neg_neg, neg_zero] using h,
|
||||
fun h => by rw [h, neg_zero]⟩
|
||||
|
||||
theorem neg_add (a b : M) : -(a + b) = -a + -b := by
|
||||
rw [← add_left_inj (a + b), neg_add_cancel, add_assoc (-a), add_comm a b, ← add_assoc (-b),
|
||||
neg_add_cancel, zero_add, neg_add_cancel]
|
||||
|
||||
theorem neg_sub (a b : M) : -(a - b) = b - a := by
|
||||
rw [sub_eq_add_neg, neg_add, neg_neg, sub_eq_add_neg, add_comm]
|
||||
|
||||
theorem sub_self (a : M) : a - a = 0 := by
|
||||
rw [sub_eq_add_neg, add_neg_cancel]
|
||||
|
||||
theorem sub_eq_iff {a b c : M} : a - b = c ↔ a = c + b := by
|
||||
rw [sub_eq_add_neg]
|
||||
constructor
|
||||
next => intro; subst c; rw [add_assoc, neg_add_cancel, add_zero]
|
||||
next => intro; subst a; rw [add_assoc, add_comm b, neg_add_cancel, add_zero]
|
||||
|
||||
theorem sub_eq_zero_iff {a b : M} : a - b = 0 ↔ a = b := by
|
||||
simp [sub_eq_iff, zero_add]
|
||||
|
||||
theorem neg_hmul (n : Int) (a : M) : (-n) * a = - (n * a) := by
|
||||
apply (add_left_inj (n * a)).mp
|
||||
rw [← add_hmul, Int.add_left_neg, zero_hmul, neg_add_cancel]
|
||||
|
||||
theorem hmul_neg (n : Int) (a : M) : n * (-a) = - (n * a) := by
|
||||
apply (add_left_inj (n * a)).mp
|
||||
rw [← hmul_add, neg_add_cancel, neg_add_cancel, hmul_zero]
|
||||
|
||||
end IntModule
|
||||
|
||||
/--
|
||||
Special case of Mathlib's `NoZeroSMulDivisors Nat α`.
|
||||
-/
|
||||
class NoNatZeroDivisors (α : Type u) [Zero α] [HMul Nat α α] where
|
||||
no_nat_zero_divisors : ∀ (k : Nat) (a : α), k ≠ 0 → k * a = 0 → a = 0
|
||||
|
||||
export NoNatZeroDivisors (no_nat_zero_divisors)
|
||||
|
||||
end Lean.Grind
|
||||
@@ -104,6 +104,26 @@ theorem flip_bool_eq (a b : Bool) : (a = b) = (b = a) := by
|
||||
theorem bool_eq_to_prop (a b : Bool) : (a = b) = ((a = true) = (b = true)) := by
|
||||
simp
|
||||
|
||||
theorem forall_or_forall {α : Sort u} {β : α → Sort v} (p : α → Prop) (q : (a : α) → β a → Prop)
|
||||
: (∀ a : α, p a ∨ ∀ b : β a, q a b) =
|
||||
(∀ (a : α) (b : β a), p a ∨ q a b) := by
|
||||
apply propext; constructor
|
||||
· intro h a b; cases h a <;> simp [*]
|
||||
· intro h a
|
||||
apply Classical.byContradiction
|
||||
intro h'; simp at h'; have ⟨h₁, b, h₂⟩ := h'
|
||||
replace h := h a b; simp [h₁, h₂] at h
|
||||
|
||||
theorem forall_forall_or {α : Sort u} {β : α → Sort v} (p : α → Prop) (q : (a : α) → β a → Prop)
|
||||
: (∀ a : α, (∀ b : β a, q a b) ∨ p a) =
|
||||
(∀ (a : α) (b : β a), q a b ∨ p a) := by
|
||||
apply propext; constructor
|
||||
· intro h a b; cases h a <;> simp [*]
|
||||
· intro h a
|
||||
apply Classical.byContradiction
|
||||
intro h'; simp at h'; have ⟨⟨b, h₁⟩, h₂⟩ := h'
|
||||
replace h := h a b; simp [h₁, h₂] at h
|
||||
|
||||
init_grind_norm
|
||||
/- Pre theorems -/
|
||||
not_and not_or not_ite not_forall not_exists
|
||||
@@ -113,6 +133,7 @@ init_grind_norm
|
||||
/- Post theorems -/
|
||||
Classical.not_not
|
||||
ne_eq iff_eq eq_self heq_eq_eq
|
||||
forall_or_forall forall_forall_or
|
||||
-- Prop equality
|
||||
eq_true_eq eq_false_eq not_eq_prop
|
||||
-- True
|
||||
|
||||
13
src/Init/Grind/Ordered.lean
Normal file
13
src/Init/Grind/Ordered.lean
Normal file
@@ -0,0 +1,13 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.Ordered.Order
|
||||
import Init.Grind.Ordered.Module
|
||||
import Init.Grind.Ordered.Ring
|
||||
import Init.Grind.Ordered.Field
|
||||
import Init.Grind.Ordered.Int
|
||||
188
src/Init/Grind/Ordered/Field.lean
Normal file
188
src/Init/Grind/Ordered/Field.lean
Normal file
@@ -0,0 +1,188 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.CommRing.Field
|
||||
import Init.Grind.Ordered.Ring
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
namespace Field.IsOrdered
|
||||
|
||||
variable {R : Type u} [Field R] [LinearOrder R] [Ring.IsOrdered R]
|
||||
|
||||
open Ring.IsOrdered
|
||||
|
||||
theorem pos_of_inv_pos {a : R} (h : 0 < a⁻¹) : 0 < a := by
|
||||
rcases LinearOrder.trichotomy 0 a with (h' | rfl | h')
|
||||
· exact h'
|
||||
· simpa [Field.inv_zero] using h
|
||||
· exfalso
|
||||
have := Ring.IsOrdered.mul_neg_of_pos_of_neg h h'
|
||||
rw [inv_mul_cancel (Preorder.ne_of_lt h')] at this
|
||||
exact Ring.IsOrdered.not_one_lt_zero this
|
||||
|
||||
theorem inv_pos_iff {a : R} : 0 < a⁻¹ ↔ 0 < a := by
|
||||
constructor
|
||||
· exact pos_of_inv_pos
|
||||
· intro h
|
||||
rw [← Field.inv_inv a] at h
|
||||
exact pos_of_inv_pos h
|
||||
|
||||
theorem inv_neg_iff {a : R} : a⁻¹ < 0 ↔ a < 0 := by
|
||||
have := inv_pos_iff (a := -a)
|
||||
rw [Field.inv_neg] at this
|
||||
simpa [IntModule.IsOrdered.neg_pos_iff]
|
||||
|
||||
theorem inv_nonneg_iff {a : R} : 0 ≤ a⁻¹ ↔ 0 ≤ a := by
|
||||
simp [PartialOrder.le_iff_lt_or_eq, inv_pos_iff, Field.zero_eq_inv_iff]
|
||||
|
||||
theorem inv_nonpos_iff {a : R} : a⁻¹ ≤ 0 ↔ a ≤ 0 := by
|
||||
have := inv_nonneg_iff (a := -a)
|
||||
rw [Field.inv_neg] at this
|
||||
simpa [IntModule.IsOrdered.neg_nonneg_iff] using this
|
||||
|
||||
private theorem mul_le_of_le_mul_inv {a b c : R} (h : 0 < c) (h' : a ≤ b * c⁻¹) : a * c ≤ b := by
|
||||
simpa [Semiring.mul_assoc, Field.inv_mul_cancel (Preorder.ne_of_gt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_le_mul_of_nonneg_right h' (Preorder.le_of_lt h)
|
||||
|
||||
private theorem le_mul_inv_of_mul_le {a b c : R} (h : 0 < b) (h' : a * b ≤ c) : a ≤ c * b⁻¹ := by
|
||||
simpa [Semiring.mul_assoc, Field.mul_inv_cancel (Preorder.ne_of_gt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_le_mul_of_nonneg_right h' (Preorder.le_of_lt (inv_pos_iff.mpr h))
|
||||
|
||||
theorem le_mul_inv_iff_mul_le (a b : R) {c : R} (h : 0 < c) : a ≤ b * c⁻¹ ↔ a * c ≤ b :=
|
||||
⟨mul_le_of_le_mul_inv h, le_mul_inv_of_mul_le h⟩
|
||||
|
||||
private theorem mul_inv_le_iff_le_mul (a c : R) {b : R} (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ c * b := by
|
||||
have := (le_mul_inv_iff_mul_le a c (inv_pos_iff.mpr h)).symm
|
||||
simpa [Field.inv_inv] using this
|
||||
|
||||
private theorem mul_lt_of_lt_mul_inv {a b c : R} (h : 0 < c) (h' : a < b * c⁻¹) : a * c < b := by
|
||||
simpa [Semiring.mul_assoc, Field.inv_mul_cancel (Preorder.ne_of_gt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_lt_mul_of_pos_right h' h
|
||||
|
||||
private theorem lt_mul_inv_of_mul_lt {a b c : R} (h : 0 < b) (h' : a * b < c) : a < c * b⁻¹ := by
|
||||
simpa [Semiring.mul_assoc, Field.mul_inv_cancel (Preorder.ne_of_gt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_lt_mul_of_pos_right h' (inv_pos_iff.mpr h)
|
||||
|
||||
theorem lt_mul_inv_iff_mul_lt (a b : R) {c : R} (h : 0 < c) : a < b * c⁻¹ ↔ a * c < b :=
|
||||
⟨mul_lt_of_lt_mul_inv h, lt_mul_inv_of_mul_lt h⟩
|
||||
|
||||
theorem mul_inv_lt_iff_lt_mul (a c : R) {b : R} (h : 0 < b) : a * b⁻¹ < c ↔ a < c * b := by
|
||||
simpa [Field.inv_inv] using (lt_mul_inv_iff_mul_lt a c (inv_pos_iff.mpr h)).symm
|
||||
|
||||
private theorem le_mul_of_le_mul_inv {a b c : R} (h : c < 0) (h' : a ≤ b * c⁻¹) : b ≤ a * c := by
|
||||
simpa [Semiring.mul_assoc, Field.inv_mul_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_le_mul_of_nonpos_right h' (Preorder.le_of_lt h)
|
||||
|
||||
private theorem mul_le_of_mul_inv_le {a b c : R} (h : b < 0) (h' : a * b⁻¹ ≤ c) : c * b ≤ a := by
|
||||
simpa [Semiring.mul_assoc, Field.inv_mul_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_le_mul_of_nonpos_right h' (Preorder.le_of_lt h)
|
||||
|
||||
private theorem mul_inv_le_of_mul_le {a b c : R} (h : b < 0) (h' : a * b ≤ c) : c * b⁻¹ ≤ a := by
|
||||
simpa [Semiring.mul_assoc, Field.mul_inv_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_le_mul_of_nonpos_right h' (Preorder.le_of_lt (inv_neg_iff.mpr h))
|
||||
|
||||
private theorem le_mul_inv_of_le_mul {a b c : R} (h : c < 0) (h' : a ≤ b * c) : b ≤ a * c⁻¹ := by
|
||||
simpa [Semiring.mul_assoc, Field.mul_inv_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_le_mul_of_nonpos_right h' (Preorder.le_of_lt (inv_neg_iff.mpr h))
|
||||
|
||||
theorem le_mul_inv_iff_le_mul_of_neg (a b : R) {c : R} (h : c < 0) : a ≤ b * c⁻¹ ↔ b ≤ a * c :=
|
||||
⟨le_mul_of_le_mul_inv h, le_mul_inv_of_le_mul h⟩
|
||||
|
||||
theorem mul_inv_le_iff_mul_le_of_neg (a c : R) {b : R} (h : b < 0) : a * b⁻¹ ≤ c ↔ c * b ≤ a :=
|
||||
⟨mul_le_of_mul_inv_le h, mul_inv_le_of_mul_le h⟩
|
||||
|
||||
private theorem lt_mul_of_lt_mul_inv {a b c : R} (h : c < 0) (h' : a < b * c⁻¹) : b < a * c := by
|
||||
simpa [Semiring.mul_assoc, Field.inv_mul_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_lt_mul_of_neg_right h' h
|
||||
|
||||
private theorem mul_lt_of_mul_inv_lt {a b c : R} (h : b < 0) (h' : a * b⁻¹ < c) : c * b < a := by
|
||||
simpa [Semiring.mul_assoc, Field.inv_mul_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_lt_mul_of_neg_right h' h
|
||||
|
||||
private theorem mul_inv_lt_of_mul_lt {a b c : R} (h : b < 0) (h' : a * b < c) : c * b⁻¹ < a := by
|
||||
simpa [Semiring.mul_assoc, Field.mul_inv_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_lt_mul_of_neg_right h' (inv_neg_iff.mpr h)
|
||||
|
||||
private theorem lt_mul_inv_of_lt_mul {a b c : R} (h : c < 0) (h' : a < b * c) : b < a * c⁻¹ := by
|
||||
simpa [Semiring.mul_assoc, Field.mul_inv_cancel (Preorder.ne_of_lt h), Semiring.mul_one] using
|
||||
Ring.IsOrdered.mul_lt_mul_of_neg_right h' (inv_neg_iff.mpr h)
|
||||
|
||||
theorem lt_mul_inv_iff_lt_mul_of_neg (a b : R) {c : R} (h : c < 0) : a < b * c⁻¹ ↔ b < a * c :=
|
||||
⟨lt_mul_of_lt_mul_inv h, lt_mul_inv_of_lt_mul h⟩
|
||||
|
||||
theorem mul_inv_lt_iff_mul_lt_of_neg (a c : R) {b : R} (h : b < 0) : a * b⁻¹ < c ↔ c * b < a :=
|
||||
⟨mul_lt_of_mul_inv_lt h, mul_inv_lt_of_mul_lt h⟩
|
||||
|
||||
theorem mul_lt_mul_iff_of_pos_right {a b c : R} (h : 0 < c) : a * c < b * c ↔ a < b := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_lt_mul_of_pos_right h' (inv_pos_iff.mpr h)
|
||||
rwa [Semiring.mul_assoc, Semiring.mul_assoc, mul_inv_cancel (Preorder.ne_of_gt h),
|
||||
Semiring.mul_one, Semiring.mul_one] at this
|
||||
· exact (mul_lt_mul_of_pos_right · h)
|
||||
|
||||
theorem mul_lt_mul_iff_of_pos_left {a b c : R} (h : 0 < c) : c * a < c * b ↔ a < b := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_lt_mul_of_pos_left h' (inv_pos_iff.mpr h)
|
||||
rwa [← Semiring.mul_assoc, ← Semiring.mul_assoc, inv_mul_cancel (Preorder.ne_of_gt h),
|
||||
Semiring.one_mul, Semiring.one_mul] at this
|
||||
· exact (mul_lt_mul_of_pos_left · h)
|
||||
|
||||
theorem mul_lt_mul_iff_of_neg_right {a b c : R} (h : c < 0) : a * c < b * c ↔ b < a := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_lt_mul_of_neg_right h' (inv_neg_iff.mpr h)
|
||||
rwa [Semiring.mul_assoc, Semiring.mul_assoc, mul_inv_cancel (Preorder.ne_of_lt h),
|
||||
Semiring.mul_one, Semiring.mul_one] at this
|
||||
· exact (mul_lt_mul_of_neg_right · h)
|
||||
|
||||
theorem mul_lt_mul_iff_of_neg_left {a b c : R} (h : c < 0) : c * a < c * b ↔ b < a := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_lt_mul_of_neg_left h' (inv_neg_iff.mpr h)
|
||||
rwa [← Semiring.mul_assoc, ← Semiring.mul_assoc, inv_mul_cancel (Preorder.ne_of_lt h),
|
||||
Semiring.one_mul, Semiring.one_mul] at this
|
||||
· exact (mul_lt_mul_of_neg_left · h)
|
||||
|
||||
theorem mul_le_mul_iff_of_pos_right {a b c : R} (h : 0 < c) : a * c ≤ b * c ↔ a ≤ b := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_le_mul_of_nonneg_right h' (Preorder.le_of_lt (inv_pos_iff.mpr h))
|
||||
rwa [Semiring.mul_assoc, Semiring.mul_assoc, mul_inv_cancel (Preorder.ne_of_gt h),
|
||||
Semiring.mul_one, Semiring.mul_one] at this
|
||||
· exact (mul_le_mul_of_nonneg_right · (Preorder.le_of_lt h))
|
||||
|
||||
theorem mul_le_mul_iff_of_pos_left {a b c : R} (h : 0 < c) : c * a ≤ c * b ↔ a ≤ b := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_le_mul_of_nonneg_left h' (Preorder.le_of_lt (inv_pos_iff.mpr h))
|
||||
rwa [← Semiring.mul_assoc, ← Semiring.mul_assoc, inv_mul_cancel (Preorder.ne_of_gt h),
|
||||
Semiring.one_mul, Semiring.one_mul] at this
|
||||
· exact (mul_le_mul_of_nonneg_left · (Preorder.le_of_lt h))
|
||||
|
||||
theorem mul_le_mul_iff_of_neg_right {a b c : R} (h : c < 0) : a * c ≤ b * c ↔ b ≤ a := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_le_mul_of_nonpos_right h' (Preorder.le_of_lt (inv_neg_iff.mpr h))
|
||||
rwa [Semiring.mul_assoc, Semiring.mul_assoc, mul_inv_cancel (Preorder.ne_of_lt h),
|
||||
Semiring.mul_one, Semiring.mul_one] at this
|
||||
· exact (mul_le_mul_of_nonpos_right · (Preorder.le_of_lt h))
|
||||
|
||||
theorem mul_le_mul_iff_of_neg_left {a b c : R} (h : c < 0) : c * a ≤ c * b ↔ b ≤ a := by
|
||||
constructor
|
||||
· intro h'
|
||||
have := mul_le_mul_of_nonpos_left h' (Preorder.le_of_lt (inv_neg_iff.mpr h))
|
||||
rwa [← Semiring.mul_assoc, ← Semiring.mul_assoc, inv_mul_cancel (Preorder.ne_of_lt h),
|
||||
Semiring.one_mul, Semiring.one_mul] at this
|
||||
· exact (mul_le_mul_of_nonpos_left · (Preorder.le_of_lt h))
|
||||
|
||||
end Field.IsOrdered
|
||||
|
||||
end Lean.Grind
|
||||
35
src/Init/Grind/Ordered/Int.lean
Normal file
35
src/Init/Grind/Ordered/Int.lean
Normal file
@@ -0,0 +1,35 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.Ordered.Ring
|
||||
import Init.Grind.CommRing.Int
|
||||
import Init.Omega
|
||||
|
||||
/-!
|
||||
# `grind` instances for `Int` as an ordered module.
|
||||
-/
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
instance : Preorder Int where
|
||||
le_refl := Int.le_refl
|
||||
le_trans := Int.le_trans
|
||||
lt_iff_le_not_le := by omega
|
||||
|
||||
instance : IntModule.IsOrdered Int where
|
||||
neg_le_iff := by omega
|
||||
add_le_left := by omega
|
||||
hmul_pos k a ha := ⟨fun hk => Int.mul_pos hk ha, fun h => Int.pos_of_mul_pos_left h ha⟩
|
||||
hmul_nonneg hk ha := Int.mul_nonneg hk ha
|
||||
|
||||
instance : Ring.IsOrdered Int where
|
||||
zero_lt_one := by omega
|
||||
mul_lt_mul_of_pos_left := Int.mul_lt_mul_of_pos_left
|
||||
mul_lt_mul_of_pos_right := Int.mul_lt_mul_of_pos_right
|
||||
|
||||
end Lean.Grind
|
||||
69
src/Init/Grind/Ordered/Module.lean
Normal file
69
src/Init/Grind/Ordered/Module.lean
Normal file
@@ -0,0 +1,69 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.Int.Order
|
||||
import Init.Grind.Module.Basic
|
||||
import Init.Grind.Ordered.Order
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
class IntModule.IsOrdered (M : Type u) [Preorder M] [IntModule M] where
|
||||
neg_le_iff : ∀ a b : M, -a ≤ b ↔ -b ≤ a
|
||||
add_le_left : ∀ {a b : M}, a ≤ b → (c : M) → a + c ≤ b + c
|
||||
hmul_pos : ∀ (k : Int) {a : M}, 0 < a → (0 < k ↔ 0 < k * a)
|
||||
hmul_nonneg : ∀ {k : Int} {a : M}, 0 ≤ k → 0 ≤ a → 0 ≤ k * a
|
||||
|
||||
namespace IntModule.IsOrdered
|
||||
|
||||
variable {M : Type u} [Preorder M] [IntModule M] [IntModule.IsOrdered M]
|
||||
|
||||
theorem le_neg_iff {a b : M} : a ≤ -b ↔ b ≤ -a := by
|
||||
conv => lhs; rw [← neg_neg a]
|
||||
rw [neg_le_iff, neg_neg]
|
||||
|
||||
theorem neg_lt_iff {a b : M} : -a < b ↔ -b < a := by
|
||||
simp [Preorder.lt_iff_le_not_le]
|
||||
rw [neg_le_iff, le_neg_iff]
|
||||
|
||||
theorem lt_neg_iff {a b : M} : a < -b ↔ b < -a := by
|
||||
conv => lhs; rw [← neg_neg a]
|
||||
rw [neg_lt_iff, neg_neg]
|
||||
|
||||
theorem neg_nonneg_iff {a : M} : 0 ≤ -a ↔ a ≤ 0 := by
|
||||
rw [le_neg_iff, neg_zero]
|
||||
|
||||
theorem neg_pos_iff {a : M} : 0 < -a ↔ a < 0 := by
|
||||
rw [lt_neg_iff, neg_zero]
|
||||
|
||||
theorem add_lt_left {a b : M} (h : a < b) (c : M) : a + c < b + c := by
|
||||
simp [Preorder.lt_iff_le_not_le] at h ⊢
|
||||
constructor
|
||||
· exact add_le_left h.1 _
|
||||
· intro w
|
||||
apply h.2
|
||||
replace w := add_le_left w (-c)
|
||||
rw [add_assoc, add_assoc, add_neg_cancel, add_zero, add_zero] at w
|
||||
exact w
|
||||
|
||||
theorem add_le_right (a : M) {b c : M} (h : b ≤ c) : a + b ≤ a + c := by
|
||||
rw [add_comm a b, add_comm a c]
|
||||
exact add_le_left h a
|
||||
|
||||
theorem add_lt_right (a : M) {b c : M} (h : b < c) : a + b < a + c := by
|
||||
rw [add_comm a b, add_comm a c]
|
||||
exact add_lt_left h a
|
||||
|
||||
theorem hmul_neg (k : Int) {a : M} (h : a < 0) : 0 < k ↔ k * a < 0 := by
|
||||
simpa [IntModule.hmul_neg, neg_pos_iff] using hmul_pos k (neg_pos_iff.mpr h)
|
||||
|
||||
theorem hmul_nonpos {k : Int} {a : M} (hk : 0 ≤ k) (ha : a ≤ 0) : k * a ≤ 0 := by
|
||||
simpa [IntModule.hmul_neg, neg_nonneg_iff] using hmul_nonneg hk (neg_nonneg_iff.mpr ha)
|
||||
|
||||
end IntModule.IsOrdered
|
||||
|
||||
end Lean.Grind
|
||||
96
src/Init/Grind/Ordered/Order.lean
Normal file
96
src/Init/Grind/Ordered/Order.lean
Normal file
@@ -0,0 +1,96 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.Int.Order
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
/-- A preorder is a reflexive, transitive relation `≤` with `a < b` defined in the obvious way. -/
|
||||
class Preorder (α : Type u) extends LE α, LT α where
|
||||
le_refl : ∀ a : α, a ≤ a
|
||||
le_trans : ∀ {a b c : α}, a ≤ b → b ≤ c → a ≤ c
|
||||
lt := fun a b => a ≤ b ∧ ¬b ≤ a
|
||||
lt_iff_le_not_le : ∀ {a b : α}, a < b ↔ a ≤ b ∧ ¬b ≤ a := by intros; rfl
|
||||
|
||||
namespace Preorder
|
||||
|
||||
variable {α : Type u} [Preorder α]
|
||||
|
||||
theorem le_of_lt {a b : α} (h : a < b) : a ≤ b := (lt_iff_le_not_le.mp h).1
|
||||
|
||||
theorem lt_of_lt_of_le {a b c : α} (h₁ : a < b) (h₂ : b ≤ c) : a < c := by
|
||||
simp [lt_iff_le_not_le] at h₁ ⊢
|
||||
exact ⟨le_trans h₁.1 h₂, fun h => h₁.2 (le_trans h₂ h)⟩
|
||||
|
||||
theorem lt_of_le_of_lt {a b c : α} (h₁ : a ≤ b) (h₂ : b < c) : a < c := by
|
||||
simp [lt_iff_le_not_le] at h₂ ⊢
|
||||
exact ⟨le_trans h₁ h₂.1, fun h => h₂.2 (le_trans h h₁)⟩
|
||||
|
||||
theorem lt_trans {a b c : α} (h₁ : a < b) (h₂ : b < c) : a < c :=
|
||||
lt_of_lt_of_le h₁ (le_of_lt h₂)
|
||||
|
||||
theorem lt_irrefl (a : α) : ¬ (a < a) := by
|
||||
intro h
|
||||
simp [lt_iff_le_not_le] at h
|
||||
|
||||
theorem ne_of_lt {a b : α} (h : a < b) : a ≠ b :=
|
||||
fun w => lt_irrefl a (w.symm ▸ h)
|
||||
|
||||
theorem ne_of_gt {a b : α} (h : a > b) : a ≠ b :=
|
||||
fun w => lt_irrefl b (w.symm ▸ h)
|
||||
|
||||
theorem not_ge_of_lt {a b : α} (h : a < b) : ¬b ≤ a :=
|
||||
fun w => lt_irrefl a (lt_of_lt_of_le h w)
|
||||
|
||||
theorem not_gt_of_lt {a b : α} (h : a < b) : ¬a > b :=
|
||||
fun w => lt_irrefl a (lt_trans h w)
|
||||
|
||||
end Preorder
|
||||
|
||||
class PartialOrder (α : Type u) extends Preorder α where
|
||||
le_antisymm : ∀ {a b : α}, a ≤ b → b ≤ a → a = b
|
||||
|
||||
namespace PartialOrder
|
||||
|
||||
variable {α : Type u} [PartialOrder α]
|
||||
|
||||
theorem le_iff_lt_or_eq {a b : α} : a ≤ b ↔ a < b ∨ a = b := by
|
||||
constructor
|
||||
· intro h
|
||||
rw [Preorder.lt_iff_le_not_le, Classical.or_iff_not_imp_right]
|
||||
exact fun w => ⟨h, fun w' => w (le_antisymm h w')⟩
|
||||
· intro h
|
||||
cases h with
|
||||
| inl h => exact Preorder.le_of_lt h
|
||||
| inr h => subst h; exact Preorder.le_refl a
|
||||
|
||||
end PartialOrder
|
||||
|
||||
class LinearOrder (α : Type u) extends PartialOrder α where
|
||||
le_total : ∀ a b : α, a ≤ b ∨ b ≤ a
|
||||
|
||||
namespace LinearOrder
|
||||
|
||||
variable {α : Type u} [LinearOrder α]
|
||||
|
||||
theorem trichotomy (a b : α) : a < b ∨ a = b ∨ b < a := by
|
||||
cases LinearOrder.le_total a b with
|
||||
| inl h =>
|
||||
rw [PartialOrder.le_iff_lt_or_eq] at h
|
||||
cases h with
|
||||
| inl h => left; exact h
|
||||
| inr h => right; left; exact h
|
||||
| inr h =>
|
||||
rw [PartialOrder.le_iff_lt_or_eq] at h
|
||||
cases h with
|
||||
| inl h => right; right; exact h
|
||||
| inr h => right; left; exact h.symm
|
||||
|
||||
end LinearOrder
|
||||
|
||||
end Lean.Grind
|
||||
159
src/Init/Grind/Ordered/Ring.lean
Normal file
159
src/Init/Grind/Ordered/Ring.lean
Normal file
@@ -0,0 +1,159 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.CommRing.Basic
|
||||
import Init.Grind.Ordered.Module
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
class Ring.IsOrdered (R : Type u) [Ring R] [Preorder R] extends IntModule.IsOrdered R where
|
||||
/-- In a strict ordered semiring, we have `0 < 1`. -/
|
||||
zero_lt_one : (0 : R) < 1
|
||||
/-- In a strict ordered semiring, we can multiply an inequality `a < b` on the left
|
||||
by a positive element `0 < c` to obtain `c * a < c * b`. -/
|
||||
mul_lt_mul_of_pos_left : ∀ {a b c : R}, a < b → 0 < c → c * a < c * b
|
||||
/-- In a strict ordered semiring, we can multiply an inequality `a < b` on the right
|
||||
by a positive element `0 < c` to obtain `a * c < b * c`. -/
|
||||
mul_lt_mul_of_pos_right : ∀ {a b c : R}, a < b → 0 < c → a * c < b * c
|
||||
|
||||
namespace Ring.IsOrdered
|
||||
|
||||
variable {R : Type u} [Ring R]
|
||||
section PartialOrder
|
||||
|
||||
variable [PartialOrder R] [Ring.IsOrdered R]
|
||||
|
||||
theorem zero_le_one : (0 : R) ≤ 1 := Preorder.le_of_lt zero_lt_one
|
||||
|
||||
theorem not_one_lt_zero : ¬ ((1 : R) < 0) :=
|
||||
fun h => Preorder.lt_irrefl (0 : R) (Preorder.lt_trans zero_lt_one h)
|
||||
|
||||
theorem mul_le_mul_of_nonneg_left {a b c : R} (h : a ≤ b) (h' : 0 ≤ c) : c * a ≤ c * b := by
|
||||
rw [PartialOrder.le_iff_lt_or_eq] at h'
|
||||
cases h' with
|
||||
| inl h' =>
|
||||
have p := mul_lt_mul_of_pos_left (a := a) (b := b) (c := c)
|
||||
rw [PartialOrder.le_iff_lt_or_eq] at h
|
||||
cases h with
|
||||
| inl h => exact Preorder.le_of_lt (p h h')
|
||||
| inr h => subst h; exact Preorder.le_refl (c * a)
|
||||
| inr h' => subst h'; simp [Semiring.zero_mul, Preorder.le_refl]
|
||||
|
||||
theorem mul_le_mul_of_nonneg_right {a b c : R} (h : a ≤ b) (h' : 0 ≤ c) : a * c ≤ b * c := by
|
||||
rw [PartialOrder.le_iff_lt_or_eq] at h'
|
||||
cases h' with
|
||||
| inl h' =>
|
||||
have p := mul_lt_mul_of_pos_right (a := a) (b := b) (c := c)
|
||||
rw [PartialOrder.le_iff_lt_or_eq] at h
|
||||
cases h with
|
||||
| inl h => exact Preorder.le_of_lt (p h h')
|
||||
| inr h => subst h; exact Preorder.le_refl (a * c)
|
||||
| inr h' => subst h'; simp [Semiring.mul_zero, Preorder.le_refl]
|
||||
|
||||
theorem mul_le_mul_of_nonpos_left {a b c : R} (h : a ≤ b) (h' : c ≤ 0) : c * b ≤ c * a := by
|
||||
have := mul_le_mul_of_nonneg_left h (IntModule.IsOrdered.neg_nonneg_iff.mpr h')
|
||||
rwa [Ring.neg_mul, Ring.neg_mul, IntModule.IsOrdered.neg_le_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_le_mul_of_nonpos_right {a b c : R} (h : a ≤ b) (h' : c ≤ 0) : b * c ≤ a * c := by
|
||||
have := mul_le_mul_of_nonneg_right h (IntModule.IsOrdered.neg_nonneg_iff.mpr h')
|
||||
rwa [Ring.mul_neg, Ring.mul_neg, IntModule.IsOrdered.neg_le_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_lt_mul_of_neg_left {a b c : R} (h : a < b) (h' : c < 0) : c * b < c * a := by
|
||||
have := mul_lt_mul_of_pos_left h (IntModule.IsOrdered.neg_pos_iff.mpr h')
|
||||
rwa [Ring.neg_mul, Ring.neg_mul, IntModule.IsOrdered.neg_lt_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_lt_mul_of_neg_right {a b c : R} (h : a < b) (h' : c < 0) : b * c < a * c := by
|
||||
have := mul_lt_mul_of_pos_right h (IntModule.IsOrdered.neg_pos_iff.mpr h')
|
||||
rwa [Ring.mul_neg, Ring.mul_neg, IntModule.IsOrdered.neg_lt_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_nonneg {a b : R} (h₁ : 0 ≤ a) (h₂ : 0 ≤ b) : 0 ≤ a * b := by
|
||||
simpa [Semiring.zero_mul] using mul_le_mul_of_nonneg_right h₁ h₂
|
||||
|
||||
theorem mul_nonneg_of_nonpos_of_nonpos {a b : R} (h₁ : a ≤ 0) (h₂ : b ≤ 0) : 0 ≤ a * b := by
|
||||
have := mul_nonneg (IntModule.IsOrdered.neg_nonneg_iff.mpr h₁) (IntModule.IsOrdered.neg_nonneg_iff.mpr h₂)
|
||||
simpa [Ring.neg_mul, Ring.mul_neg, Ring.neg_neg] using this
|
||||
|
||||
theorem mul_nonpos_of_nonneg_of_nonpos {a b : R} (h₁ : 0 ≤ a) (h₂ : b ≤ 0) : a * b ≤ 0 := by
|
||||
rw [← IntModule.IsOrdered.neg_nonneg_iff, ← Ring.mul_neg]
|
||||
apply mul_nonneg h₁ (IntModule.IsOrdered.neg_nonneg_iff.mpr h₂)
|
||||
|
||||
theorem mul_nonpos_of_nonpos_of_nonneg {a b : R} (h₁ : a ≤ 0) (h₂ : 0 ≤ b) : a * b ≤ 0 := by
|
||||
rw [← IntModule.IsOrdered.neg_nonneg_iff, ← Ring.neg_mul]
|
||||
apply mul_nonneg (IntModule.IsOrdered.neg_nonneg_iff.mpr h₁) h₂
|
||||
|
||||
theorem mul_pos {a b : R} (h₁ : 0 < a) (h₂ : 0 < b) : 0 < a * b := by
|
||||
simpa [Semiring.zero_mul] using mul_lt_mul_of_pos_right h₁ h₂
|
||||
|
||||
theorem mul_pos_of_neg_of_neg {a b : R} (h₁ : a < 0) (h₂ : b < 0) : 0 < a * b := by
|
||||
have := mul_pos (IntModule.IsOrdered.neg_pos_iff.mpr h₁) (IntModule.IsOrdered.neg_pos_iff.mpr h₂)
|
||||
simpa [Ring.neg_mul, Ring.mul_neg, Ring.neg_neg] using this
|
||||
|
||||
theorem mul_neg_of_pos_of_neg {a b : R} (h₁ : 0 < a) (h₂ : b < 0) : a * b < 0 := by
|
||||
rw [← IntModule.IsOrdered.neg_pos_iff, ← Ring.mul_neg]
|
||||
apply mul_pos h₁ (IntModule.IsOrdered.neg_pos_iff.mpr h₂)
|
||||
|
||||
theorem mul_neg_of_neg_of_pos {a b : R} (h₁ : a < 0) (h₂ : 0 < b) : a * b < 0 := by
|
||||
rw [← IntModule.IsOrdered.neg_pos_iff, ← Ring.neg_mul]
|
||||
apply mul_pos (IntModule.IsOrdered.neg_pos_iff.mpr h₁) h₂
|
||||
|
||||
end PartialOrder
|
||||
|
||||
section LinearOrder
|
||||
|
||||
variable [LinearOrder R] [Ring.IsOrdered R]
|
||||
|
||||
theorem mul_nonneg_iff {a b : R} : 0 ≤ a * b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := by
|
||||
rcases LinearOrder.trichotomy 0 a with (ha | rfl | ha)
|
||||
· rcases LinearOrder.trichotomy 0 b with (hb | rfl | hb)
|
||||
· simp [Preorder.le_of_lt ha, Preorder.le_of_lt hb, mul_nonneg]
|
||||
· simp [Semiring.mul_zero, Preorder.le_refl, LinearOrder.le_total]
|
||||
· have m : a * b < 0 := mul_neg_of_pos_of_neg ha hb
|
||||
simp [Preorder.le_of_lt ha, Preorder.le_of_lt hb, Preorder.not_ge_of_lt m,
|
||||
Preorder.not_ge_of_lt ha, Preorder.not_ge_of_lt hb]
|
||||
· simp [Semiring.zero_mul, Preorder.le_refl, LinearOrder.le_total]
|
||||
· rcases LinearOrder.trichotomy 0 b with (hb | rfl | hb)
|
||||
· have m : a * b < 0 := mul_neg_of_neg_of_pos ha hb
|
||||
simp [Preorder.le_of_lt ha, Preorder.le_of_lt hb, Preorder.not_ge_of_lt m,
|
||||
Preorder.not_ge_of_lt ha, Preorder.not_ge_of_lt hb]
|
||||
· simp [Semiring.mul_zero, Preorder.le_refl, LinearOrder.le_total]
|
||||
· simp [Preorder.le_of_lt ha, Preorder.le_of_lt hb, mul_nonneg_of_nonpos_of_nonpos]
|
||||
|
||||
theorem mul_pos_iff {a b : R} : 0 < a * b ↔ 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 := by
|
||||
rcases LinearOrder.trichotomy 0 a with (ha | rfl | ha)
|
||||
· rcases LinearOrder.trichotomy 0 b with (hb | rfl | hb)
|
||||
· simp [ha, hb, mul_pos]
|
||||
· simp [Preorder.lt_irrefl, Semiring.mul_zero]
|
||||
· have m : a * b < 0 := mul_neg_of_pos_of_neg ha hb
|
||||
simp [ha, hb, Preorder.not_gt_of_lt m,
|
||||
Preorder.not_gt_of_lt ha, Preorder.not_gt_of_lt hb]
|
||||
· simp [Preorder.lt_irrefl, Semiring.zero_mul]
|
||||
· rcases LinearOrder.trichotomy 0 b with (hb | rfl | hb)
|
||||
· have m : a * b < 0 := mul_neg_of_neg_of_pos ha hb
|
||||
simp [ha, hb, Preorder.not_gt_of_lt m,
|
||||
Preorder.not_gt_of_lt ha, Preorder.not_gt_of_lt hb]
|
||||
· simp [Preorder.lt_irrefl, Semiring.mul_zero]
|
||||
· simp [ha, hb, mul_pos_of_neg_of_neg]
|
||||
|
||||
theorem sq_nonneg {a : R} : 0 ≤ a^2 := by
|
||||
rw [Semiring.pow_two, mul_nonneg_iff]
|
||||
rcases LinearOrder.le_total 0 a with (h | h)
|
||||
· exact .inl ⟨h, h⟩
|
||||
· exact .inr ⟨h, h⟩
|
||||
|
||||
theorem sq_pos {a : R} (h : a ≠ 0) : 0 < a^2 := by
|
||||
rw [Semiring.pow_two, mul_pos_iff]
|
||||
rcases LinearOrder.trichotomy 0 a with (h' | rfl | h')
|
||||
· exact .inl ⟨h', h'⟩
|
||||
· simp at h
|
||||
· exact .inr ⟨h', h'⟩
|
||||
|
||||
end LinearOrder
|
||||
|
||||
end Ring.IsOrdered
|
||||
|
||||
end Lean.Grind
|
||||
@@ -30,6 +30,7 @@ syntax grindIntro := &"intro "
|
||||
syntax grindExt := &"ext "
|
||||
syntax grindMod := grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd <|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager <|> grindCases <|> grindIntro <|> grindExt
|
||||
syntax (name := grind) "grind" (grindMod)? : attr
|
||||
syntax (name := grind?) "grind?" (grindMod)? : attr
|
||||
end Attr
|
||||
end Lean.Parser
|
||||
|
||||
@@ -67,8 +68,6 @@ structure Config where
|
||||
if the implication is true. Otherwise, it will split only if `p` is an arithmetic predicate.
|
||||
-/
|
||||
splitImp : Bool := false
|
||||
/-- By default, `grind` halts as soon as it encounters a sub-goal where no further progress can be made. -/
|
||||
failures : Nat := 1
|
||||
/-- Maximum number of heartbeats (in thousands) the canonicalizer can spend per definitional equality test. -/
|
||||
canonHeartbeats : Nat := 1000
|
||||
/-- If `ext` is `true`, `grind` uses extensionality theorems that have been marked with `[grind ext]`. -/
|
||||
@@ -98,7 +97,7 @@ structure Config where
|
||||
This approach is cheaper but incomplete. -/
|
||||
qlia : Bool := false
|
||||
/--
|
||||
If `mbtc` is `true`, `grind` will use model-based theory commbination for creating new case splits.
|
||||
If `mbtc` is `true`, `grind` will use model-based theory combination for creating new case splits.
|
||||
See paper "Model-based Theory Combination" for details.
|
||||
-/
|
||||
mbtc : Bool := true
|
||||
|
||||
@@ -877,6 +877,12 @@ instance ImplicationOrder.instCompleteLattice : CompleteLattice ImplicationOrder
|
||||
@monotone _ _ _ ImplicationOrder.instOrder (fun x => (Exists (f x))) :=
|
||||
fun x y hxy ⟨w, hw⟩ => ⟨w, monotone_apply w f h x y hxy hw⟩
|
||||
|
||||
@[partial_fixpoint_monotone] theorem implication_order_monotone_forall
|
||||
{α} [PartialOrder α] {β} (f : α → β → ImplicationOrder)
|
||||
(h : monotone f) :
|
||||
@monotone _ _ _ ImplicationOrder.instOrder (fun x => ∀ y, f x y) :=
|
||||
fun x y hxy h₂ y₁ => monotone_apply y₁ f h x y hxy (h₂ y₁)
|
||||
|
||||
@[partial_fixpoint_monotone] theorem implication_order_monotone_and
|
||||
{α} [PartialOrder α] (f₁ : α → ImplicationOrder) (f₂ : α → ImplicationOrder)
|
||||
(h₁ : @monotone _ _ _ ImplicationOrder.instOrder f₁)
|
||||
@@ -931,6 +937,12 @@ def ReverseImplicationOrder.instCompleteLattice : CompleteLattice ReverseImplica
|
||||
@monotone _ _ _ ReverseImplicationOrder.instOrder (fun x => Exists (f x)) :=
|
||||
fun x y hxy ⟨w, hw⟩ => ⟨w, monotone_apply w f h x y hxy hw⟩
|
||||
|
||||
@[partial_fixpoint_monotone] theorem coind_monotone_forall
|
||||
{α} [PartialOrder α] {β} (f : α → β → ReverseImplicationOrder)
|
||||
(h : monotone f) :
|
||||
@monotone _ _ _ ReverseImplicationOrder.instOrder (fun x => ∀ y, f x y) :=
|
||||
fun x y hxy h₂ y₁ => monotone_apply y₁ f h x y hxy (h₂ y₁)
|
||||
|
||||
@[partial_fixpoint_monotone] theorem coind_monotone_and
|
||||
{α} [PartialOrder α] (f₁ : α → Prop) (f₂ : α → Prop)
|
||||
(h₁ : @monotone _ _ _ ReverseImplicationOrder.instOrder f₁)
|
||||
|
||||
@@ -82,16 +82,13 @@ theorem SeqRight.monotone_seqRight [LawfulMonad m] (f : γ → m α) (g : γ →
|
||||
|
||||
namespace Option
|
||||
|
||||
omit [MonoBind m] in
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_bindM (f : γ → α → m (Option β)) (xs : Option α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.bindM (f x)) := by
|
||||
cases xs with
|
||||
| none => apply monotone_const
|
||||
| some x =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
| some x => apply monotone_apply _ _ hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_mapM [LawfulMonad m] (f : γ → α → m β) (xs : Option α) (hmono : monotone f) :
|
||||
|
||||
@@ -1317,7 +1317,7 @@ test with the predicate `p`. The resulting array contains the tested elements fo
|
||||
`true`, separated by the corresponding separator elements.
|
||||
-/
|
||||
def filterSepElems (a : Array Syntax) (p : Syntax → Bool) : Array Syntax :=
|
||||
Id.run <| a.filterSepElemsM p
|
||||
Id.run <| a.filterSepElemsM (pure <| p ·)
|
||||
|
||||
private partial def mapSepElemsMAux {m : Type → Type} [Monad m] (a : Array Syntax) (f : Syntax → m Syntax) (i : Nat) (acc : Array Syntax) : m (Array Syntax) := do
|
||||
if h : i < a.size then
|
||||
@@ -1334,7 +1334,7 @@ def mapSepElemsM {m : Type → Type} [Monad m] (a : Array Syntax) (f : Syntax
|
||||
mapSepElemsMAux a f 0 #[]
|
||||
|
||||
def mapSepElems (a : Array Syntax) (f : Syntax → Syntax) : Array Syntax :=
|
||||
Id.run <| a.mapSepElemsM f
|
||||
Id.run <| a.mapSepElemsM (pure <| f ·)
|
||||
|
||||
end Array
|
||||
|
||||
|
||||
@@ -244,6 +244,11 @@ structure Config where
|
||||
`let x := v; e` simplifies to `e` when `x` does not occur in `e`.
|
||||
-/
|
||||
zetaUnused : Bool := true
|
||||
/--
|
||||
When `true` (default : `true`), then simps will catch runtime exceptions and
|
||||
convert them into `simp` exceptions.
|
||||
-/
|
||||
catchRuntime : Bool := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
-- Configuration object for `simp_all`
|
||||
|
||||
@@ -295,6 +295,7 @@ recommended_spelling "PProd" for "×'" in [PProd, «term_×'_»]
|
||||
@[inherit_doc] prefix:75 "-" => Neg.neg
|
||||
@[inherit_doc] prefix:100 "~~~" => Complement.complement
|
||||
@[inherit_doc] postfix:max "⁻¹" => Inv.inv
|
||||
@[inherit_doc] infixr:73 " • " => HSMul.hSMul
|
||||
|
||||
/-!
|
||||
Remark: the infix commands above ensure a delaborator is generated for each relations.
|
||||
@@ -312,6 +313,40 @@ macro_rules | `($x % $y) => `(binop% HMod.hMod $x $y)
|
||||
macro_rules | `($x ^ $y) => `(rightact% HPow.hPow $x $y)
|
||||
macro_rules | `($x ++ $y) => `(binop% HAppend.hAppend $x $y)
|
||||
macro_rules | `(- $x) => `(unop% Neg.neg $x)
|
||||
/-!
|
||||
We have a macro to make `x • y` notation participate in the expression tree elaborator,
|
||||
like other arithmetic expressions such as `+`, `*`, `/`, `^`, `=`, inequalities, etc.
|
||||
The macro is using the `leftact%` elaborator introduced in
|
||||
[this RFC](https://github.com/leanprover/lean4/issues/2854).
|
||||
|
||||
As a concrete example of the effect of this macro, consider
|
||||
```lean
|
||||
variable [Ring R] [AddCommMonoid M] [Module R M] (r : R) (N : Submodule R M) (m : M) (n : N)
|
||||
#check m + r • n
|
||||
```
|
||||
Without the macro, the expression would elaborate as `m + ↑(r • n : ↑N) : M`.
|
||||
With the macro, the expression elaborates as `m + r • (↑n : M) : M`.
|
||||
To get the first interpretation, one can write `m + (r • n :)`.
|
||||
|
||||
Here is a quick review of the expression tree elaborator:
|
||||
1. It builds up an expression tree of all the immediately accessible operations
|
||||
that are marked with `binop%`, `unop%`, `leftact%`, `rightact%`, `binrel%`, etc.
|
||||
2. It elaborates every leaf term of this tree
|
||||
(without an expected type, so as if it were temporarily wrapped in `(... :)`).
|
||||
3. Using the types of each elaborated leaf, it computes a supremum type they can all be
|
||||
coerced to, if such a supremum exists.
|
||||
4. It inserts coercions around leaf terms wherever needed.
|
||||
|
||||
The hypothesis is that individual expression trees tend to be calculations with respect
|
||||
to a single algebraic structure.
|
||||
|
||||
Note(kmill): If we were to remove `HSMul` and switch to using `SMul` directly,
|
||||
then the expression tree elaborator would not be able to insert coercions within the right operand;
|
||||
they would likely appear as `↑(x • y)` rather than `x • ↑y`, unlike other arithmetic operations.
|
||||
-/
|
||||
|
||||
@[inherit_doc HSMul.hSMul]
|
||||
macro_rules | `($x • $y) => `(leftact% HSMul.hSMul $x $y)
|
||||
|
||||
recommended_spelling "or" for "|||" in [HOr.hOr, «term_|||_»]
|
||||
recommended_spelling "xor" for "^^^" in [HXor.hXor, «term_^^^_»]
|
||||
@@ -323,6 +358,7 @@ recommended_spelling "mul" for "*" in [HMul.hMul, «term_*_»]
|
||||
recommended_spelling "div" for "/" in [HDiv.hDiv, «term_/_»]
|
||||
recommended_spelling "mod" for "%" in [HMod.hMod, «term_%_»]
|
||||
recommended_spelling "pow" for "^" in [HPow.hPow, «term_^_»]
|
||||
recommended_spelling "smul" for "•" in [HSMul.hSMul, «term_•_»]
|
||||
recommended_spelling "append" for "++" in [HAppend.hAppend, «term_++_»]
|
||||
/-- when used as a unary operator -/
|
||||
recommended_spelling "neg" for "-" in [Neg.neg, «term-_»]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user