mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-13 07:34:08 +00:00
Compare commits
72 Commits
array_perm
...
array_set
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8df17317b5 | ||
|
|
677d4f744d | ||
|
|
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: |
|
sparse-checkout: |
|
||||||
src/Lean
|
src/Lean
|
||||||
src/Std
|
src/Std
|
||||||
|
src/lake/Lake
|
||||||
- name: Check Prelude
|
- name: Check Prelude
|
||||||
run: |
|
run: |
|
||||||
failed_files=""
|
failed_files=""
|
||||||
@@ -21,7 +22,7 @@ jobs:
|
|||||||
if ! grep -q "^prelude$" "$file"; then
|
if ! grep -q "^prelude$" "$file"; then
|
||||||
failed_files="$failed_files$file\n"
|
failed_files="$failed_files$file\n"
|
||||||
fi
|
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
|
if [ -n "$failed_files" ]; then
|
||||||
echo -e "The following files should use 'prelude':\n$failed_files"
|
echo -e "The following files should use 'prelude':\n$failed_files"
|
||||||
exit 1
|
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.
|
- name: Download artifact from the previous workflow.
|
||||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||||
id: download-artifact
|
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:
|
with:
|
||||||
run_id: ${{ github.event.workflow_run.id }}
|
run_id: ${{ github.event.workflow_run.id }}
|
||||||
path: artifacts
|
path: artifacts
|
||||||
@@ -111,7 +111,7 @@ jobs:
|
|||||||
|
|
||||||
- name: 'Setup jq'
|
- name: 'Setup jq'
|
||||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
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'
|
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
|
||||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD
|
- name: Check merge-base and nightly-testing-YYYY-MM-DD
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# Listed persons will automatically be asked by GitHub to review a PR touching these paths.
|
# 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.
|
# 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
|
/RELEASES.md @kim-em
|
||||||
/src/kernel/ @leodemoura
|
/src/kernel/ @leodemoura
|
||||||
/src/lake/ @tydeu
|
/src/lake/ @tydeu
|
||||||
@@ -14,9 +14,7 @@
|
|||||||
/src/Lean/Elab/Tactic/ @kim-em
|
/src/Lean/Elab/Tactic/ @kim-em
|
||||||
/src/Lean/Language/ @Kha
|
/src/Lean/Language/ @Kha
|
||||||
/src/Lean/Meta/Tactic/ @leodemoura
|
/src/Lean/Meta/Tactic/ @leodemoura
|
||||||
/src/Lean/Parser/ @Kha
|
/src/Lean/PrettyPrinter/ @kmill
|
||||||
/src/Lean/PrettyPrinter/ @Kha
|
|
||||||
/src/Lean/PrettyPrinter/Delaborator/ @kmill
|
|
||||||
/src/Lean/Server/ @mhuisi
|
/src/Lean/Server/ @mhuisi
|
||||||
/src/Lean/Widget/ @Vtec234
|
/src/Lean/Widget/ @Vtec234
|
||||||
/src/Init/Data/ @kim-em
|
/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
|
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status
|
||||||
of each version.
|
of each version.
|
||||||
|
|
||||||
v4.15.0
|
v4.16.0
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Development in progress.
|
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
|
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
|
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
|
* [#4768](https://github.com/leanprover/lean4/pull/4768) fixes a parse error when `..` appears with a `.` on the next line
|
||||||
|
|
||||||
* Metaprogramming
|
* 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)
|
* [#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
|
* [#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`.
|
* [#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
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source ../../tests/common.sh
|
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
|
numeral : numeral10 | numeral2 | numeral8 | numeral16
|
||||||
numeral10 : [0-9]+
|
numeral10 : [0-9]+ ("_"+ [0-9]+)*
|
||||||
numeral2 : "0" [bB] [0-1]+
|
numeral2 : "0" [bB] ("_"* [0-1]+)+
|
||||||
numeral8 : "0" [oO] [0-7]+
|
numeral8 : "0" [oO] ("_"* [0-7]+)+
|
||||||
numeral16 : "0" [xX] hex_char+
|
numeral16 : "0" [xX] ("_"* hex_char+)+
|
||||||
```
|
```
|
||||||
|
|
||||||
Floating point literals are also possible with optional exponent:
|
Floating point literals are also possible with optional exponent:
|
||||||
|
|
||||||
```
|
```
|
||||||
float : [0-9]+ "." [0-9]+ [[eE[+-][0-9]+]
|
float : numeral10 "." numeral10? [eE[+-]numeral10]
|
||||||
```
|
```
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
@@ -147,6 +147,7 @@ constant w : Int := 55
|
|||||||
constant x : Nat := 26085
|
constant x : Nat := 26085
|
||||||
constant y : Nat := 0x65E5
|
constant y : Nat := 0x65E5
|
||||||
constant z : Float := 2.548123e-05
|
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:
|
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
|
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:
|
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
|
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`.
|
`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
|
Now it's time to move on to [StateM Monad](states.lean.md) which is like a `ReaderM` that is
|
||||||
also updatable.
|
also updatable.
|
||||||
-/
|
-/
|
||||||
|
|||||||
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)
|
include(ExternalProject)
|
||||||
project(LEAN CXX C)
|
project(LEAN CXX C)
|
||||||
set(LEAN_VERSION_MAJOR 4)
|
set(LEAN_VERSION_MAJOR 4)
|
||||||
set(LEAN_VERSION_MINOR 15)
|
set(LEAN_VERSION_MINOR 16)
|
||||||
set(LEAN_VERSION_PATCH 0)
|
set(LEAN_VERSION_PATCH 0)
|
||||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
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'")
|
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:
|
# 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.
|
# > 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")
|
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_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}")
|
||||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}")
|
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}")
|
||||||
endif()
|
endif()
|
||||||
@@ -157,11 +157,11 @@ if ((${MULTI_THREAD} MATCHES "ON") AND (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# We want explicit stack probes in huge Lean stack frames for robust stack overflow detection
|
# 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.
|
# This makes signed integer overflow guaranteed to match 2's complement.
|
||||||
string(APPEND CMAKE_CXX_FLAGS " -fwrapv")
|
string(APPEND CMAKE_CXX_FLAGS " -fwrapv")
|
||||||
string(APPEND LEANC_EXTRA_FLAGS " -fwrapv")
|
string(APPEND LEANC_EXTRA_CC_FLAGS " -fwrapv")
|
||||||
|
|
||||||
if(NOT MULTI_THREAD)
|
if(NOT MULTI_THREAD)
|
||||||
message(STATUS "Disabled multi-thread support, it will not be safe to run multiple threads in parallel")
|
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")
|
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
|
||||||
endif()
|
endif()
|
||||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
|
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 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 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")
|
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")
|
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
|
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")
|
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")
|
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()
|
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")
|
string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic")
|
||||||
# hide all other symbols
|
# hide all other symbols
|
||||||
string(APPEND CMAKE_CXX_FLAGS " -fvisibility=hidden -fvisibility-inlines-hidden")
|
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()
|
endif()
|
||||||
|
|
||||||
# On Windows, add bcrypt for random number generation
|
# 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(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||||
string(APPEND LEANC_OPTS " ${CMAKE_CXX_FLAGS_${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)
|
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()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(initialize)
|
add_subdirectory(initialize)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import Init.Data.Fin
|
|||||||
import Init.Data.UInt
|
import Init.Data.UInt
|
||||||
import Init.Data.SInt
|
import Init.Data.SInt
|
||||||
import Init.Data.Float
|
import Init.Data.Float
|
||||||
|
import Init.Data.Float32
|
||||||
import Init.Data.Option
|
import Init.Data.Option
|
||||||
import Init.Data.Ord
|
import Init.Data.Ord
|
||||||
import Init.Data.Random
|
import Init.Data.Random
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ import Init.Data.Array.Set
|
|||||||
import Init.Data.Array.Monadic
|
import Init.Data.Array.Monadic
|
||||||
import Init.Data.Array.FinRange
|
import Init.Data.Array.FinRange
|
||||||
import Init.Data.Array.Perm
|
import Init.Data.Array.Perm
|
||||||
|
import Init.Data.Array.Find
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ theorem getElem?_attach {xs : Array α} {i : Nat} :
|
|||||||
theorem getElem_attachWith {xs : Array α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
theorem getElem_attachWith {xs : Array α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||||
{i : Nat} (h : i < (xs.attachWith P H).size) :
|
{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))⟩ :=
|
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||||
getElem_pmap ..
|
getElem_pmap _ _ h
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
|
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.Repr
|
||||||
import Init.Data.ToString.Basic
|
import Init.Data.ToString.Basic
|
||||||
import Init.GetElem
|
import Init.GetElem
|
||||||
import Init.Data.List.ToArray
|
import Init.Data.List.ToArrayImpl
|
||||||
import Init.Data.Array.Set
|
import Init.Data.Array.Set
|
||||||
|
|
||||||
universe u v w
|
universe u v w
|
||||||
@@ -85,6 +85,8 @@ theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
|
|||||||
|
|
||||||
@[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} (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`. -/
|
/-- `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
|
-- 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.
|
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
||||||
@@ -97,6 +99,9 @@ instance : Membership α (Array α) where
|
|||||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
⟨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
|
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] ∈ l := by
|
||||||
rw [Array.mem_def, ← getElem_toList]
|
rw [Array.mem_def, ← getElem_toList]
|
||||||
apply List.getElem_mem
|
apply List.getElem_mem
|
||||||
@@ -242,7 +247,7 @@ def singleton (v : α) : Array α :=
|
|||||||
mkArray 1 v
|
mkArray 1 v
|
||||||
|
|
||||||
def back! [Inhabited α] (a : Array α) : α :=
|
def back! [Inhabited α] (a : Array α) : α :=
|
||||||
a.get! (a.size - 1)
|
a[a.size - 1]!
|
||||||
|
|
||||||
@[deprecated back! (since := "2024-10-31")] abbrev back := @back!
|
@[deprecated back! (since := "2024-10-31")] abbrev back := @back!
|
||||||
|
|
||||||
@@ -474,6 +479,10 @@ def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f
|
|||||||
| _ => pure ⟨⟩
|
| _ => pure ⟨⟩
|
||||||
return none
|
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]
|
@[inline]
|
||||||
def findM? {α : Type} {m : Type → Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) := do
|
def findM? {α : Type} {m : Type → Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) := do
|
||||||
for a in as do
|
for a in as do
|
||||||
@@ -585,8 +594,12 @@ def zipWithIndex (arr : Array α) : Array (α × Nat) :=
|
|||||||
arr.mapIdx fun i a => (a, i)
|
arr.mapIdx fun i a => (a, i)
|
||||||
|
|
||||||
@[inline]
|
@[inline]
|
||||||
def find? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
def find? {α : Type u} (p : α → Bool) (as : Array α) : Option α :=
|
||||||
Id.run <| as.findM? p
|
Id.run do
|
||||||
|
for a in as do
|
||||||
|
if p a then
|
||||||
|
return a
|
||||||
|
return none
|
||||||
|
|
||||||
@[inline]
|
@[inline]
|
||||||
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||||
@@ -650,7 +663,7 @@ def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool
|
|||||||
Id.run <| as.allM p start stop
|
Id.run <| as.allM p start stop
|
||||||
|
|
||||||
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
||||||
as.any (· == a)
|
as.any (a == ·)
|
||||||
|
|
||||||
def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
||||||
as.contains a
|
as.contains a
|
||||||
|
|||||||
@@ -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
|
(L.findSome? fun l => l[0]?).isSome := by
|
||||||
cases L using array_array_induction
|
cases L using array_array_induction
|
||||||
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
|
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,
|
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
|
||||||
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
|
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
|
||||||
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ namespace Array
|
|||||||
theorem exists_of_uset (self : Array α) (i d h) :
|
theorem exists_of_uset (self : Array α) (i d h) :
|
||||||
∃ l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
∃ l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
||||||
(self.uset i d h).toList = l₁ ++ d :: l₂ := by
|
(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 _
|
List.exists_of_set _
|
||||||
|
|
||||||
end Array
|
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) :=
|
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||||
Bool.eq_iff_iff.2 ⟨BEq.symm, BEq.symm⟩
|
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 :=
|
theorem BEq.symm_false [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = false → (b == a) = false :=
|
||||||
BEq.comm (α := α) ▸ id
|
BEq.comm (α := α) ▸ id
|
||||||
|
|
||||||
|
|||||||
@@ -351,17 +351,17 @@ end relations
|
|||||||
section cast
|
section cast
|
||||||
|
|
||||||
/-- `cast eq x` embeds `x` into an equal `BitVec` type. -/
|
/-- `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) :
|
@[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
|
subst h; rfl
|
||||||
|
|
||||||
@[simp] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
|
@[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
|
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
|
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 =>
|
case true =>
|
||||||
apply hmin
|
apply hmin
|
||||||
apply eq_of_getMsbD_eq
|
apply eq_of_getMsbD_eq
|
||||||
rintro ⟨i, hi⟩
|
intro i hi
|
||||||
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
|
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
|
||||||
cases i
|
cases i
|
||||||
case zero => exact hmsb
|
case zero => exact hmsb
|
||||||
@@ -470,7 +470,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
|
|||||||
case false =>
|
case false =>
|
||||||
apply hzero
|
apply hzero
|
||||||
apply eq_of_getMsbD_eq
|
apply eq_of_getMsbD_eq
|
||||||
rintro ⟨i, hi⟩
|
intro i hi
|
||||||
simp only [getMsbD_zero]
|
simp only [getMsbD_zero]
|
||||||
cases i
|
cases i
|
||||||
case zero => exact hmsb
|
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 + 1)) =
|
||||||
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
|
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
|
||||||
rw [add_eq_or_of_and_eq_zero]
|
rw [add_eq_or_of_and_eq_zero]
|
||||||
· ext k
|
· ext k h
|
||||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
simp only [getLsbD_setWidth, h, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||||
by_cases hik : i = k
|
by_cases hik : i = k
|
||||||
· subst hik
|
· subst hik
|
||||||
simp
|
simp [h]
|
||||||
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
|
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
|
||||||
by_cases hik' : k < (i + 1)
|
by_cases hik' : k < (i + 1)
|
||||||
· have hik'' : k < i := by omega
|
· 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`
|
-- We choose `eq_of_getLsbD_eq` as the `@[ext]` theorem for `BitVec`
|
||||||
-- somewhat arbitrarily over `eq_of_getMsbD_eq`.
|
-- somewhat arbitrarily over `eq_of_getMsbD_eq`.
|
||||||
@[ext] theorem eq_of_getLsbD_eq {x y : BitVec w}
|
@[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 eq_of_toNat_eq
|
||||||
apply Nat.eq_of_testBit_eq
|
apply Nat.eq_of_testBit_eq
|
||||||
intro i
|
intro i
|
||||||
if i_lt : i < w then
|
if i_lt : i < w then
|
||||||
exact pred ⟨i, i_lt⟩
|
exact pred i i_lt
|
||||||
else
|
else
|
||||||
have p : i ≥ w := Nat.le_of_not_gt i_lt
|
have p : i ≥ w := Nat.le_of_not_gt i_lt
|
||||||
simp [testBit_toNat, getLsbD_ge _ _ p]
|
simp [testBit_toNat, getLsbD_ge _ _ p]
|
||||||
|
|
||||||
theorem eq_of_getMsbD_eq {x y : BitVec w}
|
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
|
simp only [getMsbD] at pred
|
||||||
apply eq_of_getLsbD_eq
|
apply eq_of_getLsbD_eq
|
||||||
intro ⟨i, i_lt⟩
|
intro i i_lt
|
||||||
if w_zero : w = 0 then
|
if w_zero : w = 0 then
|
||||||
simp [w_zero]
|
simp [w_zero]
|
||||||
else
|
else
|
||||||
@@ -199,7 +199,7 @@ theorem eq_of_getMsbD_eq {x y : BitVec w}
|
|||||||
simp only [Nat.sub_sub]
|
simp only [Nat.sub_sub]
|
||||||
apply Nat.sub_lt w_pos
|
apply Nat.sub_lt w_pos
|
||||||
simp [Nat.succ_add]
|
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
|
simpa [q_lt, Nat.sub_sub_self, r] using q
|
||||||
|
|
||||||
-- This cannot be a `@[simp]` lemma, as it would be tried at every term.
|
-- 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
|
@[simp] theorem toNat_ofBool (b : Bool) : (ofBool b).toNat = b.toNat := by
|
||||||
cases b <;> rfl
|
cases b <;> rfl
|
||||||
|
|
||||||
@[simp] theorem msb_ofBool (b : Bool) : (ofBool b).msb = b := by
|
@[simp] theorem toInt_ofBool (b : Bool) : (ofBool b).toInt = -b.toInt := by
|
||||||
cases b <;> simp [BitVec.msb, getMsbD, getLsbD]
|
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
|
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']
|
rcases (Nat.mod_two_eq_zero_or_one n) with h | h <;> simp [h, BitVec.ofNat, Fin.ofNat']
|
||||||
@@ -366,6 +369,12 @@ theorem getElem_ofBool {b : Bool} {i : Nat} : (ofBool b)[0] = b := by
|
|||||||
· simp only [ofBool]
|
· simp only [ofBool]
|
||||||
by_cases hi : i = 0 <;> simp [hi] <;> omega
|
by_cases hi : i = 0 <;> simp [hi] <;> omega
|
||||||
|
|
||||||
|
@[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 -/
|
/-! ### msb -/
|
||||||
|
|
||||||
@[simp] theorem msb_zero : (0#w).msb = false := by simp [BitVec.msb, getMsbD]
|
@[simp] theorem msb_zero : (0#w).msb = false := by simp [BitVec.msb, getMsbD]
|
||||||
@@ -410,21 +419,21 @@ theorem toNat_ge_of_msb_true {x : BitVec n} (p : BitVec.msb x = true) : x.toNat
|
|||||||
|
|
||||||
/-! ### cast -/
|
/-! ### 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) :
|
@[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
|
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
|
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
|
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
|
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]
|
simp [BitVec.msb]
|
||||||
|
|
||||||
/-! ### toInt/ofInt -/
|
/-! ### toInt/ofInt -/
|
||||||
@@ -498,6 +507,9 @@ theorem toInt_ofNat {n : Nat} (x : Nat) :
|
|||||||
@[simp] theorem ofInt_ofNat (w n : Nat) :
|
@[simp] theorem ofInt_ofNat (w n : Nat) :
|
||||||
BitVec.ofInt w (no_index (OfNat.ofNat n)) = BitVec.ofNat w (OfNat.ofNat n) := rfl
|
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} :
|
theorem toInt_neg_iff {w : Nat} {x : BitVec w} :
|
||||||
BitVec.toInt x < 0 ↔ 2 ^ w ≤ 2 * x.toNat := by
|
BitVec.toInt x < 0 ↔ 2 ^ w ≤ 2 * x.toNat := by
|
||||||
simp [toInt_eq_toNat_cond]; omega
|
simp [toInt_eq_toNat_cond]; omega
|
||||||
@@ -569,6 +581,10 @@ theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
|
|||||||
(x.setWidth v).toInt = Int.bmod x.toNat (2^v) := by
|
(x.setWidth v).toInt = Int.bmod x.toNat (2^v) := by
|
||||||
simp [toInt_eq_toNat_bmod, toNat_setWidth, Int.emod_bmod]
|
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
|
theorem setWidth'_eq {x : BitVec w} (h : w ≤ v) : x.setWidth' h = x.setWidth v := by
|
||||||
apply eq_of_toNat_eq
|
apply eq_of_toNat_eq
|
||||||
rw [toNat_setWidth, toNat_setWidth']
|
rw [toNat_setWidth, toNat_setWidth']
|
||||||
@@ -645,6 +661,20 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
|||||||
getLsbD (setWidth m x) i = (decide (i < m) && getLsbD x i) := by
|
getLsbD (setWidth m x) i = (decide (i < m) && getLsbD x i) := by
|
||||||
simp [getLsbD, toNat_setWidth, Nat.testBit_mod_two_pow]
|
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) :
|
@[simp] theorem getMsbD_setWidth_add {x : BitVec w} (h : k ≤ i) :
|
||||||
(x.setWidth (w + k)).getMsbD i = x.getMsbD (i - k) := by
|
(x.setWidth (w + k)).getMsbD i = x.getMsbD (i - k) := by
|
||||||
by_cases h : w = 0
|
by_cases h : w = 0
|
||||||
@@ -658,7 +688,7 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
|||||||
<;> omega
|
<;> omega
|
||||||
|
|
||||||
@[simp] theorem cast_setWidth (h : v = v') (x : BitVec w) :
|
@[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
|
subst h
|
||||||
ext
|
ext
|
||||||
simp
|
simp
|
||||||
@@ -671,7 +701,7 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
|||||||
revert p
|
revert p
|
||||||
cases getLsbD x i <;> simp; omega
|
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
|
apply eq_of_getLsbD_eq
|
||||||
simp
|
simp
|
||||||
|
|
||||||
@@ -689,14 +719,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. -/
|
/-- zero extending a bitvector to width 1 equals the boolean of the lsb. -/
|
||||||
theorem setWidth_one_eq_ofBool_getLsb_zero (x : BitVec w) :
|
theorem setWidth_one_eq_ofBool_getLsb_zero (x : BitVec w) :
|
||||||
x.setWidth 1 = BitVec.ofBool (x.getLsbD 0) := by
|
x.setWidth 1 = BitVec.ofBool (x.getLsbD 0) := by
|
||||||
ext i
|
ext i h
|
||||||
simp [getLsbD_setWidth, Fin.fin_one_eq_zero i]
|
simp at h
|
||||||
|
simp [getLsbD_setWidth, h]
|
||||||
|
|
||||||
/-- Zero extending `1#v` to `1#w` equals `1#w` when `v > 0`. -/
|
/-- 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) :
|
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
|
(BitVec.ofNat v 1).setWidth w = BitVec.ofNat w 1 := by
|
||||||
ext ⟨i, hilt⟩
|
ext i h
|
||||||
simp only [getLsbD_setWidth, hilt, decide_true, getLsbD_ofNat, Bool.true_and,
|
simp only [getLsbD_setWidth, h, decide_true, getLsbD_ofNat, Bool.true_and,
|
||||||
Bool.and_iff_right_iff_imp, decide_eq_true_eq]
|
Bool.and_iff_right_iff_imp, decide_eq_true_eq]
|
||||||
intros hi₁
|
intros hi₁
|
||||||
have hv := Nat.testBit_one_eq_true_iff_self_eq_zero.mp hi₁
|
have hv := Nat.testBit_one_eq_true_iff_self_eq_zero.mp hi₁
|
||||||
@@ -723,8 +754,7 @@ protected theorem extractLsb_ofFin {n} (x : Fin (2^n)) (hi lo : Nat) :
|
|||||||
@[simp]
|
@[simp]
|
||||||
protected theorem extractLsb_ofNat (x n : Nat) (hi lo : Nat) :
|
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
|
extractLsb hi lo (BitVec.ofNat n x) = .ofNat (hi - lo + 1) ((x % 2^n) >>> lo) := by
|
||||||
apply eq_of_getLsbD_eq
|
ext i
|
||||||
intro ⟨i, _lt⟩
|
|
||||||
simp [BitVec.ofNat]
|
simp [BitVec.ofNat]
|
||||||
|
|
||||||
@[simp] theorem extractLsb'_toNat (s m : Nat) (x : BitVec n) :
|
@[simp] theorem extractLsb'_toNat (s m : Nat) (x : BitVec n) :
|
||||||
@@ -811,8 +841,8 @@ theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h
|
|||||||
|
|
||||||
@[simp] theorem setWidth_or {x y : BitVec w} :
|
@[simp] theorem setWidth_or {x y : BitVec w} :
|
||||||
(x ||| y).setWidth k = x.setWidth k ||| y.setWidth k := by
|
(x ||| y).setWidth k = x.setWidth k ||| y.setWidth k := by
|
||||||
ext
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
theorem or_assoc (x y z : BitVec w) :
|
theorem or_assoc (x y z : BitVec w) :
|
||||||
x ||| y ||| z = x ||| (y ||| z) := by
|
x ||| y ||| z = x ||| (y ||| z) := by
|
||||||
@@ -845,12 +875,12 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· ||| · ) (0#n) where
|
|||||||
simp
|
simp
|
||||||
|
|
||||||
@[simp] theorem or_allOnes {x : BitVec w} : x ||| allOnes w = allOnes w := by
|
@[simp] theorem or_allOnes {x : BitVec w} : x ||| allOnes w = allOnes w := by
|
||||||
ext i
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
@[simp] theorem allOnes_or {x : BitVec w} : allOnes w ||| x = allOnes w := by
|
@[simp] theorem allOnes_or {x : BitVec w} : allOnes w ||| x = allOnes w := by
|
||||||
ext i
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
/-! ### and -/
|
/-! ### and -/
|
||||||
|
|
||||||
@@ -884,8 +914,8 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· ||| · ) (0#n) where
|
|||||||
|
|
||||||
@[simp] theorem setWidth_and {x y : BitVec w} :
|
@[simp] theorem setWidth_and {x y : BitVec w} :
|
||||||
(x &&& y).setWidth k = x.setWidth k &&& y.setWidth k := by
|
(x &&& y).setWidth k = x.setWidth k &&& y.setWidth k := by
|
||||||
ext
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
theorem and_assoc (x y z : BitVec w) :
|
theorem and_assoc (x y z : BitVec w) :
|
||||||
x &&& y &&& z = x &&& (y &&& z) := by
|
x &&& y &&& z = x &&& (y &&& z) := by
|
||||||
@@ -915,15 +945,15 @@ instance : Std.IdempotentOp (α := BitVec n) (· &&& · ) where
|
|||||||
simp
|
simp
|
||||||
|
|
||||||
@[simp] theorem and_allOnes {x : BitVec w} : x &&& allOnes w = x := by
|
@[simp] theorem and_allOnes {x : BitVec w} : x &&& allOnes w = x := by
|
||||||
ext i
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) where
|
instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) where
|
||||||
right_id _ := BitVec.and_allOnes
|
right_id _ := BitVec.and_allOnes
|
||||||
|
|
||||||
@[simp] theorem allOnes_and {x : BitVec w} : allOnes w &&& x = x := by
|
@[simp] theorem allOnes_and {x : BitVec w} : allOnes w &&& x = x := by
|
||||||
ext i
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
/-! ### xor -/
|
/-! ### xor -/
|
||||||
|
|
||||||
@@ -960,8 +990,8 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) wher
|
|||||||
|
|
||||||
@[simp] theorem setWidth_xor {x y : BitVec w} :
|
@[simp] theorem setWidth_xor {x y : BitVec w} :
|
||||||
(x ^^^ y).setWidth k = x.setWidth k ^^^ y.setWidth k := by
|
(x ^^^ y).setWidth k = x.setWidth k ^^^ y.setWidth k := by
|
||||||
ext
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
theorem xor_assoc (x y z : BitVec w) :
|
theorem xor_assoc (x y z : BitVec w) :
|
||||||
x ^^^ y ^^^ z = x ^^^ (y ^^^ z) := by
|
x ^^^ y ^^^ z = x ^^^ (y ^^^ z) := by
|
||||||
@@ -1054,9 +1084,9 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
|||||||
rw [Nat.testBit_two_pow_sub_succ x.isLt]
|
rw [Nat.testBit_two_pow_sub_succ x.isLt]
|
||||||
simp [h]
|
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
|
(~~~x).setWidth k = ~~~(x.setWidth k) := by
|
||||||
ext
|
ext i h
|
||||||
simp [h]
|
simp [h]
|
||||||
omega
|
omega
|
||||||
|
|
||||||
@@ -1069,17 +1099,17 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
|||||||
simp
|
simp
|
||||||
|
|
||||||
@[simp] theorem xor_allOnes {x : BitVec w} : x ^^^ allOnes w = ~~~ x := by
|
@[simp] theorem xor_allOnes {x : BitVec w} : x ^^^ allOnes w = ~~~ x := by
|
||||||
ext i
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
@[simp] theorem allOnes_xor {x : BitVec w} : allOnes w ^^^ x = ~~~ x := by
|
@[simp] theorem allOnes_xor {x : BitVec w} : allOnes w ^^^ x = ~~~ x := by
|
||||||
ext i
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem not_not {b : BitVec w} : ~~~(~~~b) = b := by
|
theorem not_not {b : BitVec w} : ~~~(~~~b) = b := by
|
||||||
ext i
|
ext i h
|
||||||
simp
|
simp [h]
|
||||||
|
|
||||||
theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
||||||
constructor
|
constructor
|
||||||
@@ -1102,19 +1132,19 @@ theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
|||||||
|
|
||||||
/-! ### cast -/
|
/-! ### 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
|
ext
|
||||||
simp_all [lt_of_getLsbD]
|
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
|
ext
|
||||||
simp_all [lt_of_getLsbD]
|
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
|
ext
|
||||||
simp_all [lt_of_getLsbD]
|
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
|
ext
|
||||||
simp_all [lt_of_getLsbD]
|
simp_all [lt_of_getLsbD]
|
||||||
|
|
||||||
@@ -1154,24 +1184,21 @@ theorem zero_shiftLeft (n : Nat) : 0#w <<< n = 0#w := by
|
|||||||
|
|
||||||
theorem shiftLeft_xor_distrib (x y : BitVec w) (n : Nat) :
|
theorem shiftLeft_xor_distrib (x y : BitVec w) (n : Nat) :
|
||||||
(x ^^^ y) <<< n = (x <<< n) ^^^ (y <<< n) := by
|
(x ^^^ y) <<< n = (x <<< n) ^^^ (y <<< n) := by
|
||||||
ext i
|
ext i h
|
||||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_xor]
|
simp only [getLsbD_shiftLeft, h, decide_true, Bool.true_and, getLsbD_xor]
|
||||||
by_cases h : i < n
|
by_cases h' : i < n <;> simp [h']
|
||||||
<;> simp [h]
|
|
||||||
|
|
||||||
theorem shiftLeft_and_distrib (x y : BitVec w) (n : Nat) :
|
theorem shiftLeft_and_distrib (x y : BitVec w) (n : Nat) :
|
||||||
(x &&& y) <<< n = (x <<< n) &&& (y <<< n) := by
|
(x &&& y) <<< n = (x <<< n) &&& (y <<< n) := by
|
||||||
ext i
|
ext i h
|
||||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_and]
|
simp only [getLsbD_shiftLeft, h, decide_true, Bool.true_and, getLsbD_and]
|
||||||
by_cases h : i < n
|
by_cases h' : i < n <;> simp [h']
|
||||||
<;> simp [h]
|
|
||||||
|
|
||||||
theorem shiftLeft_or_distrib (x y : BitVec w) (n : Nat) :
|
theorem shiftLeft_or_distrib (x y : BitVec w) (n : Nat) :
|
||||||
(x ||| y) <<< n = (x <<< n) ||| (y <<< n) := by
|
(x ||| y) <<< n = (x <<< n) ||| (y <<< n) := by
|
||||||
ext i
|
ext i h
|
||||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or]
|
simp only [getLsbD_shiftLeft, h, decide_true, Bool.true_and, getLsbD_or]
|
||||||
by_cases h : i < n
|
by_cases h' : i < n <;> simp [h']
|
||||||
<;> simp [h]
|
|
||||||
|
|
||||||
@[simp] theorem getMsbD_shiftLeft (x : BitVec w) (i) :
|
@[simp] theorem getMsbD_shiftLeft (x : BitVec w) (i) :
|
||||||
(x <<< i).getMsbD k = x.getMsbD (k + i) := by
|
(x <<< i).getMsbD k = x.getMsbD (k + i) := by
|
||||||
@@ -1316,6 +1343,61 @@ theorem toNat_ushiftRight_lt (x : BitVec w) (n : Nat) (hn : n ≤ w) :
|
|||||||
· apply hn
|
· apply hn
|
||||||
· apply Nat.pow_pos (by decide)
|
· 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]
|
@[simp]
|
||||||
theorem getMsbD_ushiftRight {x : BitVec w} {i n : Nat} :
|
theorem getMsbD_ushiftRight {x : BitVec w} {i n : Nat} :
|
||||||
(x >>> n).getMsbD i = (decide (i < w) && (!decide (i < n) && x.getMsbD (i - n))) := by
|
(x >>> n).getMsbD i = (decide (i < w) && (!decide (i < n) && x.getMsbD (i - n))) := by
|
||||||
@@ -1455,12 +1537,12 @@ theorem msb_sshiftRight {n : Nat} {x : BitVec w} :
|
|||||||
simp [show n = 0 by omega]
|
simp [show n = 0 by omega]
|
||||||
|
|
||||||
@[simp] theorem sshiftRight_zero {x : BitVec w} : x.sshiftRight 0 = x := by
|
@[simp] theorem sshiftRight_zero {x : BitVec w} : x.sshiftRight 0 = x := by
|
||||||
ext i
|
ext i h
|
||||||
simp [getLsbD_sshiftRight]
|
simp [getLsbD_sshiftRight, h]
|
||||||
|
|
||||||
@[simp] theorem zero_sshiftRight {n : Nat} : (0#w).sshiftRight n = 0#w := by
|
@[simp] theorem zero_sshiftRight {n : Nat} : (0#w).sshiftRight n = 0#w := by
|
||||||
ext i
|
ext i h
|
||||||
simp [getLsbD_sshiftRight]
|
simp [getLsbD_sshiftRight, h]
|
||||||
|
|
||||||
theorem sshiftRight_add {x : BitVec w} {m n : Nat} :
|
theorem sshiftRight_add {x : BitVec w} {m n : Nat} :
|
||||||
x.sshiftRight (m + n) = (x.sshiftRight m).sshiftRight n := by
|
x.sshiftRight (m + n) = (x.sshiftRight m).sshiftRight n := by
|
||||||
@@ -1561,7 +1643,7 @@ private theorem Int.negSucc_emod (m : Nat) (n : Int) :
|
|||||||
-(m + 1) % n = Int.subNatNat (Int.natAbs n) ((m % Int.natAbs n) + 1) := rfl
|
-(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`. -/
|
/-- 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
|
x.signExtend v = x.setWidth v := by
|
||||||
ext i
|
ext i
|
||||||
by_cases hv : i < v
|
by_cases hv : i < v
|
||||||
@@ -1597,21 +1679,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} :
|
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
|
(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
|
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
|
by_cases (i < v) <;> by_cases (i < w) <;> simp_all <;> omega
|
||||||
· rw [signExtend_eq_not_setWidth_not_of_msb_true hmsb]
|
· rw [signExtend_eq_not_setWidth_not_of_msb_true hmsb]
|
||||||
by_cases (i < v) <;> by_cases (i < w) <;> simp_all <;> omega
|
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) :
|
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
|
(x.signExtend v)[i] = if i < w then x.getLsbD i else x.msb := by
|
||||||
rw [←getLsbD_eq_getElem, getLsbD_signExtend]
|
rw [←getLsbD_eq_getElem, getLsbD_signExtend]
|
||||||
simp [h]
|
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. -/
|
/-- 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):
|
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w):
|
||||||
x.signExtend v = x.setWidth v := by
|
x.signExtend v = x.setWidth v := by
|
||||||
ext i
|
ext i h
|
||||||
simp only [getLsbD_signExtend, Fin.is_lt, decide_true, Bool.true_and, getLsbD_setWidth,
|
simp only [getLsbD_signExtend, h, decide_true, Bool.true_and, getLsbD_setWidth,
|
||||||
ite_eq_left_iff, Nat.not_lt]
|
ite_eq_left_iff, Nat.not_lt]
|
||||||
omega
|
omega
|
||||||
|
|
||||||
@@ -1705,35 +1802,34 @@ theorem append_def (x : BitVec v) (y : BitVec w) :
|
|||||||
rfl
|
rfl
|
||||||
|
|
||||||
theorem getLsbD_append {x : BitVec n} {y : BitVec m} :
|
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']
|
simp only [append_def, getLsbD_or, getLsbD_shiftLeftZeroExtend, getLsbD_setWidth']
|
||||||
by_cases h : i < m
|
by_cases h : i < m
|
||||||
· simp [h]
|
· simp [h]
|
||||||
· simp_all [h]
|
· simp_all [h]
|
||||||
|
|
||||||
theorem getElem_append {x : BitVec n} {y : BitVec m} (h : i < n + m) :
|
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']
|
simp only [append_def, getElem_or, getElem_shiftLeftZeroExtend, getElem_setWidth']
|
||||||
by_cases h' : i < m
|
by_cases h' : i < m
|
||||||
· simp [h']
|
· simp [h']
|
||||||
· simp_all [h']
|
· simp_all [h']
|
||||||
|
|
||||||
@[simp] theorem getMsbD_append {x : BitVec n} {y : BitVec m} :
|
@[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]
|
simp only [append_def]
|
||||||
by_cases h : n ≤ i
|
by_cases h : n ≤ i
|
||||||
· simp [h]
|
· simp [h]
|
||||||
· simp [h]
|
· simp [h]
|
||||||
|
|
||||||
theorem msb_append {x : BitVec w} {y : BitVec v} :
|
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]
|
rw [← append_eq, append]
|
||||||
simp only [msb_or, msb_shiftLeftZeroExtend, msb_setWidth']
|
simp only [msb_or, msb_shiftLeftZeroExtend, msb_setWidth']
|
||||||
by_cases h : w = 0
|
by_cases h : w = 0
|
||||||
· subst h
|
· subst h
|
||||||
simp [BitVec.msb, getMsbD]
|
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)
|
have t : y.getLsbD (w + v - 1) = false := getLsbD_ge _ _ (by omega)
|
||||||
simp [h, q, t, BitVec.msb, getMsbD]
|
simp [h, q, t, BitVec.msb, getMsbD]
|
||||||
|
|
||||||
@@ -1742,17 +1838,17 @@ theorem msb_append {x : BitVec w} {y : BitVec v} :
|
|||||||
rw [getLsbD_append] -- Why does this not work with `simp [getLsbD_append]`?
|
rw [getLsbD_append] -- Why does this not work with `simp [getLsbD_append]`?
|
||||||
simp
|
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
|
ext
|
||||||
rw [getLsbD_append]
|
rw [getLsbD_append]
|
||||||
simpa using lt_of_getLsbD
|
simpa using lt_of_getLsbD
|
||||||
|
|
||||||
@[simp] theorem zero_append_zero : 0#v ++ 0#w = 0#(v + w) := by
|
@[simp] theorem zero_append_zero : 0#v ++ 0#w = 0#(v + w) := by
|
||||||
ext
|
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) :
|
@[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
|
ext
|
||||||
simp only [getLsbD_cast, getLsbD_append, cond_eq_if, decide_eq_true_eq]
|
simp only [getLsbD_cast, getLsbD_append, cond_eq_if, decide_eq_true_eq]
|
||||||
split <;> split
|
split <;> split
|
||||||
@@ -1763,27 +1859,25 @@ theorem msb_append {x : BitVec w} {y : BitVec v} :
|
|||||||
omega
|
omega
|
||||||
|
|
||||||
@[simp] theorem cast_append_left (h : w + v = w' + v) (x : BitVec w) (y : BitVec v) :
|
@[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
|
ext
|
||||||
simp [getLsbD_append]
|
simp [getLsbD_append]
|
||||||
|
|
||||||
theorem setWidth_append {x : BitVec w} {y : BitVec v} :
|
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
|
(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
|
ext i h
|
||||||
intro i
|
simp only [getLsbD_setWidth, h, getLsbD_append]
|
||||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, Bool.true_and]
|
split <;> rename_i h₁ <;> split <;> rename_i h₂
|
||||||
split
|
· simp [h]
|
||||||
· have t : i < v := by omega
|
· simp [getLsbD_append, h₁]
|
||||||
simp [t]
|
· omega
|
||||||
· by_cases t : i < v
|
· simp [getLsbD_append, h₁]
|
||||||
· simp [t, getLsbD_append]
|
omega
|
||||||
· have t' : i - v < k - v := by omega
|
|
||||||
simp [t, t', getLsbD_append]
|
|
||||||
|
|
||||||
@[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
|
@[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
|
subst h
|
||||||
ext i
|
ext i h
|
||||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, cond_eq_if,
|
simp only [getLsbD_setWidth, h, decide_true, getLsbD_append, cond_eq_if,
|
||||||
decide_eq_true_eq, Bool.true_and, setWidth_eq]
|
decide_eq_true_eq, Bool.true_and, setWidth_eq]
|
||||||
split
|
split
|
||||||
· simp_all
|
· simp_all
|
||||||
@@ -1833,12 +1927,12 @@ theorem shiftLeft_ushiftRight {x : BitVec w} {n : Nat}:
|
|||||||
case succ n ih =>
|
case succ n ih =>
|
||||||
rw [BitVec.shiftLeft_add, Nat.add_comm, BitVec.shiftRight_add, ih,
|
rw [BitVec.shiftLeft_add, Nat.add_comm, BitVec.shiftRight_add, ih,
|
||||||
Nat.add_comm, BitVec.shiftLeft_add, BitVec.shiftLeft_and_distrib]
|
Nat.add_comm, BitVec.shiftLeft_add, BitVec.shiftLeft_and_distrib]
|
||||||
ext i
|
ext i h
|
||||||
by_cases hw : w = 0
|
by_cases hw : w = 0
|
||||||
· simp [hw]
|
· simp [hw]
|
||||||
· by_cases hi₂ : i.val = 0
|
· by_cases hi₂ : i = 0
|
||||||
· simp [hi₂]
|
· 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]
|
@[simp]
|
||||||
theorem msb_shiftLeft {x : BitVec w} {n : Nat} :
|
theorem msb_shiftLeft {x : BitVec w} {n : Nat} :
|
||||||
@@ -1923,13 +2017,12 @@ theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
|
|||||||
|
|
||||||
theorem setWidth_succ (x : BitVec w) :
|
theorem setWidth_succ (x : BitVec w) :
|
||||||
setWidth (i+1) x = cons (getLsbD x i) (setWidth i x) := by
|
setWidth (i+1) x = cons (getLsbD x i) (setWidth i x) := by
|
||||||
apply eq_of_getLsbD_eq
|
ext j h
|
||||||
intro j
|
simp only [getLsbD_setWidth, getLsbD_cons, h, decide_true, Bool.true_and]
|
||||||
simp only [getLsbD_setWidth, getLsbD_cons, j.isLt, decide_true, Bool.true_and]
|
if j_eq : j = i then
|
||||||
if j_eq : j.val = i then
|
|
||||||
simp [j_eq]
|
simp [j_eq]
|
||||||
else
|
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 [j_eq, j_lt]
|
||||||
|
|
||||||
@[simp] theorem cons_msb_setWidth (x : BitVec (w+1)) : (cons x.msb (x.setWidth w)) = x := by
|
@[simp] theorem cons_msb_setWidth (x : BitVec (w+1)) : (cons x.msb (x.setWidth w)) = x := by
|
||||||
@@ -2002,20 +2095,64 @@ theorem getElem_concat (x : BitVec w) (b : Bool) (i : Nat) (h : i < w + 1) :
|
|||||||
(concat x b)[i + 1] = x[i] := by
|
(concat x b)[i + 1] = x[i] := by
|
||||||
simp [getElem_concat, h, getLsbD_eq_getElem]
|
simp [getElem_concat, h, getLsbD_eq_getElem]
|
||||||
|
|
||||||
|
@[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
|
||||||
|
simp only [getMsbD_eq_getLsbD, Nat.add_sub_cancel, getLsbD_concat]
|
||||||
|
by_cases h₀ : i = w
|
||||||
|
· simp [h₀]
|
||||||
|
· by_cases h₁ : i < w
|
||||||
|
· simp [h₀, h₁, show ¬ w - i = 0 by omega, show i < w + 1 by omega, Nat.sub_sub, Nat.add_comm]
|
||||||
|
· simp only [show w - i = 0 by omega, ↓reduceIte, h₁, h₀, decide_false, Bool.false_and,
|
||||||
|
Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||||
|
intro
|
||||||
|
omega
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
|
||||||
|
(x.concat b).msb = if 0 < w then x.msb else b := by
|
||||||
|
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_true, Nat.add_one_sub_one,
|
||||||
|
Nat.sub_zero, Bool.true_and]
|
||||||
|
by_cases h₀ : 0 < w
|
||||||
|
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, ↓reduceIte, decide_true,
|
||||||
|
Bool.true_and, ite_eq_right_iff]
|
||||||
|
intro
|
||||||
|
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
|
@[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]
|
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||||
|
|
||||||
@[simp] theorem concat_or_concat (x y : BitVec w) (a b : Bool) :
|
@[simp] theorem concat_or_concat (x y : BitVec w) (a b : Bool) :
|
||||||
(concat x a) ||| (concat y b) = concat (x ||| y) (a || b) := by
|
(concat x a) ||| (concat y b) = concat (x ||| y) (a || b) := by
|
||||||
ext i; cases i using Fin.succRecOn <;> simp
|
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||||
|
|
||||||
@[simp] theorem concat_and_concat (x y : BitVec w) (a b : Bool) :
|
@[simp] theorem concat_and_concat (x y : BitVec w) (a b : Bool) :
|
||||||
(concat x a) &&& (concat y b) = concat (x &&& y) (a && b) := by
|
(concat x a) &&& (concat y b) = concat (x &&& y) (a && b) := by
|
||||||
ext i; cases i using Fin.succRecOn <;> simp
|
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||||
|
|
||||||
@[simp] theorem concat_xor_concat (x y : BitVec w) (a b : Bool) :
|
@[simp] theorem concat_xor_concat (x y : BitVec w) (a b : Bool) :
|
||||||
(concat x a) ^^^ (concat y b) = concat (x ^^^ y) (a ^^ b) := by
|
(concat x a) ^^^ (concat y b) = concat (x ^^^ y) (a ^^ b) := by
|
||||||
ext i; cases i using Fin.succRecOn <;> simp
|
ext (_ | i) h <;> simp [getLsbD_concat]
|
||||||
|
|
||||||
|
@[simp] theorem zero_concat_false : concat 0#w false = 0#(w + 1) := by
|
||||||
|
ext
|
||||||
|
simp [getLsbD_concat]
|
||||||
|
|
||||||
/-! ### shiftConcat -/
|
/-! ### shiftConcat -/
|
||||||
|
|
||||||
@@ -2032,8 +2169,8 @@ theorem getLsbD_shiftConcat_eq_decide (x : BitVec w) (b : Bool) (i : Nat) :
|
|||||||
|
|
||||||
theorem shiftRight_sub_one_eq_shiftConcat (n : BitVec w) (hwn : 0 < wn) :
|
theorem shiftRight_sub_one_eq_shiftConcat (n : BitVec w) (hwn : 0 < wn) :
|
||||||
n >>> (wn - 1) = (n >>> wn).shiftConcat (n.getLsbD (wn - 1)) := by
|
n >>> (wn - 1) = (n >>> wn).shiftConcat (n.getLsbD (wn - 1)) := by
|
||||||
ext i
|
ext i h
|
||||||
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, Fin.is_lt, decide_true, Bool.true_and]
|
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, h, decide_true, Bool.true_and]
|
||||||
split
|
split
|
||||||
· simp [*]
|
· simp [*]
|
||||||
· congr 1; omega
|
· congr 1; omega
|
||||||
@@ -2062,35 +2199,6 @@ theorem toNat_shiftConcat_lt_of_lt {x : BitVec w} {b : Bool} {k : Nat}
|
|||||||
have := Bool.toNat_lt b
|
have := Bool.toNat_lt b
|
||||||
omega
|
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
|
|
||||||
simp only [getMsbD_eq_getLsbD, Nat.add_sub_cancel, getLsbD_concat]
|
|
||||||
by_cases h₀ : i = w
|
|
||||||
· simp [h₀]
|
|
||||||
· by_cases h₁ : i < w
|
|
||||||
· simp [h₀, h₁, show ¬ w - i = 0 by omega, show i < w + 1 by omega, Nat.sub_sub, Nat.add_comm]
|
|
||||||
· simp only [show w - i = 0 by omega, ↓reduceIte, h₁, h₀, decide_false, Bool.false_and,
|
|
||||||
Bool.and_eq_false_imp, decide_eq_true_eq]
|
|
||||||
intro
|
|
||||||
omega
|
|
||||||
|
|
||||||
@[simp]
|
|
||||||
theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
|
|
||||||
(x.concat b).msb = if 0 < w then x.msb else b := by
|
|
||||||
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_true, Nat.add_one_sub_one,
|
|
||||||
Nat.sub_zero, Bool.true_and]
|
|
||||||
by_cases h₀ : 0 < w
|
|
||||||
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, ↓reduceIte, decide_true,
|
|
||||||
Bool.true_and, ite_eq_right_iff]
|
|
||||||
intro
|
|
||||||
omega
|
|
||||||
· simp [h₀, show w = 0 by omega]
|
|
||||||
|
|
||||||
/-! ### add -/
|
/-! ### add -/
|
||||||
|
|
||||||
theorem add_def {n} (x y : BitVec n) : x + y = .ofNat n (x.toNat + y.toNat) := rfl
|
theorem add_def {n} (x y : BitVec n) : x + y = .ofNat n (x.toNat + y.toNat) := rfl
|
||||||
@@ -3073,8 +3181,8 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_of_getLsbD_false
|
|||||||
{x : BitVec w} {i : Nat} (hx : x.getLsbD i = false) :
|
{x : BitVec w} {i : Nat} (hx : x.getLsbD i = false) :
|
||||||
setWidth w (x.setWidth (i + 1)) =
|
setWidth w (x.setWidth (i + 1)) =
|
||||||
setWidth w (x.setWidth i) := by
|
setWidth w (x.setWidth i) := by
|
||||||
ext k
|
ext k h
|
||||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
simp only [getLsbD_setWidth, h, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||||
by_cases hik : i = k
|
by_cases hik : i = k
|
||||||
· subst hik
|
· subst hik
|
||||||
simp [hx]
|
simp [hx]
|
||||||
@@ -3089,20 +3197,17 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true
|
|||||||
{x : BitVec w} {i : Nat} (hx : x.getLsbD i = true) :
|
{x : BitVec w} {i : Nat} (hx : x.getLsbD i = true) :
|
||||||
setWidth w (x.setWidth (i + 1)) =
|
setWidth w (x.setWidth (i + 1)) =
|
||||||
setWidth w (x.setWidth i) ||| (twoPow w i) := by
|
setWidth w (x.setWidth i) ||| (twoPow w i) := by
|
||||||
ext k
|
ext k h
|
||||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
simp only [getLsbD_setWidth, h, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||||
by_cases hik : i = k
|
by_cases hik : i = k
|
||||||
· subst hik
|
· subst hik
|
||||||
simp [hx]
|
simp [hx, h]
|
||||||
· by_cases hik' : k < i + 1 <;> simp [hik, hik'] <;> omega
|
· 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`. -/
|
/-- 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} :
|
theorem and_one_eq_setWidth_ofBool_getLsbD {x : BitVec w} :
|
||||||
(x &&& 1#w) = setWidth w (ofBool (x.getLsbD 0)) := by
|
(x &&& 1#w) = setWidth w (ofBool (x.getLsbD 0)) := by
|
||||||
ext i
|
ext (_ | i) h <;> simp [Bool.and_comm]
|
||||||
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
|
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem replicate_zero_eq {x : BitVec w} : x.replicate 0 = 0#0 := by
|
theorem replicate_zero_eq {x : BitVec w} : x.replicate 0 = 0#0 := by
|
||||||
@@ -3126,7 +3231,7 @@ theorem getLsbD_replicate {n w : Nat} (x : BitVec w) :
|
|||||||
· simp only [hi, decide_true, Bool.true_and]
|
· simp only [hi, decide_true, Bool.true_and]
|
||||||
by_cases hi' : i < w * n
|
by_cases hi' : i < w * n
|
||||||
· simp [hi', ih]
|
· 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.sub_mul_eq_mod_of_lt_of_le] <;> omega
|
||||||
· rw [Nat.mul_succ] at hi ⊢
|
· rw [Nat.mul_succ] at hi ⊢
|
||||||
simp only [show ¬i < w * n by omega, decide_false, cond_false, hi, Bool.false_and]
|
simp only [show ¬i < w * n by omega, decide_false, cond_false, hi, Bool.false_and]
|
||||||
@@ -3432,7 +3537,7 @@ theorem forall_zero_iff {P : BitVec 0 → Prop} :
|
|||||||
· intro h
|
· intro h
|
||||||
apply h
|
apply h
|
||||||
· intro h v
|
· 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
|
apply h
|
||||||
|
|
||||||
theorem forall_cons_iff {P : BitVec (n + 1) → Prop} :
|
theorem forall_cons_iff {P : BitVec (n + 1) → Prop} :
|
||||||
@@ -3448,7 +3553,7 @@ theorem forall_cons_iff {P : BitVec (n + 1) → Prop} :
|
|||||||
instance instDecidableForallBitVecZero (P : BitVec 0 → Prop) :
|
instance instDecidableForallBitVecZero (P : BitVec 0 → Prop) :
|
||||||
∀ [Decidable (P 0#0)], Decidable (∀ v, P v)
|
∀ [Decidable (P 0#0)], Decidable (∀ v, P v)
|
||||||
| .isTrue h => .isTrue fun v => by
|
| .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
|
exact h
|
||||||
| .isFalse h => .isFalse (fun w => h (w _))
|
| .isFalse h => .isFalse (fun w => h (w _))
|
||||||
|
|
||||||
@@ -3493,6 +3598,9 @@ instance instDecidableExistsBitVec :
|
|||||||
|
|
||||||
set_option linter.missingDocs false
|
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")]
|
@[deprecated truncate_eq_setWidth (since := "2024-09-18")]
|
||||||
abbrev truncate_eq_zeroExtend := @truncate_eq_setWidth
|
abbrev truncate_eq_zeroExtend := @truncate_eq_setWidth
|
||||||
|
|
||||||
@@ -3595,8 +3703,8 @@ abbrev truncate_xor := @setWidth_xor
|
|||||||
@[deprecated setWidth_not (since := "2024-09-18")]
|
@[deprecated setWidth_not (since := "2024-09-18")]
|
||||||
abbrev truncate_not := @setWidth_not
|
abbrev truncate_not := @setWidth_not
|
||||||
|
|
||||||
@[deprecated signExtend_eq_not_setWidth_not_of_msb_false (since := "2024-09-18")]
|
@[deprecated signExtend_eq_setWidth_of_msb_false (since := "2024-09-18")]
|
||||||
abbrev signExtend_eq_not_zeroExtend_not_of_msb_false := @signExtend_eq_not_setWidth_not_of_msb_false
|
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")]
|
@[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
|
abbrev signExtend_eq_not_zeroExtend_not_of_msb_true := @signExtend_eq_not_setWidth_not_of_msb_true
|
||||||
|
|||||||
@@ -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
|
@[simp] theorem toNat_eq_one {b : Bool} : b.toNat = 1 ↔ b = true := by
|
||||||
cases b <;> simp
|
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 -/
|
/-! ### ite -/
|
||||||
|
|
||||||
@[simp] theorem if_true_left (p : Prop) [h : Decidable p] (f : Bool) :
|
@[simp] theorem if_true_left (p : Prop) [h : Decidable p] (f : Bool) :
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import Init.Data.Queue
|
|||||||
import Init.System.Promise
|
import Init.System.Promise
|
||||||
import Init.System.Mutex
|
import Init.System.Mutex
|
||||||
|
|
||||||
|
set_option linter.deprecated false
|
||||||
|
|
||||||
namespace IO
|
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.
|
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
|
structure Channel.State (α : Type) where
|
||||||
values : Std.Queue α := ∅
|
values : Std.Queue α := ∅
|
||||||
consumers : Std.Queue (Promise (Option α)) := ∅
|
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
|
A channel can be closed. Once it is closed, all `send`s are ignored, and
|
||||||
`recv?` returns `none` once the queue is empty.
|
`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 α)
|
def Channel (α : Type) : Type := Mutex (Channel.State α)
|
||||||
|
|
||||||
instance : Nonempty (Channel α) :=
|
instance : Nonempty (Channel α) :=
|
||||||
inferInstanceAs (Nonempty (Mutex _))
|
inferInstanceAs (Nonempty (Mutex _))
|
||||||
|
|
||||||
/-- Creates a new `Channel`. -/
|
/-- Creates a new `Channel`. -/
|
||||||
|
@[deprecated "Use Std.Channel.new from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||||
def Channel.new : BaseIO (Channel α) :=
|
def Channel.new : BaseIO (Channel α) :=
|
||||||
Mutex.new {}
|
Mutex.new {}
|
||||||
|
|
||||||
@@ -41,6 +46,7 @@ Sends a message on an `Channel`.
|
|||||||
|
|
||||||
This function does not block.
|
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 :=
|
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
|
||||||
ch.atomically do
|
ch.atomically do
|
||||||
let st ← get
|
let st ← get
|
||||||
@@ -54,6 +60,7 @@ def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
|
|||||||
/--
|
/--
|
||||||
Closes an `Channel`.
|
Closes an `Channel`.
|
||||||
-/
|
-/
|
||||||
|
@[deprecated "Use Std.Channel.close from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||||
def Channel.close (ch : Channel α) : BaseIO Unit :=
|
def Channel.close (ch : Channel α) : BaseIO Unit :=
|
||||||
ch.atomically do
|
ch.atomically do
|
||||||
let st ← get
|
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.
|
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 α)) :=
|
def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
|
||||||
ch.atomically do
|
ch.atomically do
|
||||||
let st ← get
|
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.
|
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 α)
|
partial def Channel.forAsync (f : α → BaseIO Unit) (ch : Channel α)
|
||||||
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
|
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
|
||||||
BaseIO.bindTask (prio := prio) (← ch.recv?) fun
|
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?`.
|
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 α) :=
|
def Channel.recvAllCurrent (ch : Channel α) : BaseIO (Array α) :=
|
||||||
ch.atomically do
|
ch.atomically do
|
||||||
modifyGet fun st => (st.values.toArray, { st with values := ∅ })
|
modifyGet fun st => (st.values.toArray, { st with values := ∅ })
|
||||||
|
|
||||||
/-- Type tag for synchronous (blocking) operations on a `Channel`. -/
|
/-- 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
|
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.
|
and `for msg in ch.sync do ...` iterates synchronously over the channel.
|
||||||
These functions should only be used in dedicated threads.
|
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
|
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.
|
Every message is only received once.
|
||||||
Returns `none` if the channel is closed and the queue is empty.
|
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
|
def Channel.Sync.recv? (ch : Channel.Sync α) : BaseIO (Option α) := do
|
||||||
IO.wait (← Channel.recv? ch)
|
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]
|
private partial def Channel.Sync.forIn [Monad m] [MonadLiftT BaseIO m]
|
||||||
(ch : Channel.Sync α) (f : α → β → m (ForInStep β)) : β → m β := fun b => do
|
(ch : Channel.Sync α) (f : α → β → m (ForInStep β)) : β → m β := fun b => do
|
||||||
match ← ch.recv? with
|
match ← ch.recv? with
|
||||||
|
|||||||
@@ -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⟩
|
@[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. -/
|
/-- `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`. -/
|
/-- `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) :=
|
@[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`. -/
|
/-- 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
|
@[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)` -/
|
/-- 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
|
if h : i < n then loop (f x ⟨i, h⟩) (i+1) else x
|
||||||
termination_by n - i
|
termination_by n - i
|
||||||
|
|
||||||
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
|
/-- 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
|
@[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))` -/
|
/-- 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
|
| 0, _, x => x
|
||||||
| i+1, h, x => loop i (Nat.le_of_lt h) (f ⟨i, h⟩ x)
|
| i+1, h, x => loop i (Nat.le_of_lt h) (f ⟨i, h⟩ x)
|
||||||
termination_by structural i => i
|
termination_by structural i => i
|
||||||
@@ -47,7 +47,7 @@ Fin.foldlM n f x₀ = do
|
|||||||
pure xₙ
|
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
|
if h : i < n then f x ⟨i, h⟩ >>= (loop · (i+1)) else pure x
|
||||||
termination_by n - i
|
termination_by n - i
|
||||||
decreasing_by decreasing_trivial_pre_omega
|
decreasing_by decreasing_trivial_pre_omega
|
||||||
@@ -76,7 +76,7 @@ Fin.foldrM n f xₙ = do
|
|||||||
pure x₀
|
pure x₀
|
||||||
```
|
```
|
||||||
-/
|
-/
|
||||||
loop : {i // i ≤ n} → α → m α
|
@[semireducible, specialize] loop : {i // i ≤ n} → α → m α
|
||||||
| ⟨0, _⟩, x => pure x
|
| ⟨0, _⟩, x => pure x
|
||||||
| ⟨i+1, h⟩, x => f ⟨i, h⟩ x >>= loop ⟨i, Nat.le_of_lt h⟩
|
| ⟨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 =>
|
| zero =>
|
||||||
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
|
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
|
||||||
conv => rhs; rw [←bind_pure (f 0 x)]
|
conv => rhs; rw [←bind_pure (f 0 x)]
|
||||||
congr; funext; exact foldrM_loop_zero ..
|
congr; funext
|
||||||
| succ i ih =>
|
| succ i ih =>
|
||||||
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
||||||
congr; funext; exact ih ..
|
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) :=
|
Fin.castLE mn ∘ Fin.castLE km = Fin.castLE (Nat.le_trans km mn) :=
|
||||||
funext (castLE_castLE 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])
|
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
|
ext
|
||||||
simp
|
simp
|
||||||
|
|
||||||
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
@[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
|
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 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
|
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
|
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) :
|
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) :
|
@[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) :
|
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 cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
|
||||||
the reverse direction. -/
|
the reverse direction. -/
|
||||||
@[simp] theorem cast_succ_eq {n' : Nat} (i : Fin n) (h : n.succ = n'.succ) :
|
@[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') :
|
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 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} :
|
@[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]
|
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
|
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)} :
|
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
|
@[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]
|
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) :
|
@[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) :
|
@[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} :
|
@[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_zero : castSucc (0 : Fin (n + 1)) = 0 := rfl
|
||||||
|
|
||||||
@[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 := rfl
|
@[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 := rfl
|
||||||
|
|
||||||
/-- `castSucc i` is positive when `i` is positive -/
|
/-- `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
|
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
|
not_congr <| castSucc_eq_zero_iff
|
||||||
|
|
||||||
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
|
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]
|
@[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
|
cases n
|
||||||
· exact a.elim0
|
· exact a.elim0
|
||||||
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
· 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
|
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 :=
|
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 ⟨j, hj⟩ => hj ▸ Fin.ne_of_lt j.castSucc_lt_last,
|
||||||
fun hi => ⟨i.castLT <| Fin.val_lt_last hi, rfl⟩⟩
|
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
|
@[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
|
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') :
|
@[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`. -/
|
/-- For rewriting in the reverse direction, see `Fin.cast_addNat_left`. -/
|
||||||
theorem addNat_cast {n n' m : Nat} (i : Fin n') (h : n' = n) :
|
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) :
|
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) :
|
@[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) : _)
|
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
|
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||||
@@ -522,46 +522,46 @@ 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 ..
|
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`. -/
|
/-- 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) :
|
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) :
|
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) :
|
@[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) : _)
|
Fin.ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
|
||||||
|
|
||||||
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
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) :
|
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) :
|
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
|
Fin.ext <| (Nat.add_assoc ..).symm
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
|
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 :=
|
(natAdd 0 i).cast h = i.cast ((Nat.zero_add _).symm.trans h) :=
|
||||||
Fin.ext <| Nat.zero_add _
|
Fin.ext <| Nat.zero_add _
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
|
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]
|
@[simp]
|
||||||
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
|
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 natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
|
||||||
|
|
||||||
@[simp] theorem addNat_last (n : Nat) :
|
@[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
|
ext
|
||||||
simp
|
simp
|
||||||
|
|
||||||
@@ -657,7 +657,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
|
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) :
|
@[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 -/
|
/-! ### recursion and induction principles -/
|
||||||
|
|
||||||
|
|||||||
180
src/Init/Data/Float32.lean
Normal file
180
src/Init/Data/Float32.lean
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/-
|
||||||
|
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
|
||||||
|
|
||||||
|
/-
|
||||||
|
#exit -- TODO: Remove after update stage0
|
||||||
|
|
||||||
|
-- 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_float"] 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
|
||||||
|
-/
|
||||||
@@ -34,4 +34,8 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
|
|||||||
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
|
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
|
||||||
simp [Int.shiftRight_eq_div_pow]
|
simp [Int.shiftRight_eq_div_pow]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
|
||||||
|
simp [Int.shiftRight_eq_div_pow]
|
||||||
|
|
||||||
end Int
|
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),
|
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
|
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.
|
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 -/
|
/-! ### T-rounding division -/
|
||||||
@@ -71,8 +73,6 @@ def tdiv : (@& Int) → (@& Int) → Int
|
|||||||
| -[m +1], ofNat n => -ofNat (succ m / n)
|
| -[m +1], ofNat n => -ofNat (succ m / n)
|
||||||
| -[m +1], -[n +1] => ofNat (succ m / succ 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
|
/-- Integer modulo. This function uses the
|
||||||
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
|
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
|
||||||
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
|
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], ofNat n => -ofNat (succ m % n)
|
||||||
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
|
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
|
||||||
|
|
||||||
@[deprecated tmod (since := "2024-09-11")] abbrev mod := tmod
|
|
||||||
|
|
||||||
/-! ### F-rounding division
|
/-! ### F-rounding division
|
||||||
This pair satisfies `fdiv x y = floor (x / y)`.
|
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
|
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
|
theorem ofNat_fdiv : ∀ m n : Nat, ↑(m / n) = fdiv ↑m ↑n
|
||||||
| 0, _ => by simp [fdiv]
|
| 0, _ => by simp [fdiv]
|
||||||
| succ _, _ => rfl
|
| 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⟩
|
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 :=
|
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 -/
|
/-! ### *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
|
all_goals decide
|
||||||
· exact ofNat_nonneg x
|
· exact ofNat_nonneg x
|
||||||
· exact succ_ofNat_pos (x + 1)
|
· 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,7 @@ import Init.Data.List.Zip
|
|||||||
import Init.Data.List.Perm
|
import Init.Data.List.Perm
|
||||||
import Init.Data.List.Sort
|
import Init.Data.List.Sort
|
||||||
import Init.Data.List.ToArray
|
import Init.Data.List.ToArray
|
||||||
|
import Init.Data.List.ToArrayImpl
|
||||||
import Init.Data.List.MapIdx
|
import Init.Data.List.MapIdx
|
||||||
import Init.Data.List.OfFn
|
import Init.Data.List.OfFn
|
||||||
import Init.Data.List.FinRange
|
import Init.Data.List.FinRange
|
||||||
|
|||||||
@@ -666,10 +666,14 @@ def isEmpty : List α → Bool
|
|||||||
/-! ### elem -/
|
/-! ### 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`
|
* `[1, 4, 2, 3, 3, 7].contains 3 = true`
|
||||||
* `elem 5 [1, 4, 2, 3, 3, 7] = false`
|
* `[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
|
def elem [BEq α] (a : α) : List α → Bool
|
||||||
| [] => false
|
| [] => false
|
||||||
|
|||||||
@@ -155,7 +155,8 @@ def mapMono (as : List α) (f : α → α) : List α :=
|
|||||||
|
|
||||||
/-! ## Additional lemmas required for bootstrapping `Array`. -/
|
/-! ## 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
|
induction as generalizing i with
|
||||||
| nil => trivial
|
| nil => trivial
|
||||||
| cons a as ih =>
|
| cons a as ih =>
|
||||||
|
|||||||
@@ -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
|
@[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] theorem countP_reverse (l : List α) : countP p l.reverse = countP p l := by
|
||||||
simp [countP_eq_length_filter, filter_reverse]
|
simp [countP_eq_length_filter, filter_reverse]
|
||||||
|
|
||||||
@@ -326,6 +330,9 @@ theorem count_filterMap {α} [BEq β] (b : β) (f : α → Option β) (l : List
|
|||||||
· simp
|
· simp
|
||||||
· 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 : α) :
|
theorem count_erase (a b : α) :
|
||||||
∀ l : List α, count a (l.erase b) = count a l - if b == a then 1 else 0
|
∀ l : List α, count a (l.erase b) = count a l - if b == a then 1 else 0
|
||||||
| [] => by simp
|
| [] => by simp
|
||||||
|
|||||||
@@ -220,15 +220,6 @@ We simplify `l[n]!` to `(l[n]?).getD default`.
|
|||||||
|
|
||||||
/-! ### getElem? and getElem -/
|
/-! ### 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[n]? = none ↔ length l ≤ n := by
|
||||||
simp only [← get?_eq_getElem?, get?_eq_none_iff]
|
simp only [← get?_eq_getElem?, get?_eq_none_iff]
|
||||||
|
|
||||||
@@ -237,11 +228,20 @@ theorem some_eq_getElem?_iff {l : List α} : some a = l[n]? ↔ ∃ h : n < l.le
|
|||||||
|
|
||||||
theorem getElem?_eq_none (h : length l ≤ n) : l[n]? = none := getElem?_eq_none_iff.mpr h
|
theorem getElem?_eq_none (h : length l ≤ n) : l[n]? = 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 α} {n} (h : n < l.length) : l[n]? = some l[n] :=
|
||||||
|
getElem?_pos ..
|
||||||
|
|
||||||
|
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 some_getElem_eq_getElem?_iff (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||||
(some xs[i] = xs[i]?) ↔ True := by
|
(some xs[i] = xs[i]?) ↔ True := by
|
||||||
simp [h]
|
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
|
(xs[i]? = some xs[i]) ↔ True := by
|
||||||
simp [h]
|
simp [h]
|
||||||
|
|
||||||
@@ -253,8 +253,21 @@ 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
|
l[i] = l[i]?.get (by simp [getElem?_eq_getElem, h]) := by
|
||||||
simp [getElem_eq_iff]
|
simp [getElem_eq_iff]
|
||||||
|
|
||||||
|
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 {n : Nat} : ([] : List α)[n]? = none := rfl
|
@[simp] theorem getElem?_nil {n : Nat} : ([] : List α)[n]? = 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
|
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)[n+1]? = l[n]? := by
|
||||||
@@ -264,6 +277,13 @@ theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by simp
|
|||||||
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
|
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
|
||||||
cases i <;> simp
|
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'`,
|
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
|
`rw [h]` will give a "motive it not type correct" error, as it cannot rewrite the
|
||||||
@@ -273,10 +293,6 @@ 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) :
|
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
|
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) :=
|
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos.mp h) :=
|
||||||
match l, h with
|
match l, h with
|
||||||
| _ :: _, _ => rfl
|
| _ :: _, _ => rfl
|
||||||
@@ -300,12 +316,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
|
theorem getElem?_concat_length (l : List α) (a : α) : (l ++ [a])[l.length]? = some a := by
|
||||||
simp
|
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 -/
|
/-! ### mem -/
|
||||||
|
|
||||||
@[simp] theorem not_mem_nil (a : α) : ¬ a ∈ [] := nofun
|
@[simp] theorem not_mem_nil (a : α) : ¬ a ∈ [] := nofun
|
||||||
@@ -416,8 +426,9 @@ theorem getElem_of_mem : ∀ {a} {l : List α}, a ∈ l → ∃ (n : Nat) (h : n
|
|||||||
| _, _ :: _, .head .. => ⟨0, Nat.succ_pos _, rfl⟩
|
| _, _ :: _, .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 ⟨n, h, e⟩ := getElem_of_mem m; ⟨n+1, Nat.succ_lt_succ h, e⟩
|
||||||
|
|
||||||
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = some a :=
|
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = some a := by
|
||||||
let ⟨n, _, e⟩ := getElem_of_mem h; ⟨n, e ▸ getElem?_eq_getElem _⟩
|
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 α} {n : Nat} {a : α} (e : l[n]? = some a) : a ∈ l :=
|
||||||
let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
|
let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
|
||||||
@@ -448,6 +459,10 @@ theorem forall_getElem {l : List α} {p : α → Prop} :
|
|||||||
simp only [getElem_cons_succ]
|
simp only [getElem_cons_succ]
|
||||||
exact getElem_mem (lt_of_succ_lt_succ h)
|
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 α} :
|
@[simp] theorem decide_mem_cons [BEq α] [LawfulBEq α] {l : List α} :
|
||||||
decide (y ∈ a :: l) = (y == a || decide (y ∈ l)) := by
|
decide (y ∈ a :: l) = (y == a || decide (y ∈ l)) := by
|
||||||
cases h : y == a <;> simp_all
|
cases h : y == a <;> simp_all
|
||||||
@@ -455,16 +470,27 @@ theorem forall_getElem {l : List α} {p : α → Prop} :
|
|||||||
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
|
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
|
||||||
elem a as = true ↔ a ∈ as := ⟨mem_of_elem_eq_true, elem_eq_true_of_mem⟩
|
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]
|
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` -/
|
/-! ### `isEmpty` -/
|
||||||
|
|
||||||
theorem isEmpty_iff {l : List α} : l.isEmpty ↔ l = [] := by
|
theorem isEmpty_iff {l : List α} : l.isEmpty ↔ l = [] := by
|
||||||
cases l <;> simp
|
cases l <;> simp
|
||||||
|
|
||||||
theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
|
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
|
cases xs <;> simp
|
||||||
|
|
||||||
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 := by
|
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 := by
|
||||||
@@ -502,17 +528,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] theorem all_eq_false {l : List α} : l.all p = false ↔ ∃ x, x ∈ l ∧ ¬p x := by
|
||||||
simp [all_eq]
|
simp [all_eq]
|
||||||
|
|
||||||
theorem any_beq [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => a == x) ↔ a ∈ l := by
|
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
|
||||||
simp
|
induction l <;> simp_all [contains_cons]
|
||||||
|
|
||||||
theorem any_beq' [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => x == a) ↔ a ∈ l := by
|
/-- Variant of `any_beq` with `==` reversed. -/
|
||||||
simp
|
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
|
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
|
||||||
induction l <;> simp_all
|
induction l <;> simp_all [bne]
|
||||||
|
|
||||||
theorem all_bne' [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => x != a) ↔ a ∉ l := by
|
/-- Variant of `all_bne` with `!=` reversed. -/
|
||||||
induction l <;> simp_all [eq_comm (a := a)]
|
theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||||
|
(l.all fun x => x != a) = !l.contains a := by
|
||||||
|
simp only [bne_comm, all_bne]
|
||||||
|
|
||||||
/-! ### set -/
|
/-! ### set -/
|
||||||
|
|
||||||
@@ -949,7 +979,7 @@ theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
|
|||||||
| _ :: _ :: _, _ => by
|
| _ :: _ :: _, _ => by
|
||||||
simp [getLast, get, Nat.succ_sub_succ, getLast_eq_getElem]
|
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
|
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
|
||||||
rw [← getLast_eq_getElem]
|
rw [← getLast_eq_getElem]
|
||||||
|
|
||||||
@@ -1077,7 +1107,8 @@ theorem head_eq_getElem (l : List α) (h : l ≠ []) : head l h = l[0]'(length_p
|
|||||||
| nil => simp at h
|
| nil => simp at h
|
||||||
| cons _ _ => simp
|
| 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
|
cases l with
|
||||||
| nil => simp at h
|
| nil => simp at h
|
||||||
| cons _ _ => simp
|
| cons _ _ => simp
|
||||||
@@ -1669,7 +1700,7 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
|||||||
@[simp] theorem cons_append_fun (a : α) (as : List α) :
|
@[simp] theorem cons_append_fun (a : α) (as : List α) :
|
||||||
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
|
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
|
||||||
|
|
||||||
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h) :
|
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h : n < (l₁ ++ l₂).length) :
|
||||||
(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
|
(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
|
||||||
split <;> rename_i h'
|
split <;> rename_i h'
|
||||||
· rw [getElem_append_left h']
|
· rw [getElem_append_left h']
|
||||||
@@ -2211,6 +2242,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 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] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
|
||||||
simp [flatMap_def, mem_flatten]
|
simp [flatMap_def, mem_flatten]
|
||||||
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
|
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
|
||||||
@@ -2819,11 +2855,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
|
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
|
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 [*]
|
induction l with simp | cons b l => cases b == a <;> simp [*]
|
||||||
|
|
||||||
@@ -2867,7 +2898,7 @@ are often used for theorems about `Array.pop`.
|
|||||||
@[simp] theorem getElem_dropLast : ∀ (xs : List α) (i : Nat) (h : i < xs.dropLast.length),
|
@[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 _))
|
xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. ▸ Nat.pred_le _))
|
||||||
| _::_::_, 0, _ => rfl
|
| _::_::_, 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")]
|
@[deprecated getElem_dropLast (since := "2024-06-12")]
|
||||||
theorem get_dropLast (xs : List α) (i : Fin xs.dropLast.length) :
|
theorem get_dropLast (xs : List α) (i : Fin xs.dropLast.length) :
|
||||||
@@ -3522,7 +3553,12 @@ theorem getElem?_eq (l : List α) (i : Nat) :
|
|||||||
getElem?_def _ _
|
getElem?_def _ _
|
||||||
@[deprecated getElem?_eq_none (since := "2024-11-29")] abbrev getElem?_len_le := @getElem?_eq_none
|
@[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 α} {n : Nat} : l[n]?.isNone ↔ l.length ≤ n := by
|
||||||
|
simp
|
||||||
|
|
||||||
end List
|
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]?
|
if h : i < arr.size then some arr[i] else Option.map (f i) l[i - arr.size]?
|
||||||
| [], arr, i => by
|
| [], arr, i => by
|
||||||
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
|
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
|
| a :: l, arr, i => by
|
||||||
rw [mapIdx.go, getElem?_mapIdx_go]
|
rw [mapIdx.go, getElem?_mapIdx_go]
|
||||||
simp only [Array.size_push]
|
simp only [Array.size_push]
|
||||||
split <;> split
|
split <;> split
|
||||||
· simp only [Option.some.injEq]
|
· simp only [Option.some.injEq]
|
||||||
rw [Array.getElem_eq_getElem_toList]
|
rw [← Array.getElem_toList]
|
||||||
simp only [Array.push_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
|
· have : i = arr.size := by omega
|
||||||
simp_all
|
simp_all
|
||||||
· omega
|
· omega
|
||||||
|
|||||||
@@ -841,7 +841,7 @@ theorem isPrefix_iff : l₁ <+: l₂ ↔ ∀ i (h : i < l₁.length), l₂[i]? =
|
|||||||
theorem isPrefix_iff_getElem {l₁ l₂ : List α} :
|
theorem isPrefix_iff_getElem {l₁ l₂ : List α} :
|
||||||
l₁ <+: l₂ ↔ ∃ (h : l₁.length ≤ l₂.length), ∀ x (hx : x < l₁.length),
|
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
|
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
|
mpr h := by
|
||||||
obtain ⟨hl, h⟩ := h
|
obtain ⟨hl, h⟩ := h
|
||||||
induction l₂ generalizing l₁ with
|
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),
|
theorem getElem_cons_drop : ∀ (l : List α) (i : Nat) (h : i < l.length),
|
||||||
l[i] :: drop (i + 1) l = drop i l
|
l[i] :: drop (i + 1) l = drop i l
|
||||||
| _::_, 0, _ => rfl
|
| _::_, 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")]
|
@[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
|
theorem get_cons_drop (l : List α) (i) : get l i :: drop (i + 1) l = drop i l := by
|
||||||
simp
|
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
|
(getElem_cons_drop _ n h).symm
|
||||||
|
|
||||||
@[deprecated drop_eq_getElem_cons (since := "2024-06-12")]
|
@[deprecated drop_eq_getElem_cons (since := "2024-06-12")]
|
||||||
|
|||||||
@@ -1,23 +1,374 @@
|
|||||||
/-
|
/-
|
||||||
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.
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
Authors: Henrik Böving
|
Authors: Mario Carneiro
|
||||||
-/
|
-/
|
||||||
prelude
|
prelude
|
||||||
import Init.Data.List.Basic
|
import Init.Data.List.Impl
|
||||||
|
import Init.Data.List.Nat.Erase
|
||||||
|
import Init.Data.List.Monadic
|
||||||
|
|
||||||
/--
|
/-! ### Lemmas about `List.toArray`.
|
||||||
Auxiliary definition for `List.toArray`.
|
|
||||||
`List.toArrayAux as r = r ++ as.toArray`
|
We prefer to pull `List.toArray` outwards past `Array` operations.
|
||||||
-/
|
-/
|
||||||
@[inline_if_reduce]
|
namespace List
|
||||||
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. -/
|
open Array
|
||||||
-- This function is exported to C, where it is called by `Array.mk`
|
|
||||||
-- (the constructor) to implement this functionality.
|
theorem toArray_inj {a b : List α} (h : a.toArray = b.toArray) : a = b := by
|
||||||
@[inline, match_pattern, pp_nodot, export lean_list_to_array]
|
cases a with
|
||||||
def List.toArrayImpl (as : List α) : Array α :=
|
| nil => simpa using h
|
||||||
as.toArrayAux (Array.mkEmpty as.length)
|
| 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]
|
||||||
|
|
||||||
|
@[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
|
||||||
|
|
||||||
|
@[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 `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]
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -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]
|
rw [shiftRight_add, shiftRight_eq_div_pow m k]
|
||||||
simp [Nat.div_div_eq_div_mul, ← Nat.pow_succ, shiftRight_succ]
|
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
|
### testBit
|
||||||
We define an operation for testing individual bits in the binary representation
|
We define an operation for testing individual bits in the binary representation
|
||||||
|
|||||||
@@ -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
|
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
|
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 :=
|
theorem dvd_mod_iff {k m n : Nat} (h: k ∣ n) : k ∣ m % n ↔ k ∣ m := by
|
||||||
have := Nat.dvd_add_iff_left <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
|
have := Nat.dvd_add_iff_left (m := m % n) <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
|
||||||
by rwa [mod_add_div] at this
|
rwa [mod_add_div] at this
|
||||||
|
|
||||||
theorem le_of_dvd {m n : Nat} (h : 0 < n) : m ∣ n → m ≤ n
|
theorem le_of_dvd {m n : Nat} (h : 0 < n) : m ∣ n → m ≤ n
|
||||||
| ⟨k, e⟩ => by
|
| ⟨k, e⟩ => by
|
||||||
|
|||||||
@@ -1046,6 +1046,25 @@ instance decidableExistsLE [DecidablePred p] : DecidablePred fun n => ∃ m : Na
|
|||||||
fun n => decidable_of_iff (∃ m, m < n + 1 ∧ p m)
|
fun n => decidable_of_iff (∃ m, m < n + 1 ∧ p m)
|
||||||
(exists_congr fun _ => and_congr_left' Nat.lt_succ_iff)
|
(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` -/
|
/-! ### 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
|
protected theorem sum_pos_iff_exists_pos {l : List Nat} : 0 < l.sum ↔ ∃ x ∈ l, 0 < x := by
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ import Init.Data.Option.Instances
|
|||||||
import Init.Data.Option.Lemmas
|
import Init.Data.Option.Lemmas
|
||||||
import Init.Data.Option.Attach
|
import Init.Data.Option.Attach
|
||||||
import Init.Data.Option.List
|
import Init.Data.Option.List
|
||||||
|
import Init.Data.Option.Monadic
|
||||||
|
|||||||
@@ -119,10 +119,14 @@ theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a
|
|||||||
· simp at h
|
· simp at h
|
||||||
· simp [get_some]
|
· 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
|
o.attach.toList = o.toList.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||||
cases o <;> simp
|
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 : α → β) :
|
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
|
(o.map f).attach = o.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem f h⟩) := by
|
||||||
cases o <;> simp
|
cases o <;> simp
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ satisfy `p`, using the proof to apply `f`.
|
|||||||
| none, _ => none
|
| none, _ => none
|
||||||
| some a, H => f a (H a rfl)
|
| 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`. -/
|
/-- Map a monadic function which returns `Unit` over an `Option`. -/
|
||||||
@[inline] protected def forM [Pure m] : Option α → (α → m PUnit) → m PUnit
|
@[inline] protected def forM [Pure m] : Option α → (α → m PUnit) → m PUnit
|
||||||
| none , _ => pure ⟨⟩
|
| none , _ => pure ⟨⟩
|
||||||
|
|||||||
@@ -629,4 +629,12 @@ theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → a ∈ o → Option
|
|||||||
· rintro ⟨h, rfl⟩
|
· rintro ⟨h, rfl⟩
|
||||||
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
|
end Option
|
||||||
|
|||||||
@@ -15,17 +15,25 @@ namespace Option
|
|||||||
forIn' none b f = pure b := by
|
forIn' none b f = pure b := by
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
@[simp] theorem forIn'_some [Monad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
@[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 | .done r | .yield r => pure r) := by
|
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
|
||||||
rfl
|
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 β)) :
|
@[simp] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||||
forIn none b f = pure b := by
|
forIn none b f = pure b := by
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
@[simp] theorem forIn_some [Monad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
@[simp] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||||
forIn (some a) b f = bind (f a b) (fun | .done r | .yield r => pure r) := by
|
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
|
||||||
rfl
|
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 β)) :
|
@[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
|
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
|
forIn o.toList b f = forIn o b f := by
|
||||||
cases o <;> rfl
|
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
|
end Option
|
||||||
|
|||||||
75
src/Init/Data/Option/Monadic.lean
Normal file
75
src/Init/Data/Option/Monadic.lean
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/-
|
||||||
|
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
|
||||||
|
|
||||||
|
@[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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
end Option
|
||||||
@@ -1,25 +1,39 @@
|
|||||||
/-
|
/-
|
||||||
Copyright (c) 2024 Lean FRO, LLC. All Rights Reserved.
|
Copyright (c) 2024 Lean FRO, LLC. All Rights Reserved.
|
||||||
Released under Apache 2.0 license as described in the file LICENSE.
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
Authors: Markus Himmel
|
Authors: Markus Himmel, Mac Malone
|
||||||
-/
|
-/
|
||||||
prelude
|
prelude
|
||||||
import Init.Data.UInt.Basic
|
import Init.Data.UInt.Lemmas
|
||||||
import Init.Data.Fin.Bitwise
|
import Init.Data.Fin.Bitwise
|
||||||
import Init.Data.BitVec.Lemmas
|
import Init.Data.BitVec.Lemmas
|
||||||
|
|
||||||
set_option hygiene false in
|
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
|
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
|
end $typeName
|
||||||
)
|
)
|
||||||
|
|
||||||
declare_bitwise_uint_theorems UInt8
|
declare_bitwise_uint_theorems UInt8 8
|
||||||
declare_bitwise_uint_theorems UInt16
|
declare_bitwise_uint_theorems UInt16 16
|
||||||
declare_bitwise_uint_theorems UInt32
|
declare_bitwise_uint_theorems UInt32 32
|
||||||
declare_bitwise_uint_theorems UInt64
|
declare_bitwise_uint_theorems UInt64 64
|
||||||
declare_bitwise_uint_theorems USize
|
declare_bitwise_uint_theorems USize System.Platform.numBits
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ import Init.Data.Vector.Basic
|
|||||||
Lemmas about `Vector α n`
|
Lemmas about `Vector α n`
|
||||||
-/
|
-/
|
||||||
|
|
||||||
|
namespace Array
|
||||||
|
|
||||||
|
theorem toVector_inj {a b : Array α} (h₁ : a.size = b.size) (h₂ : a.toVector.cast h₁ = b.toVector) : a = b := by
|
||||||
|
ext i ih₁ ih₂
|
||||||
|
· exact h₁
|
||||||
|
· simpa using congrArg (fun a => a[i]) h₂
|
||||||
|
|
||||||
|
end Array
|
||||||
|
|
||||||
namespace Vector
|
namespace Vector
|
||||||
|
|
||||||
@[simp] theorem getElem_mk {data : Array α} {size : data.size = n} {i : Nat} (h : i < n) :
|
@[simp] theorem getElem_mk {data : Array α} {size : data.size = n} {i : Nat} (h : i < n) :
|
||||||
@@ -115,6 +124,9 @@ theorem toArray_mk (a : Array α) (h : a.size = n) : (Vector.mk a h).toArray = a
|
|||||||
(Vector.mk a h).eraseIdx! i = Vector.mk (a.eraseIdx i) (by simp [h, hi]) := by
|
(Vector.mk a h).eraseIdx! i = Vector.mk (a.eraseIdx i) (by simp [h, hi]) := by
|
||||||
simp [Vector.eraseIdx!, hi]
|
simp [Vector.eraseIdx!, hi]
|
||||||
|
|
||||||
|
@[simp] theorem cast_mk (a : Array α) (h : a.size = n) (h' : n = m) :
|
||||||
|
(Vector.mk a h).cast h' = Vector.mk a (by simp [h, h']) := rfl
|
||||||
|
|
||||||
@[simp] theorem extract_mk (a : Array α) (h : a.size = n) (start stop) :
|
@[simp] theorem extract_mk (a : Array α) (h : a.size = n) (start stop) :
|
||||||
(Vector.mk a h).extract start stop = Vector.mk (a.extract start stop) (by simp [h]) := rfl
|
(Vector.mk a h).extract start stop = Vector.mk (a.extract start stop) (by simp [h]) := rfl
|
||||||
|
|
||||||
@@ -185,6 +197,9 @@ theorem toArray_mk (a : Array α) (h : a.size = n) : (Vector.mk a h).toArray = a
|
|||||||
(a.eraseIdx! i).toArray = a.toArray.eraseIdx! i := by
|
(a.eraseIdx! i).toArray = a.toArray.eraseIdx! i := by
|
||||||
cases a; simp_all [Array.eraseIdx!]
|
cases a; simp_all [Array.eraseIdx!]
|
||||||
|
|
||||||
|
@[simp] theorem toArray_cast (a : Vector α n) (h : n = m) :
|
||||||
|
(a.cast h).toArray = a.toArray := rfl
|
||||||
|
|
||||||
@[simp] theorem toArray_extract (a : Vector α n) (start stop) :
|
@[simp] theorem toArray_extract (a : Vector α n) (start stop) :
|
||||||
(a.extract start stop).toArray = a.toArray.extract start stop := rfl
|
(a.extract start stop).toArray = a.toArray.extract start stop := rfl
|
||||||
|
|
||||||
@@ -239,6 +254,137 @@ theorem length_toList {α n} (xs : Vector α n) : xs.toList.length = n := by sim
|
|||||||
theorem getElem_toList {α n} (xs : Vector α n) (i : Nat) (h : i < xs.toList.length) :
|
theorem getElem_toList {α n} (xs : Vector α n) (i : Nat) (h : i < xs.toList.length) :
|
||||||
xs.toList[i] = xs[i]'(by simpa using h) := by simp
|
xs.toList[i] = xs[i]'(by simpa using h) := by simp
|
||||||
|
|
||||||
|
theorem toList_inj {a b : Vector α n} (h : a.toList = b.toList) : a = b := by
|
||||||
|
rcases a with ⟨⟨a⟩, ha⟩
|
||||||
|
rcases b with ⟨⟨b⟩, hb⟩
|
||||||
|
simpa using h
|
||||||
|
|
||||||
|
/-! ### set -/
|
||||||
|
|
||||||
|
theorem getElem_set (a : Vector α n) (i : Nat) (x : α) (hi : i < n) (j : Nat) (hj : j < n) :
|
||||||
|
(a.set i x hi)[j] = if i = j then x else a[j] := by
|
||||||
|
cases a
|
||||||
|
split <;> simp_all [Array.getElem_set]
|
||||||
|
|
||||||
|
@[simp] theorem getElem_set_eq (a : Vector α n) (i : Nat) (x : α) (hi : i < n) :
|
||||||
|
(a.set i x hi)[i] = x := by simp [getElem_set]
|
||||||
|
|
||||||
|
@[simp] theorem getElem_set_ne (a : Vector α n) (i : Nat) (x : α) (hi : i < n) (j : Nat)
|
||||||
|
(hj : j < n) (h : i ≠ j) : (a.set i x hi)[j] = a[j] := by simp [getElem_set, h]
|
||||||
|
|
||||||
|
/-! ### setIfInBounds -/
|
||||||
|
|
||||||
|
theorem getElem_setIfInBounds (a : Vector α n) (i : Nat) (x : α) (j : Nat)
|
||||||
|
(hj : j < n) : (a.setIfInBounds i x)[j] = if i = j then x else a[j] := by
|
||||||
|
cases a
|
||||||
|
split <;> simp_all [Array.getElem_setIfInBounds]
|
||||||
|
|
||||||
|
@[simp] theorem getElem_setIfInBounds_eq (a : Vector α n) (i : Nat) (x : α) (hj : i < n) :
|
||||||
|
(a.setIfInBounds i x)[i] = x := by simp [getElem_setIfInBounds]
|
||||||
|
|
||||||
|
@[simp] theorem getElem_setIfInBounds_ne (a : Vector α n) (i : Nat) (x : α) (j : Nat)
|
||||||
|
(hj : j < n) (h : i ≠ j) : (a.setIfInBounds i x)[j] = a[j] := by simp [getElem_setIfInBounds, h]
|
||||||
|
|
||||||
|
/-! ### append -/
|
||||||
|
|
||||||
|
theorem getElem_append (a : Vector α n) (b : Vector α m) (i : Nat) (hi : i < n + m) :
|
||||||
|
(a ++ b)[i] = if h : i < n then a[i] else b[i - n] := by
|
||||||
|
rcases a with ⟨a, rfl⟩
|
||||||
|
rcases b with ⟨b, rfl⟩
|
||||||
|
simp [Array.getElem_append, hi]
|
||||||
|
|
||||||
|
theorem getElem_append_left {a : Vector α n} {b : Vector α m} {i : Nat} (hi : i < n) :
|
||||||
|
(a ++ b)[i] = a[i] := by simp [getElem_append, hi]
|
||||||
|
|
||||||
|
theorem getElem_append_right {a : Vector α n} {b : Vector α m} {i : Nat} (h : i < n + m) (hi : n ≤ i) :
|
||||||
|
(a ++ b)[i] = b[i - n] := by
|
||||||
|
rw [getElem_append, dif_neg (by omega)]
|
||||||
|
|
||||||
|
/-! ### cast -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_cast (a : Vector α n) (h : n = m) (i : Nat) (hi : i < m) :
|
||||||
|
(a.cast h)[i] = a[i] := by
|
||||||
|
cases a
|
||||||
|
simp
|
||||||
|
|
||||||
|
/-! ### extract -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_extract (a : Vector α n) (start stop) (i : Nat) (hi : i < min stop n - start) :
|
||||||
|
(a.extract start stop)[i] = a[start + i] := by
|
||||||
|
cases a
|
||||||
|
simp
|
||||||
|
|
||||||
|
/-! ### map -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_map (f : α → β) (a : Vector α n) (i : Nat) (hi : i < n) :
|
||||||
|
(a.map f)[i] = f a[i] := by
|
||||||
|
cases a
|
||||||
|
simp
|
||||||
|
|
||||||
|
/-! ### zipWith -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_zipWith (f : α → β → γ) (a : Vector α n) (b : Vector β n) (i : Nat)
|
||||||
|
(hi : i < n) : (zipWith a b f)[i] = f a[i] b[i] := by
|
||||||
|
cases a
|
||||||
|
cases b
|
||||||
|
simp
|
||||||
|
|
||||||
|
/-! ### swap -/
|
||||||
|
|
||||||
|
theorem getElem_swap (a : Vector α n) (i j : Nat) {hi hj} (k : Nat) (hk : k < n) :
|
||||||
|
(a.swap i j hi hj)[k] = if k = i then a[j] else if k = j then a[i] else a[k] := by
|
||||||
|
cases a
|
||||||
|
simp_all [Array.getElem_swap]
|
||||||
|
|
||||||
|
@[simp] theorem getElem_swap_right (a : Vector α n) {i j : Nat} {hi hj} :
|
||||||
|
(a.swap i j hi hj)[j]'(by simpa using hj) = a[i] := by
|
||||||
|
simp +contextual [getElem_swap]
|
||||||
|
|
||||||
|
@[simp] theorem getElem_swap_left (a : Vector α n) {i j : Nat} {hi hj} :
|
||||||
|
(a.swap i j hi hj)[i]'(by simpa using hi) = a[j] := by
|
||||||
|
simp [getElem_swap]
|
||||||
|
|
||||||
|
@[simp] theorem getElem_swap_of_ne (a : Vector α n) {i j : Nat} {hi hj} (hp : p < n)
|
||||||
|
(hi' : p ≠ i) (hj' : p ≠ j) : (a.swap i j hi hj)[p] = a[p] := by
|
||||||
|
simp_all [getElem_swap]
|
||||||
|
|
||||||
|
@[simp] theorem swap_swap (a : Vector α n) {i j : Nat} {hi hj} :
|
||||||
|
(a.swap i j hi hj).swap i j hi hj = a := by
|
||||||
|
cases a
|
||||||
|
simp_all [Array.swap_swap]
|
||||||
|
|
||||||
|
theorem swap_comm (a : Vector α n) {i j : Nat} {hi hj} :
|
||||||
|
a.swap i j hi hj = a.swap j i hj hi := by
|
||||||
|
cases a
|
||||||
|
simp only [swap_mk, mk.injEq]
|
||||||
|
rw [Array.swap_comm]
|
||||||
|
|
||||||
|
/-! ### range -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_range (i : Nat) (hi : i < n) : (Vector.range n)[i] = i := by
|
||||||
|
simp [Vector.range]
|
||||||
|
|
||||||
|
/-! ### take -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_take (a : Vector α n) (m : Nat) (hi : i < min n m) :
|
||||||
|
(a.take m)[i] = a[i] := by
|
||||||
|
cases a
|
||||||
|
simp
|
||||||
|
|
||||||
|
/-! ### drop -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_drop (a : Vector α n) (m : Nat) (hi : i < n - m) :
|
||||||
|
(a.drop m)[i] = a[m + i] := by
|
||||||
|
cases a
|
||||||
|
simp
|
||||||
|
|
||||||
|
/-! ### reverse -/
|
||||||
|
|
||||||
|
@[simp] theorem getElem_reverse (a : Vector α n) (i : Nat) (hi : i < n) :
|
||||||
|
(a.reverse)[i] = a[n - 1 - i] := by
|
||||||
|
rcases a with ⟨a, rfl⟩
|
||||||
|
simp
|
||||||
|
|
||||||
/-! ### Decidable quantifiers. -/
|
/-! ### Decidable quantifiers. -/
|
||||||
|
|
||||||
theorem forall_zero_iff {P : Vector α 0 → Prop} :
|
theorem forall_zero_iff {P : Vector α 0 → Prop} :
|
||||||
|
|||||||
@@ -118,12 +118,16 @@ instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (v
|
|||||||
GetElem? coll idx elem valid where
|
GetElem? coll idx elem valid where
|
||||||
getElem? xs i := decidableGetElem? xs i
|
getElem? xs i := decidableGetElem? xs i
|
||||||
|
|
||||||
theorem getElem_congr_coll [GetElem coll idx elem valid] {c d : coll} {i : idx} {h : valid c i}
|
theorem getElem_congr [GetElem coll idx elem valid] {c d : coll} (h : c = d)
|
||||||
(h' : c = d) : c[i] = d[i]'(h' ▸ h) := by
|
{i j : idx} (h' : i = j) (w : valid c i) : c[i] = d[j]'(h' ▸ h ▸ w) := by
|
||||||
cases h'; rfl
|
cases h; cases h'; rfl
|
||||||
|
|
||||||
theorem getElem_congr [GetElem coll idx elem valid] {c : coll} {i j : idx} {h : valid c i}
|
theorem getElem_congr_coll [GetElem coll idx elem valid] {c d : coll} {i : idx} {w : valid c i}
|
||||||
(h' : i = j) : c[i] = c[j]'(h' ▸ h) := by
|
(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
|
cases h'; rfl
|
||||||
|
|
||||||
class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
|
class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||||
@@ -216,13 +220,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
|
@[simp] theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a := by
|
||||||
rfl
|
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
|
@[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
|
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
|
@[simp] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||||
| _ :: _, 0, _ => .head ..
|
| _ :: _, 0, _ => .head ..
|
||||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||||
@@ -231,7 +231,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 :=
|
as[i] :: as.drop (i+1) = as.drop i :=
|
||||||
match as, i with
|
match as, i with
|
||||||
| _::_, 0 => rfl
|
| _::_, 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")]
|
@[deprecated getElem_cons_drop_succ_eq_drop (since := "2024-11-05")]
|
||||||
abbrev get_drop_eq_drop := @getElem_cons_drop_succ_eq_drop
|
abbrev get_drop_eq_drop := @getElem_cons_drop_succ_eq_drop
|
||||||
@@ -243,6 +243,12 @@ namespace Array
|
|||||||
instance : GetElem (Array α) Nat α fun xs i => i < xs.size where
|
instance : GetElem (Array α) Nat α fun xs i => i < xs.size where
|
||||||
getElem xs i h := xs.get i h
|
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
|
end Array
|
||||||
|
|
||||||
namespace Lean.Syntax
|
namespace Lean.Syntax
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ private partial def decodeBinLitAux (s : String) (i : String.Pos) (val : Nat) :
|
|||||||
let c := s.get i
|
let c := s.get i
|
||||||
if c == '0' then decodeBinLitAux s (s.next i) (2*val)
|
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 == '1' then decodeBinLitAux s (s.next i) (2*val + 1)
|
||||||
|
else if c == '_' then decodeBinLitAux s (s.next i) val
|
||||||
else none
|
else none
|
||||||
|
|
||||||
private partial def decodeOctalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
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
|
else
|
||||||
let c := s.get i
|
let c := s.get i
|
||||||
if '0' ≤ c && c ≤ '7' then decodeOctalLitAux s (s.next i) (8*val + c.toNat - '0'.toNat)
|
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
|
else none
|
||||||
|
|
||||||
private def decodeHexDigit (s : String) (i : String.Pos) : Option (Nat × String.Pos) :=
|
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
|
if s.atEnd i then some val
|
||||||
else match decodeHexDigit s i with
|
else match decodeHexDigit s i with
|
||||||
| some (d, i) => decodeHexLitAux s i (16*val + d)
|
| 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 :=
|
private partial def decodeDecimalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
|
||||||
if s.atEnd i then some val
|
if s.atEnd i then some val
|
||||||
else
|
else
|
||||||
let c := s.get i
|
let c := s.get i
|
||||||
if '0' ≤ c && c ≤ '9' then decodeDecimalLitAux s (s.next i) (10*val + c.toNat - '0'.toNat)
|
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
|
else none
|
||||||
|
|
||||||
def decodeNatLitVal? (s : String) : Option Nat :=
|
def decodeNatLitVal? (s : String) : Option Nat :=
|
||||||
@@ -773,6 +778,8 @@ where
|
|||||||
let c := s.get i
|
let c := s.get i
|
||||||
if '0' ≤ c && c ≤ '9' then
|
if '0' ≤ c && c ≤ '9' then
|
||||||
decodeAfterExp (s.next i) val e sign (10*exp + c.toNat - '0'.toNat)
|
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
|
else
|
||||||
none
|
none
|
||||||
|
|
||||||
@@ -793,6 +800,8 @@ where
|
|||||||
let c := s.get i
|
let c := s.get i
|
||||||
if '0' ≤ c && c ≤ '9' then
|
if '0' ≤ c && c ≤ '9' then
|
||||||
decodeAfterDot (s.next i) (10*val + c.toNat - '0'.toNat) (e+1)
|
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
|
else if c == 'e' || c == 'E' then
|
||||||
decodeExp (s.next i) val e
|
decodeExp (s.next i) val e
|
||||||
else
|
else
|
||||||
@@ -805,6 +814,8 @@ where
|
|||||||
let c := s.get i
|
let c := s.get i
|
||||||
if '0' ≤ c && c ≤ '9' then
|
if '0' ≤ c && c ≤ '9' then
|
||||||
decode (s.next i) (10*val + c.toNat - '0'.toNat)
|
decode (s.next i) (10*val + c.toNat - '0'.toNat)
|
||||||
|
else if c == '_' then
|
||||||
|
decode (s.next i) val
|
||||||
else if c == '.' then
|
else if c == '.' then
|
||||||
decodeAfterDot (s.next i) val 0
|
decodeAfterDot (s.next i) val 0
|
||||||
else if c == 'e' || c == 'E' then
|
else if c == 'e' || c == 'E' then
|
||||||
|
|||||||
@@ -250,6 +250,13 @@ def neutralConfig : Simp.Config := {
|
|||||||
zetaDelta := false
|
zetaDelta := false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
structure NormCastConfig extends Simp.Config where
|
||||||
|
zeta := false
|
||||||
|
beta := false
|
||||||
|
eta := false
|
||||||
|
proj := false
|
||||||
|
iota := false
|
||||||
|
|
||||||
end Simp
|
end Simp
|
||||||
|
|
||||||
/-- Configuration for which occurrences that match an expression should be rewritten. -/
|
/-- Configuration for which occurrences that match an expression should be rewritten. -/
|
||||||
|
|||||||
@@ -386,6 +386,15 @@ theorem exists_comm {p : α → β → Prop} : (∃ a b, p a b) ↔ (∃ b a, p
|
|||||||
theorem forall_prop_of_false {p : Prop} {q : p → Prop} (hn : ¬p) : (∀ h' : p, q h') ↔ True :=
|
theorem forall_prop_of_false {p : Prop} {q : p → Prop} (hn : ¬p) : (∀ h' : p, q h') ↔ True :=
|
||||||
iff_true_intro fun h => hn.elim h
|
iff_true_intro fun h => hn.elim h
|
||||||
|
|
||||||
|
@[simp] theorem and_exists_self (P : Prop) (Q : P → Prop) : (P ∧ ∃ p, Q p) ↔ ∃ p, Q p :=
|
||||||
|
⟨fun ⟨_, h⟩ => h, fun ⟨p, q⟩ => ⟨p, ⟨p, q⟩⟩⟩
|
||||||
|
|
||||||
|
@[simp] theorem exists_and_self (P : Prop) (Q : P → Prop) : ((∃ p, Q p) ∧ P) ↔ ∃ p, Q p :=
|
||||||
|
⟨fun ⟨h, _⟩ => h, fun ⟨p, q⟩ => ⟨⟨p, q⟩, p⟩⟩
|
||||||
|
|
||||||
|
@[simp] theorem forall_self_imp (P : Prop) (Q : P → Prop) : (∀ p : P, P → Q p) ↔ ∀ p, Q p :=
|
||||||
|
⟨fun h p => h p p, fun h _ p => h p⟩
|
||||||
|
|
||||||
end quantifiers
|
end quantifiers
|
||||||
|
|
||||||
/-! ## membership -/
|
/-! ## membership -/
|
||||||
|
|||||||
@@ -981,3 +981,14 @@ not used concurrently or which are already persistent.
|
|||||||
-/
|
-/
|
||||||
@[extern "lean_runtime_mark_persistent"]
|
@[extern "lean_runtime_mark_persistent"]
|
||||||
unsafe def Runtime.markPersistent (a : α) : BaseIO α := return a
|
unsafe def Runtime.markPersistent (a : α) : BaseIO α := return a
|
||||||
|
|
||||||
|
set_option linter.unusedVariables false in
|
||||||
|
/--
|
||||||
|
Discards the passed owned reference. This leads to `a` any any object reachable from it never being
|
||||||
|
freed. This can be a useful optimization for eliding deallocation time of big object graphs that are
|
||||||
|
kept alive close to the end of the process anyway (in which case calling `Runtime.markPersistent`
|
||||||
|
would be similarly costly to deallocation). It is still considered a safe operation as it cannot
|
||||||
|
lead to undefined behavior.
|
||||||
|
-/
|
||||||
|
@[extern "lean_runtime_forget"]
|
||||||
|
def Runtime.forget (a : α) : BaseIO Unit := return
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ prelude
|
|||||||
import Init.System.IO
|
import Init.System.IO
|
||||||
import Init.Control.StateRef
|
import Init.Control.StateRef
|
||||||
|
|
||||||
|
|
||||||
|
set_option linter.deprecated false
|
||||||
|
|
||||||
namespace IO
|
namespace IO
|
||||||
|
|
||||||
private opaque BaseMutexImpl : NonemptyType.{0}
|
private opaque BaseMutexImpl : NonemptyType.{0}
|
||||||
@@ -16,12 +19,13 @@ Mutual exclusion primitive (a lock).
|
|||||||
|
|
||||||
If you want to guard shared state, use `Mutex α` instead.
|
If you want to guard shared state, use `Mutex α` instead.
|
||||||
-/
|
-/
|
||||||
|
@[deprecated "Use Std.BaseMutex from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
def BaseMutex : Type := BaseMutexImpl.type
|
def BaseMutex : Type := BaseMutexImpl.type
|
||||||
|
|
||||||
instance : Nonempty BaseMutex := BaseMutexImpl.property
|
instance : Nonempty BaseMutex := BaseMutexImpl.property
|
||||||
|
|
||||||
/-- Creates a new `BaseMutex`. -/
|
/-- Creates a new `BaseMutex`. -/
|
||||||
@[extern "lean_io_basemutex_new"]
|
@[extern "lean_io_basemutex_new", deprecated "Use Std.BaseMutex.new from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
opaque BaseMutex.new : BaseIO BaseMutex
|
opaque BaseMutex.new : BaseIO BaseMutex
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -30,7 +34,7 @@ Locks a `BaseMutex`. Waits until no other thread has locked the mutex.
|
|||||||
The current thread must not have already locked the mutex.
|
The current thread must not have already locked the mutex.
|
||||||
Reentrant locking is undefined behavior (inherited from the C++ implementation).
|
Reentrant locking is undefined behavior (inherited from the C++ implementation).
|
||||||
-/
|
-/
|
||||||
@[extern "lean_io_basemutex_lock"]
|
@[extern "lean_io_basemutex_lock", deprecated "Use Std.BaseMutex.lock from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
opaque BaseMutex.lock (mutex : @& BaseMutex) : BaseIO Unit
|
opaque BaseMutex.lock (mutex : @& BaseMutex) : BaseIO Unit
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -39,33 +43,35 @@ Unlocks a `BaseMutex`.
|
|||||||
The current thread must have already locked the mutex.
|
The current thread must have already locked the mutex.
|
||||||
Unlocking an unlocked mutex is undefined behavior (inherited from the C++ implementation).
|
Unlocking an unlocked mutex is undefined behavior (inherited from the C++ implementation).
|
||||||
-/
|
-/
|
||||||
@[extern "lean_io_basemutex_unlock"]
|
@[extern "lean_io_basemutex_unlock", deprecated "Use Std.BaseMutex.unlock from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
opaque BaseMutex.unlock (mutex : @& BaseMutex) : BaseIO Unit
|
opaque BaseMutex.unlock (mutex : @& BaseMutex) : BaseIO Unit
|
||||||
|
|
||||||
private opaque CondvarImpl : NonemptyType.{0}
|
private opaque CondvarImpl : NonemptyType.{0}
|
||||||
|
|
||||||
/-- Condition variable. -/
|
/-- Condition variable. -/
|
||||||
|
@[deprecated "Use Std.Condvar from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
def Condvar : Type := CondvarImpl.type
|
def Condvar : Type := CondvarImpl.type
|
||||||
|
|
||||||
instance : Nonempty Condvar := CondvarImpl.property
|
instance : Nonempty Condvar := CondvarImpl.property
|
||||||
|
|
||||||
/-- Creates a new condition variable. -/
|
/-- Creates a new condition variable. -/
|
||||||
@[extern "lean_io_condvar_new"]
|
@[extern "lean_io_condvar_new", deprecated "Use Std.Condvar.new from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
opaque Condvar.new : BaseIO Condvar
|
opaque Condvar.new : BaseIO Condvar
|
||||||
|
|
||||||
/-- Waits until another thread calls `notifyOne` or `notifyAll`. -/
|
/-- Waits until another thread calls `notifyOne` or `notifyAll`. -/
|
||||||
@[extern "lean_io_condvar_wait"]
|
@[extern "lean_io_condvar_wait", deprecated "Use Std.Condvar.wait from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
opaque Condvar.wait (condvar : @& Condvar) (mutex : @& BaseMutex) : BaseIO Unit
|
opaque Condvar.wait (condvar : @& Condvar) (mutex : @& BaseMutex) : BaseIO Unit
|
||||||
|
|
||||||
/-- Wakes up a single other thread executing `wait`. -/
|
/-- Wakes up a single other thread executing `wait`. -/
|
||||||
@[extern "lean_io_condvar_notify_one"]
|
@[extern "lean_io_condvar_notify_one", deprecated "Use Std.Condvar.notifyOne from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
opaque Condvar.notifyOne (condvar : @& Condvar) : BaseIO Unit
|
opaque Condvar.notifyOne (condvar : @& Condvar) : BaseIO Unit
|
||||||
|
|
||||||
/-- Wakes up all other threads executing `wait`. -/
|
/-- Wakes up all other threads executing `wait`. -/
|
||||||
@[extern "lean_io_condvar_notify_all"]
|
@[extern "lean_io_condvar_notify_all", deprecated "Use Std.Condvar.notifyAll from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
opaque Condvar.notifyAll (condvar : @& Condvar) : BaseIO Unit
|
opaque Condvar.notifyAll (condvar : @& Condvar) : BaseIO Unit
|
||||||
|
|
||||||
/-- Waits on the condition variable until the predicate is true. -/
|
/-- Waits on the condition variable until the predicate is true. -/
|
||||||
|
@[deprecated "Use Std.Condvar.waitUntil from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
def Condvar.waitUntil [Monad m] [MonadLift BaseIO m]
|
def Condvar.waitUntil [Monad m] [MonadLift BaseIO m]
|
||||||
(condvar : Condvar) (mutex : BaseMutex) (pred : m Bool) : m Unit := do
|
(condvar : Condvar) (mutex : BaseMutex) (pred : m Bool) : m Unit := do
|
||||||
while !(← pred) do
|
while !(← pred) do
|
||||||
@@ -78,6 +84,7 @@ The type `Mutex α` is similar to `IO.Ref α`,
|
|||||||
except that concurrent accesses are guarded by a mutex
|
except that concurrent accesses are guarded by a mutex
|
||||||
instead of atomic pointer operations and busy-waiting.
|
instead of atomic pointer operations and busy-waiting.
|
||||||
-/
|
-/
|
||||||
|
@[deprecated "Use Std.Mutex from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
structure Mutex (α : Type) where private mk ::
|
structure Mutex (α : Type) where private mk ::
|
||||||
private ref : IO.Ref α
|
private ref : IO.Ref α
|
||||||
mutex : BaseMutex
|
mutex : BaseMutex
|
||||||
@@ -86,6 +93,7 @@ structure Mutex (α : Type) where private mk ::
|
|||||||
instance : CoeOut (Mutex α) BaseMutex where coe := Mutex.mutex
|
instance : CoeOut (Mutex α) BaseMutex where coe := Mutex.mutex
|
||||||
|
|
||||||
/-- Creates a new mutex. -/
|
/-- Creates a new mutex. -/
|
||||||
|
@[deprecated "Use Std.Mutex.new from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
def Mutex.new (a : α) : BaseIO (Mutex α) :=
|
def Mutex.new (a : α) : BaseIO (Mutex α) :=
|
||||||
return { ref := ← mkRef a, mutex := ← BaseMutex.new }
|
return { ref := ← mkRef a, mutex := ← BaseMutex.new }
|
||||||
|
|
||||||
@@ -94,9 +102,11 @@ def Mutex.new (a : α) : BaseIO (Mutex α) :=
|
|||||||
with outside monad `m`.
|
with outside monad `m`.
|
||||||
The action has access to the state `α` of the mutex (via `get` and `set`).
|
The action has access to the state `α` of the mutex (via `get` and `set`).
|
||||||
-/
|
-/
|
||||||
|
@[deprecated "Use Std.AtomicT from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
abbrev AtomicT := StateRefT' IO.RealWorld
|
abbrev AtomicT := StateRefT' IO.RealWorld
|
||||||
|
|
||||||
/-- `mutex.atomically k` runs `k` with access to the mutex's state while locking the mutex. -/
|
/-- `mutex.atomically k` runs `k` with access to the mutex's state while locking the mutex. -/
|
||||||
|
@[deprecated "Use Std.Mutex.atomically from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
def Mutex.atomically [Monad m] [MonadLiftT BaseIO m] [MonadFinally m]
|
def Mutex.atomically [Monad m] [MonadLiftT BaseIO m] [MonadFinally m]
|
||||||
(mutex : Mutex α) (k : AtomicT α m β) : m β := do
|
(mutex : Mutex α) (k : AtomicT α m β) : m β := do
|
||||||
try
|
try
|
||||||
@@ -110,6 +120,7 @@ def Mutex.atomically [Monad m] [MonadLiftT BaseIO m] [MonadFinally m]
|
|||||||
waiting on `condvar` until `pred` returns true.
|
waiting on `condvar` until `pred` returns true.
|
||||||
Both `k` and `pred` have access to the mutex's state.
|
Both `k` and `pred` have access to the mutex's state.
|
||||||
-/
|
-/
|
||||||
|
@[deprecated "Use Std.Mutex.atomicallyOnce from Std.Sync.Mutex instead" (since := "2024-12-02")]
|
||||||
def Mutex.atomicallyOnce [Monad m] [MonadLiftT BaseIO m] [MonadFinally m]
|
def Mutex.atomicallyOnce [Monad m] [MonadLiftT BaseIO m] [MonadFinally m]
|
||||||
(mutex : Mutex α) (condvar : Condvar)
|
(mutex : Mutex α) (condvar : Condvar)
|
||||||
(pred : AtomicT α m Bool) (k : AtomicT α m β) : m β :=
|
(pred : AtomicT α m Bool) (k : AtomicT α m β) : m β :=
|
||||||
|
|||||||
@@ -1309,7 +1309,7 @@ macro "bv_omega" : tactic => `(tactic| (try simp only [bv_toNat] at *) <;> omega
|
|||||||
syntax (name := acNf0) "ac_nf0" (location)? : tactic
|
syntax (name := acNf0) "ac_nf0" (location)? : tactic
|
||||||
|
|
||||||
/-- Implementation of `norm_cast` (the full `norm_cast` calls `trivial` afterwards). -/
|
/-- Implementation of `norm_cast` (the full `norm_cast` calls `trivial` afterwards). -/
|
||||||
syntax (name := normCast0) "norm_cast0" (location)? : tactic
|
syntax (name := normCast0) "norm_cast0" optConfig (location)? : tactic
|
||||||
|
|
||||||
/-- `assumption_mod_cast` is a variant of `assumption` that solves the goal
|
/-- `assumption_mod_cast` is a variant of `assumption` that solves the goal
|
||||||
using a hypothesis. Unlike `assumption`, it first pre-processes the goal and
|
using a hypothesis. Unlike `assumption`, it first pre-processes the goal and
|
||||||
@@ -1318,7 +1318,7 @@ in more situations.
|
|||||||
|
|
||||||
Concretely, it runs `norm_cast` on the goal. For each local hypothesis `h`, it also
|
Concretely, it runs `norm_cast` on the goal. For each local hypothesis `h`, it also
|
||||||
normalizes `h` with `norm_cast` and tries to use that to close the goal. -/
|
normalizes `h` with `norm_cast` and tries to use that to close the goal. -/
|
||||||
macro "assumption_mod_cast" : tactic => `(tactic| norm_cast0 at * <;> assumption)
|
macro "assumption_mod_cast" cfg:optConfig : tactic => `(tactic| norm_cast0 $cfg at * <;> assumption)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
The `norm_cast` family of tactics is used to normalize certain coercions (*casts*) in expressions.
|
The `norm_cast` family of tactics is used to normalize certain coercions (*casts*) in expressions.
|
||||||
@@ -1355,26 +1355,9 @@ their operation, to make them more flexible about the expressions they accept
|
|||||||
|
|
||||||
See also `push_cast`, which moves casts inwards rather than lifting them outwards.
|
See also `push_cast`, which moves casts inwards rather than lifting them outwards.
|
||||||
-/
|
-/
|
||||||
macro "norm_cast" loc:(location)? : tactic =>
|
macro "norm_cast" cfg:optConfig loc:(location)? : tactic =>
|
||||||
`(tactic| norm_cast0 $[$loc]? <;> try trivial)
|
`(tactic| norm_cast0 $cfg $[$loc]? <;> try trivial)
|
||||||
|
|
||||||
/--
|
|
||||||
`ac_nf` normalizes equalities up to application of an associative and commutative operator.
|
|
||||||
- `ac_nf` normalizes all hypotheses and the goal target of the goal.
|
|
||||||
- `ac_nf at l` normalizes at location(s) `l`, where `l` is either `*` or a
|
|
||||||
list of hypotheses in the local context. In the latter case, a turnstile `⊢` or `|-`
|
|
||||||
can also be used, to signify the target of the goal.
|
|
||||||
```
|
|
||||||
instance : Associative (α := Nat) (.+.) := ⟨Nat.add_assoc⟩
|
|
||||||
instance : Commutative (α := Nat) (.+.) := ⟨Nat.add_comm⟩
|
|
||||||
|
|
||||||
example (a b c d : Nat) : a + b + c + d = d + (b + c) + a := by
|
|
||||||
ac_nf
|
|
||||||
-- goal: a + (b + (c + d)) = a + (b + (c + d))
|
|
||||||
```
|
|
||||||
-/
|
|
||||||
macro "ac_nf" loc:(location)? : tactic =>
|
|
||||||
`(tactic| ac_nf0 $[$loc]? <;> try trivial)
|
|
||||||
|
|
||||||
/--
|
/--
|
||||||
`push_cast` rewrites the goal to move certain coercions (*casts*) inward, toward the leaf nodes.
|
`push_cast` rewrites the goal to move certain coercions (*casts*) inward, toward the leaf nodes.
|
||||||
@@ -1417,6 +1400,24 @@ syntax (name := pushCast) "push_cast" optConfig (discharger)? (&" only")?
|
|||||||
-/
|
-/
|
||||||
syntax (name := normCastAddElim) "norm_cast_add_elim" ident : command
|
syntax (name := normCastAddElim) "norm_cast_add_elim" ident : command
|
||||||
|
|
||||||
|
/--
|
||||||
|
`ac_nf` normalizes equalities up to application of an associative and commutative operator.
|
||||||
|
- `ac_nf` normalizes all hypotheses and the goal target of the goal.
|
||||||
|
- `ac_nf at l` normalizes at location(s) `l`, where `l` is either `*` or a
|
||||||
|
list of hypotheses in the local context. In the latter case, a turnstile `⊢` or `|-`
|
||||||
|
can also be used, to signify the target of the goal.
|
||||||
|
```
|
||||||
|
instance : Associative (α := Nat) (.+.) := ⟨Nat.add_assoc⟩
|
||||||
|
instance : Commutative (α := Nat) (.+.) := ⟨Nat.add_comm⟩
|
||||||
|
|
||||||
|
example (a b c d : Nat) : a + b + c + d = d + (b + c) + a := by
|
||||||
|
ac_nf
|
||||||
|
-- goal: a + (b + (c + d)) = a + (b + (c + d))
|
||||||
|
```
|
||||||
|
-/
|
||||||
|
macro "ac_nf" loc:(location)? : tactic =>
|
||||||
|
`(tactic| ac_nf0 $[$loc]? <;> try trivial)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
* `symm` applies to a goal whose target has the form `t ~ u` where `~` is a symmetric relation,
|
* `symm` applies to a goal whose target has the form `t ~ u` where `~` is a symmetric relation,
|
||||||
that is, a relation which has a symmetry lemma tagged with the attribute [symm].
|
that is, a relation which has a symmetry lemma tagged with the attribute [symm].
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ then one of the following must hold in each (execution) branch.
|
|||||||
inductive IRType where
|
inductive IRType where
|
||||||
| float | uint8 | uint16 | uint32 | uint64 | usize
|
| float | uint8 | uint16 | uint32 | uint64 | usize
|
||||||
| irrelevant | object | tobject
|
| irrelevant | object | tobject
|
||||||
|
| float32
|
||||||
| struct (leanTypeName : Option Name) (types : Array IRType) : IRType
|
| struct (leanTypeName : Option Name) (types : Array IRType) : IRType
|
||||||
| union (leanTypeName : Name) (types : Array IRType) : IRType
|
| union (leanTypeName : Name) (types : Array IRType) : IRType
|
||||||
deriving Inhabited, Repr
|
deriving Inhabited, Repr
|
||||||
@@ -89,6 +90,7 @@ namespace IRType
|
|||||||
|
|
||||||
partial def beq : IRType → IRType → Bool
|
partial def beq : IRType → IRType → Bool
|
||||||
| float, float => true
|
| float, float => true
|
||||||
|
| float32, float32 => true
|
||||||
| uint8, uint8 => true
|
| uint8, uint8 => true
|
||||||
| uint16, uint16 => true
|
| uint16, uint16 => true
|
||||||
| uint32, uint32 => true
|
| uint32, uint32 => true
|
||||||
@@ -104,13 +106,14 @@ partial def beq : IRType → IRType → Bool
|
|||||||
instance : BEq IRType := ⟨beq⟩
|
instance : BEq IRType := ⟨beq⟩
|
||||||
|
|
||||||
def isScalar : IRType → Bool
|
def isScalar : IRType → Bool
|
||||||
| float => true
|
| float => true
|
||||||
| uint8 => true
|
| float32 => true
|
||||||
| uint16 => true
|
| uint8 => true
|
||||||
| uint32 => true
|
| uint16 => true
|
||||||
| uint64 => true
|
| uint32 => true
|
||||||
| usize => true
|
| uint64 => true
|
||||||
| _ => false
|
| usize => true
|
||||||
|
| _ => false
|
||||||
|
|
||||||
def isObj : IRType → Bool
|
def isObj : IRType → Bool
|
||||||
| object => true
|
| object => true
|
||||||
@@ -611,10 +614,11 @@ def mkIf (x : VarId) (t e : FnBody) : FnBody :=
|
|||||||
|
|
||||||
def getUnboxOpName (t : IRType) : String :=
|
def getUnboxOpName (t : IRType) : String :=
|
||||||
match t with
|
match t with
|
||||||
| IRType.usize => "lean_unbox_usize"
|
| IRType.usize => "lean_unbox_usize"
|
||||||
| IRType.uint32 => "lean_unbox_uint32"
|
| IRType.uint32 => "lean_unbox_uint32"
|
||||||
| IRType.uint64 => "lean_unbox_uint64"
|
| IRType.uint64 => "lean_unbox_uint64"
|
||||||
| IRType.float => "lean_unbox_float"
|
| IRType.float => "lean_unbox_float"
|
||||||
| _ => "lean_unbox"
|
| IRType.float32 => "lean_unbox_float32"
|
||||||
|
| _ => "lean_unbox"
|
||||||
|
|
||||||
end Lean.IR
|
end Lean.IR
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ def emitArg (x : Arg) : M Unit :=
|
|||||||
|
|
||||||
def toCType : IRType → String
|
def toCType : IRType → String
|
||||||
| IRType.float => "double"
|
| IRType.float => "double"
|
||||||
|
| IRType.float32 => "float"
|
||||||
| IRType.uint8 => "uint8_t"
|
| IRType.uint8 => "uint8_t"
|
||||||
| IRType.uint16 => "uint16_t"
|
| IRType.uint16 => "uint16_t"
|
||||||
| IRType.uint32 => "uint32_t"
|
| IRType.uint32 => "uint32_t"
|
||||||
@@ -311,12 +312,13 @@ def emitUSet (x : VarId) (n : Nat) (y : VarId) : M Unit := do
|
|||||||
|
|
||||||
def emitSSet (x : VarId) (n : Nat) (offset : Nat) (y : VarId) (t : IRType) : M Unit := do
|
def emitSSet (x : VarId) (n : Nat) (offset : Nat) (y : VarId) (t : IRType) : M Unit := do
|
||||||
match t with
|
match t with
|
||||||
| IRType.float => emit "lean_ctor_set_float"
|
| IRType.float => emit "lean_ctor_set_float"
|
||||||
| IRType.uint8 => emit "lean_ctor_set_uint8"
|
| IRType.float32 => emit "lean_ctor_set_float32"
|
||||||
| IRType.uint16 => emit "lean_ctor_set_uint16"
|
| IRType.uint8 => emit "lean_ctor_set_uint8"
|
||||||
| IRType.uint32 => emit "lean_ctor_set_uint32"
|
| IRType.uint16 => emit "lean_ctor_set_uint16"
|
||||||
| IRType.uint64 => emit "lean_ctor_set_uint64"
|
| IRType.uint32 => emit "lean_ctor_set_uint32"
|
||||||
| _ => throw "invalid instruction";
|
| IRType.uint64 => emit "lean_ctor_set_uint64"
|
||||||
|
| _ => throw "invalid instruction";
|
||||||
emit "("; emit x; emit ", "; emitOffset n offset; emit ", "; emit y; emitLn ");"
|
emit "("; emit x; emit ", "; emitOffset n offset; emit ", "; emit y; emitLn ");"
|
||||||
|
|
||||||
def emitJmp (j : JoinPointId) (xs : Array Arg) : M Unit := do
|
def emitJmp (j : JoinPointId) (xs : Array Arg) : M Unit := do
|
||||||
@@ -386,12 +388,13 @@ def emitUProj (z : VarId) (i : Nat) (x : VarId) : M Unit := do
|
|||||||
def emitSProj (z : VarId) (t : IRType) (n offset : Nat) (x : VarId) : M Unit := do
|
def emitSProj (z : VarId) (t : IRType) (n offset : Nat) (x : VarId) : M Unit := do
|
||||||
emitLhs z;
|
emitLhs z;
|
||||||
match t with
|
match t with
|
||||||
| IRType.float => emit "lean_ctor_get_float"
|
| IRType.float => emit "lean_ctor_get_float"
|
||||||
| IRType.uint8 => emit "lean_ctor_get_uint8"
|
| IRType.float32 => emit "lean_ctor_get_float32"
|
||||||
| IRType.uint16 => emit "lean_ctor_get_uint16"
|
| IRType.uint8 => emit "lean_ctor_get_uint8"
|
||||||
| IRType.uint32 => emit "lean_ctor_get_uint32"
|
| IRType.uint16 => emit "lean_ctor_get_uint16"
|
||||||
| IRType.uint64 => emit "lean_ctor_get_uint64"
|
| IRType.uint32 => emit "lean_ctor_get_uint32"
|
||||||
| _ => throw "invalid instruction"
|
| IRType.uint64 => emit "lean_ctor_get_uint64"
|
||||||
|
| _ => throw "invalid instruction"
|
||||||
emit "("; emit x; emit ", "; emitOffset n offset; emitLn ");"
|
emit "("; emit x; emit ", "; emitOffset n offset; emitLn ");"
|
||||||
|
|
||||||
def toStringArgs (ys : Array Arg) : List String :=
|
def toStringArgs (ys : Array Arg) : List String :=
|
||||||
@@ -446,11 +449,12 @@ def emitApp (z : VarId) (f : VarId) (ys : Array Arg) : M Unit :=
|
|||||||
|
|
||||||
def emitBoxFn (xType : IRType) : M Unit :=
|
def emitBoxFn (xType : IRType) : M Unit :=
|
||||||
match xType with
|
match xType with
|
||||||
| IRType.usize => emit "lean_box_usize"
|
| IRType.usize => emit "lean_box_usize"
|
||||||
| IRType.uint32 => emit "lean_box_uint32"
|
| IRType.uint32 => emit "lean_box_uint32"
|
||||||
| IRType.uint64 => emit "lean_box_uint64"
|
| IRType.uint64 => emit "lean_box_uint64"
|
||||||
| IRType.float => emit "lean_box_float"
|
| IRType.float => emit "lean_box_float"
|
||||||
| _ => emit "lean_box"
|
| IRType.float32 => emit "lean_box_float32"
|
||||||
|
| _ => emit "lean_box"
|
||||||
|
|
||||||
def emitBox (z : VarId) (x : VarId) (xType : IRType) : M Unit := do
|
def emitBox (z : VarId) (x : VarId) (xType : IRType) : M Unit := do
|
||||||
emitLhs z; emitBoxFn xType; emit "("; emit x; emitLn ");"
|
emitLhs z; emitBoxFn xType; emit "("; emit x; emitLn ");"
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ def callLeanCtorSetTag (builder : LLVM.Builder llvmctx)
|
|||||||
def toLLVMType (t : IRType) : M llvmctx (LLVM.LLVMType llvmctx) := do
|
def toLLVMType (t : IRType) : M llvmctx (LLVM.LLVMType llvmctx) := do
|
||||||
match t with
|
match t with
|
||||||
| IRType.float => LLVM.doubleTypeInContext llvmctx
|
| IRType.float => LLVM.doubleTypeInContext llvmctx
|
||||||
|
| IRType.float32 => LLVM.floatTypeInContext llvmctx
|
||||||
| IRType.uint8 => LLVM.intTypeInContext llvmctx 8
|
| IRType.uint8 => LLVM.intTypeInContext llvmctx 8
|
||||||
| IRType.uint16 => LLVM.intTypeInContext llvmctx 16
|
| IRType.uint16 => LLVM.intTypeInContext llvmctx 16
|
||||||
| IRType.uint32 => LLVM.intTypeInContext llvmctx 32
|
| IRType.uint32 => LLVM.intTypeInContext llvmctx 32
|
||||||
@@ -817,12 +818,13 @@ def emitSProj (builder : LLVM.Builder llvmctx)
|
|||||||
(z : VarId) (t : IRType) (n offset : Nat) (x : VarId) : M llvmctx Unit := do
|
(z : VarId) (t : IRType) (n offset : Nat) (x : VarId) : M llvmctx Unit := do
|
||||||
let (fnName, retty) ←
|
let (fnName, retty) ←
|
||||||
match t with
|
match t with
|
||||||
| IRType.float => pure ("lean_ctor_get_float", ← LLVM.doubleTypeInContext llvmctx)
|
| IRType.float => pure ("lean_ctor_get_float", ← LLVM.doubleTypeInContext llvmctx)
|
||||||
| IRType.uint8 => pure ("lean_ctor_get_uint8", ← LLVM.i8Type llvmctx)
|
| IRType.float32 => pure ("lean_ctor_get_float32", ← LLVM.floatTypeInContext llvmctx)
|
||||||
| IRType.uint16 => pure ("lean_ctor_get_uint16", ← LLVM.i16Type llvmctx)
|
| IRType.uint8 => pure ("lean_ctor_get_uint8", ← LLVM.i8Type llvmctx)
|
||||||
| IRType.uint32 => pure ("lean_ctor_get_uint32", ← LLVM.i32Type llvmctx)
|
| IRType.uint16 => pure ("lean_ctor_get_uint16", ← LLVM.i16Type llvmctx)
|
||||||
| IRType.uint64 => pure ("lean_ctor_get_uint64", ← LLVM.i64Type llvmctx)
|
| IRType.uint32 => pure ("lean_ctor_get_uint32", ← LLVM.i32Type llvmctx)
|
||||||
| _ => throw s!"Invalid type for lean_ctor_get: '{t}'"
|
| IRType.uint64 => pure ("lean_ctor_get_uint64", ← LLVM.i64Type llvmctx)
|
||||||
|
| _ => throw s!"Invalid type for lean_ctor_get: '{t}'"
|
||||||
let argtys := #[ ← LLVM.voidPtrType llvmctx, ← LLVM.unsignedType llvmctx]
|
let argtys := #[ ← LLVM.voidPtrType llvmctx, ← LLVM.unsignedType llvmctx]
|
||||||
let fn ← getOrCreateFunctionPrototype (← getLLVMModule) retty fnName argtys
|
let fn ← getOrCreateFunctionPrototype (← getLLVMModule) retty fnName argtys
|
||||||
let xval ← emitLhsVal builder x
|
let xval ← emitLhsVal builder x
|
||||||
@@ -862,11 +864,12 @@ def emitBox (builder : LLVM.Builder llvmctx) (z : VarId) (x : VarId) (xType : IR
|
|||||||
let xv ← emitLhsVal builder x
|
let xv ← emitLhsVal builder x
|
||||||
let (fnName, argTy, xv) ←
|
let (fnName, argTy, xv) ←
|
||||||
match xType with
|
match xType with
|
||||||
| IRType.usize => pure ("lean_box_usize", ← LLVM.size_tType llvmctx, xv)
|
| IRType.usize => pure ("lean_box_usize", ← LLVM.size_tType llvmctx, xv)
|
||||||
| IRType.uint32 => pure ("lean_box_uint32", ← LLVM.i32Type llvmctx, xv)
|
| IRType.uint32 => pure ("lean_box_uint32", ← LLVM.i32Type llvmctx, xv)
|
||||||
| IRType.uint64 => pure ("lean_box_uint64", ← LLVM.size_tType llvmctx, xv)
|
| IRType.uint64 => pure ("lean_box_uint64", ← LLVM.size_tType llvmctx, xv)
|
||||||
| IRType.float => pure ("lean_box_float", ← LLVM.doubleTypeInContext llvmctx, xv)
|
| IRType.float => pure ("lean_box_float", ← LLVM.doubleTypeInContext llvmctx, xv)
|
||||||
| _ => do
|
| IRType.float32 => pure ("lean_box_float32", ← LLVM.floatTypeInContext llvmctx, xv)
|
||||||
|
| _ =>
|
||||||
-- sign extend smaller values into i64
|
-- sign extend smaller values into i64
|
||||||
let xv ← LLVM.buildSext builder xv (← LLVM.size_tType llvmctx)
|
let xv ← LLVM.buildSext builder xv (← LLVM.size_tType llvmctx)
|
||||||
pure ("lean_box", ← LLVM.size_tType llvmctx, xv)
|
pure ("lean_box", ← LLVM.size_tType llvmctx, xv)
|
||||||
@@ -892,11 +895,12 @@ def callUnboxForType (builder : LLVM.Builder llvmctx)
|
|||||||
(retName : String := "") : M llvmctx (LLVM.Value llvmctx) := do
|
(retName : String := "") : M llvmctx (LLVM.Value llvmctx) := do
|
||||||
let (fnName, retty) ←
|
let (fnName, retty) ←
|
||||||
match t with
|
match t with
|
||||||
| IRType.usize => pure ("lean_unbox_usize", ← toLLVMType t)
|
| IRType.usize => pure ("lean_unbox_usize", ← toLLVMType t)
|
||||||
| IRType.uint32 => pure ("lean_unbox_uint32", ← toLLVMType t)
|
| IRType.uint32 => pure ("lean_unbox_uint32", ← toLLVMType t)
|
||||||
| IRType.uint64 => pure ("lean_unbox_uint64", ← toLLVMType t)
|
| IRType.uint64 => pure ("lean_unbox_uint64", ← toLLVMType t)
|
||||||
| IRType.float => pure ("lean_unbox_float", ← toLLVMType t)
|
| IRType.float => pure ("lean_unbox_float", ← toLLVMType t)
|
||||||
| _ => pure ("lean_unbox", ← LLVM.size_tType llvmctx)
|
| IRType.float32 => pure ("lean_unbox_float32", ← toLLVMType t)
|
||||||
|
| _ => pure ("lean_unbox", ← LLVM.size_tType llvmctx)
|
||||||
let argtys := #[← LLVM.voidPtrType llvmctx ]
|
let argtys := #[← LLVM.voidPtrType llvmctx ]
|
||||||
let fn ← getOrCreateFunctionPrototype (← getLLVMModule) retty fnName argtys
|
let fn ← getOrCreateFunctionPrototype (← getLLVMModule) retty fnName argtys
|
||||||
let fnty ← LLVM.functionType retty argtys
|
let fnty ← LLVM.functionType retty argtys
|
||||||
@@ -1041,12 +1045,13 @@ def emitJmp (builder : LLVM.Builder llvmctx) (jp : JoinPointId) (xs : Array Arg)
|
|||||||
def emitSSet (builder : LLVM.Builder llvmctx) (x : VarId) (n : Nat) (offset : Nat) (y : VarId) (t : IRType) : M llvmctx Unit := do
|
def emitSSet (builder : LLVM.Builder llvmctx) (x : VarId) (n : Nat) (offset : Nat) (y : VarId) (t : IRType) : M llvmctx Unit := do
|
||||||
let (fnName, setty) ←
|
let (fnName, setty) ←
|
||||||
match t with
|
match t with
|
||||||
| IRType.float => pure ("lean_ctor_set_float", ← LLVM.doubleTypeInContext llvmctx)
|
| IRType.float => pure ("lean_ctor_set_float", ← LLVM.doubleTypeInContext llvmctx)
|
||||||
| IRType.uint8 => pure ("lean_ctor_set_uint8", ← LLVM.i8Type llvmctx)
|
| IRType.float32 => pure ("lean_ctor_set_float32", ← LLVM.floatTypeInContext llvmctx)
|
||||||
| IRType.uint16 => pure ("lean_ctor_set_uint16", ← LLVM.i16Type llvmctx)
|
| IRType.uint8 => pure ("lean_ctor_set_uint8", ← LLVM.i8Type llvmctx)
|
||||||
| IRType.uint32 => pure ("lean_ctor_set_uint32", ← LLVM.i32Type llvmctx)
|
| IRType.uint16 => pure ("lean_ctor_set_uint16", ← LLVM.i16Type llvmctx)
|
||||||
| IRType.uint64 => pure ("lean_ctor_set_uint64", ← LLVM.i64Type llvmctx)
|
| IRType.uint32 => pure ("lean_ctor_set_uint32", ← LLVM.i32Type llvmctx)
|
||||||
| _ => throw s!"invalid type for 'lean_ctor_set': '{t}'"
|
| IRType.uint64 => pure ("lean_ctor_set_uint64", ← LLVM.i64Type llvmctx)
|
||||||
|
| _ => throw s!"invalid type for 'lean_ctor_set': '{t}'"
|
||||||
let argtys := #[ ← LLVM.voidPtrType llvmctx, ← LLVM.unsignedType llvmctx, setty]
|
let argtys := #[ ← LLVM.voidPtrType llvmctx, ← LLVM.unsignedType llvmctx, setty]
|
||||||
let retty ← LLVM.voidType llvmctx
|
let retty ← LLVM.voidType llvmctx
|
||||||
let fn ← getOrCreateFunctionPrototype (← getLLVMModule) retty fnName argtys
|
let fn ← getOrCreateFunctionPrototype (← getLLVMModule) retty fnName argtys
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ instance : ToString Expr := ⟨fun e => Format.pretty (format e)⟩
|
|||||||
|
|
||||||
private partial def formatIRType : IRType → Format
|
private partial def formatIRType : IRType → Format
|
||||||
| IRType.float => "float"
|
| IRType.float => "float"
|
||||||
|
| IRType.float32 => "float32"
|
||||||
| IRType.uint8 => "u8"
|
| IRType.uint8 => "u8"
|
||||||
| IRType.uint16 => "u16"
|
| IRType.uint16 => "u16"
|
||||||
| IRType.uint32 => "u32"
|
| IRType.uint32 => "u32"
|
||||||
|
|||||||
@@ -593,6 +593,14 @@ where
|
|||||||
let minor ← visit minor
|
let minor ← visit minor
|
||||||
mkOverApplication minor args arity
|
mkOverApplication minor args arity
|
||||||
|
|
||||||
|
visitHEqRec (e : Expr) : M Arg :=
|
||||||
|
let arity := 7
|
||||||
|
etaIfUnderApplied e arity do
|
||||||
|
let args := e.getAppArgs
|
||||||
|
let minor := if e.isAppOf ``HEq.rec || e.isAppOf ``HEq.ndrec then args[3]! else args[6]!
|
||||||
|
let minor ← visit minor
|
||||||
|
mkOverApplication minor args arity
|
||||||
|
|
||||||
visitFalseRec (e : Expr) : M Arg :=
|
visitFalseRec (e : Expr) : M Arg :=
|
||||||
let arity := 2
|
let arity := 2
|
||||||
etaIfUnderApplied e arity do
|
etaIfUnderApplied e arity do
|
||||||
@@ -669,6 +677,8 @@ where
|
|||||||
visitCtor 3 e
|
visitCtor 3 e
|
||||||
else if declName == ``Eq.casesOn || declName == ``Eq.rec || declName == ``Eq.ndrec then
|
else if declName == ``Eq.casesOn || declName == ``Eq.rec || declName == ``Eq.ndrec then
|
||||||
visitEqRec e
|
visitEqRec e
|
||||||
|
else if declName == ``HEq.casesOn || declName == ``HEq.rec || declName == ``HEq.ndrec then
|
||||||
|
visitHEqRec e
|
||||||
else if declName == ``And.rec || declName == ``Iff.rec then
|
else if declName == ``And.rec || declName == ``Iff.rec then
|
||||||
visitAndIffRecCore e (minorPos := 3)
|
visitAndIffRecCore e (minorPos := 3)
|
||||||
else if declName == ``And.casesOn || declName == ``Iff.casesOn then
|
else if declName == ``And.casesOn || declName == ``Iff.casesOn then
|
||||||
|
|||||||
@@ -33,7 +33,15 @@ register_builtin_option maxHeartbeats : Nat := {
|
|||||||
|
|
||||||
register_builtin_option Elab.async : Bool := {
|
register_builtin_option Elab.async : Bool := {
|
||||||
defValue := false
|
defValue := false
|
||||||
descr := "perform elaboration using multiple threads where possible"
|
descr := "perform elaboration using multiple threads where possible\
|
||||||
|
\n\
|
||||||
|
\nThis option defaults to `false` but (when not explicitly set) is overridden to `true` in \
|
||||||
|
`Lean.Language.Lean.process` as used by the cmdline driver and language server. \
|
||||||
|
Metaprogramming users driving elaboration directly via e.g. \
|
||||||
|
`Lean.Elab.Command.elabCommandTopLevel` can opt into asynchronous elaboration by setting \
|
||||||
|
this option but then are responsible for processing messages and other data not only in the \
|
||||||
|
resulting command state but also from async tasks in `Lean.Command.Context.snap?` and \
|
||||||
|
`Lean.Command.State.snapshotTasks`."
|
||||||
}
|
}
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -356,9 +364,7 @@ Returns the current log and then resets its messages while adjusting `MessageLog
|
|||||||
for incremental reporting during elaboration of a single command.
|
for incremental reporting during elaboration of a single command.
|
||||||
-/
|
-/
|
||||||
def getAndEmptyMessageLog : CoreM MessageLog :=
|
def getAndEmptyMessageLog : CoreM MessageLog :=
|
||||||
modifyGet fun s => (s.messages, { s with
|
modifyGet fun s => (s.messages, { s with messages := s.messages.markAllReported })
|
||||||
messages.unreported := {}
|
|
||||||
messages.hadErrors := s.messages.hasErrors })
|
|
||||||
|
|
||||||
instance : MonadLog CoreM where
|
instance : MonadLog CoreM where
|
||||||
getRef := getRef
|
getRef := getRef
|
||||||
@@ -417,7 +423,7 @@ def wrapAsyncAsSnapshot (act : Unit → CoreM Unit) (desc : String := by exact d
|
|||||||
IO.FS.withIsolatedStreams (isolateStderr := stderrAsMessages.get (← getOptions)) do
|
IO.FS.withIsolatedStreams (isolateStderr := stderrAsMessages.get (← getOptions)) do
|
||||||
let tid ← IO.getTID
|
let tid ← IO.getTID
|
||||||
-- reset trace state and message log so as not to report them twice
|
-- reset trace state and message log so as not to report them twice
|
||||||
modify ({ · with messages := {}, traceState := { tid } })
|
modify fun st => { st with messages := st.messages.markAllReported, traceState := { tid } }
|
||||||
try
|
try
|
||||||
withTraceNode `Elab.async (fun _ => return desc) do
|
withTraceNode `Elab.async (fun _ => return desc) do
|
||||||
act ()
|
act ()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ theorem RArray.get_ofFn {n : Nat} (f : Fin n → α) (h : 0 < n) (i : Fin n) :
|
|||||||
go 0 n h (Nat.le_refl _) (Nat.zero_le _) i.2
|
go 0 n h (Nat.le_refl _) (Nat.zero_le _) i.2
|
||||||
where
|
where
|
||||||
go lb ub h1 h2 (h3 : lb ≤ i.val) (h3 : i.val < ub) : (ofFn.go f lb ub h1 h2).get i = f i := by
|
go lb ub h1 h2 (h3 : lb ≤ i.val) (h3 : i.val < ub) : (ofFn.go f lb ub h1 h2).get i = f i := by
|
||||||
induction lb, ub, h1, h2 using RArray.ofFn.go.induct (f := f) (n := n)
|
induction lb, ub, h1, h2 using RArray.ofFn.go.induct (n := n)
|
||||||
case case1 =>
|
case case1 =>
|
||||||
simp [ofFn.go, RArray.get_eq_getImpl, RArray.getImpl]
|
simp [ofFn.go, RArray.get_eq_getImpl, RArray.getImpl]
|
||||||
congr
|
congr
|
||||||
@@ -53,7 +53,7 @@ theorem RArray.size_ofFn {n : Nat} (f : Fin n → α) (h : 0 < n) :
|
|||||||
go 0 n h (Nat.le_refl _)
|
go 0 n h (Nat.le_refl _)
|
||||||
where
|
where
|
||||||
go lb ub h1 h2 : (ofFn.go f lb ub h1 h2).size = ub - lb := by
|
go lb ub h1 h2 : (ofFn.go f lb ub h1 h2).size = ub - lb := by
|
||||||
induction lb, ub, h1, h2 using RArray.ofFn.go.induct (f := f) (n := n)
|
induction lb, ub, h1, h2 using RArray.ofFn.go.induct (n := n)
|
||||||
case case1 => simp [ofFn.go, size]; omega
|
case case1 => simp [ofFn.go, size]; omega
|
||||||
case case2 ih1 ih2 hiu => rw [ofFn.go]; simp [size, *]; omega
|
case case2 ih1 ih2 hiu => rw [ofFn.go]; simp [size, *]; omega
|
||||||
|
|
||||||
|
|||||||
@@ -488,6 +488,9 @@ where
|
|||||||
let mut lines : Array MessageData := #[]
|
let mut lines : Array MessageData := #[]
|
||||||
let decls ← getOptionDecls
|
let decls ← getOptionDecls
|
||||||
for (name, val) in opts do
|
for (name, val) in opts do
|
||||||
|
-- `#guard_msgs` sets this option internally, we don't want it to end up in its output
|
||||||
|
if name == `Elab.async then
|
||||||
|
continue
|
||||||
let (isSet, isUnknown) :=
|
let (isSet, isUnknown) :=
|
||||||
match decls.find? name with
|
match decls.find? name with
|
||||||
| some decl => (decl.defValue != val, false)
|
| some decl => (decl.defValue != val, false)
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ structure Context where
|
|||||||
(mutual) defs and contained tactics, in which case the `DynamicSnapshot` is a
|
(mutual) defs and contained tactics, in which case the `DynamicSnapshot` is a
|
||||||
`HeadersParsedSnapshot`.
|
`HeadersParsedSnapshot`.
|
||||||
|
|
||||||
Definitely resolved in `Language.Lean.process.doElab`.
|
Definitely resolved in `Lean.Elab.Command.elabCommandTopLevel`.
|
||||||
|
|
||||||
Invariant: if the bundle's `old?` is set, the context and state at the beginning of current and
|
Invariant: if the bundle's `old?` is set, the context and state at the beginning of current and
|
||||||
old elaboration are identical.
|
old elaboration are identical.
|
||||||
@@ -287,7 +287,9 @@ def runLinters (stx : Syntax) : CommandElabM Unit := do
|
|||||||
| Exception.internal _ _ =>
|
| Exception.internal _ _ =>
|
||||||
logException ex
|
logException ex
|
||||||
finally
|
finally
|
||||||
modify fun s => { savedState with messages := s.messages }
|
-- TODO: it would be good to preserve even more state (#4363) but preserving info
|
||||||
|
-- trees currently breaks from linters adding context-less info nodes
|
||||||
|
modify fun s => { savedState with messages := s.messages, traceState := s.traceState }
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Catches and logs exceptions occurring in `x`. Unlike `try catch` in `CommandElabM`, this function
|
Catches and logs exceptions occurring in `x`. Unlike `try catch` in `CommandElabM`, this function
|
||||||
@@ -311,7 +313,7 @@ def wrapAsyncAsSnapshot (act : Unit → CommandElabM Unit)
|
|||||||
IO.FS.withIsolatedStreams (isolateStderr := Core.stderrAsMessages.get (← getOptions)) do
|
IO.FS.withIsolatedStreams (isolateStderr := Core.stderrAsMessages.get (← getOptions)) do
|
||||||
let tid ← IO.getTID
|
let tid ← IO.getTID
|
||||||
-- reset trace state and message log so as not to report them twice
|
-- reset trace state and message log so as not to report them twice
|
||||||
modify ({ · with messages := {}, traceState := { tid } })
|
modify fun st => { st with messages := st.messages.markAllReported, traceState := { tid } }
|
||||||
try
|
try
|
||||||
withTraceNode `Elab.async (fun _ => return desc) do
|
withTraceNode `Elab.async (fun _ => return desc) do
|
||||||
act ()
|
act ()
|
||||||
@@ -344,6 +346,17 @@ def wrapAsyncAsSnapshot (act : Unit → CommandElabM Unit)
|
|||||||
def logSnapshotTask (task : Language.SnapshotTask Language.SnapshotTree) : CommandElabM Unit :=
|
def logSnapshotTask (task : Language.SnapshotTask Language.SnapshotTree) : CommandElabM Unit :=
|
||||||
modify fun s => { s with snapshotTasks := s.snapshotTasks.push task }
|
modify fun s => { s with snapshotTasks := s.snapshotTasks.push task }
|
||||||
|
|
||||||
|
def runLintersAsync (stx : Syntax) : CommandElabM Unit := do
|
||||||
|
if !Elab.async.get (← getOptions) then
|
||||||
|
withoutModifyingEnv do
|
||||||
|
runLinters stx
|
||||||
|
return
|
||||||
|
|
||||||
|
-- We only start one task for all linters for now as most linters are fast and we simply want
|
||||||
|
-- to unblock elaboration of the next command
|
||||||
|
let lintAct ← wrapAsyncAsSnapshot fun _ => runLinters stx
|
||||||
|
logSnapshotTask { range? := none, task := (← BaseIO.asTask lintAct) }
|
||||||
|
|
||||||
protected def getCurrMacroScope : CommandElabM Nat := do pure (← read).currMacroScope
|
protected def getCurrMacroScope : CommandElabM Nat := do pure (← read).currMacroScope
|
||||||
protected def getMainModule : CommandElabM Name := do pure (← getEnv).mainModule
|
protected def getMainModule : CommandElabM Name := do pure (← getEnv).mainModule
|
||||||
|
|
||||||
@@ -547,8 +560,13 @@ def elabCommandTopLevel (stx : Syntax) : CommandElabM Unit := withRef stx do pro
|
|||||||
-- rather than engineer a general solution.
|
-- rather than engineer a general solution.
|
||||||
unless (stx.find? (·.isOfKind ``Lean.guardMsgsCmd)).isSome do
|
unless (stx.find? (·.isOfKind ``Lean.guardMsgsCmd)).isSome do
|
||||||
withLogging do
|
withLogging do
|
||||||
runLinters stx
|
runLintersAsync stx
|
||||||
finally
|
finally
|
||||||
|
-- Make sure `snap?` is definitely resolved; we do not use it for reporting as `#guard_msgs` may
|
||||||
|
-- be the caller of this function and add new messages and info trees
|
||||||
|
if let some snap := (← read).snap? then
|
||||||
|
snap.new.resolve default
|
||||||
|
|
||||||
-- note the order: first process current messages & info trees, then add back old messages & trees,
|
-- note the order: first process current messages & info trees, then add back old messages & trees,
|
||||||
-- then convert new traces to messages
|
-- then convert new traces to messages
|
||||||
let mut msgs := (← get).messages
|
let mut msgs := (← get).messages
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ def runFrontend
|
|||||||
IO.FS.writeFile ⟨out⟩ <| Json.compress <| toJson profile
|
IO.FS.writeFile ⟨out⟩ <| Json.compress <| toJson profile
|
||||||
|
|
||||||
let hasErrors := snaps.getAll.any (·.diagnostics.msgLog.hasErrors)
|
let hasErrors := snaps.getAll.any (·.diagnostics.msgLog.hasErrors)
|
||||||
|
-- no point in freeing the snapshot graph and all referenced data this close to process exit
|
||||||
|
Runtime.forget snaps
|
||||||
pure (cmdState.env, !hasErrors)
|
pure (cmdState.env, !hasErrors)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -140,9 +140,15 @@ def MessageOrdering.apply (mode : MessageOrdering) (msgs : List String) : List S
|
|||||||
|>.trim |> removeTrailingWhitespaceMarker
|
|>.trim |> removeTrailingWhitespaceMarker
|
||||||
let (whitespace, ordering, specFn) ← parseGuardMsgsSpec spec?
|
let (whitespace, ordering, specFn) ← parseGuardMsgsSpec spec?
|
||||||
let initMsgs ← modifyGet fun st => (st.messages, { st with messages := {} })
|
let initMsgs ← modifyGet fun st => (st.messages, { st with messages := {} })
|
||||||
-- The `#guard_msgs` command is special-cased in `elabCommandTopLevel` to ensure linters only run once.
|
-- do not forward snapshot as we don't want messages assigned to it to leak outside
|
||||||
elabCommandTopLevel cmd
|
withReader ({ · with snap? := none }) do
|
||||||
let msgs := (← get).messages
|
-- The `#guard_msgs` command is special-cased in `elabCommandTopLevel` to ensure linters only run once.
|
||||||
|
elabCommandTopLevel cmd
|
||||||
|
-- collect sync and async messages
|
||||||
|
let msgs := (← get).messages ++
|
||||||
|
(← get).snapshotTasks.foldl (· ++ ·.get.getAll.foldl (· ++ ·.diagnostics.msgLog) {}) {}
|
||||||
|
-- clear async messages as we don't want them to leak outside
|
||||||
|
modify ({ · with snapshotTasks := #[] })
|
||||||
let mut toCheck : MessageLog := .empty
|
let mut toCheck : MessageLog := .empty
|
||||||
let mut toPassthrough : MessageLog := .empty
|
let mut toPassthrough : MessageLog := .empty
|
||||||
for msg in msgs.toList do
|
for msg in msgs.toList do
|
||||||
|
|||||||
@@ -399,6 +399,20 @@ register_builtin_option linter.unusedSectionVars : Bool := {
|
|||||||
descr := "enable the 'unused section variables in theorem body' linter"
|
descr := "enable the 'unused section variables in theorem body' linter"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register_builtin_option debug.proofAsSorry : Bool := {
|
||||||
|
defValue := false
|
||||||
|
group := "debug"
|
||||||
|
descr := "replace the bodies (proofs) of theorems with `sorry`"
|
||||||
|
}
|
||||||
|
|
||||||
|
/-- Returns true if `k` is a theorem, option `debug.proofAsSorry` is set to true, and the environment contains the axiom `sorryAx`. -/
|
||||||
|
private def useProofAsSorry (k : DefKind) : CoreM Bool := do
|
||||||
|
if k.isTheorem then
|
||||||
|
if debug.proofAsSorry.get (← getOptions) then
|
||||||
|
if (← getEnv).contains ``sorryAx then
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
private def elabFunValues (headers : Array DefViewElabHeader) (vars : Array Expr) (sc : Command.Scope) : TermElabM (Array Expr) :=
|
private def elabFunValues (headers : Array DefViewElabHeader) (vars : Array Expr) (sc : Command.Scope) : TermElabM (Array Expr) :=
|
||||||
headers.mapM fun header => do
|
headers.mapM fun header => do
|
||||||
let mut reusableResult? := none
|
let mut reusableResult? := none
|
||||||
@@ -420,7 +434,9 @@ private def elabFunValues (headers : Array DefViewElabHeader) (vars : Array Expr
|
|||||||
for h : i in [0:header.binderIds.size] do
|
for h : i in [0:header.binderIds.size] do
|
||||||
-- skip auto-bound prefix in `xs`
|
-- skip auto-bound prefix in `xs`
|
||||||
addLocalVarInfo header.binderIds[i] xs[header.numParams - header.binderIds.size + i]!
|
addLocalVarInfo header.binderIds[i] xs[header.numParams - header.binderIds.size + i]!
|
||||||
let val ← withReader ({ · with tacSnap? := header.tacSnap? }) do
|
let val ← if (← useProofAsSorry header.kind) then
|
||||||
|
mkSorry type false
|
||||||
|
else withReader ({ · with tacSnap? := header.tacSnap? }) do
|
||||||
-- Store instantiated body in info tree for the benefit of the unused variables linter
|
-- Store instantiated body in info tree for the benefit of the unused variables linter
|
||||||
-- and other metaprograms that may want to inspect it without paying for the instantiation
|
-- and other metaprograms that may want to inspect it without paying for the instantiation
|
||||||
-- again
|
-- again
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ private def addAndCompilePartial (preDefs : Array PreDefinition) (useSorry := fa
|
|||||||
let value ← if useSorry then
|
let value ← if useSorry then
|
||||||
mkLambdaFVars xs (← mkSorry type (synthetic := true))
|
mkLambdaFVars xs (← mkSorry type (synthetic := true))
|
||||||
else
|
else
|
||||||
liftM <| mkInhabitantFor preDef.declName xs type
|
let msg := m!"failed to compile 'partial' definition '{preDef.declName}'"
|
||||||
|
liftM <| mkInhabitantFor msg xs type
|
||||||
addNonRec { preDef with
|
addNonRec { preDef with
|
||||||
kind := DefKind.«opaque»
|
kind := DefKind.«opaque»
|
||||||
value
|
value
|
||||||
|
|||||||
@@ -50,13 +50,13 @@ private partial def mkInhabitantForAux? (xs insts : Array Expr) (type : Expr) (u
|
|||||||
return none
|
return none
|
||||||
|
|
||||||
/- TODO: add a global IO.Ref to let users customize/extend this procedure -/
|
/- TODO: add a global IO.Ref to let users customize/extend this procedure -/
|
||||||
def mkInhabitantFor (declName : Name) (xs : Array Expr) (type : Expr) : MetaM Expr :=
|
def mkInhabitantFor (failedToMessage : MessageData) (xs : Array Expr) (type : Expr) : MetaM Expr :=
|
||||||
withInhabitedInstances xs fun insts => do
|
withInhabitedInstances xs fun insts => do
|
||||||
if let some val ← mkInhabitantForAux? xs insts type false <||> mkInhabitantForAux? xs insts type true then
|
if let some val ← mkInhabitantForAux? xs insts type false <||> mkInhabitantForAux? xs insts type true then
|
||||||
return val
|
return val
|
||||||
else
|
else
|
||||||
throwError "\
|
throwError "\
|
||||||
failed to compile 'partial' definition '{declName}', could not prove that the type\
|
{failedToMessage}, could not prove that the type\
|
||||||
{indentExpr (← mkForallFVars xs type)}\n\
|
{indentExpr (← mkForallFVars xs type)}\n\
|
||||||
is nonempty.\n\
|
is nonempty.\n\
|
||||||
\n\
|
\n\
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ structure EqnInfo extends EqnInfoCore where
|
|||||||
declNameNonRec : Name
|
declNameNonRec : Name
|
||||||
fixedPrefixSize : Nat
|
fixedPrefixSize : Nat
|
||||||
argsPacker : ArgsPacker
|
argsPacker : ArgsPacker
|
||||||
|
hasInduct : Bool
|
||||||
deriving Inhabited
|
deriving Inhabited
|
||||||
|
|
||||||
private partial def deltaLHSUntilFix (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
private partial def deltaLHSUntilFix (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||||||
@@ -101,7 +102,7 @@ def mkEqns (declName : Name) (info : EqnInfo) : MetaM (Array Name) :=
|
|||||||
builtin_initialize eqnInfoExt : MapDeclarationExtension EqnInfo ← mkMapDeclarationExtension
|
builtin_initialize eqnInfoExt : MapDeclarationExtension EqnInfo ← mkMapDeclarationExtension
|
||||||
|
|
||||||
def registerEqnsInfo (preDefs : Array PreDefinition) (declNameNonRec : Name) (fixedPrefixSize : Nat)
|
def registerEqnsInfo (preDefs : Array PreDefinition) (declNameNonRec : Name) (fixedPrefixSize : Nat)
|
||||||
(argsPacker : ArgsPacker) : MetaM Unit := do
|
(argsPacker : ArgsPacker) (hasInduct : Bool) : MetaM Unit := do
|
||||||
preDefs.forM fun preDef => ensureEqnReservedNamesAvailable preDef.declName
|
preDefs.forM fun preDef => ensureEqnReservedNamesAvailable preDef.declName
|
||||||
/-
|
/-
|
||||||
See issue #2327.
|
See issue #2327.
|
||||||
@@ -114,7 +115,7 @@ def registerEqnsInfo (preDefs : Array PreDefinition) (declNameNonRec : Name) (fi
|
|||||||
modifyEnv fun env =>
|
modifyEnv fun env =>
|
||||||
preDefs.foldl (init := env) fun env preDef =>
|
preDefs.foldl (init := env) fun env preDef =>
|
||||||
eqnInfoExt.insert env preDef.declName { preDef with
|
eqnInfoExt.insert env preDef.declName { preDef with
|
||||||
declNames, declNameNonRec, fixedPrefixSize, argsPacker }
|
declNames, declNameNonRec, fixedPrefixSize, argsPacker, hasInduct }
|
||||||
|
|
||||||
def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
|
def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
|
||||||
if let some info := eqnInfoExt.find? (← getEnv) declName then
|
if let some info := eqnInfoExt.find? (← getEnv) declName then
|
||||||
|
|||||||
@@ -178,7 +178,8 @@ def groupGoalsByFunction (argsPacker : ArgsPacker) (numFuncs : Nat) (goals : Arr
|
|||||||
let type ← goal.getType
|
let type ← goal.getType
|
||||||
let (.mdata _ (.app _ param)) := type
|
let (.mdata _ (.app _ param)) := type
|
||||||
| throwError "MVar does not look like a recursive call:{indentExpr type}"
|
| throwError "MVar does not look like a recursive call:{indentExpr type}"
|
||||||
let (funidx, _) ← argsPacker.unpack param
|
let some (funidx, _) := argsPacker.unpack param
|
||||||
|
| throwError "Cannot unpack param, unexpected expression:{indentExpr param}"
|
||||||
r := r.modify funidx (·.push goal)
|
r := r.modify funidx (·.push goal)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|||||||
@@ -352,8 +352,10 @@ def collectRecCalls (unaryPreDef : PreDefinition) (fixedPrefixSize : Nat)
|
|||||||
throwError "Insufficient arguments in recursive call"
|
throwError "Insufficient arguments in recursive call"
|
||||||
let arg := args[fixedPrefixSize]!
|
let arg := args[fixedPrefixSize]!
|
||||||
trace[Elab.definition.wf] "collectRecCalls: {unaryPreDef.declName} ({param}) → {unaryPreDef.declName} ({arg})"
|
trace[Elab.definition.wf] "collectRecCalls: {unaryPreDef.declName} ({param}) → {unaryPreDef.declName} ({arg})"
|
||||||
let (caller, params) ← argsPacker.unpack param
|
let some (caller, params) := argsPacker.unpack param
|
||||||
let (callee, args) ← argsPacker.unpack arg
|
| throwError "Cannot unpack param, unexpected expression:{indentExpr param}"
|
||||||
|
let some (callee, args) := argsPacker.unpack arg
|
||||||
|
| throwError "Cannot unpack arg, unexpected expression:{indentExpr arg}"
|
||||||
RecCallWithContext.create (← getRef) caller (ys ++ params) callee (ys ++ args)
|
RecCallWithContext.create (← getRef) caller (ys ++ params) callee (ys ++ args)
|
||||||
|
|
||||||
/-- Is the expression a `<`-like comparison of `Nat` expressions -/
|
/-- Is the expression a `<`-like comparison of `Nat` expressions -/
|
||||||
@@ -771,6 +773,8 @@ Main entry point of this module:
|
|||||||
|
|
||||||
Try to find a lexicographic ordering of the arguments for which the recursive definition
|
Try to find a lexicographic ordering of the arguments for which the recursive definition
|
||||||
terminates. See the module doc string for a high-level overview.
|
terminates. See the module doc string for a high-level overview.
|
||||||
|
|
||||||
|
The `preDefs` are used to determine arity and types of arguments; the bodies are ignored.
|
||||||
-/
|
-/
|
||||||
def guessLex (preDefs : Array PreDefinition) (unaryPreDef : PreDefinition)
|
def guessLex (preDefs : Array PreDefinition) (unaryPreDef : PreDefinition)
|
||||||
(fixedPrefixSize : Nat) (argsPacker : ArgsPacker) :
|
(fixedPrefixSize : Nat) (argsPacker : ArgsPacker) :
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ def wfRecursion (preDefs : Array PreDefinition) (termArg?s : Array (Option Termi
|
|||||||
unless type.isForall do
|
unless type.isForall do
|
||||||
throwError "wfRecursion: expected unary function type: {type}"
|
throwError "wfRecursion: expected unary function type: {type}"
|
||||||
let packedArgType := type.bindingDomain!
|
let packedArgType := type.bindingDomain!
|
||||||
elabWFRel preDefs unaryPreDef.declName prefixArgs argsPacker packedArgType wf fun wfRel => do
|
elabWFRel (preDefs.map (·.declName)) unaryPreDef.declName prefixArgs argsPacker packedArgType wf fun wfRel => do
|
||||||
trace[Elab.definition.wf] "wfRel: {wfRel}"
|
trace[Elab.definition.wf] "wfRel: {wfRel}"
|
||||||
let (value, envNew) ← withoutModifyingEnv' do
|
let (value, envNew) ← withoutModifyingEnv' do
|
||||||
addAsAxiom unaryPreDef
|
addAsAxiom unaryPreDef
|
||||||
@@ -142,7 +142,7 @@ def wfRecursion (preDefs : Array PreDefinition) (termArg?s : Array (Option Termi
|
|||||||
-- Reason: the nested proofs may be referring to the _unsafe_rec.
|
-- Reason: the nested proofs may be referring to the _unsafe_rec.
|
||||||
addAndCompilePartialRec preDefs
|
addAndCompilePartialRec preDefs
|
||||||
let preDefs ← preDefs.mapM (abstractNestedProofs ·)
|
let preDefs ← preDefs.mapM (abstractNestedProofs ·)
|
||||||
registerEqnsInfo preDefs preDefNonRec.declName fixedPrefixSize argsPacker
|
registerEqnsInfo preDefs preDefNonRec.declName fixedPrefixSize argsPacker (hasInduct := true)
|
||||||
for preDef in preDefs do
|
for preDef in preDefs do
|
||||||
markAsRecursive preDef.declName
|
markAsRecursive preDef.declName
|
||||||
generateEagerEqns preDef.declName
|
generateEagerEqns preDef.declName
|
||||||
|
|||||||
@@ -51,12 +51,12 @@ If the `termArgs` map the packed argument `argType` to `β`, then this function
|
|||||||
continuation a value of type `WellFoundedRelation argType` that is derived from the instance
|
continuation a value of type `WellFoundedRelation argType` that is derived from the instance
|
||||||
for `WellFoundedRelation β` using `invImage`.
|
for `WellFoundedRelation β` using `invImage`.
|
||||||
-/
|
-/
|
||||||
def elabWFRel (preDefs : Array PreDefinition) (unaryPreDefName : Name) (prefixArgs : Array Expr)
|
def elabWFRel (declNames : Array Name) (unaryPreDefName : Name) (prefixArgs : Array Expr)
|
||||||
(argsPacker : ArgsPacker) (argType : Expr) (termArgs : TerminationArguments)
|
(argsPacker : ArgsPacker) (argType : Expr) (termArgs : TerminationArguments)
|
||||||
(k : Expr → TermElabM α) : TermElabM α := withDeclName unaryPreDefName do
|
(k : Expr → TermElabM α) : TermElabM α := withDeclName unaryPreDefName do
|
||||||
let α := argType
|
let α := argType
|
||||||
let u ← getLevel α
|
let u ← getLevel α
|
||||||
let β ← checkCodomains (preDefs.map (·.declName)) prefixArgs argsPacker.arities termArgs
|
let β ← checkCodomains declNames prefixArgs argsPacker.arities termArgs
|
||||||
let v ← getLevel β
|
let v ← getLevel β
|
||||||
let packedF ← argsPacker.uncurryND (termArgs.map (·.fn.beta prefixArgs))
|
let packedF ← argsPacker.uncurryND (termArgs.map (·.fn.beta prefixArgs))
|
||||||
let inst ← synthInstance (.app (.const ``WellFoundedRelation [v]) β)
|
let inst ← synthInstance (.app (.const ``WellFoundedRelation [v]) β)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import Std.Data.HashMap
|
|||||||
import Std.Tactic.BVDecide.Bitblast.BVExpr.Basic
|
import Std.Tactic.BVDecide.Bitblast.BVExpr.Basic
|
||||||
import Lean.Meta.AppBuilder
|
import Lean.Meta.AppBuilder
|
||||||
import Lean.ToExpr
|
import Lean.ToExpr
|
||||||
|
import Lean.Data.RArray
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
This module contains the implementation of the reflection monad, used by all other components of this
|
This module contains the implementation of the reflection monad, used by all other components of this
|
||||||
@@ -138,9 +139,11 @@ structure State where
|
|||||||
-/
|
-/
|
||||||
atoms : Std.HashMap Expr Atom := {}
|
atoms : Std.HashMap Expr Atom := {}
|
||||||
/--
|
/--
|
||||||
A cache for `atomsAssignment`.
|
A cache for `atomsAssignment`. We maintain the invariant that this value is only used if
|
||||||
|
`atoms` is non empty. The reason for not using an `Option` is that it would pollute a lot of code
|
||||||
|
with error handling that is never hit as this invariant is enforced before all of this code.
|
||||||
-/
|
-/
|
||||||
atomsAssignmentCache : Expr := mkConst ``List.nil [.zero]
|
atomsAssignmentCache : Expr := mkConst `illegal
|
||||||
|
|
||||||
/--
|
/--
|
||||||
The reflection monad, used to track `BitVec` variables that we see as we traverse the context.
|
The reflection monad, used to track `BitVec` variables that we see as we traverse the context.
|
||||||
@@ -157,9 +160,9 @@ structure ReifiedBVExpr where
|
|||||||
-/
|
-/
|
||||||
bvExpr : BVExpr width
|
bvExpr : BVExpr width
|
||||||
/--
|
/--
|
||||||
A proof that `bvExpr.eval atomsAssignment = originalBVExpr`.
|
A proof that `bvExpr.eval atomsAssignment = originalBVExpr`, none if it holds by `rfl`.
|
||||||
-/
|
-/
|
||||||
evalsAtAtoms : M Expr
|
evalsAtAtoms : M (Option Expr)
|
||||||
/--
|
/--
|
||||||
A cache for `toExpr bvExpr`.
|
A cache for `toExpr bvExpr`.
|
||||||
-/
|
-/
|
||||||
@@ -174,9 +177,9 @@ structure ReifiedBVPred where
|
|||||||
-/
|
-/
|
||||||
bvPred : BVPred
|
bvPred : BVPred
|
||||||
/--
|
/--
|
||||||
A proof that `bvPred.eval atomsAssignment = originalBVPredExpr`.
|
A proof that `bvPred.eval atomsAssignment = originalBVPredExpr`, none if it holds by `rfl`.
|
||||||
-/
|
-/
|
||||||
evalsAtAtoms : M Expr
|
evalsAtAtoms : M (Option Expr)
|
||||||
/--
|
/--
|
||||||
A cache for `toExpr bvPred`
|
A cache for `toExpr bvPred`
|
||||||
-/
|
-/
|
||||||
@@ -191,9 +194,9 @@ structure ReifiedBVLogical where
|
|||||||
-/
|
-/
|
||||||
bvExpr : BVLogicalExpr
|
bvExpr : BVLogicalExpr
|
||||||
/--
|
/--
|
||||||
A proof that `bvExpr.eval atomsAssignment = originalBVLogicalExpr`.
|
A proof that `bvExpr.eval atomsAssignment = originalBVLogicalExpr`, none if it holds by `rfl`.
|
||||||
-/
|
-/
|
||||||
evalsAtAtoms : M Expr
|
evalsAtAtoms : M (Option Expr)
|
||||||
/--
|
/--
|
||||||
A cache for `toExpr bvExpr`
|
A cache for `toExpr bvExpr`
|
||||||
-/
|
-/
|
||||||
@@ -228,9 +231,9 @@ def run (m : M α) : MetaM α :=
|
|||||||
/--
|
/--
|
||||||
Retrieve the atoms as pairs of their width and expression.
|
Retrieve the atoms as pairs of their width and expression.
|
||||||
-/
|
-/
|
||||||
def atoms : M (List (Nat × Expr)) := do
|
def atoms : M (Array (Nat × Expr)) := do
|
||||||
let sortedAtoms := (← getThe State).atoms.toArray.qsort (·.2.atomNumber < ·.2.atomNumber)
|
let sortedAtoms := (← getThe State).atoms.toArray.qsort (·.2.atomNumber < ·.2.atomNumber)
|
||||||
return sortedAtoms.map (fun (expr, {width, ..}) => (width, expr)) |>.toList
|
return sortedAtoms.map (fun (expr, {width, ..}) => (width, expr))
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Retrieve a `BitVec.Assignment` representing the atoms we found so far.
|
Retrieve a `BitVec.Assignment` representing the atoms we found so far.
|
||||||
@@ -257,11 +260,37 @@ def lookup (e : Expr) (width : Nat) (synthetic : Bool) : M Nat := do
|
|||||||
where
|
where
|
||||||
updateAtomsAssignment : M Unit := do
|
updateAtomsAssignment : M Unit := do
|
||||||
let as ← atoms
|
let as ← atoms
|
||||||
let packed :=
|
if h : 0 < as.size then
|
||||||
as.map (fun (width, expr) => mkApp2 (mkConst ``BVExpr.PackedBitVec.mk) (toExpr width) expr)
|
let ras := Lean.RArray.ofArray as h
|
||||||
let packedType := mkConst ``BVExpr.PackedBitVec
|
let packedType := mkConst ``BVExpr.PackedBitVec
|
||||||
let newAtomsAssignment ← mkListLit packedType packed
|
let pack := fun (width, expr) => mkApp2 (mkConst ``BVExpr.PackedBitVec.mk) (toExpr width) expr
|
||||||
modify fun s => { s with atomsAssignmentCache := newAtomsAssignment }
|
let newAtomsAssignment := ras.toExpr packedType pack
|
||||||
|
modify fun s => { s with atomsAssignmentCache := newAtomsAssignment }
|
||||||
|
else
|
||||||
|
throwError "updateAtomsAssignment should only be called when there is an atom"
|
||||||
|
|
||||||
|
@[specialize]
|
||||||
|
def simplifyBinaryProof' (mkFRefl : Expr → Expr) (fst : Expr) (fproof : Option Expr)
|
||||||
|
(mkSRefl : Expr → Expr) (snd : Expr) (sproof : Option Expr) : Option (Expr × Expr) := do
|
||||||
|
match fproof, sproof with
|
||||||
|
| some fproof, some sproof => some (fproof, sproof)
|
||||||
|
| some fproof, none => some (fproof, mkSRefl snd)
|
||||||
|
| none, some sproof => some (mkFRefl fst, sproof)
|
||||||
|
| none, none => none
|
||||||
|
|
||||||
|
@[specialize]
|
||||||
|
def simplifyBinaryProof (mkRefl : Expr → Expr) (fst : Expr) (fproof : Option Expr) (snd : Expr)
|
||||||
|
(sproof : Option Expr) : Option (Expr × Expr) := do
|
||||||
|
simplifyBinaryProof' mkRefl fst fproof mkRefl snd sproof
|
||||||
|
|
||||||
|
@[specialize]
|
||||||
|
def simplifyTernaryProof (mkRefl : Expr → Expr) (fst : Expr) (fproof : Option Expr) (snd : Expr)
|
||||||
|
(sproof : Option Expr) (thd : Expr) (tproof : Option Expr) : Option (Expr × Expr × Expr) := do
|
||||||
|
match fproof, simplifyBinaryProof mkRefl snd sproof thd tproof with
|
||||||
|
| some fproof, some stproof => some (fproof, stproof)
|
||||||
|
| some fproof, none => some (fproof, mkRefl snd, mkRefl thd)
|
||||||
|
| none, some stproof => some (mkRefl fst, stproof)
|
||||||
|
| none, none => none
|
||||||
|
|
||||||
end M
|
end M
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,8 @@ Register `e` as an atom of `width` that might potentially be `synthetic`.
|
|||||||
def mkAtom (e : Expr) (width : Nat) (synthetic : Bool) : M ReifiedBVExpr := do
|
def mkAtom (e : Expr) (width : Nat) (synthetic : Bool) : M ReifiedBVExpr := do
|
||||||
let ident ← M.lookup e width synthetic
|
let ident ← M.lookup e width synthetic
|
||||||
let expr := mkApp2 (mkConst ``BVExpr.var) (toExpr width) (toExpr ident)
|
let expr := mkApp2 (mkConst ``BVExpr.var) (toExpr width) (toExpr ident)
|
||||||
let proof := do
|
-- This is safe because this proof always holds definitionally.
|
||||||
let evalExpr ← mkEvalExpr width expr
|
let proof := pure none
|
||||||
return mkBVRefl width evalExpr
|
|
||||||
return ⟨width, .var ident, proof, expr⟩
|
return ⟨width, .var ident, proof, expr⟩
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -70,9 +69,8 @@ Build a reified version of the constant `val`.
|
|||||||
def mkBVConst (val : BitVec w) : M ReifiedBVExpr := do
|
def mkBVConst (val : BitVec w) : M ReifiedBVExpr := do
|
||||||
let bvExpr : BVExpr w := .const val
|
let bvExpr : BVExpr w := .const val
|
||||||
let expr := mkApp2 (mkConst ``BVExpr.const) (toExpr w) (toExpr val)
|
let expr := mkApp2 (mkConst ``BVExpr.const) (toExpr w) (toExpr val)
|
||||||
let proof := do
|
-- This is safe because this proof always holds definitionally.
|
||||||
let evalExpr ← ReifiedBVExpr.mkEvalExpr w expr
|
let proof := pure none
|
||||||
return ReifiedBVExpr.mkBVRefl w evalExpr
|
|
||||||
return ⟨w, bvExpr, proof, expr⟩
|
return ⟨w, bvExpr, proof, expr⟩
|
||||||
|
|
||||||
end ReifiedBVExpr
|
end ReifiedBVExpr
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ Build a reified version of the constant `val`.
|
|||||||
def mkBoolConst (val : Bool) : M ReifiedBVLogical := do
|
def mkBoolConst (val : Bool) : M ReifiedBVLogical := do
|
||||||
let boolExpr := .const val
|
let boolExpr := .const val
|
||||||
let expr := mkApp2 (mkConst ``BoolExpr.const) (mkConst ``BVPred) (toExpr val)
|
let expr := mkApp2 (mkConst ``BoolExpr.const) (mkConst ``BVPred) (toExpr val)
|
||||||
let proof := pure <| ReifiedBVLogical.mkRefl (toExpr val)
|
-- This is safe because this proof always holds definitionally.
|
||||||
|
let proof := pure none
|
||||||
return ⟨boolExpr, proof, expr⟩
|
return ⟨boolExpr, proof, expr⟩
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -71,8 +72,13 @@ def mkGate (lhs rhs : ReifiedBVLogical) (lhsExpr rhsExpr : Expr) (gate : Gate) :
|
|||||||
let proof := do
|
let proof := do
|
||||||
let lhsEvalExpr ← ReifiedBVLogical.mkEvalExpr lhs.expr
|
let lhsEvalExpr ← ReifiedBVLogical.mkEvalExpr lhs.expr
|
||||||
let rhsEvalExpr ← ReifiedBVLogical.mkEvalExpr rhs.expr
|
let rhsEvalExpr ← ReifiedBVLogical.mkEvalExpr rhs.expr
|
||||||
let lhsProof ← lhs.evalsAtAtoms
|
let lhsProof? ← lhs.evalsAtAtoms
|
||||||
let rhsProof ← rhs.evalsAtAtoms
|
let rhsProof? ← rhs.evalsAtAtoms
|
||||||
|
let some (lhsProof, rhsProof) :=
|
||||||
|
M.simplifyBinaryProof
|
||||||
|
ReifiedBVLogical.mkRefl
|
||||||
|
lhsEvalExpr lhsProof?
|
||||||
|
rhsEvalExpr rhsProof? | return none
|
||||||
return mkApp6
|
return mkApp6
|
||||||
(mkConst congrThm)
|
(mkConst congrThm)
|
||||||
lhsExpr rhsExpr
|
lhsExpr rhsExpr
|
||||||
@@ -95,8 +101,9 @@ def mkNot (sub : ReifiedBVLogical) (subExpr : Expr) : M ReifiedBVLogical := do
|
|||||||
let boolExpr := .not sub.bvExpr
|
let boolExpr := .not sub.bvExpr
|
||||||
let expr := mkApp2 (mkConst ``BoolExpr.not) (mkConst ``BVPred) sub.expr
|
let expr := mkApp2 (mkConst ``BoolExpr.not) (mkConst ``BVPred) sub.expr
|
||||||
let proof := do
|
let proof := do
|
||||||
|
-- This is safe as `not_congr` holds definitionally if the arguments are defeq.
|
||||||
|
let some subProof ← sub.evalsAtAtoms | return none
|
||||||
let subEvalExpr ← ReifiedBVLogical.mkEvalExpr sub.expr
|
let subEvalExpr ← ReifiedBVLogical.mkEvalExpr sub.expr
|
||||||
let subProof ← sub.evalsAtAtoms
|
|
||||||
return mkApp3 (mkConst ``Std.Tactic.BVDecide.Reflect.Bool.not_congr) subExpr subEvalExpr subProof
|
return mkApp3 (mkConst ``Std.Tactic.BVDecide.Reflect.Bool.not_congr) subExpr subEvalExpr subProof
|
||||||
return ⟨boolExpr, proof, expr⟩
|
return ⟨boolExpr, proof, expr⟩
|
||||||
|
|
||||||
@@ -119,9 +126,15 @@ def mkIte (discr lhs rhs : ReifiedBVLogical) (discrExpr lhsExpr rhsExpr : Expr)
|
|||||||
let discrEvalExpr ← ReifiedBVLogical.mkEvalExpr discr.expr
|
let discrEvalExpr ← ReifiedBVLogical.mkEvalExpr discr.expr
|
||||||
let lhsEvalExpr ← ReifiedBVLogical.mkEvalExpr lhs.expr
|
let lhsEvalExpr ← ReifiedBVLogical.mkEvalExpr lhs.expr
|
||||||
let rhsEvalExpr ← ReifiedBVLogical.mkEvalExpr rhs.expr
|
let rhsEvalExpr ← ReifiedBVLogical.mkEvalExpr rhs.expr
|
||||||
let discrProof ← discr.evalsAtAtoms
|
let discrProof? ← discr.evalsAtAtoms
|
||||||
let lhsProof ← lhs.evalsAtAtoms
|
let lhsProof? ← lhs.evalsAtAtoms
|
||||||
let rhsProof ← rhs.evalsAtAtoms
|
let rhsProof? ← rhs.evalsAtAtoms
|
||||||
|
let some (discrProof, lhsProof, rhsProof) :=
|
||||||
|
M.simplifyTernaryProof
|
||||||
|
ReifiedBVLogical.mkRefl
|
||||||
|
discrEvalExpr discrProof?
|
||||||
|
lhsEvalExpr lhsProof?
|
||||||
|
rhsEvalExpr rhsProof? | return none
|
||||||
return mkApp9
|
return mkApp9
|
||||||
(mkConst ``Std.Tactic.BVDecide.Reflect.Bool.ite_congr)
|
(mkConst ``Std.Tactic.BVDecide.Reflect.Bool.ite_congr)
|
||||||
discrExpr lhsExpr rhsExpr
|
discrExpr lhsExpr rhsExpr
|
||||||
|
|||||||
@@ -35,8 +35,10 @@ def boolAtom (t : Expr) : M (Option ReifiedBVPred) := do
|
|||||||
let bvExpr : BVPred := .getLsbD atom.bvExpr 0
|
let bvExpr : BVPred := .getLsbD atom.bvExpr 0
|
||||||
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr 1) atom.expr (toExpr 0)
|
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr 1) atom.expr (toExpr 0)
|
||||||
let proof := do
|
let proof := do
|
||||||
|
-- ofBool_congr does not hold definitionally, if this ever becomes an issue we need to find
|
||||||
|
-- a more clever encoding for boolean atoms
|
||||||
let atomEval ← ReifiedBVExpr.mkEvalExpr atom.width atom.expr
|
let atomEval ← ReifiedBVExpr.mkEvalExpr atom.width atom.expr
|
||||||
let atomProof ← atom.evalsAtAtoms
|
let atomProof := (← atom.evalsAtAtoms).getD (ReifiedBVExpr.mkBVRefl atom.width atomEval)
|
||||||
return mkApp3
|
return mkApp3
|
||||||
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.ofBool_congr)
|
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.ofBool_congr)
|
||||||
t
|
t
|
||||||
@@ -63,9 +65,14 @@ def mkBinPred (lhs rhs : ReifiedBVExpr) (lhsExpr rhsExpr : Expr) (pred : BVBinPr
|
|||||||
rhs.expr
|
rhs.expr
|
||||||
let proof := do
|
let proof := do
|
||||||
let lhsEval ← ReifiedBVExpr.mkEvalExpr lhs.width lhs.expr
|
let lhsEval ← ReifiedBVExpr.mkEvalExpr lhs.width lhs.expr
|
||||||
let lhsProof ← lhs.evalsAtAtoms
|
|
||||||
let rhsEval ← ReifiedBVExpr.mkEvalExpr rhs.width rhs.expr
|
let rhsEval ← ReifiedBVExpr.mkEvalExpr rhs.width rhs.expr
|
||||||
let rhsProof ← rhs.evalsAtAtoms
|
let lhsProof? ← lhs.evalsAtAtoms
|
||||||
|
let rhsProof? ← rhs.evalsAtAtoms
|
||||||
|
let some (lhsProof, rhsProof) :=
|
||||||
|
M.simplifyBinaryProof
|
||||||
|
(ReifiedBVExpr.mkBVRefl lhs.width)
|
||||||
|
lhsEval lhsProof?
|
||||||
|
rhsEval rhsProof? | return none
|
||||||
return mkApp7
|
return mkApp7
|
||||||
(mkConst congrThm)
|
(mkConst congrThm)
|
||||||
(toExpr lhs.width)
|
(toExpr lhs.width)
|
||||||
@@ -90,8 +97,9 @@ def mkGetLsbD (sub : ReifiedBVExpr) (subExpr : Expr) (idx : Nat) : M ReifiedBVPr
|
|||||||
let idxExpr := toExpr idx
|
let idxExpr := toExpr idx
|
||||||
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr sub.width) sub.expr idxExpr
|
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr sub.width) sub.expr idxExpr
|
||||||
let proof := do
|
let proof := do
|
||||||
|
-- This is safe as `getLsbD_congr` holds definitionally if the arguments are defeq.
|
||||||
|
let some subProof ← sub.evalsAtAtoms | return none
|
||||||
let subEval ← ReifiedBVExpr.mkEvalExpr sub.width sub.expr
|
let subEval ← ReifiedBVExpr.mkEvalExpr sub.width sub.expr
|
||||||
let subProof ← sub.evalsAtAtoms
|
|
||||||
return mkApp5
|
return mkApp5
|
||||||
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.getLsbD_congr)
|
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.getLsbD_congr)
|
||||||
idxExpr
|
idxExpr
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ where
|
|||||||
|
|
||||||
let proof := do
|
let proof := do
|
||||||
let evalExpr ← ReifiedBVLogical.mkEvalExpr imp.expr
|
let evalExpr ← ReifiedBVLogical.mkEvalExpr imp.expr
|
||||||
let congrProof ← imp.evalsAtAtoms
|
let congrProof := (← imp.evalsAtAtoms).getD (ReifiedBVLogical.mkRefl evalExpr)
|
||||||
let lemmaProof := mkApp4 (mkConst lemmaName) (toExpr lhs.width) discrExpr lhsExpr rhsExpr
|
let lemmaProof := mkApp4 (mkConst lemmaName) (toExpr lhs.width) discrExpr lhsExpr rhsExpr
|
||||||
|
|
||||||
let trueExpr := mkConst ``Bool.true
|
let trueExpr := mkConst ``Bool.true
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ where
|
|||||||
inner.expr
|
inner.expr
|
||||||
let proof := do
|
let proof := do
|
||||||
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
||||||
let innerProof ← inner.evalsAtAtoms
|
-- This is safe as `zeroExtend_congr` holds definitionally if the arguments are defeq.
|
||||||
|
let some innerProof ← inner.evalsAtAtoms | return none
|
||||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.zeroExtend_congr)
|
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.zeroExtend_congr)
|
||||||
newWidthExpr
|
newWidthExpr
|
||||||
(toExpr inner.width)
|
(toExpr inner.width)
|
||||||
@@ -132,7 +133,8 @@ where
|
|||||||
inner.expr
|
inner.expr
|
||||||
let proof := do
|
let proof := do
|
||||||
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
||||||
let innerProof ← inner.evalsAtAtoms
|
-- This is safe as `zeroExtend_congr` holds definitionally if the arguments are defeq.
|
||||||
|
let some innerProof ← inner.evalsAtAtoms | return none
|
||||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.signExtend_congr)
|
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.signExtend_congr)
|
||||||
newWidthExpr
|
newWidthExpr
|
||||||
(toExpr inner.width)
|
(toExpr inner.width)
|
||||||
@@ -150,9 +152,13 @@ where
|
|||||||
lhs.expr rhs.expr
|
lhs.expr rhs.expr
|
||||||
let proof := do
|
let proof := do
|
||||||
let lhsEval ← ReifiedBVExpr.mkEvalExpr lhs.width lhs.expr
|
let lhsEval ← ReifiedBVExpr.mkEvalExpr lhs.width lhs.expr
|
||||||
let lhsProof ← lhs.evalsAtAtoms
|
|
||||||
let rhsProof ← rhs.evalsAtAtoms
|
|
||||||
let rhsEval ← ReifiedBVExpr.mkEvalExpr rhs.width rhs.expr
|
let rhsEval ← ReifiedBVExpr.mkEvalExpr rhs.width rhs.expr
|
||||||
|
let lhsProof? ← lhs.evalsAtAtoms
|
||||||
|
let rhsProof? ← rhs.evalsAtAtoms
|
||||||
|
let some (lhsProof, rhsProof) :=
|
||||||
|
M.simplifyBinaryProof'
|
||||||
|
(ReifiedBVExpr.mkBVRefl lhs.width) lhsEval lhsProof?
|
||||||
|
(ReifiedBVExpr.mkBVRefl rhs.width) rhsEval rhsProof? | return none
|
||||||
return mkApp8 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.append_congr)
|
return mkApp8 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.append_congr)
|
||||||
(toExpr lhs.width) (toExpr rhs.width)
|
(toExpr lhs.width) (toExpr rhs.width)
|
||||||
lhsExpr lhsEval
|
lhsExpr lhsEval
|
||||||
@@ -169,7 +175,8 @@ where
|
|||||||
inner.expr
|
inner.expr
|
||||||
let proof := do
|
let proof := do
|
||||||
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
||||||
let innerProof ← inner.evalsAtAtoms
|
-- This is safe as `zeroExtend_congr` holds definitionally if the arguments are defeq.
|
||||||
|
let some innerProof ← inner.evalsAtAtoms | return none
|
||||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.replicate_congr)
|
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.replicate_congr)
|
||||||
(toExpr n)
|
(toExpr n)
|
||||||
(toExpr inner.width)
|
(toExpr inner.width)
|
||||||
@@ -189,7 +196,8 @@ where
|
|||||||
inner.expr
|
inner.expr
|
||||||
let proof := do
|
let proof := do
|
||||||
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
||||||
let innerProof ← inner.evalsAtAtoms
|
-- This is safe as `zeroExtend_congr` holds definitionally if the arguments are defeq.
|
||||||
|
let some innerProof ← inner.evalsAtAtoms | return none
|
||||||
return mkApp6 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.extract_congr)
|
return mkApp6 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.extract_congr)
|
||||||
startExpr
|
startExpr
|
||||||
lenExpr
|
lenExpr
|
||||||
@@ -301,11 +309,16 @@ where
|
|||||||
return none
|
return none
|
||||||
|
|
||||||
binaryCongrProof (lhs rhs : ReifiedBVExpr) (lhsExpr rhsExpr : Expr) (congrThm : Expr) :
|
binaryCongrProof (lhs rhs : ReifiedBVExpr) (lhsExpr rhsExpr : Expr) (congrThm : Expr) :
|
||||||
M Expr := do
|
M (Option Expr) := do
|
||||||
let lhsEval ← ReifiedBVExpr.mkEvalExpr lhs.width lhs.expr
|
let lhsEval ← ReifiedBVExpr.mkEvalExpr lhs.width lhs.expr
|
||||||
let lhsProof ← lhs.evalsAtAtoms
|
|
||||||
let rhsProof ← rhs.evalsAtAtoms
|
|
||||||
let rhsEval ← ReifiedBVExpr.mkEvalExpr rhs.width rhs.expr
|
let rhsEval ← ReifiedBVExpr.mkEvalExpr rhs.width rhs.expr
|
||||||
|
let lhsProof? ← lhs.evalsAtAtoms
|
||||||
|
let rhsProof? ← rhs.evalsAtAtoms
|
||||||
|
let some (lhsProof, rhsProof) :=
|
||||||
|
M.simplifyBinaryProof
|
||||||
|
(ReifiedBVExpr.mkBVRefl lhs.width)
|
||||||
|
lhsEval lhsProof?
|
||||||
|
rhsEval rhsProof? | return none
|
||||||
return mkApp6 congrThm lhsExpr rhsExpr lhsEval rhsEval lhsProof rhsProof
|
return mkApp6 congrThm lhsExpr rhsExpr lhsEval rhsEval lhsProof rhsProof
|
||||||
|
|
||||||
unaryReflection (innerExpr : Expr) (op : BVUnOp) (congrThm : Name) :
|
unaryReflection (innerExpr : Expr) (op : BVUnOp) (congrThm : Name) :
|
||||||
@@ -316,9 +329,9 @@ where
|
|||||||
let proof := unaryCongrProof inner innerExpr (mkConst congrThm)
|
let proof := unaryCongrProof inner innerExpr (mkConst congrThm)
|
||||||
return some ⟨inner.width, bvExpr, proof, expr⟩
|
return some ⟨inner.width, bvExpr, proof, expr⟩
|
||||||
|
|
||||||
unaryCongrProof (inner : ReifiedBVExpr) (innerExpr : Expr) (congrProof : Expr) : M Expr := do
|
unaryCongrProof (inner : ReifiedBVExpr) (innerExpr : Expr) (congrProof : Expr) : M (Option Expr) := do
|
||||||
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
let innerEval ← ReifiedBVExpr.mkEvalExpr inner.width inner.expr
|
||||||
let innerProof ← inner.evalsAtAtoms
|
let some innerProof ← inner.evalsAtAtoms | return none
|
||||||
return mkApp4 congrProof (toExpr inner.width) innerExpr innerEval innerProof
|
return mkApp4 congrProof (toExpr inner.width) innerExpr innerEval innerProof
|
||||||
|
|
||||||
goBvLit (x : Expr) : M (Option ReifiedBVExpr) := do
|
goBvLit (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ partial def of (h : Expr) : LemmaM (Option SatAtBVLogical) := do
|
|||||||
let proof := do
|
let proof := do
|
||||||
let evalLogic ← ReifiedBVLogical.mkEvalExpr bvLogical.expr
|
let evalLogic ← ReifiedBVLogical.mkEvalExpr bvLogical.expr
|
||||||
-- this is evalLogic = lhsExpr
|
-- this is evalLogic = lhsExpr
|
||||||
let evalProof ← bvLogical.evalsAtAtoms
|
let evalProof := (← bvLogical.evalsAtAtoms).getD (ReifiedBVLogical.mkRefl evalLogic)
|
||||||
-- h is lhsExpr = true
|
-- h is lhsExpr = true
|
||||||
-- we prove evalLogic = true by evalLogic = lhsExpr = true
|
-- we prove evalLogic = true by evalLogic = lhsExpr = true
|
||||||
return ReifiedBVLogical.mkTrans evalLogic lhsExpr (mkConst ``Bool.true) evalProof h
|
return ReifiedBVLogical.mkTrans evalLogic lhsExpr (mkConst ``Bool.true) evalProof h
|
||||||
@@ -61,13 +61,16 @@ def and (x y : SatAtBVLogical) : SatAtBVLogical where
|
|||||||
|
|
||||||
/-- Given a proof that `x.expr.Unsat`, produce a proof of `False`. -/
|
/-- Given a proof that `x.expr.Unsat`, produce a proof of `False`. -/
|
||||||
def proveFalse (x : SatAtBVLogical) (h : Expr) : M Expr := do
|
def proveFalse (x : SatAtBVLogical) (h : Expr) : M Expr := do
|
||||||
let atomsList ← M.atomsAssignment
|
if (← get).atoms.isEmpty then
|
||||||
let evalExpr := mkApp2 (mkConst ``BVLogicalExpr.eval) atomsList x.expr
|
throwError "Unable to identify any relevant atoms."
|
||||||
return mkApp3
|
else
|
||||||
(mkConst ``Std.Tactic.BVDecide.Reflect.Bool.false_of_eq_true_of_eq_false)
|
let atomsList ← M.atomsAssignment
|
||||||
evalExpr
|
let evalExpr := mkApp2 (mkConst ``BVLogicalExpr.eval) atomsList x.expr
|
||||||
(← x.satAtAtoms)
|
return mkApp3
|
||||||
(.app h atomsList)
|
(mkConst ``Std.Tactic.BVDecide.Reflect.Bool.false_of_eq_true_of_eq_false)
|
||||||
|
evalExpr
|
||||||
|
(← x.satAtAtoms)
|
||||||
|
(.app h atomsList)
|
||||||
|
|
||||||
|
|
||||||
end SatAtBVLogical
|
end SatAtBVLogical
|
||||||
|
|||||||
@@ -168,20 +168,16 @@ def numeralToCoe (e : Expr) : MetaM Simp.Result := do
|
|||||||
let some pr ← proveEqUsingDown e newE | failure
|
let some pr ← proveEqUsingDown e newE | failure
|
||||||
return pr
|
return pr
|
||||||
|
|
||||||
|
declare_config_elab elabNormCastConfig NormCastConfig
|
||||||
|
|
||||||
/--
|
/--
|
||||||
The core simplification routine of `normCast`.
|
The core simplification routine of `normCast`.
|
||||||
-/
|
-/
|
||||||
def derive (e : Expr) : MetaM Simp.Result := do
|
def derive (e : Expr) (config : NormCastConfig := {}) : MetaM Simp.Result := do
|
||||||
withTraceNode `Tactic.norm_cast (fun _ => return m!"{e}") do
|
withTraceNode `Tactic.norm_cast (fun _ => return m!"{e}") do
|
||||||
let e ← instantiateMVars e
|
let e ← instantiateMVars e
|
||||||
|
|
||||||
let config : Simp.Config := {
|
let config := config.toConfig
|
||||||
zeta := false
|
|
||||||
beta := false
|
|
||||||
eta := false
|
|
||||||
proj := false
|
|
||||||
iota := false
|
|
||||||
}
|
|
||||||
let congrTheorems ← Meta.getSimpCongrTheorems
|
let congrTheorems ← Meta.getSimpCongrTheorems
|
||||||
|
|
||||||
let r : Simp.Result := { expr := e }
|
let r : Simp.Result := { expr := e }
|
||||||
@@ -193,13 +189,13 @@ def derive (e : Expr) : MetaM Simp.Result := do
|
|||||||
-- step 1: pre-processing of numerals
|
-- step 1: pre-processing of numerals
|
||||||
let r ← withTrace "pre-processing numerals" do
|
let r ← withTrace "pre-processing numerals" do
|
||||||
let post e := return Simp.Step.done (← try numeralToCoe e catch _ => pure {expr := e})
|
let post e := return Simp.Step.done (← try numeralToCoe e catch _ => pure {expr := e})
|
||||||
let ctx ← Simp.mkContext (config := config) (congrTheorems := congrTheorems)
|
let ctx ← Simp.mkContext config (congrTheorems := congrTheorems)
|
||||||
r.mkEqTrans (← Simp.main r.expr ctx (methods := { post })).1
|
r.mkEqTrans (← Simp.main r.expr ctx (methods := { post })).1
|
||||||
|
|
||||||
-- step 2: casts are moved upwards and eliminated
|
-- step 2: casts are moved upwards and eliminated
|
||||||
let r ← withTrace "moving upward, splitting and eliminating" do
|
let r ← withTrace "moving upward, splitting and eliminating" do
|
||||||
let post := upwardAndElim (← normCastExt.up.getTheorems)
|
let post := upwardAndElim (← normCastExt.up.getTheorems)
|
||||||
let ctx ← Simp.mkContext (config := config) (congrTheorems := congrTheorems)
|
let ctx ← Simp.mkContext config (congrTheorems := congrTheorems)
|
||||||
r.mkEqTrans (← Simp.main r.expr ctx (methods := { post })).1
|
r.mkEqTrans (← Simp.main r.expr ctx (methods := { post })).1
|
||||||
|
|
||||||
let simprocs ← ({} : Simp.SimprocsArray).add `reduceCtorEq false
|
let simprocs ← ({} : Simp.SimprocsArray).add `reduceCtorEq false
|
||||||
@@ -234,32 +230,33 @@ open Term
|
|||||||
| _ => throwUnsupportedSyntax
|
| _ => throwUnsupportedSyntax
|
||||||
|
|
||||||
/-- Implementation of the `norm_cast` tactic when operating on the main goal. -/
|
/-- Implementation of the `norm_cast` tactic when operating on the main goal. -/
|
||||||
def normCastTarget : TacticM Unit :=
|
def normCastTarget (cfg : NormCastConfig) : TacticM Unit :=
|
||||||
liftMetaTactic1 fun goal => do
|
liftMetaTactic1 fun goal => do
|
||||||
let tgt ← instantiateMVars (← goal.getType)
|
let tgt ← instantiateMVars (← goal.getType)
|
||||||
let prf ← derive tgt
|
let prf ← derive tgt cfg
|
||||||
applySimpResultToTarget goal tgt prf
|
applySimpResultToTarget goal tgt prf
|
||||||
|
|
||||||
/-- Implementation of the `norm_cast` tactic when operating on a hypothesis. -/
|
/-- Implementation of the `norm_cast` tactic when operating on a hypothesis. -/
|
||||||
def normCastHyp (fvarId : FVarId) : TacticM Unit :=
|
def normCastHyp (cfg : NormCastConfig) (fvarId : FVarId) : TacticM Unit :=
|
||||||
liftMetaTactic1 fun goal => do
|
liftMetaTactic1 fun goal => do
|
||||||
let hyp ← instantiateMVars (← fvarId.getDecl).type
|
let hyp ← instantiateMVars (← fvarId.getDecl).type
|
||||||
let prf ← derive hyp
|
let prf ← derive hyp cfg
|
||||||
return (← applySimpResultToLocalDecl goal fvarId prf false).map (·.snd)
|
return (← applySimpResultToLocalDecl goal fvarId prf false).map (·.snd)
|
||||||
|
|
||||||
@[builtin_tactic normCast0]
|
@[builtin_tactic normCast0]
|
||||||
def evalNormCast0 : Tactic := fun stx => do
|
def evalNormCast0 : Tactic := fun stx => do
|
||||||
match stx with
|
match stx with
|
||||||
| `(tactic| norm_cast0 $[$loc?]?) =>
|
| `(tactic| norm_cast0 $cfg $[$loc?]?) =>
|
||||||
let loc := if let some loc := loc? then expandLocation loc else Location.targets #[] true
|
let loc := if let some loc := loc? then expandLocation loc else Location.targets #[] true
|
||||||
|
let cfg ← elabNormCastConfig cfg
|
||||||
withMainContext do
|
withMainContext do
|
||||||
match loc with
|
match loc with
|
||||||
| Location.targets hyps target =>
|
| Location.targets hyps target =>
|
||||||
if target then normCastTarget
|
if target then (normCastTarget cfg)
|
||||||
(← getFVarIds hyps).forM normCastHyp
|
(← getFVarIds hyps).forM (normCastHyp cfg)
|
||||||
| Location.wildcard =>
|
| Location.wildcard =>
|
||||||
normCastTarget
|
normCastTarget cfg
|
||||||
(← (← getMainGoal).getNondepPropHyps).forM normCastHyp
|
(← (← getMainGoal).getNondepPropHyps).forM (normCastHyp cfg)
|
||||||
| _ => throwUnsupportedSyntax
|
| _ => throwUnsupportedSyntax
|
||||||
|
|
||||||
@[builtin_tactic Lean.Parser.Tactic.Conv.normCast]
|
@[builtin_tactic Lean.Parser.Tactic.Conv.normCast]
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ partial def asLinearComboImpl (e : Expr) : OmegaM (LinearCombo × OmegaM Expr ×
|
|||||||
| .app (.app (.app (.app (.const ``Prod.mk [u, v]) _) _) x) y =>
|
| .app (.app (.app (.app (.const ``Prod.mk [u, v]) _) _) x) y =>
|
||||||
rewrite e (mkApp4 (.const ``Prod.snd_mk [u, v]) α x β y)
|
rewrite e (mkApp4 (.const ``Prod.snd_mk [u, v]) α x β y)
|
||||||
| _ => mkAtomLinearCombo e
|
| _ => mkAtomLinearCombo e
|
||||||
|
| (``Int.negSucc, #[n]) => rewrite e (mkApp (.const ``Int.negSucc_eq []) n)
|
||||||
| _ => mkAtomLinearCombo e
|
| _ => mkAtomLinearCombo e
|
||||||
where
|
where
|
||||||
/--
|
/--
|
||||||
|
|||||||
@@ -1235,6 +1235,9 @@ def getRevArg!' : Expr → Nat → Expr
|
|||||||
@[inline] def getArgD (e : Expr) (i : Nat) (v₀ : Expr) (n := e.getAppNumArgs) : Expr :=
|
@[inline] def getArgD (e : Expr) (i : Nat) (v₀ : Expr) (n := e.getAppNumArgs) : Expr :=
|
||||||
getRevArgD e (n - i - 1) v₀
|
getRevArgD e (n - i - 1) v₀
|
||||||
|
|
||||||
|
/-- Return `true` if `e` contains any loose bound variables.
|
||||||
|
|
||||||
|
This is a constant time operation. -/
|
||||||
def hasLooseBVars (e : Expr) : Bool :=
|
def hasLooseBVars (e : Expr) : Bool :=
|
||||||
e.looseBVarRange > 0
|
e.looseBVarRange > 0
|
||||||
|
|
||||||
@@ -1247,6 +1250,11 @@ def isArrow (e : Expr) : Bool :=
|
|||||||
| forallE _ _ b _ => !b.hasLooseBVars
|
| forallE _ _ b _ => !b.hasLooseBVars
|
||||||
| _ => false
|
| _ => false
|
||||||
|
|
||||||
|
/--
|
||||||
|
Return `true` if `e` contains the specified loose bound variable with index `bvarIdx`.
|
||||||
|
|
||||||
|
This operation traverses the expression tree.
|
||||||
|
-/
|
||||||
@[extern "lean_expr_has_loose_bvar"]
|
@[extern "lean_expr_has_loose_bvar"]
|
||||||
opaque hasLooseBVar (e : @& Expr) (bvarIdx : @& Nat) : Bool
|
opaque hasLooseBVar (e : @& Expr) (bvarIdx : @& Nat) : Bool
|
||||||
|
|
||||||
|
|||||||
@@ -433,6 +433,8 @@ where
|
|||||||
}
|
}
|
||||||
-- now that imports have been loaded, check options again
|
-- now that imports have been loaded, check options again
|
||||||
let opts ← reparseOptions setup.opts
|
let opts ← reparseOptions setup.opts
|
||||||
|
-- default to async elaboration; see also `Elab.async` docs
|
||||||
|
let opts := Elab.async.setIfNotSet opts true
|
||||||
let cmdState := Elab.Command.mkState headerEnv msgLog opts
|
let cmdState := Elab.Command.mkState headerEnv msgLog opts
|
||||||
let cmdState := { cmdState with
|
let cmdState := { cmdState with
|
||||||
infoState := {
|
infoState := {
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ def checkDeprecated [Monad m] [MonadEnv m] [MonadLog m] [AddMessageContext m] [M
|
|||||||
if getLinterValue linter.deprecated (← getOptions) then
|
if getLinterValue linter.deprecated (← getOptions) then
|
||||||
let some attr := deprecatedAttr.getParam? (← getEnv) declName | pure ()
|
let some attr := deprecatedAttr.getParam? (← getEnv) declName | pure ()
|
||||||
logWarning <| .tagged ``deprecatedAttr <|
|
logWarning <| .tagged ``deprecatedAttr <|
|
||||||
s!"`{declName}` has been deprecated" ++ match attr.text? with
|
m!"`{.ofConstName declName true}` has been deprecated" ++ match attr.text? with
|
||||||
| some text => s!": {text}"
|
| some text => s!": {text}"
|
||||||
| none => match attr.newName? with
|
| none => match attr.newName? with
|
||||||
| some newName => s!": use `{newName}` instead"
|
| some newName => m!": use `{.ofConstName newName true}` instead"
|
||||||
| none => ""
|
| none => ""
|
||||||
|
|||||||
@@ -441,6 +441,10 @@ instance : Append MessageLog :=
|
|||||||
def hasErrors (log : MessageLog) : Bool :=
|
def hasErrors (log : MessageLog) : Bool :=
|
||||||
log.hadErrors || log.unreported.any (·.severity matches .error)
|
log.hadErrors || log.unreported.any (·.severity matches .error)
|
||||||
|
|
||||||
|
/-- Clears unreported messages while preserving `hasErrors`. -/
|
||||||
|
def markAllReported (log : MessageLog) : MessageLog :=
|
||||||
|
{ log with unreported := {}, hadErrors := log.hasErrors }
|
||||||
|
|
||||||
def errorsToWarnings (log : MessageLog) : MessageLog :=
|
def errorsToWarnings (log : MessageLog) : MessageLog :=
|
||||||
{ unreported := log.unreported.map (fun m => match m.severity with | MessageSeverity.error => { m with severity := MessageSeverity.warning } | _ => m) }
|
{ unreported := log.unreported.map (fun m => match m.severity with | MessageSeverity.error => { m with severity := MessageSeverity.warning } | _ => m) }
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ Unpacks a unary packed argument created with `Unary.pack`.
|
|||||||
|
|
||||||
Throws an error if the expression is not of that form.
|
Throws an error if the expression is not of that form.
|
||||||
-/
|
-/
|
||||||
def unpack (arity : Nat) (e : Expr) : MetaM (Array Expr) := do
|
def unpack (arity : Nat) (e : Expr) : Option (Array Expr) := do
|
||||||
let mut e := e
|
let mut e := e
|
||||||
let mut args := #[]
|
let mut args := #[]
|
||||||
while args.size + 1 < arity do
|
while args.size + 1 < arity do
|
||||||
@@ -95,11 +95,10 @@ def unpack (arity : Nat) (e : Expr) : MetaM (Array Expr) := do
|
|||||||
args := args.push (e.getArg! 2)
|
args := args.push (e.getArg! 2)
|
||||||
e := e.getArg! 3
|
e := e.getArg! 3
|
||||||
else
|
else
|
||||||
throwError "Unexpected expression while unpacking n-ary argument"
|
none
|
||||||
args := args.push e
|
args := args.push e
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Given a (dependent) tuple `t` (using `PSigma`) of the given arity.
|
Given a (dependent) tuple `t` (using `PSigma`) of the given arity.
|
||||||
Return an array containing its "elements".
|
Return an array containing its "elements".
|
||||||
@@ -258,7 +257,7 @@ argument and function index.
|
|||||||
|
|
||||||
Throws an error if the expression is not of that form.
|
Throws an error if the expression is not of that form.
|
||||||
-/
|
-/
|
||||||
def unpack (numFuncs : Nat) (expr : Expr) : MetaM (Nat × Expr) := do
|
def unpack (numFuncs : Nat) (expr : Expr) : Option (Nat × Expr) := do
|
||||||
let mut funidx := 0
|
let mut funidx := 0
|
||||||
let mut e := expr
|
let mut e := expr
|
||||||
while funidx + 1 < numFuncs do
|
while funidx + 1 < numFuncs do
|
||||||
@@ -269,7 +268,7 @@ def unpack (numFuncs : Nat) (expr : Expr) : MetaM (Nat × Expr) := do
|
|||||||
e := e.getArg! 2
|
e := e.getArg! 2
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
throwError "Unexpected expression while unpacking mutual argument:{indentExpr expr}"
|
none
|
||||||
return (funidx, e)
|
return (funidx, e)
|
||||||
|
|
||||||
|
|
||||||
@@ -377,14 +376,17 @@ and `(z : C) → R₂[z]`, returns an expression of type
|
|||||||
(x : A ⊕' C) → (match x with | .inl x => R₁[x] | .inr R₂[z])
|
(x : A ⊕' C) → (match x with | .inl x => R₁[x] | .inr R₂[z])
|
||||||
```
|
```
|
||||||
-/
|
-/
|
||||||
def uncurry (es : Array Expr) : MetaM Expr := do
|
def uncurryWithType (resultType : Expr) (es : Array Expr) : MetaM Expr := do
|
||||||
let types ← es.mapM inferType
|
|
||||||
let resultType ← uncurryType types
|
|
||||||
forallBoundedTelescope resultType (some 1) fun xs codomain => do
|
forallBoundedTelescope resultType (some 1) fun xs codomain => do
|
||||||
let #[x] := xs | unreachable!
|
let #[x] := xs | unreachable!
|
||||||
let value ← casesOn x codomain es.toList
|
let value ← casesOn x codomain es.toList
|
||||||
mkLambdaFVars #[x] value
|
mkLambdaFVars #[x] value
|
||||||
|
|
||||||
|
def uncurry (es : Array Expr) : MetaM Expr := do
|
||||||
|
let types ← es.mapM inferType
|
||||||
|
let resultType ← uncurryType types
|
||||||
|
uncurryWithType resultType es
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Given unary expressions `e₁`, `e₂` with types `(x : A) → R`
|
Given unary expressions `e₁`, `e₂` with types `(x : A) → R`
|
||||||
and `(z : C) → R`, returns an expression of type
|
and `(z : C) → R`, returns an expression of type
|
||||||
@@ -414,7 +416,7 @@ def curryType (n : Nat) (type : Expr) : MetaM (Array Expr) := do
|
|||||||
|
|
||||||
end Mutual
|
end Mutual
|
||||||
|
|
||||||
-- Now for the main definitions in this moduleo
|
-- Now for the main definitions in this module
|
||||||
|
|
||||||
/-- The number of functions being packed -/
|
/-- The number of functions being packed -/
|
||||||
def numFuncs (argsPacker : ArgsPacker) : Nat := argsPacker.varNamess.size
|
def numFuncs (argsPacker : ArgsPacker) : Nat := argsPacker.varNamess.size
|
||||||
@@ -422,6 +424,10 @@ def numFuncs (argsPacker : ArgsPacker) : Nat := argsPacker.varNamess.size
|
|||||||
/-- The arities of the functions being packed -/
|
/-- The arities of the functions being packed -/
|
||||||
def arities (argsPacker : ArgsPacker) : Array Nat := argsPacker.varNamess.map (·.size)
|
def arities (argsPacker : ArgsPacker) : Array Nat := argsPacker.varNamess.map (·.size)
|
||||||
|
|
||||||
|
def onlyOneUnary (argsPacker : ArgsPacker) :=
|
||||||
|
argsPacker.varNamess.size = 1 &&
|
||||||
|
argsPacker.varNamess[0]!.size = 1
|
||||||
|
|
||||||
def pack (argsPacker : ArgsPacker) (domain : Expr) (fidx : Nat) (args : Array Expr)
|
def pack (argsPacker : ArgsPacker) (domain : Expr) (fidx : Nat) (args : Array Expr)
|
||||||
: MetaM Expr := do
|
: MetaM Expr := do
|
||||||
assert! fidx < argsPacker.numFuncs
|
assert! fidx < argsPacker.numFuncs
|
||||||
@@ -436,14 +442,13 @@ return the function index that is called and the arguments individually.
|
|||||||
|
|
||||||
We expect precisely the expressions produced by `pack`, with manifest
|
We expect precisely the expressions produced by `pack`, with manifest
|
||||||
`PSum.inr`, `PSum.inl` and `PSigma.mk` constructors, and thus take them apart
|
`PSum.inr`, `PSum.inl` and `PSigma.mk` constructors, and thus take them apart
|
||||||
rather than using projectinos.
|
rather than using projections.
|
||||||
-/
|
-/
|
||||||
def unpack (argsPacker : ArgsPacker) (e : Expr) : MetaM (Nat × Array Expr) := do
|
def unpack (argsPacker : ArgsPacker) (e : Expr) : Option (Nat × Array Expr) := do
|
||||||
let (funidx, e) ← Mutual.unpack argsPacker.numFuncs e
|
let (funidx, e) ← Mutual.unpack argsPacker.numFuncs e
|
||||||
let args ← Unary.unpack argsPacker.varNamess[funidx]!.size e
|
let args ← Unary.unpack argsPacker.varNamess[funidx]!.size e
|
||||||
return (funidx, args)
|
return (funidx, args)
|
||||||
|
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Given types `(x : A) → (y : B[x]) → R₁[x,y]` and `(z : C) → R₂[z]`, returns the type uncurried type
|
Given types `(x : A) → (y : B[x]) → R₁[x,y]` and `(z : C) → R₂[z]`, returns the type uncurried type
|
||||||
```
|
```
|
||||||
@@ -465,6 +470,10 @@ def uncurry (argsPacker : ArgsPacker) (es : Array Expr) : MetaM Expr := do
|
|||||||
let unary ← (Array.zipWith argsPacker.varNamess es Unary.uncurry).mapM id
|
let unary ← (Array.zipWith argsPacker.varNamess es Unary.uncurry).mapM id
|
||||||
Mutual.uncurry unary
|
Mutual.uncurry unary
|
||||||
|
|
||||||
|
def uncurryWithType (argsPacker : ArgsPacker) (resultType : Expr) (es : Array Expr) : MetaM Expr := do
|
||||||
|
let unary ← (Array.zipWith argsPacker.varNamess es Unary.uncurry).mapM id
|
||||||
|
Mutual.uncurryWithType resultType unary
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Given expressions `e₁`, `e₂` with types `(x : A) → (y : B[x]) → R`
|
Given expressions `e₁`, `e₂` with types `(x : A) → (y : B[x]) → R`
|
||||||
and `(z : C) → R`, returns an expression of type
|
and `(z : C) → R`, returns an expression of type
|
||||||
|
|||||||
@@ -35,11 +35,27 @@ def isConstructorApp? (e : Expr) : MetaM (Option ConstructorVal) := do
|
|||||||
|
|
||||||
/--
|
/--
|
||||||
Similar to `isConstructorApp?`, but uses `whnf`.
|
Similar to `isConstructorApp?`, but uses `whnf`.
|
||||||
|
It also uses `isOffset?` for `Nat`.
|
||||||
|
|
||||||
|
See also `Lean.Meta.constructorApp'?`.
|
||||||
-/
|
-/
|
||||||
def isConstructorApp'? (e : Expr) : MetaM (Option ConstructorVal) := do
|
def isConstructorApp'? (e : Expr) : MetaM (Option ConstructorVal) := do
|
||||||
if let some r ← isConstructorApp? e then
|
if let some (_, k) ← isOffset? e then
|
||||||
|
if k = 0 then
|
||||||
|
return none
|
||||||
|
else
|
||||||
|
let .ctorInfo val ← getConstInfo ``Nat.succ | return none
|
||||||
|
return some val
|
||||||
|
else if let some r ← isConstructorApp? e then
|
||||||
return r
|
return r
|
||||||
isConstructorApp? (← whnf e)
|
else try
|
||||||
|
/-
|
||||||
|
We added the `try` block here because `whnf` fails at terms `n ^ m`
|
||||||
|
when `m` is a big numeral, and `n` is a numeral. This is a little bit hackish.
|
||||||
|
-/
|
||||||
|
isConstructorApp? (← whnf e)
|
||||||
|
catch _ =>
|
||||||
|
return none
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Returns `true`, if `e` is constructor application of builtin literal defeq to
|
Returns `true`, if `e` is constructor application of builtin literal defeq to
|
||||||
@@ -70,7 +86,9 @@ def constructorApp? (e : Expr) : MetaM (Option (ConstructorVal × Array Expr)) :
|
|||||||
|
|
||||||
/--
|
/--
|
||||||
Similar to `constructorApp?`, but on failure it puts `e` in WHNF and tries again.
|
Similar to `constructorApp?`, but on failure it puts `e` in WHNF and tries again.
|
||||||
It also `isOffset?`
|
It also uses `isOffset?` for `Nat`.
|
||||||
|
|
||||||
|
See also `Lean.Meta.isConstructorApp'?`.
|
||||||
-/
|
-/
|
||||||
def constructorApp'? (e : Expr) : MetaM (Option (ConstructorVal × Array Expr)) := do
|
def constructorApp'? (e : Expr) : MetaM (Option (ConstructorVal × Array Expr)) := do
|
||||||
if let some (e, k) ← isOffset? e then
|
if let some (e, k) ← isOffset? e then
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ def getStringValue? (e : Expr) : (Option String) :=
|
|||||||
| .lit (.strVal s) => some s
|
| .lit (.strVal s) => some s
|
||||||
| _ => none
|
| _ => none
|
||||||
|
|
||||||
/-- Return `some ⟨n, v⟩` if `e` is af `OfNat.ofNat` application encoding a `Fin n` with value `v` -/
|
/-- Return `some ⟨n, v⟩` if `e` is an `OfNat.ofNat` application encoding a `Fin n` with value `v` -/
|
||||||
def getFinValue? (e : Expr) : MetaM (Option ((n : Nat) × Fin n)) := OptionT.run do
|
def getFinValue? (e : Expr) : MetaM (Option ((n : Nat) × Fin n)) := OptionT.run do
|
||||||
let (v, type) ← getOfNatValue? e ``Fin
|
let (v, type) ← getOfNatValue? e ``Fin
|
||||||
let n ← getNatValue? (← whnfD type.appArg!)
|
let n ← getNatValue? (← whnfD type.appArg!)
|
||||||
|
|||||||
@@ -719,13 +719,11 @@ def deriveUnaryInduction (name : Name) : MetaM Name := do
|
|||||||
let e' ← abstractIndependentMVars mvars (← motive.fvarId!.getDecl).index e'
|
let e' ← abstractIndependentMVars mvars (← motive.fvarId!.getDecl).index e'
|
||||||
let e' ← mkLambdaFVars #[motive] e'
|
let e' ← mkLambdaFVars #[motive] e'
|
||||||
|
|
||||||
-- We could pass (usedOnly := true) below, and get nicer induction principles that
|
-- We used to pass (usedOnly := false) below in the hope that the types of the
|
||||||
-- do not mention odd unused parameters.
|
-- induction principle match the type of the function better.
|
||||||
-- But the downside is that automatic instantiation of the principle (e.g. in a tactic
|
-- But this leads to avoidable parameters that make functional induction strictly less
|
||||||
-- that derives them from an function application in the goal) is harder, as
|
-- useful (e.g. when the unsued parameter mentions bound variables in the users' goal)
|
||||||
-- one would have to infer or keep track of which parameters to pass.
|
let e' ← mkLambdaFVars (binderInfoForMVars := .default) (usedOnly := true) fixedParams e'
|
||||||
-- So for now lets just keep them around.
|
|
||||||
let e' ← mkLambdaFVars (binderInfoForMVars := .default) fixedParams e'
|
|
||||||
instantiateMVars e'
|
instantiateMVars e'
|
||||||
| _ =>
|
| _ =>
|
||||||
if funBody.isAppOf ``WellFounded.fix then
|
if funBody.isAppOf ``WellFounded.fix then
|
||||||
@@ -812,7 +810,8 @@ def cleanPackedArgs (eqnInfo : WF.EqnInfo) (value : Expr) : MetaM Expr := do
|
|||||||
let args := e.getAppArgs
|
let args := e.getAppArgs
|
||||||
if eqnInfo.fixedPrefixSize + 1 ≤ args.size then
|
if eqnInfo.fixedPrefixSize + 1 ≤ args.size then
|
||||||
let packedArg := args.back!
|
let packedArg := args.back!
|
||||||
let (i, unpackedArgs) ← eqnInfo.argsPacker.unpack packedArg
|
let some (i, unpackedArgs) := eqnInfo.argsPacker.unpack packedArg
|
||||||
|
| throwError "Unexpected packedArg:{indentExpr packedArg}"
|
||||||
let e' := .const eqnInfo.declNames[i]! e.getAppFn.constLevels!
|
let e' := .const eqnInfo.declNames[i]! e.getAppFn.constLevels!
|
||||||
let e' := mkAppN e' args.pop
|
let e' := mkAppN e' args.pop
|
||||||
let e' := mkAppN e' unpackedArgs
|
let e' := mkAppN e' unpackedArgs
|
||||||
@@ -1062,13 +1061,11 @@ def deriveInductionStructural (names : Array Name) (numFixed : Nat) : MetaM Unit
|
|||||||
let e' ← abstractIndependentMVars mvars (← motives.back!.fvarId!.getDecl).index e'
|
let e' ← abstractIndependentMVars mvars (← motives.back!.fvarId!.getDecl).index e'
|
||||||
let e' ← mkLambdaFVars motives e'
|
let e' ← mkLambdaFVars motives e'
|
||||||
|
|
||||||
-- We could pass (usedOnly := true) below, and get nicer induction principles that
|
-- We used to pass (usedOnly := false) below in the hope that the types of the
|
||||||
-- do not mention odd unused parameters.
|
-- induction principle match the type of the function better.
|
||||||
-- But the downside is that automatic instantiation of the principle (e.g. in a tactic
|
-- But this leads to avoidable parameters that make functional induction strictly less
|
||||||
-- that derives them from an function application in the goal) is harder, as
|
-- useful (e.g. when the unsued parameter mentions bound variables in the users' goal)
|
||||||
-- one would have to infer or keep track of which parameters to pass.
|
let e' ← mkLambdaFVars (binderInfoForMVars := .default) (usedOnly := true) xs e'
|
||||||
-- So for now lets just keep them around.
|
|
||||||
let e' ← mkLambdaFVars (binderInfoForMVars := .default) xs e'
|
|
||||||
let e' ← instantiateMVars e'
|
let e' ← instantiateMVars e'
|
||||||
trace[Meta.FunInd] "complete body of mutual induction principle:{indentExpr e'}"
|
trace[Meta.FunInd] "complete body of mutual induction principle:{indentExpr e'}"
|
||||||
pure e'
|
pure e'
|
||||||
@@ -1114,11 +1111,16 @@ def isFunInductName (env : Environment) (name : Name) : Bool := Id.run do
|
|||||||
let .str p s := name | return false
|
let .str p s := name | return false
|
||||||
match s with
|
match s with
|
||||||
| "induct" =>
|
| "induct" =>
|
||||||
if (WF.eqnInfoExt.find? env p).isSome then return true
|
if let some eqnInfo := WF.eqnInfoExt.find? env p then
|
||||||
|
unless eqnInfo.hasInduct do
|
||||||
|
return false
|
||||||
|
return true
|
||||||
if (Structural.eqnInfoExt.find? env p).isSome then return true
|
if (Structural.eqnInfoExt.find? env p).isSome then return true
|
||||||
return false
|
return false
|
||||||
| "mutual_induct" =>
|
| "mutual_induct" =>
|
||||||
if let some eqnInfo := WF.eqnInfoExt.find? env p then
|
if let some eqnInfo := WF.eqnInfoExt.find? env p then
|
||||||
|
unless eqnInfo.hasInduct do
|
||||||
|
return false
|
||||||
if h : eqnInfo.declNames.size > 1 then
|
if h : eqnInfo.declNames.size > 1 then
|
||||||
return eqnInfo.declNames[0] = p
|
return eqnInfo.declNames[0] = p
|
||||||
if let some eqnInfo := Structural.eqnInfoExt.find? env p then
|
if let some eqnInfo := Structural.eqnInfoExt.find? env p then
|
||||||
|
|||||||
@@ -20,6 +20,18 @@ def fromExpr? (e : Expr) : SimpM (Option Value) := do
|
|||||||
let some ⟨n, value⟩ ← getFinValue? e | return none
|
let some ⟨n, value⟩ ← getFinValue? e | return none
|
||||||
return some { n, value }
|
return some { n, value }
|
||||||
|
|
||||||
|
@[inline] def reduceOp (declName : Name) (arity : Nat) (f : Nat → Nat) (op : {n : Nat} → Fin n → Fin (f n)) (e : Expr) : SimpM DStep := do
|
||||||
|
unless e.isAppOfArity declName arity do return .continue
|
||||||
|
let some v ← fromExpr? e.appArg! | return .continue
|
||||||
|
let v' := op v.value
|
||||||
|
return .done <| toExpr v'
|
||||||
|
|
||||||
|
@[inline] def reduceNatOp (declName : Name) (arity : Nat) (f : Nat → Nat) (op : (n : Nat) → Fin (f n)) (e : Expr) : SimpM DStep := do
|
||||||
|
unless e.isAppOfArity declName arity do return .continue
|
||||||
|
let some v ← getNatValue? e.appArg! | return .continue
|
||||||
|
let v' := op v
|
||||||
|
return .done <| toExpr v'
|
||||||
|
|
||||||
@[inline] def reduceBin (declName : Name) (arity : Nat) (op : {n : Nat} → Fin n → Fin n → Fin n) (e : Expr) : SimpM DStep := do
|
@[inline] def reduceBin (declName : Name) (arity : Nat) (op : {n : Nat} → Fin n → Fin n → Fin n) (e : Expr) : SimpM DStep := do
|
||||||
unless e.isAppOfArity declName arity do return .continue
|
unless e.isAppOfArity declName arity do return .continue
|
||||||
let some v₁ ← fromExpr? e.appFn!.appArg! | return .continue
|
let some v₁ ← fromExpr? e.appFn!.appArg! | return .continue
|
||||||
@@ -47,12 +59,23 @@ The following code assumes users did not override the `Fin n` instances for the
|
|||||||
If they do, they must disable the following `simprocs`.
|
If they do, they must disable the following `simprocs`.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceSucc (Fin.succ _) := reduceOp ``Fin.succ 2 (· + 1) Fin.succ
|
||||||
|
builtin_dsimproc [simp, seval] reduceRev (Fin.rev _) := reduceOp ``Fin.rev 2 (·) Fin.rev
|
||||||
|
builtin_dsimproc [simp, seval] reduceLast (Fin.last _) := reduceNatOp ``Fin.last 1 (· + 1) Fin.last
|
||||||
|
|
||||||
builtin_dsimproc [simp, seval] reduceAdd ((_ + _ : Fin _)) := reduceBin ``HAdd.hAdd 6 (· + ·)
|
builtin_dsimproc [simp, seval] reduceAdd ((_ + _ : Fin _)) := reduceBin ``HAdd.hAdd 6 (· + ·)
|
||||||
builtin_dsimproc [simp, seval] reduceMul ((_ * _ : Fin _)) := reduceBin ``HMul.hMul 6 (· * ·)
|
builtin_dsimproc [simp, seval] reduceMul ((_ * _ : Fin _)) := reduceBin ``HMul.hMul 6 (· * ·)
|
||||||
builtin_dsimproc [simp, seval] reduceSub ((_ - _ : Fin _)) := reduceBin ``HSub.hSub 6 (· - ·)
|
builtin_dsimproc [simp, seval] reduceSub ((_ - _ : Fin _)) := reduceBin ``HSub.hSub 6 (· - ·)
|
||||||
builtin_dsimproc [simp, seval] reduceDiv ((_ / _ : Fin _)) := reduceBin ``HDiv.hDiv 6 (· / ·)
|
builtin_dsimproc [simp, seval] reduceDiv ((_ / _ : Fin _)) := reduceBin ``HDiv.hDiv 6 (· / ·)
|
||||||
builtin_dsimproc [simp, seval] reduceMod ((_ % _ : Fin _)) := reduceBin ``HMod.hMod 6 (· % ·)
|
builtin_dsimproc [simp, seval] reduceMod ((_ % _ : Fin _)) := reduceBin ``HMod.hMod 6 (· % ·)
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceAnd ((_ &&& _ : Fin _)) := reduceBin ``HAnd.hAnd 6 (· &&& ·)
|
||||||
|
builtin_dsimproc [simp, seval] reduceOr ((_ ||| _ : Fin _)) := reduceBin ``HOr.hOr 6 (· ||| ·)
|
||||||
|
builtin_dsimproc [simp, seval] reduceXor ((_ ^^^ _ : Fin _)) := reduceBin ``HXor.hXor 6 (· ^^^ ·)
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceShiftLeft ((_ <<< _ : Fin _)) := reduceBin ``HShiftLeft.hShiftLeft 6 (· <<< ·)
|
||||||
|
builtin_dsimproc [simp, seval] reduceShiftRight ((_ >>> _ : Fin _)) := reduceBin ``HShiftRight.hShiftRight 6 (· >>> ·)
|
||||||
|
|
||||||
builtin_simproc [simp, seval] reduceLT (( _ : Fin _) < _) := reduceBinPred ``LT.lt 4 (. < .)
|
builtin_simproc [simp, seval] reduceLT (( _ : Fin _) < _) := reduceBinPred ``LT.lt 4 (. < .)
|
||||||
builtin_simproc [simp, seval] reduceLE (( _ : Fin _) ≤ _) := reduceBinPred ``LE.le 4 (. ≤ .)
|
builtin_simproc [simp, seval] reduceLE (( _ : Fin _) ≤ _) := reduceBinPred ``LE.le 4 (. ≤ .)
|
||||||
builtin_simproc [simp, seval] reduceGT (( _ : Fin _) > _) := reduceBinPred ``GT.gt 4 (. > .)
|
builtin_simproc [simp, seval] reduceGT (( _ : Fin _) > _) := reduceBinPred ``GT.gt 4 (. > .)
|
||||||
@@ -83,4 +106,70 @@ builtin_dsimproc [simp, seval] reduceFinMk (Fin.mk _ _) := fun e => do
|
|||||||
else
|
else
|
||||||
return .continue
|
return .continue
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceOfNat' (Fin.ofNat' _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.ofNat' 3 do return .continue
|
||||||
|
let some (n + 1) ← getNatValue? e.appFn!.appFn!.appArg! | return .continue
|
||||||
|
let some k ← getNatValue? e.appArg! | return .continue
|
||||||
|
return .done <| toExpr (Fin.ofNat' (n + 1) k)
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceCastSucc (Fin.castSucc _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.castSucc 2 do return .continue
|
||||||
|
let some k ← fromExpr? e.appArg! | return .continue
|
||||||
|
return .done <| toExpr (castSucc k.value)
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceCastAdd (Fin.castAdd _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.castAdd 3 do return .continue
|
||||||
|
let some m ← getNatValue? e.appFn!.appArg! | return .continue
|
||||||
|
let some k ← fromExpr? e.appArg! | return .continue
|
||||||
|
return .done <| toExpr (castAdd m k.value)
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceAddNat (Fin.addNat _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.addNat 3 do return .continue
|
||||||
|
let some k ← fromExpr? e.appFn!.appArg! | return .continue
|
||||||
|
let some m ← getNatValue? e.appArg! | return .continue
|
||||||
|
return .done <| toExpr (addNat k.value m)
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceNatAdd (Fin.natAdd _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.natAdd 3 do return .continue
|
||||||
|
let some m ← getNatValue? e.appFn!.appArg! | return .continue
|
||||||
|
let some k ← fromExpr? e.appArg! | return .continue
|
||||||
|
return .done <| toExpr (natAdd m k.value)
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceCastLT (Fin.castLT _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.castLT 4 do return .continue
|
||||||
|
let some n ← getNatValue? e.appFn!.appFn!.appFn!.appArg! | return .continue
|
||||||
|
let some i ← fromExpr? e.appFn!.appArg! | return .continue
|
||||||
|
if h : i.value < n then
|
||||||
|
return .done <| toExpr (castLT i.value h)
|
||||||
|
else
|
||||||
|
return .continue
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceCastLE (Fin.castLE _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.castLE 4 do return .continue
|
||||||
|
let some m ← getNatValue? e.appFn!.appFn!.appArg! | return .continue
|
||||||
|
let some i ← fromExpr? e.appArg! | return .continue
|
||||||
|
if h : i.n ≤ m then
|
||||||
|
return .done <| toExpr (castLE h i.value)
|
||||||
|
else
|
||||||
|
return .continue
|
||||||
|
|
||||||
|
-- No simproc is needed for `Fin.cast`, as for explicit numbers `Fin.cast_refl` will apply.
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reduceSubNat (Fin.subNat _ _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.subNat 4 do return .continue
|
||||||
|
let some m ← getNatValue? e.appFn!.appFn!.appArg! | return .continue
|
||||||
|
let some i ← fromExpr? e.appFn!.appArg! | return .continue
|
||||||
|
if h : m ≤ i.value then
|
||||||
|
return .done <| toExpr (subNat m (i.value.cast (by omega : i.n = (i.n - m) + m)) h)
|
||||||
|
else
|
||||||
|
return .continue
|
||||||
|
|
||||||
|
builtin_dsimproc [simp, seval] reducePred (Fin.pred _ _) := fun e => do
|
||||||
|
unless e.isAppOfArity ``Fin.pred 3 do return .continue
|
||||||
|
let some ⟨(_ + 1), i⟩ ← fromExpr? e.appFn!.appArg! | return .continue
|
||||||
|
if h : i ≠ 0 then
|
||||||
|
return .done <| toExpr (pred i h)
|
||||||
|
else
|
||||||
|
return .continue
|
||||||
|
|
||||||
end Fin
|
end Fin
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ builtin_dsimproc [simp, seval] reduceMul ((_ * _ : Int)) := reduceBin ``HMul.hMu
|
|||||||
builtin_dsimproc [simp, seval] reduceSub ((_ - _ : Int)) := reduceBin ``HSub.hSub 6 (· - ·)
|
builtin_dsimproc [simp, seval] reduceSub ((_ - _ : Int)) := reduceBin ``HSub.hSub 6 (· - ·)
|
||||||
builtin_dsimproc [simp, seval] reduceDiv ((_ / _ : Int)) := reduceBin ``HDiv.hDiv 6 (· / ·)
|
builtin_dsimproc [simp, seval] reduceDiv ((_ / _ : Int)) := reduceBin ``HDiv.hDiv 6 (· / ·)
|
||||||
builtin_dsimproc [simp, seval] reduceMod ((_ % _ : Int)) := reduceBin ``HMod.hMod 6 (· % ·)
|
builtin_dsimproc [simp, seval] reduceMod ((_ % _ : Int)) := reduceBin ``HMod.hMod 6 (· % ·)
|
||||||
builtin_dsimproc [simp, seval] reduceTDiv (tdiv _ _) := reduceBin ``Int.div 2 Int.tdiv
|
builtin_dsimproc [simp, seval] reduceTDiv (tdiv _ _) := reduceBin ``Int.tdiv 2 Int.tdiv
|
||||||
builtin_dsimproc [simp, seval] reduceTMod (tmod _ _) := reduceBin ``Int.mod 2 Int.tmod
|
builtin_dsimproc [simp, seval] reduceTMod (tmod _ _) := reduceBin ``Int.tmod 2 Int.tmod
|
||||||
builtin_dsimproc [simp, seval] reduceFDiv (fdiv _ _) := reduceBin ``Int.fdiv 2 Int.fdiv
|
builtin_dsimproc [simp, seval] reduceFDiv (fdiv _ _) := reduceBin ``Int.fdiv 2 Int.fdiv
|
||||||
builtin_dsimproc [simp, seval] reduceFMod (fmod _ _) := reduceBin ``Int.fmod 2 Int.fmod
|
builtin_dsimproc [simp, seval] reduceFMod (fmod _ _) := reduceBin ``Int.fmod 2 Int.fmod
|
||||||
builtin_dsimproc [simp, seval] reduceBdiv (bdiv _ _) := reduceBinIntNatOp ``bdiv bdiv
|
builtin_dsimproc [simp, seval] reduceBdiv (bdiv _ _) := reduceBinIntNatOp ``bdiv bdiv
|
||||||
|
|||||||
@@ -804,18 +804,45 @@ where
|
|||||||
else
|
else
|
||||||
normalState num c s
|
normalState num c s
|
||||||
|
|
||||||
def decimalNumberFn (startPos : String.Pos) (c : ParserContext) : ParserState → ParserState := fun s =>
|
/--
|
||||||
let s := takeWhileFn (fun c => c.isDigit) c s
|
Parses a sequence of the form `many (many '_' >> many1 digit)`, but if `needDigit` is true the parsed result must be nonempty.
|
||||||
|
|
||||||
|
Note: this does not report that it is expecting `_` if we reach EOI or an unexpected character.
|
||||||
|
Rationale: this error happens if there is already a `_`, and while sequences of `_` are allowed, it's a bit perverse to suggest extending the sequence.
|
||||||
|
-/
|
||||||
|
partial def takeDigitsFn (isDigit : Char → Bool) (expecting : String) (needDigit : Bool) : ParserFn := fun c s =>
|
||||||
let input := c.input
|
let input := c.input
|
||||||
let i := s.pos
|
let i := s.pos
|
||||||
let curr := input.get i
|
if h : input.atEnd i then
|
||||||
if curr == '.' || curr == 'e' || curr == 'E' then
|
if needDigit then
|
||||||
|
s.mkEOIError [expecting]
|
||||||
|
else
|
||||||
|
s
|
||||||
|
else
|
||||||
|
let curr := input.get' i h
|
||||||
|
if curr == '_' then takeDigitsFn isDigit expecting true c (s.next' c.input i h)
|
||||||
|
else if isDigit curr then takeDigitsFn isDigit expecting false c (s.next' c.input i h)
|
||||||
|
else if needDigit then s.mkUnexpectedError "unexpected character" (expected := [expecting])
|
||||||
|
else s
|
||||||
|
|
||||||
|
def decimalNumberFn (startPos : String.Pos) (c : ParserContext) : ParserState → ParserState := fun s =>
|
||||||
|
let s := takeDigitsFn (fun c => c.isDigit) "decimal number" false c s
|
||||||
|
let input := c.input
|
||||||
|
let i := s.pos
|
||||||
|
if h : input.atEnd i then
|
||||||
|
mkNodeToken numLitKind startPos c s
|
||||||
|
else
|
||||||
|
let curr := input.get' i h
|
||||||
|
if curr == '.' || curr == 'e' || curr == 'E' then
|
||||||
|
parseScientific s
|
||||||
|
else
|
||||||
|
mkNodeToken numLitKind startPos c s
|
||||||
|
where
|
||||||
|
parseScientific s :=
|
||||||
let s := parseOptDot s
|
let s := parseOptDot s
|
||||||
let s := parseOptExp s
|
let s := parseOptExp s
|
||||||
mkNodeToken scientificLitKind startPos c s
|
mkNodeToken scientificLitKind startPos c s
|
||||||
else
|
|
||||||
mkNodeToken numLitKind startPos c s
|
|
||||||
where
|
|
||||||
parseOptDot s :=
|
parseOptDot s :=
|
||||||
let input := c.input
|
let input := c.input
|
||||||
let i := s.pos
|
let i := s.pos
|
||||||
@@ -824,7 +851,7 @@ where
|
|||||||
let i := input.next i
|
let i := input.next i
|
||||||
let curr := input.get i
|
let curr := input.get i
|
||||||
if curr.isDigit then
|
if curr.isDigit then
|
||||||
takeWhileFn (fun c => c.isDigit) c (s.setPos i)
|
takeDigitsFn (fun c => c.isDigit) "decimal number" false c (s.setPos i)
|
||||||
else
|
else
|
||||||
s.setPos i
|
s.setPos i
|
||||||
else
|
else
|
||||||
@@ -839,22 +866,22 @@ where
|
|||||||
let i := if input.get i == '-' || input.get i == '+' then input.next i else i
|
let i := if input.get i == '-' || input.get i == '+' then input.next i else i
|
||||||
let curr := input.get i
|
let curr := input.get i
|
||||||
if curr.isDigit then
|
if curr.isDigit then
|
||||||
takeWhileFn (fun c => c.isDigit) c (s.setPos i)
|
takeDigitsFn (fun c => c.isDigit) "decimal number" false c (s.setPos i)
|
||||||
else
|
else
|
||||||
s.mkUnexpectedError "missing exponent digits in scientific literal"
|
s.mkUnexpectedError "missing exponent digits in scientific literal"
|
||||||
else
|
else
|
||||||
s
|
s
|
||||||
|
|
||||||
def binNumberFn (startPos : String.Pos) : ParserFn := fun c s =>
|
def binNumberFn (startPos : String.Pos) : ParserFn := fun c s =>
|
||||||
let s := takeWhile1Fn (fun c => c == '0' || c == '1') "binary number" c s
|
let s := takeDigitsFn (fun c => c == '0' || c == '1') "binary number" true c s
|
||||||
mkNodeToken numLitKind startPos c s
|
mkNodeToken numLitKind startPos c s
|
||||||
|
|
||||||
def octalNumberFn (startPos : String.Pos) : ParserFn := fun c s =>
|
def octalNumberFn (startPos : String.Pos) : ParserFn := fun c s =>
|
||||||
let s := takeWhile1Fn (fun c => '0' ≤ c && c ≤ '7') "octal number" c s
|
let s := takeDigitsFn (fun c => '0' ≤ c && c ≤ '7') "octal number" true c s
|
||||||
mkNodeToken numLitKind startPos c s
|
mkNodeToken numLitKind startPos c s
|
||||||
|
|
||||||
def hexNumberFn (startPos : String.Pos) : ParserFn := fun c s =>
|
def hexNumberFn (startPos : String.Pos) : ParserFn := fun c s =>
|
||||||
let s := takeWhile1Fn (fun c => ('0' ≤ c && c ≤ '9') || ('a' ≤ c && c ≤ 'f') || ('A' ≤ c && c ≤ 'F')) "hexadecimal number" c s
|
let s := takeDigitsFn (fun c => ('0' ≤ c && c ≤ '9') || ('a' ≤ c && c ≤ 'f') || ('A' ≤ c && c ≤ 'F')) "hexadecimal number" true c s
|
||||||
mkNodeToken numLitKind startPos c s
|
mkNodeToken numLitKind startPos c s
|
||||||
|
|
||||||
def numberFnAux : ParserFn := fun c s =>
|
def numberFnAux : ParserFn := fun c s =>
|
||||||
|
|||||||
@@ -398,16 +398,22 @@ Aliases are considered first.
|
|||||||
|
|
||||||
When `fullNames` is true, returns either `n₀` or `_root_.n₀`.
|
When `fullNames` is true, returns either `n₀` or `_root_.n₀`.
|
||||||
|
|
||||||
|
When `allowHorizAliases` is false, then "horizontal aliases" (ones that are not put into a parent namespace) are filtered out.
|
||||||
|
The assumption is that non-horizontal aliases are "API exports" (i.e., intentional exports that should be considered to be the new canonical name).
|
||||||
|
"Non-API exports" arise from (1) using `export` to add names to a namespace for dot notation or (2) projects that want names to be conveniently and permanently accessible in their own namespaces.
|
||||||
|
|
||||||
This function is meant to be used for pretty printing.
|
This function is meant to be used for pretty printing.
|
||||||
If `n₀` is an accessible name, then the result will be an accessible name.
|
If `n₀` is an accessible name, then the result will be an accessible name.
|
||||||
-/
|
-/
|
||||||
def unresolveNameGlobal [Monad m] [MonadResolveName m] [MonadEnv m] (n₀ : Name) (fullNames := false) : m Name := do
|
def unresolveNameGlobal [Monad m] [MonadResolveName m] [MonadEnv m] (n₀ : Name) (fullNames := false) (allowHorizAliases := false) : m Name := do
|
||||||
if n₀.hasMacroScopes then return n₀
|
if n₀.hasMacroScopes then return n₀
|
||||||
if fullNames then
|
if fullNames then
|
||||||
match (← resolveGlobalName n₀) with
|
match (← resolveGlobalName n₀) with
|
||||||
| [(potentialMatch, _)] => if (privateToUserName? potentialMatch).getD potentialMatch == n₀ then return n₀ else return rootNamespace ++ n₀
|
| [(potentialMatch, _)] => if (privateToUserName? potentialMatch).getD potentialMatch == n₀ then return n₀ else return rootNamespace ++ n₀
|
||||||
| _ => return n₀ -- if can't resolve, return the original
|
| _ => return n₀ -- if can't resolve, return the original
|
||||||
let mut initialNames := (getRevAliases (← getEnv) n₀).toArray
|
let mut initialNames := (getRevAliases (← getEnv) n₀).toArray
|
||||||
|
unless allowHorizAliases do
|
||||||
|
initialNames := initialNames.filter fun n => n.getPrefix.isPrefixOf n₀.getPrefix
|
||||||
initialNames := initialNames.push (rootNamespace ++ n₀)
|
initialNames := initialNames.push (rootNamespace ++ n₀)
|
||||||
for initialName in initialNames do
|
for initialName in initialNames do
|
||||||
if let some n ← unresolveNameCore initialName then
|
if let some n ← unresolveNameCore initialName then
|
||||||
|
|||||||
@@ -100,20 +100,6 @@ private def findSyntheticIdentifierCompletion?
|
|||||||
HoverInfo.after
|
HoverInfo.after
|
||||||
some { hoverInfo, ctx, info := .id stx id danglingDot info.lctx none }
|
some { hoverInfo, ctx, info := .id stx id danglingDot info.lctx none }
|
||||||
|
|
||||||
private partial def getIndentationAmount (fileMap : FileMap) (line : Nat) : Nat := Id.run do
|
|
||||||
let lineStartPos := fileMap.lineStart line
|
|
||||||
let lineEndPos := fileMap.lineStart (line + 1)
|
|
||||||
let mut it : String.Iterator := ⟨fileMap.source, lineStartPos⟩
|
|
||||||
let mut indentationAmount := 0
|
|
||||||
while it.pos < lineEndPos do
|
|
||||||
let c := it.curr
|
|
||||||
if c = ' ' || c = '\t' then
|
|
||||||
indentationAmount := indentationAmount + 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
it := it.next
|
|
||||||
return indentationAmount
|
|
||||||
|
|
||||||
private partial def isCursorOnWhitespace (fileMap : FileMap) (hoverPos : String.Pos) : Bool :=
|
private partial def isCursorOnWhitespace (fileMap : FileMap) (hoverPos : String.Pos) : Bool :=
|
||||||
fileMap.source.atEnd hoverPos || (fileMap.source.get hoverPos).isWhitespace
|
fileMap.source.atEnd hoverPos || (fileMap.source.get hoverPos).isWhitespace
|
||||||
|
|
||||||
@@ -127,15 +113,10 @@ private partial def isSyntheticTacticCompletion
|
|||||||
(cmdStx : Syntax)
|
(cmdStx : Syntax)
|
||||||
: Bool := Id.run do
|
: Bool := Id.run do
|
||||||
let hoverFilePos := fileMap.toPosition hoverPos
|
let hoverFilePos := fileMap.toPosition hoverPos
|
||||||
let mut hoverLineIndentation := getIndentationAmount fileMap hoverFilePos.line
|
go hoverFilePos cmdStx 0
|
||||||
if hoverFilePos.column < hoverLineIndentation then
|
|
||||||
-- Ignore trailing whitespace after the cursor
|
|
||||||
hoverLineIndentation := hoverFilePos.column
|
|
||||||
go hoverFilePos hoverLineIndentation cmdStx 0
|
|
||||||
where
|
where
|
||||||
go
|
go
|
||||||
(hoverFilePos : Position)
|
(hoverFilePos : Position)
|
||||||
(hoverLineIndentation : Nat)
|
|
||||||
(stx : Syntax)
|
(stx : Syntax)
|
||||||
(leadingWs : Nat)
|
(leadingWs : Nat)
|
||||||
: Bool := Id.run do
|
: Bool := Id.run do
|
||||||
@@ -148,7 +129,7 @@ where
|
|||||||
return false
|
return false
|
||||||
let mut wsBeforeArg := leadingWs
|
let mut wsBeforeArg := leadingWs
|
||||||
for arg in stx.getArgs do
|
for arg in stx.getArgs do
|
||||||
if go hoverFilePos hoverLineIndentation arg wsBeforeArg then
|
if go hoverFilePos arg wsBeforeArg then
|
||||||
return true
|
return true
|
||||||
-- We must account for the whitespace before an argument because the syntax nodes we use
|
-- We must account for the whitespace before an argument because the syntax nodes we use
|
||||||
-- to identify tactic blocks only start *after* the whitespace following a `by`, and we
|
-- to identify tactic blocks only start *after* the whitespace following a `by`, and we
|
||||||
@@ -158,7 +139,7 @@ where
|
|||||||
wsBeforeArg := arg.getTrailingSize
|
wsBeforeArg := arg.getTrailingSize
|
||||||
return isCompletionInEmptyTacticBlock stx
|
return isCompletionInEmptyTacticBlock stx
|
||||||
|| isCompletionAfterSemicolon stx
|
|| isCompletionAfterSemicolon stx
|
||||||
|| isCompletionOnTacticBlockIndentation hoverFilePos hoverLineIndentation stx
|
|| isCompletionOnTacticBlockIndentation hoverFilePos stx
|
||||||
| _, _ =>
|
| _, _ =>
|
||||||
-- Empty tactic blocks typically lack ranges since they do not contain any tokens.
|
-- Empty tactic blocks typically lack ranges since they do not contain any tokens.
|
||||||
-- We do not perform more precise range checking in this case because we assume that empty
|
-- We do not perform more precise range checking in this case because we assume that empty
|
||||||
@@ -169,24 +150,17 @@ where
|
|||||||
|
|
||||||
isCompletionOnTacticBlockIndentation
|
isCompletionOnTacticBlockIndentation
|
||||||
(hoverFilePos : Position)
|
(hoverFilePos : Position)
|
||||||
(hoverLineIndentation : Nat)
|
|
||||||
(stx : Syntax)
|
(stx : Syntax)
|
||||||
: Bool := Id.run do
|
: Bool := Id.run do
|
||||||
let isCursorInIndentation := hoverFilePos.column <= hoverLineIndentation
|
|
||||||
if ! isCursorInIndentation then
|
|
||||||
-- Do not trigger tactic completion at the end of a properly indented tactic block line since
|
|
||||||
-- that line might already have entered term mode by that point.
|
|
||||||
return false
|
|
||||||
let some tacticsNode := getTacticsNode? stx
|
let some tacticsNode := getTacticsNode? stx
|
||||||
| return false
|
| return false
|
||||||
let some firstTacticPos := tacticsNode.getPos?
|
let some firstTacticPos := tacticsNode.getPos?
|
||||||
| return false
|
| return false
|
||||||
let firstTacticLine := fileMap.toPosition firstTacticPos |>.line
|
let firstTacticColumn := fileMap.toPosition firstTacticPos |>.column
|
||||||
let firstTacticIndentation := getIndentationAmount fileMap firstTacticLine
|
|
||||||
-- This ensures that we do not accidentally provide tactic completions in a term mode proof -
|
-- This ensures that we do not accidentally provide tactic completions in a term mode proof -
|
||||||
-- tactic completions are only provided at the same indentation level as the other tactics in
|
-- tactic completions are only provided at the same indentation level as the other tactics in
|
||||||
-- that tactic block.
|
-- that tactic block.
|
||||||
let isCursorInTacticBlock := hoverLineIndentation == firstTacticIndentation
|
let isCursorInTacticBlock := hoverFilePos.column == firstTacticColumn
|
||||||
return isCursorInProperWhitespace fileMap hoverPos && isCursorInTacticBlock
|
return isCursorInProperWhitespace fileMap hoverPos && isCursorInTacticBlock
|
||||||
|
|
||||||
isCompletionAfterSemicolon (stx : Syntax) : Bool := Id.run do
|
isCompletionAfterSemicolon (stx : Syntax) : Bool := Id.run do
|
||||||
@@ -315,10 +289,6 @@ private def isSyntheticStructFieldCompletion
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
let hoverFilePos := fileMap.toPosition hoverPos
|
let hoverFilePos := fileMap.toPosition hoverPos
|
||||||
let mut hoverLineIndentation := getIndentationAmount fileMap hoverFilePos.line
|
|
||||||
if hoverFilePos.column < hoverLineIndentation then
|
|
||||||
-- Ignore trailing whitespace after the cursor
|
|
||||||
hoverLineIndentation := hoverFilePos.column
|
|
||||||
|
|
||||||
return Option.isSome <| findWithLeadingToken? (stx := cmdStx) fun leadingToken? stx => Id.run do
|
return Option.isSome <| findWithLeadingToken? (stx := cmdStx) fun leadingToken? stx => Id.run do
|
||||||
let some leadingToken := leadingToken?
|
let some leadingToken := leadingToken?
|
||||||
@@ -355,14 +325,10 @@ private def isSyntheticStructFieldCompletion
|
|||||||
let isCompletionOnIndentation := Id.run do
|
let isCompletionOnIndentation := Id.run do
|
||||||
if ! isCursorInProperWhitespace then
|
if ! isCursorInProperWhitespace then
|
||||||
return false
|
return false
|
||||||
let isCursorInIndentation := hoverFilePos.column <= hoverLineIndentation
|
|
||||||
if ! isCursorInIndentation then
|
|
||||||
return false
|
|
||||||
let some firstFieldPos := stx.getPos?
|
let some firstFieldPos := stx.getPos?
|
||||||
| return false
|
| return false
|
||||||
let firstFieldLine := fileMap.toPosition firstFieldPos |>.line
|
let firstFieldColumn := fileMap.toPosition firstFieldPos |>.column
|
||||||
let firstFieldIndentation := getIndentationAmount fileMap firstFieldLine
|
let isCursorInBlock := hoverFilePos.column == firstFieldColumn
|
||||||
let isCursorInBlock := hoverLineIndentation == firstFieldIndentation
|
|
||||||
return isCursorInBlock
|
return isCursorInBlock
|
||||||
return isCompletionOnIndentation
|
return isCompletionOnIndentation
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Authors: Marc Huisinga, Wojciech Nawrocki
|
|||||||
-/
|
-/
|
||||||
prelude
|
prelude
|
||||||
import Init.System.IO
|
import Init.System.IO
|
||||||
import Init.Data.Channel
|
import Std.Sync.Channel
|
||||||
|
|
||||||
import Lean.Data.RBMap
|
import Lean.Data.RBMap
|
||||||
import Lean.Environment
|
import Lean.Environment
|
||||||
@@ -64,7 +64,7 @@ open Widget in
|
|||||||
structure WorkerContext where
|
structure WorkerContext where
|
||||||
/-- Synchronized output channel for LSP messages. Notifications for outdated versions are
|
/-- Synchronized output channel for LSP messages. Notifications for outdated versions are
|
||||||
discarded on read. -/
|
discarded on read. -/
|
||||||
chanOut : IO.Channel JsonRpc.Message
|
chanOut : Std.Channel JsonRpc.Message
|
||||||
/--
|
/--
|
||||||
Latest document version received by the client, used for filtering out notifications from
|
Latest document version received by the client, used for filtering out notifications from
|
||||||
previous versions.
|
previous versions.
|
||||||
@@ -75,7 +75,7 @@ structure WorkerContext where
|
|||||||
Channel that receives a message for every a `$/lean/fileProgress` notification, indicating whether
|
Channel that receives a message for every a `$/lean/fileProgress` notification, indicating whether
|
||||||
the notification suggests that the file is currently being processed.
|
the notification suggests that the file is currently being processed.
|
||||||
-/
|
-/
|
||||||
chanIsProcessing : IO.Channel Bool
|
chanIsProcessing : Std.Channel Bool
|
||||||
/--
|
/--
|
||||||
Diagnostics that are included in every single `textDocument/publishDiagnostics` notification.
|
Diagnostics that are included in every single `textDocument/publishDiagnostics` notification.
|
||||||
-/
|
-/
|
||||||
@@ -271,7 +271,7 @@ open Language Lean in
|
|||||||
Callback from Lean language processor after parsing imports that requests necessary information from
|
Callback from Lean language processor after parsing imports that requests necessary information from
|
||||||
Lake for processing imports.
|
Lake for processing imports.
|
||||||
-/
|
-/
|
||||||
def setupImports (meta : DocumentMeta) (cmdlineOpts : Options) (chanOut : Channel JsonRpc.Message)
|
def setupImports (meta : DocumentMeta) (cmdlineOpts : Options) (chanOut : Std.Channel JsonRpc.Message)
|
||||||
(srcSearchPathPromise : Promise SearchPath) (stx : Syntax) :
|
(srcSearchPathPromise : Promise SearchPath) (stx : Syntax) :
|
||||||
Language.ProcessingT IO (Except Language.Lean.HeaderProcessedSnapshot SetupImportsResult) := do
|
Language.ProcessingT IO (Except Language.Lean.HeaderProcessedSnapshot SetupImportsResult) := do
|
||||||
let importsAlreadyLoaded ← importsLoadedRef.modifyGet ((·, true))
|
let importsAlreadyLoaded ← importsLoadedRef.modifyGet ((·, true))
|
||||||
@@ -337,7 +337,7 @@ section Initialization
|
|||||||
let clientHasWidgets := initParams.initializationOptions?.bind (·.hasWidgets?) |>.getD false
|
let clientHasWidgets := initParams.initializationOptions?.bind (·.hasWidgets?) |>.getD false
|
||||||
let maxDocVersionRef ← IO.mkRef 0
|
let maxDocVersionRef ← IO.mkRef 0
|
||||||
let freshRequestIdRef ← IO.mkRef (0 : Int)
|
let freshRequestIdRef ← IO.mkRef (0 : Int)
|
||||||
let chanIsProcessing ← IO.Channel.new
|
let chanIsProcessing ← Std.Channel.new
|
||||||
let stickyDiagnosticsRef ← IO.mkRef ∅
|
let stickyDiagnosticsRef ← IO.mkRef ∅
|
||||||
let chanOut ← mkLspOutputChannel maxDocVersionRef chanIsProcessing
|
let chanOut ← mkLspOutputChannel maxDocVersionRef chanIsProcessing
|
||||||
let srcSearchPathPromise ← IO.Promise.new
|
let srcSearchPathPromise ← IO.Promise.new
|
||||||
@@ -380,8 +380,8 @@ section Initialization
|
|||||||
the output FS stream after discarding outdated notifications. This is the only component of
|
the output FS stream after discarding outdated notifications. This is the only component of
|
||||||
the worker with access to the output stream, so we can synchronize messages from parallel
|
the worker with access to the output stream, so we can synchronize messages from parallel
|
||||||
elaboration tasks here. -/
|
elaboration tasks here. -/
|
||||||
mkLspOutputChannel maxDocVersion chanIsProcessing : IO (IO.Channel JsonRpc.Message) := do
|
mkLspOutputChannel maxDocVersion chanIsProcessing : IO (Std.Channel JsonRpc.Message) := do
|
||||||
let chanOut ← IO.Channel.new
|
let chanOut ← Std.Channel.new
|
||||||
let _ ← chanOut.forAsync (prio := .dedicated) fun msg => do
|
let _ ← chanOut.forAsync (prio := .dedicated) fun msg => do
|
||||||
-- discard outdated notifications; note that in contrast to responses, notifications can
|
-- discard outdated notifications; note that in contrast to responses, notifications can
|
||||||
-- always be silently discarded
|
-- always be silently discarded
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user