mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-20 03:44:10 +00:00
Compare commits
114 Commits
array_perm
...
array_lex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
189070444f | ||
|
|
75772e3009 | ||
|
|
007b20395b | ||
|
|
1b15a0f27c | ||
|
|
0340f904b3 | ||
|
|
791bea027f | ||
|
|
a8d323db33 | ||
|
|
155813a396 | ||
|
|
5c2ef51b44 | ||
|
|
a8656c5812 | ||
|
|
a8dc619f8e | ||
|
|
80fb404a04 | ||
|
|
49ad9d1821 | ||
|
|
a3588d9a70 | ||
|
|
63dea907aa | ||
|
|
195a93c22d | ||
|
|
0c010eb8fb | ||
|
|
474adc8c9e | ||
|
|
6893913683 | ||
|
|
8af9462e9a | ||
|
|
a8a160b091 | ||
|
|
e08d35cea1 | ||
|
|
94641e88cf | ||
|
|
b721c0f540 | ||
|
|
f790b1999f | ||
|
|
6571bc01d7 | ||
|
|
37122c3262 | ||
|
|
280fcc9883 | ||
|
|
19eac5f341 | ||
|
|
aa00725624 | ||
|
|
7530fd6955 | ||
|
|
58ffd15a8f | ||
|
|
bac34c7767 | ||
|
|
db354d2cde | ||
|
|
945abe0065 | ||
|
|
48be424eaa | ||
|
|
58f8e21502 | ||
|
|
a64a17e914 | ||
|
|
b862e2d251 | ||
|
|
8709ca35e9 | ||
|
|
19fb1fb388 | ||
|
|
cb31ddc6ad | ||
|
|
633c825ff3 | ||
|
|
c83ce020bf | ||
|
|
cd909b0a98 | ||
|
|
d27c5afa6e | ||
|
|
938651121f | ||
|
|
a9b6a9a975 | ||
|
|
d5b565e95f | ||
|
|
27c2323ef9 | ||
|
|
17865394d4 | ||
|
|
a805946466 | ||
|
|
8a3a806b1a | ||
|
|
5c333ef969 | ||
|
|
e69bcb0757 | ||
|
|
c5b82e0b16 | ||
|
|
b6177bad9c | ||
|
|
2e11b8ac88 | ||
|
|
ff3d12c8b5 | ||
|
|
520d4b698f | ||
|
|
c7b8c5c6a6 | ||
|
|
3f791933f1 | ||
|
|
63791f0177 | ||
|
|
6abb8aad43 | ||
|
|
4dd182c554 | ||
|
|
762c5758f5 | ||
|
|
6447fda253 | ||
|
|
279f36b4cc | ||
|
|
d2853ecbc4 | ||
|
|
6e60d13084 | ||
|
|
019f8e175f | ||
|
|
c366a291ca | ||
|
|
1400b95ffb | ||
|
|
00c7b85261 | ||
|
|
f6e88e5a05 | ||
|
|
88573c802d | ||
|
|
faf07e58db | ||
|
|
c5181569f9 | ||
|
|
77211029da | ||
|
|
da9a0c4190 | ||
|
|
b9bf94313a | ||
|
|
2a891a3889 | ||
|
|
00718c3959 | ||
|
|
473274f145 | ||
|
|
7b98fbece4 | ||
|
|
24b412ebe3 | ||
|
|
cb600ed9b4 | ||
|
|
57d83c835e | ||
|
|
ce27d49e31 | ||
|
|
8a7889d602 | ||
|
|
69340297be | ||
|
|
222abdd43d | ||
|
|
490be9282e | ||
|
|
cda6d5c67a | ||
|
|
904404303b | ||
|
|
f6bc6b2eb1 | ||
|
|
d9d54c1f99 | ||
|
|
b2336fd980 | ||
|
|
f156f22d7c | ||
|
|
3c348d4526 | ||
|
|
0b8f50f78d | ||
|
|
0d89f0194b | ||
|
|
e157fcbcd1 | ||
|
|
95dbac26cf | ||
|
|
be63c8280e | ||
|
|
6fcf35e930 | ||
|
|
b3e0c9c3fa | ||
|
|
3c5e612dc5 | ||
|
|
29e84fa7ea | ||
|
|
6bf8ff32f0 | ||
|
|
62b8238782 | ||
|
|
0a2a8e8aa4 | ||
|
|
23236ef520 | ||
|
|
b2f70dad52 |
3
.github/workflows/check-prelude.yml
vendored
3
.github/workflows/check-prelude.yml
vendored
@@ -14,6 +14,7 @@ jobs:
|
||||
sparse-checkout: |
|
||||
src/Lean
|
||||
src/Std
|
||||
src/lake/Lake
|
||||
- name: Check Prelude
|
||||
run: |
|
||||
failed_files=""
|
||||
@@ -21,7 +22,7 @@ jobs:
|
||||
if ! grep -q "^prelude$" "$file"; then
|
||||
failed_files="$failed_files$file\n"
|
||||
fi
|
||||
done < <(find src/Lean src/Std -name '*.lean' -print0)
|
||||
done < <(find src/Lean src/Std src/lake/Lake -name '*.lean' -print0)
|
||||
if [ -n "$failed_files" ]; then
|
||||
echo -e "The following files should use 'prelude':\n$failed_files"
|
||||
exit 1
|
||||
|
||||
4
.github/workflows/pr-release.yml
vendored
4
.github/workflows/pr-release.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Download artifact from the previous workflow.
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v6 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
uses: dawidd6/action-download-artifact@v7 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
path: artifacts
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
|
||||
- name: 'Setup jq'
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: dcarbone/install-jq-action@v2.1.0
|
||||
uses: dcarbone/install-jq-action@v3.0.1
|
||||
|
||||
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD
|
||||
|
||||
14
.gitpod.Dockerfile
vendored
Normal file
14
.gitpod.Dockerfile
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# You can find the new timestamped tags here: https://hub.docker.com/r/gitpod/workspace-full/tags
|
||||
FROM gitpod/workspace-full
|
||||
|
||||
USER root
|
||||
RUN apt-get update && apt-get install git libgmp-dev libuv1-dev cmake ccache clang -y && apt-get clean
|
||||
|
||||
USER gitpod
|
||||
|
||||
# Install and configure elan
|
||||
RUN curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh -s -- -y --default-toolchain none
|
||||
ENV PATH="/home/gitpod/.elan/bin:${PATH}"
|
||||
# Create a dummy toolchain so that we can pre-register it with elan
|
||||
RUN mkdir -p /workspace/lean4/build/release/stage1/bin && touch /workspace/lean4/build/release/stage1/bin/lean && elan toolchain link lean4 /workspace/lean4/build/release/stage1
|
||||
RUN mkdir -p /workspace/lean4/build/release/stage0/bin && touch /workspace/lean4/build/release/stage0/bin/lean && elan toolchain link lean4-stage0 /workspace/lean4/build/release/stage0
|
||||
11
.gitpod.yml
Normal file
11
.gitpod.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- leanprover.lean4
|
||||
|
||||
tasks:
|
||||
- name: Release build
|
||||
init: cmake --preset release
|
||||
command: make -C build/release -j$(nproc || sysctl -n hw.logicalcpu)
|
||||
@@ -4,7 +4,7 @@
|
||||
# Listed persons will automatically be asked by GitHub to review a PR touching these paths.
|
||||
# If multiple names are listed, a review by any of them is considered sufficient by default.
|
||||
|
||||
/.github/ @Kha @kim-em
|
||||
/.github/ @kim-em
|
||||
/RELEASES.md @kim-em
|
||||
/src/kernel/ @leodemoura
|
||||
/src/lake/ @tydeu
|
||||
@@ -14,9 +14,7 @@
|
||||
/src/Lean/Elab/Tactic/ @kim-em
|
||||
/src/Lean/Language/ @Kha
|
||||
/src/Lean/Meta/Tactic/ @leodemoura
|
||||
/src/Lean/Parser/ @Kha
|
||||
/src/Lean/PrettyPrinter/ @Kha
|
||||
/src/Lean/PrettyPrinter/Delaborator/ @kmill
|
||||
/src/Lean/PrettyPrinter/ @kmill
|
||||
/src/Lean/Server/ @mhuisi
|
||||
/src/Lean/Widget/ @Vtec234
|
||||
/src/Init/Data/ @kim-em
|
||||
|
||||
290
RELEASES.md
290
RELEASES.md
@@ -8,15 +8,299 @@ This file contains work-in-progress notes for the upcoming release, as well as p
|
||||
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status
|
||||
of each version.
|
||||
|
||||
v4.15.0
|
||||
v4.16.0
|
||||
----------
|
||||
|
||||
Development in progress.
|
||||
|
||||
v4.15.0
|
||||
----------
|
||||
|
||||
Release candidate, release notes will be copied from the branch `releases/v4.15.0` once completed.
|
||||
|
||||
v4.14.0
|
||||
----------
|
||||
|
||||
Release candidate, release notes will be copied from the branch `releases/v4.14.0` once completed.
|
||||
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.13.0...v4.14.0
|
||||
|
||||
### Language features, tactics, and metaprograms
|
||||
|
||||
* `structure` and `inductive` commands
|
||||
* [#5517](https://github.com/leanprover/lean4/pull/5517) improves universe level inference for the resulting type of an `inductive` or `structure.` Recall that a `Prop`-valued inductive type is a syntactic subsingleton if it has at most one constructor and all the arguments to the constructor are in `Prop`. Such types have large elimination, so they could be defined in `Type` or `Prop` without any trouble. The way inference has changed is that if a type is a syntactic subsingleton with exactly one constructor, and the constructor has at least one parameter/field, then the `inductive`/`structure` command will prefer creating a `Prop` instead of a `Type`. The upshot is that the `: Prop` in `structure S : Prop` is often no longer needed. (With @arthur-adjedj).
|
||||
* [#5842](https://github.com/leanprover/lean4/pull/5842) and [#5783](https://github.com/leanprover/lean4/pull/5783) implement a feature where the `structure` command can now define recursive inductive types:
|
||||
```lean
|
||||
structure Tree where
|
||||
n : Nat
|
||||
children : Fin n → Tree
|
||||
|
||||
def Tree.size : Tree → Nat
|
||||
| {n, children} => Id.run do
|
||||
let mut s := 0
|
||||
for h : i in [0 : n] do
|
||||
s := s + (children ⟨i, h.2⟩).size
|
||||
pure s
|
||||
```
|
||||
* [#5814](https://github.com/leanprover/lean4/pull/5814) fixes a bug where Mathlib's `Type*` elaborator could lead to incorrect universe parameters with the `inductive` command.
|
||||
* [#3152](https://github.com/leanprover/lean4/pull/3152) and [#5844](https://github.com/leanprover/lean4/pull/5844) fix bugs in default value processing for structure instance notation (with @arthur-adjedj).
|
||||
* [#5399](https://github.com/leanprover/lean4/pull/5399) promotes instance synthesis order calculation failure from a soft error to a hard error.
|
||||
* [#5542](https://github.com/leanprover/lean4/pull/5542) deprecates `:=` variants of `inductive` and `structure` (see breaking changes).
|
||||
|
||||
* **Application elaboration improvements**
|
||||
* [#5671](https://github.com/leanprover/lean4/pull/5671) makes `@[elab_as_elim]` require at least one discriminant, since otherwise there is no advantage to this alternative elaborator.
|
||||
* [#5528](https://github.com/leanprover/lean4/pull/5528) enables field notation in explicit mode. The syntax `@x.f` elaborates as `@S.f` with `x` supplied to the appropriate parameter.
|
||||
* [#5692](https://github.com/leanprover/lean4/pull/5692) modifies the dot notation resolution algorithm so that it can apply `CoeFun` instances. For example, Mathlib has `Multiset.card : Multiset α →+ Nat`, and now with `m : Multiset α`, the notation `m.card` resolves to `⇑Multiset.card m`.
|
||||
* [#5658](https://github.com/leanprover/lean4/pull/5658) fixes a bug where 'don't know how to synthesize implicit argument' errors might have the incorrect local context when the eta arguments feature is activated.
|
||||
* [#5933](https://github.com/leanprover/lean4/pull/5933) fixes a bug where `..` ellipses in patterns made use of optparams and autoparams.
|
||||
* [#5770](https://github.com/leanprover/lean4/pull/5770) makes dot notation for structures resolve using *all* ancestors. Adds a *resolution order* for generalized field notation. This is the order of namespaces visited during resolution when trying to resolve names. The algorithm to compute a resolution order is the commonly used C3 linearization (used for example by Python), which when successful ensures that immediate parents' namespaces are considered before more distant ancestors' namespaces. By default we use a relaxed version of the algorithm that tolerates inconsistencies, but using `set_option structure.strictResolutionOrder true` makes inconsistent parent orderings into warnings.
|
||||
|
||||
* **Recursion and induction principles**
|
||||
* [#5619](https://github.com/leanprover/lean4/pull/5619) fixes functional induction principle generation to avoid over-eta-expanding in the preprocessing step.
|
||||
* [#5766](https://github.com/leanprover/lean4/pull/5766) fixes structural nested recursion so that it is not confused when a nested type appears first.
|
||||
* [#5803](https://github.com/leanprover/lean4/pull/5803) fixes a bug in functional induction principle generation when there are `let` bindings.
|
||||
* [#5904](https://github.com/leanprover/lean4/pull/5904) improves functional induction principle generation to unfold aux definitions more carefully.
|
||||
* [#5850](https://github.com/leanprover/lean4/pull/5850) refactors code for `Predefinition.Structural`.
|
||||
|
||||
* **Error messages**
|
||||
* [#5276](https://github.com/leanprover/lean4/pull/5276) fixes a bug in "type mismatch" errors that would structurally assign metavariables during the algorithm to expose differences.
|
||||
* [#5919](https://github.com/leanprover/lean4/pull/5919) makes "type mismatch" errors add type ascriptions to expose differences for numeric literals.
|
||||
* [#5922](https://github.com/leanprover/lean4/pull/5922) makes "type mismatch" errors expose differences in the bodies of functions and pi types.
|
||||
* [#5888](https://github.com/leanprover/lean4/pull/5888) improves the error message for invalid induction alternative names in `match` expressions (@josojo).
|
||||
* [#5719](https://github.com/leanprover/lean4/pull/5719) improves `calc` error messages.
|
||||
|
||||
* [#5627](https://github.com/leanprover/lean4/pull/5627) and [#5663](https://github.com/leanprover/lean4/pull/5663) improve the **`#eval` command** and introduce some new features.
|
||||
* Now results can be pretty printed if there is a `ToExpr` instance, which means **hoverable output**. If `ToExpr` fails, it then tries looking for a `Repr` or `ToString` instance like before. Setting `set_option eval.pp false` disables making use of `ToExpr` instances.
|
||||
* There is now **auto-derivation** of `Repr` instances, enabled with the `pp.derive.repr` option (default to **true**). For example:
|
||||
```lean
|
||||
inductive Baz
|
||||
| a | b
|
||||
|
||||
#eval Baz.a
|
||||
-- Baz.a
|
||||
```
|
||||
It simply does `deriving instance Repr for Baz` when there's no way to represent `Baz`.
|
||||
* The option `eval.type` controls whether or not to include the type in the output. For now the default is false.
|
||||
* Now expressions such as `#eval do return 2`, where monad is unknown, work. It tries unifying the monad with `CommandElabM`, `TermElabM`, or `IO`.
|
||||
* The classes `Lean.Eval` and `Lean.MetaEval` have been removed. These each used to be responsible for adapting monads and printing results. Now the `MonadEval` class is responsible for adapting monads for evaluation (it is similar to `MonadLift`, but instances are allowed to use default data when initializing state), and representing results is handled through a separate process.
|
||||
* Error messages about failed instance synthesis are now more precise. Once it detects that a `MonadEval` class applies, then the error message will be specific about missing `ToExpr`/`Repr`/`ToString` instances.
|
||||
* Fixes bugs where evaluating `MetaM` and `CoreM` wouldn't collect log messages.
|
||||
* Fixes a bug where `let rec` could not be used in `#eval`.
|
||||
|
||||
* `partial` definitions
|
||||
* [#5780](https://github.com/leanprover/lean4/pull/5780) improves the error message when `partial` fails to prove a type is inhabited. Add delta deriving.
|
||||
* [#5821](https://github.com/leanprover/lean4/pull/5821) gives `partial` inhabitation the ability to create local `Inhabited` instances from parameters.
|
||||
|
||||
* **New tactic configuration syntax.** The configuration syntax for all core tactics has been given an upgrade. Rather than `simp (config := { contextual := true, maxSteps := 22})`, one can now write `simp +contextual (maxSteps := 22)`. Tactic authors can migrate by switching from `(config)?` to `optConfig` in tactic syntaxes and potentially deleting `mkOptionalNode` in elaborators. [#5883](https://github.com/leanprover/lean4/pull/5883), [#5898](https://github.com/leanprover/lean4/pull/5898), [#5928](https://github.com/leanprover/lean4/pull/5928), and [#5932](https://github.com/leanprover/lean4/pull/5932). (Tactic authors, see breaking changes.)
|
||||
|
||||
* `simp` tactic
|
||||
* [#5632](https://github.com/leanprover/lean4/pull/5632) fixes the simpproc for `Fin` literals to reduce more consistently.
|
||||
* [#5648](https://github.com/leanprover/lean4/pull/5648) fixes a bug in `simpa ... using t` where metavariables in `t` were not properly accounted for, and also improves the type mismatch error.
|
||||
* [#5838](https://github.com/leanprover/lean4/pull/5838) fixes the docstring of `simp!` to actually talk about `simp!`.
|
||||
* [#5870](https://github.com/leanprover/lean4/pull/5870) adds support for `attribute [simp ←]` (note the reverse direction). This adds the reverse of a theorem as a global simp theorem.
|
||||
|
||||
* `decide` tactic
|
||||
* [#5665](https://github.com/leanprover/lean4/pull/5665) adds `decide!` tactic for using kernel reduction (warning: this is renamed to `decide +kernel` in a future release).
|
||||
|
||||
* `bv_decide` tactic
|
||||
* [#5714](https://github.com/leanprover/lean4/pull/5714) adds inequality regression tests (@alexkeizer).
|
||||
* [#5608](https://github.com/leanprover/lean4/pull/5608) adds `bv_toNat` tag for `toNat_ofInt` (@bollu).
|
||||
* [#5618](https://github.com/leanprover/lean4/pull/5618) adds support for `at` in `ac_nf` and uses it in `bv_normalize` (@tobiasgrosser).
|
||||
* [#5628](https://github.com/leanprover/lean4/pull/5628) adds udiv support.
|
||||
* [#5635](https://github.com/leanprover/lean4/pull/5635) adds auxiliary bitblasters for negation and subtraction.
|
||||
* [#5637](https://github.com/leanprover/lean4/pull/5637) adds more `getLsbD` bitblaster theory.
|
||||
* [#5652](https://github.com/leanprover/lean4/pull/5652) adds umod support.
|
||||
* [#5653](https://github.com/leanprover/lean4/pull/5653) adds performance benchmark for modulo.
|
||||
* [#5655](https://github.com/leanprover/lean4/pull/5655) reduces error on `bv_check` to warning.
|
||||
* [#5670](https://github.com/leanprover/lean4/pull/5670) adds `~~~(-x)` support.
|
||||
* [#5673](https://github.com/leanprover/lean4/pull/5673) disables `ac_nf` by default.
|
||||
* [#5675](https://github.com/leanprover/lean4/pull/5675) fixes context tracking in `bv_decide` counter example.
|
||||
* [#5676](https://github.com/leanprover/lean4/pull/5676) adds an error when the LRAT proof is invalid.
|
||||
* [#5781](https://github.com/leanprover/lean4/pull/5781) introduces uninterpreted symbols everywhere.
|
||||
* [#5823](https://github.com/leanprover/lean4/pull/5823) adds `BitVec.sdiv` support.
|
||||
* [#5852](https://github.com/leanprover/lean4/pull/5852) adds `BitVec.ofBool` support.
|
||||
* [#5855](https://github.com/leanprover/lean4/pull/5855) adds `if` support.
|
||||
* [#5869](https://github.com/leanprover/lean4/pull/5869) adds support for all the SMTLIB BitVec divison/remainder operations.
|
||||
* [#5886](https://github.com/leanprover/lean4/pull/5886) adds embedded constraint substitution.
|
||||
* [#5918](https://github.com/leanprover/lean4/pull/5918) fixes loose mvars bug in `bv_normalize`.
|
||||
* Documentation:
|
||||
* [#5636](https://github.com/leanprover/lean4/pull/5636) adds remarks about multiplication.
|
||||
|
||||
* `conv` mode
|
||||
* [#5861](https://github.com/leanprover/lean4/pull/5861) improves the `congr` conv tactic to handle "over-applied" functions.
|
||||
* [#5894](https://github.com/leanprover/lean4/pull/5894) improves the `arg` conv tactic so that it can access more arguments and so that it can handle "over-applied" functions (it generates a specialized congruence lemma for the specific argument in question). Makes `arg 1` and `arg 2` apply to pi types in more situations. Adds negative indexing, for example `arg -2` is equivalent to the `lhs` tactic. Makes the `enter [...]` tactic show intermediate states like `rw`.
|
||||
|
||||
* **Other tactics**
|
||||
* [#4846](https://github.com/leanprover/lean4/pull/4846) fixes a bug where `generalize ... at *` would apply to implementation details (@ymherklotz).
|
||||
* [#5730](https://github.com/leanprover/lean4/pull/5730) upstreams the `classical` tactic combinator.
|
||||
* [#5815](https://github.com/leanprover/lean4/pull/5815) improves the error message when trying to unfold a local hypothesis that is not a local definition.
|
||||
* [#5862](https://github.com/leanprover/lean4/pull/5862) and [#5863](https://github.com/leanprover/lean4/pull/5863) change how `apply` and `simp` elaborate, making them not disable error recovery. This improves hovers and completions when the term has elaboration errors.
|
||||
|
||||
* `deriving` clauses
|
||||
* [#5899](https://github.com/leanprover/lean4/pull/5899) adds declaration ranges for delta-derived instances.
|
||||
* [#5265](https://github.com/leanprover/lean4/pull/5265) removes unused syntax in `deriving` clauses for providing arguments to deriving handlers (see breaking changes).
|
||||
|
||||
* [#5065](https://github.com/leanprover/lean4/pull/5065) upstreams and updates `#where`, a command that reports the current scope information.
|
||||
|
||||
* **Linters**
|
||||
* [#5338](https://github.com/leanprover/lean4/pull/5338) makes the unused variables linter ignore variables defined in tactics by default now, avoiding performance bottlenecks.
|
||||
* [#5644](https://github.com/leanprover/lean4/pull/5644) ensures that linters in general do not run on `#guard_msgs` itself.
|
||||
|
||||
* **Metaprogramming interface**
|
||||
* [#5720](https://github.com/leanprover/lean4/pull/5720) adds `pushGoal`/`pushGoals` and `popGoal` for manipulating the goal state. These are an alternative to `replaceMainGoal` and `getMainGoal`, and with them you don't need to worry about making sure nothing clears assigned metavariables from the goal list between assigning the main goal and using `replaceMainGoal`. Modifies `closeMainGoalUsing`, which is like a `TacticM` version of `liftMetaTactic`. Now the callback is run in a context where the main goal is removed from the goal list, and the callback is free to modify the goal list. Furthermore, the `checkUnassigned` argument has been replaced with `checkNewUnassigned`, which checks whether the value assigned to the goal has any *new* metavariables, relative to the start of execution of the callback. Modifies `withCollectingNewGoalsFrom` to take the `parentTag` argument explicitly rather than indirectly via `getMainTag`. Modifies `elabTermWithHoles` to optionally take `parentTag?`.
|
||||
* [#5563](https://github.com/leanprover/lean4/pull/5563) fixes `getFunInfo` and `inferType` to use `withAtLeastTransparency` rather than `withTransparency`.
|
||||
* [#5679](https://github.com/leanprover/lean4/pull/5679) fixes `RecursorVal.getInduct` to return the name of major argument’s type. This makes "structure eta" work for nested inductives.
|
||||
* [#5681](https://github.com/leanprover/lean4/pull/5681) removes unused `mkRecursorInfoForKernelRec`.
|
||||
* [#5686](https://github.com/leanprover/lean4/pull/5686) makes discrimination trees index the domains of foralls, for better performance of the simplify and type class search.
|
||||
* [#5760](https://github.com/leanprover/lean4/pull/5760) adds `Lean.Expr.name?` recognizer for `Name` expressions.
|
||||
* [#5800](https://github.com/leanprover/lean4/pull/5800) modifies `liftCommandElabM` to preserve more state, fixing an issue where using it would drop messages.
|
||||
* [#5857](https://github.com/leanprover/lean4/pull/5857) makes it possible to use dot notation in `m!` strings, for example `m!"{.ofConstName n}"`.
|
||||
* [#5841](https://github.com/leanprover/lean4/pull/5841) and [#5853](https://github.com/leanprover/lean4/pull/5853) record the complete list of `structure` parents in the `StructureInfo` environment extension.
|
||||
|
||||
* **Other fixes or improvements**
|
||||
* [#5566](https://github.com/leanprover/lean4/pull/5566) fixes a bug introduced in [#4781](https://github.com/leanprover/lean4/pull/4781) where heartbeat exceptions were no longer being handled properly. Now such exceptions are tagged with `runtime.maxHeartbeats` (@eric-wieser).
|
||||
* [#5708](https://github.com/leanprover/lean4/pull/5708) modifies the proof objects produced by the proof-by-reflection tactics `ac_nf0` and `simp_arith` so that the kernel is less prone to reducing expensive atoms.
|
||||
* [#5768](https://github.com/leanprover/lean4/pull/5768) adds a `#version` command that prints Lean's version information.
|
||||
* [#5822](https://github.com/leanprover/lean4/pull/5822) fixes elaborator algorithms to match kernel algorithms for primitive projections (`Expr.proj`).
|
||||
* [#5811](https://github.com/leanprover/lean4/pull/5811) improves the docstring for the `rwa` tactic.
|
||||
|
||||
|
||||
### Language server, widgets, and IDE extensions
|
||||
|
||||
* [#5224](https://github.com/leanprover/lean4/pull/5224) fixes `WorkspaceClientCapabilities` to make `applyEdit` optional, in accordance with the LSP specification (@pzread).
|
||||
* [#5340](https://github.com/leanprover/lean4/pull/5340) fixes a server deadlock when shutting down the language server and a desync between client and language server after a file worker crash.
|
||||
* [#5560](https://github.com/leanprover/lean4/pull/5560) makes `initialize` and `builtin_initialize` participate in the call hierarchy and other requests.
|
||||
* [#5650](https://github.com/leanprover/lean4/pull/5650) makes references in attributes participate in the call hierarchy and other requests.
|
||||
* [#5666](https://github.com/leanprover/lean4/pull/5666) add auto-completion in tactic blocks without having to type the first character of the tactic, and adds tactic completion docs to tactic auto-completion items.
|
||||
* [#5677](https://github.com/leanprover/lean4/pull/5677) fixes several cases where goal states were not displayed in certain text cursor positions.
|
||||
* [#5707](https://github.com/leanprover/lean4/pull/5707) indicates deprecations in auto-completion items.
|
||||
* [#5736](https://github.com/leanprover/lean4/pull/5736), [#5752](https://github.com/leanprover/lean4/pull/5752), [#5763](https://github.com/leanprover/lean4/pull/5763), [#5802](https://github.com/leanprover/lean4/pull/5802), and [#5805](https://github.com/leanprover/lean4/pull/5805) fix various performance issues in the language server.
|
||||
* [#5801](https://github.com/leanprover/lean4/pull/5801) distinguishes theorem auto-completions from non-theorem auto-completions.
|
||||
|
||||
### Pretty printing
|
||||
|
||||
* [#5640](https://github.com/leanprover/lean4/pull/5640) fixes a bug where goal states in messages might print newlines as spaces.
|
||||
* [#5643](https://github.com/leanprover/lean4/pull/5643) adds option `pp.mvars.delayed` (default false), which when false causes delayed assignment metavariables to pretty print with what they are assigned to. Now `fun x : Nat => ?a` pretty prints as `fun x : Nat => ?a` rather than `fun x ↦ ?m.7 x`.
|
||||
* [#5711](https://github.com/leanprover/lean4/pull/5711) adds options `pp.mvars.anonymous` and `pp.mvars.levels`, which when false respectively cause expression metavariables and level metavariables to pretty print as `?_`.
|
||||
* [#5710](https://github.com/leanprover/lean4/pull/5710) adjusts the `⋯` elaboration warning to mention `pp.maxSteps`.
|
||||
|
||||
* [#5759](https://github.com/leanprover/lean4/pull/5759) fixes the app unexpander for `sorryAx`.
|
||||
* [#5827](https://github.com/leanprover/lean4/pull/5827) improves accuracy of binder names in the signature pretty printer (like in output of `#check`). Also fixes the issue where consecutive hygienic names pretty print without a space separating them, so we now have `(x✝ y✝ : Nat)` rather than `(x✝y✝ : Nat)`.
|
||||
* [#5830](https://github.com/leanprover/lean4/pull/5830) makes sure all the core delaborators respond to `pp.explicit` when appropriate.
|
||||
* [#5639](https://github.com/leanprover/lean4/pull/5639) makes sure name literals use escaping when pretty printing.
|
||||
* [#5854](https://github.com/leanprover/lean4/pull/5854) adds delaborators for `<|>`, `<*>`, `>>`, `<*`, and `*>`.
|
||||
|
||||
### Library
|
||||
|
||||
* `Array`
|
||||
* [#5687](https://github.com/leanprover/lean4/pull/5687) deprecates `Array.data`.
|
||||
* [#5705](https://github.com/leanprover/lean4/pull/5705) uses a better default value for `Array.swapAt!`.
|
||||
* [#5748](https://github.com/leanprover/lean4/pull/5748) moves `Array.mapIdx` lemmas to a new file.
|
||||
* [#5749](https://github.com/leanprover/lean4/pull/5749) simplifies signature of `Array.mapIdx`.
|
||||
* [#5758](https://github.com/leanprover/lean4/pull/5758) upstreams `Array.reduceOption`.
|
||||
* [#5786](https://github.com/leanprover/lean4/pull/5786) adds simp lemmas for `Array.isEqv` and `BEq`.
|
||||
* [#5796](https://github.com/leanprover/lean4/pull/5796) renames `Array.shrink` to `Array.take`, and relates it to `List.take`.
|
||||
* [#5798](https://github.com/leanprover/lean4/pull/5798) upstreams `List.modify`, adds lemmas, relates to `Array.modify`.
|
||||
* [#5799](https://github.com/leanprover/lean4/pull/5799) relates `Array.forIn` and `List.forIn`.
|
||||
* [#5833](https://github.com/leanprover/lean4/pull/5833) adds `Array.forIn'`, and relates to `List`.
|
||||
* [#5848](https://github.com/leanprover/lean4/pull/5848) fixes deprecations in `Init.Data.Array.Basic` to not recommend the deprecated constant.
|
||||
* [#5895](https://github.com/leanprover/lean4/pull/5895) adds `LawfulBEq (Array α) ↔ LawfulBEq α`.
|
||||
* [#5896](https://github.com/leanprover/lean4/pull/5896) moves `@[simp]` from `back_eq_back?` to `back_push`.
|
||||
* [#5897](https://github.com/leanprover/lean4/pull/5897) renames `Array.back` to `back!`.
|
||||
|
||||
* `List`
|
||||
* [#5605](https://github.com/leanprover/lean4/pull/5605) removes `List.redLength`.
|
||||
* [#5696](https://github.com/leanprover/lean4/pull/5696) upstreams `List.mapIdx` and adds lemmas.
|
||||
* [#5697](https://github.com/leanprover/lean4/pull/5697) upstreams `List.foldxM_map`.
|
||||
* [#5701](https://github.com/leanprover/lean4/pull/5701) renames `List.join` to `List.flatten`.
|
||||
* [#5703](https://github.com/leanprover/lean4/pull/5703) upstreams `List.sum`.
|
||||
* [#5706](https://github.com/leanprover/lean4/pull/5706) marks `prefix_append_right_inj` as a simp lemma.
|
||||
* [#5716](https://github.com/leanprover/lean4/pull/5716) fixes `List.drop_drop` addition order.
|
||||
* [#5731](https://github.com/leanprover/lean4/pull/5731) renames `List.bind` and `Array.concatMap` to `flatMap`.
|
||||
* [#5732](https://github.com/leanprover/lean4/pull/5732) renames `List.pure` to `List.singleton`.
|
||||
* [#5742](https://github.com/leanprover/lean4/pull/5742) upstreams `ne_of_mem_of_not_mem`.
|
||||
* [#5743](https://github.com/leanprover/lean4/pull/5743) upstreams `ne_of_apply_ne`.
|
||||
* [#5816](https://github.com/leanprover/lean4/pull/5816) adds more `List.modify` lemmas.
|
||||
* [#5879](https://github.com/leanprover/lean4/pull/5879) renames `List.groupBy` to `splitBy`.
|
||||
* [#5913](https://github.com/leanprover/lean4/pull/5913) relates `for` loops over `List` with `foldlM`.
|
||||
|
||||
* `Nat`
|
||||
* [#5694](https://github.com/leanprover/lean4/pull/5694) removes `instBEqNat`, which is redundant with `instBEqOfDecidableEq` but not defeq.
|
||||
* [#5746](https://github.com/leanprover/lean4/pull/5746) deprecates `Nat.sum`.
|
||||
* [#5785](https://github.com/leanprover/lean4/pull/5785) adds `Nat.forall_lt_succ` and variants.
|
||||
|
||||
* Fixed width integers
|
||||
* [#5323](https://github.com/leanprover/lean4/pull/5323) redefine unsigned fixed width integers in terms of `BitVec`.
|
||||
* [#5735](https://github.com/leanprover/lean4/pull/5735) adds `UIntX.[val_ofNat, toBitVec_ofNat]`.
|
||||
* [#5790](https://github.com/leanprover/lean4/pull/5790) defines `Int8`.
|
||||
* [#5901](https://github.com/leanprover/lean4/pull/5901) removes native code for `UInt8.modn`.
|
||||
|
||||
* `BitVec`
|
||||
* [#5604](https://github.com/leanprover/lean4/pull/5604) completes `BitVec.[getMsbD|getLsbD|msb]` for shifts (@luisacicolini).
|
||||
* [#5609](https://github.com/leanprover/lean4/pull/5609) adds lemmas for division when denominator is zero (@bollu).
|
||||
* [#5620](https://github.com/leanprover/lean4/pull/5620) documents Bitblasting (@bollu)
|
||||
* [#5623](https://github.com/leanprover/lean4/pull/5623) moves `BitVec.udiv/umod/sdiv/smod` after `add/sub/mul/lt` (@tobiasgrosser).
|
||||
* [#5645](https://github.com/leanprover/lean4/pull/5645) defines `udiv` normal form to be `/`, resp. `umod` and `%` (@bollu).
|
||||
* [#5646](https://github.com/leanprover/lean4/pull/5646) adds lemmas about arithmetic inequalities (@bollu).
|
||||
* [#5680](https://github.com/leanprover/lean4/pull/5680) expands relationship with `toFin` (@tobiasgrosser).
|
||||
* [#5691](https://github.com/leanprover/lean4/pull/5691) adds `BitVec.(getMSbD, msb)_(add, sub)` and `BitVec.getLsbD_sub` (@luisacicolini).
|
||||
* [#5712](https://github.com/leanprover/lean4/pull/5712) adds `BitVec.[udiv|umod]_[zero|one|self]` (@tobiasgrosser).
|
||||
* [#5718](https://github.com/leanprover/lean4/pull/5718) adds `BitVec.sdiv_[zero|one|self]` (@tobiasgrosser).
|
||||
* [#5721](https://github.com/leanprover/lean4/pull/5721) adds `BitVec.(msb, getMsbD, getLsbD)_(neg, abs)` (@luisacicolini).
|
||||
* [#5772](https://github.com/leanprover/lean4/pull/5772) adds `BitVec.toInt_sub`, simplifies `BitVec.toInt_neg` (@tobiasgrosser).
|
||||
* [#5778](https://github.com/leanprover/lean4/pull/5778) prove that `intMin` the smallest signed bitvector (@alexkeizer).
|
||||
* [#5851](https://github.com/leanprover/lean4/pull/5851) adds `(msb, getMsbD)_twoPow` (@luisacicolini).
|
||||
* [#5858](https://github.com/leanprover/lean4/pull/5858) adds `BitVec.[zero_ushiftRight|zero_sshiftRight|zero_mul]` and cleans up BVDecide (@tobiasgrosser).
|
||||
* [#5865](https://github.com/leanprover/lean4/pull/5865) adds `BitVec.(msb, getMsbD)_concat` (@luisacicolini).
|
||||
* [#5881](https://github.com/leanprover/lean4/pull/5881) adds `Hashable (BitVec n)`
|
||||
|
||||
* `String`/`Char`
|
||||
* [#5728](https://github.com/leanprover/lean4/pull/5728) upstreams `String.dropPrefix?`.
|
||||
* [#5745](https://github.com/leanprover/lean4/pull/5745) changes `String.dropPrefix?` signature.
|
||||
* [#5747](https://github.com/leanprover/lean4/pull/5747) adds `Hashable Char` instance
|
||||
|
||||
* `HashMap`
|
||||
* [#5880](https://github.com/leanprover/lean4/pull/5880) adds interim implementation of `HashMap.modify`/`alter`
|
||||
|
||||
* **Other**
|
||||
* [#5704](https://github.com/leanprover/lean4/pull/5704) removes `@[simp]` from `Option.isSome_eq_isSome`.
|
||||
* [#5739](https://github.com/leanprover/lean4/pull/5739) upstreams material on `Prod`.
|
||||
* [#5740](https://github.com/leanprover/lean4/pull/5740) moves `Antisymm` to `Std.Antisymm`.
|
||||
* [#5741](https://github.com/leanprover/lean4/pull/5741) upstreams basic material on `Sum`.
|
||||
* [#5756](https://github.com/leanprover/lean4/pull/5756) adds `Nat.log2_two_pow` (@spinylobster).
|
||||
* [#5892](https://github.com/leanprover/lean4/pull/5892) removes duplicated `ForIn` instances.
|
||||
* [#5900](https://github.com/leanprover/lean4/pull/5900) removes `@[simp]` from `Sum.forall` and `Sum.exists`.
|
||||
* [#5812](https://github.com/leanprover/lean4/pull/5812) removes redundant `Decidable` assumptions (@FR-vdash-bot).
|
||||
|
||||
### Compiler, runtime, and FFI
|
||||
|
||||
* [#5685](https://github.com/leanprover/lean4/pull/5685) fixes help message flags, removes the `-f` flag and adds the `-g` flag (@James-Oswald).
|
||||
* [#5930](https://github.com/leanprover/lean4/pull/5930) adds `--short-version` (`-V`) option to display short version (@juhp).
|
||||
* [#5144](https://github.com/leanprover/lean4/pull/5144) switches all 64-bit platforms over to consistently using GMP for bignum arithmetic.
|
||||
* [#5753](https://github.com/leanprover/lean4/pull/5753) raises the minimum supported Windows version to Windows 10 1903 (released May 2019).
|
||||
|
||||
### Lake
|
||||
|
||||
* [#5715](https://github.com/leanprover/lean4/pull/5715) changes `lake new math` to use `autoImplicit false` (@eric-wieser).
|
||||
* [#5688](https://github.com/leanprover/lean4/pull/5688) makes `Lake` not create core aliases in the `Lake` namespace.
|
||||
* [#5924](https://github.com/leanprover/lean4/pull/5924) adds a `text` option for `buildFile*` utilities.
|
||||
* [#5789](https://github.com/leanprover/lean4/pull/5789) makes `lake init` not `git init` when inside git work tree (@haoxins).
|
||||
* [#5684](https://github.com/leanprover/lean4/pull/5684) has Lake update a package's `lean-toolchain` file on `lake update` if it finds the package's direct dependencies use a newer compatible toolchain. To skip this step, use the `--keep-toolchain` CLI option. (See breaking changes.)
|
||||
* [#6218](https://github.com/leanprover/lean4/pull/6218) makes Lake no longer automatically fetch GitHub cloud releases if the package build directory is already present (mirroring the behavior of the Reservoir cache). This prevents the cache from clobbering existing prebuilt artifacts. Users can still manually fetch the cache and clobber the build directory by running `lake build <pkg>:release`.
|
||||
* [#6231](https://github.com/leanprover/lean4/pull/6231) improves the errors Lake produces when it fails to fetch a dependency from Reservoir. If the package is not indexed, it will produce a suggestion about how to require it from GitHub.
|
||||
|
||||
### Documentation
|
||||
|
||||
* [#5617](https://github.com/leanprover/lean4/pull/5617) fixes MSYS2 build instructions.
|
||||
* [#5725](https://github.com/leanprover/lean4/pull/5725) points out that `OfScientific` is called with raw literals (@eric-wieser).
|
||||
* [#5794](https://github.com/leanprover/lean4/pull/5794) adds a stub for application ellipsis notation (@eric-wieser).
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* The syntax for providing arguments to deriving handlers has been removed, which was not used by any major Lean projects in the ecosystem. As a result, the `applyDerivingHandlers` now takes one fewer argument, `registerDerivingHandlerWithArgs` is now simply `registerDerivingHandler`, `DerivingHandler` no longer includes the unused parameter, and `DerivingHandlerNoArgs` has been deprecated. To migrate code, delete the unused `none` argument and use `registerDerivingHandler` and `DerivingHandler`. ([#5265](https://github.com/leanprover/lean4/pull/5265))
|
||||
* The minimum supported Windows version has been raised to Windows 10 1903, released May 2019. ([#5753](https://github.com/leanprover/lean4/pull/5753))
|
||||
* The `--lean` CLI option for `lake` was removed. Use the `LEAN` environment variable instead. ([#5684](https://github.com/leanprover/lean4/pull/5684))
|
||||
* The `inductive ... :=`, `structure ... :=`, and `class ... :=` syntaxes have been deprecated in favor of the `... where` variants. The old syntax produces a warning, controlled by the `linter.deprecated` option. ([#5542](https://github.com/leanprover/lean4/pull/5542))
|
||||
* The generated tactic configuration elaborators now land in `TacticM` to make use of the current recovery state. Commands that wish to elaborate configurations should now use `declare_command_config_elab` instead of `declare_config_elab` to get an elaborator landing in `CommandElabM`. Syntaxes should migrate to `optConfig` instead of `(config)?`, but the elaborators are reverse compatible. ([#5883](https://github.com/leanprover/lean4/pull/5883))
|
||||
|
||||
|
||||
v4.13.0
|
||||
----------
|
||||
@@ -88,7 +372,7 @@ v4.13.0
|
||||
* [#4768](https://github.com/leanprover/lean4/pull/4768) fixes a parse error when `..` appears with a `.` on the next line
|
||||
|
||||
* Metaprogramming
|
||||
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
|
||||
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
|
||||
* [#5401](https://github.com/leanprover/lean4/pull/5401) instance for `Inhabited (TacticM α)` (@alexkeizer)
|
||||
* [#5412](https://github.com/leanprover/lean4/pull/5412) expose Kernel.check for debugging purposes
|
||||
* [#5556](https://github.com/leanprover/lean4/pull/5556) improves the "invalid projection" type inference error in `inferType`.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[0829/202002.254:ERROR:crashpad_client_win.cc(868)] not connected
|
||||
@@ -29,7 +29,7 @@ def ex3 (declName : Name) : MetaM Unit := do
|
||||
for x in xs do
|
||||
trace[Meta.debug] "{x} : {← inferType x}"
|
||||
|
||||
def myMin [LT α] [DecidableRel (α := α) (·<·)] (a b : α) : α :=
|
||||
def myMin [LT α] [DecidableLT α] (a b : α) : α :=
|
||||
if a < b then
|
||||
a
|
||||
else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
source ../../tests/common.sh
|
||||
|
||||
exec_check lean -Dlinter.all=false "$f"
|
||||
exec_check_raw lean -Dlinter.all=false "$f"
|
||||
|
||||
@@ -128,16 +128,16 @@ Numeric literals can be specified in various bases.
|
||||
|
||||
```
|
||||
numeral : numeral10 | numeral2 | numeral8 | numeral16
|
||||
numeral10 : [0-9]+
|
||||
numeral2 : "0" [bB] [0-1]+
|
||||
numeral8 : "0" [oO] [0-7]+
|
||||
numeral16 : "0" [xX] hex_char+
|
||||
numeral10 : [0-9]+ ("_"+ [0-9]+)*
|
||||
numeral2 : "0" [bB] ("_"* [0-1]+)+
|
||||
numeral8 : "0" [oO] ("_"* [0-7]+)+
|
||||
numeral16 : "0" [xX] ("_"* hex_char+)+
|
||||
```
|
||||
|
||||
Floating point literals are also possible with optional exponent:
|
||||
|
||||
```
|
||||
float : [0-9]+ "." [0-9]+ [[eE[+-][0-9]+]
|
||||
float : numeral10 "." numeral10? [eE[+-]numeral10]
|
||||
```
|
||||
|
||||
For example:
|
||||
@@ -147,6 +147,7 @@ constant w : Int := 55
|
||||
constant x : Nat := 26085
|
||||
constant y : Nat := 0x65E5
|
||||
constant z : Float := 2.548123e-05
|
||||
constant b : Bool := 0b_11_01_10_00
|
||||
```
|
||||
|
||||
Note: that negative numbers are created by applying the "-" negation prefix operator to the number, for example:
|
||||
|
||||
@@ -139,7 +139,7 @@ You might be wondering, how does the context actually move through the `ReaderM`
|
||||
add an input argument to a function by modifying its return type? There is a special command in
|
||||
Lean that will show you the reduced types:
|
||||
-/
|
||||
#reduce ReaderM Environment String -- Environment → String
|
||||
#reduce (types := true) ReaderM Environment String -- Environment → String
|
||||
/-!
|
||||
And you can see here that this type is actually a function! It's a function that takes an
|
||||
`Environment` as input and returns a `String`.
|
||||
@@ -196,4 +196,4 @@ entirely.
|
||||
|
||||
Now it's time to move on to [StateM Monad](states.lean.md) which is like a `ReaderM` that is
|
||||
also updatable.
|
||||
-/
|
||||
-/
|
||||
|
||||
16
releases_drafts/list_lex.md
Normal file
16
releases_drafts/list_lex.md
Normal file
@@ -0,0 +1,16 @@
|
||||
We replace the inductive predicate `List.lt` with an upstreamed version of `List.Lex` from Mathlib.
|
||||
(Previously `Lex.lt` was defined in terms of `<`; now it is generalized to take an arbitrary relation.)
|
||||
This subtely changes the notion of ordering on `List α`.
|
||||
|
||||
`List.lt` was a weaker relation: in particular if `l₁ < l₂`, then
|
||||
`a :: l₁ < b :: l₂` may hold according to `List.lt` even if `a` and `b` are merely incomparable
|
||||
(either neither `a < b` nor `b < a`), whereas according to `List.Lex` this would require `a = b`.
|
||||
|
||||
When `<` is total, in the sense that `¬ · < ·` is antisymmetric, then the two relations coincide.
|
||||
|
||||
Mathlib was already overriding the order instances for `List α`,
|
||||
so this change should not be noticed by anyone already using Mathlib.
|
||||
|
||||
We simultaneously add the boolean valued `List.lex` function, parameterised by a `BEq` typeclass
|
||||
and an arbitrary `lt` function. This will support the flexibility previously provided for `List.lt`,
|
||||
via a `==` function which is weaker than strict equality.
|
||||
12
script/mathlib-bench
Executable file
12
script/mathlib-bench
Executable file
@@ -0,0 +1,12 @@
|
||||
#! /bin/env bash
|
||||
# Open a Mathlib4 PR for benchmarking a given Lean 4 PR
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
[ $# -eq 1 ] || (echo "usage: $0 <lean4 PR #>"; exit 1)
|
||||
|
||||
LEAN_PR=$1
|
||||
PR_RESPONSE=$(gh api repos/leanprover-community/mathlib4/pulls -X POST -f head=lean-pr-testing-$LEAN_PR -f base=nightly-testing -f title="leanprover/lean4#$LEAN_PR benchmarking" -f draft=true -f body="ignore me")
|
||||
PR_NUMBER=$(echo "$PR_RESPONSE" | jq '.number')
|
||||
echo "opened https://github.com/leanprover-community/mathlib4/pull/$PR_NUMBER"
|
||||
gh api repos/leanprover-community/mathlib4/issues/$PR_NUMBER/comments -X POST -f body="!bench" > /dev/null
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 15)
|
||||
set(LEAN_VERSION_MINOR 16)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
@@ -122,7 +122,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
# From https://emscripten.org/docs/compiling/WebAssembly.html#backends:
|
||||
# > The simple and safe thing is to pass all -s flags at both compile and link time.
|
||||
set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -fwasm-exceptions -pthread -flto")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -pthread")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -pthread")
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}")
|
||||
endif()
|
||||
@@ -157,11 +157,11 @@ if ((${MULTI_THREAD} MATCHES "ON") AND (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
|
||||
endif ()
|
||||
|
||||
# We want explicit stack probes in huge Lean stack frames for robust stack overflow detection
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fstack-clash-protection")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fstack-clash-protection")
|
||||
|
||||
# This makes signed integer overflow guaranteed to match 2's complement.
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fwrapv")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fwrapv")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fwrapv")
|
||||
|
||||
if(NOT MULTI_THREAD)
|
||||
message(STATUS "Disabled multi-thread support, it will not be safe to run multiple threads in parallel")
|
||||
@@ -451,7 +451,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
|
||||
endif()
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
|
||||
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
|
||||
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
|
||||
@@ -464,7 +464,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libLake_shared.dll.a -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
|
||||
endif()
|
||||
@@ -479,7 +479,7 @@ if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND NOT(${CMAKE_SYSTEM_NAME} MATC
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic")
|
||||
# hide all other symbols
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fvisibility=hidden -fvisibility-inlines-hidden")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fvisibility=hidden")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fvisibility=hidden")
|
||||
endif()
|
||||
|
||||
# On Windows, add bcrypt for random number generation
|
||||
@@ -544,9 +544,10 @@ include_directories(${CMAKE_BINARY_DIR}/include) # config.h etc., "public" head
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||
string(APPEND LEANC_OPTS " ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
|
||||
|
||||
# Do embed flag for finding system libraries in dev builds
|
||||
# Do embed flag for finding system headers and libraries in dev builds
|
||||
if(CMAKE_OSX_SYSROOT AND NOT LEAN_STANDALONE)
|
||||
string(APPEND LEANC_EXTRA_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(initialize)
|
||||
|
||||
@@ -106,7 +106,7 @@ theorem seq_eq_bind_map {α β : Type u} [Monad m] [LawfulMonad m] (f : m (α
|
||||
theorem bind_congr [Bind m] {x : m α} {f g : α → m β} (h : ∀ a, f a = g a) : x >>= f = x >>= g := by
|
||||
simp [funext h]
|
||||
|
||||
@[simp] theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ => pure ⟨⟩) = x := by
|
||||
theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ => pure ⟨⟩) = x := by
|
||||
rw [bind_pure]
|
||||
|
||||
theorem map_congr [Functor m] {x : m α} {f g : α → β} (h : ∀ a, f a = g a) : (f <$> x : m β) = g <$> x := by
|
||||
@@ -133,7 +133,7 @@ theorem seqLeft_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x <* y
|
||||
rw [← bind_pure_comp]
|
||||
simp only [bind_assoc, pure_bind]
|
||||
|
||||
@[simp] theorem Functor.map_unit [Monad m] [LawfulMonad m] {a : m PUnit} : (fun _ => PUnit.unit) <$> a = a := by
|
||||
theorem Functor.map_unit [Monad m] [LawfulMonad m] {a : m PUnit} : (fun _ => PUnit.unit) <$> a = a := by
|
||||
simp [map]
|
||||
|
||||
/--
|
||||
|
||||
@@ -2116,14 +2116,37 @@ instance : Commutative Or := ⟨fun _ _ => propext or_comm⟩
|
||||
instance : Commutative And := ⟨fun _ _ => propext and_comm⟩
|
||||
instance : Commutative Iff := ⟨fun _ _ => propext iff_comm⟩
|
||||
|
||||
/-- `IsRefl X r` means the binary relation `r` on `X` is reflexive. -/
|
||||
class Refl (r : α → α → Prop) : Prop where
|
||||
/-- A reflexive relation satisfies `r a a`. -/
|
||||
refl : ∀ a, r a a
|
||||
|
||||
/--
|
||||
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
|
||||
-/
|
||||
class Antisymm (r : α → α → Prop) : Prop where
|
||||
/-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
|
||||
antisymm {a b : α} : r a b → r b a → a = b
|
||||
antisymm (a b : α) : r a b → r b a → a = b
|
||||
|
||||
@[deprecated Antisymm (since := "2024-10-16"), inherit_doc Antisymm]
|
||||
abbrev _root_.Antisymm (r : α → α → Prop) : Prop := Std.Antisymm r
|
||||
|
||||
/-- `Asymm X r` means that the binary relation `r` on `X` is asymmetric, that is,
|
||||
`r a b → ¬ r b a`. -/
|
||||
class Asymm (r : α → α → Prop) : Prop where
|
||||
/-- An asymmetric relation satisfies `r a b → ¬ r b a`. -/
|
||||
asymm : ∀ a b, r a b → ¬r b a
|
||||
|
||||
/-- `Total X r` means that the binary relation `r` on `X` is total, that is, that for any
|
||||
`x y : X` we have `r x y` or `r y x`. -/
|
||||
class Total (r : α → α → Prop) : Prop where
|
||||
/-- A total relation satisfies `r a b ∨ r b a`. -/
|
||||
total : ∀ a b, r a b ∨ r b a
|
||||
|
||||
/-- `Irrefl X r` means the binary relation `r` on `X` is irreflexive (that is, `r x x` never
|
||||
holds). -/
|
||||
class Irrefl (r : α → α → Prop) : Prop where
|
||||
/-- An irreflexive relation satisfies `¬ r a a`. -/
|
||||
irrefl : ∀ a, ¬r a a
|
||||
|
||||
end Std
|
||||
|
||||
@@ -21,6 +21,7 @@ import Init.Data.Fin
|
||||
import Init.Data.UInt
|
||||
import Init.Data.SInt
|
||||
import Init.Data.Float
|
||||
import Init.Data.Float32
|
||||
import Init.Data.Option
|
||||
import Init.Data.Ord
|
||||
import Init.Data.Random
|
||||
|
||||
@@ -21,3 +21,5 @@ import Init.Data.Array.Set
|
||||
import Init.Data.Array.Monadic
|
||||
import Init.Data.Array.FinRange
|
||||
import Init.Data.Array.Perm
|
||||
import Init.Data.Array.Find
|
||||
import Init.Data.Array.Lex
|
||||
|
||||
@@ -150,7 +150,6 @@ theorem attach_map_coe (l : Array α) (f : α → β) :
|
||||
theorem attach_map_val (l : Array α) (f : α → β) : (l.attach.map fun i => f i.val) = l.map f :=
|
||||
attach_map_coe _ _
|
||||
|
||||
@[simp]
|
||||
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
|
||||
cases l; simp
|
||||
|
||||
@@ -162,7 +161,6 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : Array α) (H :
|
||||
((l.attachWith p H).map fun i => f i.val) = l.map f :=
|
||||
attachWith_map_coe _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (l : Array α) (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l := by
|
||||
cases l; simp
|
||||
@@ -204,8 +202,8 @@ theorem pmap_ne_empty_iff {P : α → Prop} (f : (a : α) → P a → β) {xs :
|
||||
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ #[] ↔ xs ≠ #[] := by
|
||||
cases xs; simp
|
||||
|
||||
theorem pmap_eq_self {l : Array α} {p : α → Prop} (hp : ∀ (a : α), a ∈ l → p a)
|
||||
(f : (a : α) → p a → α) : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
theorem pmap_eq_self {l : Array α} {p : α → Prop} {hp : ∀ (a : α), a ∈ l → p a}
|
||||
{f : (a : α) → p a → α} : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
cases l; simp [List.pmap_eq_self]
|
||||
|
||||
@[simp]
|
||||
@@ -251,7 +249,7 @@ theorem getElem?_attach {xs : Array α} {i : Nat} :
|
||||
theorem getElem_attachWith {xs : Array α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < (xs.attachWith P H).size) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap ..
|
||||
getElem_pmap _ _ h
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
|
||||
|
||||
@@ -11,7 +11,7 @@ import Init.Data.UInt.BasicAux
|
||||
import Init.Data.Repr
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.GetElem
|
||||
import Init.Data.List.ToArray
|
||||
import Init.Data.List.ToArrayImpl
|
||||
import Init.Data.Array.Set
|
||||
|
||||
universe u v w
|
||||
@@ -79,12 +79,15 @@ theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
|
||||
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by
|
||||
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
|
||||
|
||||
@[simp] theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl
|
||||
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
|
||||
theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl
|
||||
|
||||
@[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [size]
|
||||
|
||||
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
|
||||
|
||||
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := rfl
|
||||
|
||||
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
|
||||
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
||||
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
||||
@@ -97,6 +100,9 @@ instance : Membership α (Array α) where
|
||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||||
|
||||
@[simp] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
simp [mem_def]
|
||||
|
||||
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] ∈ l := by
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
@@ -203,7 +209,7 @@ instance : EmptyCollection (Array α) := ⟨Array.empty⟩
|
||||
instance : Inhabited (Array α) where
|
||||
default := Array.empty
|
||||
|
||||
@[simp] def isEmpty (a : Array α) : Bool :=
|
||||
def isEmpty (a : Array α) : Bool :=
|
||||
a.size = 0
|
||||
|
||||
@[specialize]
|
||||
@@ -242,7 +248,7 @@ def singleton (v : α) : Array α :=
|
||||
mkArray 1 v
|
||||
|
||||
def back! [Inhabited α] (a : Array α) : α :=
|
||||
a.get! (a.size - 1)
|
||||
a[a.size - 1]!
|
||||
|
||||
@[deprecated back! (since := "2024-10-31")] abbrev back := @back!
|
||||
|
||||
@@ -474,6 +480,10 @@ def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f
|
||||
| _ => pure ⟨⟩
|
||||
return none
|
||||
|
||||
/--
|
||||
Note that the universe level is contrained to `Type` here,
|
||||
to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
|
||||
-/
|
||||
@[inline]
|
||||
def findM? {α : Type} {m : Type → Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) := do
|
||||
for a in as do
|
||||
@@ -585,8 +595,12 @@ def zipWithIndex (arr : Array α) : Array (α × Nat) :=
|
||||
arr.mapIdx fun i a => (a, i)
|
||||
|
||||
@[inline]
|
||||
def find? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run <| as.findM? p
|
||||
def find? {α : Type u} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run do
|
||||
for a in as do
|
||||
if p a then
|
||||
return a
|
||||
return none
|
||||
|
||||
@[inline]
|
||||
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
@@ -649,9 +663,15 @@ def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool
|
||||
def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.allM p start stop
|
||||
|
||||
/-- `as.contains a` is true if there is some element `b` in `as` such that `a == b`. -/
|
||||
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
||||
as.any (· == a)
|
||||
as.any (a == ·)
|
||||
|
||||
/--
|
||||
Variant of `Array.contains` with arguments reversed.
|
||||
|
||||
For verification purposes, we simplify this to `contains`.
|
||||
-/
|
||||
def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
||||
as.contains a
|
||||
|
||||
@@ -801,7 +821,7 @@ decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
|
||||
induction a, i, h using Array.eraseIdx.induct with
|
||||
| @case1 a i h h' a' ih =>
|
||||
unfold eraseIdx
|
||||
simp [h', a', ih]
|
||||
simp +zetaDelta [h', a', ih]
|
||||
| case2 a i h h' =>
|
||||
unfold eraseIdx
|
||||
simp [h']
|
||||
@@ -924,6 +944,13 @@ def split (as : Array α) (p : α → Bool) : Array α × Array α :=
|
||||
as.foldl (init := (#[], #[])) fun (as, bs) a =>
|
||||
if p a then (as.push a, bs) else (as, bs.push a)
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
instance instLT [LT α] : LT (Array α) := ⟨fun as bs => as.toList < bs.toList⟩
|
||||
instance instLE [LT α] : LE (Array α) := ⟨fun as bs => as.toList ≤ bs.toList⟩
|
||||
|
||||
-- See `Init.Data.Array.Lex.Basic` for the boolean valued lexicographic comparator.
|
||||
|
||||
/-! ## Auxiliary functions used in metaprogramming.
|
||||
|
||||
We do not currently intend to provide verification theorems for these functions.
|
||||
|
||||
@@ -32,10 +32,8 @@ private theorem List.of_toArrayAux_eq_toArrayAux {as bs : List α} {cs ds : Arra
|
||||
have := Array.of_push_eq_push ih₂
|
||||
simp [this]
|
||||
|
||||
@[simp] theorem List.toArray_eq_toArray_eq (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) := by
|
||||
apply propext; apply Iff.intro
|
||||
· intro h; simpa [toArray] using h
|
||||
· intro h; rw [h]
|
||||
theorem List.toArray_eq_toArray_eq (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) := by
|
||||
simp
|
||||
|
||||
def Array.mapM' [Monad m] (f : α → m β) (as : Array α) : m { bs : Array β // bs.size = as.size } :=
|
||||
go 0 ⟨mkEmpty as.size, rfl⟩ (by simp)
|
||||
|
||||
@@ -93,11 +93,14 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α → β → m β) (init
|
||||
@[simp] theorem appendList_eq_append
|
||||
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
|
||||
|
||||
@[simp] theorem appendList_toList (arr : Array α) (l : List α) :
|
||||
@[simp] theorem toList_appendList (arr : Array α) (l : List α) :
|
||||
(arr ++ l).toList = arr.toList ++ l := by
|
||||
rw [← appendList_eq_append]; unfold Array.appendList
|
||||
induction l generalizing arr <;> simp [*]
|
||||
|
||||
@[deprecated toList_appendList (since := "2024-12-11")]
|
||||
abbrev appendList_toList := @toList_appendList
|
||||
|
||||
@[deprecated "Use the reverse direction of `foldrM_toList`." (since := "2024-11-13")]
|
||||
theorem foldrM_eq_foldrM_toList [Monad m]
|
||||
(f : α → β → m β) (init : β) (arr : Array α) :
|
||||
@@ -149,7 +152,7 @@ abbrev pop_data := @pop_toList
|
||||
@[deprecated toList_append (since := "2024-09-09")]
|
||||
abbrev append_data := @toList_append
|
||||
|
||||
@[deprecated appendList_toList (since := "2024-09-09")]
|
||||
abbrev appendList_data := @appendList_toList
|
||||
@[deprecated toList_appendList (since := "2024-09-09")]
|
||||
abbrev appendList_data := @toList_appendList
|
||||
|
||||
end Array
|
||||
|
||||
@@ -42,7 +42,7 @@ theorem rel_of_isEqv {r : α → α → Bool} {a b : Array α} :
|
||||
· exact fun h' => ⟨h, fun i => rel_of_isEqvAux h (Nat.le_refl ..) h'⟩
|
||||
· intro; contradiction
|
||||
|
||||
theorem isEqv_iff_rel (a b : Array α) (r) :
|
||||
theorem isEqv_iff_rel {a b : Array α} {r} :
|
||||
Array.isEqv a b r ↔ ∃ h : a.size = b.size, ∀ (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h ▸ h')) :=
|
||||
⟨rel_of_isEqv, fun ⟨h, w⟩ => by
|
||||
simp only [isEqv, ← h, ↓reduceDIte]
|
||||
|
||||
@@ -81,7 +81,7 @@ theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.siz
|
||||
(L.findSome? fun l => l[0]?).isSome := by
|
||||
cases L using array_array_induction
|
||||
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
|
||||
List.findSome?_isSome_iff, List.isSome_getElem?]
|
||||
List.findSome?_isSome_iff, isSome_getElem?]
|
||||
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
|
||||
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
|
||||
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
||||
@@ -99,7 +99,7 @@ theorem back?_flatten {L : Array (Array α)} :
|
||||
simp [List.getLast?_flatten, ← List.map_reverse, List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
|
||||
simp [mkArray_eq_toArray_replicate, List.findSome?_replicate]
|
||||
simp [← List.toArray_replicate, List.findSome?_replicate]
|
||||
|
||||
@[simp] theorem findSome?_mkArray_of_pos (h : 0 < n) : findSome? f (mkArray n a) = f a := by
|
||||
simp [findSome?_mkArray, Nat.ne_of_gt h]
|
||||
@@ -246,7 +246,7 @@ theorem find?_flatMap_eq_none {xs : Array α} {f : α → Array β} {p : β →
|
||||
|
||||
theorem find?_mkArray :
|
||||
find? p (mkArray n a) = if n = 0 then none else if p a then some a else none := by
|
||||
simp [mkArray_eq_toArray_replicate, List.find?_replicate]
|
||||
simp [← List.toArray_replicate, List.find?_replicate]
|
||||
|
||||
@[simp] theorem find?_mkArray_of_length_pos (h : 0 < n) :
|
||||
find? p (mkArray n a) = if p a then some a else none := by
|
||||
@@ -262,15 +262,15 @@ theorem find?_mkArray :
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_mkArray_eq_none {n : Nat} {a : α} {p : α → Bool} :
|
||||
(mkArray n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [mkArray_eq_toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
|
||||
simp [← List.toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
|
||||
|
||||
@[simp] theorem find?_mkArray_eq_some {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(mkArray n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
simp [mkArray_eq_toArray_replicate]
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[simp] theorem get_find?_mkArray (n : Nat) (a : α) (p : α → Bool) (h) :
|
||||
((mkArray n a).find? p).get h = a := by
|
||||
simp [mkArray_eq_toArray_replicate]
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
theorem find?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (p : β → Bool) :
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
8
src/Init/Data/Array/Lex.lean
Normal file
8
src/Init/Data/Array/Lex.lean
Normal file
@@ -0,0 +1,8 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lex.Basic
|
||||
import Init.Data.Array.Lex.Lemmas
|
||||
30
src/Init/Data/Array/Lex/Basic.lean
Normal file
30
src/Init/Data/Array/Lex/Basic.lean
Normal file
@@ -0,0 +1,30 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Range
|
||||
|
||||
namespace Array
|
||||
|
||||
/--
|
||||
Lexicographic comparator for arrays.
|
||||
|
||||
`lex as bs lt` is true if
|
||||
- `bs` is larger than `as` and `as` is pairwise equivalent via `==` to the initial segment of `bs`, or
|
||||
- there is an index `i` such that `lt as[i] bs[i]`, and for all `j < i`, `as[j] == bs[j]`.
|
||||
-/
|
||||
def lex [BEq α] (as bs : Array α) (lt : α → α → Bool := by exact (· < ·)) : Bool := Id.run do
|
||||
for h : i in [0 : min as.size bs.size] do
|
||||
-- TODO: `omega` should be able to find this itself.
|
||||
have : i < min as.size bs.size := Membership.get_elem_helper h rfl
|
||||
if lt as[i] bs[i] then
|
||||
return true
|
||||
else if as[i] != bs[i] then
|
||||
return false
|
||||
return as.size < bs.size
|
||||
|
||||
end Array
|
||||
216
src/Init/Data/Array/Lex/Lemmas.lean
Normal file
216
src/Init/Data/Array/Lex/Lemmas.lean
Normal file
@@ -0,0 +1,216 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Lex
|
||||
|
||||
namespace Array
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
@[simp] theorem lt_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray < l₂.toArray ↔ l₁ < l₂ := Iff.rfl
|
||||
@[simp] theorem le_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray ≤ l₂.toArray ↔ l₁ ≤ l₂ := Iff.rfl
|
||||
|
||||
theorem not_lt_iff_ge [LT α] (l₁ l₂ : List α) : ¬ l₁ < l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
|
||||
¬ l₁ ≤ l₂ ↔ l₂ < l₁ :=
|
||||
Decidable.not_not
|
||||
|
||||
@[simp] theorem lex_empty [BEq α] {lt : α → α → Bool} (l : Array α) : l.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]
|
||||
|
||||
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 [Std.Range.forIn'_eq_forIn'_range', size_append, 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,
|
||||
getElem_append_right]
|
||||
cases lt a b
|
||||
· rw [bne]
|
||||
cases a == b <;> simp
|
||||
· simp
|
||||
|
||||
@[simp] 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]
|
||||
| cons x l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex, Id.run]
|
||||
| cons y l₂ =>
|
||||
rw [List.toArray_cons, List.toArray_cons y, cons_lex_cons, List.lex, ih]
|
||||
|
||||
@[simp] theorem lex_toList [BEq α] (lt : α → α → Bool) (l₁ l₂ : Array α) :
|
||||
l₁.toList.lex l₂.toList lt = l₁.lex l₂ lt := by
|
||||
cases l₁ <;> cases l₂ <;> simp
|
||||
|
||||
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] (l : Array α) : ¬ l < l :=
|
||||
List.lt_irrefl l.toList
|
||||
|
||||
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] : Std.Irrefl (α := Array α) (· < ·) where
|
||||
irrefl := Array.lt_irrefl
|
||||
|
||||
@[simp] theorem empty_le [LT α] (l : Array α) : #[] ≤ l := List.nil_le l.toList
|
||||
|
||||
@[simp] theorem le_empty [LT α] (l : Array α) : l ≤ #[] ↔ l = #[] := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem empty_lt_push [LT α] (l : Array α) (a : α) : #[] < l.push a := by
|
||||
rcases l with (_ | ⟨x, l⟩) <;> simp
|
||||
|
||||
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α → α → Prop)] (l : Array α) : l ≤ l :=
|
||||
List.le_refl l.toList
|
||||
|
||||
instance [LT α] [Std.Irrefl (· < · : α → α → Prop)] : Std.Refl (· ≤ · : Array α → Array α → Prop) where
|
||||
refl := Array.le_refl
|
||||
|
||||
protected theorem lt_trans [LT α] [DecidableLT α]
|
||||
[i₁ : Trans (· < · : α → α → Prop) (· < ·) (· < ·)]
|
||||
{l₁ l₂ l₃ : Array α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
|
||||
List.lt_trans h₁ h₂
|
||||
|
||||
instance [LT α] [DecidableLT α]
|
||||
[Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : Array α → Array α → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := Array.lt_trans h₁ h₂
|
||||
|
||||
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : Array α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
|
||||
List.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : Array α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)] :
|
||||
Trans (· ≤ · : Array α → Array α → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans h₁ h₂ := Array.le_trans h₁ h₂
|
||||
|
||||
protected theorem lt_asymm [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{l₁ l₂ : Array α} (h : l₁ < l₂) : ¬ l₂ < l₁ := List.lt_asymm h
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Asymm (· < · : Array α → Array α → Prop) where
|
||||
asymm _ _ := Array.lt_asymm
|
||||
|
||||
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] {l₁ l₂ : Array α} : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
List.le_total
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : Array α → Array α → Prop) where
|
||||
total _ _ := Array.le_total
|
||||
|
||||
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : Array α} : lex l₁ l₂ = true ↔ l₁ < l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : Array α} : lex l₁ l₂ = false ↔ l₂ ≤ l₁ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.not_lt_iff_ge]
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLT (Array α) :=
|
||||
fun l₁ l₂ => decidable_of_iff (lex l₁ l₂ = true) lex_eq_true_iff_lt
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLE (Array α) :=
|
||||
fun l₁ l₂ => decidable_of_iff (lex l₂ l₁ = false) lex_eq_false_iff_ge
|
||||
|
||||
/--
|
||||
`l₁` is lexicographically less than `l₂` if either
|
||||
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.size`,
|
||||
and `l₁` is shorter than `l₂` or
|
||||
- there exists an index `i` such that
|
||||
- for all `j < i`, `l₁[j] == l₂[j]` and
|
||||
- `l₁[i] < l₂[i]`
|
||||
-/
|
||||
theorem lex_eq_true_iff_exists [BEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = true ↔
|
||||
(l₁.isEqv (l₂.take l₁.size) (· == ·) ∧ l₁.size < l₂.size) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) ∧ lt l₁[i] l₂[i]) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.lex_eq_true_iff_exists]
|
||||
|
||||
/--
|
||||
`l₁` is *not* lexicographically less than `l₂`
|
||||
(which you might think of as "`l₂` is lexicographically greater than or equal to `l₁`"") if either
|
||||
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.length` or
|
||||
- there exists an index `i` such that
|
||||
- for all `j < i`, `l₁[j] == l₂[j]` and
|
||||
- `l₂[i] < l₁[i]`
|
||||
|
||||
This formulation requires that `==` and `lt` are compatible in the following senses:
|
||||
- `==` is symmetric
|
||||
(we unnecessarily further assume it is transitive, to make use of the existing typeclasses)
|
||||
- `lt` is irreflexive with respect to `==` (i.e. if `x == y` then `lt x y = false`
|
||||
- `lt` is asymmmetric (i.e. `lt x y = true → lt y x = false`)
|
||||
- `lt` is antisymmetric with respect to `==` (i.e. `lt x y = false → lt y x = false → x == y`)
|
||||
-/
|
||||
theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α → α → Bool)
|
||||
(lt_irrefl : ∀ x y, x == y → lt x y = false)
|
||||
(lt_asymm : ∀ x y, lt x y = true → lt y x = false)
|
||||
(lt_antisymm : ∀ x y, lt x y = false → lt y x = false → x == y) :
|
||||
lex l₁ l₂ lt = false ↔
|
||||
(l₂.isEqv (l₁.take l₂.size) (· == ·)) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) ∧ lt l₂[i] l₁[i]) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all [List.lex_eq_false_iff_exists]
|
||||
|
||||
theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : Array α} :
|
||||
l₁ < l₂ ↔
|
||||
(l₁ = l₂.take l₁.size ∧ l₁.size < l₂.size) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) ∧ l₁[i] < l₂[i]) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.lt_iff_exists]
|
||||
|
||||
theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {l₁ l₂ : Array α} :
|
||||
l₁ ≤ l₂ ↔
|
||||
(l₁ = l₂.take l₁.size) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) ∧ l₁[i] < l₂[i]) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.le_iff_exists]
|
||||
|
||||
end Array
|
||||
@@ -79,8 +79,31 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
|
||||
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldrM_filter]
|
||||
|
||||
/-! ### forM -/
|
||||
|
||||
@[congr] theorem forM_congr [Monad m] {as bs : Array α} (w : as = bs)
|
||||
{f : α → m PUnit} :
|
||||
forM f as = forM f bs := by
|
||||
cases as <;> cases bs
|
||||
simp_all
|
||||
|
||||
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (l : Array α) (g : α → β) (f : β → m PUnit) :
|
||||
(l.map g).forM f = l.forM (fun a => f (g a)) := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
/-! ### forIn' -/
|
||||
|
||||
@[congr] theorem forIn'_congr [Monad m] {as bs : Array α} (w : as = bs)
|
||||
{b b' : β} (hb : b = b')
|
||||
{f : (a' : α) → a' ∈ as → β → m (ForInStep β)}
|
||||
{g : (a' : α) → a' ∈ bs → β → m (ForInStep β)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
forIn' as b f = forIn' bs b' g := by
|
||||
cases as <;> cases bs
|
||||
simp only [mk.injEq, mem_toArray, List.forIn'_toArray] at w h ⊢
|
||||
exact List.forIn'_congr w hb h
|
||||
|
||||
/--
|
||||
We can express a for loop over an array as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
@@ -120,6 +143,12 @@ theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
cases l
|
||||
simp [List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (g : α → β) (f : (b : β) → b ∈ l.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem g h) y := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
/--
|
||||
We can express a for loop over an array as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
@@ -156,4 +185,10 @@ theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
cases l
|
||||
simp [List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (g : α → β) (f : β → γ → m (ForInStep γ)) :
|
||||
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Array
|
||||
theorem exists_of_uset (self : Array α) (i d h) :
|
||||
∃ l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
||||
(self.uset i d h).toList = l₁ ++ d :: l₂ := by
|
||||
simpa only [ugetElem_eq_getElem, getElem_eq_getElem_toList, uset, toList_set] using
|
||||
simpa only [ugetElem_eq_getElem, ← getElem_toList, uset, toList_set] using
|
||||
List.exists_of_set _
|
||||
|
||||
end Array
|
||||
|
||||
@@ -40,6 +40,9 @@ theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b → b == a :=
|
||||
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||
Bool.eq_iff_iff.2 ⟨BEq.symm, BEq.symm⟩
|
||||
|
||||
theorem bne_comm [BEq α] [PartialEquivBEq α] {a b : α} : (a != b) = (b != a) := by
|
||||
rw [bne, BEq.comm, bne]
|
||||
|
||||
theorem BEq.symm_false [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = false → (b == a) = false :=
|
||||
BEq.comm (α := α) ▸ id
|
||||
|
||||
|
||||
@@ -351,17 +351,17 @@ end relations
|
||||
section cast
|
||||
|
||||
/-- `cast eq x` embeds `x` into an equal `BitVec` type. -/
|
||||
@[inline] def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq ▸ x.isLt)
|
||||
@[inline] protected def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq ▸ x.isLt)
|
||||
|
||||
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
|
||||
cast h (BitVec.ofNat n x) = BitVec.ofNat m x := by
|
||||
(BitVec.ofNat n x).cast h = BitVec.ofNat m x := by
|
||||
subst h; rfl
|
||||
|
||||
@[simp] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
|
||||
cast h₂ (cast h₁ x) = cast (h₁ ▸ h₂) x :=
|
||||
(x.cast h₁).cast h₂ = x.cast (h₁ ▸ h₂) :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : cast h x = x := rfl
|
||||
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : x.cast h = x := rfl
|
||||
|
||||
/--
|
||||
Extraction of bits `start` to `start + len - 1` from a bit vector of size `n` to yield a
|
||||
|
||||
@@ -462,7 +462,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
|
||||
case true =>
|
||||
apply hmin
|
||||
apply eq_of_getMsbD_eq
|
||||
rintro ⟨i, hi⟩
|
||||
intro i hi
|
||||
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
|
||||
cases i
|
||||
case zero => exact hmsb
|
||||
@@ -470,7 +470,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
|
||||
case false =>
|
||||
apply hzero
|
||||
apply eq_of_getMsbD_eq
|
||||
rintro ⟨i, hi⟩
|
||||
intro i hi
|
||||
simp only [getMsbD_zero]
|
||||
cases i
|
||||
case zero => exact hmsb
|
||||
@@ -573,11 +573,11 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
setWidth w (x.setWidth (i + 1)) =
|
||||
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
|
||||
rw [add_eq_or_of_and_eq_zero]
|
||||
· ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
· ext k h
|
||||
simp only [getLsbD_setWidth, h, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp
|
||||
simp [h]
|
||||
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
|
||||
by_cases hik' : k < (i + 1)
|
||||
· have hik'' : k < i := by omega
|
||||
|
||||
@@ -173,21 +173,21 @@ theorem getMsbD_eq_getMsb?_getD (x : BitVec w) (i : Nat) :
|
||||
-- We choose `eq_of_getLsbD_eq` as the `@[ext]` theorem for `BitVec`
|
||||
-- somewhat arbitrarily over `eq_of_getMsbD_eq`.
|
||||
@[ext] theorem eq_of_getLsbD_eq {x y : BitVec w}
|
||||
(pred : ∀(i : Fin w), x.getLsbD i.val = y.getLsbD i.val) : x = y := by
|
||||
(pred : ∀ i, i < w → x.getLsbD i = y.getLsbD i) : x = y := by
|
||||
apply eq_of_toNat_eq
|
||||
apply Nat.eq_of_testBit_eq
|
||||
intro i
|
||||
if i_lt : i < w then
|
||||
exact pred ⟨i, i_lt⟩
|
||||
exact pred i i_lt
|
||||
else
|
||||
have p : i ≥ w := Nat.le_of_not_gt i_lt
|
||||
simp [testBit_toNat, getLsbD_ge _ _ p]
|
||||
|
||||
theorem eq_of_getMsbD_eq {x y : BitVec w}
|
||||
(pred : ∀(i : Fin w), x.getMsbD i.val = y.getMsbD i.val) : x = y := by
|
||||
(pred : ∀ i, i < w → x.getMsbD i = y.getMsbD i) : x = y := by
|
||||
simp only [getMsbD] at pred
|
||||
apply eq_of_getLsbD_eq
|
||||
intro ⟨i, i_lt⟩
|
||||
intro i i_lt
|
||||
if w_zero : w = 0 then
|
||||
simp [w_zero]
|
||||
else
|
||||
@@ -199,7 +199,7 @@ theorem eq_of_getMsbD_eq {x y : BitVec w}
|
||||
simp only [Nat.sub_sub]
|
||||
apply Nat.sub_lt w_pos
|
||||
simp [Nat.succ_add]
|
||||
have q := pred ⟨w - 1 - i, q_lt⟩
|
||||
have q := pred (w - 1 - i) q_lt
|
||||
simpa [q_lt, Nat.sub_sub_self, r] using q
|
||||
|
||||
-- This cannot be a `@[simp]` lemma, as it would be tried at every term.
|
||||
@@ -241,8 +241,11 @@ theorem toFin_one : toFin (1 : BitVec w) = 1 := by
|
||||
@[simp] theorem toNat_ofBool (b : Bool) : (ofBool b).toNat = b.toNat := by
|
||||
cases b <;> rfl
|
||||
|
||||
@[simp] theorem msb_ofBool (b : Bool) : (ofBool b).msb = b := by
|
||||
cases b <;> simp [BitVec.msb, getMsbD, getLsbD]
|
||||
@[simp] theorem toInt_ofBool (b : Bool) : (ofBool b).toInt = -b.toInt := by
|
||||
cases b <;> rfl
|
||||
|
||||
@[simp] theorem toFin_ofBool (b : Bool) : (ofBool b).toFin = Fin.ofNat' 2 (b.toNat) := by
|
||||
cases b <;> rfl
|
||||
|
||||
theorem ofNat_one (n : Nat) : BitVec.ofNat 1 n = BitVec.ofBool (n % 2 = 1) := by
|
||||
rcases (Nat.mod_two_eq_zero_or_one n) with h | h <;> simp [h, BitVec.ofNat, Fin.ofNat']
|
||||
@@ -329,11 +332,11 @@ theorem getLsbD_ofNat (n : Nat) (x : Nat) (i : Nat) :
|
||||
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m ≤ n) : x < 2 ^ n :=
|
||||
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_of_le_right (by trivial : 0 < 2) le)
|
||||
|
||||
@[simp] theorem getElem_zero_ofNat_zero (i : Nat) (h : i < w) : (BitVec.ofNat w 0)[i] = false := by
|
||||
simp [getElem_eq_testBit_toNat]
|
||||
theorem getElem_zero_ofNat_zero (i : Nat) (h : i < w) : (BitVec.ofNat w 0)[i] = false := by
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem_zero_ofNat_one (h : 0 < w) : (BitVec.ofNat w 1)[0] = true := by
|
||||
simp [getElem_eq_testBit_toNat, h]
|
||||
theorem getElem_zero_ofNat_one (h : 0 < w) : (BitVec.ofNat w 1)[0] = true := by
|
||||
simp
|
||||
|
||||
theorem getElem?_zero_ofNat_zero : (BitVec.ofNat (w+1) 0)[0]? = some false := by
|
||||
simp
|
||||
@@ -359,12 +362,13 @@ 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 {b : Bool} {i : Nat} : (ofBool b)[0] = b := by
|
||||
rcases b with rfl | rfl
|
||||
· simp [ofBool]
|
||||
· simp only [ofBool]
|
||||
by_cases hi : i = 0 <;> simp [hi] <;> omega
|
||||
theorem getElem_ofBool {b : Bool} : (ofBool b)[0] = b := by simp
|
||||
|
||||
@[simp] theorem getMsbD_ofBool (b : Bool) : (ofBool b).getMsbD i = (decide (i = 0) && b) := by
|
||||
cases b <;> simp [getMsbD]
|
||||
|
||||
@[simp] theorem msb_ofBool (b : Bool) : (ofBool b).msb = b := by
|
||||
cases b <;> simp [BitVec.msb]
|
||||
|
||||
/-! ### msb -/
|
||||
|
||||
@@ -410,21 +414,21 @@ theorem toNat_ge_of_msb_true {x : BitVec n} (p : BitVec.msb x = true) : x.toNat
|
||||
|
||||
/-! ### cast -/
|
||||
|
||||
@[simp, bv_toNat] theorem toNat_cast (h : w = v) (x : BitVec w) : (cast h x).toNat = x.toNat := rfl
|
||||
@[simp, bv_toNat] theorem toNat_cast (h : w = v) (x : BitVec w) : (x.cast h).toNat = x.toNat := rfl
|
||||
@[simp] theorem toFin_cast (h : w = v) (x : BitVec w) :
|
||||
(cast h x).toFin = x.toFin.cast (by rw [h]) :=
|
||||
(x.cast h).toFin = x.toFin.cast (by rw [h]) :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem getLsbD_cast (h : w = v) (x : BitVec w) : (cast h x).getLsbD i = x.getLsbD i := by
|
||||
@[simp] theorem getLsbD_cast (h : w = v) (x : BitVec w) : (x.cast h).getLsbD i = x.getLsbD i := by
|
||||
subst h; simp
|
||||
|
||||
@[simp] theorem getMsbD_cast (h : w = v) (x : BitVec w) : (cast h x).getMsbD i = x.getMsbD i := by
|
||||
@[simp] theorem getMsbD_cast (h : w = v) (x : BitVec w) : (x.cast h).getMsbD i = x.getMsbD i := by
|
||||
subst h; simp
|
||||
|
||||
@[simp] theorem getElem_cast (h : w = v) (x : BitVec w) (p : i < v) : (cast h x)[i] = x[i] := by
|
||||
@[simp] theorem getElem_cast (h : w = v) (x : BitVec w) (p : i < v) : (x.cast h)[i] = x[i] := by
|
||||
subst h; simp
|
||||
|
||||
@[simp] theorem msb_cast (h : w = v) (x : BitVec w) : (cast h x).msb = x.msb := by
|
||||
@[simp] theorem msb_cast (h : w = v) (x : BitVec w) : (x.cast h).msb = x.msb := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
/-! ### toInt/ofInt -/
|
||||
@@ -498,6 +502,9 @@ theorem toInt_ofNat {n : Nat} (x : Nat) :
|
||||
@[simp] theorem ofInt_ofNat (w n : Nat) :
|
||||
BitVec.ofInt w (no_index (OfNat.ofNat n)) = BitVec.ofNat w (OfNat.ofNat n) := rfl
|
||||
|
||||
@[simp] theorem ofInt_toInt {x : BitVec w} : BitVec.ofInt w x.toInt = x := by
|
||||
by_cases h : 2 * x.toNat < 2^w <;> ext <;> simp [getLsbD, h, BitVec.toInt]
|
||||
|
||||
theorem toInt_neg_iff {w : Nat} {x : BitVec w} :
|
||||
BitVec.toInt x < 0 ↔ 2 ^ w ≤ 2 * x.toNat := by
|
||||
simp [toInt_eq_toNat_cond]; omega
|
||||
@@ -526,7 +533,7 @@ theorem toInt_zero {w : Nat} : (0#w).toInt = 0 := by
|
||||
A bitvector, when interpreted as an integer, is less than zero iff
|
||||
its most significant bit is true.
|
||||
-/
|
||||
theorem slt_zero_iff_msb_cond (x : BitVec w) : x.slt 0#w ↔ x.msb = true := by
|
||||
theorem slt_zero_iff_msb_cond {x : BitVec w} : x.slt 0#w ↔ x.msb = true := by
|
||||
have := toInt_eq_msb_cond x
|
||||
constructor
|
||||
· intros h
|
||||
@@ -569,6 +576,10 @@ theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
|
||||
(x.setWidth v).toInt = Int.bmod x.toNat (2^v) := by
|
||||
simp [toInt_eq_toNat_bmod, toNat_setWidth, Int.emod_bmod]
|
||||
|
||||
@[simp] theorem toFin_setWidth {x : BitVec w} :
|
||||
(x.setWidth v).toFin = Fin.ofNat' (2^v) x.toNat := by
|
||||
ext; simp
|
||||
|
||||
theorem setWidth'_eq {x : BitVec w} (h : w ≤ v) : x.setWidth' h = x.setWidth v := by
|
||||
apply eq_of_toNat_eq
|
||||
rw [toNat_setWidth, toNat_setWidth']
|
||||
@@ -645,6 +656,20 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
getLsbD (setWidth m x) i = (decide (i < m) && getLsbD x i) := by
|
||||
simp [getLsbD, toNat_setWidth, Nat.testBit_mod_two_pow]
|
||||
|
||||
theorem getMsbD_setWidth {m : Nat} {x : BitVec n} {i : Nat} :
|
||||
getMsbD (setWidth m x) i = (decide (m - n ≤ i) && getMsbD x (i + n - m)) := by
|
||||
unfold setWidth
|
||||
by_cases h : n ≤ m <;> simp only [h]
|
||||
· by_cases h' : m - n ≤ i
|
||||
<;> simp [h', show i - (m - n) = i + n - m by omega]
|
||||
· simp only [show m - n = 0 by omega, getMsbD, getLsbD_setWidth]
|
||||
by_cases h' : i < m
|
||||
· simp [show m - 1 - i < m by omega, show i + n - m < n by omega,
|
||||
show n - 1 - (i + n - m) = m - 1 - i by omega]
|
||||
omega
|
||||
· simp [h']
|
||||
omega
|
||||
|
||||
@[simp] theorem getMsbD_setWidth_add {x : BitVec w} (h : k ≤ i) :
|
||||
(x.setWidth (w + k)).getMsbD i = x.getMsbD (i - k) := by
|
||||
by_cases h : w = 0
|
||||
@@ -658,7 +683,7 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
<;> omega
|
||||
|
||||
@[simp] theorem cast_setWidth (h : v = v') (x : BitVec w) :
|
||||
cast h (setWidth v x) = setWidth v' x := by
|
||||
(x.setWidth v).cast h = x.setWidth v' := by
|
||||
subst h
|
||||
ext
|
||||
simp
|
||||
@@ -671,7 +696,7 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
revert p
|
||||
cases getLsbD x i <;> simp; omega
|
||||
|
||||
@[simp] theorem setWidth_cast {h : w = v} : (cast h x).setWidth k = x.setWidth k := by
|
||||
@[simp] theorem setWidth_cast {x : BitVec w} {h : w = v} : (x.cast h).setWidth k = x.setWidth k := by
|
||||
apply eq_of_getLsbD_eq
|
||||
simp
|
||||
|
||||
@@ -689,14 +714,15 @@ theorem msb_setWidth'' (x : BitVec w) : (x.setWidth (k + 1)).msb = x.getLsbD k :
|
||||
/-- zero extending a bitvector to width 1 equals the boolean of the lsb. -/
|
||||
theorem setWidth_one_eq_ofBool_getLsb_zero (x : BitVec w) :
|
||||
x.setWidth 1 = BitVec.ofBool (x.getLsbD 0) := by
|
||||
ext i
|
||||
simp [getLsbD_setWidth, Fin.fin_one_eq_zero i]
|
||||
ext i h
|
||||
simp at h
|
||||
simp [getLsbD_setWidth, h]
|
||||
|
||||
/-- Zero extending `1#v` to `1#w` equals `1#w` when `v > 0`. -/
|
||||
theorem setWidth_ofNat_one_eq_ofNat_one_of_lt {v w : Nat} (hv : 0 < v) :
|
||||
(BitVec.ofNat v 1).setWidth w = BitVec.ofNat w 1 := by
|
||||
ext ⟨i, hilt⟩
|
||||
simp only [getLsbD_setWidth, hilt, decide_true, getLsbD_ofNat, Bool.true_and,
|
||||
ext i h
|
||||
simp only [getLsbD_setWidth, h, decide_true, getLsbD_ofNat, Bool.true_and,
|
||||
Bool.and_iff_right_iff_imp, decide_eq_true_eq]
|
||||
intros hi₁
|
||||
have hv := Nat.testBit_one_eq_true_iff_self_eq_zero.mp hi₁
|
||||
@@ -723,8 +749,7 @@ protected theorem extractLsb_ofFin {n} (x : Fin (2^n)) (hi lo : Nat) :
|
||||
@[simp]
|
||||
protected theorem extractLsb_ofNat (x n : Nat) (hi lo : Nat) :
|
||||
extractLsb hi lo (BitVec.ofNat n x) = .ofNat (hi - lo + 1) ((x % 2^n) >>> lo) := by
|
||||
apply eq_of_getLsbD_eq
|
||||
intro ⟨i, _lt⟩
|
||||
ext i
|
||||
simp [BitVec.ofNat]
|
||||
|
||||
@[simp] theorem extractLsb'_toNat (s m : Nat) (x : BitVec n) :
|
||||
@@ -811,8 +836,8 @@ theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h
|
||||
|
||||
@[simp] theorem setWidth_or {x y : BitVec w} :
|
||||
(x ||| y).setWidth k = x.setWidth k ||| y.setWidth k := by
|
||||
ext
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
theorem or_assoc (x y z : BitVec w) :
|
||||
x ||| y ||| z = x ||| (y ||| z) := by
|
||||
@@ -845,12 +870,12 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· ||| · ) (0#n) where
|
||||
simp
|
||||
|
||||
@[simp] theorem or_allOnes {x : BitVec w} : x ||| allOnes w = allOnes w := by
|
||||
ext i
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem allOnes_or {x : BitVec w} : allOnes w ||| x = allOnes w := by
|
||||
ext i
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
/-! ### and -/
|
||||
|
||||
@@ -884,8 +909,8 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· ||| · ) (0#n) where
|
||||
|
||||
@[simp] theorem setWidth_and {x y : BitVec w} :
|
||||
(x &&& y).setWidth k = x.setWidth k &&& y.setWidth k := by
|
||||
ext
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
theorem and_assoc (x y z : BitVec w) :
|
||||
x &&& y &&& z = x &&& (y &&& z) := by
|
||||
@@ -915,15 +940,15 @@ instance : Std.IdempotentOp (α := BitVec n) (· &&& · ) where
|
||||
simp
|
||||
|
||||
@[simp] theorem and_allOnes {x : BitVec w} : x &&& allOnes w = x := by
|
||||
ext i
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) where
|
||||
right_id _ := BitVec.and_allOnes
|
||||
|
||||
@[simp] theorem allOnes_and {x : BitVec w} : allOnes w &&& x = x := by
|
||||
ext i
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
@@ -960,8 +985,8 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) wher
|
||||
|
||||
@[simp] theorem setWidth_xor {x y : BitVec w} :
|
||||
(x ^^^ y).setWidth k = x.setWidth k ^^^ y.setWidth k := by
|
||||
ext
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
theorem xor_assoc (x y z : BitVec w) :
|
||||
x ^^^ y ^^^ z = x ^^^ (y ^^^ z) := by
|
||||
@@ -1054,9 +1079,9 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
rw [Nat.testBit_two_pow_sub_succ x.isLt]
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem setWidth_not {x : BitVec w} (h : k ≤ w) :
|
||||
@[simp] theorem setWidth_not {x : BitVec w} (_ : k ≤ w) :
|
||||
(~~~x).setWidth k = ~~~(x.setWidth k) := by
|
||||
ext
|
||||
ext i h
|
||||
simp [h]
|
||||
omega
|
||||
|
||||
@@ -1069,17 +1094,17 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
simp
|
||||
|
||||
@[simp] theorem xor_allOnes {x : BitVec w} : x ^^^ allOnes w = ~~~ x := by
|
||||
ext i
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem allOnes_xor {x : BitVec w} : allOnes w ^^^ x = ~~~ x := by
|
||||
ext i
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
@[simp]
|
||||
theorem not_not {b : BitVec w} : ~~~(~~~b) = b := by
|
||||
ext i
|
||||
simp
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
||||
constructor
|
||||
@@ -1090,31 +1115,27 @@ theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
||||
rw [h]
|
||||
simp
|
||||
|
||||
@[simp] theorem getMsb_not {x : BitVec w} :
|
||||
(~~~x).getMsbD i = (decide (i < w) && !(x.getMsbD i)) := by
|
||||
simp only [getMsbD]
|
||||
by_cases h : i < w
|
||||
· simp [h]; omega
|
||||
· simp [h];
|
||||
theorem getMsb_not {x : BitVec w} :
|
||||
(~~~x).getMsbD i = (decide (i < w) && !(x.getMsbD i)) := by simp
|
||||
|
||||
@[simp] theorem msb_not {x : BitVec w} : (~~~x).msb = (decide (0 < w) && !x.msb) := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
/-! ### cast -/
|
||||
|
||||
@[simp] theorem not_cast {x : BitVec w} (h : w = w') : ~~~(cast h x) = cast h (~~~x) := by
|
||||
@[simp] theorem not_cast {x : BitVec w} (h : w = w') : ~~~(x.cast h) = (~~~x).cast h := by
|
||||
ext
|
||||
simp_all [lt_of_getLsbD]
|
||||
|
||||
@[simp] theorem and_cast {x y : BitVec w} (h : w = w') : cast h x &&& cast h y = cast h (x &&& y) := by
|
||||
@[simp] theorem and_cast {x y : BitVec w} (h : w = w') : x.cast h &&& y.cast h = (x &&& y).cast h := by
|
||||
ext
|
||||
simp_all [lt_of_getLsbD]
|
||||
|
||||
@[simp] theorem or_cast {x y : BitVec w} (h : w = w') : cast h x ||| cast h y = cast h (x ||| y) := by
|
||||
@[simp] theorem or_cast {x y : BitVec w} (h : w = w') : x.cast h ||| y.cast h = (x ||| y).cast h := by
|
||||
ext
|
||||
simp_all [lt_of_getLsbD]
|
||||
|
||||
@[simp] theorem xor_cast {x y : BitVec w} (h : w = w') : cast h x ^^^ cast h y = cast h (x ^^^ y) := by
|
||||
@[simp] theorem xor_cast {x y : BitVec w} (h : w = w') : x.cast h ^^^ y.cast h = (x ^^^ y).cast h := by
|
||||
ext
|
||||
simp_all [lt_of_getLsbD]
|
||||
|
||||
@@ -1154,24 +1175,21 @@ theorem zero_shiftLeft (n : Nat) : 0#w <<< n = 0#w := by
|
||||
|
||||
theorem shiftLeft_xor_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x ^^^ y) <<< n = (x <<< n) ^^^ (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_xor]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
ext i h
|
||||
simp only [getLsbD_shiftLeft, h, decide_true, Bool.true_and, getLsbD_xor]
|
||||
by_cases h' : i < n <;> simp [h']
|
||||
|
||||
theorem shiftLeft_and_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x &&& y) <<< n = (x <<< n) &&& (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_and]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
ext i h
|
||||
simp only [getLsbD_shiftLeft, h, decide_true, Bool.true_and, getLsbD_and]
|
||||
by_cases h' : i < n <;> simp [h']
|
||||
|
||||
theorem shiftLeft_or_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x ||| y) <<< n = (x <<< n) ||| (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
ext i h
|
||||
simp only [getLsbD_shiftLeft, h, decide_true, Bool.true_and, getLsbD_or]
|
||||
by_cases h' : i < n <;> simp [h']
|
||||
|
||||
@[simp] theorem getMsbD_shiftLeft (x : BitVec w) (i) :
|
||||
(x <<< i).getMsbD k = x.getMsbD (k + i) := by
|
||||
@@ -1216,7 +1234,6 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
|
||||
|
||||
@[simp] theorem getMsbD_shiftLeftZeroExtend (x : BitVec m) (n : Nat) :
|
||||
getMsbD (shiftLeftZeroExtend x n) i = getMsbD x i := by
|
||||
have : n ≤ i + n := by omega
|
||||
simp_all [shiftLeftZeroExtend_eq]
|
||||
|
||||
@[simp] theorem msb_shiftLeftZeroExtend (x : BitVec w) (i : Nat) :
|
||||
@@ -1264,10 +1281,9 @@ theorem getLsbD_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} :
|
||||
(x <<< y).getLsbD i = (decide (i < w₁) && !decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by
|
||||
simp [shiftLeft_eq', getLsbD_shiftLeft]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} (h : i < w₁) :
|
||||
(x <<< y)[i] = (!decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by
|
||||
simp [shiftLeft_eq', getLsbD_shiftLeft]
|
||||
simp
|
||||
|
||||
/-! ### ushiftRight -/
|
||||
|
||||
@@ -1316,6 +1332,61 @@ theorem toNat_ushiftRight_lt (x : BitVec w) (n : Nat) (hn : n ≤ w) :
|
||||
· apply hn
|
||||
· apply Nat.pow_pos (by decide)
|
||||
|
||||
|
||||
/-- Shifting right by `n`, which is larger than the bitwidth `w` produces `0. -/
|
||||
theorem ushiftRight_eq_zero {x : BitVec w} {n : Nat} (hn : w ≤ n) :
|
||||
x >>> n = 0#w := by
|
||||
simp only [toNat_eq, toNat_ushiftRight, toNat_ofNat, Nat.zero_mod]
|
||||
have : 2^w ≤ 2^n := Nat.pow_le_pow_of_le Nat.one_lt_two hn
|
||||
rw [Nat.shiftRight_eq_div_pow, Nat.div_eq_of_lt (by omega)]
|
||||
|
||||
|
||||
/--
|
||||
Unsigned shift right by at least one bit makes the interpretations of the bitvector as an `Int` or `Nat` agree,
|
||||
because it makes the value of the bitvector less than or equal to `2^(w-1)`.
|
||||
-/
|
||||
theorem toInt_ushiftRight_of_lt {x : BitVec w} {n : Nat} (hn : 0 < n) :
|
||||
(x >>> n).toInt = x.toNat >>> n := by
|
||||
rw [toInt_eq_toNat_cond]
|
||||
simp only [toNat_ushiftRight, ite_eq_left_iff, Nat.not_lt]
|
||||
intros h
|
||||
by_cases hn : n ≤ w
|
||||
· have h1 := Nat.mul_lt_mul_of_pos_left (toNat_ushiftRight_lt x n hn) Nat.two_pos
|
||||
simp only [toNat_ushiftRight, Nat.zero_lt_succ, Nat.mul_lt_mul_left] at h1
|
||||
have : 2 ^ (w - n).succ ≤ 2^ w := Nat.pow_le_pow_of_le (by decide) (by omega)
|
||||
have := show 2 * x.toNat >>> n < 2 ^ w by
|
||||
omega
|
||||
omega
|
||||
· have : x.toNat >>> n = 0 := by
|
||||
apply Nat.shiftRight_eq_zero
|
||||
have : 2^w ≤ 2^n := Nat.pow_le_pow_of_le (by decide) (by omega)
|
||||
omega
|
||||
simp [this] at h
|
||||
omega
|
||||
|
||||
/--
|
||||
Unsigned shift right by at least one bit makes the interpretations of the bitvector as an `Int` or `Nat` agree,
|
||||
because it makes the value of the bitvector less than or equal to `2^(w-1)`.
|
||||
In the case when `n = 0`, then the shift right value equals the integer interpretation.
|
||||
-/
|
||||
@[simp]
|
||||
theorem toInt_ushiftRight {x : BitVec w} {n : Nat} :
|
||||
(x >>> n).toInt = if n = 0 then x.toInt else x.toNat >>> n := by
|
||||
by_cases hn : n = 0
|
||||
· simp [hn]
|
||||
· rw [toInt_ushiftRight_of_lt (by omega), toInt_eq_toNat_cond]
|
||||
simp [hn]
|
||||
|
||||
@[simp]
|
||||
theorem toFin_uShiftRight {x : BitVec w} {n : Nat} :
|
||||
(x >>> n).toFin = x.toFin / (Fin.ofNat' (2^w) (2^n)) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
by_cases hn : n < w
|
||||
· simp [Nat.shiftRight_eq_div_pow, Nat.mod_eq_of_lt (Nat.pow_lt_pow_of_lt Nat.one_lt_two hn)]
|
||||
· simp only [Nat.not_lt] at hn
|
||||
rw [ushiftRight_eq_zero (by omega)]
|
||||
simp [Nat.dvd_iff_mod_eq_zero.mp (Nat.pow_dvd_pow 2 hn)]
|
||||
|
||||
@[simp]
|
||||
theorem getMsbD_ushiftRight {x : BitVec w} {i n : Nat} :
|
||||
(x >>> n).getMsbD i = (decide (i < w) && (!decide (i < n) && x.getMsbD (i - n))) := by
|
||||
@@ -1455,12 +1526,12 @@ theorem msb_sshiftRight {n : Nat} {x : BitVec w} :
|
||||
simp [show n = 0 by omega]
|
||||
|
||||
@[simp] theorem sshiftRight_zero {x : BitVec w} : x.sshiftRight 0 = x := by
|
||||
ext i
|
||||
simp [getLsbD_sshiftRight]
|
||||
ext i h
|
||||
simp [getLsbD_sshiftRight, h]
|
||||
|
||||
@[simp] theorem zero_sshiftRight {n : Nat} : (0#w).sshiftRight n = 0#w := by
|
||||
ext i
|
||||
simp [getLsbD_sshiftRight]
|
||||
ext i h
|
||||
simp [getLsbD_sshiftRight, h]
|
||||
|
||||
theorem sshiftRight_add {x : BitVec w} {m n : Nat} :
|
||||
x.sshiftRight (m + n) = (x.sshiftRight m).sshiftRight n := by
|
||||
@@ -1515,39 +1586,25 @@ theorem getMsbD_sshiftRight {x : BitVec w} {i n : Nat} :
|
||||
@[simp]
|
||||
theorem sshiftRight_eq' (x : BitVec w) : x.sshiftRight' y = x.sshiftRight y.toNat := rfl
|
||||
|
||||
@[simp]
|
||||
theorem getLsbD_sshiftRight' {x y: BitVec w} {i : Nat} :
|
||||
-- This should not be a `@[simp]` lemma as the left hand side is not in simp normal form.
|
||||
theorem getLsbD_sshiftRight' {x y : BitVec w} {i : Nat} :
|
||||
getLsbD (x.sshiftRight' y) i =
|
||||
(!decide (w ≤ i) && if y.toNat + i < w then x.getLsbD (y.toNat + i) else x.msb) := by
|
||||
simp only [BitVec.sshiftRight', BitVec.getLsbD_sshiftRight]
|
||||
|
||||
@[simp]
|
||||
-- This should not be a `@[simp]` lemma as the left hand side is not in simp normal form.
|
||||
theorem getElem_sshiftRight' {x y : BitVec w} {i : Nat} (h : i < w) :
|
||||
(x.sshiftRight' y)[i] =
|
||||
(!decide (w ≤ i) && if y.toNat + i < w then x.getLsbD (y.toNat + i) else x.msb) := by
|
||||
simp only [← getLsbD_eq_getElem, BitVec.sshiftRight', BitVec.getLsbD_sshiftRight]
|
||||
|
||||
@[simp]
|
||||
theorem getMsbD_sshiftRight' {x y: BitVec w} {i : Nat} :
|
||||
(x.sshiftRight y.toNat).getMsbD i = (decide (i < w) && if i < y.toNat then x.msb else x.getMsbD (i - y.toNat)) := by
|
||||
simp only [BitVec.sshiftRight', getMsbD, BitVec.getLsbD_sshiftRight]
|
||||
by_cases h : i < w
|
||||
· simp only [h, decide_true, Bool.true_and]
|
||||
by_cases h₁ : w ≤ w - 1 - i
|
||||
· simp [h₁]
|
||||
omega
|
||||
· simp only [h₁, decide_false, Bool.not_false, Bool.true_and]
|
||||
by_cases h₂ : i < y.toNat
|
||||
· simp only [h₂, ↓reduceIte, ite_eq_right_iff]
|
||||
omega
|
||||
· simp only [show i - y.toNat < w by omega, h₂, ↓reduceIte, decide_true, Bool.true_and]
|
||||
by_cases h₄ : y.toNat + (w - 1 - i) < w <;> (simp only [h₄, ↓reduceIte]; congr; omega)
|
||||
· simp [h]
|
||||
(x.sshiftRight y.toNat).getMsbD i =
|
||||
(decide (i < w) && if i < y.toNat then x.msb else x.getMsbD (i - y.toNat)) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem msb_sshiftRight' {x y: BitVec w} :
|
||||
(x.sshiftRight' y).msb = x.msb := by
|
||||
simp [BitVec.sshiftRight', BitVec.msb_sshiftRight]
|
||||
(x.sshiftRight' y).msb = x.msb := by simp
|
||||
|
||||
/-! ### signExtend -/
|
||||
|
||||
@@ -1561,7 +1618,7 @@ private theorem Int.negSucc_emod (m : Nat) (n : Int) :
|
||||
-(m + 1) % n = Int.subNatNat (Int.natAbs n) ((m % Int.natAbs n) + 1) := rfl
|
||||
|
||||
/-- The sign extension is the same as zero extending when `msb = false`. -/
|
||||
theorem signExtend_eq_not_setWidth_not_of_msb_false {x : BitVec w} {v : Nat} (hmsb : x.msb = false) :
|
||||
theorem signExtend_eq_setWidth_of_msb_false {x : BitVec w} {v : Nat} (hmsb : x.msb = false) :
|
||||
x.signExtend v = x.setWidth v := by
|
||||
ext i
|
||||
by_cases hv : i < v
|
||||
@@ -1597,21 +1654,36 @@ theorem signExtend_eq_not_setWidth_not_of_msb_true {x : BitVec w} {v : Nat} (hms
|
||||
theorem getLsbD_signExtend (x : BitVec w) {v i : Nat} :
|
||||
(x.signExtend v).getLsbD i = (decide (i < v) && if i < w then x.getLsbD i else x.msb) := by
|
||||
rcases hmsb : x.msb with rfl | rfl
|
||||
· rw [signExtend_eq_not_setWidth_not_of_msb_false hmsb]
|
||||
· rw [signExtend_eq_setWidth_of_msb_false hmsb]
|
||||
by_cases (i < v) <;> by_cases (i < w) <;> simp_all <;> omega
|
||||
· rw [signExtend_eq_not_setWidth_not_of_msb_true hmsb]
|
||||
by_cases (i < v) <;> by_cases (i < w) <;> simp_all <;> omega
|
||||
|
||||
theorem getMsbD_signExtend {x : BitVec w} {v i : Nat} :
|
||||
(x.signExtend v).getMsbD i =
|
||||
(decide (i < v) && if v - w ≤ i then x.getMsbD (i + w - v) else x.msb) := by
|
||||
rcases hmsb : x.msb with rfl | rfl
|
||||
· simp only [signExtend_eq_setWidth_of_msb_false hmsb, getMsbD_setWidth]
|
||||
by_cases h : v - w ≤ i <;> simp [h, getMsbD] <;> omega
|
||||
· simp only [signExtend_eq_not_setWidth_not_of_msb_true hmsb, getMsbD_not, getMsbD_setWidth]
|
||||
by_cases h : i < v <;> by_cases h' : v - w ≤ i <;> simp [h, h'] <;> omega
|
||||
|
||||
theorem getElem_signExtend {x : BitVec w} {v i : Nat} (h : i < v) :
|
||||
(x.signExtend v)[i] = if i < w then x.getLsbD i else x.msb := by
|
||||
rw [←getLsbD_eq_getElem, getLsbD_signExtend]
|
||||
simp [h]
|
||||
|
||||
theorem msb_signExtend {x : BitVec w} :
|
||||
(x.signExtend v).msb = (decide (0 < v) && if w ≥ v then x.getMsbD (w - v) else x.msb) := by
|
||||
by_cases h : w ≥ v
|
||||
· simp [h, BitVec.msb, getMsbD_signExtend, show v - w = 0 by omega]
|
||||
· simp [h, BitVec.msb, getMsbD_signExtend, show ¬ (v - w = 0) by omega]
|
||||
|
||||
/-- Sign extending to a width smaller than the starting width is a truncation. -/
|
||||
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w):
|
||||
x.signExtend v = x.setWidth v := by
|
||||
ext i
|
||||
simp only [getLsbD_signExtend, Fin.is_lt, decide_true, Bool.true_and, getLsbD_setWidth,
|
||||
ext i h
|
||||
simp only [getLsbD_signExtend, h, decide_true, Bool.true_and, getLsbD_setWidth,
|
||||
ite_eq_left_iff, Nat.not_lt]
|
||||
omega
|
||||
|
||||
@@ -1705,35 +1777,34 @@ theorem append_def (x : BitVec v) (y : BitVec w) :
|
||||
rfl
|
||||
|
||||
theorem getLsbD_append {x : BitVec n} {y : BitVec m} :
|
||||
getLsbD (x ++ y) i = bif i < m then getLsbD y i else getLsbD x (i - m) := by
|
||||
getLsbD (x ++ y) i = if i < m then getLsbD y i else getLsbD x (i - m) := by
|
||||
simp only [append_def, getLsbD_or, getLsbD_shiftLeftZeroExtend, getLsbD_setWidth']
|
||||
by_cases h : i < m
|
||||
· simp [h]
|
||||
· simp_all [h]
|
||||
|
||||
theorem getElem_append {x : BitVec n} {y : BitVec m} (h : i < n + m) :
|
||||
(x ++ y)[i] = bif i < m then getLsbD y i else getLsbD x (i - m) := by
|
||||
(x ++ y)[i] = if i < m then getLsbD y i else getLsbD x (i - m) := by
|
||||
simp only [append_def, getElem_or, getElem_shiftLeftZeroExtend, getElem_setWidth']
|
||||
by_cases h' : i < m
|
||||
· simp [h']
|
||||
· simp_all [h']
|
||||
|
||||
@[simp] theorem getMsbD_append {x : BitVec n} {y : BitVec m} :
|
||||
getMsbD (x ++ y) i = bif n ≤ i then getMsbD y (i - n) else getMsbD x i := by
|
||||
getMsbD (x ++ y) i = if n ≤ i then getMsbD y (i - n) else getMsbD x i := by
|
||||
simp only [append_def]
|
||||
by_cases h : n ≤ i
|
||||
· simp [h]
|
||||
· simp [h]
|
||||
|
||||
theorem msb_append {x : BitVec w} {y : BitVec v} :
|
||||
(x ++ y).msb = bif (w == 0) then (y.msb) else (x.msb) := by
|
||||
(x ++ y).msb = if w = 0 then y.msb else x.msb := by
|
||||
rw [← append_eq, append]
|
||||
simp only [msb_or, msb_shiftLeftZeroExtend, msb_setWidth']
|
||||
by_cases h : w = 0
|
||||
· subst h
|
||||
simp [BitVec.msb, getMsbD]
|
||||
· rw [cond_eq_if]
|
||||
have q : 0 < w + v := by omega
|
||||
· have q : 0 < w + v := by omega
|
||||
have t : y.getLsbD (w + v - 1) = false := getLsbD_ge _ _ (by omega)
|
||||
simp [h, q, t, BitVec.msb, getMsbD]
|
||||
|
||||
@@ -1742,17 +1813,17 @@ theorem msb_append {x : BitVec w} {y : BitVec v} :
|
||||
rw [getLsbD_append] -- Why does this not work with `simp [getLsbD_append]`?
|
||||
simp
|
||||
|
||||
@[simp] theorem zero_width_append (x : BitVec 0) (y : BitVec v) : x ++ y = cast (by omega) y := by
|
||||
@[simp] theorem zero_width_append (x : BitVec 0) (y : BitVec v) : x ++ y = y.cast (by omega) := by
|
||||
ext
|
||||
rw [getLsbD_append]
|
||||
simpa using lt_of_getLsbD
|
||||
|
||||
@[simp] theorem zero_append_zero : 0#v ++ 0#w = 0#(v + w) := by
|
||||
ext
|
||||
simp only [getLsbD_append, getLsbD_zero, Bool.cond_self]
|
||||
simp only [getLsbD_append, getLsbD_zero, ite_self]
|
||||
|
||||
@[simp] theorem cast_append_right (h : w + v = w + v') (x : BitVec w) (y : BitVec v) :
|
||||
cast h (x ++ y) = x ++ cast (by omega) y := by
|
||||
(x ++ y).cast h = x ++ y.cast (by omega) := by
|
||||
ext
|
||||
simp only [getLsbD_cast, getLsbD_append, cond_eq_if, decide_eq_true_eq]
|
||||
split <;> split
|
||||
@@ -1763,33 +1834,30 @@ theorem msb_append {x : BitVec w} {y : BitVec v} :
|
||||
omega
|
||||
|
||||
@[simp] theorem cast_append_left (h : w + v = w' + v) (x : BitVec w) (y : BitVec v) :
|
||||
cast h (x ++ y) = cast (by omega) x ++ y := by
|
||||
(x ++ y).cast h = x.cast (by omega) ++ y := by
|
||||
ext
|
||||
simp [getLsbD_append]
|
||||
|
||||
theorem setWidth_append {x : BitVec w} {y : BitVec v} :
|
||||
(x ++ y).setWidth k = if h : k ≤ v then y.setWidth k else (x.setWidth (k - v) ++ y).cast (by omega) := by
|
||||
apply eq_of_getLsbD_eq
|
||||
intro i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, Bool.true_and]
|
||||
split
|
||||
· have t : i < v := by omega
|
||||
simp [t]
|
||||
· by_cases t : i < v
|
||||
· simp [t, getLsbD_append]
|
||||
· have t' : i - v < k - v := by omega
|
||||
simp [t, t', getLsbD_append]
|
||||
ext i h
|
||||
simp only [getLsbD_setWidth, h, getLsbD_append]
|
||||
split <;> rename_i h₁ <;> split <;> rename_i h₂
|
||||
· simp [h]
|
||||
· simp [getLsbD_append, h₁]
|
||||
· omega
|
||||
· simp [getLsbD_append, h₁]
|
||||
omega
|
||||
|
||||
@[simp] theorem setWidth_append_of_eq {x : BitVec v} {y : BitVec w} (h : w' = w) : setWidth (v' + w') (x ++ y) = setWidth v' x ++ setWidth w' y := by
|
||||
subst h
|
||||
ext i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, cond_eq_if,
|
||||
ext i h
|
||||
simp only [getLsbD_setWidth, h, decide_true, getLsbD_append, cond_eq_if,
|
||||
decide_eq_true_eq, Bool.true_and, setWidth_eq]
|
||||
split
|
||||
· simp_all
|
||||
· simp_all only [Bool.iff_and_self, decide_eq_true_eq]
|
||||
intro h
|
||||
have := BitVec.lt_of_getLsbD h
|
||||
omega
|
||||
|
||||
@[simp] theorem setWidth_cons {x : BitVec w} : (cons a x).setWidth w = x := by
|
||||
@@ -1833,12 +1901,12 @@ theorem shiftLeft_ushiftRight {x : BitVec w} {n : Nat}:
|
||||
case succ n ih =>
|
||||
rw [BitVec.shiftLeft_add, Nat.add_comm, BitVec.shiftRight_add, ih,
|
||||
Nat.add_comm, BitVec.shiftLeft_add, BitVec.shiftLeft_and_distrib]
|
||||
ext i
|
||||
ext i h
|
||||
by_cases hw : w = 0
|
||||
· simp [hw]
|
||||
· by_cases hi₂ : i.val = 0
|
||||
· by_cases hi₂ : i = 0
|
||||
· simp [hi₂]
|
||||
· simp [Nat.lt_one_iff, hi₂, show 1 + (i.val - 1) = i by omega]
|
||||
· simp [Nat.lt_one_iff, hi₂, h, show 1 + (i - 1) = i by omega]
|
||||
|
||||
@[simp]
|
||||
theorem msb_shiftLeft {x : BitVec w} {n : Nat} :
|
||||
@@ -1923,13 +1991,12 @@ theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
|
||||
|
||||
theorem setWidth_succ (x : BitVec w) :
|
||||
setWidth (i+1) x = cons (getLsbD x i) (setWidth i x) := by
|
||||
apply eq_of_getLsbD_eq
|
||||
intro j
|
||||
simp only [getLsbD_setWidth, getLsbD_cons, j.isLt, decide_true, Bool.true_and]
|
||||
if j_eq : j.val = i then
|
||||
ext j h
|
||||
simp only [getLsbD_setWidth, getLsbD_cons, h, decide_true, Bool.true_and]
|
||||
if j_eq : j = i then
|
||||
simp [j_eq]
|
||||
else
|
||||
have j_lt : j.val < i := Nat.lt_of_le_of_ne (Nat.le_of_succ_le_succ j.isLt) j_eq
|
||||
have j_lt : j < i := Nat.lt_of_le_of_ne (Nat.le_of_succ_le_succ h) j_eq
|
||||
simp [j_eq, j_lt]
|
||||
|
||||
@[simp] theorem cons_msb_setWidth (x : BitVec (w+1)) : (cons x.msb (x.setWidth w)) = x := by
|
||||
@@ -1998,74 +2065,11 @@ theorem getElem_concat (x : BitVec w) (b : Bool) (i : Nat) (h : i < w + 1) :
|
||||
@[simp] theorem getLsbD_concat_succ : (concat x b).getLsbD (i + 1) = x.getLsbD i := by
|
||||
simp [getLsbD_concat]
|
||||
|
||||
@[simp] theorem getElem_concat_succ {x : BitVec w} {i : Nat} (h : i < w) :
|
||||
@[simp] theorem getElem_concat_succ {x : BitVec w} {i : Nat} (h : i + 1 < w + 1) :
|
||||
(concat x b)[i + 1] = x[i] := by
|
||||
simp only [Nat.add_lt_add_iff_right] at h
|
||||
simp [getElem_concat, h, getLsbD_eq_getElem]
|
||||
|
||||
@[simp] theorem not_concat (x : BitVec w) (b : Bool) : ~~~(concat x b) = concat (~~~x) !b := by
|
||||
ext i; cases i using Fin.succRecOn <;> simp [*, Nat.succ_lt_succ]
|
||||
|
||||
@[simp] theorem concat_or_concat (x y : BitVec w) (a b : Bool) :
|
||||
(concat x a) ||| (concat y b) = concat (x ||| y) (a || b) := by
|
||||
ext i; cases i using Fin.succRecOn <;> simp
|
||||
|
||||
@[simp] theorem concat_and_concat (x y : BitVec w) (a b : Bool) :
|
||||
(concat x a) &&& (concat y b) = concat (x &&& y) (a && b) := by
|
||||
ext i; cases i using Fin.succRecOn <;> simp
|
||||
|
||||
@[simp] theorem concat_xor_concat (x y : BitVec w) (a b : Bool) :
|
||||
(concat x a) ^^^ (concat y b) = concat (x ^^^ y) (a ^^ b) := by
|
||||
ext i; cases i using Fin.succRecOn <;> simp
|
||||
|
||||
/-! ### shiftConcat -/
|
||||
|
||||
theorem getLsbD_shiftConcat (x : BitVec w) (b : Bool) (i : Nat) :
|
||||
(shiftConcat x b).getLsbD i
|
||||
= (decide (i < w) && (if (i = 0) then b else x.getLsbD (i - 1))) := by
|
||||
simp only [shiftConcat, getLsbD_setWidth, getLsbD_concat]
|
||||
|
||||
theorem getLsbD_shiftConcat_eq_decide (x : BitVec w) (b : Bool) (i : Nat) :
|
||||
(shiftConcat x b).getLsbD i
|
||||
= (decide (i < w) && ((decide (i = 0) && b) || (decide (0 < i) && x.getLsbD (i - 1)))) := by
|
||||
simp only [getLsbD_shiftConcat]
|
||||
split <;> simp [*, show ((0 < i) ↔ ¬(i = 0)) by omega]
|
||||
|
||||
theorem shiftRight_sub_one_eq_shiftConcat (n : BitVec w) (hwn : 0 < wn) :
|
||||
n >>> (wn - 1) = (n >>> wn).shiftConcat (n.getLsbD (wn - 1)) := by
|
||||
ext i
|
||||
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, Fin.is_lt, decide_true, Bool.true_and]
|
||||
split
|
||||
· simp [*]
|
||||
· congr 1; omega
|
||||
|
||||
@[simp, bv_toNat]
|
||||
theorem toNat_shiftConcat {x : BitVec w} {b : Bool} :
|
||||
(x.shiftConcat b).toNat
|
||||
= (x.toNat <<< 1 + b.toNat) % 2 ^ w := by
|
||||
simp [shiftConcat, Nat.shiftLeft_eq]
|
||||
|
||||
/-- `x.shiftConcat b` does not overflow if `x < 2^k` for `k < w`, and so
|
||||
`x.shiftConcat b |>.toNat = x.toNat * 2 + b.toNat`. -/
|
||||
theorem toNat_shiftConcat_eq_of_lt {x : BitVec w} {b : Bool} {k : Nat}
|
||||
(hk : k < w) (hx : x.toNat < 2 ^ k) :
|
||||
(x.shiftConcat b).toNat = x.toNat * 2 + b.toNat := by
|
||||
simp only [toNat_shiftConcat, Nat.shiftLeft_eq, Nat.pow_one]
|
||||
have : 2 ^ k < 2 ^ w := Nat.pow_lt_pow_of_lt (by omega) (by omega)
|
||||
have : 2 ^ k * 2 ≤ 2 ^ w := (Nat.pow_lt_pow_iff_pow_mul_le_pow (by omega)).mp this
|
||||
rw [Nat.mod_eq_of_lt (by cases b <;> simp [bv_toNat] <;> omega)]
|
||||
|
||||
theorem toNat_shiftConcat_lt_of_lt {x : BitVec w} {b : Bool} {k : Nat}
|
||||
(hk : k < w) (hx : x.toNat < 2 ^ k) :
|
||||
(x.shiftConcat b).toNat < 2 ^ (k + 1) := by
|
||||
rw [toNat_shiftConcat_eq_of_lt hk hx]
|
||||
have : 2 ^ (k + 1) ≤ 2 ^ w := Nat.pow_le_pow_of_le_right (by decide) (by assumption)
|
||||
have := Bool.toNat_lt b
|
||||
omega
|
||||
|
||||
@[simp] theorem zero_concat_false : concat 0#w false = 0#(w + 1) := by
|
||||
ext
|
||||
simp [getLsbD_concat]
|
||||
|
||||
@[simp]
|
||||
theorem getMsbD_concat {i w : Nat} {b : Bool} {x : BitVec w} :
|
||||
(x.concat b).getMsbD i = if i < w then x.getMsbD i else decide (i = w) && b := by
|
||||
@@ -2091,6 +2095,84 @@ theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
|
||||
omega
|
||||
· simp [h₀, show w = 0 by omega]
|
||||
|
||||
@[simp] theorem toInt_concat (x : BitVec w) (b : Bool) :
|
||||
(concat x b).toInt = if w = 0 then -b.toInt else x.toInt * 2 + b.toInt := by
|
||||
simp only [BitVec.toInt, toNat_concat]
|
||||
cases w
|
||||
· cases b <;> simp [eq_nil x]
|
||||
· cases b <;> simp <;> omega
|
||||
|
||||
@[simp] theorem toFin_concat (x : BitVec w) (b : Bool) :
|
||||
(concat x b).toFin = Fin.mk (x.toNat * 2 + b.toNat) (by
|
||||
have := Bool.toNat_lt b
|
||||
simp [← Nat.two_pow_pred_add_two_pow_pred, Bool.toNat_lt b]
|
||||
omega
|
||||
) := by
|
||||
simp [← Fin.val_inj]
|
||||
|
||||
@[simp] theorem not_concat (x : BitVec w) (b : Bool) : ~~~(concat x b) = concat (~~~x) !b := by
|
||||
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||
|
||||
@[simp] theorem concat_or_concat (x y : BitVec w) (a b : Bool) :
|
||||
(concat x a) ||| (concat y b) = concat (x ||| y) (a || b) := by
|
||||
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||
|
||||
@[simp] theorem concat_and_concat (x y : BitVec w) (a b : Bool) :
|
||||
(concat x a) &&& (concat y b) = concat (x &&& y) (a && b) := by
|
||||
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||
|
||||
@[simp] theorem concat_xor_concat (x y : BitVec w) (a b : Bool) :
|
||||
(concat x a) ^^^ (concat y b) = concat (x ^^^ y) (a ^^ b) := by
|
||||
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||
|
||||
@[simp] theorem zero_concat_false : concat 0#w false = 0#(w + 1) := by
|
||||
ext
|
||||
simp [getLsbD_concat]
|
||||
|
||||
/-! ### shiftConcat -/
|
||||
|
||||
theorem getLsbD_shiftConcat (x : BitVec w) (b : Bool) (i : Nat) :
|
||||
(shiftConcat x b).getLsbD i
|
||||
= (decide (i < w) && (if (i = 0) then b else x.getLsbD (i - 1))) := by
|
||||
simp only [shiftConcat, getLsbD_setWidth, getLsbD_concat]
|
||||
|
||||
theorem getLsbD_shiftConcat_eq_decide (x : BitVec w) (b : Bool) (i : Nat) :
|
||||
(shiftConcat x b).getLsbD i
|
||||
= (decide (i < w) && ((decide (i = 0) && b) || (decide (0 < i) && x.getLsbD (i - 1)))) := by
|
||||
simp only [getLsbD_shiftConcat]
|
||||
split <;> simp [*, show ((0 < i) ↔ ¬(i = 0)) by omega]
|
||||
|
||||
theorem shiftRight_sub_one_eq_shiftConcat (n : BitVec w) (hwn : 0 < wn) :
|
||||
n >>> (wn - 1) = (n >>> wn).shiftConcat (n.getLsbD (wn - 1)) := by
|
||||
ext i h
|
||||
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, h, decide_true, Bool.true_and]
|
||||
split
|
||||
· simp [*]
|
||||
· congr 1; omega
|
||||
|
||||
@[simp, bv_toNat]
|
||||
theorem toNat_shiftConcat {x : BitVec w} {b : Bool} :
|
||||
(x.shiftConcat b).toNat
|
||||
= (x.toNat <<< 1 + b.toNat) % 2 ^ w := by
|
||||
simp [shiftConcat, Nat.shiftLeft_eq]
|
||||
|
||||
/-- `x.shiftConcat b` does not overflow if `x < 2^k` for `k < w`, and so
|
||||
`x.shiftConcat b |>.toNat = x.toNat * 2 + b.toNat`. -/
|
||||
theorem toNat_shiftConcat_eq_of_lt {x : BitVec w} {b : Bool} {k : Nat}
|
||||
(hk : k < w) (hx : x.toNat < 2 ^ k) :
|
||||
(x.shiftConcat b).toNat = x.toNat * 2 + b.toNat := by
|
||||
simp only [toNat_shiftConcat, Nat.shiftLeft_eq, Nat.pow_one]
|
||||
have : 2 ^ k < 2 ^ w := Nat.pow_lt_pow_of_lt (by omega) (by omega)
|
||||
have : 2 ^ k * 2 ≤ 2 ^ w := (Nat.pow_lt_pow_iff_pow_mul_le_pow (by omega)).mp this
|
||||
rw [Nat.mod_eq_of_lt (by cases b <;> simp [bv_toNat] <;> omega)]
|
||||
|
||||
theorem toNat_shiftConcat_lt_of_lt {x : BitVec w} {b : Bool} {k : Nat}
|
||||
(hk : k < w) (hx : x.toNat < 2 ^ k) :
|
||||
(x.shiftConcat b).toNat < 2 ^ (k + 1) := by
|
||||
rw [toNat_shiftConcat_eq_of_lt hk hx]
|
||||
have := Bool.toNat_lt b
|
||||
omega
|
||||
|
||||
/-! ### add -/
|
||||
|
||||
theorem add_def {n} (x y : BitVec n) : x + y = .ofNat n (x.toNat + y.toNat) := rfl
|
||||
@@ -2596,7 +2678,7 @@ theorem smtSDiv_eq (x y : BitVec w) : smtSDiv x y =
|
||||
|
||||
@[simp]
|
||||
theorem smtSDiv_zero {x : BitVec n} : x.smtSDiv 0#n = if x.slt 0#n then 1#n else (allOnes n) := by
|
||||
rcases hx : x.msb <;> simp [smtSDiv, slt_zero_iff_msb_cond x, hx, ← negOne_eq_allOnes]
|
||||
rcases hx : x.msb <;> simp [smtSDiv, slt_zero_iff_msb_cond, hx, ← negOne_eq_allOnes]
|
||||
|
||||
/-! ### srem -/
|
||||
|
||||
@@ -2916,10 +2998,10 @@ theorem getMsbD_rotateRightAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i
|
||||
simp [rotateRightAux, show ¬ i < r by omega, show i + (w - r) ≥ w by omega]
|
||||
|
||||
/-- When `m < w`, we give a formula for `(x.rotateLeft m).getMsbD i`. -/
|
||||
@[simp]
|
||||
theorem getMsbD_rotateRight_of_lt {w n m : Nat} {x : BitVec w} (hr : m < w):
|
||||
-- This should not be a simp lemma as `getMsbD_rotateRight` will apply first.
|
||||
theorem getMsbD_rotateRight_of_lt {w n m : Nat} {x : BitVec w} (hr : m < w) :
|
||||
(x.rotateRight m).getMsbD n = (decide (n < w) && (if (n < m % w)
|
||||
then x.getMsbD ((w + n - m % w) % w) else x.getMsbD (n - m % w))):= by
|
||||
then x.getMsbD ((w + n - m % w) % w) else x.getMsbD (n - m % w))) := by
|
||||
rcases w with rfl | w
|
||||
· simp
|
||||
· rw [rotateRight_eq_rotateRightAux_of_lt (by omega)]
|
||||
@@ -3073,8 +3155,8 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_of_getLsbD_false
|
||||
{x : BitVec w} {i : Nat} (hx : x.getLsbD i = false) :
|
||||
setWidth w (x.setWidth (i + 1)) =
|
||||
setWidth w (x.setWidth i) := by
|
||||
ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
ext k h
|
||||
simp only [getLsbD_setWidth, h, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
@@ -3089,20 +3171,17 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true
|
||||
{x : BitVec w} {i : Nat} (hx : x.getLsbD i = true) :
|
||||
setWidth w (x.setWidth (i + 1)) =
|
||||
setWidth w (x.setWidth i) ||| (twoPow w i) := by
|
||||
ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
ext k h
|
||||
simp only [getLsbD_setWidth, h, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
simp [hx, h]
|
||||
· by_cases hik' : k < i + 1 <;> simp [hik, hik'] <;> omega
|
||||
|
||||
/-- Bitwise and of `(x : BitVec w)` with `1#w` equals zero extending `x.lsb` to `w`. -/
|
||||
theorem and_one_eq_setWidth_ofBool_getLsbD {x : BitVec w} :
|
||||
(x &&& 1#w) = setWidth w (ofBool (x.getLsbD 0)) := by
|
||||
ext i
|
||||
simp only [getLsbD_and, getLsbD_one, getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_ofBool,
|
||||
Bool.true_and]
|
||||
by_cases h : ((i : Nat) = 0) <;> simp [h] <;> omega
|
||||
ext (_ | i) h <;> simp [Bool.and_comm]
|
||||
|
||||
@[simp]
|
||||
theorem replicate_zero_eq {x : BitVec w} : x.replicate 0 = 0#0 := by
|
||||
@@ -3126,7 +3205,7 @@ theorem getLsbD_replicate {n w : Nat} (x : BitVec w) :
|
||||
· simp only [hi, decide_true, Bool.true_and]
|
||||
by_cases hi' : i < w * n
|
||||
· simp [hi', ih]
|
||||
· simp only [hi', decide_false, cond_false]
|
||||
· simp [hi', decide_false]
|
||||
rw [Nat.sub_mul_eq_mod_of_lt_of_le] <;> omega
|
||||
· rw [Nat.mul_succ] at hi ⊢
|
||||
simp only [show ¬i < w * n by omega, decide_false, cond_false, hi, Bool.false_and]
|
||||
@@ -3432,7 +3511,7 @@ theorem forall_zero_iff {P : BitVec 0 → Prop} :
|
||||
· intro h
|
||||
apply h
|
||||
· intro h v
|
||||
obtain (rfl : v = 0#0) := (by ext ⟨i, h⟩; simp at h)
|
||||
obtain (rfl : v = 0#0) := (by ext i ⟨⟩)
|
||||
apply h
|
||||
|
||||
theorem forall_cons_iff {P : BitVec (n + 1) → Prop} :
|
||||
@@ -3448,7 +3527,7 @@ theorem forall_cons_iff {P : BitVec (n + 1) → Prop} :
|
||||
instance instDecidableForallBitVecZero (P : BitVec 0 → Prop) :
|
||||
∀ [Decidable (P 0#0)], Decidable (∀ v, P v)
|
||||
| .isTrue h => .isTrue fun v => by
|
||||
obtain (rfl : v = 0#0) := (by ext ⟨i, h⟩; cases h)
|
||||
obtain (rfl : v = 0#0) := (by ext i ⟨⟩)
|
||||
exact h
|
||||
| .isFalse h => .isFalse (fun w => h (w _))
|
||||
|
||||
@@ -3485,14 +3564,15 @@ Note, however, that for large numerals the decision procedure may be very slow.
|
||||
instance instDecidableExistsBitVec :
|
||||
∀ (n : Nat) (P : BitVec n → Prop) [DecidablePred P], Decidable (∃ v, P v)
|
||||
| 0, _, _ => inferInstance
|
||||
| n + 1, _, _ =>
|
||||
have := instDecidableExistsBitVec n
|
||||
inferInstance
|
||||
| _ + 1, _, _ => inferInstance
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
set_option linter.missingDocs false
|
||||
|
||||
@[deprecated signExtend_eq_setWidth_of_msb_false (since := "2024-12-08")]
|
||||
abbrev signExtend_eq_not_setWidth_not_of_msb_false := @signExtend_eq_setWidth_of_msb_false
|
||||
|
||||
@[deprecated truncate_eq_setWidth (since := "2024-09-18")]
|
||||
abbrev truncate_eq_zeroExtend := @truncate_eq_setWidth
|
||||
|
||||
@@ -3595,8 +3675,8 @@ abbrev truncate_xor := @setWidth_xor
|
||||
@[deprecated setWidth_not (since := "2024-09-18")]
|
||||
abbrev truncate_not := @setWidth_not
|
||||
|
||||
@[deprecated signExtend_eq_not_setWidth_not_of_msb_false (since := "2024-09-18")]
|
||||
abbrev signExtend_eq_not_zeroExtend_not_of_msb_false := @signExtend_eq_not_setWidth_not_of_msb_false
|
||||
@[deprecated signExtend_eq_setWidth_of_msb_false (since := "2024-09-18")]
|
||||
abbrev signExtend_eq_not_zeroExtend_not_of_msb_false := @signExtend_eq_setWidth_of_msb_false
|
||||
|
||||
@[deprecated signExtend_eq_not_setWidth_not_of_msb_true (since := "2024-09-18")]
|
||||
abbrev signExtend_eq_not_zeroExtend_not_of_msb_true := @signExtend_eq_not_setWidth_not_of_msb_true
|
||||
|
||||
@@ -225,7 +225,7 @@ theorem bne_not_self : ∀ (x : Bool), (x != !x) = true := by decide
|
||||
Added for equivalence with `Bool.not_beq_self` and needed for confluence
|
||||
due to `beq_iff_eq`.
|
||||
-/
|
||||
@[simp] theorem not_eq_self : ∀(b : Bool), ((!b) = b) ↔ False := by decide
|
||||
theorem not_eq_self : ∀(b : Bool), ((!b) = b) ↔ False := by simp
|
||||
@[simp] theorem eq_not_self : ∀(b : Bool), (b = (!b)) ↔ False := by decide
|
||||
|
||||
@[simp] theorem beq_self_left : ∀(a b : Bool), (a == (a == b)) = b := by decide
|
||||
@@ -384,6 +384,15 @@ theorem toNat_lt (b : Bool) : b.toNat < 2 :=
|
||||
@[simp] theorem toNat_eq_one {b : Bool} : b.toNat = 1 ↔ b = true := by
|
||||
cases b <;> simp
|
||||
|
||||
/-! ## toInt -/
|
||||
|
||||
/-- convert a `Bool` to an `Int`, `false -> 0`, `true -> 1` -/
|
||||
def toInt (b : Bool) : Int := cond b 1 0
|
||||
|
||||
@[simp] theorem toInt_false : false.toInt = 0 := rfl
|
||||
|
||||
@[simp] theorem toInt_true : true.toInt = 1 := rfl
|
||||
|
||||
/-! ### ite -/
|
||||
|
||||
@[simp] theorem if_true_left (p : Prop) [h : Decidable p] (f : Bool) :
|
||||
@@ -411,7 +420,7 @@ theorem toNat_lt (b : Bool) : b.toNat < 2 :=
|
||||
|
||||
@[simp] theorem ite_eq_true_else_eq_false {q : Prop} :
|
||||
(if b = true then q else b = false) ↔ (b = true → q) := by
|
||||
cases b <;> simp
|
||||
cases b <;> simp [not_eq_self]
|
||||
|
||||
/-
|
||||
`not_ite_eq_true_eq_true` and related theorems below are added for
|
||||
|
||||
@@ -8,6 +8,8 @@ import Init.Data.Queue
|
||||
import Init.System.Promise
|
||||
import Init.System.Mutex
|
||||
|
||||
set_option linter.deprecated false
|
||||
|
||||
namespace IO
|
||||
|
||||
/--
|
||||
@@ -15,6 +17,7 @@ Internal state of an `Channel`.
|
||||
|
||||
We maintain the invariant that at all times either `consumers` or `values` is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.State from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
structure Channel.State (α : Type) where
|
||||
values : Std.Queue α := ∅
|
||||
consumers : Std.Queue (Promise (Option α)) := ∅
|
||||
@@ -27,12 +30,14 @@ FIFO channel with unbounded buffer, where `recv?` returns a `Task`.
|
||||
A channel can be closed. Once it is closed, all `send`s are ignored, and
|
||||
`recv?` returns `none` once the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel (α : Type) : Type := Mutex (Channel.State α)
|
||||
|
||||
instance : Nonempty (Channel α) :=
|
||||
inferInstanceAs (Nonempty (Mutex _))
|
||||
|
||||
/-- Creates a new `Channel`. -/
|
||||
@[deprecated "Use Std.Channel.new from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.new : BaseIO (Channel α) :=
|
||||
Mutex.new {}
|
||||
|
||||
@@ -41,6 +46,7 @@ Sends a message on an `Channel`.
|
||||
|
||||
This function does not block.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.send from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
@@ -54,6 +60,7 @@ def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
|
||||
/--
|
||||
Closes an `Channel`.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.close from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.close (ch : Channel α) : BaseIO Unit :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
@@ -67,6 +74,7 @@ Every message is only received once.
|
||||
|
||||
Returns `none` if the channel is closed and the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
@@ -85,6 +93,7 @@ def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
|
||||
|
||||
Note that if this function is called twice, each `forAsync` only gets half the messages.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.forAsync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
partial def Channel.forAsync (f : α → BaseIO Unit) (ch : Channel α)
|
||||
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
|
||||
BaseIO.bindTask (prio := prio) (← ch.recv?) fun
|
||||
@@ -96,11 +105,13 @@ Receives all currently queued messages from the channel.
|
||||
|
||||
Those messages are dequeued and will not be returned by `recv?`.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.recvAllCurrent from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.recvAllCurrent (ch : Channel α) : BaseIO (Array α) :=
|
||||
ch.atomically do
|
||||
modifyGet fun st => (st.values.toArray, { st with values := ∅ })
|
||||
|
||||
/-- Type tag for synchronous (blocking) operations on a `Channel`. -/
|
||||
@[deprecated "Use Std.Channel.Sync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.Sync := Channel
|
||||
|
||||
/--
|
||||
@@ -110,6 +121,7 @@ For example, `ch.sync.recv?` blocks until the next message,
|
||||
and `for msg in ch.sync do ...` iterates synchronously over the channel.
|
||||
These functions should only be used in dedicated threads.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.sync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.sync (ch : Channel α) : Channel.Sync α := ch
|
||||
|
||||
/--
|
||||
@@ -118,9 +130,11 @@ Synchronously receives a message from the channel.
|
||||
Every message is only received once.
|
||||
Returns `none` if the channel is closed and the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.Sync.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.Sync.recv? (ch : Channel.Sync α) : BaseIO (Option α) := do
|
||||
IO.wait (← Channel.recv? ch)
|
||||
|
||||
@[deprecated "Use Std.Channel.Sync.forIn from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
private partial def Channel.Sync.forIn [Monad m] [MonadLiftT BaseIO m]
|
||||
(ch : Channel.Sync α) (f : α → β → m (ForInStep β)) : β → m β := fun b => do
|
||||
match ← ch.recv? with
|
||||
|
||||
@@ -9,6 +9,9 @@ import Init.Data.UInt.Lemmas
|
||||
|
||||
namespace Char
|
||||
|
||||
@[ext] protected theorem ext : {a b : Char} → a.val = b.val → a = b
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl => rfl
|
||||
|
||||
theorem le_def {a b : Char} : a ≤ b ↔ a.1 ≤ b.1 := .rfl
|
||||
theorem lt_def {a b : Char} : a < b ↔ a.1 < b.1 := .rfl
|
||||
theorem lt_iff_val_lt_val {a b : Char} : a < b ↔ a.val < b.val := Iff.rfl
|
||||
@@ -19,9 +22,44 @@ theorem lt_iff_val_lt_val {a b : Char} : a < b ↔ a.val < b.val := Iff.rfl
|
||||
protected theorem le_trans {a b c : Char} : a ≤ b → b ≤ c → a ≤ c := UInt32.le_trans
|
||||
protected theorem lt_trans {a b c : Char} : a < b → b < c → a < c := UInt32.lt_trans
|
||||
protected theorem le_total (a b : Char) : a ≤ b ∨ b ≤ a := UInt32.le_total a.1 b.1
|
||||
protected theorem le_antisymm {a b : Char} : a ≤ b → b ≤ a → a = b :=
|
||||
fun h₁ h₂ => Char.ext (UInt32.le_antisymm h₁ h₂)
|
||||
protected theorem lt_asymm {a b : Char} (h : a < b) : ¬ b < a := UInt32.lt_asymm h
|
||||
protected theorem ne_of_lt {a b : Char} (h : a < b) : a ≠ b := Char.ne_of_val_ne (UInt32.ne_of_lt h)
|
||||
|
||||
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 ltTrans : Trans (· < · : Char → Char → Prop) (· < ·) (· < ·) where
|
||||
trans := Char.lt_trans
|
||||
|
||||
-- This instance is useful while setting up instances for `String`.
|
||||
def notLTTrans : Trans (¬ · < · : Char → Char → Prop) (¬ · < ·) (¬ · < ·) where
|
||||
trans h₁ h₂ := by simpa using Char.le_trans (by simpa using h₂) (by simpa using h₁)
|
||||
|
||||
instance leAntisymm : Std.Antisymm (· ≤ · : Char → Char → Prop) where
|
||||
antisymm _ _ := Char.le_antisymm
|
||||
|
||||
-- This instance is useful while setting up instances for `String`.
|
||||
def notLTAntisymm : Std.Antisymm (¬ · < · : Char → Char → Prop) where
|
||||
antisymm _ _ h₁ h₂ := Char.le_antisymm (by simpa using h₂) (by simpa using h₁)
|
||||
|
||||
instance ltAsymm : Std.Asymm (· < · : Char → Char → Prop) where
|
||||
asymm _ _ := Char.lt_asymm
|
||||
|
||||
instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
|
||||
total := Char.le_total
|
||||
|
||||
-- This instance is useful while setting up instances for `String`.
|
||||
def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
|
||||
total := fun x y => by simpa using Char.le_total y x
|
||||
|
||||
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
have := c.utf8Size_pos
|
||||
have := c.utf8Size_le_four
|
||||
@@ -31,9 +69,6 @@ theorem utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Siz
|
||||
rw [Char.ofNat, dif_pos]
|
||||
rfl
|
||||
|
||||
@[ext] protected theorem ext : {a b : Char} → a.val = b.val → a = b
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl => rfl
|
||||
|
||||
end Char
|
||||
|
||||
@[deprecated Char.utf8Size (since := "2024-06-04")] abbrev String.csize := Char.utf8Size
|
||||
|
||||
@@ -176,7 +176,7 @@ protected theorem pos (i : Fin n) : 0 < n :=
|
||||
@[inline] def castLE (h : n ≤ m) (i : Fin n) : Fin m := ⟨i, Nat.lt_of_lt_of_le i.2 h⟩
|
||||
|
||||
/-- `cast eq i` embeds `i` into an equal `Fin` type. -/
|
||||
@[inline] def cast (eq : n = m) (i : Fin n) : Fin m := ⟨i, eq ▸ i.2⟩
|
||||
@[inline] protected def cast (eq : n = m) (i : Fin n) : Fin m := ⟨i, eq ▸ i.2⟩
|
||||
|
||||
/-- `castAdd m i` embeds `i : Fin n` in `Fin (n+m)`. See also `Fin.natAdd` and `Fin.addNat`. -/
|
||||
@[inline] def castAdd (m) : Fin n → Fin (n + m) :=
|
||||
|
||||
@@ -13,14 +13,14 @@ namespace Fin
|
||||
/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/
|
||||
@[inline] def foldl (n) (f : α → Fin n → α) (init : α) : α := loop init 0 where
|
||||
/-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/
|
||||
@[semireducible] loop (x : α) (i : Nat) : α :=
|
||||
@[semireducible, specialize] loop (x : α) (i : Nat) : α :=
|
||||
if h : i < n then loop (f x ⟨i, h⟩) (i+1) else x
|
||||
termination_by n - i
|
||||
|
||||
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
|
||||
@[inline] def foldr (n) (f : Fin n → α → α) (init : α) : α := loop n (Nat.le_refl n) init where
|
||||
/-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/
|
||||
loop : (i : _) → i ≤ n → α → α
|
||||
@[specialize] loop : (i : _) → i ≤ n → α → α
|
||||
| 0, _, x => x
|
||||
| i+1, h, x => loop i (Nat.le_of_lt h) (f ⟨i, h⟩ x)
|
||||
termination_by structural i => i
|
||||
@@ -47,7 +47,7 @@ Fin.foldlM n f x₀ = do
|
||||
pure xₙ
|
||||
```
|
||||
-/
|
||||
loop (x : α) (i : Nat) : m α := do
|
||||
@[semireducible, specialize] loop (x : α) (i : Nat) : m α := do
|
||||
if h : i < n then f x ⟨i, h⟩ >>= (loop · (i+1)) else pure x
|
||||
termination_by n - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
@@ -76,7 +76,7 @@ Fin.foldrM n f xₙ = do
|
||||
pure x₀
|
||||
```
|
||||
-/
|
||||
loop : {i // i ≤ n} → α → m α
|
||||
@[semireducible, specialize] loop : {i // i ≤ n} → α → m α
|
||||
| ⟨0, _⟩, x => pure x
|
||||
| ⟨i+1, h⟩, x => f ⟨i, h⟩ x >>= loop ⟨i, Nat.le_of_lt h⟩
|
||||
|
||||
@@ -125,7 +125,7 @@ theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x
|
||||
| zero =>
|
||||
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
|
||||
conv => rhs; rw [←bind_pure (f 0 x)]
|
||||
congr; funext; exact foldrM_loop_zero ..
|
||||
congr; funext
|
||||
| succ i ih =>
|
||||
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
||||
congr; funext; exact ih ..
|
||||
|
||||
@@ -370,25 +370,25 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
Fin.castLE mn ∘ Fin.castLE km = Fin.castLE (Nat.le_trans km mn) :=
|
||||
funext (castLE_castLE km mn)
|
||||
|
||||
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i := rfl
|
||||
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' :=
|
||||
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : (last n).cast h = last n' :=
|
||||
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
|
||||
|
||||
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
||||
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : Fin.cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
||||
|
||||
@[simp] theorem cast_refl (n : Nat) (h : n = n) : cast h = id := by
|
||||
@[simp] theorem cast_refl (n : Nat) (h : n = n) : Fin.cast h = id := by
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
cast h' (cast h i) = cast (Eq.trans h h') i := rfl
|
||||
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
|
||||
|
||||
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h := rfl
|
||||
|
||||
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n → Fin (n + 0)) = cast rfl := rfl
|
||||
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n → Fin (n + 0)) = Fin.cast rfl := rfl
|
||||
|
||||
theorem castAdd_lt {m : Nat} (n : Nat) (i : Fin m) : (castAdd n i : Nat) < m := by simp
|
||||
|
||||
@@ -406,37 +406,37 @@ theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
|
||||
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := Fin.ext rfl
|
||||
|
||||
theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) := rfl
|
||||
(i.castAdd m).cast h = (i.cast (Nat.add_right_cancel h)).castAdd m := rfl
|
||||
|
||||
@[simp] theorem cast_castAdd_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
|
||||
cast h (castAdd m' i) = castAdd m i := rfl
|
||||
(i.castAdd m').cast h = i.castAdd m := rfl
|
||||
|
||||
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
|
||||
castAdd p (castAdd n i) = cast (Nat.add_assoc ..).symm (castAdd (n + p) i) := rfl
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
|
||||
the reverse direction. -/
|
||||
@[simp] theorem cast_succ_eq {n' : Nat} (i : Fin n) (h : n.succ = n'.succ) :
|
||||
cast h i.succ = (cast (Nat.succ.inj h) i).succ := rfl
|
||||
i.succ.cast h = (i.cast (Nat.succ.inj h)).succ := rfl
|
||||
|
||||
theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
|
||||
(cast h i).succ = cast (by rw [h]) i.succ := rfl
|
||||
(i.cast h).succ = i.succ.cast (by rw [h]) := rfl
|
||||
|
||||
@[simp] theorem coe_castSucc (i : Fin n) : (Fin.castSucc i : Nat) = i := rfl
|
||||
@[simp] theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc ⟨i, h⟩ = ⟨i, Nat.lt.step h⟩ := rfl
|
||||
|
||||
@[simp] theorem cast_castSucc {n' : Nat} {h : n + 1 = n' + 1} {i : Fin n} :
|
||||
cast h (castSucc i) = castSucc (cast (Nat.succ.inj h) i) := rfl
|
||||
i.castSucc.cast h = (i.cast (Nat.succ.inj h)).castSucc := rfl
|
||||
|
||||
theorem castSucc_lt_succ (i : Fin n) : Fin.castSucc i < i.succ :=
|
||||
theorem castSucc_lt_succ (i : Fin n) : i.castSucc < i.succ :=
|
||||
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
|
||||
|
||||
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ Fin.castSucc j ↔ i < j.succ := by
|
||||
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ j.castSucc ↔ i < j.succ := by
|
||||
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
|
||||
|
||||
theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
||||
Fin.castSucc i < j ↔ i.succ ≤ j := .rfl
|
||||
i.castSucc < j ↔ i.succ ≤ j := .rfl
|
||||
|
||||
@[simp] theorem succ_last (n : Nat) : (last n).succ = last n.succ := rfl
|
||||
|
||||
@@ -444,48 +444,48 @@ theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
||||
i.succ = last (n + 1) ↔ i = last n := by rw [← succ_last, succ_inj]
|
||||
|
||||
@[simp] theorem castSucc_castLT (i : Fin (n + 1)) (h : (i : Nat) < n) :
|
||||
castSucc (castLT i h) = i := rfl
|
||||
(castLT i h).castSucc = i := rfl
|
||||
|
||||
@[simp] theorem castLT_castSucc {n : Nat} (a : Fin n) (h : (a : Nat) < n) :
|
||||
castLT (castSucc a) h = a := rfl
|
||||
castLT a.castSucc h = a := rfl
|
||||
|
||||
@[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
|
||||
Fin.castSucc a < Fin.castSucc b ↔ a < b := .rfl
|
||||
a.castSucc < b.castSucc ↔ a < b := .rfl
|
||||
|
||||
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b ↔ a = b := by simp [Fin.ext_iff]
|
||||
theorem castSucc_inj {a b : Fin n} : a.castSucc = b.castSucc ↔ a = b := by simp [Fin.ext_iff]
|
||||
|
||||
theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
|
||||
theorem castSucc_lt_last (a : Fin n) : a.castSucc < last n := a.is_lt
|
||||
|
||||
@[simp] theorem castSucc_zero : castSucc (0 : Fin (n + 1)) = 0 := rfl
|
||||
|
||||
@[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 := rfl
|
||||
|
||||
/-- `castSucc i` is positive when `i` is positive -/
|
||||
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i := by
|
||||
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < i.castSucc := by
|
||||
simpa [lt_def] using h
|
||||
|
||||
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : castSucc a = 0 ↔ a = 0 := by simp [Fin.ext_iff]
|
||||
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : a.castSucc = 0 ↔ a = 0 := by simp [Fin.ext_iff]
|
||||
|
||||
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : castSucc a ≠ 0 ↔ a ≠ 0 :=
|
||||
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : a.castSucc ≠ 0 ↔ a ≠ 0 :=
|
||||
not_congr <| castSucc_eq_zero_iff
|
||||
|
||||
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
|
||||
castSucc (Fin.succ j) = Fin.succ (castSucc j) := by simp [Fin.ext_iff]
|
||||
j.succ.castSucc = (j.castSucc).succ := by simp [Fin.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ := by
|
||||
theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
|
||||
cases n
|
||||
· exact a.elim0
|
||||
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
||||
|
||||
theorem lt_succ {a : Fin n} : castSucc a < a.succ := by
|
||||
theorem lt_succ {a : Fin n} : a.castSucc < a.succ := by
|
||||
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
|
||||
|
||||
theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : (∃ j, castSucc j = i) ↔ i ≠ last n :=
|
||||
⟨fun ⟨j, hj⟩ => hj ▸ Fin.ne_of_lt j.castSucc_lt_last,
|
||||
fun hi => ⟨i.castLT <| Fin.val_lt_last hi, rfl⟩⟩
|
||||
|
||||
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = castSucc i.succ := rfl
|
||||
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = i.succ.castSucc := rfl
|
||||
|
||||
@[simp] theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
|
||||
|
||||
@@ -502,17 +502,17 @@ theorem le_coe_addNat (m : Nat) (i : Fin n) : m ≤ addNat i m :=
|
||||
addNat ⟨i, hi⟩ n = ⟨i + n, Nat.add_lt_add_right hi n⟩ := rfl
|
||||
|
||||
@[simp] theorem cast_addNat_zero {n n' : Nat} (i : Fin n) (h : n + 0 = n') :
|
||||
cast h (addNat i 0) = cast ((Nat.add_zero _).symm.trans h) i := rfl
|
||||
(addNat i 0).cast h = i.cast ((Nat.add_zero _).symm.trans h) := rfl
|
||||
|
||||
/-- For rewriting in the reverse direction, see `Fin.cast_addNat_left`. -/
|
||||
theorem addNat_cast {n n' m : Nat} (i : Fin n') (h : n' = n) :
|
||||
addNat (cast h i) m = cast (congrArg (. + m) h) (addNat i m) := rfl
|
||||
addNat (i.cast h) m = (addNat i m).cast (congrArg (. + m) h) := rfl
|
||||
|
||||
theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
cast h (addNat i m) = addNat (cast (Nat.add_right_cancel h) i) m := rfl
|
||||
(addNat i m).cast h = addNat (i.cast (Nat.add_right_cancel h)) m := rfl
|
||||
|
||||
@[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
|
||||
cast h (addNat i m') = addNat i m :=
|
||||
(addNat i m').cast h = addNat i m :=
|
||||
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
|
||||
|
||||
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||
@@ -522,46 +522,44 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
|
||||
theorem le_coe_natAdd (m : Nat) (i : Fin n) : m ≤ natAdd m i := Nat.le_add_right ..
|
||||
|
||||
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = cast (Nat.zero_add n).symm := by ext; simp
|
||||
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = Fin.cast (Nat.zero_add n).symm := by ext; simp
|
||||
|
||||
/-- For rewriting in the reverse direction, see `Fin.cast_natAdd_right`. -/
|
||||
theorem natAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
|
||||
natAdd m (cast h i) = cast (congrArg _ h) (natAdd m i) := rfl
|
||||
natAdd m (i.cast h) = (natAdd m i).cast (congrArg _ h) := rfl
|
||||
|
||||
theorem cast_natAdd_right {n n' m : Nat} (i : Fin n') (h : m + n' = m + n) :
|
||||
cast h (natAdd m i) = natAdd m (cast (Nat.add_left_cancel h) i) := rfl
|
||||
(natAdd m i).cast h = natAdd m (i.cast (Nat.add_left_cancel h)) := rfl
|
||||
|
||||
@[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
|
||||
cast h (natAdd m' i) = natAdd m i :=
|
||||
(natAdd m' i).cast h = natAdd m i :=
|
||||
Fin.ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
|
||||
|
||||
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
||||
castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) := rfl
|
||||
castAdd p (natAdd m i) = (natAdd m (castAdd p i)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
theorem natAdd_castAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
||||
natAdd m (castAdd p i) = cast (Nat.add_assoc ..) (castAdd p (natAdd m i)) := rfl
|
||||
natAdd m (castAdd p i) = (castAdd p (natAdd m i)).cast (Nat.add_assoc ..) := rfl
|
||||
|
||||
theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
|
||||
natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) :=
|
||||
natAdd m (natAdd n i) = (natAdd (m + n) i).cast (Nat.add_assoc ..) :=
|
||||
Fin.ext <| (Nat.add_assoc ..).symm
|
||||
|
||||
@[simp]
|
||||
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
|
||||
cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i :=
|
||||
Fin.ext <| Nat.zero_add _
|
||||
(natAdd 0 i).cast h = i.cast ((Nat.zero_add _).symm.trans h) := by simp
|
||||
|
||||
@[simp]
|
||||
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
|
||||
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := Fin.ext <| Nat.add_comm ..
|
||||
(natAdd n i).cast (Nat.add_comm ..) = addNat i n := Fin.ext <| Nat.add_comm ..
|
||||
|
||||
@[simp]
|
||||
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
|
||||
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := Fin.ext <| Nat.add_comm ..
|
||||
(addNat i m).cast (Nat.add_comm ..) = natAdd m i := Fin.ext <| Nat.add_comm ..
|
||||
|
||||
@[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
|
||||
|
||||
@[simp] theorem addNat_last (n : Nat) :
|
||||
addNat (last n) m = cast (by omega) (last (n + m)) := by
|
||||
addNat (last n) m = (last (n + m)).cast (by omega) := by
|
||||
ext
|
||||
simp
|
||||
|
||||
@@ -657,7 +655,7 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
subNat m (addNat i m) h = i := Fin.ext <| Nat.add_sub_cancel i m
|
||||
|
||||
@[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n ≤ i) :
|
||||
natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i := by simp [← cast_addNat]
|
||||
natAdd n (subNat n (i.cast (Nat.add_comm ..)) h) = i := by simp [← cast_addNat]
|
||||
|
||||
/-! ### recursion and induction principles -/
|
||||
|
||||
|
||||
179
src/Init/Data/Float32.lean
Normal file
179
src/Init/Data/Float32.lean
Normal file
@@ -0,0 +1,179 @@
|
||||
/-
|
||||
Copyright (c) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Core
|
||||
import Init.Data.Int.Basic
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.Data.Float
|
||||
|
||||
-- Just show FloatSpec is inhabited.
|
||||
opaque float32Spec : FloatSpec := {
|
||||
float := Unit,
|
||||
val := (),
|
||||
lt := fun _ _ => True,
|
||||
le := fun _ _ => True,
|
||||
decLt := fun _ _ => inferInstanceAs (Decidable True),
|
||||
decLe := fun _ _ => inferInstanceAs (Decidable True)
|
||||
}
|
||||
|
||||
/-- Native floating point type, corresponding to the IEEE 754 *binary32* format
|
||||
(`float` in C or `f32` in Rust). -/
|
||||
structure Float32 where
|
||||
val : float32Spec.float
|
||||
|
||||
instance : Nonempty Float32 := ⟨{ val := float32Spec.val }⟩
|
||||
|
||||
@[extern "lean_float32_add"] opaque Float32.add : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_sub"] opaque Float32.sub : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_mul"] opaque Float32.mul : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_div"] opaque Float32.div : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_negate"] opaque Float32.neg : Float32 → Float32
|
||||
|
||||
set_option bootstrap.genMatcherCode false
|
||||
def Float32.lt : Float32 → Float32 → Prop := fun a b =>
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => float32Spec.lt a b
|
||||
|
||||
def Float32.le : Float32 → Float32 → Prop := fun a b =>
|
||||
float32Spec.le a.val b.val
|
||||
|
||||
/--
|
||||
Raw transmutation from `UInt32`.
|
||||
|
||||
Float32s and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
-/
|
||||
@[extern "lean_float32_of_bits"] opaque Float32.ofBits : UInt32 → Float32
|
||||
|
||||
/--
|
||||
Raw transmutation to `UInt32`.
|
||||
|
||||
Float32s and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
|
||||
Note that this function is distinct from `Float32.toUInt32`, which attempts
|
||||
to preserve the numeric value, and not the bitwise value.
|
||||
-/
|
||||
@[extern "lean_float32_to_bits"] opaque Float32.toBits : Float32 → UInt32
|
||||
|
||||
instance : Add Float32 := ⟨Float32.add⟩
|
||||
instance : Sub Float32 := ⟨Float32.sub⟩
|
||||
instance : Mul Float32 := ⟨Float32.mul⟩
|
||||
instance : Div Float32 := ⟨Float32.div⟩
|
||||
instance : Neg Float32 := ⟨Float32.neg⟩
|
||||
instance : LT Float32 := ⟨Float32.lt⟩
|
||||
instance : LE Float32 := ⟨Float32.le⟩
|
||||
|
||||
/-- Note: this is not reflexive since `NaN != NaN`.-/
|
||||
@[extern "lean_float32_beq"] opaque Float32.beq (a b : Float32) : Bool
|
||||
|
||||
instance : BEq Float32 := ⟨Float32.beq⟩
|
||||
|
||||
@[extern "lean_float32_decLt"] opaque Float32.decLt (a b : Float32) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => float32Spec.decLt a b
|
||||
|
||||
@[extern "lean_float32_decLe"] 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
|
||||
|
||||
@[extern "lean_float32_to_string"] opaque Float32.toString : Float32 → String
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt8` (including Inf), returns the maximum value of `UInt8`
|
||||
(i.e. `UInt8.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint8"] opaque Float32.toUInt8 : Float32 → UInt8
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt16` (including Inf), returns the maximum value of `UInt16`
|
||||
(i.e. `UInt16.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint16"] opaque Float32.toUInt16 : Float32 → UInt16
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt32` (including Inf), returns the maximum value of `UInt32`
|
||||
(i.e. `UInt32.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint32"] opaque Float32.toUInt32 : Float32 → UInt32
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt64` (including Inf), returns the maximum value of `UInt64`
|
||||
(i.e. `UInt64.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint64"] opaque Float32.toUInt64 : Float32 → UInt64
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `USize` (including Inf), returns the maximum value of `USize`
|
||||
(i.e. `USize.size - 1`). This value is platform dependent).
|
||||
-/
|
||||
@[extern "lean_float32_to_usize"] opaque Float32.toUSize : Float32 → USize
|
||||
|
||||
@[extern "lean_float32_isnan"] opaque Float32.isNaN : Float32 → Bool
|
||||
@[extern "lean_float32_isfinite"] opaque Float32.isFinite : Float32 → Bool
|
||||
@[extern "lean_float32_isinf"] opaque Float32.isInf : Float32 → Bool
|
||||
/-- Splits the given float `x` into a significand/exponent pair `(s, i)`
|
||||
such that `x = s * 2^i` where `s ∈ (-1;-0.5] ∪ [0.5; 1)`.
|
||||
Returns an undefined value if `x` is not finite.
|
||||
-/
|
||||
@[extern "lean_float32_frexp"] opaque Float32.frExp : Float32 → Float32 × Int
|
||||
|
||||
instance : ToString Float32 where
|
||||
toString := Float32.toString
|
||||
|
||||
@[extern "lean_uint64_to_float32"] opaque UInt64.toFloat32 (n : UInt64) : Float32
|
||||
|
||||
instance : Inhabited Float32 where
|
||||
default := UInt64.toFloat32 0
|
||||
|
||||
instance : Repr Float32 where
|
||||
reprPrec n prec := if n < UInt64.toFloat32 0 then Repr.addAppParen (toString n) prec else toString n
|
||||
|
||||
instance : ReprAtom Float32 := ⟨⟩
|
||||
|
||||
@[extern "sinf"] opaque Float32.sin : Float32 → Float32
|
||||
@[extern "cosf"] opaque Float32.cos : Float32 → Float32
|
||||
@[extern "tanf"] opaque Float32.tan : Float32 → Float32
|
||||
@[extern "asinf"] opaque Float32.asin : Float32 → Float32
|
||||
@[extern "acosf"] opaque Float32.acos : Float32 → Float32
|
||||
@[extern "atanf"] opaque Float32.atan : Float32 → Float32
|
||||
@[extern "atan2f"] opaque Float32.atan2 : Float32 → Float32 → Float32
|
||||
@[extern "sinhf"] opaque Float32.sinh : Float32 → Float32
|
||||
@[extern "coshf"] opaque Float32.cosh : Float32 → Float32
|
||||
@[extern "tanhf"] opaque Float32.tanh : Float32 → Float32
|
||||
@[extern "asinhf"] opaque Float32.asinh : Float32 → Float32
|
||||
@[extern "acoshf"] opaque Float32.acosh : Float32 → Float32
|
||||
@[extern "atanhf"] opaque Float32.atanh : Float32 → Float32
|
||||
@[extern "expf"] opaque Float32.exp : Float32 → Float32
|
||||
@[extern "exp2f"] opaque Float32.exp2 : Float32 → Float32
|
||||
@[extern "logf"] opaque Float32.log : Float32 → Float32
|
||||
@[extern "log2f"] opaque Float32.log2 : Float32 → Float32
|
||||
@[extern "log10f"] opaque Float32.log10 : Float32 → Float32
|
||||
@[extern "powf"] opaque Float32.pow : Float32 → Float32 → Float32
|
||||
@[extern "sqrtf"] opaque Float32.sqrt : Float32 → Float32
|
||||
@[extern "cbrtf"] opaque Float32.cbrt : Float32 → Float32
|
||||
@[extern "ceilf"] opaque Float32.ceil : Float32 → Float32
|
||||
@[extern "floorf"] opaque Float32.floor : Float32 → Float32
|
||||
@[extern "roundf"] opaque Float32.round : Float32 → Float32
|
||||
@[extern "fabsf"] opaque Float32.abs : Float32 → Float32
|
||||
|
||||
instance : HomogeneousPow Float32 := ⟨Float32.pow⟩
|
||||
|
||||
instance : Min Float32 := minOfLe
|
||||
|
||||
instance : Max Float32 := maxOfLe
|
||||
|
||||
/--
|
||||
Efficiently computes `x * 2^i`.
|
||||
-/
|
||||
@[extern "lean_float32_scaleb"]
|
||||
opaque Float32.scaleB (x : Float32) (i : @& Int) : Float32
|
||||
|
||||
@[extern "lean_float32_to_float"] opaque Float32.toFloat : Float32 → Float
|
||||
@[extern "lean_float_to_float32"] opaque Float.toFloat32 : Float → Float32
|
||||
@@ -7,7 +7,7 @@ The integers, with addition, multiplication, and subtraction.
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Cast
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.Nat.Div.Basic
|
||||
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
open Nat
|
||||
|
||||
@@ -34,4 +34,8 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
|
||||
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
|
||||
simp [Int.shiftRight_eq_div_pow]
|
||||
|
||||
@[simp]
|
||||
theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
|
||||
simp [Int.shiftRight_eq_div_pow]
|
||||
|
||||
end Int
|
||||
|
||||
@@ -29,6 +29,8 @@ At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with
|
||||
In September 2024, we decided to do this rename (with deprecations in place),
|
||||
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
|
||||
ever need to use these functions and their associated lemmas.
|
||||
|
||||
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
|
||||
-/
|
||||
|
||||
/-! ### T-rounding division -/
|
||||
@@ -71,8 +73,6 @@ def tdiv : (@& Int) → (@& Int) → Int
|
||||
| -[m +1], ofNat n => -ofNat (succ m / n)
|
||||
| -[m +1], -[n +1] => ofNat (succ m / succ n)
|
||||
|
||||
@[deprecated tdiv (since := "2024-09-11")] abbrev div := tdiv
|
||||
|
||||
/-- Integer modulo. This function uses the
|
||||
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
|
||||
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
|
||||
@@ -107,8 +107,6 @@ def tmod : (@& Int) → (@& Int) → Int
|
||||
| -[m +1], ofNat n => -ofNat (succ m % n)
|
||||
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
|
||||
|
||||
@[deprecated tmod (since := "2024-09-11")] abbrev mod := tmod
|
||||
|
||||
/-! ### F-rounding division
|
||||
This pair satisfies `fdiv x y = floor (x / y)`.
|
||||
-/
|
||||
@@ -251,8 +249,6 @@ instance : Mod Int where
|
||||
|
||||
theorem ofNat_tdiv (m n : Nat) : ↑(m / n) = tdiv ↑m ↑n := rfl
|
||||
|
||||
@[deprecated ofNat_tdiv (since := "2024-09-11")] abbrev ofNat_div := ofNat_tdiv
|
||||
|
||||
theorem ofNat_fdiv : ∀ m n : Nat, ↑(m / n) = fdiv ↑m ↑n
|
||||
| 0, _ => by simp [fdiv]
|
||||
| succ _, _ => rfl
|
||||
|
||||
@@ -125,7 +125,7 @@ theorem eq_one_of_mul_eq_one_right {a b : Int} (H : 0 ≤ a) (H' : a * b = 1) :
|
||||
eq_one_of_dvd_one H ⟨b, H'.symm⟩
|
||||
|
||||
theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 ≤ b) (H' : a * b = 1) : b = 1 :=
|
||||
eq_one_of_mul_eq_one_right H <| by rw [Int.mul_comm, H']
|
||||
eq_one_of_mul_eq_one_right (b := a) H <| by rw [Int.mul_comm, H']
|
||||
|
||||
/-! ### *div zero -/
|
||||
|
||||
@@ -1315,65 +1315,3 @@ theorem bmod_natAbs_plus_one (x : Int) (w : 1 < x.natAbs) : bmod x (x.natAbs + 1
|
||||
all_goals decide
|
||||
· exact ofNat_nonneg x
|
||||
· exact succ_ofNat_pos (x + 1)
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@[deprecated Int.zero_tdiv (since := "2024-09-11")] protected abbrev zero_div := @Int.zero_tdiv
|
||||
@[deprecated Int.tdiv_zero (since := "2024-09-11")] protected abbrev div_zero := @Int.tdiv_zero
|
||||
@[deprecated tdiv_eq_ediv (since := "2024-09-11")] abbrev div_eq_ediv := @tdiv_eq_ediv
|
||||
@[deprecated fdiv_eq_tdiv (since := "2024-09-11")] abbrev fdiv_eq_div := @fdiv_eq_tdiv
|
||||
@[deprecated zero_tmod (since := "2024-09-11")] abbrev zero_mod := @zero_tmod
|
||||
@[deprecated tmod_zero (since := "2024-09-11")] abbrev mod_zero := @tmod_zero
|
||||
@[deprecated tmod_add_tdiv (since := "2024-09-11")] abbrev mod_add_div := @tmod_add_tdiv
|
||||
@[deprecated tdiv_add_tmod (since := "2024-09-11")] abbrev div_add_mod := @tdiv_add_tmod
|
||||
@[deprecated tmod_add_tdiv' (since := "2024-09-11")] abbrev mod_add_div' := @tmod_add_tdiv'
|
||||
@[deprecated tdiv_add_tmod' (since := "2024-09-11")] abbrev div_add_mod' := @tdiv_add_tmod'
|
||||
@[deprecated tmod_def (since := "2024-09-11")] abbrev mod_def := @tmod_def
|
||||
@[deprecated tmod_eq_emod (since := "2024-09-11")] abbrev mod_eq_emod := @tmod_eq_emod
|
||||
@[deprecated fmod_eq_tmod (since := "2024-09-11")] abbrev fmod_eq_mod := @fmod_eq_tmod
|
||||
@[deprecated Int.tdiv_one (since := "2024-09-11")] protected abbrev div_one := @Int.tdiv_one
|
||||
@[deprecated Int.tdiv_neg (since := "2024-09-11")] protected abbrev div_neg := @Int.tdiv_neg
|
||||
@[deprecated Int.neg_tdiv (since := "2024-09-11")] protected abbrev neg_div := @Int.neg_tdiv
|
||||
@[deprecated Int.neg_tdiv_neg (since := "2024-09-11")] protected abbrev neg_div_neg := @Int.neg_tdiv_neg
|
||||
@[deprecated Int.tdiv_nonneg (since := "2024-09-11")] protected abbrev div_nonneg := @Int.tdiv_nonneg
|
||||
@[deprecated Int.tdiv_nonpos (since := "2024-09-11")] protected abbrev div_nonpos := @Int.tdiv_nonpos
|
||||
@[deprecated Int.tdiv_eq_zero_of_lt (since := "2024-09-11")] abbrev div_eq_zero_of_lt := @Int.tdiv_eq_zero_of_lt
|
||||
@[deprecated Int.mul_tdiv_cancel (since := "2024-09-11")] protected abbrev mul_div_cancel := @Int.mul_tdiv_cancel
|
||||
@[deprecated Int.mul_tdiv_cancel_left (since := "2024-09-11")] protected abbrev mul_div_cancel_left := @Int.mul_tdiv_cancel_left
|
||||
@[deprecated Int.tdiv_self (since := "2024-09-11")] protected abbrev div_self := @Int.tdiv_self
|
||||
@[deprecated Int.mul_tdiv_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev mul_div_cancel_of_mod_eq_zero := @Int.mul_tdiv_cancel_of_tmod_eq_zero
|
||||
@[deprecated Int.tdiv_mul_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev div_mul_cancel_of_mod_eq_zero := @Int.tdiv_mul_cancel_of_tmod_eq_zero
|
||||
@[deprecated Int.dvd_of_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_of_mod_eq_zero := @Int.dvd_of_tmod_eq_zero
|
||||
@[deprecated Int.mul_tdiv_assoc (since := "2024-09-11")] protected abbrev mul_div_assoc := @Int.mul_tdiv_assoc
|
||||
@[deprecated Int.mul_tdiv_assoc' (since := "2024-09-11")] protected abbrev mul_div_assoc' := @Int.mul_tdiv_assoc'
|
||||
@[deprecated Int.tdiv_dvd_tdiv (since := "2024-09-11")] abbrev div_dvd_div := @Int.tdiv_dvd_tdiv
|
||||
@[deprecated Int.natAbs_tdiv (since := "2024-09-11")] abbrev natAbs_div := @Int.natAbs_tdiv
|
||||
@[deprecated Int.tdiv_eq_of_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_right := @Int.tdiv_eq_of_eq_mul_right
|
||||
@[deprecated Int.eq_tdiv_of_mul_eq_right (since := "2024-09-11")] protected abbrev eq_div_of_mul_eq_right := @Int.eq_tdiv_of_mul_eq_right
|
||||
@[deprecated Int.ofNat_tmod (since := "2024-09-11")] abbrev ofNat_mod := @Int.ofNat_tmod
|
||||
@[deprecated Int.tmod_one (since := "2024-09-11")] abbrev mod_one := @Int.tmod_one
|
||||
@[deprecated Int.tmod_eq_of_lt (since := "2024-09-11")] abbrev mod_eq_of_lt := @Int.tmod_eq_of_lt
|
||||
@[deprecated Int.tmod_lt_of_pos (since := "2024-09-11")] abbrev mod_lt_of_pos := @Int.tmod_lt_of_pos
|
||||
@[deprecated Int.tmod_nonneg (since := "2024-09-11")] abbrev mod_nonneg := @Int.tmod_nonneg
|
||||
@[deprecated Int.tmod_neg (since := "2024-09-11")] abbrev mod_neg := @Int.tmod_neg
|
||||
@[deprecated Int.mul_tmod_left (since := "2024-09-11")] abbrev mul_mod_left := @Int.mul_tmod_left
|
||||
@[deprecated Int.mul_tmod_right (since := "2024-09-11")] abbrev mul_mod_right := @Int.mul_tmod_right
|
||||
@[deprecated Int.tmod_eq_zero_of_dvd (since := "2024-09-11")] abbrev mod_eq_zero_of_dvd := @Int.tmod_eq_zero_of_dvd
|
||||
@[deprecated Int.dvd_iff_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_iff_mod_eq_zero := @Int.dvd_iff_tmod_eq_zero
|
||||
@[deprecated Int.neg_mul_tmod_right (since := "2024-09-11")] abbrev neg_mul_mod_right := @Int.neg_mul_tmod_right
|
||||
@[deprecated Int.neg_mul_tmod_left (since := "2024-09-11")] abbrev neg_mul_mod_left := @Int.neg_mul_tmod_left
|
||||
@[deprecated Int.tdiv_mul_cancel (since := "2024-09-11")] protected abbrev div_mul_cancel := @Int.tdiv_mul_cancel
|
||||
@[deprecated Int.mul_tdiv_cancel' (since := "2024-09-11")] protected abbrev mul_div_cancel' := @Int.mul_tdiv_cancel'
|
||||
@[deprecated Int.eq_mul_of_tdiv_eq_right (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_right := @Int.eq_mul_of_tdiv_eq_right
|
||||
@[deprecated Int.tmod_self (since := "2024-09-11")] abbrev mod_self := @Int.tmod_self
|
||||
@[deprecated Int.neg_tmod_self (since := "2024-09-11")] abbrev neg_mod_self := @Int.neg_tmod_self
|
||||
@[deprecated Int.lt_tdiv_add_one_mul_self (since := "2024-09-11")] abbrev lt_div_add_one_mul_self := @Int.lt_tdiv_add_one_mul_self
|
||||
@[deprecated Int.tdiv_eq_iff_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_right := @Int.tdiv_eq_iff_eq_mul_right
|
||||
@[deprecated Int.tdiv_eq_iff_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_left := @Int.tdiv_eq_iff_eq_mul_left
|
||||
@[deprecated Int.eq_mul_of_tdiv_eq_left (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_left := @Int.eq_mul_of_tdiv_eq_left
|
||||
@[deprecated Int.tdiv_eq_of_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_left := @Int.tdiv_eq_of_eq_mul_left
|
||||
@[deprecated Int.eq_zero_of_tdiv_eq_zero (since := "2024-09-11")] protected abbrev eq_zero_of_div_eq_zero := @Int.eq_zero_of_tdiv_eq_zero
|
||||
@[deprecated Int.tdiv_left_inj (since := "2024-09-11")] protected abbrev div_left_inj := @Int.tdiv_left_inj
|
||||
@[deprecated Int.tdiv_sign (since := "2024-09-11")] abbrev div_sign := @Int.tdiv_sign
|
||||
@[deprecated Int.sign_eq_tdiv_abs (since := "2024-09-11")] protected abbrev sign_eq_div_abs := @Int.sign_eq_tdiv_abs
|
||||
@[deprecated Int.tdiv_eq_ediv_of_dvd (since := "2024-09-11")] abbrev div_eq_ediv_of_dvd := @Int.tdiv_eq_ediv_of_dvd
|
||||
|
||||
@@ -24,6 +24,8 @@ import Init.Data.List.Zip
|
||||
import Init.Data.List.Perm
|
||||
import Init.Data.List.Sort
|
||||
import Init.Data.List.ToArray
|
||||
import Init.Data.List.ToArrayImpl
|
||||
import Init.Data.List.MapIdx
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.List.FinRange
|
||||
import Init.Data.List.Lex
|
||||
|
||||
@@ -118,7 +118,6 @@ theorem attach_map_coe (l : List α) (f : α → β) :
|
||||
theorem attach_map_val (l : List α) (f : α → β) : (l.attach.map fun i => f i.val) = l.map f :=
|
||||
attach_map_coe _ _
|
||||
|
||||
@[simp]
|
||||
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
|
||||
(attach_map_coe _ _).trans (List.map_id _)
|
||||
|
||||
@@ -130,7 +129,6 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : List α) (H :
|
||||
((l.attachWith p H).map fun i => f i.val) = l.map f :=
|
||||
attachWith_map_coe _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (l : List α) (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l :=
|
||||
(attachWith_map_coe _ _ _).trans (List.map_id _)
|
||||
@@ -174,8 +172,8 @@ theorem pmap_ne_nil_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Li
|
||||
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ [] ↔ xs ≠ [] := by
|
||||
simp
|
||||
|
||||
theorem pmap_eq_self {l : List α} {p : α → Prop} (hp : ∀ (a : α), a ∈ l → p a)
|
||||
(f : (a : α) → p a → α) : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
theorem pmap_eq_self {l : List α} {p : α → Prop} {hp : ∀ (a : α), a ∈ l → p a}
|
||||
{f : (a : α) → p a → α} : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
rw [pmap_eq_map_attach]
|
||||
conv => lhs; rhs; rw [← attach_map_subtype_val l]
|
||||
rw [map_inj_left]
|
||||
|
||||
@@ -162,46 +162,74 @@ theorem isEqv_cons₂ : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv)
|
||||
|
||||
/-! ## Lexicographic ordering -/
|
||||
|
||||
/--
|
||||
The lexicographic order on lists.
|
||||
`[] < a::as`, and `a::as < b::bs` if `a < b` or if `a` and `b` are equivalent and `as < bs`.
|
||||
-/
|
||||
inductive lt [LT α] : List α → List α → Prop where
|
||||
/-- Lexicographic ordering for lists. -/
|
||||
inductive Lex (r : α → α → Prop) : List α → List α → Prop
|
||||
/-- `[]` is the smallest element in the order. -/
|
||||
| nil (b : α) (bs : List α) : lt [] (b::bs)
|
||||
| nil {a l} : Lex r [] (a :: l)
|
||||
/-- If `a` is indistinguishable from `b` and `as < bs`, then `a::as < b::bs`. -/
|
||||
| cons {a l₁ l₂} (h : Lex r l₁ l₂) : Lex r (a :: l₁) (a :: l₂)
|
||||
/-- If `a < b` then `a::as < b::bs`. -/
|
||||
| head {a : α} (as : List α) {b : α} (bs : List α) : a < b → lt (a::as) (b::bs)
|
||||
/-- If `a` and `b` are equivalent and `as < bs`, then `a::as < b::bs`. -/
|
||||
| tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b → ¬ b < a → lt as bs → lt (a::as) (b::bs)
|
||||
| rel {a₁ l₁ a₂ l₂} (h : r a₁ a₂) : Lex r (a₁ :: l₁) (a₂ :: l₂)
|
||||
|
||||
instance [LT α] : LT (List α) := ⟨List.lt⟩
|
||||
|
||||
instance hasDecidableLt [LT α] [h : DecidableRel (α := α) (· < ·)] : (l₁ l₂ : List α) → Decidable (l₁ < l₂)
|
||||
| [], [] => isFalse nofun
|
||||
| [], _::_ => isTrue (List.lt.nil _ _)
|
||||
| _::_, [] => isFalse nofun
|
||||
instance decidableLex [DecidableEq α] (r : α → α → Prop) [h : DecidableRel r] :
|
||||
(l₁ l₂ : List α) → Decidable (Lex r l₁ l₂)
|
||||
| [], [] => isFalse nofun
|
||||
| [], _::_ => isTrue Lex.nil
|
||||
| _::_, [] => isFalse nofun
|
||||
| a::as, b::bs =>
|
||||
match h a b with
|
||||
| isTrue h₁ => isTrue (List.lt.head _ _ h₁)
|
||||
| isTrue h₁ => isTrue (Lex.rel h₁)
|
||||
| isFalse h₁ =>
|
||||
match h b a with
|
||||
| isTrue h₂ => isFalse (fun h => match h with
|
||||
| List.lt.head _ _ h₁' => absurd h₁' h₁
|
||||
| List.lt.tail _ h₂' _ => absurd h₂ h₂')
|
||||
| isFalse h₂ =>
|
||||
match hasDecidableLt as bs with
|
||||
| isTrue h₃ => isTrue (List.lt.tail h₁ h₂ h₃)
|
||||
if h₂ : a = b then
|
||||
match decidableLex r as bs with
|
||||
| isTrue h₃ => isTrue (h₂ ▸ Lex.cons h₃)
|
||||
| isFalse h₃ => isFalse (fun h => match h with
|
||||
| List.lt.head _ _ h₁' => absurd h₁' h₁
|
||||
| List.lt.tail _ _ h₃' => absurd h₃' h₃)
|
||||
| Lex.rel h₁' => absurd h₁' h₁
|
||||
| Lex.cons h₃' => absurd h₃' h₃)
|
||||
else
|
||||
isFalse (fun h => match h with
|
||||
| Lex.rel h₁' => absurd h₁' h₁
|
||||
| Lex.cons h₂' => h₂ rfl)
|
||||
|
||||
@[inherit_doc Lex]
|
||||
protected abbrev lt [LT α] : List α → List α → Prop := Lex (· < ·)
|
||||
|
||||
instance instLT [LT α] : LT (List α) := ⟨List.lt⟩
|
||||
|
||||
/-- Decidability of lexicographic ordering. -/
|
||||
instance decidableLT [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
|
||||
Decidable (l₁ < l₂) := decidableLex (· < ·) l₁ l₂
|
||||
|
||||
@[deprecated decidableLT (since := "2024-12-13"), inherit_doc decidableLT]
|
||||
abbrev hasDecidableLt := @decidableLT
|
||||
|
||||
/-- The lexicographic order on lists. -/
|
||||
@[reducible] protected def le [LT α] (a b : List α) : Prop := ¬ b < a
|
||||
|
||||
instance [LT α] : LE (List α) := ⟨List.le⟩
|
||||
instance instLE [LT α] : LE (List α) := ⟨List.le⟩
|
||||
|
||||
instance [LT α] [DecidableRel ((· < ·) : α → α → Prop)] : (l₁ l₂ : List α) → Decidable (l₁ ≤ l₂) :=
|
||||
fun _ _ => inferInstanceAs (Decidable (Not _))
|
||||
instance decidableLE [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
|
||||
Decidable (l₁ ≤ l₂) :=
|
||||
inferInstanceAs (Decidable (Not _))
|
||||
|
||||
/--
|
||||
Lexicographic comparator for lists.
|
||||
|
||||
* `lex lt [] (b :: bs)` is true.
|
||||
* `lex lt as []` is false.
|
||||
* `lex lt (a :: as) (b :: bs)` is true if `lt a b` or `a == b` and `lex lt as bs` is true.
|
||||
-/
|
||||
def lex [BEq α] (l₁ l₂ : List α) (lt : α → α → Bool := by exact (· < ·)) : Bool :=
|
||||
match l₁, l₂ with
|
||||
| [], _ :: _ => true
|
||||
| _, [] => false
|
||||
| a :: as, b :: bs => lt a b || (a == b && lex as bs lt)
|
||||
|
||||
@[simp] theorem lex_nil_nil [BEq α] : lex ([] : List α) [] lt = false := rfl
|
||||
@[simp] theorem lex_nil_cons [BEq α] {b} {bs : List α} : lex [] (b :: bs) lt = true := rfl
|
||||
@[simp] theorem lex_cons_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false := rfl
|
||||
@[simp] theorem lex_cons_cons [BEq α] {a b} {as bs : List α} :
|
||||
lex (a :: as) (b :: bs) lt = (lt a b || (a == b && lex as bs lt)) := rfl
|
||||
|
||||
/-! ## Alternative getters -/
|
||||
|
||||
@@ -666,10 +694,14 @@ def isEmpty : List α → Bool
|
||||
/-! ### elem -/
|
||||
|
||||
/--
|
||||
`O(|l|)`. `elem a l` or `l.contains a` is true if there is an element in `l` equal to `a`.
|
||||
`O(|l|)`.
|
||||
`l.contains a` or `elem a l` is true if there is an element in `l` equal (according to `==`) to `a`.
|
||||
|
||||
* `elem 3 [1, 4, 2, 3, 3, 7] = true`
|
||||
* `elem 5 [1, 4, 2, 3, 3, 7] = false`
|
||||
* `[1, 4, 2, 3, 3, 7].contains 3 = true`
|
||||
* `[1, 4, 2, 3, 3, 7].contains 5 = false`
|
||||
|
||||
The preferred simp normal form is `l.contains a`, and when `LawfulBEq α` is available,
|
||||
`l.contains a = true ↔ a ∈ l` and `l.contains a = false ↔ a ∉ l`.
|
||||
-/
|
||||
def elem [BEq α] (a : α) : List α → Bool
|
||||
| [] => false
|
||||
|
||||
@@ -155,7 +155,8 @@ def mapMono (as : List α) (f : α → α) : List α :=
|
||||
|
||||
/-! ## Additional lemmas required for bootstrapping `Array`. -/
|
||||
|
||||
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h'} : (as ++ bs)[i] = as[i] := by
|
||||
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h' : i < (as ++ bs).length} :
|
||||
(as ++ bs)[i] = as[i] := by
|
||||
induction as generalizing i with
|
||||
| nil => trivial
|
||||
| cons a as ih =>
|
||||
@@ -232,25 +233,34 @@ theorem sizeOf_get [SizeOf α] (as : List α) (i : Fin as.length) : sizeOf (as.g
|
||||
apply Nat.lt_trans ih
|
||||
simp_arith
|
||||
|
||||
theorem le_antisymm [LT α] [s : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{as bs : List α} (h₁ : as ≤ bs) (h₂ : bs ≤ as) : as = bs :=
|
||||
theorem not_lex_antisymm [DecidableEq α] {r : α → α → Prop} [DecidableRel r]
|
||||
(antisymm : ∀ x y : α, ¬ r x y → ¬ r y x → x = y)
|
||||
{as bs : List α} (h₁ : ¬ Lex r bs as) (h₂ : ¬ Lex r as bs) : as = bs :=
|
||||
match as, bs with
|
||||
| [], [] => rfl
|
||||
| [], _::_ => False.elim <| h₂ (List.lt.nil ..)
|
||||
| _::_, [] => False.elim <| h₁ (List.lt.nil ..)
|
||||
| [], _::_ => False.elim <| h₂ (List.Lex.nil ..)
|
||||
| _::_, [] => False.elim <| h₁ (List.Lex.nil ..)
|
||||
| a::as, b::bs => by
|
||||
by_cases hab : a < b
|
||||
· exact False.elim <| h₂ (List.lt.head _ _ hab)
|
||||
· by_cases hba : b < a
|
||||
· exact False.elim <| h₁ (List.lt.head _ _ hba)
|
||||
· have h₁ : as ≤ bs := fun h => h₁ (List.lt.tail hba hab h)
|
||||
have h₂ : bs ≤ as := fun h => h₂ (List.lt.tail hab hba h)
|
||||
have ih : as = bs := le_antisymm h₁ h₂
|
||||
have : a = b := s.antisymm hab hba
|
||||
simp [this, ih]
|
||||
by_cases hab : r a b
|
||||
· exact False.elim <| h₂ (List.Lex.rel hab)
|
||||
· by_cases eq : a = b
|
||||
· subst eq
|
||||
have h₁ : ¬ Lex r bs as := fun h => h₁ (List.Lex.cons h)
|
||||
have h₂ : ¬ Lex r as bs := fun h => h₂ (List.Lex.cons h)
|
||||
simp [not_lex_antisymm antisymm h₁ h₂]
|
||||
· exfalso
|
||||
by_cases hba : r b a
|
||||
· exact h₁ (Lex.rel hba)
|
||||
· exact eq (antisymm _ _ hab hba)
|
||||
|
||||
instance [LT α] [Std.Antisymm (¬ · < · : α → α → Prop)] :
|
||||
protected theorem le_antisymm [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{as bs : List α} (h₁ : as ≤ bs) (h₂ : bs ≤ as) : as = bs :=
|
||||
not_lex_antisymm i.antisymm h₁ h₂
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[s : Std.Antisymm (¬ · < · : α → α → Prop)] :
|
||||
Std.Antisymm (· ≤ · : List α → List α → Prop) where
|
||||
antisymm h₁ h₂ := le_antisymm h₁ h₂
|
||||
antisymm _ _ h₁ h₂ := List.le_antisymm h₁ h₂
|
||||
|
||||
end List
|
||||
|
||||
@@ -162,6 +162,10 @@ theorem countP_filterMap (p : β → Bool) (f : α → Option β) (l : List α)
|
||||
|
||||
@[deprecated countP_flatten (since := "2024-10-14")] abbrev countP_join := @countP_flatten
|
||||
|
||||
theorem countP_flatMap (p : β → Bool) (l : List α) (f : α → List β) :
|
||||
countP p (l.flatMap f) = sum (map (countP p ∘ f) l) := by
|
||||
rw [List.flatMap, countP_flatten, map_map]
|
||||
|
||||
@[simp] theorem countP_reverse (l : List α) : countP p l.reverse = countP p l := by
|
||||
simp [countP_eq_length_filter, filter_reverse]
|
||||
|
||||
@@ -326,6 +330,9 @@ theorem count_filterMap {α} [BEq β] (b : β) (f : α → Option β) (l : List
|
||||
· simp
|
||||
· simp
|
||||
|
||||
theorem count_flatMap {α} [BEq β] (l : List α) (f : α → List β) (x : β) :
|
||||
count x (l.flatMap f) = sum (map (count x ∘ f) l) := countP_flatMap _ _ _
|
||||
|
||||
theorem count_erase (a b : α) :
|
||||
∀ l : List α, count a (l.erase b) = count a l - if b == a then 1 else 0
|
||||
| [] => by simp
|
||||
|
||||
@@ -566,7 +566,6 @@ theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
|
||||
| inl e => simpa [e, Fin.zero_eta, get_cons_zero]
|
||||
| inr e =>
|
||||
have ipm := Nat.succ_pred_eq_of_pos e
|
||||
have ilt := Nat.le_trans ho (findIdx_le_length p)
|
||||
simp +singlePass only [← ipm, getElem_cons_succ]
|
||||
rw [← ipm, Nat.succ_lt_succ_iff] at h
|
||||
simpa using ih h
|
||||
|
||||
@@ -332,7 +332,7 @@ def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
rw [← show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
|
||||
simp [enumFrom, f]
|
||||
rw [← Array.foldr_toList]
|
||||
simp [go]
|
||||
simp +zetaDelta [go]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
|
||||
|
||||
@@ -154,6 +154,9 @@ theorem ne_nil_iff_exists_cons {l : List α} : l ≠ [] ↔ ∃ b L, l = b :: L
|
||||
theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] ↔ a = b := by
|
||||
simp
|
||||
|
||||
@[simp] theorem concat_ne_nil (a : α) (l : List α) : l ++ [a] ≠ [] := by
|
||||
cases l <;> simp
|
||||
|
||||
/-! ## L[i] and L[i]? -/
|
||||
|
||||
/-! ### `get` and `get?`.
|
||||
@@ -191,61 +194,63 @@ We simplify away `getD`, replacing `getD l n a` with `(l[n]?).getD a`.
|
||||
Because of this, there is only minimal API for `getD`.
|
||||
-/
|
||||
|
||||
@[simp] theorem getD_eq_getElem?_getD (l) (n) (a : α) : getD l n a = (l[n]?).getD a := by
|
||||
@[simp] theorem getD_eq_getElem?_getD (l) (i) (a : α) : getD l i a = (l[i]?).getD a := by
|
||||
simp [getD]
|
||||
|
||||
/-! ### get!
|
||||
|
||||
We simplify `l.get! n` to `l[n]!`.
|
||||
We simplify `l.get! i` to `l[i]!`.
|
||||
-/
|
||||
|
||||
theorem get!_eq_getD [Inhabited α] : ∀ (l : List α) n, l.get! n = l.getD n default
|
||||
theorem get!_eq_getD [Inhabited α] : ∀ (l : List α) i, l.get! i = l.getD i default
|
||||
| [], _ => rfl
|
||||
| _a::_, 0 => rfl
|
||||
| _a::l, n+1 => get!_eq_getD l n
|
||||
|
||||
@[simp] theorem get!_eq_getElem! [Inhabited α] (l : List α) (n) : l.get! n = l[n]! := by
|
||||
@[simp] theorem get!_eq_getElem! [Inhabited α] (l : List α) (i) : l.get! i = l[i]! := by
|
||||
simp [get!_eq_getD]
|
||||
rfl
|
||||
|
||||
/-! ### getElem!
|
||||
|
||||
We simplify `l[n]!` to `(l[n]?).getD default`.
|
||||
We simplify `l[i]!` to `(l[i]?).getD default`.
|
||||
-/
|
||||
|
||||
@[simp] theorem getElem!_eq_getElem?_getD [Inhabited α] (l : List α) (n : Nat) :
|
||||
l[n]! = (l[n]?).getD (default : α) := by
|
||||
@[simp] theorem getElem!_eq_getElem?_getD [Inhabited α] (l : List α) (i : Nat) :
|
||||
l[i]! = (l[i]?).getD (default : α) := by
|
||||
simp only [getElem!_def]
|
||||
split <;> simp_all
|
||||
match l[i]? with
|
||||
| some _ => simp
|
||||
| none => simp
|
||||
|
||||
/-! ### getElem? and getElem -/
|
||||
|
||||
@[simp] theorem getElem?_eq_getElem {l : List α} {n} (h : n < l.length) : l[n]? = some l[n] := by
|
||||
simp only [getElem?_def, h, ↓reduceDIte]
|
||||
|
||||
theorem getElem?_eq_some_iff {l : List α} : l[n]? = some a ↔ ∃ h : n < l.length, l[n] = a := by
|
||||
simp only [← get?_eq_getElem?, get?_eq_some_iff, get_eq_getElem]
|
||||
|
||||
theorem some_eq_getElem?_iff {l : List α} : some a = l[n]? ↔ ∃ h : n < l.length, l[n] = a := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@[simp] theorem getElem?_eq_none_iff : l[n]? = none ↔ length l ≤ n := by
|
||||
@[simp] theorem getElem?_eq_none_iff : l[i]? = none ↔ length l ≤ i := by
|
||||
simp only [← get?_eq_getElem?, get?_eq_none_iff]
|
||||
|
||||
@[simp] theorem none_eq_getElem?_iff {l : List α} {n : Nat} : none = l[n]? ↔ length l ≤ n := by
|
||||
@[simp] 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 ≤ n) : l[n]? = none := getElem?_eq_none_iff.mpr h
|
||||
theorem getElem?_eq_none (h : length l ≤ i) : l[i]? = none := getElem?_eq_none_iff.mpr h
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem?_iff {α} (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||
@[simp] theorem getElem?_eq_getElem {l : List α} {i} (h : i < l.length) : l[i]? = some l[i] :=
|
||||
getElem?_pos ..
|
||||
|
||||
theorem getElem?_eq_some_iff {l : List α} : l[i]? = some a ↔ ∃ h : i < l.length, l[i] = a := by
|
||||
simp only [← get?_eq_getElem?, get?_eq_some_iff, get_eq_getElem]
|
||||
|
||||
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) :
|
||||
(some xs[i] = xs[i]?) ↔ True := by
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff {α} (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||
(xs[i]? = some xs[i]) ↔ True := by
|
||||
simp [h]
|
||||
|
||||
theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ l[n]? = some x := by
|
||||
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]
|
||||
exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩
|
||||
|
||||
@@ -253,17 +258,37 @@ theorem getElem_eq_getElem?_get (l : List α) (i : Nat) (h : i < l.length) :
|
||||
l[i] = l[i]?.get (by simp [getElem?_eq_getElem, h]) := by
|
||||
simp [getElem_eq_iff]
|
||||
|
||||
@[simp] theorem getElem?_nil {n : Nat} : ([] : List α)[n]? = none := rfl
|
||||
theorem getD_getElem? (l : List α) (i : Nat) (d : α) :
|
||||
l[i]?.getD d = if p : i < l.length then l[i]'p else d := by
|
||||
if h : i < l.length then
|
||||
simp [h, getElem?_def]
|
||||
else
|
||||
have p : i ≥ l.length := Nat.le_of_not_gt h
|
||||
simp [getElem?_eq_none p, h]
|
||||
|
||||
@[simp] theorem getElem?_nil {i : Nat} : ([] : List α)[i]? = none := rfl
|
||||
|
||||
theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
|
||||
(a :: l)[i] =
|
||||
if h : i = 0 then a else l[i-1]'(match i, h with | i+1, _ => succ_lt_succ_iff.mp w) := by
|
||||
cases i <;> simp
|
||||
|
||||
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by simp
|
||||
|
||||
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[n+1]? = l[n]? := by
|
||||
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := by
|
||||
simp only [← get?_eq_getElem?]
|
||||
rfl
|
||||
|
||||
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
|
||||
cases i <;> simp
|
||||
|
||||
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : [a][i] = a :=
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
|
||||
theorem getElem?_singleton (a : α) (i : Nat) : [a][i]? = if i = 0 then some a else none := by
|
||||
simp [getElem?_cons]
|
||||
|
||||
/--
|
||||
If one has `l[i]` in an expression and `h : l = l'`,
|
||||
`rw [h]` will give a "motive it not type correct" error, as it cannot rewrite the
|
||||
@@ -273,19 +298,15 @@ such a rewrite, with `rw [getElem_of_eq h]`.
|
||||
theorem getElem_of_eq {l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) :
|
||||
l[i] = l'[i]'(h ▸ w) := by cases h; rfl
|
||||
|
||||
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : [a][i] = a :=
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
|
||||
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos.mp h) :=
|
||||
match l, h with
|
||||
| _ :: _, _ => rfl
|
||||
|
||||
@[ext] theorem ext_getElem? {l₁ l₂ : List α} (h : ∀ n : Nat, l₁[n]? = l₂[n]?) : l₁ = l₂ :=
|
||||
@[ext] theorem ext_getElem? {l₁ l₂ : List α} (h : ∀ i : Nat, l₁[i]? = l₂[i]?) : l₁ = l₂ :=
|
||||
ext_get? fun n => by simp_all
|
||||
|
||||
theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
(h : ∀ (n : Nat) (h₁ : n < l₁.length) (h₂ : n < l₂.length), l₁[n]'h₁ = l₂[n]'h₂) : l₁ = l₂ :=
|
||||
(h : ∀ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length), l₁[i]'h₁ = l₂[i]'h₂) : l₁ = l₂ :=
|
||||
ext_getElem? fun n =>
|
||||
if h₁ : n < length l₁ then by
|
||||
simp_all [getElem?_eq_getElem]
|
||||
@@ -300,12 +321,6 @@ theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
theorem getElem?_concat_length (l : List α) (a : α) : (l ++ [a])[l.length]? = some a := by
|
||||
simp
|
||||
|
||||
theorem isSome_getElem? {l : List α} {n : Nat} : l[n]?.isSome ↔ n < l.length := by
|
||||
simp
|
||||
|
||||
theorem isNone_getElem? {l : List α} {n : Nat} : l[n]?.isNone ↔ l.length ≤ n := by
|
||||
simp
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[simp] theorem not_mem_nil (a : α) : ¬ a ∈ [] := nofun
|
||||
@@ -412,24 +427,25 @@ theorem not_mem_cons_of_ne_of_not_mem {a y : α} {l : List α} : a ≠ y → a
|
||||
theorem ne_and_not_mem_of_not_mem_cons {a y : α} {l : List α} : a ∉ y :: l → a ≠ y ∧ a ∉ l :=
|
||||
fun p => ⟨ne_of_not_mem_cons p, not_mem_of_not_mem_cons p⟩
|
||||
|
||||
theorem getElem_of_mem : ∀ {a} {l : List α}, a ∈ l → ∃ (n : Nat) (h : n < l.length), l[n]'h = a
|
||||
theorem getElem_of_mem : ∀ {a} {l : List α}, a ∈ l → ∃ (i : Nat) (h : i < l.length), l[i]'h = a
|
||||
| _, _ :: _, .head .. => ⟨0, Nat.succ_pos _, rfl⟩
|
||||
| _, _ :: _, .tail _ m => let ⟨n, h, e⟩ := getElem_of_mem m; ⟨n+1, Nat.succ_lt_succ h, e⟩
|
||||
| _, _ :: _, .tail _ m => let ⟨i, h, e⟩ := getElem_of_mem m; ⟨i+1, Nat.succ_lt_succ h, e⟩
|
||||
|
||||
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = some a :=
|
||||
let ⟨n, _, e⟩ := getElem_of_mem h; ⟨n, e ▸ getElem?_eq_getElem _⟩
|
||||
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ i : Nat, l[i]? = some a := by
|
||||
let ⟨n, _, e⟩ := getElem_of_mem h
|
||||
exact ⟨n, e ▸ getElem?_eq_getElem _⟩
|
||||
|
||||
theorem mem_of_getElem? {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a ∈ l :=
|
||||
theorem mem_of_getElem? {l : List α} {i : Nat} {a : α} (e : l[i]? = some a) : a ∈ l :=
|
||||
let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
|
||||
|
||||
theorem mem_iff_getElem {a} {l : List α} : a ∈ l ↔ ∃ (n : Nat) (h : n < l.length), l[n]'h = a :=
|
||||
theorem mem_iff_getElem {a} {l : List α} : a ∈ l ↔ ∃ (i : Nat) (h : i < l.length), l[i]'h = a :=
|
||||
⟨getElem_of_mem, fun ⟨_, _, e⟩ => e ▸ getElem_mem ..⟩
|
||||
|
||||
theorem mem_iff_getElem? {a} {l : List α} : a ∈ l ↔ ∃ n : Nat, l[n]? = some a := by
|
||||
theorem mem_iff_getElem? {a} {l : List α} : a ∈ l ↔ ∃ i : Nat, l[i]? = some a := by
|
||||
simp [getElem?_eq_some_iff, mem_iff_getElem]
|
||||
|
||||
theorem forall_getElem {l : List α} {p : α → Prop} :
|
||||
(∀ (n : Nat) h, p (l[n]'h)) ↔ ∀ a, a ∈ l → p a := by
|
||||
(∀ (i : Nat) h, p (l[i]'h)) ↔ ∀ a, a ∈ l → p a := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
@@ -448,6 +464,10 @@ theorem forall_getElem {l : List α} {p : α → Prop} :
|
||||
simp only [getElem_cons_succ]
|
||||
exact getElem_mem (lt_of_succ_lt_succ h)
|
||||
|
||||
@[simp] theorem elem_eq_contains [BEq α] {a : α} {l : List α} :
|
||||
elem a l = l.contains a := by
|
||||
simp [contains]
|
||||
|
||||
@[simp] theorem decide_mem_cons [BEq α] [LawfulBEq α] {l : List α} :
|
||||
decide (y ∈ a :: l) = (y == a || decide (y ∈ l)) := by
|
||||
cases h : y == a <;> simp_all
|
||||
@@ -455,16 +475,27 @@ theorem forall_getElem {l : List α} {p : α → Prop} :
|
||||
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
|
||||
elem a as = true ↔ a ∈ as := ⟨mem_of_elem_eq_true, elem_eq_true_of_mem⟩
|
||||
|
||||
@[simp] theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
|
||||
as.contains a = true ↔ a ∈ as := ⟨mem_of_elem_eq_true, elem_eq_true_of_mem⟩
|
||||
|
||||
theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
elem a as = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
as.contains a = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
|
||||
(a :: l).contains b = (b == a || l.contains b) := by
|
||||
simp only [contains, elem_cons]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### `isEmpty` -/
|
||||
|
||||
theorem isEmpty_iff {l : List α} : l.isEmpty ↔ l = [] := by
|
||||
cases l <;> simp
|
||||
|
||||
theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
|
||||
(List.isEmpty xs = false) ↔ ∃ x, x ∈ xs := by
|
||||
xs.isEmpty = false ↔ ∃ x, x ∈ xs := by
|
||||
cases xs <;> simp
|
||||
|
||||
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 := by
|
||||
@@ -502,17 +533,21 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
@[simp] theorem all_eq_false {l : List α} : l.all p = false ↔ ∃ x, x ∈ l ∧ ¬p x := by
|
||||
simp [all_eq]
|
||||
|
||||
theorem any_beq [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => a == x) ↔ a ∈ l := by
|
||||
simp
|
||||
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
|
||||
induction l <;> simp_all [contains_cons]
|
||||
|
||||
theorem any_beq' [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => x == a) ↔ a ∈ l := by
|
||||
simp
|
||||
/-- Variant of `any_beq` with `==` reversed. -/
|
||||
theorem any_beq' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||
(l.any fun x => x == a) = l.contains a := by
|
||||
simp only [BEq.comm, any_beq]
|
||||
|
||||
theorem all_bne [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => a != x) ↔ a ∉ l := by
|
||||
induction l <;> simp_all
|
||||
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
|
||||
induction l <;> simp_all [bne]
|
||||
|
||||
theorem all_bne' [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => x != a) ↔ a ∉ l := by
|
||||
induction l <;> simp_all [eq_comm (a := a)]
|
||||
/-- Variant of `all_bne` with `!=` reversed. -/
|
||||
theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||
(l.all fun x => x != a) = !l.contains a := by
|
||||
simp only [bne_comm, all_bne]
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@@ -563,10 +598,10 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
|
||||
simp_all
|
||||
· rw [getElem?_eq_none (by simp_all), getElem?_eq_none (by simp_all)]
|
||||
|
||||
theorem getElem_set {l : List α} {m n} {a} (h) :
|
||||
(set l m a)[n]'h = if m = n then a else l[n]'(length_set .. ▸ h) := by
|
||||
if h : m = n then
|
||||
subst m; simp only [getElem_set_self, ↓reduceIte]
|
||||
theorem getElem_set {l : List α} {i j} {a} (h) :
|
||||
(set l i a)[j]'h = if i = j then a else l[j]'(length_set .. ▸ h) := by
|
||||
if h : i = j then
|
||||
subst h; simp only [getElem_set_self, ↓reduceIte]
|
||||
else
|
||||
simp [h]
|
||||
|
||||
@@ -639,6 +674,42 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.s
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp] theorem beq_nil_iff [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem nil_beq_iff [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
|
||||
@[simp] theorem concat_beq_concat [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(l₁ ++ [a] == l₂ ++ [b]) = (l₁ == l₂ && a == b) := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil => cases l₂ <;> simp
|
||||
| cons x l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp
|
||||
| cons y l₂ => simp [ih, Bool.and_assoc]
|
||||
|
||||
theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l₁.length = l₂.length :=
|
||||
match l₁, l₂ with
|
||||
| [], [] => rfl
|
||||
| [], _ :: _ => by simp [beq_nil_iff] at h
|
||||
| _ :: _, [] => by simp [nil_beq_iff] at h
|
||||
| a :: l₁, b :: l₂ => by
|
||||
simp at h
|
||||
simpa [Nat.add_one_inj] using length_eq_of_beq h.2
|
||||
|
||||
@[simp] theorem replicate_beq_replicate [BEq α] {a b : α} {n : Nat} :
|
||||
(replicate n a == replicate n b) = (n == 0 || a == b) := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
rw [replicate_succ, replicate_succ, cons_beq_cons, replicate_beq_replicate]
|
||||
rw [Bool.eq_iff_iff]
|
||||
simp +contextual
|
||||
|
||||
@[simp] theorem reflBEq_iff [BEq α] : ReflBEq (List α) ↔ ReflBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -676,66 +747,15 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.s
|
||||
· intro a
|
||||
simp
|
||||
|
||||
@[simp] theorem beq_nil_iff [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
/-! ### isEqv -/
|
||||
|
||||
@[simp] theorem nil_beq_iff [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
|
||||
theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l₁.length = l₂.length :=
|
||||
match l₁, l₂ with
|
||||
| [], [] => rfl
|
||||
| [], _ :: _ => by simp [beq_nil_iff] at h
|
||||
| _ :: _, [] => by simp [nil_beq_iff] at h
|
||||
| a :: l₁, b :: l₂ => by
|
||||
simp at h
|
||||
simpa [Nat.add_one_inj]using length_eq_of_beq h.2
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
protected theorem lt_irrefl [LT α] (lt_irrefl : ∀ x : α, ¬x < x) (l : List α) : ¬l < l := by
|
||||
induction l with
|
||||
| nil => nofun
|
||||
| cons a l ih => intro
|
||||
| .head _ _ h => exact lt_irrefl _ h
|
||||
| .tail _ _ h => exact ih h
|
||||
|
||||
protected theorem lt_trans [LT α] [DecidableRel (@LT.lt α _)]
|
||||
(lt_trans : ∀ {x y z : α}, x < y → y < z → x < z)
|
||||
(le_trans : ∀ {x y z : α}, ¬x < y → ¬y < z → ¬x < z)
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
|
||||
induction h₁ generalizing l₃ with
|
||||
| nil => let _::_ := l₃; exact List.lt.nil ..
|
||||
| @head a l₁ b l₂ ab =>
|
||||
match h₂ with
|
||||
| .head l₂ l₃ bc => exact List.lt.head _ _ (lt_trans ab bc)
|
||||
| .tail _ cb ih =>
|
||||
exact List.lt.head _ _ <| Decidable.by_contra (le_trans · cb ab)
|
||||
| @tail a l₁ b l₂ ab ba h₁ ih2 =>
|
||||
match h₂ with
|
||||
| .head l₂ l₃ bc =>
|
||||
exact List.lt.head _ _ <| Decidable.by_contra (le_trans ba · bc)
|
||||
| .tail bc cb ih =>
|
||||
exact List.lt.tail (le_trans ab bc) (le_trans cb ba) (ih2 ih)
|
||||
|
||||
protected theorem lt_antisymm [LT α]
|
||||
(lt_antisymm : ∀ {x y : α}, ¬x < y → ¬y < x → x = y)
|
||||
{l₁ l₂ : List α} (h₁ : ¬l₁ < l₂) (h₂ : ¬l₂ < l₁) : l₁ = l₂ := by
|
||||
@[simp] theorem isEqv_eq [DecidableEq α] {l₁ l₂ : List α} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂) := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil =>
|
||||
cases l₂ with
|
||||
| nil => rfl
|
||||
| cons b l₂ => cases h₁ (.nil ..)
|
||||
| nil => cases l₂ <;> simp
|
||||
| cons a l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => cases h₂ (.nil ..)
|
||||
| cons b l₂ =>
|
||||
have ab : ¬a < b := fun ab => h₁ (.head _ _ ab)
|
||||
cases lt_antisymm ab (fun ba => h₂ (.head _ _ ba))
|
||||
rw [ih (fun ll => h₁ (.tail ab ab ll)) (fun ll => h₂ (.tail ab ab ll))]
|
||||
| nil => simp
|
||||
| cons b l₂ => simp [isEqv, ih]
|
||||
|
||||
/-! ### foldlM and foldrM -/
|
||||
|
||||
@@ -949,7 +969,7 @@ theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
|
||||
| _ :: _ :: _, _ => by
|
||||
simp [getLast, get, Nat.succ_sub_succ, getLast_eq_getElem]
|
||||
|
||||
theorem getElem_length_sub_one_eq_getLast (l : List α) (h) :
|
||||
theorem getElem_length_sub_one_eq_getLast (l : List α) (h : l.length - 1 < l.length) :
|
||||
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
|
||||
rw [← getLast_eq_getElem]
|
||||
|
||||
@@ -989,8 +1009,8 @@ theorem getLastD_mem_cons : ∀ (l : List α) (a : α), getLastD l a ∈ a::l
|
||||
| [], _ => .head ..
|
||||
| _::_, _ => .tail _ <| getLast_mem _
|
||||
|
||||
theorem getElem_cons_length (x : α) (xs : List α) (n : Nat) (h : n = xs.length) :
|
||||
(x :: xs)[n]'(by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs) := by
|
||||
theorem getElem_cons_length (x : α) (xs : List α) (i : Nat) (h : i = xs.length) :
|
||||
(x :: xs)[i]'(by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs) := by
|
||||
rw [getLast_eq_getElem]; cases h; rfl
|
||||
|
||||
@[deprecated getElem_cons_length (since := "2024-06-12")]
|
||||
@@ -1077,7 +1097,8 @@ theorem head_eq_getElem (l : List α) (h : l ≠ []) : head l h = l[0]'(length_p
|
||||
| nil => simp at h
|
||||
| cons _ _ => simp
|
||||
|
||||
theorem getElem_zero_eq_head (l : List α) (h) : l[0] = head l (by simpa [length_pos] using h) := by
|
||||
theorem getElem_zero_eq_head (l : List α) (h : 0 < l.length) :
|
||||
l[0] = head l (by simpa [length_pos] using h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ _ => simp
|
||||
@@ -1221,24 +1242,24 @@ theorem map_singleton (f : α → β) (a : α) : map f [a] = [f a] := rfl
|
||||
| nil => simp [List.map]
|
||||
| cons _ as ih => simp [List.map, ih]
|
||||
|
||||
@[simp] theorem getElem?_map (f : α → β) : ∀ (l : List α) (n : Nat), (map f l)[n]? = Option.map f l[n]?
|
||||
@[simp] theorem getElem?_map (f : α → β) : ∀ (l : List α) (i : Nat), (map f l)[i]? = Option.map f l[i]?
|
||||
| [], _ => rfl
|
||||
| _ :: _, 0 => by simp
|
||||
| _ :: l, n+1 => by simp [getElem?_map f l n]
|
||||
| _ :: l, i+1 => by simp [getElem?_map f l i]
|
||||
|
||||
@[deprecated getElem?_map (since := "2024-06-12")]
|
||||
theorem get?_map (f : α → β) : ∀ l n, (map f l).get? n = (l.get? n).map f
|
||||
theorem get?_map (f : α → β) : ∀ l i, (map f l).get? i = (l.get? i).map f
|
||||
| [], _ => rfl
|
||||
| _ :: _, 0 => rfl
|
||||
| _ :: l, n+1 => get?_map f l n
|
||||
| _ :: l, i+1 => get?_map f l i
|
||||
|
||||
@[simp] theorem getElem_map (f : α → β) {l} {n : Nat} {h : n < (map f l).length} :
|
||||
(map f l)[n] = f (l[n]'(length_map l f ▸ h)) :=
|
||||
@[simp] theorem getElem_map (f : α → β) {l} {i : Nat} {h : i < (map f l).length} :
|
||||
(map f l)[i] = f (l[i]'(length_map l f ▸ h)) :=
|
||||
Option.some.inj <| by rw [← getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
|
||||
|
||||
@[deprecated getElem_map (since := "2024-06-12")]
|
||||
theorem get_map (f : α → β) {l n} :
|
||||
get (map f l) n = f (get l ⟨n, length_map l f ▸ n.2⟩) := by
|
||||
theorem get_map (f : α → β) {l i} :
|
||||
get (map f l) i = f (get l ⟨i, length_map l f ▸ i.2⟩) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem mem_map {f : α → β} : ∀ {l : List α}, b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b
|
||||
@@ -1669,71 +1690,71 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
||||
@[simp] theorem cons_append_fun (a : α) (as : List α) :
|
||||
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
|
||||
|
||||
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h) :
|
||||
(l₁ ++ l₂)[n] = if h' : n < l₁.length then l₁[n] else l₂[n - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
|
||||
theorem getElem_append {l₁ l₂ : List α} (i : Nat) (h : i < (l₁ ++ l₂).length) :
|
||||
(l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
|
||||
split <;> rename_i h'
|
||||
· rw [getElem_append_left h']
|
||||
· rw [getElem_append_right (by simpa using h')]
|
||||
|
||||
theorem getElem?_append_left {l₁ l₂ : List α} {n : Nat} (hn : n < l₁.length) :
|
||||
(l₁ ++ l₂)[n]? = l₁[n]? := by
|
||||
have hn' : n < (l₁ ++ l₂).length := Nat.lt_of_lt_of_le hn <|
|
||||
theorem getElem?_append_left {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :
|
||||
(l₁ ++ l₂)[i]? = l₁[i]? := by
|
||||
have hn' : i < (l₁ ++ l₂).length := Nat.lt_of_lt_of_le hn <|
|
||||
length_append .. ▸ Nat.le_add_right ..
|
||||
simp_all [getElem?_eq_getElem, getElem_append]
|
||||
|
||||
theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {n : Nat}, l₁.length ≤ n →
|
||||
(l₁ ++ l₂)[n]? = l₂[n - l₁.length]?
|
||||
theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length ≤ i →
|
||||
(l₁ ++ l₂)[i]? = l₂[i - l₁.length]?
|
||||
| [], _, _, _ => rfl
|
||||
| a :: l, _, n+1, h₁ => by
|
||||
| a :: l, _, i+1, h₁ => by
|
||||
rw [cons_append]
|
||||
simp [Nat.succ_sub_succ_eq_sub, getElem?_append_right (Nat.lt_succ.1 h₁)]
|
||||
|
||||
theorem getElem?_append {l₁ l₂ : List α} {n : Nat} :
|
||||
(l₁ ++ l₂)[n]? = if n < l₁.length then l₁[n]? else l₂[n - l₁.length]? := by
|
||||
theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
|
||||
(l₁ ++ l₂)[i]? = if i < l₁.length then l₁[i]? else l₂[i - l₁.length]? := by
|
||||
split <;> rename_i h
|
||||
· exact getElem?_append_left h
|
||||
· exact getElem?_append_right (by simpa using h)
|
||||
|
||||
@[deprecated getElem?_append_right (since := "2024-06-12")]
|
||||
theorem get?_append_right {l₁ l₂ : List α} {n : Nat} (h : l₁.length ≤ n) :
|
||||
(l₁ ++ l₂).get? n = l₂.get? (n - l₁.length) := by
|
||||
theorem get?_append_right {l₁ l₂ : List α} {i : Nat} (h : l₁.length ≤ i) :
|
||||
(l₁ ++ l₂).get? i = l₂.get? (i - l₁.length) := by
|
||||
simp [getElem?_append_right, h]
|
||||
|
||||
/-- Variant of `getElem_append_left` useful for rewriting from the small list to the big list. -/
|
||||
theorem getElem_append_left' (l₂ : List α) {l₁ : List α} {n : Nat} (hn : n < l₁.length) :
|
||||
l₁[n] = (l₁ ++ l₂)[n]'(by simpa using Nat.lt_add_right l₂.length hn) := by
|
||||
theorem getElem_append_left' (l₂ : List α) {l₁ : List α} {i : Nat} (hi : i < l₁.length) :
|
||||
l₁[i] = (l₁ ++ l₂)[i]'(by simpa using Nat.lt_add_right l₂.length hi) := by
|
||||
rw [getElem_append_left] <;> simp
|
||||
|
||||
/-- Variant of `getElem_append_right` useful for rewriting from the small list to the big list. -/
|
||||
theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {n : Nat} (hn : n < l₂.length) :
|
||||
l₂[n] = (l₁ ++ l₂)[n + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hn _) := by
|
||||
theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {i : Nat} (hi : i < l₂.length) :
|
||||
l₂[i] = (l₁ ++ l₂)[i + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hi _) := by
|
||||
rw [getElem_append_right] <;> simp [*, le_add_left]
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_append_right_aux {l₁ l₂ : List α} {n : Nat}
|
||||
(h₁ : l₁.length ≤ n) (h₂ : n < (l₁ ++ l₂).length) : n - l₁.length < l₂.length := by
|
||||
theorem get_append_right_aux {l₁ l₂ : List α} {i : Nat}
|
||||
(h₁ : l₁.length ≤ i) (h₂ : i < (l₁ ++ l₂).length) : i - l₁.length < l₂.length := by
|
||||
rw [length_append] at h₂
|
||||
exact Nat.sub_lt_left_of_lt_add h₁ h₂
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated getElem_append_right (since := "2024-06-12")]
|
||||
theorem get_append_right' {l₁ l₂ : List α} {n : Nat} (h₁ : l₁.length ≤ n) (h₂) :
|
||||
(l₁ ++ l₂).get ⟨n, h₂⟩ = l₂.get ⟨n - l₁.length, get_append_right_aux h₁ h₂⟩ :=
|
||||
theorem get_append_right' {l₁ l₂ : List α} {i : Nat} (h₁ : l₁.length ≤ i) (h₂) :
|
||||
(l₁ ++ l₂).get ⟨i, h₂⟩ = l₂.get ⟨i - l₁.length, get_append_right_aux h₁ h₂⟩ :=
|
||||
Option.some.inj <| by rw [← get?_eq_get, ← get?_eq_get, get?_append_right h₁]
|
||||
|
||||
theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) :
|
||||
l[n]'(eq ▸ h ▸ by simp_arith) = a := Option.some.inj <| by
|
||||
theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) :
|
||||
l[i]'(eq ▸ h ▸ by simp_arith) = a := Option.some.inj <| by
|
||||
rw [← getElem?_eq_getElem, eq, getElem?_append_right (h ▸ Nat.le_refl _), h]
|
||||
simp
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_of_append_proof {l : List α}
|
||||
(eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) : n < length l := eq ▸ h ▸ by simp_arith
|
||||
(eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) : i < length l := eq ▸ h ▸ by simp_arith
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated getElem_of_append (since := "2024-06-12")]
|
||||
theorem get_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) :
|
||||
l.get ⟨n, get_of_append_proof eq h⟩ = a := Option.some.inj <| by
|
||||
theorem get_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) :
|
||||
l.get ⟨i, get_of_append_proof eq h⟩ = a := Option.some.inj <| by
|
||||
rw [← get?_eq_get, eq, get?_append_right (h ▸ Nat.le_refl _), h, Nat.sub_self]; rfl
|
||||
|
||||
/--
|
||||
@@ -2041,8 +2062,6 @@ theorem concat_inj_right {l : List α} {a a' : α} : concat l a = concat l a'
|
||||
|
||||
@[deprecated concat_inj (since := "2024-09-05")] abbrev concat_eq_concat := @concat_inj
|
||||
|
||||
theorem concat_ne_nil (a : α) (l : List α) : concat l a ≠ [] := by cases l <;> simp
|
||||
|
||||
theorem concat_append (a : α) (l₁ l₂ : List α) : concat l₁ a ++ l₂ = l₁ ++ a :: l₂ := by simp
|
||||
|
||||
theorem append_concat (a : α) (l₁ l₂ : List α) : l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a := by simp
|
||||
@@ -2211,6 +2230,11 @@ theorem flatMap_def (l : List α) (f : α → List β) : l.flatMap f = flatten (
|
||||
|
||||
@[simp] theorem flatMap_id (l : List (List α)) : List.flatMap l id = l.flatten := by simp [flatMap_def]
|
||||
|
||||
@[simp]
|
||||
theorem length_flatMap (l : List α) (f : α → List β) :
|
||||
length (l.flatMap f) = sum (map (length ∘ f) l) := by
|
||||
rw [List.flatMap, length_flatten, map_map]
|
||||
|
||||
@[simp] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
|
||||
simp [flatMap_def, mem_flatten]
|
||||
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
|
||||
@@ -2290,6 +2314,10 @@ theorem flatMap_eq_foldl (f : α → List β) (l : List α) :
|
||||
|
||||
@[simp] theorem replicate_one : replicate 1 a = [a] := rfl
|
||||
|
||||
/-- Variant of `replicate_succ` that concatenates `a` to the end of the list. -/
|
||||
theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
|
||||
induction n <;> simp_all [replicate_succ, ← cons_append]
|
||||
|
||||
@[simp] theorem mem_replicate {a b : α} : ∀ {n}, b ∈ replicate n a ↔ n ≠ 0 ∧ b = a
|
||||
| 0 => by simp
|
||||
| n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
|
||||
@@ -2819,11 +2847,6 @@ theorem leftpad_suffix (n : Nat) (a : α) (l : List α) : l <:+ (leftpad n a l)
|
||||
|
||||
theorem elem_cons_self [BEq α] [LawfulBEq α] {a : α} : (a::as).elem a = true := by simp
|
||||
|
||||
@[simp] theorem contains_cons [BEq α] :
|
||||
(a :: as : List α).contains x = (x == a || as.contains x) := by
|
||||
simp only [contains, elem]
|
||||
split <;> simp_all
|
||||
|
||||
theorem contains_eq_any_beq [BEq α] (l : List α) (a : α) : l.contains a = l.any (a == ·) := by
|
||||
induction l with simp | cons b l => cases b == a <;> simp [*]
|
||||
|
||||
@@ -2867,7 +2890,7 @@ are often used for theorems about `Array.pop`.
|
||||
@[simp] theorem getElem_dropLast : ∀ (xs : List α) (i : Nat) (h : i < xs.dropLast.length),
|
||||
xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. ▸ Nat.pred_le _))
|
||||
| _::_::_, 0, _ => rfl
|
||||
| _::_::_, i+1, _ => getElem_dropLast _ i _
|
||||
| _::_::_, i+1, h => getElem_dropLast _ i (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[deprecated getElem_dropLast (since := "2024-06-12")]
|
||||
theorem get_dropLast (xs : List α) (i : Fin xs.dropLast.length) :
|
||||
@@ -3373,12 +3396,12 @@ theorem getElem!_nil [Inhabited α] {n : Nat} : ([] : List α)[n]! = default :=
|
||||
theorem getElem!_cons_zero [Inhabited α] {l : List α} : (a::l)[0]! = a := by
|
||||
rw [getElem!_pos] <;> simp
|
||||
|
||||
theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[n+1]! = l[n]! := by
|
||||
by_cases h : n < l.length
|
||||
theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[i+1]! = l[i]! := by
|
||||
by_cases h : i < l.length
|
||||
· rw [getElem!_pos, getElem!_pos] <;> simp_all [Nat.succ_lt_succ_iff]
|
||||
· rw [getElem!_neg, getElem!_neg] <;> simp_all [Nat.succ_lt_succ_iff]
|
||||
|
||||
theorem getElem!_of_getElem? [Inhabited α] : ∀ {l : List α} {n : Nat}, l[n]? = some a → l[n]! = a
|
||||
theorem getElem!_of_getElem? [Inhabited α] : ∀ {l : List α} {i : Nat}, l[i]? = some a → l[i]! = a
|
||||
| _a::_, 0, _ => by
|
||||
rw [getElem!_pos] <;> simp_all
|
||||
| _::l, _+1, e => by
|
||||
@@ -3522,7 +3545,12 @@ theorem getElem?_eq (l : List α) (i : Nat) :
|
||||
getElem?_def _ _
|
||||
@[deprecated getElem?_eq_none (since := "2024-11-29")] abbrev getElem?_len_le := @getElem?_eq_none
|
||||
|
||||
@[deprecated _root_.isSome_getElem? (since := "2024-12-09")]
|
||||
theorem isSome_getElem? {l : List α} {n : Nat} : l[n]?.isSome ↔ n < l.length := by
|
||||
simp
|
||||
|
||||
|
||||
@[deprecated _root_.isNone_getElem? (since := "2024-12-09")]
|
||||
theorem isNone_getElem? {l : List α} {i : Nat} : l[i]?.isNone ↔ l.length ≤ i := by
|
||||
simp
|
||||
|
||||
end List
|
||||
|
||||
430
src/Init/Data/List/Lex.lean
Normal file
430
src/Init/Data/List/Lex.lean
Normal file
@@ -0,0 +1,430 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Lemmas
|
||||
|
||||
namespace List
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
@[simp] theorem lex_lt [LT α] (l₁ l₂ : List α) : Lex (· < ·) l₁ l₂ ↔ l₁ < l₂ := Iff.rfl
|
||||
@[simp] theorem not_lex_lt [LT α] (l₁ l₂ : List α) : ¬ Lex (· < ·) l₁ l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
|
||||
theorem not_lt_iff_ge [LT α] (l₁ l₂ : List α) : ¬ l₁ < l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
|
||||
¬ l₁ ≤ l₂ ↔ l₂ < l₁ :=
|
||||
Decidable.not_not
|
||||
|
||||
theorem lex_irrefl {r : α → α → Prop} (irrefl : ∀ x, ¬r x x) (l : List α) : ¬Lex r l l := by
|
||||
induction l with
|
||||
| nil => nofun
|
||||
| cons a l ih => intro
|
||||
| .rel h => exact irrefl _ h
|
||||
| .cons h => exact ih h
|
||||
|
||||
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] (l : List α) : ¬ l < l :=
|
||||
lex_irrefl Std.Irrefl.irrefl l
|
||||
|
||||
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] : Std.Irrefl (α := List α) (· < ·) where
|
||||
irrefl := List.lt_irrefl
|
||||
|
||||
@[simp] theorem not_lex_nil : ¬Lex r l [] := fun h => nomatch h
|
||||
|
||||
@[simp] theorem nil_le [LT α] (l : List α) : [] ≤ l := fun h => nomatch h
|
||||
|
||||
@[simp] theorem not_nil_lex_iff : ¬Lex r [] l ↔ l = [] := by
|
||||
constructor
|
||||
· rintro h
|
||||
match l, h with
|
||||
| [], h => rfl
|
||||
| a :: _, h => exact False.elim (h Lex.nil)
|
||||
· rintro rfl
|
||||
exact not_lex_nil
|
||||
|
||||
@[simp] theorem le_nil [LT α] (l : List α) : l ≤ [] ↔ l = [] := not_nil_lex_iff
|
||||
|
||||
@[simp] theorem nil_lex_cons : Lex r [] (a :: l) := Lex.nil
|
||||
|
||||
@[simp] theorem nil_lt_cons [LT α] (a : α) (l : List α) : [] < a :: l := Lex.nil
|
||||
|
||||
theorem cons_lex_cons_iff : Lex r (a :: l₁) (b :: l₂) ↔ r a b ∨ a = b ∧ Lex r l₁ l₂ :=
|
||||
⟨fun | .rel h => .inl h | .cons h => .inr ⟨rfl, h⟩,
|
||||
fun | .inl h => Lex.rel h | .inr ⟨rfl, h⟩ => Lex.cons h⟩
|
||||
|
||||
theorem cons_lt_cons_iff [LT α] {a b} {l₁ l₂ : List α} :
|
||||
(a :: l₁) < (b :: l₂) ↔ a < b ∨ a = b ∧ l₁ < l₂ := by
|
||||
dsimp only [instLT, List.lt]
|
||||
simp [cons_lex_cons_iff]
|
||||
|
||||
theorem not_cons_lex_cons_iff [DecidableEq α] [DecidableRel r] {a b} {l₁ l₂ : List α} :
|
||||
¬ Lex r (a :: l₁) (b :: l₂) ↔ (¬ r a b ∧ a ≠ b) ∨ (¬ r a b ∧ ¬ Lex r l₁ l₂) := by
|
||||
rw [cons_lex_cons_iff, not_or, Decidable.not_and_iff_or_not, and_or_left]
|
||||
|
||||
theorem cons_le_cons_iff [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a b} {l₁ l₂ : List α} :
|
||||
(a :: l₁) ≤ (b :: l₂) ↔ a < b ∨ a = b ∧ l₁ ≤ l₂ := by
|
||||
dsimp only [instLE, instLT, List.le, List.lt]
|
||||
simp only [not_cons_lex_cons_iff, ne_eq]
|
||||
constructor
|
||||
· rintro (⟨h₁, h₂⟩ | ⟨h₁, h₂⟩)
|
||||
· left
|
||||
apply Decidable.byContradiction
|
||||
intro h₃
|
||||
apply h₂
|
||||
exact i₂.antisymm _ _ h₁ h₃
|
||||
· if h₃ : a < b then
|
||||
exact .inl h₃
|
||||
else
|
||||
right
|
||||
exact ⟨i₂.antisymm _ _ h₃ h₁, h₂⟩
|
||||
· rintro (h | ⟨h₁, h₂⟩)
|
||||
· left
|
||||
exact ⟨i₁.asymm _ _ h, fun w => i₀.irrefl _ (w ▸ h)⟩
|
||||
· right
|
||||
exact ⟨fun w => i₀.irrefl _ (h₁ ▸ w), h₂⟩
|
||||
|
||||
theorem not_lt_of_cons_le_cons [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a b : α} {l₁ l₂ : List α} (h : a :: l₁ ≤ b :: l₂) : ¬ b < a := by
|
||||
rw [cons_le_cons_iff] at h
|
||||
rcases h with h | ⟨rfl, h⟩
|
||||
· exact i₁.asymm _ _ h
|
||||
· exact i₀.irrefl _
|
||||
|
||||
theorem le_of_cons_le_cons [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a} {l₁ l₂ : List α} (h : a :: l₁ ≤ a :: l₂) : l₁ ≤ l₂ := by
|
||||
rw [cons_le_cons_iff] at h
|
||||
rcases h with h | ⟨_, h⟩
|
||||
· exact False.elim (i₀.irrefl _ h)
|
||||
· exact h
|
||||
|
||||
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α → α → Prop)] (l : List α) : l ≤ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
intro
|
||||
| .rel h => exact i₀.irrefl _ h
|
||||
| .cons h₃ => exact ih h₃
|
||||
|
||||
instance [LT α] [Std.Irrefl (· < · : α → α → Prop)] : Std.Refl (· ≤ · : List α → List α → Prop) where
|
||||
refl := List.le_refl
|
||||
|
||||
theorem lex_trans {r : α → α → Prop} [DecidableRel r]
|
||||
(lt_trans : ∀ {x y z : α}, r x y → r y z → r x z)
|
||||
(h₁ : Lex r l₁ l₂) (h₂ : Lex r l₂ l₃) : Lex r l₁ l₃ := by
|
||||
induction h₁ generalizing l₃ with
|
||||
| nil => let _::_ := l₃; exact List.Lex.nil ..
|
||||
| @rel a l₁ b l₂ ab =>
|
||||
match h₂ with
|
||||
| .rel bc => exact List.Lex.rel (lt_trans ab bc)
|
||||
| .cons ih =>
|
||||
exact List.Lex.rel ab
|
||||
| @cons a l₁ l₂ h₁ ih2 =>
|
||||
match h₂ with
|
||||
| .rel bc =>
|
||||
exact List.Lex.rel bc
|
||||
| .cons ih =>
|
||||
exact List.Lex.cons (ih2 ih)
|
||||
|
||||
protected theorem lt_trans [LT α] [DecidableLT α]
|
||||
[i₁ : Trans (· < · : α → α → Prop) (· < ·) (· < ·)]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
|
||||
simp only [instLT, List.lt] at h₁ h₂ ⊢
|
||||
exact lex_trans (fun h₁ h₂ => i₁.trans h₁ h₂) h₁ h₂
|
||||
|
||||
instance [LT α] [DecidableLT α]
|
||||
[Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : List α → List α → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := List.lt_trans h₁ h₂
|
||||
|
||||
@[deprecated List.le_antisymm (since := "2024-12-13")]
|
||||
protected abbrev lt_antisymm := @List.le_antisymm
|
||||
|
||||
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
|
||||
induction h₂ generalizing l₁ with
|
||||
| nil => simp_all
|
||||
| rel hab =>
|
||||
rename_i a b
|
||||
cases l₁ with
|
||||
| nil => simp_all
|
||||
| cons c l₁ =>
|
||||
apply Lex.rel
|
||||
replace h₁ := not_lt_of_cons_le_cons h₁
|
||||
apply Decidable.byContradiction
|
||||
intro h₂
|
||||
have := i₃.trans h₁ h₂
|
||||
contradiction
|
||||
| cons w₃ ih =>
|
||||
rename_i a as bs
|
||||
cases l₁ with
|
||||
| nil => simp_all
|
||||
| cons c l₁ =>
|
||||
have w₄ := not_lt_of_cons_le_cons h₁
|
||||
by_cases w₅ : a = c
|
||||
· subst w₅
|
||||
exact Lex.cons (ih (le_of_cons_le_cons h₁))
|
||||
· exact Lex.rel (Decidable.byContradiction fun w₆ => w₅ (i₂.antisymm _ _ w₄ w₆))
|
||||
|
||||
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)] :
|
||||
Trans (· ≤ · : List α → List α → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans h₁ h₂ := List.le_trans h₁ h₂
|
||||
|
||||
theorem lex_asymm {r : α → α → Prop} [DecidableRel r]
|
||||
(h : ∀ {x y : α}, r x y → ¬ r y x) : ∀ {l₁ l₂ : List α}, Lex r l₁ l₂ → ¬ Lex r l₂ l₁
|
||||
| nil, _, .nil => by simp
|
||||
| x :: l₁, y :: l₂, .rel h₁ =>
|
||||
fun
|
||||
| .rel h₂ => h h₁ h₂
|
||||
| .cons h₂ => h h₁ h₁
|
||||
| x :: l₁, _ :: l₂, .cons h₁ =>
|
||||
fun
|
||||
| .rel h₂ => h h₂ h₂
|
||||
| .cons h₂ => lex_asymm h h₁ h₂
|
||||
|
||||
protected theorem lt_asymm [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{l₁ l₂ : List α} (h : l₁ < l₂) : ¬ l₂ < l₁ := lex_asymm (i.asymm _ _) h
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Asymm (· < · : List α → List α → Prop) where
|
||||
asymm _ _ := List.lt_asymm
|
||||
|
||||
theorem not_lex_total [DecidableEq α] {r : α → α → Prop} [DecidableRel r]
|
||||
(h : ∀ x y : α, ¬ r x y ∨ ¬ r y x) (l₁ l₂ : List α) : ¬ Lex r l₁ l₂ ∨ ¬ Lex r l₂ l₁ := by
|
||||
rw [Decidable.or_iff_not_imp_left, Decidable.not_not]
|
||||
intro w₁ w₂
|
||||
match l₁, l₂, w₁, w₂ with
|
||||
| nil, _ :: _, .nil, w₂ => simp at w₂
|
||||
| x :: _, y :: _, .rel _, .rel _ =>
|
||||
obtain (_ | _) := h x y <;> contradiction
|
||||
| x :: _, _ :: _, .rel _, .cons _ =>
|
||||
obtain (_ | _) := h x x <;> contradiction
|
||||
| x :: _, _ :: _, .cons _, .rel _ =>
|
||||
obtain (_ | _) := h x x <;> contradiction
|
||||
| _ :: l₁, _ :: l₂, .cons _, .cons _ =>
|
||||
obtain (_ | _) := not_lex_total h l₁ l₂ <;> contradiction
|
||||
|
||||
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] {l₁ l₂ : List α} : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
not_lex_total i.total l₂ l₁
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : List α → List α → Prop) where
|
||||
total _ _ := List.le_total
|
||||
|
||||
theorem lex_eq_decide_lex [DecidableEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = decide (Lex (fun x y => lt x y) l₁ l₂) := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex]
|
||||
| cons b bs => simp [lex]
|
||||
| cons a l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex]
|
||||
| cons b bs =>
|
||||
simp [lex, ih, cons_lex_cons_iff, Bool.beq_eq_decide_eq]
|
||||
|
||||
/-- Variant of `lex_eq_true_iff` using an arbitrary comparator. -/
|
||||
@[simp] theorem lex_eq_true_iff_lex [DecidableEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = true ↔ Lex (fun x y => lt x y) l₁ l₂ := by
|
||||
simp [lex_eq_decide_lex]
|
||||
|
||||
/-- Variant of `lex_eq_false_iff` using an arbitrary comparator. -/
|
||||
@[simp] theorem lex_eq_false_iff_not_lex [DecidableEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = false ↔ ¬ Lex (fun x y => lt x y) l₁ l₂ := by
|
||||
simp [Bool.eq_false_iff, lex_eq_true_iff_lex]
|
||||
|
||||
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : List α} : lex l₁ l₂ = true ↔ l₁ < l₂ := by
|
||||
simp only [lex_eq_true_iff_lex, decide_eq_true_eq]
|
||||
exact Iff.rfl
|
||||
|
||||
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : List α} : lex l₁ l₂ = false ↔ l₂ ≤ l₁ := by
|
||||
simp only [lex_eq_false_iff_not_lex, decide_eq_true_eq]
|
||||
exact Iff.rfl
|
||||
|
||||
attribute [local simp] Nat.add_one_lt_add_one_iff in
|
||||
/--
|
||||
`l₁` is lexicographically less than `l₂` if either
|
||||
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.length`,
|
||||
and `l₁` is shorter than `l₂` or
|
||||
- there exists an index `i` such that
|
||||
- for all `j < i`, `l₁[j] == l₂[j]` and
|
||||
- `l₁[i] < l₂[i]`
|
||||
-/
|
||||
theorem lex_eq_true_iff_exists [BEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = true ↔
|
||||
(l₁.isEqv (l₂.take l₁.length) (· == ·) ∧ l₁.length < l₂.length) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) ∧ lt l₁[i] l₂[i]) := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex]
|
||||
| cons b bs => simp [lex]
|
||||
| cons a l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex]
|
||||
| cons b l₂ =>
|
||||
simp only [lex_cons_cons, Bool.or_eq_true, Bool.and_eq_true, ih, isEqv, length_cons]
|
||||
constructor
|
||||
· rintro (hab | ⟨hab, ⟨h₁, h₂⟩ | ⟨i, h₁, h₂, w₁, w₂⟩⟩)
|
||||
· exact .inr ⟨0, by simp [hab]⟩
|
||||
· exact .inl ⟨⟨hab, h₁⟩, by simpa using h₂⟩
|
||||
· refine .inr ⟨i + 1, by simp [h₁],
|
||||
by simp [h₂], ?_, ?_⟩
|
||||
· intro j hj
|
||||
cases j with
|
||||
| zero => simp [hab]
|
||||
| succ j =>
|
||||
simp only [getElem_cons_succ]
|
||||
rw [w₁]
|
||||
simpa using hj
|
||||
· simpa using w₂
|
||||
· rintro (⟨⟨h₁, h₂⟩, h₃⟩ | ⟨i, h₁, h₂, w₁, w₂⟩)
|
||||
· exact .inr ⟨h₁, .inl ⟨h₂, by simpa using h₃⟩⟩
|
||||
· cases i with
|
||||
| zero =>
|
||||
left
|
||||
simpa using w₂
|
||||
| succ i =>
|
||||
right
|
||||
refine ⟨by simpa using w₁ 0 (by simp), ?_⟩
|
||||
right
|
||||
refine ⟨i, by simpa using h₁, by simpa using h₂, ?_, ?_⟩
|
||||
· intro j hj
|
||||
simpa using w₁ (j + 1) (by simpa)
|
||||
· simpa using w₂
|
||||
|
||||
attribute [local simp] Nat.add_one_lt_add_one_iff in
|
||||
/--
|
||||
`l₁` is *not* lexicographically less than `l₂`
|
||||
(which you might think of as "`l₂` is lexicographically greater than or equal to `l₁`"") if either
|
||||
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.length` or
|
||||
- there exists an index `i` such that
|
||||
- for all `j < i`, `l₁[j] == l₂[j]` and
|
||||
- `l₂[i] < l₁[i]`
|
||||
|
||||
This formulation requires that `==` and `lt` are compatible in the following senses:
|
||||
- `==` is symmetric
|
||||
(we unnecessarily further assume it is transitive, to make use of the existing typeclasses)
|
||||
- `lt` is irreflexive with respect to `==` (i.e. if `x == y` then `lt x y = false`
|
||||
- `lt` is asymmmetric (i.e. `lt x y = true → lt y x = false`)
|
||||
- `lt` is antisymmetric with respect to `==` (i.e. `lt x y = false → lt y x = false → x == y`)
|
||||
-/
|
||||
theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α → α → Bool)
|
||||
(lt_irrefl : ∀ x y, x == y → lt x y = false)
|
||||
(lt_asymm : ∀ x y, lt x y = true → lt y x = false)
|
||||
(lt_antisymm : ∀ x y, lt x y = false → lt y x = false → x == y) :
|
||||
lex l₁ l₂ lt = false ↔
|
||||
(l₂.isEqv (l₁.take l₂.length) (· == ·)) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) ∧ lt l₂[i] l₁[i]) := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex]
|
||||
| cons b bs => simp [lex]
|
||||
| cons a l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex]
|
||||
| cons b l₂ =>
|
||||
simp only [lex_cons_cons, Bool.or_eq_false_iff, Bool.and_eq_false_imp, ih, isEqv,
|
||||
Bool.and_eq_true, length_cons]
|
||||
constructor
|
||||
· rintro ⟨hab, h⟩
|
||||
if eq : b == a then
|
||||
specialize h (BEq.symm eq)
|
||||
obtain (h | ⟨i, h₁, h₂, w₁, w₂⟩) := h
|
||||
· exact .inl ⟨eq, h⟩
|
||||
· refine .inr ⟨i + 1, by simpa using h₁, by simpa using h₂, ?_, ?_⟩
|
||||
· intro j hj
|
||||
cases j with
|
||||
| zero => simpa using BEq.symm eq
|
||||
| succ j =>
|
||||
simp only [getElem_cons_succ]
|
||||
rw [w₁]
|
||||
simpa using hj
|
||||
· simpa using w₂
|
||||
else
|
||||
right
|
||||
have hba : lt b a :=
|
||||
Decidable.byContradiction fun hba => eq (lt_antisymm _ _ (by simpa using hba) hab)
|
||||
exact ⟨0, by simp, by simp, by simpa⟩
|
||||
· rintro (⟨eq, h⟩ | ⟨i, h₁, h₂, w₁, w₂⟩)
|
||||
· exact ⟨lt_irrefl _ _ (BEq.symm eq), fun _ => .inl h⟩
|
||||
· cases i with
|
||||
| zero =>
|
||||
simp at w₂
|
||||
refine ⟨lt_asymm _ _ w₂, ?_⟩
|
||||
intro eq
|
||||
exfalso
|
||||
simp [lt_irrefl _ _ (BEq.symm eq)] at w₂
|
||||
| succ i =>
|
||||
refine ⟨lt_irrefl _ _ (by simpa using w₁ 0 (by simp)), ?_⟩
|
||||
refine fun _ => .inr ⟨i, by simpa using h₁, by simpa using h₂, ?_, ?_⟩
|
||||
· intro j hj
|
||||
simpa using w₁ (j + 1) (by simpa)
|
||||
· simpa using w₂
|
||||
|
||||
theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : List α} :
|
||||
l₁ < l₂ ↔
|
||||
(l₁ = l₂.take l₁.length ∧ l₁.length < l₂.length) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) ∧ l₁[i] < l₂[i]) := by
|
||||
rw [← lex_eq_true_iff_lt, lex_eq_true_iff_exists]
|
||||
simp
|
||||
|
||||
theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {l₁ l₂ : List α} :
|
||||
l₁ ≤ l₂ ↔
|
||||
(l₁ = l₂.take l₁.length) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) ∧ l₁[i] < l₂[i]) := by
|
||||
rw [← lex_eq_false_iff_ge, lex_eq_false_iff_exists]
|
||||
· simp only [isEqv_eq, beq_iff_eq, decide_eq_true_eq]
|
||||
simp only [eq_comm]
|
||||
conv => lhs; simp +singlePass [exists_comm]
|
||||
· simpa using Std.Irrefl.irrefl
|
||||
· simpa using Std.Asymm.asymm
|
||||
· simpa using Std.Antisymm.antisymm
|
||||
|
||||
end List
|
||||
@@ -237,15 +237,15 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
|
||||
if h : i < arr.size then some arr[i] else Option.map (f i) l[i - arr.size]?
|
||||
| [], arr, i => by
|
||||
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
|
||||
Array.getElem_eq_getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none']
|
||||
← Array.getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none']
|
||||
| a :: l, arr, i => by
|
||||
rw [mapIdx.go, getElem?_mapIdx_go]
|
||||
simp only [Array.size_push]
|
||||
split <;> split
|
||||
· simp only [Option.some.injEq]
|
||||
rw [Array.getElem_eq_getElem_toList]
|
||||
rw [← Array.getElem_toList]
|
||||
simp only [Array.push_toList]
|
||||
rw [getElem_append_left, Array.getElem_eq_getElem_toList]
|
||||
rw [getElem_append_left, ← Array.getElem_toList]
|
||||
· have : i = arr.size := by omega
|
||||
simp_all
|
||||
· omega
|
||||
|
||||
@@ -85,7 +85,7 @@ theorem min?_eq_some_iff [Min α] [LE α] [anti : Std.Antisymm ((· : α) ≤ ·
|
||||
cases xs with
|
||||
| nil => simp at h₁
|
||||
| cons x xs =>
|
||||
exact congrArg some <| anti.1
|
||||
exact congrArg some <| anti.1 _ _
|
||||
((le_min?_iff le_min_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
|
||||
(h₂ _ (min?_mem min_eq_or (xs := x::xs) rfl))
|
||||
|
||||
@@ -156,7 +156,7 @@ theorem max?_eq_some_iff [Max α] [LE α] [anti : Std.Antisymm ((· : α) ≤ ·
|
||||
cases xs with
|
||||
| nil => simp at h₁
|
||||
| cons x xs =>
|
||||
exact congrArg some <| anti.1
|
||||
exact congrArg some <| anti.1 _ _
|
||||
(h₂ _ (max?_mem max_eq_or (xs := x::xs) rfl))
|
||||
((max?_le_iff max_le_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
|
||||
|
||||
|
||||
@@ -124,7 +124,8 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
|
||||
|
||||
/-! ### forM -/
|
||||
|
||||
-- We use `List.forM` as the simp normal form, rather that `ForM.forM`.
|
||||
-- We currently use `List.forM` as the simp normal form, rather that `ForM.forM`.
|
||||
-- (This should probably be revisited.)
|
||||
-- As such we need to replace `List.forM_nil` and `List.forM_cons`:
|
||||
|
||||
@[simp] theorem forM_nil' [Monad m] : ([] : List α).forM f = (pure .unit : m PUnit) := rfl
|
||||
@@ -137,6 +138,10 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
|
||||
(l₁ ++ l₂).forM f = (do l₁.forM f; l₂.forM f) := by
|
||||
induction l₁ <;> simp [*]
|
||||
|
||||
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (l : List α) (g : α → β) (f : β → m PUnit) :
|
||||
(l.map g).forM f = l.forM (fun a => f (g a)) := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
/-! ### forIn' -/
|
||||
|
||||
theorem forIn'_loop_congr [Monad m] {as bs : List α}
|
||||
@@ -259,6 +264,11 @@ theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
generalize l.attach = l'
|
||||
induction l' generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
(l : List α) (g : α → β) (f : (b : β) → b ∈ l.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem g h) y := by
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
/--
|
||||
We can express a for loop over a list as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
@@ -307,6 +317,11 @@ theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
(l : List α) (g : α → β) (f : β → γ → m (ForInStep γ)) :
|
||||
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
/-! ### allM -/
|
||||
|
||||
theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α → m Bool) (as : List α) :
|
||||
|
||||
@@ -68,8 +68,8 @@ theorem getElem?_modifyHead {l : List α} {f : α → α} {n} :
|
||||
(l.modifyHead f).drop n = l.drop n := by
|
||||
cases l <;> cases n <;> simp_all
|
||||
|
||||
@[simp] theorem eraseIdx_modifyHead_zero {f : α → α} {l : List α} :
|
||||
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by cases l <;> simp
|
||||
theorem eraseIdx_modifyHead_zero {f : α → α} {l : List α} :
|
||||
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by simp
|
||||
|
||||
@[simp] theorem eraseIdx_modifyHead_of_pos {f : α → α} {l : List α} {n} (h : 0 < n) :
|
||||
(l.modifyHead f).eraseIdx n = (l.eraseIdx n).modifyHead f := by cases l <;> cases n <;> simp_all
|
||||
@@ -142,7 +142,7 @@ theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (n : Nat) (
|
||||
theorem modifyHead_eq_modify_zero (f : α → α) (l : List α) :
|
||||
l.modifyHead f = l.modify f 0 := by cases l <;> simp
|
||||
|
||||
@[simp] theorem modify_eq_nil_iff (f : α → α) (n) (l : List α) :
|
||||
@[simp] theorem modify_eq_nil_iff {f : α → α} {n} {l : List α} :
|
||||
l.modify f n = [] ↔ l = [] := by cases l <;> cases n <;> simp
|
||||
|
||||
theorem getElem?_modify (f : α → α) :
|
||||
|
||||
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.Nat.Div.Basic
|
||||
|
||||
/-!
|
||||
# Notation for `List` literals.
|
||||
|
||||
@@ -84,11 +84,15 @@ theorem head?_range' (n : Nat) : (range' s n).head? = if n = 0 then none else so
|
||||
@[simp] theorem head_range' (n : Nat) (h) : (range' s n).head h = s := by
|
||||
repeat simp_all [head?_range', head_eq_iff_head?_eq_some]
|
||||
|
||||
@[simp]
|
||||
theorem map_add_range' (a) : ∀ s n step, map (a + ·) (range' s n step) = range' (a + s) n step
|
||||
| _, 0, _ => rfl
|
||||
| s, n + 1, step => by simp [range', map_add_range' _ (s + step) n step, Nat.add_assoc]
|
||||
|
||||
theorem range'_succ_left : range' (s + 1) n step = (range' s n step).map (· + 1) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· simp [Nat.add_right_comm]
|
||||
|
||||
theorem range'_append : ∀ s m n step : Nat,
|
||||
range' s m step ++ range' (s + step * m) n step = range' s (n + m) step
|
||||
| _, 0, _, _ => rfl
|
||||
|
||||
@@ -40,12 +40,15 @@ def merge (xs ys : List α) (le : α → α → Bool := by exact fun a b => a
|
||||
|
||||
/--
|
||||
Split a list in two equal parts. If the length is odd, the first part will be one element longer.
|
||||
|
||||
This is an implementation detail of `mergeSort`.
|
||||
-/
|
||||
def splitInTwo (l : { l : List α // l.length = n }) :
|
||||
def MergeSort.Internal.splitInTwo (l : { l : List α // l.length = n }) :
|
||||
{ l : List α // l.length = (n+1)/2 } × { l : List α // l.length = n/2 } :=
|
||||
let r := splitAt ((n+1)/2) l.1
|
||||
(⟨r.1, by simp [r, splitAt_eq, l.2]; omega⟩, ⟨r.2, by simp [r, splitAt_eq, l.2]; omega⟩)
|
||||
|
||||
open MergeSort.Internal in
|
||||
set_option linter.unusedVariables false in
|
||||
/--
|
||||
Simplified implementation of stable merge sort.
|
||||
|
||||
@@ -147,23 +147,21 @@ where
|
||||
mergeTR (run' r) (run l) le
|
||||
|
||||
theorem splitRevInTwo'_fst (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo' l).1 = ⟨(splitInTwo ⟨l.1.reverse, by simpa using l.2⟩).2.1, by have := l.2; simp; omega⟩ := by
|
||||
(splitRevInTwo' l).1 = ⟨(splitInTwo ⟨l.1.reverse, by simpa using l.2⟩).2.1, by simp; omega⟩ := by
|
||||
simp only [splitRevInTwo', splitRevAt_eq, reverse_take, splitInTwo_snd]
|
||||
congr
|
||||
have := l.2
|
||||
omega
|
||||
theorem splitRevInTwo'_snd (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo' l).2 = ⟨(splitInTwo ⟨l.1.reverse, by simpa using l.2⟩).1.1.reverse, by have := l.2; simp; omega⟩ := by
|
||||
(splitRevInTwo' l).2 = ⟨(splitInTwo ⟨l.1.reverse, by simpa using l.2⟩).1.1.reverse, by simp; omega⟩ := by
|
||||
simp only [splitRevInTwo', splitRevAt_eq, reverse_take, splitInTwo_fst, reverse_reverse]
|
||||
congr 2
|
||||
have := l.2
|
||||
simp
|
||||
omega
|
||||
theorem splitRevInTwo_fst (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo l).1 = ⟨(splitInTwo l).1.1.reverse, by have := l.2; simp; omega⟩ := by
|
||||
(splitRevInTwo l).1 = ⟨(splitInTwo l).1.1.reverse, by simp; omega⟩ := by
|
||||
simp only [splitRevInTwo, splitRevAt_eq, reverse_take, splitInTwo_fst]
|
||||
theorem splitRevInTwo_snd (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo l).2 = ⟨(splitInTwo l).2.1, by have := l.2; simp; omega⟩ := by
|
||||
(splitRevInTwo l).2 = ⟨(splitInTwo l).2.1, by simp; omega⟩ := by
|
||||
simp only [splitRevInTwo, splitRevAt_eq, reverse_take, splitInTwo_snd]
|
||||
|
||||
theorem mergeSortTR_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR.run le l = mergeSort l.1 le
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace List
|
||||
|
||||
/-! ### splitInTwo -/
|
||||
|
||||
namespace MergeSort.Internal
|
||||
|
||||
@[simp] theorem splitInTwo_fst (l : { l : List α // l.length = n }) :
|
||||
(splitInTwo l).1 = ⟨l.1.take ((n+1)/2), by simp [splitInTwo, splitAt_eq, l.2]; omega⟩ := by
|
||||
simp [splitInTwo, splitAt_eq]
|
||||
@@ -82,6 +84,10 @@ theorem splitInTwo_fst_le_splitInTwo_snd {l : { l : List α // l.length = n }} (
|
||||
intro a b ma mb
|
||||
exact h.rel_of_mem_take_of_mem_drop ma mb
|
||||
|
||||
end MergeSort.Internal
|
||||
|
||||
open MergeSort.Internal
|
||||
|
||||
/-! ### enumLE -/
|
||||
|
||||
variable {le : α → α → Bool}
|
||||
@@ -285,8 +291,6 @@ theorem sorted_mergeSort
|
||||
| [] => by simp [mergeSort]
|
||||
| [a] => by simp [mergeSort]
|
||||
| a :: b :: xs => by
|
||||
have : (splitInTwo ⟨a :: b :: xs, rfl⟩).1.1.length < xs.length + 1 + 1 := by simp [splitInTwo_fst]; omega
|
||||
have : (splitInTwo ⟨a :: b :: xs, rfl⟩).2.1.length < xs.length + 1 + 1 := by simp [splitInTwo_snd]; omega
|
||||
rw [mergeSort]
|
||||
apply sorted_merge @trans @total
|
||||
apply sorted_mergeSort trans total
|
||||
|
||||
@@ -841,7 +841,7 @@ theorem isPrefix_iff : l₁ <+: l₂ ↔ ∀ i (h : i < l₁.length), l₂[i]? =
|
||||
theorem isPrefix_iff_getElem {l₁ l₂ : List α} :
|
||||
l₁ <+: l₂ ↔ ∃ (h : l₁.length ≤ l₂.length), ∀ x (hx : x < l₁.length),
|
||||
l₁[x] = l₂[x]'(Nat.lt_of_lt_of_le hx h) where
|
||||
mp h := ⟨h.length_le, fun _ _ ↦ h.getElem _⟩
|
||||
mp h := ⟨h.length_le, fun _ h' ↦ h.getElem h'⟩
|
||||
mpr h := by
|
||||
obtain ⟨hl, h⟩ := h
|
||||
induction l₂ generalizing l₁ with
|
||||
|
||||
@@ -65,13 +65,13 @@ theorem lt_length_of_take_ne_self {l : List α} {n} (h : l.take n ≠ l) : n < l
|
||||
theorem getElem_cons_drop : ∀ (l : List α) (i : Nat) (h : i < l.length),
|
||||
l[i] :: drop (i + 1) l = drop i l
|
||||
| _::_, 0, _ => rfl
|
||||
| _::_, i+1, _ => getElem_cons_drop _ i _
|
||||
| _::_, i+1, h => getElem_cons_drop _ i (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[deprecated getElem_cons_drop (since := "2024-06-12")]
|
||||
theorem get_cons_drop (l : List α) (i) : get l i :: drop (i + 1) l = drop i l := by
|
||||
simp
|
||||
|
||||
theorem drop_eq_getElem_cons {n} {l : List α} (h) : drop n l = l[n] :: drop (n + 1) l :=
|
||||
theorem drop_eq_getElem_cons {n} {l : List α} (h : n < l.length) : drop n l = l[n] :: drop (n + 1) l :=
|
||||
(getElem_cons_drop _ n h).symm
|
||||
|
||||
@[deprecated drop_eq_getElem_cons (since := "2024-06-12")]
|
||||
|
||||
@@ -1,23 +1,397 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
Authors: Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Basic
|
||||
import Init.Data.List.Impl
|
||||
import Init.Data.List.Nat.Erase
|
||||
import Init.Data.List.Monadic
|
||||
import Init.Data.Array.Lex.Basic
|
||||
|
||||
/--
|
||||
Auxiliary definition for `List.toArray`.
|
||||
`List.toArrayAux as r = r ++ as.toArray`
|
||||
/-! ### Lemmas about `List.toArray`.
|
||||
|
||||
We prefer to pull `List.toArray` outwards past `Array` operations.
|
||||
-/
|
||||
@[inline_if_reduce]
|
||||
def List.toArrayAux : List α → Array α → Array α
|
||||
| nil, r => r
|
||||
| cons a as, r => toArrayAux as (r.push a)
|
||||
namespace List
|
||||
|
||||
/-- Convert a `List α` into an `Array α`. This is O(n) in the length of the list. -/
|
||||
-- This function is exported to C, where it is called by `Array.mk`
|
||||
-- (the constructor) to implement this functionality.
|
||||
@[inline, match_pattern, pp_nodot, export lean_list_to_array]
|
||||
def List.toArrayImpl (as : List α) : Array α :=
|
||||
as.toArrayAux (Array.mkEmpty as.length)
|
||||
open Array
|
||||
|
||||
theorem toArray_inj {a b : List α} (h : a.toArray = b.toArray) : a = b := by
|
||||
cases a with
|
||||
| nil => simpa using h
|
||||
| cons a as =>
|
||||
cases b with
|
||||
| nil => simp at h
|
||||
| cons b bs => simpa using h
|
||||
|
||||
@[simp] theorem size_toArrayAux {a : List α} {b : Array α} :
|
||||
(a.toArrayAux b).size = b.size + a.length := by
|
||||
simp [size]
|
||||
|
||||
-- This is not a `@[simp]` lemma because it is pushing `toArray` inwards.
|
||||
theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem push_toArray (l : List α) (a : α) : l.toArray.push a = (l ++ [a]).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
/-- Unapplied variant of `push_toArray`, useful for monadic reasoning. -/
|
||||
@[simp] theorem push_toArray_fun (l : List α) : l.toArray.push = fun a => (l ++ [a]).toArray := by
|
||||
funext a
|
||||
simp
|
||||
|
||||
@[simp] theorem isEmpty_toArray (l : List α) : l.toArray.isEmpty = l.isEmpty := by
|
||||
cases l <;> simp [Array.isEmpty]
|
||||
|
||||
@[simp] theorem toArray_singleton (a : α) : (List.singleton a).toArray = singleton a := rfl
|
||||
|
||||
@[simp] theorem back!_toArray [Inhabited α] (l : List α) : l.toArray.back! = l.getLast! := by
|
||||
simp only [back!, size_toArray, Array.get!_eq_getElem!, getElem!_toArray, getLast!_eq_getElem!]
|
||||
|
||||
@[simp] theorem back?_toArray (l : List α) : l.toArray.back? = l.getLast? := by
|
||||
simp [back?, List.getLast?_eq_getElem?]
|
||||
|
||||
@[simp] theorem set_toArray (l : List α) (i : Nat) (a : α) (h : i < l.length) :
|
||||
(l.toArray.set i a) = (l.set i a).toArray := rfl
|
||||
|
||||
@[simp] theorem forIn'_loop_toArray [Monad m] (l : List α) (f : (a : α) → a ∈ l.toArray → β → m (ForInStep β)) (i : Nat)
|
||||
(h : i ≤ l.length) (b : β) :
|
||||
Array.forIn'.loop l.toArray f i h b =
|
||||
forIn' (l.drop (l.length - i)) b (fun a m b => f a (by simpa using mem_of_mem_drop m) b) := by
|
||||
induction i generalizing l b with
|
||||
| zero =>
|
||||
simp [Array.forIn'.loop]
|
||||
| succ i ih =>
|
||||
simp only [Array.forIn'.loop, size_toArray, getElem_toArray, ih]
|
||||
have t : drop (l.length - (i + 1)) l = l[l.length - i - 1] :: drop (l.length - i) l := by
|
||||
simp only [Nat.sub_add_eq]
|
||||
rw [List.drop_sub_one (by omega), List.getElem?_eq_getElem (by omega)]
|
||||
simp only [Option.toList_some, singleton_append]
|
||||
simp [t]
|
||||
have t : l.length - 1 - i = l.length - i - 1 := by omega
|
||||
simp only [t]
|
||||
congr
|
||||
|
||||
@[simp] theorem forIn'_toArray [Monad m] (l : List α) (b : β) (f : (a : α) → a ∈ l.toArray → β → m (ForInStep β)) :
|
||||
forIn' l.toArray b f = forIn' l b (fun a m b => f a (mem_toArray.mpr m) b) := by
|
||||
change Array.forIn' _ _ _ = List.forIn' _ _ _
|
||||
rw [Array.forIn', forIn'_loop_toArray]
|
||||
simp
|
||||
|
||||
@[simp] theorem forIn_toArray [Monad m] (l : List α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn l.toArray b f = forIn l b f := by
|
||||
simpa using forIn'_toArray l b fun a m b => f a b
|
||||
|
||||
theorem foldrM_toArray [Monad m] (f : α → β → m β) (init : β) (l : List α) :
|
||||
l.toArray.foldrM f init = l.foldrM f init := by
|
||||
rw [foldrM_eq_reverse_foldlM_toList]
|
||||
simp
|
||||
|
||||
theorem foldlM_toArray [Monad m] (f : β → α → m β) (init : β) (l : List α) :
|
||||
l.toArray.foldlM f init = l.foldlM f init := by
|
||||
rw [foldlM_toList]
|
||||
|
||||
theorem foldr_toArray (f : α → β → β) (init : β) (l : List α) :
|
||||
l.toArray.foldr f init = l.foldr f init := by
|
||||
rw [foldr_toList]
|
||||
|
||||
theorem foldl_toArray (f : β → α → β) (init : β) (l : List α) :
|
||||
l.toArray.foldl f init = l.foldl f init := by
|
||||
rw [foldl_toList]
|
||||
|
||||
/-- Variant of `foldrM_toArray` with a side condition for the `start` argument. -/
|
||||
@[simp] theorem foldrM_toArray' [Monad m] (f : α → β → m β) (init : β) (l : List α)
|
||||
(h : start = l.toArray.size) :
|
||||
l.toArray.foldrM f init start 0 = l.foldrM f init := by
|
||||
subst h
|
||||
rw [foldrM_eq_reverse_foldlM_toList]
|
||||
simp
|
||||
|
||||
/-- Variant of `foldlM_toArray` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem foldlM_toArray' [Monad m] (f : β → α → m β) (init : β) (l : List α)
|
||||
(h : stop = l.toArray.size) :
|
||||
l.toArray.foldlM f init 0 stop = l.foldlM f init := by
|
||||
subst h
|
||||
rw [foldlM_toList]
|
||||
|
||||
/-- Variant of `forM_toArray` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem forM_toArray' [Monad m] (l : List α) (f : α → m PUnit) (h : stop = l.toArray.size) :
|
||||
(l.toArray.forM f 0 stop) = l.forM f := by
|
||||
subst h
|
||||
rw [Array.forM]
|
||||
simp only [size_toArray, foldlM_toArray']
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
|
||||
(l.toArray.forM f) = l.forM f := by
|
||||
simp
|
||||
|
||||
/-- Variant of `foldr_toArray` with a side condition for the `start` argument. -/
|
||||
@[simp] theorem foldr_toArray' (f : α → β → β) (init : β) (l : List α)
|
||||
(h : start = l.toArray.size) :
|
||||
l.toArray.foldr f init start 0 = l.foldr f init := by
|
||||
subst h
|
||||
rw [foldr_toList]
|
||||
|
||||
/-- Variant of `foldl_toArray` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem foldl_toArray' (f : β → α → β) (init : β) (l : List α)
|
||||
(h : stop = l.toArray.size) :
|
||||
l.toArray.foldl f init 0 stop = l.foldl f init := by
|
||||
subst h
|
||||
rw [foldl_toList]
|
||||
|
||||
@[simp] theorem append_toArray (l₁ l₂ : List α) :
|
||||
l₁.toArray ++ l₂.toArray = (l₁ ++ l₂).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem push_append_toArray {as : Array α} {a : α} {bs : List α} : as.push a ++ bs.toArray = as ++ (a ::bs).toArray := by
|
||||
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 b => push b a) as = as ++ l.reverse.toArray := by
|
||||
rw [foldr_eq_foldl_reverse, foldl_push]
|
||||
|
||||
@[simp] theorem findSomeM?_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α) :
|
||||
l.toArray.findSomeM? f = l.findSomeM? f := by
|
||||
rw [Array.findSomeM?]
|
||||
simp only [bind_pure_comp, map_pure, forIn_toArray]
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [forIn_cons, LawfulMonad.bind_assoc, findSomeM?]
|
||||
congr
|
||||
ext1 (_|_) <;> simp [ih]
|
||||
|
||||
theorem findSomeRevM?_find_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α)
|
||||
(i : Nat) (h) :
|
||||
findSomeRevM?.find f l.toArray i h = (l.take i).reverse.findSomeM? f := by
|
||||
induction i generalizing l with
|
||||
| zero => simp [Array.findSomeRevM?.find.eq_def]
|
||||
| succ i ih =>
|
||||
rw [size_toArray] at h
|
||||
rw [Array.findSomeRevM?.find, take_succ, getElem?_eq_getElem (by omega)]
|
||||
simp only [ih, reverse_append]
|
||||
congr
|
||||
ext1 (_|_) <;> simp
|
||||
|
||||
-- This is not marked as `@[simp]` as later we simplify all occurrences of `findSomeRevM?`.
|
||||
theorem findSomeRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α) :
|
||||
l.toArray.findSomeRevM? f = l.reverse.findSomeM? f := by
|
||||
simp [Array.findSomeRevM?, findSomeRevM?_find_toArray]
|
||||
|
||||
-- This is not marked as `@[simp]` as later we simplify all occurrences of `findRevM?`.
|
||||
theorem findRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : List α) :
|
||||
l.toArray.findRevM? f = l.reverse.findM? f := by
|
||||
rw [Array.findRevM?, findSomeRevM?_toArray, findM?_eq_findSomeM?]
|
||||
|
||||
@[simp] theorem findM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : List α) :
|
||||
l.toArray.findM? f = l.findM? f := by
|
||||
rw [Array.findM?]
|
||||
simp only [bind_pure_comp, map_pure, forIn_toArray]
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [forIn_cons, LawfulMonad.bind_assoc, findM?]
|
||||
congr
|
||||
ext1 (_|_) <;> simp [ih]
|
||||
|
||||
@[simp] theorem findSome?_toArray (f : α → Option β) (l : List α) :
|
||||
l.toArray.findSome? f = l.findSome? f := by
|
||||
rw [Array.findSome?, ← findSomeM?_id, findSomeM?_toArray, Id.run]
|
||||
|
||||
@[simp] 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]
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [forIn_cons, Id.pure_eq, Id.bind_eq, find?]
|
||||
by_cases f a <;> simp_all
|
||||
|
||||
theorem isPrefixOfAux_toArray_succ [BEq α] (l₁ l₂ : List α) (hle : l₁.length ≤ l₂.length) (i : Nat) :
|
||||
Array.isPrefixOfAux l₁.toArray l₂.toArray hle (i + 1) =
|
||||
Array.isPrefixOfAux l₁.tail.toArray l₂.tail.toArray (by simp; omega) i := by
|
||||
rw [Array.isPrefixOfAux]
|
||||
conv => rhs; rw [Array.isPrefixOfAux]
|
||||
simp only [size_toArray, getElem_toArray, Bool.if_false_right, length_tail, getElem_tail]
|
||||
split <;> rename_i h₁ <;> split <;> rename_i h₂
|
||||
· rw [isPrefixOfAux_toArray_succ]
|
||||
· omega
|
||||
· omega
|
||||
· rfl
|
||||
|
||||
theorem isPrefixOfAux_toArray_succ' [BEq α] (l₁ l₂ : List α) (hle : l₁.length ≤ l₂.length) (i : Nat) :
|
||||
Array.isPrefixOfAux l₁.toArray l₂.toArray hle (i + 1) =
|
||||
Array.isPrefixOfAux (l₁.drop (i+1)).toArray (l₂.drop (i+1)).toArray (by simp; omega) 0 := by
|
||||
induction i generalizing l₁ l₂ with
|
||||
| zero => simp [isPrefixOfAux_toArray_succ]
|
||||
| succ i ih =>
|
||||
rw [isPrefixOfAux_toArray_succ, ih]
|
||||
simp
|
||||
|
||||
theorem isPrefixOfAux_toArray_zero [BEq α] (l₁ l₂ : List α) (hle : l₁.length ≤ l₂.length) :
|
||||
Array.isPrefixOfAux l₁.toArray l₂.toArray hle 0 =
|
||||
l₁.isPrefixOf l₂ := by
|
||||
rw [Array.isPrefixOfAux]
|
||||
match l₁, l₂ with
|
||||
| [], _ => rw [dif_neg] <;> simp
|
||||
| _::_, [] => simp at hle
|
||||
| a::l₁, b::l₂ =>
|
||||
simp [isPrefixOf_cons₂, isPrefixOfAux_toArray_succ', isPrefixOfAux_toArray_zero]
|
||||
|
||||
@[simp] theorem isPrefixOf_toArray [BEq α] (l₁ l₂ : List α) :
|
||||
l₁.toArray.isPrefixOf l₂.toArray = l₁.isPrefixOf l₂ := by
|
||||
rw [Array.isPrefixOf]
|
||||
split <;> rename_i h
|
||||
· simp [isPrefixOfAux_toArray_zero]
|
||||
· simp only [Bool.false_eq]
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil => simp at h
|
||||
| cons a l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp
|
||||
| cons b l₂ =>
|
||||
simp only [isPrefixOf_cons₂, Bool.and_eq_false_imp]
|
||||
intro w
|
||||
rw [ih]
|
||||
simp_all
|
||||
|
||||
theorem zipWithAux_toArray_succ (as : List α) (bs : List β) (f : α → β → γ) (i : Nat) (cs : Array γ) :
|
||||
zipWithAux as.toArray bs.toArray f (i + 1) cs = zipWithAux as.tail.toArray bs.tail.toArray f i cs := by
|
||||
rw [zipWithAux]
|
||||
conv => rhs; rw [zipWithAux]
|
||||
simp only [size_toArray, getElem_toArray, length_tail, getElem_tail]
|
||||
split <;> rename_i h₁
|
||||
· split <;> rename_i h₂
|
||||
· rw [dif_pos (by omega), dif_pos (by omega), zipWithAux_toArray_succ]
|
||||
· rw [dif_pos (by omega)]
|
||||
rw [dif_neg (by omega)]
|
||||
· rw [dif_neg (by omega)]
|
||||
|
||||
theorem zipWithAux_toArray_succ' (as : List α) (bs : List β) (f : α → β → γ) (i : Nat) (cs : Array γ) :
|
||||
zipWithAux as.toArray bs.toArray f (i + 1) cs = zipWithAux (as.drop (i+1)).toArray (bs.drop (i+1)).toArray f 0 cs := by
|
||||
induction i generalizing as bs cs with
|
||||
| zero => simp [zipWithAux_toArray_succ]
|
||||
| succ i ih =>
|
||||
rw [zipWithAux_toArray_succ, ih]
|
||||
simp
|
||||
|
||||
theorem zipWithAux_toArray_zero (f : α → β → γ) (as : List α) (bs : List β) (cs : Array γ) :
|
||||
zipWithAux as.toArray bs.toArray f 0 cs = cs ++ (List.zipWith f as bs).toArray := by
|
||||
rw [Array.zipWithAux]
|
||||
match as, bs with
|
||||
| [], _ => simp
|
||||
| _, [] => simp
|
||||
| a :: as, b :: bs =>
|
||||
simp [zipWith_cons_cons, zipWithAux_toArray_succ', zipWithAux_toArray_zero, push_append_toArray]
|
||||
|
||||
@[simp] theorem zipWith_toArray (as : List α) (bs : List β) (f : α → β → γ) :
|
||||
Array.zipWith as.toArray bs.toArray f = (List.zipWith f as bs).toArray := by
|
||||
rw [Array.zipWith]
|
||||
simp [zipWithAux_toArray_zero]
|
||||
|
||||
@[simp] theorem zip_toArray (as : List α) (bs : List β) :
|
||||
Array.zip as.toArray bs.toArray = (List.zip as bs).toArray := by
|
||||
simp [Array.zip, zipWith_toArray, zip]
|
||||
|
||||
theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → Option β → γ) (i : Nat) (cs : Array γ) :
|
||||
zipWithAll.go f as.toArray bs.toArray i cs = cs ++ (List.zipWithAll f (as.drop i) (bs.drop i)).toArray := by
|
||||
unfold zipWithAll.go
|
||||
split <;> rename_i h
|
||||
· rw [zipWithAll_go_toArray]
|
||||
simp at h
|
||||
simp only [getElem?_toArray, push_append_toArray]
|
||||
if ha : i < as.length then
|
||||
if hb : i < bs.length then
|
||||
rw [List.drop_eq_getElem_cons ha, List.drop_eq_getElem_cons hb]
|
||||
simp only [ha, hb, getElem?_eq_getElem, zipWithAll_cons_cons]
|
||||
else
|
||||
simp only [Nat.not_lt] at hb
|
||||
rw [List.drop_eq_getElem_cons ha]
|
||||
rw [(drop_eq_nil_iff (l := bs)).mpr (by omega), (drop_eq_nil_iff (l := bs)).mpr (by omega)]
|
||||
simp only [zipWithAll_nil, map_drop, map_cons]
|
||||
rw [getElem?_eq_getElem ha]
|
||||
rw [getElem?_eq_none hb]
|
||||
else
|
||||
if hb : i < bs.length then
|
||||
simp only [Nat.not_lt] at ha
|
||||
rw [List.drop_eq_getElem_cons hb]
|
||||
rw [(drop_eq_nil_iff (l := as)).mpr (by omega), (drop_eq_nil_iff (l := as)).mpr (by omega)]
|
||||
simp only [nil_zipWithAll, map_drop, map_cons]
|
||||
rw [getElem?_eq_getElem hb]
|
||||
rw [getElem?_eq_none ha]
|
||||
else
|
||||
omega
|
||||
· simp only [size_toArray, Nat.not_lt] at h
|
||||
rw [drop_eq_nil_of_le (by omega), drop_eq_nil_of_le (by omega)]
|
||||
simp
|
||||
termination_by max as.length bs.length - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[simp] theorem zipWithAll_toArray (f : Option α → Option β → γ) (as : List α) (bs : List β) :
|
||||
Array.zipWithAll as.toArray bs.toArray f = (List.zipWithAll f as bs).toArray := by
|
||||
simp [Array.zipWithAll, zipWithAll_go_toArray]
|
||||
|
||||
@[simp] theorem toArray_appendList (l₁ l₂ : List α) :
|
||||
l₁.toArray ++ l₂ = (l₁ ++ l₂).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem pop_toArray (l : List α) : l.toArray.pop = l.dropLast.toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
takeWhile.go p (a :: l).toArray (i+1) r = takeWhile.go p l.toArray i r := by
|
||||
rw [takeWhile.go, takeWhile.go]
|
||||
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
|
||||
getElem_toArray, getElem_cons_succ]
|
||||
split
|
||||
rw [takeWhile_go_succ]
|
||||
rfl
|
||||
|
||||
theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
|
||||
Array.takeWhile.go p l.toArray i r = r ++ (takeWhile p (l.drop i)).toArray := by
|
||||
induction l generalizing i r with
|
||||
| nil => simp [takeWhile.go]
|
||||
| cons a l ih =>
|
||||
rw [takeWhile.go]
|
||||
cases i with
|
||||
| zero =>
|
||||
simp [takeWhile_go_succ, ih, takeWhile_cons]
|
||||
split <;> simp
|
||||
| succ i =>
|
||||
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
|
||||
getElem_toArray, getElem_cons_succ, drop_succ_cons]
|
||||
split <;> rename_i h₁
|
||||
· rw [takeWhile_go_succ, ih]
|
||||
rw [← getElem_cons_drop_succ_eq_drop h₁, takeWhile_cons]
|
||||
split <;> simp_all
|
||||
· simp_all [drop_eq_nil_of_le]
|
||||
|
||||
@[simp] theorem takeWhile_toArray (p : α → Bool) (l : List α) :
|
||||
l.toArray.takeWhile p = (l.takeWhile p).toArray := by
|
||||
simp [Array.takeWhile, takeWhile_go_toArray]
|
||||
|
||||
@[simp] theorem setIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
|
||||
l.toArray.setIfInBounds i a = (l.set i a).toArray := by
|
||||
apply ext'
|
||||
simp only [setIfInBounds]
|
||||
split
|
||||
· simp
|
||||
· simp_all [List.set_eq_of_length_le]
|
||||
|
||||
@[simp] theorem toArray_replicate (n : Nat) (v : α) : (List.replicate n v).toArray = mkArray n v := rfl
|
||||
|
||||
@[deprecated toArray_replicate (since := "2024-12-13")]
|
||||
abbrev _root_.Array.mkArray_eq_toArray_replicate := @toArray_replicate
|
||||
|
||||
end List
|
||||
|
||||
23
src/Init/Data/List/ToArrayImpl.lean
Normal file
23
src/Init/Data/List/ToArrayImpl.lean
Normal file
@@ -0,0 +1,23 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Basic
|
||||
|
||||
/--
|
||||
Auxiliary definition for `List.toArray`.
|
||||
`List.toArrayAux as r = r ++ as.toArray`
|
||||
-/
|
||||
@[inline_if_reduce]
|
||||
def List.toArrayAux : List α → Array α → Array α
|
||||
| nil, r => r
|
||||
| cons a as, r => toArrayAux as (r.push a)
|
||||
|
||||
/-- Convert a `List α` into an `Array α`. This is O(n) in the length of the list. -/
|
||||
-- This function is exported to C, where it is called by `Array.mk`
|
||||
-- (the constructor) to implement this functionality.
|
||||
@[inline, match_pattern, pp_nodot, export lean_list_to_array]
|
||||
def List.toArrayImpl (as : List α) : Array α :=
|
||||
as.toArrayAux (Array.mkEmpty as.length)
|
||||
@@ -5,7 +5,7 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.Nat.Div.Basic
|
||||
import Init.Data.Nat.Dvd
|
||||
import Init.Data.Nat.Gcd
|
||||
import Init.Data.Nat.MinMax
|
||||
|
||||
@@ -445,10 +445,10 @@ protected theorem le_antisymm_iff {a b : Nat} : a = b ↔ a ≤ b ∧ b ≤ a :=
|
||||
protected theorem eq_iff_le_and_ge : ∀{a b : Nat}, a = b ↔ a ≤ b ∧ b ≤ a := @Nat.le_antisymm_iff
|
||||
|
||||
instance : Std.Antisymm ( . ≤ . : Nat → Nat → Prop) where
|
||||
antisymm h₁ h₂ := Nat.le_antisymm h₁ h₂
|
||||
antisymm _ _ h₁ h₂ := Nat.le_antisymm h₁ h₂
|
||||
|
||||
instance : Std.Antisymm (¬ . < . : Nat → Nat → Prop) where
|
||||
antisymm h₁ h₂ := Nat.le_antisymm (Nat.ge_of_not_lt h₂) (Nat.ge_of_not_lt h₁)
|
||||
antisymm _ _ h₁ h₂ := Nat.le_antisymm (Nat.ge_of_not_lt h₂) (Nat.ge_of_not_lt h₁)
|
||||
|
||||
protected theorem add_le_add_left {n m : Nat} (h : n ≤ m) (k : Nat) : k + n ≤ k + m :=
|
||||
match le.dest h with
|
||||
|
||||
@@ -5,7 +5,7 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.Nat.Div.Basic
|
||||
import Init.Coe
|
||||
|
||||
namespace Nat
|
||||
@@ -71,6 +71,9 @@ theorem shiftRight_eq_div_pow (m : Nat) : ∀ n, m >>> n = m / 2 ^ n
|
||||
rw [shiftRight_add, shiftRight_eq_div_pow m k]
|
||||
simp [Nat.div_div_eq_div_mul, ← Nat.pow_succ, shiftRight_succ]
|
||||
|
||||
theorem shiftRight_eq_zero (m n : Nat) (hn : m < 2^n) : m >>> n = 0 := by
|
||||
simp [Nat.shiftRight_eq_div_pow, Nat.div_eq_of_lt hn]
|
||||
|
||||
/-!
|
||||
### testBit
|
||||
We define an operation for testing individual bits in the binary representation
|
||||
|
||||
@@ -106,9 +106,21 @@ theorem testBit_add_one (x i : Nat) : testBit x (i + 1) = testBit (x/2) i := by
|
||||
unfold testBit
|
||||
simp [shiftRight_succ_inside]
|
||||
|
||||
theorem testBit_add (x i n : Nat) : testBit x (i + n) = testBit (x / 2 ^ n) i := by
|
||||
revert x
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
intro x
|
||||
rw [← Nat.add_assoc, testBit_add_one, ih (x / 2),
|
||||
Nat.pow_succ, Nat.div_div_eq_div_mul, Nat.mul_comm]
|
||||
|
||||
theorem testBit_div_two (x i : Nat) : testBit (x / 2) i = testBit x (i + 1) := by
|
||||
simp
|
||||
|
||||
theorem testBit_div_two_pow (x i : Nat) : testBit (x / 2 ^ n) i = testBit x (i + n) :=
|
||||
testBit_add .. |>.symm
|
||||
|
||||
theorem testBit_to_div_mod {x : Nat} : testBit x i = decide (x / 2^i % 2 = 1) := by
|
||||
induction i generalizing x with
|
||||
| zero =>
|
||||
@@ -365,7 +377,7 @@ theorem testBit_two_pow_of_ne {n m : Nat} (hm : n ≠ m) : testBit (2 ^ n) m = f
|
||||
|
||||
/-! ### bitwise -/
|
||||
|
||||
theorem testBit_bitwise (false_false_axiom : f false false = false) (x y i : Nat) :
|
||||
theorem testBit_bitwise (of_false_false : f false false = false) (x y i : Nat) :
|
||||
(bitwise f x y).testBit i = f (x.testBit i) (y.testBit i) := by
|
||||
induction i using Nat.strongRecOn generalizing x y with
|
||||
| ind i hyp =>
|
||||
@@ -373,12 +385,12 @@ theorem testBit_bitwise (false_false_axiom : f false false = false) (x y i : Nat
|
||||
if x_zero : x = 0 then
|
||||
cases p : f false true <;>
|
||||
cases yi : testBit y i <;>
|
||||
simp [x_zero, p, yi, false_false_axiom]
|
||||
simp [x_zero, p, yi, of_false_false]
|
||||
else if y_zero : y = 0 then
|
||||
simp [x_zero, y_zero]
|
||||
cases p : f true false <;>
|
||||
cases xi : testBit x i <;>
|
||||
simp [p, xi, false_false_axiom]
|
||||
simp [p, xi, of_false_false]
|
||||
else
|
||||
simp only [x_zero, y_zero, ←Nat.two_mul]
|
||||
cases i with
|
||||
@@ -440,6 +452,11 @@ theorem bitwise_lt_two_pow (left : x < 2^n) (right : y < 2^n) : (Nat.bitwise f x
|
||||
case neg =>
|
||||
apply Nat.add_lt_add <;> exact hyp1
|
||||
|
||||
theorem bitwise_div_two_pow (of_false_false : f false false = false := by rfl) :
|
||||
(bitwise f x y) / 2 ^ n = bitwise f (x / 2 ^ n) (y / 2 ^ n) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [testBit_bitwise of_false_false, testBit_div_two_pow]
|
||||
|
||||
/-! ### and -/
|
||||
|
||||
@[simp] theorem testBit_and (x y i : Nat) : (x &&& y).testBit i = (x.testBit i && y.testBit i) := by
|
||||
@@ -495,9 +512,11 @@ theorem and_pow_two_sub_one_of_lt_two_pow {x : Nat} (lt : x < 2^n) : x &&& 2^n -
|
||||
rw [testBit_and]
|
||||
simp
|
||||
|
||||
theorem and_div_two : (a &&& b) / 2 = a / 2 &&& b / 2 := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [testBit_and, ← testBit_add_one]
|
||||
theorem and_div_two_pow : (a &&& b) / 2 ^ n = a / 2 ^ n &&& b / 2 ^ n :=
|
||||
bitwise_div_two_pow
|
||||
|
||||
theorem and_div_two : (a &&& b) / 2 = a / 2 &&& b / 2 :=
|
||||
and_div_two_pow (n := 1)
|
||||
|
||||
/-! ### lor -/
|
||||
|
||||
@@ -563,9 +582,11 @@ theorem or_lt_two_pow {x y n : Nat} (left : x < 2^n) (right : y < 2^n) : x ||| y
|
||||
rw [testBit_or]
|
||||
simp
|
||||
|
||||
theorem or_div_two : (a ||| b) / 2 = a / 2 ||| b / 2 := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [testBit_or, ← testBit_add_one]
|
||||
theorem or_div_two_pow : (a ||| b) / 2 ^ n = a / 2 ^ n ||| b / 2 ^ n :=
|
||||
bitwise_div_two_pow
|
||||
|
||||
theorem or_div_two : (a ||| b) / 2 = a / 2 ||| b / 2 :=
|
||||
or_div_two_pow (n := 1)
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
@@ -619,9 +640,11 @@ theorem and_xor_distrib_left {a b c : Nat} : a &&& (b ^^^ c) = (a &&& b) ^^^ (a
|
||||
rw [testBit_xor]
|
||||
simp
|
||||
|
||||
theorem xor_div_two : (a ^^^ b) / 2 = a / 2 ^^^ b / 2 := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [testBit_xor, ← testBit_add_one]
|
||||
theorem xor_div_two_pow : (a ^^^ b) / 2 ^ n = a / 2 ^ n ^^^ b / 2 ^ n :=
|
||||
bitwise_div_two_pow
|
||||
|
||||
theorem xor_div_two : (a ^^^ b) / 2 = a / 2 ^^^ b / 2 :=
|
||||
xor_div_two_pow (n := 1)
|
||||
|
||||
/-! ### Arithmetic -/
|
||||
|
||||
@@ -693,6 +716,19 @@ theorem mul_add_lt_is_or {b : Nat} (b_lt : b < 2^i) (a : Nat) : 2^i * a + b = 2^
|
||||
simp only [testBit, one_and_eq_mod_two, mod_two_bne_zero]
|
||||
exact (Bool.beq_eq_decide_eq _ _).symm
|
||||
|
||||
theorem shiftRight_bitwise_distrib {a b : Nat} (of_false_false : f false false = false := by rfl) :
|
||||
(bitwise f a b) >>> i = bitwise f (a >>> i) (b >>> i) := by
|
||||
simp [shiftRight_eq_div_pow, bitwise_div_two_pow of_false_false]
|
||||
|
||||
theorem shiftRight_and_distrib {a b : Nat} : (a &&& b) >>> i = a >>> i &&& b >>> i :=
|
||||
shiftRight_bitwise_distrib
|
||||
|
||||
theorem shiftRight_or_distrib {a b : Nat} : (a ||| b) >>> i = a >>> i ||| b >>> i :=
|
||||
shiftRight_bitwise_distrib
|
||||
|
||||
theorem shiftRight_xor_distrib {a b : Nat} : (a ^^^ b) >>> i = a >>> i ^^^ b >>> i :=
|
||||
shiftRight_bitwise_distrib
|
||||
|
||||
/-! ### le -/
|
||||
|
||||
theorem le_of_testBit {n m : Nat} (h : ∀ i, n.testBit i = true → m.testBit i = true) : n ≤ m := by
|
||||
|
||||
@@ -1,418 +1,8 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.WF
|
||||
import Init.WFTactics
|
||||
import Init.Data.Nat.Basic
|
||||
|
||||
namespace Nat
|
||||
|
||||
/--
|
||||
Divisibility of natural numbers. `a ∣ b` (typed as `\|`) says that
|
||||
there is some `c` such that `b = a * c`.
|
||||
-/
|
||||
instance : Dvd Nat where
|
||||
dvd a b := Exists (fun c => b = a * c)
|
||||
|
||||
theorem div_rec_lemma {x y : Nat} : 0 < y ∧ y ≤ x → x - y < x :=
|
||||
fun ⟨ypos, ylex⟩ => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
|
||||
|
||||
@[extern "lean_nat_div"]
|
||||
protected def div (x y : @& Nat) : Nat :=
|
||||
if 0 < y ∧ y ≤ x then
|
||||
Nat.div (x - y) y + 1
|
||||
else
|
||||
0
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
instance instDiv : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
theorem div_eq (x y : Nat) : x / y = if 0 < y ∧ y ≤ x then (x - y) / y + 1 else 0 := by
|
||||
show Nat.div x y = _
|
||||
rw [Nat.div]
|
||||
rfl
|
||||
|
||||
def div.inductionOn.{u}
|
||||
{motive : Nat → Nat → Sort u}
|
||||
(x y : Nat)
|
||||
(ind : ∀ x y, 0 < y ∧ y ≤ x → motive (x - y) y → motive x y)
|
||||
(base : ∀ x y, ¬(0 < y ∧ y ≤ x) → motive x y)
|
||||
: motive x y :=
|
||||
if h : 0 < y ∧ y ≤ x then
|
||||
ind x y h (inductionOn (x - y) y ind base)
|
||||
else
|
||||
base x y h
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
theorem div_le_self (n k : Nat) : n / k ≤ n := by
|
||||
induction n using Nat.strongRecOn with
|
||||
| ind n ih =>
|
||||
rw [div_eq]
|
||||
-- Note: manual split to avoid Classical.em which is not yet defined
|
||||
cases (inferInstance : Decidable (0 < k ∧ k ≤ n)) with
|
||||
| isFalse h => simp [h]
|
||||
| isTrue h =>
|
||||
suffices (n - k) / k + 1 ≤ n by simp [h, this]
|
||||
have ⟨hK, hKN⟩ := h
|
||||
have hSub : n - k < n := sub_lt (Nat.lt_of_lt_of_le hK hKN) hK
|
||||
have : (n - k) / k ≤ n - k := ih (n - k) hSub
|
||||
exact succ_le_of_lt (Nat.lt_of_le_of_lt this hSub)
|
||||
|
||||
theorem div_lt_self {n k : Nat} (hLtN : 0 < n) (hLtK : 1 < k) : n / k < n := by
|
||||
rw [div_eq]
|
||||
cases (inferInstance : Decidable (0 < k ∧ k ≤ n)) with
|
||||
| isFalse h => simp [hLtN, h]
|
||||
| isTrue h =>
|
||||
suffices (n - k) / k + 1 < n by simp [h, this]
|
||||
have ⟨_, hKN⟩ := h
|
||||
have : (n - k) / k ≤ n - k := div_le_self (n - k) k
|
||||
have := Nat.add_le_of_le_sub hKN this
|
||||
exact Nat.lt_of_lt_of_le (Nat.add_lt_add_left hLtK _) this
|
||||
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def modCore (x y : @& Nat) : Nat :=
|
||||
if 0 < y ∧ y ≤ x then
|
||||
Nat.modCore (x - y) y
|
||||
else
|
||||
x
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def mod : @& Nat → @& Nat → Nat
|
||||
/-
|
||||
Nat.modCore is defined by well-founded recursion and thus irreducible. Nevertheless it is
|
||||
desirable if trivial `Nat.mod` calculations, namely
|
||||
* `Nat.mod 0 m` for all `m`
|
||||
* `Nat.mod n (m+n)` for concrete literals `n`
|
||||
reduce definitionally.
|
||||
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
|
||||
definition.
|
||||
-/
|
||||
| 0, _ => 0
|
||||
| n@(_ + 1), m =>
|
||||
if m ≤ n -- NB: if n < m does not reduce as well as `m ≤ n`!
|
||||
then Nat.modCore n m
|
||||
else n
|
||||
|
||||
instance instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
|
||||
show Nat.modCore n m = Nat.mod n m
|
||||
match n, m with
|
||||
| 0, _ =>
|
||||
rw [Nat.modCore]
|
||||
exact if_neg fun ⟨hlt, hle⟩ => Nat.lt_irrefl _ (Nat.lt_of_lt_of_le hlt hle)
|
||||
| (_ + 1), _ =>
|
||||
rw [Nat.mod]; dsimp
|
||||
refine iteInduction (fun _ => rfl) (fun h => ?false) -- cannot use `split` this early yet
|
||||
rw [Nat.modCore]
|
||||
exact if_neg fun ⟨_hlt, hle⟩ => h hle
|
||||
|
||||
theorem mod_eq (x y : Nat) : x % y = if 0 < y ∧ y ≤ x then (x - y) % y else x := by
|
||||
rw [←Nat.modCore_eq_mod, ←Nat.modCore_eq_mod, Nat.modCore]
|
||||
|
||||
def mod.inductionOn.{u}
|
||||
{motive : Nat → Nat → Sort u}
|
||||
(x y : Nat)
|
||||
(ind : ∀ x y, 0 < y ∧ y ≤ x → motive (x - y) y → motive x y)
|
||||
(base : ∀ x y, ¬(0 < y ∧ y ≤ x) → motive x y)
|
||||
: motive x y :=
|
||||
div.inductionOn x y ind base
|
||||
|
||||
@[simp] theorem mod_zero (a : Nat) : a % 0 = a :=
|
||||
have : (if 0 < 0 ∧ 0 ≤ a then (a - 0) % 0 else a) = a :=
|
||||
have h : ¬ (0 < 0 ∧ 0 ≤ a) := fun ⟨h₁, _⟩ => absurd h₁ (Nat.lt_irrefl _)
|
||||
if_neg h
|
||||
(mod_eq a 0).symm ▸ this
|
||||
|
||||
theorem mod_eq_of_lt {a b : Nat} (h : a < b) : a % b = a :=
|
||||
have : (if 0 < b ∧ b ≤ a then (a - b) % b else a) = a :=
|
||||
have h' : ¬(0 < b ∧ b ≤ a) := fun ⟨_, h₁⟩ => absurd h₁ (Nat.not_le_of_gt h)
|
||||
if_neg h'
|
||||
(mod_eq a b).symm ▸ this
|
||||
|
||||
@[simp] theorem one_mod_eq_zero_iff {n : Nat} : 1 % n = 0 ↔ n = 1 := by
|
||||
match n with
|
||||
| 0 => simp
|
||||
| 1 => simp
|
||||
| n + 2 =>
|
||||
rw [mod_eq_of_lt (by exact Nat.lt_of_sub_eq_succ rfl)]
|
||||
simp only [add_one_ne_zero, false_iff, ne_eq]
|
||||
exact ne_of_beq_eq_false rfl
|
||||
|
||||
@[simp] theorem Nat.zero_eq_one_mod_iff {n : Nat} : 0 = 1 % n ↔ n = 1 := by
|
||||
rw [eq_comm]
|
||||
simp
|
||||
|
||||
theorem mod_eq_sub_mod {a b : Nat} (h : a ≥ b) : a % b = (a - b) % b :=
|
||||
match eq_zero_or_pos b with
|
||||
| Or.inl h₁ => h₁.symm ▸ (Nat.sub_zero a).symm ▸ rfl
|
||||
| Or.inr h₁ => (mod_eq a b).symm ▸ if_pos ⟨h₁, h⟩
|
||||
|
||||
theorem mod_lt (x : Nat) {y : Nat} : y > 0 → x % y < y := by
|
||||
induction x, y using mod.inductionOn with
|
||||
| base x y h₁ =>
|
||||
intro h₂
|
||||
have h₁ : ¬ 0 < y ∨ ¬ y ≤ x := Decidable.not_and_iff_or_not.mp h₁
|
||||
match h₁ with
|
||||
| Or.inl h₁ => exact absurd h₂ h₁
|
||||
| Or.inr h₁ =>
|
||||
have hgt : y > x := gt_of_not_le h₁
|
||||
have heq : x % y = x := mod_eq_of_lt hgt
|
||||
rw [← heq] at hgt
|
||||
exact hgt
|
||||
| ind x y h h₂ =>
|
||||
intro h₃
|
||||
have ⟨_, h₁⟩ := h
|
||||
rw [mod_eq_sub_mod h₁]
|
||||
exact h₂ h₃
|
||||
|
||||
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
|
||||
rw [Nat.sub_add_cancel]
|
||||
cases a with
|
||||
| zero => simp_all
|
||||
| succ a =>
|
||||
exact Nat.le_of_lt (mod_lt b (zero_lt_succ a))
|
||||
|
||||
theorem mod_le (x y : Nat) : x % y ≤ x := by
|
||||
match Nat.lt_or_ge x y with
|
||||
| Or.inl h₁ => rw [mod_eq_of_lt h₁]; apply Nat.le_refl
|
||||
| Or.inr h₁ => match eq_zero_or_pos y with
|
||||
| Or.inl h₂ => rw [h₂, Nat.mod_zero x]; apply Nat.le_refl
|
||||
| Or.inr h₂ => exact Nat.le_trans (Nat.le_of_lt (mod_lt _ h₂)) h₁
|
||||
|
||||
@[simp] theorem zero_mod (b : Nat) : 0 % b = 0 := by
|
||||
rw [mod_eq]
|
||||
have : ¬ (0 < b ∧ b = 0) := by
|
||||
intro ⟨h₁, h₂⟩
|
||||
simp_all
|
||||
simp [this]
|
||||
|
||||
@[simp] theorem mod_self (n : Nat) : n % n = 0 := by
|
||||
rw [mod_eq_sub_mod (Nat.le_refl _), Nat.sub_self, zero_mod]
|
||||
|
||||
theorem mod_one (x : Nat) : x % 1 = 0 := by
|
||||
have h : x % 1 < 1 := mod_lt x (by decide)
|
||||
have : (y : Nat) → y < 1 → y = 0 := by
|
||||
intro y
|
||||
cases y with
|
||||
| zero => intro _; rfl
|
||||
| succ y => intro h; apply absurd (Nat.lt_of_succ_lt_succ h) (Nat.not_lt_zero y)
|
||||
exact this _ h
|
||||
|
||||
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
|
||||
|
||||
theorem div_eq_sub_div (h₁ : 0 < b) (h₂ : b ≤ a) : a / b = (a - b) / b + 1 := by
|
||||
rw [div_eq a, if_pos]; constructor <;> assumption
|
||||
|
||||
theorem mod_add_div (m k : Nat) : m % k + k * (m / k) = m := by
|
||||
induction m, k using mod.inductionOn with rw [div_eq, mod_eq]
|
||||
| base x y h => simp [h]
|
||||
| ind x y h IH => simp [h]; rw [Nat.mul_succ, ← Nat.add_assoc, IH, Nat.sub_add_cancel h.2]
|
||||
|
||||
theorem mod_def (m k : Nat) : m % k = m - k * (m / k) := by
|
||||
rw [Nat.sub_eq_of_eq_add]
|
||||
apply (Nat.mod_add_div _ _).symm
|
||||
|
||||
@[simp] protected theorem div_one (n : Nat) : n / 1 = n := by
|
||||
have := mod_add_div n 1
|
||||
rwa [mod_one, Nat.zero_add, Nat.one_mul] at this
|
||||
|
||||
@[simp] protected theorem div_zero (n : Nat) : n / 0 = 0 := by
|
||||
rw [div_eq]; simp [Nat.lt_irrefl]
|
||||
|
||||
@[simp] protected theorem zero_div (b : Nat) : 0 / b = 0 :=
|
||||
(div_eq 0 b).trans <| if_neg <| And.rec Nat.not_le_of_gt
|
||||
|
||||
theorem le_div_iff_mul_le (k0 : 0 < k) : x ≤ y / k ↔ x * k ≤ y := by
|
||||
induction y, k using mod.inductionOn generalizing x with
|
||||
(rw [div_eq]; simp [h]; cases x with | zero => simp [zero_le] | succ x => ?_)
|
||||
| base y k h =>
|
||||
simp only [add_one, succ_mul, false_iff, Nat.not_le, Nat.succ_ne_zero]
|
||||
refine Nat.lt_of_lt_of_le ?_ (Nat.le_add_left ..)
|
||||
exact Nat.not_le.1 fun h' => h ⟨k0, h'⟩
|
||||
| ind y k h IH =>
|
||||
rw [Nat.add_le_add_iff_right, IH k0, succ_mul,
|
||||
← Nat.add_sub_cancel (x*k) k, Nat.sub_le_sub_iff_right h.2, Nat.add_sub_cancel]
|
||||
|
||||
protected theorem div_div_eq_div_mul (m n k : Nat) : m / n / k = m / (n * k) := by
|
||||
cases eq_zero_or_pos k with
|
||||
| inl k0 => rw [k0, Nat.mul_zero, Nat.div_zero, Nat.div_zero] | inr kpos => ?_
|
||||
cases eq_zero_or_pos n with
|
||||
| inl n0 => rw [n0, Nat.zero_mul, Nat.div_zero, Nat.zero_div] | inr npos => ?_
|
||||
|
||||
apply Nat.le_antisymm
|
||||
|
||||
apply (le_div_iff_mul_le (Nat.mul_pos npos kpos)).2
|
||||
rw [Nat.mul_comm n k, ← Nat.mul_assoc]
|
||||
apply (le_div_iff_mul_le npos).1
|
||||
apply (le_div_iff_mul_le kpos).1
|
||||
(apply Nat.le_refl)
|
||||
|
||||
apply (le_div_iff_mul_le kpos).2
|
||||
apply (le_div_iff_mul_le npos).2
|
||||
rw [Nat.mul_assoc, Nat.mul_comm n k]
|
||||
apply (le_div_iff_mul_le (Nat.mul_pos kpos npos)).1
|
||||
apply Nat.le_refl
|
||||
|
||||
theorem div_mul_le_self : ∀ (m n : Nat), m / n * n ≤ m
|
||||
| m, 0 => by simp
|
||||
| _, _+1 => (le_div_iff_mul_le (Nat.succ_pos _)).1 (Nat.le_refl _)
|
||||
|
||||
theorem div_lt_iff_lt_mul (Hk : 0 < k) : x / k < y ↔ x < y * k := by
|
||||
rw [← Nat.not_le, ← Nat.not_le]; exact not_congr (le_div_iff_mul_le Hk)
|
||||
|
||||
@[simp] theorem add_div_right (x : Nat) {z : Nat} (H : 0 < z) : (x + z) / z = (x / z) + 1 := by
|
||||
rw [div_eq_sub_div H (Nat.le_add_left _ _), Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem add_div_left (x : Nat) {z : Nat} (H : 0 < z) : (z + x) / z = (x / z) + 1 := by
|
||||
rw [Nat.add_comm, add_div_right x H]
|
||||
|
||||
theorem add_mul_div_left (x z : Nat) {y : Nat} (H : 0 < y) : (x + y * z) / y = x / y + z := by
|
||||
induction z with
|
||||
| zero => rw [Nat.mul_zero, Nat.add_zero, Nat.add_zero]
|
||||
| succ z ih => rw [mul_succ, ← Nat.add_assoc, add_div_right _ H, ih]; rfl
|
||||
|
||||
theorem add_mul_div_right (x y : Nat) {z : Nat} (H : 0 < z) : (x + y * z) / z = x / z + y := by
|
||||
rw [Nat.mul_comm, add_mul_div_left _ _ H]
|
||||
|
||||
@[simp] theorem add_mod_right (x z : Nat) : (x + z) % z = x % z := by
|
||||
rw [mod_eq_sub_mod (Nat.le_add_left ..), Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem add_mod_left (x z : Nat) : (x + z) % x = z % x := by
|
||||
rw [Nat.add_comm, add_mod_right]
|
||||
|
||||
@[simp] theorem add_mul_mod_self_left (x y z : Nat) : (x + y * z) % y = x % y := by
|
||||
match z with
|
||||
| 0 => rw [Nat.mul_zero, Nat.add_zero]
|
||||
| succ z => rw [mul_succ, ← Nat.add_assoc, add_mod_right, add_mul_mod_self_left (z := z)]
|
||||
|
||||
@[simp] theorem add_mul_mod_self_right (x y z : Nat) : (x + y * z) % z = x % z := by
|
||||
rw [Nat.mul_comm, add_mul_mod_self_left]
|
||||
|
||||
@[simp] theorem mul_mod_right (m n : Nat) : (m * n) % m = 0 := by
|
||||
rw [← Nat.zero_add (m * n), add_mul_mod_self_left, zero_mod]
|
||||
|
||||
@[simp] theorem mul_mod_left (m n : Nat) : (m * n) % n = 0 := by
|
||||
rw [Nat.mul_comm, mul_mod_right]
|
||||
|
||||
protected theorem div_eq_of_lt_le (lo : k * n ≤ m) (hi : m < (k + 1) * n) : m / n = k :=
|
||||
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun hn => by
|
||||
rw [hn, Nat.mul_zero] at hi lo; exact absurd lo (Nat.not_le_of_gt hi)
|
||||
Nat.le_antisymm
|
||||
(le_of_lt_succ ((Nat.div_lt_iff_lt_mul npos).2 hi))
|
||||
((Nat.le_div_iff_mul_le npos).2 lo)
|
||||
|
||||
theorem sub_mul_div (x n p : Nat) (h₁ : n*p ≤ x) : (x - n*p) / n = x / n - p := by
|
||||
match eq_zero_or_pos n with
|
||||
| .inl h₀ => rw [h₀, Nat.div_zero, Nat.div_zero, Nat.zero_sub]
|
||||
| .inr h₀ => induction p with
|
||||
| zero => rw [Nat.mul_zero, Nat.sub_zero, Nat.sub_zero]
|
||||
| succ p IH =>
|
||||
have h₂ : n * p ≤ x := Nat.le_trans (Nat.mul_le_mul_left _ (le_succ _)) h₁
|
||||
have h₃ : x - n * p ≥ n := by
|
||||
apply Nat.le_of_add_le_add_right
|
||||
rw [Nat.sub_add_cancel h₂, Nat.add_comm]
|
||||
rw [mul_succ] at h₁
|
||||
exact h₁
|
||||
rw [sub_succ, ← IH h₂, div_eq_sub_div h₀ h₃]
|
||||
simp [Nat.pred_succ, mul_succ, Nat.sub_sub]
|
||||
|
||||
theorem mul_sub_div (x n p : Nat) (h₁ : x < n*p) : (n * p - (x + 1)) / n = p - ((x / n) + 1) := by
|
||||
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun n0 => by
|
||||
rw [n0, Nat.zero_mul] at h₁; exact not_lt_zero _ h₁
|
||||
apply Nat.div_eq_of_lt_le
|
||||
focus
|
||||
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
|
||||
exact Nat.sub_le_sub_left ((div_lt_iff_lt_mul npos).1 (lt_succ_self _)) _
|
||||
focus
|
||||
show succ (pred (n * p - x)) ≤ (succ (pred (p - x / n))) * n
|
||||
rw [succ_pred_eq_of_pos (Nat.sub_pos_of_lt h₁),
|
||||
fun h => succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)] -- TODO: why is the function needed?
|
||||
focus
|
||||
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
|
||||
exact Nat.sub_le_sub_left (div_mul_le_self ..) _
|
||||
focus
|
||||
rwa [div_lt_iff_lt_mul npos, Nat.mul_comm]
|
||||
|
||||
theorem mul_mod_mul_left (z x y : Nat) : (z * x) % (z * y) = z * (x % y) :=
|
||||
if y0 : y = 0 then by
|
||||
rw [y0, Nat.mul_zero, mod_zero, mod_zero]
|
||||
else if z0 : z = 0 then by
|
||||
rw [z0, Nat.zero_mul, Nat.zero_mul, Nat.zero_mul, mod_zero]
|
||||
else by
|
||||
induction x using Nat.strongRecOn with
|
||||
| _ n IH =>
|
||||
have y0 : y > 0 := Nat.pos_of_ne_zero y0
|
||||
have z0 : z > 0 := Nat.pos_of_ne_zero z0
|
||||
cases Nat.lt_or_ge n y with
|
||||
| inl yn => rw [mod_eq_of_lt yn, mod_eq_of_lt (Nat.mul_lt_mul_of_pos_left yn z0)]
|
||||
| inr yn =>
|
||||
rw [mod_eq_sub_mod yn, mod_eq_sub_mod (Nat.mul_le_mul_left z yn),
|
||||
← Nat.mul_sub_left_distrib]
|
||||
exact IH _ (sub_lt (Nat.lt_of_lt_of_le y0 yn) y0)
|
||||
|
||||
theorem div_eq_of_lt (h₀ : a < b) : a / b = 0 := by
|
||||
rw [div_eq a, if_neg]
|
||||
intro h₁
|
||||
apply Nat.not_le_of_gt h₀ h₁.right
|
||||
|
||||
protected theorem mul_div_cancel (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
|
||||
let t := add_mul_div_right 0 m H
|
||||
rwa [Nat.zero_add, Nat.zero_div, Nat.zero_add] at t
|
||||
|
||||
protected theorem mul_div_cancel_left (m : Nat) {n : Nat} (H : 0 < n) : n * m / n = m := by
|
||||
rw [Nat.mul_comm, Nat.mul_div_cancel _ H]
|
||||
|
||||
protected theorem div_le_of_le_mul {m n : Nat} : ∀ {k}, m ≤ k * n → m / k ≤ n
|
||||
| 0, _ => by simp [Nat.div_zero, n.zero_le]
|
||||
| succ k, h => by
|
||||
suffices succ k * (m / succ k) ≤ succ k * n from
|
||||
Nat.le_of_mul_le_mul_left this (zero_lt_succ _)
|
||||
have h1 : succ k * (m / succ k) ≤ m % succ k + succ k * (m / succ k) := Nat.le_add_left _ _
|
||||
have h2 : m % succ k + succ k * (m / succ k) = m := by rw [mod_add_div]
|
||||
have h3 : m ≤ succ k * n := h
|
||||
rw [← h2] at h3
|
||||
exact Nat.le_trans h1 h3
|
||||
|
||||
@[simp] theorem mul_div_right (n : Nat) {m : Nat} (H : 0 < m) : m * n / m = n := by
|
||||
induction n <;> simp_all [mul_succ]
|
||||
|
||||
@[simp] theorem mul_div_left (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
|
||||
rw [Nat.mul_comm, mul_div_right _ H]
|
||||
|
||||
protected theorem div_self (H : 0 < n) : n / n = 1 := by
|
||||
let t := add_div_right 0 H
|
||||
rwa [Nat.zero_add, Nat.zero_div] at t
|
||||
|
||||
protected theorem div_eq_of_eq_mul_left (H1 : 0 < n) (H2 : m = k * n) : m / n = k :=
|
||||
by rw [H2, Nat.mul_div_cancel _ H1]
|
||||
|
||||
protected theorem div_eq_of_eq_mul_right (H1 : 0 < n) (H2 : m = n * k) : m / n = k :=
|
||||
by rw [H2, Nat.mul_div_cancel_left _ H1]
|
||||
|
||||
protected theorem mul_div_mul_left {m : Nat} (n k : Nat) (H : 0 < m) :
|
||||
m * n / (m * k) = n / k := by rw [← Nat.div_div_eq_div_mul, Nat.mul_div_cancel_left _ H]
|
||||
|
||||
protected theorem mul_div_mul_right {m : Nat} (n k : Nat) (H : 0 < m) :
|
||||
n * m / (k * m) = n / k := by rw [Nat.mul_comm, Nat.mul_comm k, Nat.mul_div_mul_left _ _ H]
|
||||
|
||||
theorem mul_div_le (m n : Nat) : n * (m / n) ≤ m := by
|
||||
match n, Nat.eq_zero_or_pos n with
|
||||
| _, Or.inl rfl => rw [Nat.zero_mul]; exact m.zero_le
|
||||
| n, Or.inr h => rw [Nat.mul_comm, ← Nat.le_div_iff_mul_le h]; exact Nat.le_refl _
|
||||
|
||||
|
||||
end Nat
|
||||
import Init.Data.Nat.Div.Basic
|
||||
import Init.Data.Nat.Div.Lemmas
|
||||
|
||||
437
src/Init/Data/Nat/Div/Basic.lean
Normal file
437
src/Init/Data/Nat/Div/Basic.lean
Normal file
@@ -0,0 +1,437 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.WF
|
||||
import Init.WFTactics
|
||||
import Init.Data.Nat.Basic
|
||||
|
||||
namespace Nat
|
||||
|
||||
/--
|
||||
Divisibility of natural numbers. `a ∣ b` (typed as `\|`) says that
|
||||
there is some `c` such that `b = a * c`.
|
||||
-/
|
||||
instance : Dvd Nat where
|
||||
dvd a b := Exists (fun c => b = a * c)
|
||||
|
||||
theorem div_rec_lemma {x y : Nat} : 0 < y ∧ y ≤ x → x - y < x :=
|
||||
fun ⟨ypos, ylex⟩ => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
|
||||
|
||||
@[extern "lean_nat_div"]
|
||||
protected def div (x y : @& Nat) : Nat :=
|
||||
if 0 < y ∧ y ≤ x then
|
||||
Nat.div (x - y) y + 1
|
||||
else
|
||||
0
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
instance instDiv : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
theorem div_eq (x y : Nat) : x / y = if 0 < y ∧ y ≤ x then (x - y) / y + 1 else 0 := by
|
||||
show Nat.div x y = _
|
||||
rw [Nat.div]
|
||||
rfl
|
||||
|
||||
def div.inductionOn.{u}
|
||||
{motive : Nat → Nat → Sort u}
|
||||
(x y : Nat)
|
||||
(ind : ∀ x y, 0 < y ∧ y ≤ x → motive (x - y) y → motive x y)
|
||||
(base : ∀ x y, ¬(0 < y ∧ y ≤ x) → motive x y)
|
||||
: motive x y :=
|
||||
if h : 0 < y ∧ y ≤ x then
|
||||
ind x y h (inductionOn (x - y) y ind base)
|
||||
else
|
||||
base x y h
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
theorem div_le_self (n k : Nat) : n / k ≤ n := by
|
||||
induction n using Nat.strongRecOn with
|
||||
| ind n ih =>
|
||||
rw [div_eq]
|
||||
-- Note: manual split to avoid Classical.em which is not yet defined
|
||||
cases (inferInstance : Decidable (0 < k ∧ k ≤ n)) with
|
||||
| isFalse h => simp [h]
|
||||
| isTrue h =>
|
||||
suffices (n - k) / k + 1 ≤ n by simp [h, this]
|
||||
have ⟨hK, hKN⟩ := h
|
||||
have hSub : n - k < n := sub_lt (Nat.lt_of_lt_of_le hK hKN) hK
|
||||
have : (n - k) / k ≤ n - k := ih (n - k) hSub
|
||||
exact succ_le_of_lt (Nat.lt_of_le_of_lt this hSub)
|
||||
|
||||
theorem div_lt_self {n k : Nat} (hLtN : 0 < n) (hLtK : 1 < k) : n / k < n := by
|
||||
rw [div_eq]
|
||||
cases (inferInstance : Decidable (0 < k ∧ k ≤ n)) with
|
||||
| isFalse h => simp [hLtN, h]
|
||||
| isTrue h =>
|
||||
suffices (n - k) / k + 1 < n by simp [h, this]
|
||||
have ⟨_, hKN⟩ := h
|
||||
have : (n - k) / k ≤ n - k := div_le_self (n - k) k
|
||||
have := Nat.add_le_of_le_sub hKN this
|
||||
exact Nat.lt_of_lt_of_le (Nat.add_lt_add_left hLtK _) this
|
||||
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def modCore (x y : @& Nat) : Nat :=
|
||||
if 0 < y ∧ y ≤ x then
|
||||
Nat.modCore (x - y) y
|
||||
else
|
||||
x
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def mod : @& Nat → @& Nat → Nat
|
||||
/-
|
||||
Nat.modCore is defined by well-founded recursion and thus irreducible. Nevertheless it is
|
||||
desirable if trivial `Nat.mod` calculations, namely
|
||||
* `Nat.mod 0 m` for all `m`
|
||||
* `Nat.mod n (m+n)` for concrete literals `n`
|
||||
reduce definitionally.
|
||||
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
|
||||
definition.
|
||||
-/
|
||||
| 0, _ => 0
|
||||
| n@(_ + 1), m =>
|
||||
if m ≤ n -- NB: if n < m does not reduce as well as `m ≤ n`!
|
||||
then Nat.modCore n m
|
||||
else n
|
||||
|
||||
instance instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
|
||||
show Nat.modCore n m = Nat.mod n m
|
||||
match n, m with
|
||||
| 0, _ =>
|
||||
rw [Nat.modCore]
|
||||
exact if_neg fun ⟨hlt, hle⟩ => Nat.lt_irrefl _ (Nat.lt_of_lt_of_le hlt hle)
|
||||
| (_ + 1), _ =>
|
||||
rw [Nat.mod]; dsimp
|
||||
refine iteInduction (fun _ => rfl) (fun h => ?false) -- cannot use `split` this early yet
|
||||
rw [Nat.modCore]
|
||||
exact if_neg fun ⟨_hlt, hle⟩ => h hle
|
||||
|
||||
theorem mod_eq (x y : Nat) : x % y = if 0 < y ∧ y ≤ x then (x - y) % y else x := by
|
||||
rw [←Nat.modCore_eq_mod, ←Nat.modCore_eq_mod, Nat.modCore]
|
||||
|
||||
def mod.inductionOn.{u}
|
||||
{motive : Nat → Nat → Sort u}
|
||||
(x y : Nat)
|
||||
(ind : ∀ x y, 0 < y ∧ y ≤ x → motive (x - y) y → motive x y)
|
||||
(base : ∀ x y, ¬(0 < y ∧ y ≤ x) → motive x y)
|
||||
: motive x y :=
|
||||
div.inductionOn x y ind base
|
||||
|
||||
@[simp] theorem mod_zero (a : Nat) : a % 0 = a :=
|
||||
have : (if 0 < 0 ∧ 0 ≤ a then (a - 0) % 0 else a) = a :=
|
||||
have h : ¬ (0 < 0 ∧ 0 ≤ a) := fun ⟨h₁, _⟩ => absurd h₁ (Nat.lt_irrefl _)
|
||||
if_neg h
|
||||
(mod_eq a 0).symm ▸ this
|
||||
|
||||
theorem mod_eq_of_lt {a b : Nat} (h : a < b) : a % b = a :=
|
||||
have : (if 0 < b ∧ b ≤ a then (a - b) % b else a) = a :=
|
||||
have h' : ¬(0 < b ∧ b ≤ a) := fun ⟨_, h₁⟩ => absurd h₁ (Nat.not_le_of_gt h)
|
||||
if_neg h'
|
||||
(mod_eq a b).symm ▸ this
|
||||
|
||||
@[simp] theorem one_mod_eq_zero_iff {n : Nat} : 1 % n = 0 ↔ n = 1 := by
|
||||
match n with
|
||||
| 0 => simp
|
||||
| 1 => simp
|
||||
| n + 2 =>
|
||||
rw [mod_eq_of_lt (by exact Nat.lt_of_sub_eq_succ rfl)]
|
||||
simp only [add_one_ne_zero, false_iff, ne_eq]
|
||||
exact ne_of_beq_eq_false rfl
|
||||
|
||||
@[simp] theorem Nat.zero_eq_one_mod_iff {n : Nat} : 0 = 1 % n ↔ n = 1 := by
|
||||
rw [eq_comm]
|
||||
simp
|
||||
|
||||
theorem mod_eq_sub_mod {a b : Nat} (h : a ≥ b) : a % b = (a - b) % b :=
|
||||
match eq_zero_or_pos b with
|
||||
| Or.inl h₁ => h₁.symm ▸ (Nat.sub_zero a).symm ▸ rfl
|
||||
| Or.inr h₁ => (mod_eq a b).symm ▸ if_pos ⟨h₁, h⟩
|
||||
|
||||
theorem mod_lt (x : Nat) {y : Nat} : y > 0 → x % y < y := by
|
||||
induction x, y using mod.inductionOn with
|
||||
| base x y h₁ =>
|
||||
intro h₂
|
||||
have h₁ : ¬ 0 < y ∨ ¬ y ≤ x := Decidable.not_and_iff_or_not.mp h₁
|
||||
match h₁ with
|
||||
| Or.inl h₁ => exact absurd h₂ h₁
|
||||
| Or.inr h₁ =>
|
||||
have hgt : y > x := gt_of_not_le h₁
|
||||
have heq : x % y = x := mod_eq_of_lt hgt
|
||||
rw [← heq] at hgt
|
||||
exact hgt
|
||||
| ind x y h h₂ =>
|
||||
intro h₃
|
||||
have ⟨_, h₁⟩ := h
|
||||
rw [mod_eq_sub_mod h₁]
|
||||
exact h₂ h₃
|
||||
|
||||
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
|
||||
rw [Nat.sub_add_cancel]
|
||||
cases a with
|
||||
| zero => simp_all
|
||||
| succ a =>
|
||||
exact Nat.le_of_lt (mod_lt b (zero_lt_succ a))
|
||||
|
||||
theorem mod_le (x y : Nat) : x % y ≤ x := by
|
||||
match Nat.lt_or_ge x y with
|
||||
| Or.inl h₁ => rw [mod_eq_of_lt h₁]; apply Nat.le_refl
|
||||
| Or.inr h₁ => match eq_zero_or_pos y with
|
||||
| Or.inl h₂ => rw [h₂, Nat.mod_zero x]; apply Nat.le_refl
|
||||
| Or.inr h₂ => exact Nat.le_trans (Nat.le_of_lt (mod_lt _ h₂)) h₁
|
||||
|
||||
@[simp] theorem zero_mod (b : Nat) : 0 % b = 0 := by
|
||||
rw [mod_eq]
|
||||
have : ¬ (0 < b ∧ b = 0) := by
|
||||
intro ⟨h₁, h₂⟩
|
||||
simp_all
|
||||
simp [this]
|
||||
|
||||
@[simp] theorem mod_self (n : Nat) : n % n = 0 := by
|
||||
rw [mod_eq_sub_mod (Nat.le_refl _), Nat.sub_self, zero_mod]
|
||||
|
||||
theorem mod_one (x : Nat) : x % 1 = 0 := by
|
||||
have h : x % 1 < 1 := mod_lt x (by decide)
|
||||
have : (y : Nat) → y < 1 → y = 0 := by
|
||||
intro y
|
||||
cases y with
|
||||
| zero => intro _; rfl
|
||||
| succ y => intro h; apply absurd (Nat.lt_of_succ_lt_succ h) (Nat.not_lt_zero y)
|
||||
exact this _ h
|
||||
|
||||
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
|
||||
|
||||
theorem div_eq_sub_div (h₁ : 0 < b) (h₂ : b ≤ a) : a / b = (a - b) / b + 1 := by
|
||||
rw [div_eq a, if_pos]; constructor <;> assumption
|
||||
|
||||
theorem mod_add_div (m k : Nat) : m % k + k * (m / k) = m := by
|
||||
induction m, k using mod.inductionOn with rw [div_eq, mod_eq]
|
||||
| base x y h => simp [h]
|
||||
| ind x y h IH => simp [h]; rw [Nat.mul_succ, ← Nat.add_assoc, IH, Nat.sub_add_cancel h.2]
|
||||
|
||||
theorem mod_def (m k : Nat) : m % k = m - k * (m / k) := by
|
||||
rw [Nat.sub_eq_of_eq_add]
|
||||
apply (Nat.mod_add_div _ _).symm
|
||||
|
||||
theorem mod_eq_sub_mul_div {x k : Nat} : x % k = x - k * (x / k) := mod_def _ _
|
||||
|
||||
theorem mod_eq_sub_div_mul {x k : Nat} : x % k = x - (x / k) * k := by
|
||||
rw [mod_eq_sub_mul_div, Nat.mul_comm]
|
||||
|
||||
@[simp] protected theorem div_one (n : Nat) : n / 1 = n := by
|
||||
have := mod_add_div n 1
|
||||
rwa [mod_one, Nat.zero_add, Nat.one_mul] at this
|
||||
|
||||
@[simp] protected theorem div_zero (n : Nat) : n / 0 = 0 := by
|
||||
rw [div_eq]; simp [Nat.lt_irrefl]
|
||||
|
||||
@[simp] protected theorem zero_div (b : Nat) : 0 / b = 0 :=
|
||||
(div_eq 0 b).trans <| if_neg <| And.rec Nat.not_le_of_gt
|
||||
|
||||
theorem le_div_iff_mul_le (k0 : 0 < k) : x ≤ y / k ↔ x * k ≤ y := by
|
||||
induction y, k using mod.inductionOn generalizing x with
|
||||
(rw [div_eq]; simp [h]; cases x with | zero => simp [zero_le] | succ x => ?_)
|
||||
| base y k h =>
|
||||
simp only [add_one, succ_mul, false_iff, Nat.not_le, Nat.succ_ne_zero]
|
||||
refine Nat.lt_of_lt_of_le ?_ (Nat.le_add_left ..)
|
||||
exact Nat.not_le.1 fun h' => h ⟨k0, h'⟩
|
||||
| ind y k h IH =>
|
||||
rw [Nat.add_le_add_iff_right, IH k0, succ_mul,
|
||||
← Nat.add_sub_cancel (x*k) k, Nat.sub_le_sub_iff_right h.2, Nat.add_sub_cancel]
|
||||
|
||||
protected theorem div_div_eq_div_mul (m n k : Nat) : m / n / k = m / (n * k) := by
|
||||
cases eq_zero_or_pos k with
|
||||
| inl k0 => rw [k0, Nat.mul_zero, Nat.div_zero, Nat.div_zero] | inr kpos => ?_
|
||||
cases eq_zero_or_pos n with
|
||||
| inl n0 => rw [n0, Nat.zero_mul, Nat.div_zero, Nat.zero_div] | inr npos => ?_
|
||||
|
||||
apply Nat.le_antisymm
|
||||
|
||||
apply (le_div_iff_mul_le (Nat.mul_pos npos kpos)).2
|
||||
rw [Nat.mul_comm n k, ← Nat.mul_assoc]
|
||||
apply (le_div_iff_mul_le npos).1
|
||||
apply (le_div_iff_mul_le kpos).1
|
||||
(apply Nat.le_refl)
|
||||
|
||||
apply (le_div_iff_mul_le kpos).2
|
||||
apply (le_div_iff_mul_le npos).2
|
||||
rw [Nat.mul_assoc, Nat.mul_comm n k]
|
||||
apply (le_div_iff_mul_le (Nat.mul_pos kpos npos)).1
|
||||
apply Nat.le_refl
|
||||
|
||||
theorem div_mul_le_self : ∀ (m n : Nat), m / n * n ≤ m
|
||||
| m, 0 => by simp
|
||||
| _, _+1 => (le_div_iff_mul_le (Nat.succ_pos _)).1 (Nat.le_refl _)
|
||||
|
||||
theorem div_lt_iff_lt_mul (Hk : 0 < k) : x / k < y ↔ x < y * k := by
|
||||
rw [← Nat.not_le, ← Nat.not_le]; exact not_congr (le_div_iff_mul_le Hk)
|
||||
|
||||
theorem pos_of_div_pos {a b : Nat} (h : 0 < a / b) : 0 < a := by
|
||||
cases b with
|
||||
| zero => simp at h
|
||||
| succ b =>
|
||||
match a, h with
|
||||
| 0, h => simp at h
|
||||
| a + 1, _ => exact zero_lt_succ a
|
||||
|
||||
@[simp] theorem add_div_right (x : Nat) {z : Nat} (H : 0 < z) : (x + z) / z = (x / z) + 1 := by
|
||||
rw [div_eq_sub_div H (Nat.le_add_left _ _), Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem add_div_left (x : Nat) {z : Nat} (H : 0 < z) : (z + x) / z = (x / z) + 1 := by
|
||||
rw [Nat.add_comm, add_div_right x H]
|
||||
|
||||
theorem add_mul_div_left (x z : Nat) {y : Nat} (H : 0 < y) : (x + y * z) / y = x / y + z := by
|
||||
induction z with
|
||||
| zero => rw [Nat.mul_zero, Nat.add_zero, Nat.add_zero]
|
||||
| succ z ih => rw [mul_succ, ← Nat.add_assoc, add_div_right _ H, ih]; rfl
|
||||
|
||||
theorem add_mul_div_right (x y : Nat) {z : Nat} (H : 0 < z) : (x + y * z) / z = x / z + y := by
|
||||
rw [Nat.mul_comm, add_mul_div_left _ _ H]
|
||||
|
||||
@[simp] theorem add_mod_right (x z : Nat) : (x + z) % z = x % z := by
|
||||
rw [mod_eq_sub_mod (Nat.le_add_left ..), Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem add_mod_left (x z : Nat) : (x + z) % x = z % x := by
|
||||
rw [Nat.add_comm, add_mod_right]
|
||||
|
||||
@[simp] theorem add_mul_mod_self_left (x y z : Nat) : (x + y * z) % y = x % y := by
|
||||
match z with
|
||||
| 0 => rw [Nat.mul_zero, Nat.add_zero]
|
||||
| succ z => rw [mul_succ, ← Nat.add_assoc, add_mod_right, add_mul_mod_self_left (z := z)]
|
||||
|
||||
@[simp] theorem mul_add_mod_self_left (a b c : Nat) : (a * b + c) % a = c % a := by
|
||||
rw [Nat.add_comm, Nat.add_mul_mod_self_left]
|
||||
|
||||
@[simp] theorem add_mul_mod_self_right (x y z : Nat) : (x + y * z) % z = x % z := by
|
||||
rw [Nat.mul_comm, add_mul_mod_self_left]
|
||||
|
||||
@[simp] theorem mul_add_mod_self_right (a b c : Nat) : (a * b + c) % b = c % b := by
|
||||
rw [Nat.add_comm, Nat.add_mul_mod_self_right]
|
||||
|
||||
@[simp] theorem mul_mod_right (m n : Nat) : (m * n) % m = 0 := by
|
||||
rw [← Nat.zero_add (m * n), add_mul_mod_self_left, zero_mod]
|
||||
|
||||
@[simp] theorem mul_mod_left (m n : Nat) : (m * n) % n = 0 := by
|
||||
rw [Nat.mul_comm, mul_mod_right]
|
||||
|
||||
protected theorem div_eq_of_lt_le (lo : k * n ≤ m) (hi : m < (k + 1) * n) : m / n = k :=
|
||||
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun hn => by
|
||||
rw [hn, Nat.mul_zero] at hi lo; exact absurd lo (Nat.not_le_of_gt hi)
|
||||
Nat.le_antisymm
|
||||
(le_of_lt_succ ((Nat.div_lt_iff_lt_mul npos).2 hi))
|
||||
((Nat.le_div_iff_mul_le npos).2 lo)
|
||||
|
||||
theorem sub_mul_div (x n p : Nat) (h₁ : n*p ≤ x) : (x - n*p) / n = x / n - p := by
|
||||
match eq_zero_or_pos n with
|
||||
| .inl h₀ => rw [h₀, Nat.div_zero, Nat.div_zero, Nat.zero_sub]
|
||||
| .inr h₀ => induction p with
|
||||
| zero => rw [Nat.mul_zero, Nat.sub_zero, Nat.sub_zero]
|
||||
| succ p IH =>
|
||||
have h₂ : n * p ≤ x := Nat.le_trans (Nat.mul_le_mul_left _ (le_succ _)) h₁
|
||||
have h₃ : x - n * p ≥ n := by
|
||||
apply Nat.le_of_add_le_add_right
|
||||
rw [Nat.sub_add_cancel h₂, Nat.add_comm]
|
||||
rw [mul_succ] at h₁
|
||||
exact h₁
|
||||
rw [sub_succ, ← IH h₂, div_eq_sub_div h₀ h₃]
|
||||
simp [Nat.pred_succ, mul_succ, Nat.sub_sub]
|
||||
|
||||
theorem mul_sub_div (x n p : Nat) (h₁ : x < n*p) : (n * p - (x + 1)) / n = p - ((x / n) + 1) := by
|
||||
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun n0 => by
|
||||
rw [n0, Nat.zero_mul] at h₁; exact not_lt_zero _ h₁
|
||||
apply Nat.div_eq_of_lt_le
|
||||
focus
|
||||
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
|
||||
exact Nat.sub_le_sub_left ((div_lt_iff_lt_mul npos).1 (lt_succ_self _)) _
|
||||
focus
|
||||
show succ (pred (n * p - x)) ≤ (succ (pred (p - x / n))) * n
|
||||
rw [succ_pred_eq_of_pos (Nat.sub_pos_of_lt h₁),
|
||||
fun h => succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)] -- TODO: why is the function needed?
|
||||
focus
|
||||
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
|
||||
exact Nat.sub_le_sub_left (div_mul_le_self ..) _
|
||||
focus
|
||||
rwa [div_lt_iff_lt_mul npos, Nat.mul_comm]
|
||||
|
||||
theorem mul_mod_mul_left (z x y : Nat) : (z * x) % (z * y) = z * (x % y) :=
|
||||
if y0 : y = 0 then by
|
||||
rw [y0, Nat.mul_zero, mod_zero, mod_zero]
|
||||
else if z0 : z = 0 then by
|
||||
rw [z0, Nat.zero_mul, Nat.zero_mul, Nat.zero_mul, mod_zero]
|
||||
else by
|
||||
induction x using Nat.strongRecOn with
|
||||
| _ n IH =>
|
||||
have y0 : y > 0 := Nat.pos_of_ne_zero y0
|
||||
have z0 : z > 0 := Nat.pos_of_ne_zero z0
|
||||
cases Nat.lt_or_ge n y with
|
||||
| inl yn => rw [mod_eq_of_lt yn, mod_eq_of_lt (Nat.mul_lt_mul_of_pos_left yn z0)]
|
||||
| inr yn =>
|
||||
rw [mod_eq_sub_mod yn, mod_eq_sub_mod (Nat.mul_le_mul_left z yn),
|
||||
← Nat.mul_sub_left_distrib]
|
||||
exact IH _ (sub_lt (Nat.lt_of_lt_of_le y0 yn) y0)
|
||||
|
||||
theorem div_eq_of_lt (h₀ : a < b) : a / b = 0 := by
|
||||
rw [div_eq a, if_neg]
|
||||
intro h₁
|
||||
apply Nat.not_le_of_gt h₀ h₁.right
|
||||
|
||||
protected theorem mul_div_cancel (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
|
||||
let t := add_mul_div_right 0 m H
|
||||
rwa [Nat.zero_add, Nat.zero_div, Nat.zero_add] at t
|
||||
|
||||
protected theorem mul_div_cancel_left (m : Nat) {n : Nat} (H : 0 < n) : n * m / n = m := by
|
||||
rw [Nat.mul_comm, Nat.mul_div_cancel _ H]
|
||||
|
||||
protected theorem div_le_of_le_mul {m n : Nat} : ∀ {k}, m ≤ k * n → m / k ≤ n
|
||||
| 0, _ => by simp [Nat.div_zero, n.zero_le]
|
||||
| succ k, h => by
|
||||
suffices succ k * (m / succ k) ≤ succ k * n from
|
||||
Nat.le_of_mul_le_mul_left this (zero_lt_succ _)
|
||||
have h1 : succ k * (m / succ k) ≤ m % succ k + succ k * (m / succ k) := Nat.le_add_left _ _
|
||||
have h2 : m % succ k + succ k * (m / succ k) = m := by rw [mod_add_div]
|
||||
have h3 : m ≤ succ k * n := h
|
||||
rw [← h2] at h3
|
||||
exact Nat.le_trans h1 h3
|
||||
|
||||
@[simp] theorem mul_div_right (n : Nat) {m : Nat} (H : 0 < m) : m * n / m = n := by
|
||||
induction n <;> simp_all [mul_succ]
|
||||
|
||||
@[simp] theorem mul_div_left (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
|
||||
rw [Nat.mul_comm, mul_div_right _ H]
|
||||
|
||||
protected theorem div_self (H : 0 < n) : n / n = 1 := by
|
||||
let t := add_div_right 0 H
|
||||
rwa [Nat.zero_add, Nat.zero_div] at t
|
||||
|
||||
protected theorem div_eq_of_eq_mul_left (H1 : 0 < n) (H2 : m = k * n) : m / n = k :=
|
||||
by rw [H2, Nat.mul_div_cancel _ H1]
|
||||
|
||||
protected theorem div_eq_of_eq_mul_right (H1 : 0 < n) (H2 : m = n * k) : m / n = k :=
|
||||
by rw [H2, Nat.mul_div_cancel_left _ H1]
|
||||
|
||||
protected theorem mul_div_mul_left {m : Nat} (n k : Nat) (H : 0 < m) :
|
||||
m * n / (m * k) = n / k := by rw [← Nat.div_div_eq_div_mul, Nat.mul_div_cancel_left _ H]
|
||||
|
||||
protected theorem mul_div_mul_right {m : Nat} (n k : Nat) (H : 0 < m) :
|
||||
n * m / (k * m) = n / k := by rw [Nat.mul_comm, Nat.mul_comm k, Nat.mul_div_mul_left _ _ H]
|
||||
|
||||
theorem mul_div_le (m n : Nat) : n * (m / n) ≤ m := by
|
||||
match n, Nat.eq_zero_or_pos n with
|
||||
| _, Or.inl rfl => rw [Nat.zero_mul]; exact m.zero_le
|
||||
| n, Or.inr h => rw [Nat.mul_comm, ← Nat.le_div_iff_mul_le h]; exact Nat.le_refl _
|
||||
|
||||
|
||||
end Nat
|
||||
52
src/Init/Data/Nat/Div/Lemmas.lean
Normal file
52
src/Init/Data/Nat/Div/Lemmas.lean
Normal file
@@ -0,0 +1,52 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Omega
|
||||
import Init.Data.Nat.Lemmas
|
||||
|
||||
/-!
|
||||
# Further lemmas about `Nat.div` and `Nat.mod`, with the convenience of having `omega` available.
|
||||
-/
|
||||
|
||||
namespace Nat
|
||||
|
||||
theorem lt_div_iff_mul_lt (h : 0 < k) : x < y / k ↔ x * k < y - (k - 1) := by
|
||||
have t := le_div_iff_mul_le h (x := x + 1) (y := y)
|
||||
rw [succ_le, add_one_mul] at t
|
||||
have s : k = k - 1 + 1 := by omega
|
||||
conv at t => rhs; lhs; rhs; rw [s]
|
||||
rw [← Nat.add_assoc, succ_le, add_lt_iff_lt_sub_right] at t
|
||||
exact t
|
||||
|
||||
theorem div_le_iff_le_mul (h : 0 < k) : x / k ≤ y ↔ x ≤ y * k + k - 1 := by
|
||||
rw [le_iff_lt_add_one, Nat.div_lt_iff_lt_mul h, Nat.add_one_mul]
|
||||
omega
|
||||
|
||||
-- TODO: reprove `div_eq_of_lt_le` in terms of this:
|
||||
theorem div_eq_iff (h : 0 < k) : x / k = y ↔ x ≤ y * k + k - 1 ∧ y * k ≤ x := by
|
||||
rw [Nat.eq_iff_le_and_ge, le_div_iff_mul_le h, Nat.div_le_iff_le_mul h]
|
||||
|
||||
theorem lt_of_div_eq_zero (h : 0 < k) (h' : x / k = 0) : x < k := by
|
||||
rw [div_eq_iff h] at h'
|
||||
omega
|
||||
|
||||
theorem div_eq_zero_iff_lt (h : 0 < k) : x / k = 0 ↔ x < k :=
|
||||
⟨lt_of_div_eq_zero h, fun h' => Nat.div_eq_of_lt h'⟩
|
||||
|
||||
theorem div_mul_self_eq_mod_sub_self {x k : Nat} : (x / k) * k = x - (x % k) := by
|
||||
have := mod_eq_sub_div_mul (x := x) (k := k)
|
||||
have := div_mul_le_self x k
|
||||
omega
|
||||
|
||||
theorem mul_div_self_eq_mod_sub_self {x k : Nat} : k * (x / k) = x - (x % k) := by
|
||||
rw [Nat.mul_comm, div_mul_self_eq_mod_sub_self]
|
||||
|
||||
theorem lt_div_mul_self (h : 0 < k) (w : k ≤ x) : x - k < x / k * k := by
|
||||
rw [div_mul_self_eq_mod_sub_self]
|
||||
have : x % k < k := mod_lt x h
|
||||
omega
|
||||
|
||||
end Nat
|
||||
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.Nat.Div.Basic
|
||||
import Init.Meta
|
||||
|
||||
namespace Nat
|
||||
@@ -39,9 +39,9 @@ protected theorem dvd_add_iff_right {k m n : Nat} (h : k ∣ m) : k ∣ n ↔ k
|
||||
protected theorem dvd_add_iff_left {k m n : Nat} (h : k ∣ n) : k ∣ m ↔ k ∣ m + n := by
|
||||
rw [Nat.add_comm]; exact Nat.dvd_add_iff_right h
|
||||
|
||||
theorem dvd_mod_iff {k m n : Nat} (h: k ∣ n) : k ∣ m % n ↔ k ∣ m :=
|
||||
have := Nat.dvd_add_iff_left <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
|
||||
by rwa [mod_add_div] at this
|
||||
theorem dvd_mod_iff {k m n : Nat} (h: k ∣ n) : k ∣ m % n ↔ k ∣ m := by
|
||||
have := Nat.dvd_add_iff_left (m := m % n) <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
|
||||
rwa [mod_add_div] at this
|
||||
|
||||
theorem le_of_dvd {m n : Nat} (h : 0 < n) : m ∣ n → m ≤ n
|
||||
| ⟨k, e⟩ => by
|
||||
@@ -77,7 +77,7 @@ theorem dvd_of_mod_eq_zero {m n : Nat} (H : n % m = 0) : m ∣ n := by
|
||||
theorem dvd_iff_mod_eq_zero {m n : Nat} : m ∣ n ↔ n % m = 0 :=
|
||||
⟨mod_eq_zero_of_dvd, dvd_of_mod_eq_zero⟩
|
||||
|
||||
instance decidable_dvd : @DecidableRel Nat (·∣·) :=
|
||||
instance decidable_dvd : @DecidableRel Nat Nat (·∣·) :=
|
||||
fun _ _ => decidable_of_decidable_of_iff dvd_iff_mod_eq_zero.symm
|
||||
|
||||
theorem emod_pos_of_not_dvd {a b : Nat} (h : ¬ a ∣ b) : 0 < b % a := by
|
||||
|
||||
@@ -176,6 +176,9 @@ protected theorem add_pos_right (m) (h : 0 < n) : 0 < m + n :=
|
||||
protected theorem add_self_ne_one : ∀ n, n + n ≠ 1
|
||||
| n+1, h => by rw [Nat.succ_add, Nat.succ.injEq] at h; contradiction
|
||||
|
||||
theorem le_iff_lt_add_one : x ≤ y ↔ x < y + 1 := by
|
||||
omega
|
||||
|
||||
/-! ## sub -/
|
||||
|
||||
protected theorem sub_one (n) : n - 1 = pred n := rfl
|
||||
@@ -225,6 +228,9 @@ protected theorem sub_le_iff_le_add' {a b c : Nat} : a - b ≤ c ↔ a ≤ b + c
|
||||
protected theorem le_sub_iff_add_le {n : Nat} (h : k ≤ m) : n ≤ m - k ↔ n + k ≤ m :=
|
||||
⟨Nat.add_le_of_le_sub h, Nat.le_sub_of_add_le⟩
|
||||
|
||||
theorem add_lt_iff_lt_sub_right {a b c : Nat} : a + b < c ↔ a < c - b := by
|
||||
omega
|
||||
|
||||
protected theorem add_le_of_le_sub' {n k m : Nat} (h : m ≤ k) : n ≤ k - m → m + n ≤ k :=
|
||||
Nat.add_comm .. ▸ Nat.add_le_of_le_sub h
|
||||
|
||||
@@ -1046,6 +1052,25 @@ instance decidableExistsLE [DecidablePred p] : DecidablePred fun n => ∃ m : Na
|
||||
fun n => decidable_of_iff (∃ m, m < n + 1 ∧ p m)
|
||||
(exists_congr fun _ => and_congr_left' Nat.lt_succ_iff)
|
||||
|
||||
/-- Dependent version of `decidableExistsLT`. -/
|
||||
instance decidableExistsLT' {p : (m : Nat) → m < k → Prop} [I : ∀ m h, Decidable (p m h)] :
|
||||
Decidable (∃ m : Nat, ∃ h : m < k, p m h) :=
|
||||
match k, p, I with
|
||||
| 0, _, _ => isFalse (by simp)
|
||||
| (k + 1), p, I => @decidable_of_iff _ ((∃ m, ∃ h : m < k, p m (by omega)) ∨ p k (by omega))
|
||||
⟨by rintro (⟨m, h, w⟩ | w); exact ⟨m, by omega, w⟩; exact ⟨k, by omega, w⟩,
|
||||
fun ⟨m, h, w⟩ => if h' : m < k then .inl ⟨m, h', w⟩ else
|
||||
by obtain rfl := (by omega : m = k); exact .inr w⟩
|
||||
(@instDecidableOr _ _
|
||||
(decidableExistsLT' (p := fun m h => p m (by omega)) (I := fun m h => I m (by omega)))
|
||||
inferInstance)
|
||||
|
||||
/-- Dependent version of `decidableExistsLE`. -/
|
||||
instance decidableExistsLE' {p : (m : Nat) → m ≤ k → Prop} [I : ∀ m h, Decidable (p m h)] :
|
||||
Decidable (∃ m : Nat, ∃ h : m ≤ k, p m h) :=
|
||||
decidable_of_iff (∃ m, ∃ h : m < k + 1, p m (by omega)) (exists_congr fun _ =>
|
||||
⟨fun ⟨h, w⟩ => ⟨le_of_lt_succ h, w⟩, fun ⟨h, w⟩ => ⟨lt_add_one_of_le h, w⟩⟩)
|
||||
|
||||
/-! ### Results about `List.sum` specialized to `Nat` -/
|
||||
|
||||
protected theorem sum_pos_iff_exists_pos {l : List Nat} : 0 < l.sum ↔ ∃ x ∈ l, 0 < x := by
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Meta
|
||||
import Init.Data.Float
|
||||
import Init.Data.Float32
|
||||
import Init.Data.Nat.Log2
|
||||
|
||||
/-- For decimal and scientific numbers (e.g., `1.23`, `3.12e10`).
|
||||
@@ -56,3 +57,34 @@ instance : OfNat Float n := ⟨Float.ofNat n⟩
|
||||
|
||||
abbrev Nat.toFloat (n : Nat) : Float :=
|
||||
Float.ofNat n
|
||||
|
||||
/-- Computes `m * 2^e`. -/
|
||||
def Float32.ofBinaryScientific (m : Nat) (e : Int) : Float32 :=
|
||||
let s := m.log2 - 63
|
||||
let m := (m >>> s).toUInt64
|
||||
let e := e + s
|
||||
m.toFloat32.scaleB e
|
||||
|
||||
protected opaque Float32.ofScientific (m : Nat) (s : Bool) (e : Nat) : Float32 :=
|
||||
if s then
|
||||
let s := 64 - m.log2 -- ensure we have 64 bits of mantissa left after division
|
||||
let m := (m <<< (3 * e + s)) / 5^e
|
||||
Float32.ofBinaryScientific m (-4 * e - s)
|
||||
else
|
||||
Float32.ofBinaryScientific (m * 5^e) e
|
||||
|
||||
instance : OfScientific Float32 where
|
||||
ofScientific := Float32.ofScientific
|
||||
|
||||
@[export lean_float32_of_nat]
|
||||
def Float32.ofNat (n : Nat) : Float32 :=
|
||||
OfScientific.ofScientific n false 0
|
||||
|
||||
def Float32.ofInt : Int → Float
|
||||
| Int.ofNat n => Float.ofNat n
|
||||
| Int.negSucc n => Float.neg (Float.ofNat (Nat.succ n))
|
||||
|
||||
instance : OfNat Float32 n := ⟨Float32.ofNat n⟩
|
||||
|
||||
abbrev Nat.toFloat32 (n : Nat) : Float32 :=
|
||||
Float32.ofNat n
|
||||
|
||||
@@ -10,3 +10,4 @@ import Init.Data.Option.Instances
|
||||
import Init.Data.Option.Lemmas
|
||||
import Init.Data.Option.Attach
|
||||
import Init.Data.Option.List
|
||||
import Init.Data.Option.Monadic
|
||||
|
||||
@@ -56,7 +56,6 @@ theorem attach_map_val (o : Option α) (f : α → β) :
|
||||
(o.attach.map fun i => f i.val) = o.map f :=
|
||||
attach_map_coe _ _
|
||||
|
||||
@[simp]
|
||||
theorem attach_map_subtype_val (o : Option α) :
|
||||
o.attach.map Subtype.val = o :=
|
||||
(attach_map_coe _ _).trans (congrFun Option.map_id _)
|
||||
@@ -69,12 +68,11 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (o : Option α) (H
|
||||
((o.attachWith p H).map fun i => f i.val) = o.map f :=
|
||||
attachWith_map_coe _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a ∈ o, p a) :
|
||||
(o.attachWith p H).map Subtype.val = o :=
|
||||
(attachWith_map_coe _ _ _).trans (congrFun Option.map_id _)
|
||||
|
||||
@[simp] theorem mem_attach : ∀ (o : Option α) (x : {x // x ∈ o}), x ∈ o.attach
|
||||
theorem mem_attach : ∀ (o : Option α) (x : {x // x ∈ o}), x ∈ o.attach
|
||||
| none, ⟨x, h⟩ => by simp at h
|
||||
| some a, ⟨x, h⟩ => by simpa using h
|
||||
|
||||
@@ -92,14 +90,14 @@ theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a
|
||||
(o.attachWith p H).isSome = o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem attach_eq_none_iff (o : Option α) : o.attach = none ↔ o = none := by
|
||||
@[simp] theorem attach_eq_none_iff {o : Option α} : o.attach = none ↔ o = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem attach_eq_some_iff {o : Option α} {x : {x // x ∈ o}} :
|
||||
o.attach = some x ↔ o = some x.val := by
|
||||
cases o <;> cases x <;> simp
|
||||
|
||||
@[simp] theorem attachWith_eq_none_iff {p : α → Prop} (o : Option α) (H : ∀ a ∈ o, p a) :
|
||||
@[simp] theorem attachWith_eq_none_iff {p : α → Prop} {o : Option α} (H : ∀ a ∈ o, p a) :
|
||||
o.attachWith p H = none ↔ o = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -119,10 +117,14 @@ theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a
|
||||
· simp at h
|
||||
· simp [get_some]
|
||||
|
||||
@[simp] theorem toList_attach (o : Option α) :
|
||||
theorem toList_attach (o : Option α) :
|
||||
o.attach.toList = o.toList.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem attach_toList (o : Option α) :
|
||||
o.toList.attach = (o.attach.map fun ⟨a, h⟩ => ⟨a, by simpa using h⟩).toList := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem attach_map {o : Option α} (f : α → β) :
|
||||
(o.map f).attach = o.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem f h⟩) := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -96,12 +96,12 @@ This is similar to `<|>`/`orElse`, but it is strict in the second argument. -/
|
||||
| some a, _ => some a
|
||||
| none, b => b
|
||||
|
||||
@[inline] protected def lt (r : α → α → Prop) : Option α → Option α → Prop
|
||||
@[inline] protected def lt (r : α → β → Prop) : Option α → Option β → Prop
|
||||
| none, some _ => True
|
||||
| some x, some y => r x y
|
||||
| _, _ => False
|
||||
|
||||
instance (r : α → α → Prop) [s : DecidableRel r] : DecidableRel (Option.lt r)
|
||||
instance (r : α → β → Prop) [s : DecidableRel r] : DecidableRel (Option.lt r)
|
||||
| none, some _ => isTrue trivial
|
||||
| some x, some y => s x y
|
||||
| some _, none => isFalse not_false
|
||||
|
||||
@@ -70,6 +70,13 @@ satisfy `p`, using the proof to apply `f`.
|
||||
| none, _ => none
|
||||
| some a, H => f a (H a rfl)
|
||||
|
||||
/-- Partial elimination. If `o : Option α` and `f : (a : α) → a ∈ o → β`, then `o.pelim b f` is
|
||||
the same as `o.elim b f` but `f` is passed the proof that `a ∈ o`. -/
|
||||
@[inline] def pelim (o : Option α) (b : β) (f : (a : α) → a ∈ o → β) : β :=
|
||||
match o with
|
||||
| none => b
|
||||
| some a => f a rfl
|
||||
|
||||
/-- Map a monadic function which returns `Unit` over an `Option`. -/
|
||||
@[inline] protected def forM [Pure m] : Option α → (α → m PUnit) → m PUnit
|
||||
| none , _ => pure ⟨⟩
|
||||
|
||||
@@ -629,4 +629,12 @@ theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → a ∈ o → Option
|
||||
· rintro ⟨h, rfl⟩
|
||||
rfl
|
||||
|
||||
/-! ### pelim -/
|
||||
|
||||
@[simp] theorem pelim_none : pelim none b f = b := rfl
|
||||
@[simp] theorem pelim_some : pelim (some a) b f = f a rfl := rfl
|
||||
|
||||
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
|
||||
cases o <;> simp
|
||||
|
||||
end Option
|
||||
|
||||
@@ -15,17 +15,25 @@ namespace Option
|
||||
forIn' none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp] theorem forIn'_some [Monad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
forIn' (some a) b f = bind (f a rfl b) (fun | .done r | .yield r => pure r) := by
|
||||
rfl
|
||||
@[simp] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
congr
|
||||
funext x
|
||||
split <;> rfl
|
||||
|
||||
@[simp] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp] theorem forIn_some [Monad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn (some a) b f = bind (f a b) (fun | .done r | .yield r => pure r) := by
|
||||
rfl
|
||||
@[simp] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn, forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
congr
|
||||
funext x
|
||||
split <;> rfl
|
||||
|
||||
@[simp] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
|
||||
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
|
||||
@@ -35,4 +43,20 @@ namespace Option
|
||||
forIn o.toList b f = forIn o b f := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
|
||||
o.toList.foldl f a = o.elim a (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem foldr_toList (o : Option β) (a : α) (f : β → α → α) :
|
||||
o.toList.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
end Option
|
||||
|
||||
95
src/Init/Data/Option/Monadic.lean
Normal file
95
src/Init/Data/Option/Monadic.lean
Normal file
@@ -0,0 +1,95 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
|
||||
import Init.Data.Option.Attach
|
||||
import Init.Control.Lawful.Basic
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp] theorem forM_none [Monad m] (f : α → m PUnit) :
|
||||
none.forM f = pure .unit := rfl
|
||||
|
||||
@[simp] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
|
||||
(some a).forM f = f a := rfl
|
||||
|
||||
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
|
||||
(o.map g).forM f = o.forM (fun a => f (g a)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[congr] theorem forIn'_congr [Monad m] [LawfulMonad m] {as bs : Option α} (w : as = bs)
|
||||
{b b' : β} (hb : b = b')
|
||||
{f : (a' : α) → a' ∈ as → β → m (ForInStep β)}
|
||||
{g : (a' : α) → a' ∈ bs → β → m (ForInStep β)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
forIn' as b f = forIn' bs b' g := by
|
||||
cases as <;> cases bs
|
||||
· simp [hb]
|
||||
· simp at w
|
||||
· simp at w
|
||||
· simp only [some.injEq] at w
|
||||
subst w
|
||||
simp [hb, h]
|
||||
|
||||
theorem forIn'_eq_pelim [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (f : (a : α) → a ∈ o → β → m (ForInStep β)) (b : β) :
|
||||
forIn' o b f =
|
||||
o.pelim (pure b) (fun a h => ForInStep.value <$> f a h b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_pelim [Monad m] [LawfulMonad m] (o : Option α)
|
||||
(f : (a : α) → a ∈ o → β → m γ) (g : (a : α) → a ∈ o → β → γ → β) (b : β) :
|
||||
forIn' o b (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
|
||||
o.pelim (pure b) (fun a h => g a h b <$> f a h b) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem forIn'_pure_yield_eq_pelim [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (f : (a : α) → a ∈ o → β → β) (b : β) :
|
||||
forIn' o b (fun a m b => pure (.yield (f a m b))) =
|
||||
pure (f := m) (o.pelim b (fun a h => f a h b)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] 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
|
||||
|
||||
@[simp] 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_eq_elim [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (f : (a : α) → β → m (ForInStep β)) (b : β) :
|
||||
forIn o b f =
|
||||
o.elim (pure b) (fun a => ForInStep.value <$> f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem forIn_yield_eq_elim [Monad m] [LawfulMonad m] (o : Option α)
|
||||
(f : (a : α) → β → m γ) (g : (a : α) → β → γ → β) (b : β) :
|
||||
forIn o b (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||||
o.elim (pure b) (fun a => g a b <$> f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem forIn_pure_yield_eq_elim [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (f : (a : α) → β → β) (b : β) :
|
||||
forIn o b (fun a b => pure (.yield (f a b))) =
|
||||
pure (f := m) (o.elim b (fun a => f a b)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] 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
|
||||
|
||||
@[simp] 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
|
||||
|
||||
end Option
|
||||
@@ -210,12 +210,18 @@ Derive an `LT` instance from an `Ord` instance.
|
||||
protected def toLT (_ : Ord α) : LT α :=
|
||||
ltOfOrd
|
||||
|
||||
instance [i : Ord α] : DecidableRel (@LT.lt _ (Ord.toLT i)) :=
|
||||
inferInstanceAs (DecidableRel (fun a b => compare a b = Ordering.lt))
|
||||
|
||||
/--
|
||||
Derive an `LE` instance from an `Ord` instance.
|
||||
-/
|
||||
protected def toLE (_ : Ord α) : LE α :=
|
||||
leOfOrd
|
||||
|
||||
instance [i : Ord α] : DecidableRel (@LE.le _ (Ord.toLE i)) :=
|
||||
inferInstanceAs (DecidableRel (fun a b => (compare a b).isLE))
|
||||
|
||||
/--
|
||||
Invert the order of an `Ord` instance.
|
||||
-/
|
||||
@@ -248,6 +254,6 @@ protected def arrayOrd [a : Ord α] : Ord (Array α) where
|
||||
compare x y :=
|
||||
let _ : LT α := a.toLT
|
||||
let _ : BEq α := a.toBEq
|
||||
compareOfLessAndBEq x.toList y.toList
|
||||
if List.lex x.toList y.toList then .lt else if x == y then .eq else .gt
|
||||
|
||||
end Ord
|
||||
|
||||
@@ -1,74 +1,8 @@
|
||||
/-
|
||||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Meta
|
||||
|
||||
namespace Std
|
||||
-- We put `Range` in `Init` because we want the notation `[i:j]` without importing `Std`
|
||||
-- We don't put `Range` in the top-level namespace to avoid collisions with user defined types
|
||||
structure Range where
|
||||
start : Nat := 0
|
||||
stop : Nat
|
||||
step : Nat := 1
|
||||
|
||||
instance : Membership Nat Range where
|
||||
mem r i := r.start ≤ i ∧ i < r.stop
|
||||
|
||||
namespace Range
|
||||
universe u v
|
||||
|
||||
@[inline] protected def forIn' {β : Type u} {m : Type u → Type v} [Monad m] (range : Range) (init : β) (f : (i : Nat) → i ∈ range → β → m (ForInStep β)) : m β :=
|
||||
let rec @[specialize] loop (start stop step : Nat) (f : (i : Nat) → start ≤ i ∧ i < stop → β → m (ForInStep β)) (fuel i : Nat) (hl : start ≤ i) (b : β) : m β := do
|
||||
if hu : i < stop then
|
||||
match fuel with
|
||||
| 0 => pure b
|
||||
| fuel+1 => match (← f i ⟨hl, hu⟩ b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop start stop step f fuel (i + step) (Nat.le_trans hl (Nat.le_add_right ..)) b
|
||||
else
|
||||
return b
|
||||
loop range.start range.stop range.step f range.stop range.start (Nat.le_refl ..) init
|
||||
|
||||
instance : ForIn' m Range Nat inferInstance where
|
||||
forIn' := Range.forIn'
|
||||
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
|
||||
@[inline] protected def forM {m : Type u → Type v} [Monad m] (range : Range) (f : Nat → m PUnit) : m PUnit :=
|
||||
let rec @[specialize] loop (fuel i stop step : Nat) : m PUnit := do
|
||||
if i ≥ stop then
|
||||
pure ⟨⟩
|
||||
else match fuel with
|
||||
| 0 => pure ⟨⟩
|
||||
| fuel+1 => f i; loop fuel (i + step) stop step
|
||||
loop range.stop range.start range.stop range.step
|
||||
|
||||
instance : ForM m Range Nat where
|
||||
forM := Range.forM
|
||||
|
||||
syntax:max "[" withoutPosition(":" term) "]" : term
|
||||
syntax:max "[" withoutPosition(term ":" term) "]" : term
|
||||
syntax:max "[" withoutPosition(":" term ":" term) "]" : term
|
||||
syntax:max "[" withoutPosition(term ":" term ":" term) "]" : term
|
||||
|
||||
macro_rules
|
||||
| `([ : $stop]) => `({ stop := $stop : Range })
|
||||
| `([ $start : $stop ]) => `({ start := $start, stop := $stop : Range })
|
||||
| `([ $start : $stop : $step ]) => `({ start := $start, stop := $stop, step := $step : Range })
|
||||
| `([ : $stop : $step ]) => `({ stop := $stop, step := $step : Range })
|
||||
|
||||
end Range
|
||||
end Std
|
||||
|
||||
theorem Membership.mem.upper {i : Nat} {r : Std.Range} (h : i ∈ r) : i < r.stop := h.2
|
||||
|
||||
theorem Membership.mem.lower {i : Nat} {r : Std.Range} (h : i ∈ r) : r.start ≤ i := h.1
|
||||
|
||||
theorem Membership.get_elem_helper {i n : Nat} {r : Std.Range} (h₁ : i ∈ r) (h₂ : r.stop = n) :
|
||||
i < n := h₂ ▸ h₁.2
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Membership.get_elem_helper; assumption; rfl)
|
||||
import Init.Data.Range.Basic
|
||||
import Init.Data.Range.Lemmas
|
||||
|
||||
86
src/Init/Data/Range/Basic.lean
Normal file
86
src/Init/Data/Range/Basic.lean
Normal file
@@ -0,0 +1,86 @@
|
||||
/-
|
||||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Meta
|
||||
import Init.Omega
|
||||
|
||||
namespace Std
|
||||
-- We put `Range` in `Init` because we want the notation `[i:j]` without importing `Std`
|
||||
-- We don't put `Range` in the top-level namespace to avoid collisions with user defined types
|
||||
structure Range where
|
||||
start : Nat := 0
|
||||
stop : Nat
|
||||
step : Nat := 1
|
||||
step_pos : 0 < step
|
||||
|
||||
instance : Membership Nat Range where
|
||||
mem r i := r.start ≤ i ∧ i < r.stop ∧ (i - r.start) % r.step = 0
|
||||
|
||||
namespace Range
|
||||
universe u v
|
||||
|
||||
/-- The number of elements in the range. -/
|
||||
@[simp] def size (r : Range) : Nat := (r.stop - r.start + r.step - 1) / r.step
|
||||
|
||||
@[inline] protected def forIn' [Monad m] (range : Range) (init : β)
|
||||
(f : (i : Nat) → i ∈ range → β → m (ForInStep β)) : m β :=
|
||||
let rec @[specialize] loop (b : β) (i : Nat)
|
||||
(hs : (i - range.start) % range.step = 0) (hl : range.start ≤ i := by omega) : m β := do
|
||||
if h : i < range.stop then
|
||||
match (← f i ⟨hl, by omega, hs⟩ b) with
|
||||
| .done b => pure b
|
||||
| .yield b =>
|
||||
have := range.step_pos
|
||||
loop b (i + range.step) (by rwa [Nat.add_comm, Nat.add_sub_assoc hl, Nat.add_mod_left])
|
||||
else
|
||||
pure b
|
||||
have := range.step_pos
|
||||
loop init range.start (by simp)
|
||||
|
||||
instance : ForIn' m Range Nat inferInstance where
|
||||
forIn' := Range.forIn'
|
||||
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
|
||||
@[inline] protected def forM [Monad m] (range : Range) (f : Nat → m PUnit) : m PUnit :=
|
||||
let rec @[specialize] loop (i : Nat): m PUnit := do
|
||||
if i < range.stop then
|
||||
f i
|
||||
have := range.step_pos
|
||||
loop (i + range.step)
|
||||
else
|
||||
pure ⟨⟩
|
||||
have := range.step_pos
|
||||
loop range.start
|
||||
|
||||
instance : ForM m Range Nat where
|
||||
forM := Range.forM
|
||||
|
||||
syntax:max "[" withoutPosition(":" term) "]" : term
|
||||
syntax:max "[" withoutPosition(term ":" term) "]" : term
|
||||
syntax:max "[" withoutPosition(":" term ":" term) "]" : term
|
||||
syntax:max "[" withoutPosition(term ":" term ":" term) "]" : term
|
||||
|
||||
macro_rules
|
||||
| `([ : $stop]) => `({ stop := $stop, step_pos := Nat.zero_lt_one : Range })
|
||||
| `([ $start : $stop ]) => `({ start := $start, stop := $stop, step_pos := Nat.zero_lt_one : Range })
|
||||
| `([ $start : $stop : $step ]) => `({ start := $start, stop := $stop, step := $step, step_pos := by decide : Range })
|
||||
| `([ : $stop : $step ]) => `({ stop := $stop, step := $step, step_pos := by decide : Range })
|
||||
|
||||
end Range
|
||||
end Std
|
||||
|
||||
theorem Membership.mem.upper {i : Nat} {r : Std.Range} (h : i ∈ r) : i < r.stop := h.2.1
|
||||
|
||||
theorem Membership.mem.lower {i : Nat} {r : Std.Range} (h : i ∈ r) : r.start ≤ i := h.1
|
||||
|
||||
theorem Membership.mem.step {i : Nat} {r : Std.Range} (h : i ∈ r) : (i - r.start) % r.step = 0 := h.2.2
|
||||
|
||||
theorem Membership.get_elem_helper {i n : Nat} {r : Std.Range} (h₁ : i ∈ r) (h₂ : r.stop = n) :
|
||||
i < n := h₂ ▸ h₁.2.1
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Membership.get_elem_helper; assumption; rfl)
|
||||
103
src/Init/Data/Range/Lemmas.lean
Normal file
103
src/Init/Data/Range/Lemmas.lean
Normal file
@@ -0,0 +1,103 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Range.Basic
|
||||
import Init.Data.List.Range
|
||||
import Init.Data.List.Monadic
|
||||
import Init.Data.Nat.Div.Lemmas
|
||||
|
||||
/-!
|
||||
# Lemmas about `Std.Range`
|
||||
|
||||
We provide lemmas rewriting for loops over `Std.Range` in terms of `List.range'`.
|
||||
-/
|
||||
|
||||
namespace Std.Range
|
||||
|
||||
/-- Generalization of `mem_of_mem_range'` used in `forIn'_loop_eq_forIn'_range'` below. -/
|
||||
private theorem mem_of_mem_range'_aux {r : Range} {a : Nat} (w₁ : (i - r.start) % r.step = 0)
|
||||
(w₂ : r.start ≤ i)
|
||||
(h : a ∈ List.range' i ((r.stop - i + r.step - 1) / r.step) r.step) : a ∈ r := by
|
||||
obtain ⟨j, h', rfl⟩ := List.mem_range'.1 h
|
||||
refine ⟨by omega, ?_⟩
|
||||
rw [Nat.lt_div_iff_mul_lt r.step_pos, Nat.mul_comm] at h'
|
||||
constructor
|
||||
· omega
|
||||
· rwa [Nat.add_comm, Nat.add_sub_assoc w₂, Nat.mul_add_mod_self_left]
|
||||
|
||||
theorem mem_of_mem_range' {r : Range} (h : x ∈ List.range' r.start r.size r.step) : x ∈ r := by
|
||||
unfold size at h
|
||||
apply mem_of_mem_range'_aux (by simp) (by simp) h
|
||||
|
||||
private theorem size_eq (r : Std.Range) (h : i < r.stop) :
|
||||
(r.stop - i + r.step - 1) / r.step =
|
||||
(r.stop - (i + r.step) + r.step - 1) / r.step + 1 := by
|
||||
have w := r.step_pos
|
||||
if i + r.step < r.stop then -- Not sure this case split is strictly necessary.
|
||||
rw [Nat.div_eq_iff w, Nat.add_one_mul]
|
||||
have : (r.stop - (i + r.step) + r.step - 1) / r.step * r.step ≤
|
||||
(r.stop - (i + r.step) + r.step - 1) := Nat.div_mul_le_self _ _
|
||||
have : r.stop - (i + r.step) + r.step - 1 - r.step <
|
||||
(r.stop - (i + r.step) + r.step - 1) / r.step * r.step :=
|
||||
Nat.lt_div_mul_self w (by omega)
|
||||
omega
|
||||
else
|
||||
have : (r.stop - i + r.step - 1) / r.step = 1 := by
|
||||
rw [Nat.div_eq_iff w, Nat.one_mul]
|
||||
omega
|
||||
have : (r.stop - (i + r.step) + r.step - 1) / r.step = 0 := by
|
||||
rw [Nat.div_eq_iff] <;> omega
|
||||
omega
|
||||
|
||||
private theorem forIn'_loop_eq_forIn'_range' [Monad m] (r : Std.Range)
|
||||
(init : β) (f : (a : Nat) → a ∈ r → β → m (ForInStep β)) (i) (w₁) (w₂) :
|
||||
forIn'.loop r f init i w₁ w₂ =
|
||||
forIn' (List.range' i ((r.stop - i + r.step - 1) / r.step) r.step) init
|
||||
fun a h => f a (mem_of_mem_range'_aux w₁ w₂ h) := by
|
||||
have w := r.step_pos
|
||||
rw [forIn'.loop]
|
||||
split <;> rename_i h
|
||||
· simp only [size_eq r h, List.range'_succ, List.forIn'_cons]
|
||||
congr 1
|
||||
funext step
|
||||
split
|
||||
· simp
|
||||
· rw [forIn'_loop_eq_forIn'_range']
|
||||
· have : (r.stop - i + r.step - 1) / r.step = 0 := by
|
||||
rw [Nat.div_eq_iff] <;> omega
|
||||
simp [this]
|
||||
|
||||
@[simp] theorem forIn'_eq_forIn'_range' [Monad m] (r : Std.Range)
|
||||
(init : β) (f : (a : Nat) → a ∈ r → β → m (ForInStep β)) :
|
||||
forIn' r init f =
|
||||
forIn' (List.range' r.start r.size r.step) init (fun a h => f a (mem_of_mem_range' h)) := by
|
||||
conv => lhs; simp only [forIn', Range.forIn']
|
||||
simp only [size]
|
||||
rw [forIn'_loop_eq_forIn'_range']
|
||||
|
||||
@[simp] theorem forIn_eq_forIn_range' [Monad m] (r : Std.Range)
|
||||
(init : β) (f : Nat → β → m (ForInStep β)) :
|
||||
forIn r init f = forIn (List.range' r.start r.size r.step) init f := by
|
||||
simp only [forIn, forIn'_eq_forIn'_range']
|
||||
|
||||
private theorem forM_loop_eq_forM_range' [Monad m] (r : Std.Range) (f : Nat → m PUnit) :
|
||||
forM.loop r f i = forM (List.range' i ((r.stop - i + r.step - 1) / r.step) r.step) f := by
|
||||
have w := r.step_pos
|
||||
rw [forM.loop]
|
||||
split <;> rename_i h
|
||||
· simp [size_eq r h, List.range'_succ, List.forM_cons]
|
||||
congr 1
|
||||
funext
|
||||
rw [forM_loop_eq_forM_range']
|
||||
· have : (r.stop - i + r.step - 1) / r.step = 0 := by
|
||||
rw [Nat.div_eq_iff] <;> omega
|
||||
simp [this]
|
||||
|
||||
@[simp] theorem forM_eq_forM_range' [Monad m] (r : Std.Range) (f : Nat → m PUnit) :
|
||||
forM r f = forM (List.range' r.start r.size r.step) f := by
|
||||
simp only [forM, Range.forM, forM_loop_eq_forM_range', size]
|
||||
|
||||
end Std.Range
|
||||
@@ -21,8 +21,10 @@ instance : LT String :=
|
||||
⟨fun s₁ s₂ => s₁.data < s₂.data⟩
|
||||
|
||||
@[extern "lean_string_dec_lt"]
|
||||
instance decLt (s₁ s₂ : @& String) : Decidable (s₁ < s₂) :=
|
||||
List.hasDecidableLt s₁.data s₂.data
|
||||
instance decidableLT (s₁ s₂ : @& String) : Decidable (s₁ < s₂) :=
|
||||
List.decidableLT s₁.data s₂.data
|
||||
|
||||
@[deprecated decidableLT (since := "2024-12-13")] abbrev decLt := @decidableLT
|
||||
|
||||
@[reducible] protected def le (a b : String) : Prop := ¬ b < a
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Char.Lemmas
|
||||
import Init.Data.List.Lex
|
||||
|
||||
namespace String
|
||||
|
||||
@@ -12,10 +13,39 @@ protected theorem data_eq_of_eq {a b : String} (h : a = b) : a.data = b.data :=
|
||||
h ▸ rfl
|
||||
protected theorem ne_of_data_ne {a b : String} (h : a.data ≠ b.data) : a ≠ b :=
|
||||
fun h' => absurd (String.data_eq_of_eq h') h
|
||||
@[simp] protected theorem lt_irrefl (s : String) : ¬ s < s :=
|
||||
List.lt_irrefl Char.lt_irrefl s.data
|
||||
|
||||
@[simp] protected theorem not_le {a b : String} : ¬ a ≤ b ↔ b < a := Decidable.not_not
|
||||
@[simp] protected theorem not_lt {a b : String} : ¬ a < b ↔ b ≤ a := Iff.rfl
|
||||
@[simp] protected theorem le_refl (a : String) : a ≤ a := List.le_refl _
|
||||
@[simp] protected theorem lt_irrefl (a : String) : ¬ a < a := List.lt_irrefl _
|
||||
|
||||
attribute [local instance] Char.notLTTrans Char.notLTAntisymm Char.notLTTotal
|
||||
|
||||
protected theorem le_trans {a b c : String} : a ≤ b → b ≤ c → a ≤ c := List.le_trans
|
||||
protected theorem lt_trans {a b c : String} : a < b → b < c → a < c := List.lt_trans
|
||||
protected theorem le_total (a b : String) : a ≤ b ∨ b ≤ a := List.le_total
|
||||
protected theorem le_antisymm {a b : String} : a ≤ b → b ≤ a → a = b := fun h₁ h₂ => String.ext (List.le_antisymm (as := a.data) (bs := b.data) h₁ h₂)
|
||||
protected theorem lt_asymm {a b : String} (h : a < b) : ¬ b < a := List.lt_asymm h
|
||||
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
|
||||
|
||||
@@ -30,7 +30,7 @@ protected theorem «exists» {p : α ⊕ β → Prop} :
|
||||
| Or.inl ⟨a, h⟩ => ⟨inl a, h⟩
|
||||
| Or.inr ⟨b, h⟩ => ⟨inr b, h⟩⟩
|
||||
|
||||
theorem forall_sum {γ : α ⊕ β → Sort _} (p : (∀ ab, γ ab) → Prop) :
|
||||
theorem forall_sum {γ : α ⊕ β → Sort _} {p : (∀ ab, γ ab) → Prop} :
|
||||
(∀ fab, p fab) ↔ (∀ fa fb, p (Sum.rec fa fb)) := by
|
||||
refine ⟨fun h fa fb => h _, fun h fab => ?_⟩
|
||||
have h1 : fab = Sum.rec (fun a => fab (Sum.inl a)) (fun b => fab (Sum.inr b)) := by
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
Authors: Markus Himmel, Mac Malone
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt.Lemmas
|
||||
import Init.Data.Fin.Bitwise
|
||||
import Init.Data.BitVec.Lemmas
|
||||
|
||||
set_option hygiene false in
|
||||
macro "declare_bitwise_uint_theorems" typeName:ident : command =>
|
||||
macro "declare_bitwise_uint_theorems" typeName:ident bits:term:arg : command =>
|
||||
`(
|
||||
namespace $typeName
|
||||
|
||||
@[simp] protected theorem and_toNat (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := BitVec.toNat_and ..
|
||||
@[simp] protected theorem toBitVec_and (a b : $typeName) : (a &&& b).toBitVec = a.toBitVec &&& b.toBitVec := rfl
|
||||
@[simp] protected theorem toBitVec_or (a b : $typeName) : (a ||| b).toBitVec = a.toBitVec ||| b.toBitVec := rfl
|
||||
@[simp] protected theorem toBitVec_xor (a b : $typeName) : (a ^^^ b).toBitVec = a.toBitVec ^^^ b.toBitVec := rfl
|
||||
@[simp] protected theorem toBitVec_shiftLeft (a b : $typeName) : (a <<< b).toBitVec = a.toBitVec <<< (b.toBitVec % $bits) := rfl
|
||||
@[simp] protected theorem toBitVec_shiftRight (a b : $typeName) : (a >>> b).toBitVec = a.toBitVec >>> (b.toBitVec % $bits) := rfl
|
||||
|
||||
@[simp] protected theorem toNat_and (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := by simp [toNat]
|
||||
@[simp] protected theorem toNat_or (a b : $typeName) : (a ||| b).toNat = a.toNat ||| b.toNat := by simp [toNat]
|
||||
@[simp] protected theorem toNat_xor (a b : $typeName) : (a ^^^ b).toNat = a.toNat ^^^ b.toNat := by simp [toNat]
|
||||
@[simp] protected theorem toNat_shiftLeft (a b : $typeName) : (a <<< b).toNat = a.toNat <<< (b.toNat % $bits) % 2 ^ $bits := by simp [toNat]
|
||||
@[simp] protected theorem toNat_shiftRight (a b : $typeName) : (a >>> b).toNat = a.toNat >>> (b.toNat % $bits) := by simp [toNat]
|
||||
|
||||
open $typeName (toNat_and) in
|
||||
@[deprecated toNat_and (since := "2024-11-28")]
|
||||
protected theorem and_toNat (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := BitVec.toNat_and ..
|
||||
|
||||
end $typeName
|
||||
)
|
||||
|
||||
declare_bitwise_uint_theorems UInt8
|
||||
declare_bitwise_uint_theorems UInt16
|
||||
declare_bitwise_uint_theorems UInt32
|
||||
declare_bitwise_uint_theorems UInt64
|
||||
declare_bitwise_uint_theorems USize
|
||||
declare_bitwise_uint_theorems UInt8 8
|
||||
declare_bitwise_uint_theorems UInt16 16
|
||||
declare_bitwise_uint_theorems UInt32 32
|
||||
declare_bitwise_uint_theorems UInt64 64
|
||||
declare_bitwise_uint_theorems USize System.Platform.numBits
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Shreyas Srinivas, François G. Dorais, Kim Morrison
|
||||
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Range
|
||||
|
||||
/-!
|
||||
# Vectors
|
||||
@@ -70,6 +71,16 @@ instance [Inhabited α] : Inhabited (Vector α n) where
|
||||
instance : GetElem (Vector α n) Nat α fun _ i => i < n where
|
||||
getElem x i h := get x ⟨i, h⟩
|
||||
|
||||
/-- Check if there is an element which satisfies `a == ·`. -/
|
||||
def contains [BEq α] (v : Vector α n) (a : α) : Bool := v.toArray.contains a
|
||||
|
||||
/-- `a ∈ v` is a predicate which asserts that `a` is in the vector `v`. -/
|
||||
structure Mem (as : Vector α n) (a : α) : Prop where
|
||||
val : a ∈ as.toArray
|
||||
|
||||
instance : Membership α (Vector α n) where
|
||||
mem := Mem
|
||||
|
||||
/--
|
||||
Get an element of a vector using a `Nat` index. Returns the given default value if the index is out
|
||||
of bounds.
|
||||
@@ -254,3 +265,39 @@ no element of the index matches the given value.
|
||||
/-- Returns `true` when `v` is a prefix of the vector `w`. -/
|
||||
@[inline] def isPrefixOf [BEq α] (v : Vector α m) (w : Vector α n) : Bool :=
|
||||
v.toArray.isPrefixOf w.toArray
|
||||
|
||||
/-- Returns `true` with the monad if `p` returns `true` for any element of the vector. -/
|
||||
@[inline] def anyM [Monad m] (p : α → m Bool) (v : Vector α n) : m Bool :=
|
||||
v.toArray.anyM p
|
||||
|
||||
/-- Returns `true` with the monad if `p` returns `true` for all elements of the vector. -/
|
||||
@[inline] def allM [Monad m] (p : α → m Bool) (v : Vector α n) : m Bool :=
|
||||
v.toArray.allM p
|
||||
|
||||
/-- Returns `true` if `p` returns `true` for any element of the vector. -/
|
||||
@[inline] def any (v : Vector α n) (p : α → Bool) : Bool :=
|
||||
v.toArray.any p
|
||||
|
||||
/-- Returns `true` if `p` returns `true` for all elements of the vector. -/
|
||||
@[inline] def all (v : Vector α n) (p : α → Bool) : Bool :=
|
||||
v.toArray.all p
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
instance instLT [LT α] : LT (Vector α n) := ⟨fun v w => v.toArray < w.toArray⟩
|
||||
instance instLE [LT α] : LE (Vector α n) := ⟨fun v w => v.toArray ≤ w.toArray⟩
|
||||
|
||||
/--
|
||||
Lexicographic comparator for vectors.
|
||||
|
||||
`lex v w lt` is true if
|
||||
- `v` is pairwise equivalent via `==` to `w`, or
|
||||
- there is an index `i` such that `lt v[i] w[i]`, and for all `j < i`, `v[j] == w[j]`.
|
||||
-/
|
||||
def lex [BEq α] (v w : Vector α n) (lt : α → α → Bool := by exact (· < ·)) : Bool := Id.run do
|
||||
for h : i in [0 : n] do
|
||||
if lt v[i] w[i] then
|
||||
return true
|
||||
else if v[i] != w[i] then
|
||||
return false
|
||||
return false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
202
src/Init/Data/Vector/Lex.lean
Normal file
202
src/Init/Data/Vector/Lex.lean
Normal file
@@ -0,0 +1,202 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Vector.Basic
|
||||
import Init.Data.Vector.Lemmas
|
||||
import Init.Data.Array.Lex.Lemmas
|
||||
|
||||
namespace Vector
|
||||
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
@[simp] theorem lt_toArray [LT α] (l₁ l₂ : Vector α n) : l₁.toArray < l₂.toArray ↔ l₁ < l₂ := Iff.rfl
|
||||
@[simp] theorem le_toArray [LT α] (l₁ l₂ : Vector α n) : l₁.toArray ≤ l₂.toArray ↔ l₁ ≤ l₂ := Iff.rfl
|
||||
|
||||
@[simp] theorem lt_toList [LT α] (l₁ l₂ : Vector α n) : l₁.toList < l₂.toList ↔ l₁ < l₂ := Iff.rfl
|
||||
@[simp] theorem le_toList [LT α] (l₁ l₂ : Vector α n) : l₁.toList ≤ l₂.toList ↔ l₁ ≤ l₂ := Iff.rfl
|
||||
|
||||
@[simp] theorem mk_lt_mk [LT α] :
|
||||
Vector.mk (α := α) (n := n) data₁ size₁ < Vector.mk data₂ size₂ ↔ data₁ < data₂ := Iff.rfl
|
||||
|
||||
@[simp] theorem mk_le_mk [LT α] :
|
||||
Vector.mk (α := α) (n := n) data₁ size₁ ≤ Vector.mk data₂ size₂ ↔ data₁ ≤ data₂ := Iff.rfl
|
||||
|
||||
@[simp] theorem mk_lex_mk [BEq α] (lt : α → α → Bool) {l₁ l₂ : Array α} {n₁ : l₁.size = n} {n₂ : l₂.size = n} :
|
||||
(Vector.mk l₁ n₁).lex (Vector.mk l₂ n₂) lt = l₁.lex l₂ lt := by
|
||||
simp [Vector.lex, Array.lex, n₁, n₂]
|
||||
rfl
|
||||
|
||||
@[simp] theorem lex_toArray [BEq α] (lt : α → α → Bool) (l₁ l₂ : Vector α n) :
|
||||
l₁.toArray.lex l₂.toArray lt = l₁.lex l₂ lt := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem lex_toList [BEq α] (lt : α → α → Bool) (l₁ l₂ : Vector α n) :
|
||||
l₁.toList.lex l₂.toList lt = l₁.lex l₂ lt := by
|
||||
rcases l₁ with ⟨⟨l₁⟩, n₁⟩
|
||||
rcases l₂ with ⟨⟨l₂⟩, n₂⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem lex_empty
|
||||
[BEq α] {lt : α → α → Bool} (l₁ : Vector α 0) : l₁.lex #v[] lt = false := by
|
||||
cases l₁
|
||||
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]
|
||||
|
||||
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] (l : Vector α n) : ¬ l < l :=
|
||||
Array.lt_irrefl l.toArray
|
||||
|
||||
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] : Std.Irrefl (α := Vector α n) (· < ·) where
|
||||
irrefl := Vector.lt_irrefl
|
||||
|
||||
@[simp] theorem empty_le [LT α] (l : Vector α 0) : #v[] ≤ l := Array.empty_le l.toArray
|
||||
|
||||
@[simp] theorem le_empty [LT α] (l : Vector α 0) : l ≤ #v[] ↔ l = #v[] := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α → α → Prop)] (l : Vector α n) : l ≤ l :=
|
||||
Array.le_refl l.toArray
|
||||
|
||||
instance [LT α] [Std.Irrefl (· < · : α → α → Prop)] : Std.Refl (· ≤ · : Vector α n → Vector α n → Prop) where
|
||||
refl := Vector.le_refl
|
||||
|
||||
protected theorem lt_trans [LT α] [DecidableLT α]
|
||||
[i₁ : Trans (· < · : α → α → Prop) (· < ·) (· < ·)]
|
||||
{l₁ l₂ l₃ : Vector α n} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
|
||||
Array.lt_trans h₁ h₂
|
||||
|
||||
instance [LT α] [DecidableLT α]
|
||||
[Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : Vector α n → Vector α n → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := Vector.lt_trans h₁ h₂
|
||||
|
||||
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : Vector α n} (h₁ : l₁ ≤ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
|
||||
Array.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : Vector α n} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (Vector.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)] :
|
||||
Trans (· ≤ · : Vector α n → Vector α n → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans h₁ h₂ := Vector.le_trans h₁ h₂
|
||||
|
||||
protected theorem lt_asymm [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{l₁ l₂ : Vector α n} (h : l₁ < l₂) : ¬ l₂ < l₁ := Array.lt_asymm h
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Asymm (· < · : Vector α n → Vector α n → Prop) where
|
||||
asymm _ _ := Vector.lt_asymm
|
||||
|
||||
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] {l₁ l₂ : Vector α n} : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
Array.le_total
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : Vector α n → Vector α n → Prop) where
|
||||
total _ _ := Vector.le_total
|
||||
|
||||
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : Vector α n} : lex l₁ l₂ = true ↔ l₁ < l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : Vector α n} : lex l₁ l₂ = false ↔ l₂ ≤ l₁ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [Array.not_lt_iff_ge]
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLT (Vector α n) :=
|
||||
fun l₁ l₂ => decidable_of_iff (lex l₁ l₂ = true) lex_eq_true_iff_lt
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLE (Vector α n) :=
|
||||
fun l₁ l₂ => decidable_of_iff (lex l₂ l₁ = false) lex_eq_false_iff_ge
|
||||
|
||||
/--
|
||||
`l₁` is lexicographically less than `l₂` if either
|
||||
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.size`,
|
||||
and `l₁` is shorter than `l₂` or
|
||||
- there exists an index `i` such that
|
||||
- for all `j < i`, `l₁[j] == l₂[j]` and
|
||||
- `l₁[i] < l₂[i]`
|
||||
-/
|
||||
theorem lex_eq_true_iff_exists [BEq α] (lt : α → α → Bool) {l₁ l₂ : Vector α n} :
|
||||
lex l₁ l₂ lt = true ↔
|
||||
(∃ (i : Nat) (h : i < n), (∀ j, (hj : j < i) → l₁[j] == l₂[j]) ∧ lt l₁[i] l₂[i]) := by
|
||||
rcases l₁ with ⟨l₁, n₁⟩
|
||||
rcases l₂ with ⟨l₂, n₂⟩
|
||||
simp [Array.lex_eq_true_iff_exists, n₁, n₂]
|
||||
|
||||
/--
|
||||
`l₁` is *not* lexicographically less than `l₂`
|
||||
(which you might think of as "`l₂` is lexicographically greater than or equal to `l₁`"") if either
|
||||
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.length` or
|
||||
- there exists an index `i` such that
|
||||
- for all `j < i`, `l₁[j] == l₂[j]` and
|
||||
- `l₂[i] < l₁[i]`
|
||||
|
||||
This formulation requires that `==` and `lt` are compatible in the following senses:
|
||||
- `==` is symmetric
|
||||
(we unnecessarily further assume it is transitive, to make use of the existing typeclasses)
|
||||
- `lt` is irreflexive with respect to `==` (i.e. if `x == y` then `lt x y = false`
|
||||
- `lt` is asymmmetric (i.e. `lt x y = true → lt y x = false`)
|
||||
- `lt` is antisymmetric with respect to `==` (i.e. `lt x y = false → lt y x = false → x == y`)
|
||||
-/
|
||||
theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α → α → Bool)
|
||||
(lt_irrefl : ∀ x y, x == y → lt x y = false)
|
||||
(lt_asymm : ∀ x y, lt x y = true → lt y x = false)
|
||||
(lt_antisymm : ∀ x y, lt x y = false → lt y x = false → x == y)
|
||||
{l₁ l₂ : Vector α n} :
|
||||
lex l₁ l₂ lt = false ↔
|
||||
(l₂.isEqv l₁ (· == ·)) ∨
|
||||
(∃ (i : Nat) (h : i < n),(∀ j, (hj : j < i) → l₁[j] == l₂[j]) ∧ lt l₂[i] l₁[i]) := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, n₂⟩
|
||||
simp_all [Array.lex_eq_false_iff_exists, n₂]
|
||||
|
||||
theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : Vector α n} :
|
||||
l₁ < l₂ ↔
|
||||
(∃ (i : Nat) (h : i < n), (∀ j, (hj : j < i) → l₁[j] = l₂[j]) ∧ l₁[i] < l₂[i]) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all [Array.lt_iff_exists]
|
||||
|
||||
theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {l₁ l₂ : Vector α n} :
|
||||
l₁ ≤ l₂ ↔
|
||||
(l₁ = l₂) ∨
|
||||
(∃ (i : Nat) (h : i < n), (∀ j, (hj : j < i) → l₁[j] = l₂[j]) ∧ l₁[i] < l₂[i]) := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, n₂⟩
|
||||
simp [Array.le_iff_exists, ← n₂]
|
||||
|
||||
end Vector
|
||||
@@ -118,12 +118,16 @@ instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (v
|
||||
GetElem? coll idx elem valid where
|
||||
getElem? xs i := decidableGetElem? xs i
|
||||
|
||||
theorem getElem_congr_coll [GetElem coll idx elem valid] {c d : coll} {i : idx} {h : valid c i}
|
||||
(h' : c = d) : c[i] = d[i]'(h' ▸ h) := by
|
||||
cases h'; rfl
|
||||
theorem getElem_congr [GetElem coll idx elem valid] {c d : coll} (h : c = d)
|
||||
{i j : idx} (h' : i = j) (w : valid c i) : c[i] = d[j]'(h' ▸ h ▸ w) := by
|
||||
cases h; cases h'; rfl
|
||||
|
||||
theorem getElem_congr [GetElem coll idx elem valid] {c : coll} {i j : idx} {h : valid c i}
|
||||
(h' : i = j) : c[i] = c[j]'(h' ▸ h) := by
|
||||
theorem getElem_congr_coll [GetElem coll idx elem valid] {c d : coll} {i : idx} {w : valid c i}
|
||||
(h : c = d) : c[i] = d[i]'(h ▸ w) := by
|
||||
cases h; rfl
|
||||
|
||||
theorem getElem_congr_idx [GetElem coll idx elem valid] {c : coll} {i j : idx} {w : valid c i}
|
||||
(h' : i = j) : c[i] = c[j]'(h' ▸ w) := by
|
||||
cases h'; rfl
|
||||
|
||||
class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||
@@ -172,11 +176,14 @@ theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem d
|
||||
simp only [getElem?_def] at h ⊢
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem isNone_getElem? [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) [Decidable (dom c i)] : c[i]?.isNone = ¬dom c i := by
|
||||
@[simp] theorem getElem?_eq_none [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) [Decidable (dom c i)] : c[i]? = none ↔ ¬dom c i := by
|
||||
simp only [getElem?_def]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated getElem?_eq_none (since := "2024-12-11")]
|
||||
abbrev isNone_getElem? := @getElem?_eq_none
|
||||
|
||||
@[simp] theorem isSome_getElem? [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) [Decidable (dom c i)] : c[i]?.isSome = dom c i := by
|
||||
simp only [getElem?_def]
|
||||
@@ -216,13 +223,9 @@ instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
@[simp] theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a := by
|
||||
rfl
|
||||
|
||||
@[deprecated getElem_cons_zero (since := "2024-06-12")] abbrev cons_getElem_zero := @getElem_cons_zero
|
||||
|
||||
@[simp] theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) := by
|
||||
rfl
|
||||
|
||||
@[deprecated getElem_cons_succ (since := "2024-06-12")] abbrev cons_getElem_succ := @getElem_cons_succ
|
||||
|
||||
@[simp] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
@@ -231,7 +234,7 @@ theorem getElem_cons_drop_succ_eq_drop {as : List α} {i : Nat} (h : i < as.leng
|
||||
as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
| _::_, 0 => rfl
|
||||
| _::_, i+1 => getElem_cons_drop_succ_eq_drop (i := i) _
|
||||
| _::_, i+1 => getElem_cons_drop_succ_eq_drop (i := i) (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[deprecated getElem_cons_drop_succ_eq_drop (since := "2024-11-05")]
|
||||
abbrev get_drop_eq_drop := @getElem_cons_drop_succ_eq_drop
|
||||
@@ -243,6 +246,12 @@ namespace Array
|
||||
instance : GetElem (Array α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get i h
|
||||
|
||||
@[simp] theorem get_eq_getElem (a : Array α) (i : Nat) (h) : a.get i h = a[i] := rfl
|
||||
|
||||
@[simp] theorem get!_eq_getElem! [Inhabited α] (a : Array α) (i : Nat) : a.get! i = a[i]! := by
|
||||
simp only [get!, getD, get_eq_getElem, getElem!_def]
|
||||
split <;> simp_all [getElem?_pos, getElem?_neg]
|
||||
|
||||
end Array
|
||||
|
||||
namespace Lean.Syntax
|
||||
|
||||
@@ -679,6 +679,7 @@ private partial def decodeBinLitAux (s : String) (i : String.Pos) (val : Nat) :
|
||||
let c := s.get i
|
||||
if c == '0' then decodeBinLitAux s (s.next i) (2*val)
|
||||
else if c == '1' then decodeBinLitAux s (s.next i) (2*val + 1)
|
||||
else if c == '_' then decodeBinLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
private partial def decodeOctalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
@@ -686,6 +687,7 @@ private partial def decodeOctalLitAux (s : String) (i : String.Pos) (val : Nat)
|
||||
else
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '7' then decodeOctalLitAux s (s.next i) (8*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeOctalLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
private def decodeHexDigit (s : String) (i : String.Pos) : Option (Nat × String.Pos) :=
|
||||
@@ -700,13 +702,16 @@ private partial def decodeHexLitAux (s : String) (i : String.Pos) (val : Nat) :
|
||||
if s.atEnd i then some val
|
||||
else match decodeHexDigit s i with
|
||||
| some (d, i) => decodeHexLitAux s i (16*val + d)
|
||||
| none => none
|
||||
| none =>
|
||||
if s.get i == '_' then decodeHexLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
private partial def decodeDecimalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||
if s.atEnd i then some val
|
||||
else
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then decodeDecimalLitAux s (s.next i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then decodeDecimalLitAux s (s.next i) val
|
||||
else none
|
||||
|
||||
def decodeNatLitVal? (s : String) : Option Nat :=
|
||||
@@ -773,6 +778,8 @@ where
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decodeAfterExp (s.next i) val e sign (10*exp + c.toNat - '0'.toNat)
|
||||
else if c == '_' then
|
||||
decodeAfterExp (s.next i) val e sign exp
|
||||
else
|
||||
none
|
||||
|
||||
@@ -793,6 +800,8 @@ where
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decodeAfterDot (s.next i) (10*val + c.toNat - '0'.toNat) (e+1)
|
||||
else if c == '_' then
|
||||
decodeAfterDot (s.next i) val e
|
||||
else if c == 'e' || c == 'E' then
|
||||
decodeExp (s.next i) val e
|
||||
else
|
||||
@@ -805,6 +814,8 @@ where
|
||||
let c := s.get i
|
||||
if '0' ≤ c && c ≤ '9' then
|
||||
decode (s.next i) (10*val + c.toNat - '0'.toNat)
|
||||
else if c == '_' then
|
||||
decode (s.next i) val
|
||||
else if c == '.' then
|
||||
decodeAfterDot (s.next i) val 0
|
||||
else if c == 'e' || c == 'E' then
|
||||
|
||||
@@ -250,6 +250,13 @@ def neutralConfig : Simp.Config := {
|
||||
zetaDelta := false
|
||||
}
|
||||
|
||||
structure NormCastConfig extends Simp.Config where
|
||||
zeta := false
|
||||
beta := false
|
||||
eta := false
|
||||
proj := false
|
||||
iota := false
|
||||
|
||||
end Simp
|
||||
|
||||
/-- Configuration for which occurrences that match an expression should be rewritten. -/
|
||||
|
||||
@@ -168,11 +168,6 @@ end Lean
|
||||
| `($(_) $c $t $e) => `(if $c then $t else $e)
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander sorryAx] def unexpandSorryAx : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $_) => `(sorry)
|
||||
| `($(_) $_ $_) => `(sorry)
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Eq.ndrec] def unexpandEqNDRec : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $m $h) => `($h ▸ $m)
|
||||
| _ => throw ()
|
||||
|
||||
@@ -645,23 +645,22 @@ set_option linter.unusedVariables.funArgs false in
|
||||
@[reducible] def namedPattern {α : Sort u} (x a : α) (h : Eq x a) : α := a
|
||||
|
||||
/--
|
||||
Auxiliary axiom used to implement `sorry`.
|
||||
Auxiliary axiom used to implement the `sorry` term and tactic.
|
||||
|
||||
The `sorry` term/tactic expands to `sorryAx _ (synthetic := false)`. This is a
|
||||
proof of anything, which is intended for stubbing out incomplete parts of a
|
||||
proof while still having a syntactically correct proof skeleton. Lean will give
|
||||
a warning whenever a proof uses `sorry`, so you aren't likely to miss it, but
|
||||
you can double check if a theorem depends on `sorry` by using
|
||||
`#print axioms my_thm` and looking for `sorryAx` in the axiom list.
|
||||
The `sorry` term/tactic expands to `sorryAx _ (synthetic := false)`.
|
||||
It is intended for stubbing-out incomplete parts of a value or proof while still having a syntactically correct skeleton.
|
||||
Lean will give a warning whenever a declaration uses `sorry`, so you aren't likely to miss it,
|
||||
but you can check if a declaration depends on `sorry` either directly or indirectly by looking for `sorryAx` in the output
|
||||
of the `#print axioms my_thm` command.
|
||||
|
||||
The `synthetic` flag is false when written explicitly by the user, but it is
|
||||
The `synthetic` flag is false when a `sorry` is written explicitly by the user, but it is
|
||||
set to `true` when a tactic fails to prove a goal, or if there is a type error
|
||||
in the expression. A synthetic `sorry` acts like a regular one, except that it
|
||||
suppresses follow-up errors in order to prevent one error from causing a cascade
|
||||
suppresses follow-up errors in order to prevent an error from causing a cascade
|
||||
of other errors because the desired term was not constructed.
|
||||
-/
|
||||
@[extern "lean_sorry", never_extract]
|
||||
axiom sorryAx (α : Sort u) (synthetic := false) : α
|
||||
axiom sorryAx (α : Sort u) (synthetic : Bool) : α
|
||||
|
||||
theorem eq_false_of_ne_true : {b : Bool} → Not (Eq b true) → Eq b false
|
||||
| true, h => False.elim (h rfl)
|
||||
@@ -860,8 +859,8 @@ abbrev DecidablePred {α : Sort u} (r : α → Prop) :=
|
||||
(a : α) → Decidable (r a)
|
||||
|
||||
/-- A decidable relation. See `Decidable`. -/
|
||||
abbrev DecidableRel {α : Sort u} (r : α → α → Prop) :=
|
||||
(a b : α) → Decidable (r a b)
|
||||
abbrev DecidableRel {α : Sort u} {β : Sort v} (r : α → β → Prop) :=
|
||||
(a : α) → (b : β) → Decidable (r a b)
|
||||
|
||||
/--
|
||||
Asserts that `α` has decidable equality, that is, `a = b` is decidable
|
||||
@@ -1127,6 +1126,11 @@ class LT (α : Type u) where
|
||||
/-- `a > b` is an abbreviation for `b < a`. -/
|
||||
@[reducible] def GT.gt {α : Type u} [LT α] (a b : α) : Prop := LT.lt b a
|
||||
|
||||
/-- Abbreviation for `DecidableRel (· < · : α → α → Prop)`. -/
|
||||
abbrev DecidableLT (α : Type u) [LT α] := DecidableRel (LT.lt : α → α → Prop)
|
||||
/-- Abbreviation for `DecidableRel (· ≤ · : α → α → Prop)`. -/
|
||||
abbrev DecidableLE (α : Type u) [LE α] := DecidableRel (LE.le : α → α → Prop)
|
||||
|
||||
/-- `Max α` is the typeclass which supports the operation `max x y` where `x y : α`.-/
|
||||
class Max (α : Type u) where
|
||||
/-- The maximum operation: `max x y`. -/
|
||||
@@ -2550,7 +2554,7 @@ When we reimplement the specializer, we may consider copying `inst` if it also
|
||||
occurs outside binders or if it is an instance.
|
||||
-/
|
||||
@[never_extract, extern "lean_panic_fn"]
|
||||
def panicCore {α : Type u} [Inhabited α] (msg : String) : α := default
|
||||
def panicCore {α : Sort u} [Inhabited α] (msg : String) : α := default
|
||||
|
||||
/--
|
||||
`(panic "msg" : α)` has a built-in implementation which prints `msg` to
|
||||
@@ -2564,7 +2568,7 @@ Because this is a pure function with side effects, it is marked as
|
||||
elimination and other optimizations that assume that the expression is pure.
|
||||
-/
|
||||
@[noinline, never_extract]
|
||||
def panic {α : Type u} [Inhabited α] (msg : String) : α :=
|
||||
def panic {α : Sort u} [Inhabited α] (msg : String) : α :=
|
||||
panicCore msg
|
||||
|
||||
-- TODO: this be applied directly to `Inhabited`'s definition when we remove the above workaround
|
||||
@@ -3932,6 +3936,13 @@ def getId : Syntax → Name
|
||||
| ident _ _ val _ => val
|
||||
| _ => Name.anonymous
|
||||
|
||||
/-- Retrieve the immediate info from the Syntax node. -/
|
||||
def getInfo? : Syntax → Option SourceInfo
|
||||
| atom info .. => some info
|
||||
| ident info .. => some info
|
||||
| node info .. => some info
|
||||
| missing => none
|
||||
|
||||
/-- Retrieve the left-most node or leaf's info in the Syntax tree. -/
|
||||
partial def getHeadInfo? : Syntax → Option SourceInfo
|
||||
| atom info _ => some info
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user