Compare commits

..

2 Commits

Author SHA1 Message Date
Kim Morrison
5aedb2b8d4 chore: reordering in Array.Basic 2024-09-20 11:45:25 +10:00
Kim Morrison
cd9f3e12e0 chore: reordering in Array.Basic 2024-09-20 11:45:17 +10:00
311 changed files with 708 additions and 2318 deletions

View File

@@ -25,7 +25,7 @@ Please put an X between the brackets as you perform the following steps:
### Context ### Context
[Broader context that the issue occurred in. If there was any prior discussion on [the Lean Zulip](https://leanprover.zulipchat.com), link it here as well.] [Broader context that the issue occured in. If there was any prior discussion on [the Lean Zulip](https://leanprover.zulipchat.com), link it here as well.]
### Steps to Reproduce ### Steps to Reproduce

View File

@@ -316,7 +316,7 @@ jobs:
git fetch --depth=1 origin ${{ github.sha }} git fetch --depth=1 origin ${{ github.sha }}
git checkout FETCH_HEAD flake.nix flake.lock git checkout FETCH_HEAD flake.nix flake.lock
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
# (needs to be after "Checkout" so files don't get overridden) # (needs to be after "Checkout" so files don't get overriden)
- name: Setup emsdk - name: Setup emsdk
uses: mymindstorm/setup-emsdk@v12 uses: mymindstorm/setup-emsdk@v12
with: with:

View File

@@ -134,7 +134,7 @@ jobs:
MESSAGE="" MESSAGE=""
if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then
echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag." echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
else else
echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag." echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now." MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now."
@@ -149,7 +149,7 @@ jobs:
echo "but 'git merge-base origin/master HEAD' reported: $MERGE_BASE_SHA" echo "but 'git merge-base origin/master HEAD' reported: $MERGE_BASE_SHA"
git -C lean4.git log -10 origin/master git -C lean4.git log -10 origin/master
git -C lean4.git fetch origin nightly-with-mathlib git -C lean4.git fetch origin nightly-with-mathlib
NIGHTLY_WITH_MATHLIB_SHA="$(git -C lean4.git rev-parse "origin/nightly-with-mathlib")" NIGHTLY_WITH_MATHLIB_SHA="$(git -C lean4.git rev-parse "origin/nightly-with-mathlib")"
MESSAGE="- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the \`nightly-with-mathlib\` branch. Try \`git rebase $MERGE_BASE_SHA --onto $NIGHTLY_WITH_MATHLIB_SHA\`." MESSAGE="- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the \`nightly-with-mathlib\` branch. Try \`git rebase $MERGE_BASE_SHA --onto $NIGHTLY_WITH_MATHLIB_SHA\`."
fi fi
@@ -329,17 +329,16 @@ jobs:
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE" git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
git add lean-toolchain git add lean-toolchain
sed -i 's,require "leanprover-community" / "batteries" @ git ".\+",require "leanprover-community" / "batteries" @ git "lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}",' lakefile.lean sed -i 's,require "leanprover-community" / "batteries" @ git ".\+",require "leanprover-community" / "batteries" @ git "nightly-testing-'"${MOST_RECENT_NIGHTLY}"'",' lakefile.lean
lake update batteries lake update batteries
git add lakefile.lean lake-manifest.json git add lakefile.lean lake-manifest.json
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}" git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
else else
echo "Branch already exists, merging $BASE and bumping Batteries." echo "Branch already exists, pushing an empty commit."
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
# The Mathlib `nightly-testing` branch or `nightly-testing-YYYY-MM-DD` tag may have moved since this branch was created, so merge their changes. # The Mathlib `nightly-testing` branch or `nightly-testing-YYYY-MM-DD` tag may have moved since this branch was created, so merge their changes.
# (This should no longer be possible once `nightly-testing-YYYY-MM-DD` is a tag, but it is still safe to merge.) # (This should no longer be possible once `nightly-testing-YYYY-MM-DD` is a tag, but it is still safe to merge.)
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
lake update batteries
git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}" git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
fi fi

View File

@@ -381,7 +381,7 @@ v4.10.0
* **Commands** * **Commands**
* [#4370](https://github.com/leanprover/lean4/pull/4370) makes the `variable` command fully elaborate binders during validation, fixing an issue where some errors would be reported only at the next declaration. * [#4370](https://github.com/leanprover/lean4/pull/4370) makes the `variable` command fully elaborate binders during validation, fixing an issue where some errors would be reported only at the next declaration.
* [#4408](https://github.com/leanprover/lean4/pull/4408) fixes a discrepancy in universe parameter order between `theorem` and `def` declarations. * [#4408](https://github.com/leanprover/lean4/pull/4408) fixes a discrepency in universe parameter order between `theorem` and `def` declarations.
* [#4493](https://github.com/leanprover/lean4/pull/4493) and * [#4493](https://github.com/leanprover/lean4/pull/4493) and
[#4482](https://github.com/leanprover/lean4/pull/4482) fix a discrepancy in the elaborators for `theorem`, `def`, and `example`, [#4482](https://github.com/leanprover/lean4/pull/4482) fix a discrepancy in the elaborators for `theorem`, `def`, and `example`,
making `Prop`-valued `example`s and other definition commands elaborate like `theorem`s. making `Prop`-valued `example`s and other definition commands elaborate like `theorem`s.
@@ -443,7 +443,7 @@ v4.10.0
* [#4454](https://github.com/leanprover/lean4/pull/4454) adds public `Name.isInternalDetail` function for filtering declarations using naming conventions for internal names. * [#4454](https://github.com/leanprover/lean4/pull/4454) adds public `Name.isInternalDetail` function for filtering declarations using naming conventions for internal names.
* **Other fixes or improvements** * **Other fixes or improvements**
* [#4416](https://github.com/leanprover/lean4/pull/4416) sorts the output of `#print axioms` for determinism. * [#4416](https://github.com/leanprover/lean4/pull/4416) sorts the ouput of `#print axioms` for determinism.
* [#4528](https://github.com/leanprover/lean4/pull/4528) fixes error message range for the cdot focusing tactic. * [#4528](https://github.com/leanprover/lean4/pull/4528) fixes error message range for the cdot focusing tactic.
### Language server, widgets, and IDE extensions ### Language server, widgets, and IDE extensions
@@ -479,7 +479,7 @@ v4.10.0
* [#4372](https://github.com/leanprover/lean4/pull/4372) fixes linearity in `HashMap.insert` and `HashMap.erase`, leading to a 40% speedup in a replace-heavy workload. * [#4372](https://github.com/leanprover/lean4/pull/4372) fixes linearity in `HashMap.insert` and `HashMap.erase`, leading to a 40% speedup in a replace-heavy workload.
* `Option` * `Option`
* [#4403](https://github.com/leanprover/lean4/pull/4403) generalizes type of `Option.forM` from `Unit` to `PUnit`. * [#4403](https://github.com/leanprover/lean4/pull/4403) generalizes type of `Option.forM` from `Unit` to `PUnit`.
* [#4504](https://github.com/leanprover/lean4/pull/4504) remove simp attribute from `Option.elim` and instead adds it to individual reduction lemmas, making unfolding less aggressive. * [#4504](https://github.com/leanprover/lean4/pull/4504) remove simp attribute from `Option.elim` and instead adds it to individal reduction lemmas, making unfolding less aggressive.
* `Nat` * `Nat`
* [#4242](https://github.com/leanprover/lean4/pull/4242) adds missing theorems for `n + 1` and `n - 1` normal forms. * [#4242](https://github.com/leanprover/lean4/pull/4242) adds missing theorems for `n + 1` and `n - 1` normal forms.
* [#4486](https://github.com/leanprover/lean4/pull/4486) makes `Nat.min_assoc` be a simp lemma. * [#4486](https://github.com/leanprover/lean4/pull/4486) makes `Nat.min_assoc` be a simp lemma.
@@ -940,7 +940,7 @@ While most changes could be considered to be a breaking change, this section mak
In particular, tactics embedded in the type will no longer make use of the type of `value` in expressions such as `let x : type := value; body`. In particular, tactics embedded in the type will no longer make use of the type of `value` in expressions such as `let x : type := value; body`.
* Now functions defined by well-founded recursion are marked with `@[irreducible]` by default ([#4061](https://github.com/leanprover/lean4/pull/4061)). * Now functions defined by well-founded recursion are marked with `@[irreducible]` by default ([#4061](https://github.com/leanprover/lean4/pull/4061)).
Existing proofs that hold by definitional equality (e.g. `rfl`) can be Existing proofs that hold by definitional equality (e.g. `rfl`) can be
rewritten to explicitly unfold the function definition (using `simp`, rewritten to explictly unfold the function definition (using `simp`,
`unfold`, `rw`), or the recursive function can be temporarily made `unfold`, `rw`), or the recursive function can be temporarily made
semireducible (using `unseal f in` before the command), or the function semireducible (using `unseal f in` before the command), or the function
definition itself can be marked as `@[semireducible]` to get the previous definition itself can be marked as `@[semireducible]` to get the previous
@@ -1559,7 +1559,7 @@ v4.7.0
and `BitVec` as we begin making the APIs and simp normal forms for these types and `BitVec` as we begin making the APIs and simp normal forms for these types
more complete and consistent. more complete and consistent.
4. Laying the groundwork for the Std roadmap, as a library focused on 4. Laying the groundwork for the Std roadmap, as a library focused on
essential datatypes not provided by the core language (e.g. `RBMap`) essential datatypes not provided by the core langauge (e.g. `RBMap`)
and utilities such as basic IO. and utilities such as basic IO.
While we have achieved most of our initial aims in `v4.7.0-rc1`, While we have achieved most of our initial aims in `v4.7.0-rc1`,
some upstreaming will continue over the coming months. some upstreaming will continue over the coming months.
@@ -1570,7 +1570,7 @@ v4.7.0
There is now kernel support for these functions. There is now kernel support for these functions.
[#3376](https://github.com/leanprover/lean4/pull/3376). [#3376](https://github.com/leanprover/lean4/pull/3376).
* `omega`, our integer linear arithmetic tactic, is now available in the core language. * `omega`, our integer linear arithmetic tactic, is now availabe in the core langauge.
* It is supplemented by a preprocessing tactic `bv_omega` which can solve goals about `BitVec` * It is supplemented by a preprocessing tactic `bv_omega` which can solve goals about `BitVec`
which naturally translate into linear arithmetic problems. which naturally translate into linear arithmetic problems.
[#3435](https://github.com/leanprover/lean4/pull/3435). [#3435](https://github.com/leanprover/lean4/pull/3435).
@@ -1663,11 +1663,11 @@ v4.6.0
/- /-
The `Step` type has three constructors: `.done`, `.visit`, `.continue`. The `Step` type has three constructors: `.done`, `.visit`, `.continue`.
* The constructor `.done` instructs `simp` that the result does * The constructor `.done` instructs `simp` that the result does
not need to be simplified further. not need to be simplied further.
* The constructor `.visit` instructs `simp` to visit the resulting expression. * The constructor `.visit` instructs `simp` to visit the resulting expression.
* The constructor `.continue` instructs `simp` to try other simplification procedures. * The constructor `.continue` instructs `simp` to try other simplification procedures.
All three constructors take a `Result`. The `.continue` constructor may also take `none`. All three constructors take a `Result`. The `.continue` contructor may also take `none`.
`Result` has two fields `expr` (the new expression), and `proof?` (an optional proof). `Result` has two fields `expr` (the new expression), and `proof?` (an optional proof).
If the new expression is definitionally equal to the input one, then `proof?` can be omitted or set to `none`. If the new expression is definitionally equal to the input one, then `proof?` can be omitted or set to `none`.
-/ -/
@@ -1879,7 +1879,7 @@ v4.5.0
--------- ---------
* Modify the lexical syntax of string literals to have string gaps, which are escape sequences of the form `"\" newline whitespace*`. * Modify the lexical syntax of string literals to have string gaps, which are escape sequences of the form `"\" newline whitespace*`.
These have the interpretation of an empty string and allow a string to flow across multiple lines without introducing additional whitespace. These have the interpetation of an empty string and allow a string to flow across multiple lines without introducing additional whitespace.
The following is equivalent to `"this is a string"`. The following is equivalent to `"this is a string"`.
```lean ```lean
"this is \ "this is \
@@ -1902,7 +1902,7 @@ v4.5.0
If the well-founded relation you want to use is not the one that the If the well-founded relation you want to use is not the one that the
`WellFoundedRelation` type class would infer for your termination argument, `WellFoundedRelation` type class would infer for your termination argument,
you can use `WellFounded.wrap` from the std library to explicitly give one: you can use `WellFounded.wrap` from the std libarary to explicitly give one:
```diff ```diff
-termination_by' ⟨r, hwf⟩ -termination_by' ⟨r, hwf⟩
+termination_by x => hwf.wrap x +termination_by x => hwf.wrap x

View File

@@ -73,7 +73,7 @@ update the archived C source code of the stage 0 compiler in `stage0/src`.
The github repository will automatically update stage0 on `master` once The github repository will automatically update stage0 on `master` once
`src/stdlib_flags.h` and `stage0/src/stdlib_flags.h` are out of sync. `src/stdlib_flags.h` and `stage0/src/stdlib_flags.h` are out of sync.
If you have write access to the lean4 repository, you can also manually If you have write access to the lean4 repository, you can also also manually
trigger that process, for example to be able to use new features in the compiler itself. trigger that process, for example to be able to use new features in the compiler itself.
You can do that on <https://github.com/leanprover/lean4/actions/workflows/update-stage0.yml> You can do that on <https://github.com/leanprover/lean4/actions/workflows/update-stage0.yml>
or using Github CLI with or using Github CLI with

View File

@@ -71,12 +71,6 @@ We'll use `v4.6.0` as the intended release version as a running example.
- Toolchain bump PR including updated Lake manifest - Toolchain bump PR including updated Lake manifest
- Create and push the tag - Create and push the tag
- There is no `stable` branch; skip this step - There is no `stable` branch; skip this step
- [Verso](https://github.com/leanprover/verso)
- Dependencies: exist, but they're not part of the release workflow
- The `SubVerso` dependency should be compatible with _every_ Lean release simultaneously, rather than following this workflow
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [import-graph](https://github.com/leanprover-community/import-graph) - [import-graph](https://github.com/leanprover-community/import-graph)
- Toolchain bump PR including updated Lake manifest - Toolchain bump PR including updated Lake manifest
- Create and push the tag - Create and push the tag

View File

@@ -18,7 +18,7 @@ def ctor (mvarId : MVarId) (idx : Nat) : MetaM (List MVarId) := do
else if h : idx - 1 < ctors.length then else if h : idx - 1 < ctors.length then
mvarId.apply (.const ctors[idx - 1] us) mvarId.apply (.const ctors[idx - 1] us)
else else
throwTacticEx `ctor mvarId "invalid index, inductive datatype has only {ctors.length} constructors" throwTacticEx `ctor mvarId "invalid index, inductive datatype has only {ctors.length} contructors"
open Elab Tactic open Elab Tactic

View File

@@ -149,7 +149,7 @@ We now define the constant folding optimization that traverses a term if replace
/-! /-!
The correctness of the `Term.constFold` is proved using induction, case-analysis, and the term simplifier. The correctness of the `Term.constFold` is proved using induction, case-analysis, and the term simplifier.
We prove all cases but the one for `plus` using `simp [*]`. This tactic instructs the term simplifier to We prove all cases but the one for `plus` using `simp [*]`. This tactic instructs the term simplifier to
use hypotheses such as `a = b` as rewriting/simplifications rules. use hypotheses such as `a = b` as rewriting/simplications rules.
We use the `split` to break the nested `match` expression in the `plus` case into two cases. We use the `split` to break the nested `match` expression in the `plus` case into two cases.
The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`. The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`.
The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in

View File

@@ -225,7 +225,7 @@ We now define the constant folding optimization that traverses a term if replace
/-! /-!
The correctness of the `constFold` is proved using induction, case-analysis, and the term simplifier. The correctness of the `constFold` is proved using induction, case-analysis, and the term simplifier.
We prove all cases but the one for `plus` using `simp [*]`. This tactic instructs the term simplifier to We prove all cases but the one for `plus` using `simp [*]`. This tactic instructs the term simplifier to
use hypotheses such as `a = b` as rewriting/simplifications rules. use hypotheses such as `a = b` as rewriting/simplications rules.
We use the `split` to break the nested `match` expression in the `plus` case into two cases. We use the `split` to break the nested `match` expression in the `plus` case into two cases.
The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`. The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`.
The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in

View File

@@ -29,7 +29,7 @@ inductive HasType : Expr → Ty → Prop
/-! /-!
We can easily show that if `e` has type `t₁` and type `t₂`, then `t₁` and `t₂` must be equal We can easily show that if `e` has type `t₁` and type `t₂`, then `t₁` and `t₂` must be equal
by using the `cases` tactic. This tactic creates a new subgoal for every constructor, by using the the `cases` tactic. This tactic creates a new subgoal for every constructor,
and automatically discharges unreachable cases. The tactic combinator `tac₁ <;> tac₂` applies and automatically discharges unreachable cases. The tactic combinator `tac₁ <;> tac₂` applies
`tac₂` to each subgoal produced by `tac₁`. Then, the tactic `rfl` is used to close all produced `tac₂` to each subgoal produced by `tac₁`. Then, the tactic `rfl` is used to close all produced
goals using reflexivity. goals using reflexivity.
@@ -82,7 +82,7 @@ theorem Expr.typeCheck_correct (h₁ : HasType e ty) (h₂ : e.typeCheck ≠ .un
/-! /-!
Now, we prove that if `Expr.typeCheck e` returns `Maybe.unknown`, then forall `ty`, `HasType e ty` does not hold. Now, we prove that if `Expr.typeCheck e` returns `Maybe.unknown`, then forall `ty`, `HasType e ty` does not hold.
The notation `e.typeCheck` is sugar for `Expr.typeCheck e`. Lean can infer this because we explicitly said that `e` has type `Expr`. The notation `e.typeCheck` is sugar for `Expr.typeCheck e`. Lean can infer this because we explicitly said that `e` has type `Expr`.
The proof is by induction on `e` and case analysis. The tactic `rename_i` is used to rename "inaccessible" variables. The proof is by induction on `e` and case analysis. The tactic `rename_i` is used to to rename "inaccessible" variables.
We say a variable is inaccessible if it is introduced by a tactic (e.g., `cases`) or has been shadowed by another variable introduced We say a variable is inaccessible if it is introduced by a tactic (e.g., `cases`) or has been shadowed by another variable introduced
by the user. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes by the user. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes
the cases corresponding to the constructors `Expr.nat` and `Expr.bool`. the cases corresponding to the constructors `Expr.nat` and `Expr.bool`.

View File

@@ -93,7 +93,7 @@ Meaning "Remote Procedure Call",this is a Lean function callable from widget cod
Our method will take in the `name : Name` of a constant in the environment and return its type. Our method will take in the `name : Name` of a constant in the environment and return its type.
By convention, we represent the input data as a `structure`. By convention, we represent the input data as a `structure`.
Since it will be sent over from JavaScript, Since it will be sent over from JavaScript,
we need `FromJson` and `ToJson` instance. we need `FromJson` and `ToJson` instnace.
We'll see why the position field is needed later. We'll see why the position field is needed later.
-/ -/

View File

@@ -396,7 +396,7 @@ Every expression in Lean has a natural computational interpretation, unless it i
* *β-reduction* : An expression ``(λ x, t) s`` β-reduces to ``t[s/x]``, that is, the result of replacing ``x`` by ``s`` in ``t``. * *β-reduction* : An expression ``(λ x, t) s`` β-reduces to ``t[s/x]``, that is, the result of replacing ``x`` by ``s`` in ``t``.
* *ζ-reduction* : An expression ``let x := s in t`` ζ-reduces to ``t[s/x]``. * *ζ-reduction* : An expression ``let x := s in t`` ζ-reduces to ``t[s/x]``.
* *δ-reduction* : If ``c`` is a defined constant with definition ``t``, then ``c`` δ-reduces to ``t``. * *δ-reduction* : If ``c`` is a defined constant with definition ``t``, then ``c`` δ-reduces to to ``t``.
* *ι-reduction* : When a function defined by recursion on an inductive type is applied to an element given by an explicit constructor, the result ι-reduces to the specified function value, as described in [Inductive Types](inductive.md). * *ι-reduction* : When a function defined by recursion on an inductive type is applied to an element given by an explicit constructor, the result ι-reduces to the specified function value, as described in [Inductive Types](inductive.md).
The reduction relation is transitive, which is to say, is ``s`` reduces to ``s'`` and ``t`` reduces to ``t'``, then ``s t`` reduces to ``s' t'``, ``λ x, s`` reduces to ``λ x, s'``, and so on. If ``s`` and ``t`` reduce to a common term, they are said to be *definitionally equal*. Definitional equality is defined to be the smallest equivalence relation that satisfies all these properties and also includes α-equivalence and the following two relations: The reduction relation is transitive, which is to say, is ``s`` reduces to ``s'`` and ``t`` reduces to ``t'``, then ``s t`` reduces to ``s' t'``, ``λ x, s`` reduces to ``λ x, s'``, and so on. If ``s`` and ``t`` reduce to a common term, they are said to be *definitionally equal*. Definitional equality is defined to be the smallest equivalence relation that satisfies all these properties and also includes α-equivalence and the following two relations:

View File

@@ -171,7 +171,7 @@ of data contained in the container resulting in a new container that has the sam
`u <*> pure y = pure (. y) <*> u`. `u <*> pure y = pure (. y) <*> u`.
This law is a little more complicated, so don't sweat it too much. It states that the order that This law is is a little more complicated, so don't sweat it too much. It states that the order that
you wrap things shouldn't matter. One the left, you apply any applicative `u` over a pure wrapped you wrap things shouldn't matter. One the left, you apply any applicative `u` over a pure wrapped
object. On the right, you first wrap a function applying the object as an argument. Note that `(· object. On the right, you first wrap a function applying the object as an argument. Note that `(·
y)` is short hand for: `fun f => f y`. Then you apply this to the first applicative `u`. These y)` is short hand for: `fun f => f y`. Then you apply this to the first applicative `u`. These

View File

@@ -17,7 +17,7 @@ for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
done done
# special handling for Lake files due to its nested directory # special handling for Lake files due to its nested directory
# copy the README to ensure the `stage0/src/lake` directory is committed # copy the README to ensure the `stage0/src/lake` directory is comitted
for f in $(git ls-files 'src/lake/Lake/*' src/lake/Lake.lean src/lake/LakeMain.lean src/lake/README.md ':!:src/lakefile.toml'); do for f in $(git ls-files 'src/lake/Lake/*' src/lake/Lake.lean src/lake/LakeMain.lean src/lake/README.md ':!:src/lakefile.toml'); do
if [[ $f == *.lean ]]; then if [[ $f == *.lean ]]; then
f=${f#src/lake} f=${f#src/lake}

View File

@@ -121,11 +121,11 @@ theorem propComplete (a : Prop) : a = True a = False :=
| Or.inl ha => Or.inl (eq_true ha) | Or.inl ha => Or.inl (eq_true ha)
| Or.inr hn => Or.inr (eq_false hn) | Or.inr hn => Or.inr (eq_false hn)
-- this supersedes byCases in Decidable -- this supercedes byCases in Decidable
theorem byCases {p q : Prop} (hpq : p q) (hnpq : ¬p q) : q := theorem byCases {p q : Prop} (hpq : p q) (hnpq : ¬p q) : q :=
Decidable.byCases (dec := propDecidable _) hpq hnpq Decidable.byCases (dec := propDecidable _) hpq hnpq
-- this supersedes byContradiction in Decidable -- this supercedes byContradiction in Decidable
theorem byContradiction {p : Prop} (h : ¬p False) : p := theorem byContradiction {p : Prop} (h : ¬p False) : p :=
Decidable.byContradiction (dec := propDecidable _) h Decidable.byContradiction (dec := propDecidable _) h

View File

@@ -1892,8 +1892,7 @@ theorem funext {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x}
show extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g) show extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g)
exact congrArg extfunApp (Quot.sound h) exact congrArg extfunApp (Quot.sound h)
instance Pi.instSubsingleton {α : Sort u} {β : α Sort v} [ a, Subsingleton (β a)] : instance {α : Sort u} {β : α Sort v} [ a, Subsingleton (β a)] : Subsingleton ( a, β a) where
Subsingleton ( a, β a) where
allEq f g := funext fun a => Subsingleton.elim (f a) (g a) allEq f g := funext fun a => Subsingleton.elim (f a) (g a)
/-! # Squash -/ /-! # Squash -/
@@ -2056,7 +2055,7 @@ class IdempotentOp (op : ααα) : Prop where
`LeftIdentify op o` indicates `o` is a left identity of `op`. `LeftIdentify op o` indicates `o` is a left identity of `op`.
This class does not require a proof that `o` is an identity, and This class does not require a proof that `o` is an identity, and
is used primarily for inferring the identity using class resolution. is used primarily for infering the identity using class resoluton.
-/ -/
class LeftIdentity (op : α β β) (o : outParam α) : Prop class LeftIdentity (op : α β β) (o : outParam α) : Prop
@@ -2072,7 +2071,7 @@ class LawfulLeftIdentity (op : α → β → β) (o : outParam α) extends LeftI
`RightIdentify op o` indicates `o` is a right identity `o` of `op`. `RightIdentify op o` indicates `o` is a right identity `o` of `op`.
This class does not require a proof that `o` is an identity, and is used This class does not require a proof that `o` is an identity, and is used
primarily for inferring the identity using class resolution. primarily for infering the identity using class resoluton.
-/ -/
class RightIdentity (op : α β α) (o : outParam β) : Prop class RightIdentity (op : α β α) (o : outParam β) : Prop
@@ -2088,7 +2087,7 @@ class LawfulRightIdentity (op : α → β → α) (o : outParam β) extends Righ
`Identity op o` indicates `o` is a left and right identity of `op`. `Identity op o` indicates `o` is a left and right identity of `op`.
This class does not require a proof that `o` is an identity, and is used This class does not require a proof that `o` is an identity, and is used
primarily for inferring the identity using class resolution. primarily for infering the identity using class resoluton.
-/ -/
class Identity (op : α α α) (o : outParam α) extends LeftIdentity op o, RightIdentity op o : Prop class Identity (op : α α α) (o : outParam α) extends LeftIdentity op o, RightIdentity op o : Prop

View File

@@ -33,6 +33,7 @@ import Init.Data.Prod
import Init.Data.AC import Init.Data.AC
import Init.Data.Queue import Init.Data.Queue
import Init.Data.Channel import Init.Data.Channel
import Init.Data.Cast
import Init.Data.Sum import Init.Data.Sum
import Init.Data.BEq import Init.Data.BEq
import Init.Data.Subtype import Init.Data.Subtype

View File

@@ -73,7 +73,8 @@ theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by @[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append] induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
@[simp] theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl @[simp] theorem toList_toArray (as : List α) : as.toArray.toList = as := by
simp [List.toArray, Array.mkEmpty]
@[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [size] @[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [size]
@@ -161,16 +162,19 @@ instance : Inhabited (Array α) where
@[simp] def isEmpty (a : Array α) : Bool := @[simp] def isEmpty (a : Array α) : Bool :=
a.size = 0 a.size = 0
-- TODO(Leo): cleanup
@[specialize] @[specialize]
def isEqvAux (a b : Array α) (hsz : a.size = b.size) (p : α α Bool) : def isEqvAux (a b : Array α) (hsz : a.size = b.size) (p : α α Bool) (i : Nat) : Bool :=
(i : Nat) (_ : i a.size), Bool if h : i < a.size then
| 0, _ => true have : i < b.size := hsz h
| i+1, h => p a[i] b[i] && isEqvAux a b hsz p (i+1)
p a[i] (b[i]'(hsz h)) && isEqvAux a b hsz p i (Nat.le_trans (Nat.le_add_right i 1) h) else
true
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[inline] def isEqv (a b : Array α) (p : α α Bool) : Bool := @[inline] def isEqv (a b : Array α) (p : α α Bool) : Bool :=
if h : a.size = b.size then if h : a.size = b.size then
isEqvAux a b h p a.size (Nat.le_refl a.size) isEqvAux a b h p 0
else else
false false
@@ -184,10 +188,9 @@ ofFn f = #[f 0, f 1, ... , f(n - 1)]
``` -/ ``` -/
def ofFn {n} (f : Fin n α) : Array α := go 0 (mkEmpty n) where def ofFn {n} (f : Fin n α) : Array α := go 0 (mkEmpty n) where
/-- Auxiliary for `ofFn`. `ofFn.go f i acc = acc ++ #[f i, ..., f(n - 1)]` -/ /-- Auxiliary for `ofFn`. `ofFn.go f i acc = acc ++ #[f i, ..., f(n - 1)]` -/
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
go (i : Nat) (acc : Array α) : Array α := go (i : Nat) (acc : Array α) : Array α :=
if h : i < n then go (i+1) (acc.push (f i, h)) else acc if h : i < n then go (i+1) (acc.push (f i, h)) else acc
decreasing_by simp_wf; decreasing_trivial_pre_omega decreasing_by simp_wf; decreasing_trivial_pre_omega
/-- The array `#[0, 1, ..., n - 1]`. -/ /-- The array `#[0, 1, ..., n - 1]`. -/
def range (n : Nat) : Array Nat := def range (n : Nat) : Array Nat :=
@@ -386,12 +389,11 @@ unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad
def mapM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β) := def mapM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β) :=
-- Note: we cannot use `foldlM` here for the reference implementation because this calls -- Note: we cannot use `foldlM` here for the reference implementation because this calls
-- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`) -- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`)
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion. let rec map (i : Nat) (r : Array β) : m (Array β) := do
map (i : Nat) (r : Array β) : m (Array β) := do if hlt : i < as.size then
if hlt : i < as.size then map (i+1) (r.push ( f as[i]))
map (i+1) (r.push ( f as[i])) else
else pure r
pure r
decreasing_by simp_wf; decreasing_trivial_pre_omega decreasing_by simp_wf; decreasing_trivial_pre_omega
map 0 (mkEmpty as.size) map 0 (mkEmpty as.size)
@@ -455,8 +457,7 @@ unsafe def anyMUnsafe {α : Type u} {m : Type → Type w} [Monad m] (p : α
@[implemented_by anyMUnsafe] @[implemented_by anyMUnsafe]
def anyM {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) (start := 0) (stop := as.size) : m Bool := def anyM {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) (start := 0) (stop := as.size) : m Bool :=
let any (stop : Nat) (h : stop as.size) := let any (stop : Nat) (h : stop as.size) :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion. let rec loop (j : Nat) : m Bool := do
loop (j : Nat) : m Bool := do
if hlt : j < stop then if hlt : j < stop then
have : j < as.size := Nat.lt_of_lt_of_le hlt h have : j < as.size := Nat.lt_of_lt_of_le hlt h
if ( p as[j]) then if ( p as[j]) then
@@ -546,8 +547,7 @@ def findRev? {α : Type} (as : Array α) (p : α → Bool) : Option α :=
@[inline] @[inline]
def findIdx? {α : Type u} (as : Array α) (p : α Bool) : Option Nat := def findIdx? {α : Type u} (as : Array α) (p : α Bool) : Option Nat :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion. let rec loop (j : Nat) :=
loop (j : Nat) :=
if h : j < as.size then if h : j < as.size then
if p as[j] then some j else loop (j + 1) if p as[j] then some j else loop (j + 1)
else none else none
@@ -557,7 +557,6 @@ def findIdx? {α : Type u} (as : Array α) (p : α → Bool) : Option Nat :=
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat := def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
a.findIdx? fun a => a == v a.findIdx? fun a => a == v
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) := def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) :=
if h : i < a.size then if h : i < a.size then
let idx : Fin a.size := i, h; let idx : Fin a.size := i, h;
@@ -679,7 +678,6 @@ where
else else
as as
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def popWhile (p : α Bool) (as : Array α) : Array α := def popWhile (p : α Bool) (as : Array α) : Array α :=
if h : as.size > 0 then if h : as.size > 0 then
if p (as.get as.size - 1, Nat.sub_lt h (by decide)) then if p (as.get as.size - 1, Nat.sub_lt h (by decide)) then
@@ -691,8 +689,7 @@ def popWhile (p : α → Bool) (as : Array α) : Array α :=
decreasing_by simp_wf; decreasing_trivial_pre_omega decreasing_by simp_wf; decreasing_trivial_pre_omega
def takeWhile (p : α Bool) (as : Array α) : Array α := def takeWhile (p : α Bool) (as : Array α) : Array α :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion. let rec go (i : Nat) (r : Array α) : Array α :=
go (i : Nat) (r : Array α) : Array α :=
if h : i < as.size then if h : i < as.size then
let a := as.get i, h let a := as.get i, h
if p a then if p a then
@@ -708,7 +705,6 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
This function takes worst case O(n) time because This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/ it has to backshift all elements at positions greater than `i`.-/
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def feraseIdx (a : Array α) (i : Fin a.size) : Array α := def feraseIdx (a : Array α) (i : Fin a.size) : Array α :=
if h : i.val + 1 < a.size then if h : i.val + 1 < a.size then
let a' := a.swap i.val + 1, h i let a' := a.swap i.val + 1, h i
@@ -743,8 +739,7 @@ def erase [BEq α] (as : Array α) (a : α) : Array α :=
/-- Insert element `a` at position `i`. -/ /-- Insert element `a` at position `i`. -/
@[inline] def insertAt (as : Array α) (i : Fin (as.size + 1)) (a : α) : Array α := @[inline] def insertAt (as : Array α) (i : Fin (as.size + 1)) (a : α) : Array α :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion. let rec loop (as : Array α) (j : Fin as.size) :=
loop (as : Array α) (j : Fin as.size) :=
if i.1 < j then if i.1 < j then
let j' := j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2 let j' := j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
let as := as.swap j' j let as := as.swap j' j
@@ -762,7 +757,6 @@ def insertAt! (as : Array α) (i : Nat) (a : α) : Array α :=
insertAt as i, Nat.lt_succ_of_le h a insertAt as i, Nat.lt_succ_of_le h a
else panic! "invalid index" else panic! "invalid index"
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size bs.size) (i : Nat) : Bool := def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size bs.size) (i : Nat) : Bool :=
if h : i < as.size then if h : i < as.size then
let a := as[i] let a := as[i]
@@ -784,8 +778,7 @@ def isPrefixOf [BEq α] (as bs : Array α) : Bool :=
else else
false false
@[semireducible, specialize] -- This is otherwise irreducible because it uses well-founded recursion. @[specialize] def zipWithAux (f : α β γ) (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) : Array γ :=
def zipWithAux (f : α β γ) (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) : Array γ :=
if h : i < as.size then if h : i < as.size then
let a := as[i] let a := as[i]
if h : i < bs.size then if h : i < bs.size then
@@ -821,7 +814,6 @@ private def allDiffAuxAux [BEq α] (as : Array α) (a : α) : forall (i : Nat),
have : i < as.size := Nat.lt_trans (Nat.lt_succ_self _) h; have : i < as.size := Nat.lt_trans (Nat.lt_succ_self _) h;
a != as[i] && allDiffAuxAux as a i this a != as[i] && allDiffAuxAux as a i this
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
private def allDiffAux [BEq α] (as : Array α) (i : Nat) : Bool := private def allDiffAux [BEq α] (as : Array α) (i : Nat) : Bool :=
if h : i < as.size then if h : i < as.size then
allDiffAuxAux as as[i] i h && allDiffAux as (i+1) allDiffAuxAux as as[i] i h && allDiffAux as (i+1)

View File

@@ -34,7 +34,7 @@ private theorem List.of_toArrayAux_eq_toArrayAux {as bs : List α} {cs ds : Arra
@[simp] theorem List.toArray_eq_toArray_eq (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) := by @[simp] theorem List.toArray_eq_toArray_eq (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) := by
apply propext; apply Iff.intro apply propext; apply Iff.intro
· intro h; simpa [toArray] using h · intro h; simp [toArray] at h; have := of_toArrayAux_eq_toArrayAux h rfl; exact this.1
· intro h; rw [h] · intro h; rw [h]
def Array.mapM' [Monad m] (f : α m β) (as : Array α) : m { bs : Array β // bs.size = as.size } := def Array.mapM' [Monad m] (f : α m β) (as : Array α) : m { bs : Array β // bs.size = as.size } :=

View File

@@ -5,49 +5,43 @@ Authors: Leonardo de Moura
-/ -/
prelude prelude
import Init.Data.Array.Basic import Init.Data.Array.Basic
import Init.Data.BEq
import Init.ByCases import Init.ByCases
namespace Array namespace Array
theorem rel_of_isEqvAux theorem eq_of_isEqvAux [DecidableEq α] (a b : Array α) (hsz : a.size = b.size) (i : Nat) (hi : i a.size) (heqv : Array.isEqvAux a b hsz (fun x y => x = y) i) (j : Nat) (low : i j) (high : j < a.size) : a[j] = b[j]'(hsz high) := by
(r : α α Bool) (a b : Array α) (hsz : a.size = b.size) (i : Nat) (hi : i a.size) by_cases h : i < a.size
(heqv : Array.isEqvAux a b hsz r i hi) · unfold Array.isEqvAux at heqv
(j : Nat) (hj : j < i) : r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz hi))) := by simp [h] at heqv
induction i with have hind := eq_of_isEqvAux a b hsz (i+1) (Nat.succ_le_of_lt h) heqv.2
| zero => contradiction by_cases heq : i = j
| succ i ih => · subst heq; exact heqv.1
simp only [Array.isEqvAux, Bool.and_eq_true, decide_eq_true_eq] at heqv · exact hind j (Nat.succ_le_of_lt (Nat.lt_of_le_of_ne low heq)) high
by_cases hj' : j < i · have heq : i = a.size := Nat.le_antisymm hi (Nat.ge_of_not_lt h)
next => subst heq
exact ih _ heqv.right hj' exact absurd (Nat.lt_of_lt_of_le high low) (Nat.lt_irrefl j)
next => termination_by a.size - i
replace hj' : j = i := Nat.eq_of_le_of_lt_succ (Nat.not_lt.mp hj') hj decreasing_by decreasing_trivial_pre_omega
subst hj'
exact heqv.left
theorem rel_of_isEqv (r : α α Bool) (a b : Array α) :
Array.isEqv a b r h : a.size = b.size, (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h h')) := by
simp only [isEqv]
split <;> rename_i h
· exact fun h' => h, rel_of_isEqvAux r a b h a.size (Nat.le_refl ..) h'
· intro; contradiction
theorem eq_of_isEqv [DecidableEq α] (a b : Array α) (h : Array.isEqv a b (fun x y => x = y)) : a = b := by theorem eq_of_isEqv [DecidableEq α] (a b : Array α) : Array.isEqv a b (fun x y => x = y) a = b := by
have h, h' := rel_of_isEqv (fun x y => x = y) a b h simp [Array.isEqv]
exact ext _ _ h (fun i lt _ => by simpa using h' i lt) split
next hsz =>
intro h
have aux := eq_of_isEqvAux a b hsz 0 (Nat.zero_le ..) h
exact ext a b hsz fun i h _ => aux i (Nat.zero_le ..) _
next => intro; contradiction
theorem isEqvAux_self (r : α α Bool) (hr : a, r a a) (a : Array α) (i : Nat) (h : i a.size) : theorem isEqvAux_self [DecidableEq α] (a : Array α) (i : Nat) : Array.isEqvAux a a rfl (fun x y => x = y) i = true := by
Array.isEqvAux a a rfl r i h = true := by unfold Array.isEqvAux
induction i with split
| zero => simp [Array.isEqvAux] next h => simp [h, isEqvAux_self a (i+1)]
| succ i ih => next h => simp [h]
simp_all only [isEqvAux, Bool.and_self] termination_by a.size - i
decreasing_by decreasing_trivial_pre_omega
theorem isEqv_self_beq [BEq α] [ReflBEq α] (a : Array α) : Array.isEqv a a (· == ·) = true := by theorem isEqv_self [DecidableEq α] (a : Array α) : Array.isEqv a a (fun x y => x = y) = true := by
simp [isEqv, isEqvAux_self]
theorem isEqv_self [DecidableEq α] (a : Array α) : Array.isEqv a a (· = ·) = true := by
simp [isEqv, isEqvAux_self] simp [isEqv, isEqvAux_self]
instance [DecidableEq α] : DecidableEq (Array α) := instance [DecidableEq α] : DecidableEq (Array α) :=

View File

@@ -19,9 +19,24 @@ This file contains some theorems about `Array` and `List` needed for `Init.Data.
namespace Array namespace Array
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl attribute [simp] uset
@[simp] theorem getElem_mk {xs : List α} {i : Nat} (h : i < xs.length) : (Array.mk xs)[i] = xs[i] := rfl @[simp] theorem singleton_def (v : α) : singleton v = #[v] := rfl
@[simp] theorem toArray_toList : (a : Array α) a.toList.toArray = a
| l => ext' (toList_toArray l)
@[deprecated toArray_toList (since := "2024-09-09")]
abbrev toArray_data := @toArray_toList
@[simp] theorem toList_length {l : Array α} : l.toList.length = l.size := rfl
@[deprecated toList_length (since := "2024-09-09")]
abbrev data_length := @toList_length
@[simp] theorem mkEmpty_eq (α n) : @mkEmpty α n = #[] := rfl
@[simp] theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
theorem getElem_eq_toList_getElem (a : Array α) (h : i < a.size) : a[i] = a.toList[i] := by theorem getElem_eq_toList_getElem (a : Array α) (h : i < a.size) : a[i] = a.toList[i] := by
by_cases i < a.size <;> (try simp [*]) <;> rfl by_cases i < a.size <;> (try simp [*]) <;> rfl
@@ -31,7 +46,27 @@ abbrev getElem_eq_data_getElem := @getElem_eq_toList_getElem
@[deprecated getElem_eq_toList_getElem (since := "2024-06-12")] @[deprecated getElem_eq_toList_getElem (since := "2024-06-12")]
theorem getElem_eq_toList_get (a : Array α) (h : i < a.size) : a[i] = a.toList.get i, h := by theorem getElem_eq_toList_get (a : Array α) (h : i < a.size) : a[i] = a.toList.get i, h := by
simp simp [getElem_eq_toList_getElem]
theorem foldrM_push [Monad m] (f : α β m β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldrM f init = f a init >>= arr.foldrM f := by
simp [foldrM_eq_reverse_foldlM_toList, -size_push]
@[simp] theorem foldrM_push' [Monad m] (f : α β m β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldrM f init (start := arr.size + 1) = f a init >>= arr.foldrM f := by
simp [ foldrM_push]
theorem foldr_push (f : α β β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldr f init = arr.foldr f (f a init) := foldrM_push ..
@[simp] theorem foldr_push' (f : α β β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldr f init (start := arr.size + 1) = arr.foldr f (f a init) := foldrM_push' ..
/-- A more efficient version of `arr.toList.reverse`. -/
@[inline] def toListRev (arr : Array α) : List α := arr.foldl (fun l t => t :: l) []
@[simp] theorem toListRev_eq (arr : Array α) : arr.toListRev = arr.toList.reverse := by
rw [toListRev, foldl_eq_foldl_toList, List.foldr_reverse, List.foldr_cons_nil]
theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) : theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
have : i < (a.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt] have : i < (a.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt]
@@ -49,75 +84,6 @@ theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
· simp at h · simp at h
simp [get_push_lt, Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')] simp [get_push_lt, Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')]
end Array
namespace List
open Array
/-! ### Lemmas about `List.toArray`. -/
@[simp] theorem size_toArrayAux {a : List α} {b : Array α} :
(a.toArrayAux b).size = b.size + a.length := by
simp [size]
@[simp] theorem toArray_toList (a : Array α) : a.toList.toArray = a := rfl
@[deprecated toArray_toList (since := "2024-09-09")]
abbrev toArray_data := @toArray_toList
@[simp] theorem getElem_toArray {a : List α} {i : Nat} (h : i < a.toArray.size) :
a.toArray[i] = a[i]'(by simpa using h) := rfl
@[simp] theorem toArray_concat {as : List α} {x : α} :
(as ++ [x]).toArray = as.toArray.push x := by
apply ext'
simp
end List
namespace Array
attribute [simp] uset
@[simp] theorem singleton_def (v : α) : singleton v = #[v] := rfl
@[simp] theorem toArray_toList (a : Array α) : a.toList.toArray = a := rfl
@[deprecated toArray_toList (since := "2024-09-09")]
abbrev toArray_data := @toArray_toList
@[simp] theorem toList_length {l : Array α} : l.toList.length = l.size := rfl
@[deprecated toList_length (since := "2024-09-09")]
abbrev data_length := @toList_length
@[simp] theorem mkEmpty_eq (α n) : @mkEmpty α n = #[] := rfl
@[simp] theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
theorem foldrM_push [Monad m] (f : α β m β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldrM f init = f a init >>= arr.foldrM f := by
simp [foldrM_eq_reverse_foldlM_toList, -size_push]
/-- Variant of `foldrM_push` with the `start := arr.size + 1` rather than `(arr.push a).size`. -/
@[simp] theorem foldrM_push' [Monad m] (f : α β m β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldrM f init (start := arr.size + 1) = f a init >>= arr.foldrM f := by
simp [ foldrM_push]
theorem foldr_push (f : α β β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldr f init = arr.foldr f (f a init) := foldrM_push ..
/-- Variant of `foldr_push` with the `start := arr.size + 1` rather than `(arr.push a).size`. -/
@[simp] theorem foldr_push' (f : α β β) (init : β) (arr : Array α) (a : α) :
(arr.push a).foldr f init (start := arr.size + 1) = arr.foldr f (f a init) := foldrM_push' ..
/-- A more efficient version of `arr.toList.reverse`. -/
@[inline] def toListRev (arr : Array α) : List α := arr.foldl (fun l t => t :: l) []
@[simp] theorem toListRev_eq (arr : Array α) : arr.toListRev = arr.toList.reverse := by
rw [toListRev, foldl_eq_foldl_toList, List.foldr_reverse, List.foldr_cons_nil]
theorem mapM_eq_foldlM [Monad m] [LawfulMonad m] (f : α m β) (arr : Array α) : theorem mapM_eq_foldlM [Monad m] [LawfulMonad m] (f : α m β) (arr : Array α) :
arr.mapM f = arr.foldlM (fun bs a => bs.push <$> f a) #[] := by arr.mapM f = arr.foldlM (fun bs a => bs.push <$> f a) #[] := by
rw [mapM, aux, foldlM_eq_foldlM_toList]; rfl rw [mapM, aux, foldlM_eq_foldlM_toList]; rfl
@@ -379,7 +345,7 @@ theorem getElem_mem_toList (a : Array α) (h : i < a.size) : a[i] ∈ a.toList :
abbrev getElem_mem_data := @getElem_mem_toList abbrev getElem_mem_data := @getElem_mem_toList
theorem getElem?_eq_toList_get? (a : Array α) (i : Nat) : a[i]? = a.toList.get? i := by theorem getElem?_eq_toList_get? (a : Array α) (i : Nat) : a[i]? = a.toList.get? i := by
by_cases i < a.size <;> simp_all [getElem?_pos, getElem?_neg, List.get?_eq_get, eq_comm] by_cases i < a.size <;> simp_all [getElem?_pos, getElem?_neg, List.get?_eq_get, eq_comm]; rfl
@[deprecated getElem?_eq_toList_get? (since := "2024-09-09")] @[deprecated getElem?_eq_toList_get? (since := "2024-09-09")]
abbrev getElem?_eq_data_get? := @getElem?_eq_toList_get? abbrev getElem?_eq_data_get? := @getElem?_eq_toList_get?
@@ -643,8 +609,8 @@ theorem mapM_eq_mapM_toList [Monad m] [LawfulMonad m] (f : α → m β) (arr : A
rw [mapM_eq_foldlM, foldlM_eq_foldlM_toList, List.foldrM_reverse] rw [mapM_eq_foldlM, foldlM_eq_foldlM_toList, List.foldrM_reverse]
conv => rhs; rw [ List.reverse_reverse arr.toList] conv => rhs; rw [ List.reverse_reverse arr.toList]
induction arr.toList.reverse with induction arr.toList.reverse with
| nil => simp | nil => simp; rfl
| cons a l ih => simp [ih]; simp [map_eq_pure_bind] | cons a l ih => simp [ih]; simp [map_eq_pure_bind, push]
@[deprecated mapM_eq_mapM_toList (since := "2024-09-09")] @[deprecated mapM_eq_mapM_toList (since := "2024-09-09")]
abbrev mapM_eq_mapM_data := @mapM_eq_mapM_toList abbrev mapM_eq_mapM_data := @mapM_eq_mapM_toList

View File

@@ -12,7 +12,6 @@ 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_toList_getElem, uset, toList_set] using simpa [Array.getElem_eq_toList_getElem] using List.exists_of_set _
List.exists_of_set _
end Array end Array

View File

@@ -1,7 +1,7 @@
/- /-
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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Data.BitVec.Basic import Init.Data.BitVec.Basic

View File

@@ -264,8 +264,6 @@ theorem getLsbD_ofNat (n : Nat) (x : Nat) (i : Nat) :
@[simp] theorem getLsbD_zero : (0#w).getLsbD i = false := by simp [getLsbD] @[simp] theorem getLsbD_zero : (0#w).getLsbD i = false := by simp [getLsbD]
@[simp] theorem getElem_zero (h : i < w) : (0#w)[i] = false := by simp [getElem_eq_testBit_toNat]
@[simp] theorem getMsbD_zero : (0#w).getMsbD i = false := by simp [getMsbD] @[simp] theorem getMsbD_zero : (0#w).getMsbD i = false := by simp [getMsbD]
@[simp] theorem toNat_mod_cancel (x : BitVec n) : x.toNat % (2^n) = x.toNat := @[simp] theorem toNat_mod_cancel (x : BitVec n) : x.toNat % (2^n) = x.toNat :=
@@ -314,13 +312,6 @@ theorem getLsbD_ofBool (b : Bool) (i : Nat) : (ofBool b).getLsbD i = ((i = 0) &&
· simp only [ofBool, ofNat_eq_ofNat, cond_true, getLsbD_ofNat, Bool.and_true] · simp only [ofBool, ofNat_eq_ofNat, cond_true, getLsbD_ofNat, Bool.and_true]
by_cases hi : i = 0 <;> simp [hi] <;> omega by_cases hi : i = 0 <;> simp [hi] <;> omega
@[simp]
theorem getElem_ofBool {b : Bool} {i : Nat} : (ofBool b)[0] = b := by
rcases b with rfl | rfl
· simp [ofBool]
· simp only [ofBool]
by_cases hi : i = 0 <;> simp [hi] <;> omega
/-! ### 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]
@@ -644,18 +635,10 @@ protected theorem extractLsb_ofNat (x n : Nat) (hi lo : Nat) :
@[simp] theorem extractLsb_toNat (hi lo : Nat) (x : BitVec n) : @[simp] theorem extractLsb_toNat (hi lo : Nat) (x : BitVec n) :
(extractLsb hi lo x).toNat = (x.toNat >>> lo) % 2^(hi-lo+1) := rfl (extractLsb hi lo x).toNat = (x.toNat >>> lo) % 2^(hi-lo+1) := rfl
@[simp] theorem getElem_extractLsb' {start len : Nat} {x : BitVec n} {i : Nat} (h : i < len) :
(extractLsb' start len x)[i] = x.getLsbD (start+i) := by
simp [getElem_eq_testBit_toNat, getLsbD, h]
@[simp] theorem getLsbD_extractLsb' (start len : Nat) (x : BitVec n) (i : Nat) : @[simp] theorem getLsbD_extractLsb' (start len : Nat) (x : BitVec n) (i : Nat) :
(extractLsb' start len x).getLsbD i = (i < len && x.getLsbD (start+i)) := by (extractLsb' start len x).getLsbD i = (i < len && x.getLsbD (start+i)) := by
simp [getLsbD, Nat.lt_succ] simp [getLsbD, Nat.lt_succ]
@[simp] theorem getElem_extract {hi lo : Nat} {x : BitVec n} {i : Nat} (h : i < hi - lo + 1) :
(extractLsb hi lo x)[i] = getLsbD x (lo+i) := by
simp [getElem_eq_testBit_toNat, getLsbD, h]
@[simp] theorem getLsbD_extract (hi lo : Nat) (x : BitVec n) (i : Nat) : @[simp] theorem getLsbD_extract (hi lo : Nat) (x : BitVec n) (i : Nat) :
getLsbD (extractLsb hi lo x) i = (i (hi-lo) && getLsbD x (lo+i)) := by getLsbD (extractLsb hi lo x) i = (i (hi-lo) && getLsbD x (lo+i)) := by
simp [getLsbD, Nat.lt_succ] simp [getLsbD, Nat.lt_succ]
@@ -727,32 +710,6 @@ theorem or_comm (x y : BitVec w) :
simp [Bool.or_comm] simp [Bool.or_comm]
instance : Std.Commutative (fun (x y : BitVec w) => x ||| y) := BitVec.or_comm instance : Std.Commutative (fun (x y : BitVec w) => x ||| y) := BitVec.or_comm
@[simp] theorem or_self {x : BitVec w} : x ||| x = x := by
ext i
simp
instance : Std.IdempotentOp (α := BitVec n) (· ||| · ) where
idempotent _ := BitVec.or_self
@[simp] theorem or_zero {x : BitVec w} : x ||| 0#w = x := by
ext i
simp
instance : Std.LawfulCommIdentity (α := BitVec n) (· ||| · ) (0#n) where
right_id _ := BitVec.or_zero
@[simp] theorem zero_or {x : BitVec w} : 0#w ||| x = x := by
ext i
simp
@[simp] theorem or_allOnes {x : BitVec w} : x ||| allOnes w = allOnes w := by
ext i
simp
@[simp] theorem allOnes_or {x : BitVec w} : allOnes w ||| x = allOnes w := by
ext i
simp
/-! ### and -/ /-! ### and -/
@[simp] theorem toNat_and (x y : BitVec v) : @[simp] theorem toNat_and (x y : BitVec v) :
@@ -794,32 +751,6 @@ theorem and_comm (x y : BitVec w) :
simp [Bool.and_comm] simp [Bool.and_comm]
instance : Std.Commutative (fun (x y : BitVec w) => x &&& y) := BitVec.and_comm instance : Std.Commutative (fun (x y : BitVec w) => x &&& y) := BitVec.and_comm
@[simp] theorem and_self {x : BitVec w} : x &&& x = x := by
ext i
simp
instance : Std.IdempotentOp (α := BitVec n) (· &&& · ) where
idempotent _ := BitVec.and_self
@[simp] theorem and_zero {x : BitVec w} : x &&& 0#w = 0#w := by
ext i
simp
@[simp] theorem zero_and {x : BitVec w} : 0#w &&& x = 0#w := by
ext i
simp
@[simp] theorem and_allOnes {x : BitVec w} : x &&& allOnes w = x := by
ext i
simp
instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) where
right_id _ := BitVec.and_allOnes
@[simp] theorem allOnes_and {x : BitVec w} : allOnes w &&& x = x := by
ext i
simp
/-! ### xor -/ /-! ### xor -/
@[simp] theorem toNat_xor (x y : BitVec v) : @[simp] theorem toNat_xor (x y : BitVec v) :
@@ -864,21 +795,6 @@ theorem xor_comm (x y : BitVec w) :
simp [Bool.xor_comm] simp [Bool.xor_comm]
instance : Std.Commutative (fun (x y : BitVec w) => x ^^^ y) := BitVec.xor_comm instance : Std.Commutative (fun (x y : BitVec w) => x ^^^ y) := BitVec.xor_comm
@[simp] theorem xor_self {x : BitVec w} : x ^^^ x = 0#w := by
ext i
simp
@[simp] theorem xor_zero {x : BitVec w} : x ^^^ 0#w = x := by
ext i
simp
instance : Std.LawfulCommIdentity (α := BitVec n) (· ^^^ · ) (0#n) where
right_id _ := BitVec.xor_zero
@[simp] theorem zero_xor {x : BitVec w} : 0#w ^^^ x = x := by
ext i
simp
/-! ### not -/ /-! ### not -/
theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
@@ -927,14 +843,6 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
ext ext
simp simp
@[simp] theorem xor_allOnes {x : BitVec w} : x ^^^ allOnes w = ~~~ x := by
ext i
simp
@[simp] theorem allOnes_xor {x : BitVec w} : allOnes w ^^^ x = ~~~ x := by
ext i
simp
/-! ### 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') : ~~~(cast h x) = cast h (~~~x) := by
@@ -979,14 +887,6 @@ theorem zero_shiftLeft (n : Nat) : 0#w <<< n = 0#w := by
cases h₁ : decide (i < m) <;> cases h₂ : decide (n i) <;> cases h₃ : decide (i < n) cases h₁ : decide (i < m) <;> cases h₂ : decide (n i) <;> cases h₃ : decide (i < n)
all_goals { simp_all <;> omega } all_goals { simp_all <;> omega }
@[simp] theorem getElem_shiftLeft {x : BitVec m} {n : Nat} (h : i < m) :
(x <<< n)[i] = (!decide (i < n) && getLsbD x (i - n)) := by
rw [ testBit_toNat, getElem_eq_testBit_toNat]
simp only [toNat_shiftLeft, Nat.testBit_mod_two_pow, Nat.testBit_shiftLeft, ge_iff_le]
-- This step could be a case bashing tactic.
cases h₁ : decide (i < m) <;> cases h₂ : decide (n i) <;> cases h₃ : decide (i < n)
all_goals { simp_all <;> omega }
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
@@ -1032,14 +932,6 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
exact Nat.mul_lt_mul_of_pos_right x.isLt (Nat.two_pow_pos _) exact Nat.mul_lt_mul_of_pos_right x.isLt (Nat.two_pow_pos _)
· omega · omega
@[simp] theorem getElem_shiftLeftZeroExtend {x : BitVec m} {n : Nat} (h : i < m + n) :
(shiftLeftZeroExtend x n)[i] = ((! decide (i < n)) && getLsbD x (i - n)) := by
rw [shiftLeftZeroExtend_eq, getLsbD]
simp only [getElem_eq_testBit_toNat, getLsbD_shiftLeft, getLsbD_setWidth]
cases h₁ : decide (i < n) <;> cases h₂ : decide (i - n < m + n)
<;> simp_all [h]
<;> omega
@[simp] theorem getLsbD_shiftLeftZeroExtend (x : BitVec m) (n : Nat) : @[simp] theorem getLsbD_shiftLeftZeroExtend (x : BitVec m) (n : Nat) :
getLsbD (shiftLeftZeroExtend x n) i = ((! decide (i < n)) && getLsbD x (i - n)) := by getLsbD (shiftLeftZeroExtend x n) i = ((! decide (i < n)) && getLsbD x (i - n)) := by
rw [shiftLeftZeroExtend_eq] rw [shiftLeftZeroExtend_eq]
@@ -1088,11 +980,6 @@ theorem getLsbD_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} :
(x <<< y).getLsbD i = (decide (i < w₁) && !decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by (x <<< y).getLsbD i = (decide (i < w₁) && !decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by
simp [shiftLeft_eq', getLsbD_shiftLeft] simp [shiftLeft_eq', getLsbD_shiftLeft]
@[simp]
theorem getElem_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} (h : i < w₁) :
(x <<< y)[i] = (!decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by
simp [shiftLeft_eq', getLsbD_shiftLeft]
/-! ### ushiftRight -/ /-! ### ushiftRight -/
@[simp, bv_toNat] theorem toNat_ushiftRight (x : BitVec n) (i : Nat) : @[simp, bv_toNat] theorem toNat_ushiftRight (x : BitVec n) (i : Nat) :
@@ -1174,7 +1061,7 @@ theorem sshiftRight_eq_of_msb_true {x : BitVec w} {s : Nat} (h : x.msb = true) :
· rw [Nat.shiftRight_eq_div_pow] · rw [Nat.shiftRight_eq_div_pow]
apply Nat.lt_of_le_of_lt (Nat.div_le_self _ _) (by omega) apply Nat.lt_of_le_of_lt (Nat.div_le_self _ _) (by omega)
theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) : @[simp] theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) :
getLsbD (x.sshiftRight s) i = getLsbD (x.sshiftRight s) i =
(!decide (w i) && if s + i < w then x.getLsbD (s + i) else x.msb) := by (!decide (w i) && if s + i < w then x.getLsbD (s + i) else x.msb) := by
rcases hmsb : x.msb with rfl | rfl rcases hmsb : x.msb with rfl | rfl
@@ -1195,15 +1082,6 @@ theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) :
Nat.not_lt, decide_eq_true_eq] Nat.not_lt, decide_eq_true_eq]
omega omega
theorem getElem_sshiftRight {x : BitVec w} {s i : Nat} (h : i < w) :
(x.sshiftRight s)[i] = (if s + i < w then x.getLsbD (s + i) else x.msb) := by
rcases hmsb : x.msb with rfl | rfl
· simp only [sshiftRight_eq_of_msb_false hmsb, getElem_ushiftRight, Bool.if_false_right,
Bool.iff_and_self, decide_eq_true_eq]
intros hlsb
apply BitVec.lt_of_getLsbD hlsb
· simp [sshiftRight_eq_of_msb_true hmsb]
theorem sshiftRight_xor_distrib (x y : BitVec w) (n : Nat) : theorem sshiftRight_xor_distrib (x y : BitVec w) (n : Nat) :
(x ^^^ y).sshiftRight n = (x.sshiftRight n) ^^^ (y.sshiftRight n) := by (x ^^^ y).sshiftRight n = (x.sshiftRight n) ^^^ (y.sshiftRight n) := by
ext i ext i
@@ -1241,7 +1119,7 @@ theorem sshiftRight_msb_eq_msb {n : Nat} {x : BitVec w} :
@[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
simp [getLsbD_sshiftRight] simp
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
@@ -1333,7 +1211,7 @@ theorem signExtend_eq_not_setWidth_not_of_msb_true {x : BitVec w} {v : Nat} (hms
· apply Nat.le_refl · apply Nat.le_refl
· omega · omega
theorem getLsbD_signExtend (x : BitVec w) {v i : Nat} : @[simp] 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_not_setWidth_not_of_msb_false hmsb]
@@ -1341,11 +1219,6 @@ theorem getLsbD_signExtend (x : BitVec w) {v i : Nat} :
· 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 getElem_signExtend {x : BitVec w} {v i : Nat} (h : i < v) :
(x.signExtend v)[i] = if i < w then x.getLsbD i else x.msb := by
rw [getLsbD_eq_getElem, getLsbD_signExtend]
simp [h]
/-- 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
@@ -1367,20 +1240,13 @@ theorem append_def (x : BitVec v) (y : BitVec w) :
(x ++ y).toNat = x.toNat <<< n ||| y.toNat := (x ++ y).toNat = x.toNat <<< n ||| y.toNat :=
rfl rfl
theorem getLsbD_append {x : BitVec n} {y : BitVec m} : @[simp] 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 = bif 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 [h]; simp_all · simp [h]; simp_all
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
simp only [append_def, getElem_or, getElem_shiftLeftZeroExtend, getElem_setWidth']
by_cases h' : i < m
· simp [h']
· simp [h']; simp_all
@[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 = bif n i then getMsbD y (i - n) else getMsbD x i := by
simp [append_def] simp [append_def]
@@ -1424,7 +1290,7 @@ theorem msb_append {x : BitVec w} {y : BitVec v} :
@[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 cast h (x ++ y) = cast (by omega) x ++ y := by
ext ext
simp [getLsbD_append] simp
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
@@ -1435,9 +1301,9 @@ theorem setWidth_append {x : BitVec w} {y : BitVec v} :
· have t : i < v := by omega · have t : i < v := by omega
simp [t] simp [t]
· by_cases t : i < v · by_cases t : i < v
· simp [t, getLsbD_append] · simp [t]
· have t' : i - v < k - v := by omega · have t' : i - v < k - v := by omega
simp [t, t', getLsbD_append] simp [t, t']
@[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
@@ -1465,19 +1331,19 @@ theorem setWidth_append {x : BitVec w} {y : BitVec v} :
(x₁ ++ y₁) &&& (x₂ ++ y₂) = (x₁ &&& x₂) ++ (y₁ &&& y₂) := by (x₁ ++ y₁) &&& (x₂ ++ y₂) = (x₁ &&& x₂) ++ (y₁ &&& y₂) := by
ext i ext i
simp only [getLsbD_append, cond_eq_if] simp only [getLsbD_append, cond_eq_if]
split <;> simp [getLsbD_append, *] split <;> simp [*]
@[simp] theorem or_append {x₁ x₂ : BitVec w} {y₁ y₂ : BitVec v} : @[simp] theorem or_append {x₁ x₂ : BitVec w} {y₁ y₂ : BitVec v} :
(x₁ ++ y₁) ||| (x₂ ++ y₂) = (x₁ ||| x₂) ++ (y₁ ||| y₂) := by (x₁ ++ y₁) ||| (x₂ ++ y₂) = (x₁ ||| x₂) ++ (y₁ ||| y₂) := by
ext i ext i
simp only [getLsbD_append, cond_eq_if] simp only [getLsbD_append, cond_eq_if]
split <;> simp [getLsbD_append, *] split <;> simp [*]
@[simp] theorem xor_append {x₁ x₂ : BitVec w} {y₁ y₂ : BitVec v} : @[simp] theorem xor_append {x₁ x₂ : BitVec w} {y₁ y₂ : BitVec v} :
(x₁ ++ y₁) ^^^ (x₂ ++ y₂) = (x₁ ^^^ x₂) ++ (y₁ ^^^ y₂) := by (x₁ ++ y₁) ^^^ (x₂ ++ y₂) = (x₁ ^^^ x₂) ++ (y₁ ^^^ y₂) := by
ext i ext i
simp only [getLsbD_append, cond_eq_if] simp only [getLsbD_append, cond_eq_if]
split <;> simp [getLsbD_append, *] split <;> simp [*]
theorem shiftRight_add {w : Nat} (x : BitVec w) (n m : Nat) : theorem shiftRight_add {w : Nat} (x : BitVec w) (n m : Nat) :
x >>> (n + m) = (x >>> n) >>> m:= by x >>> (n + m) = (x >>> n) >>> m:= by
@@ -1497,12 +1363,6 @@ theorem getLsbD_rev (x : BitVec w) (i : Fin w) :
congr 1 congr 1
omega omega
theorem getElem_rev {x : BitVec w} {i : Fin w}:
x[i.rev] = x.getMsbD i := by
simp [getMsbD]
congr 1
omega
theorem getMsbD_rev (x : BitVec w) (i : Fin w) : theorem getMsbD_rev (x : BitVec w) (i : Fin w) :
x.getMsbD i.rev = x.getLsbD i := by x.getMsbD i.rev = x.getLsbD i := by
simp only [ getLsbD_rev] simp only [ getLsbD_rev]
@@ -1522,7 +1382,7 @@ theorem toNat_cons' {x : BitVec w} :
(cons a x).toNat = (a.toNat <<< w) + x.toNat := by (cons a x).toNat = (a.toNat <<< w) + x.toNat := by
simp [cons, Nat.shiftLeft_eq, Nat.mul_comm _ (2^w), Nat.mul_add_lt_is_or, x.isLt] simp [cons, Nat.shiftLeft_eq, Nat.mul_comm _ (2^w), Nat.mul_add_lt_is_or, x.isLt]
theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) : @[simp] theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) :
getLsbD (cons b x) i = if i = n then b else getLsbD x i := by getLsbD (cons b x) i = if i = n then b else getLsbD x i := by
simp only [getLsbD, toNat_cons, Nat.testBit_or] simp only [getLsbD, toNat_cons, Nat.testBit_or]
rw [Nat.testBit_shiftLeft] rw [Nat.testBit_shiftLeft]
@@ -1536,20 +1396,6 @@ theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) :
have p2 : i - n 0 := by omega have p2 : i - n 0 := by omega
simp [p1, p2, Nat.testBit_bool_to_nat] simp [p1, p2, Nat.testBit_bool_to_nat]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
(cons b x)[i] = if i = n then b else getLsbD x i := by
simp only [getElem_eq_testBit_toNat, toNat_cons, Nat.testBit_or, getLsbD]
rw [Nat.testBit_shiftLeft]
rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
· have p1 : ¬(n i) := by omega
have p2 : i n := by omega
simp [p1, p2]
· simp [i_eq_n, testBit_toNat]
cases b <;> trivial
· have p1 : i n := by omega
have p2 : i - n 0 := by omega
simp [p1, p2, Nat.testBit_bool_to_nat]
@[simp] theorem msb_cons : (cons a x).msb = a := by @[simp] theorem msb_cons : (cons a x).msb = a := by
simp [cons, msb_cast, msb_append] simp [cons, msb_cast, msb_append]
@@ -1570,19 +1416,15 @@ theorem setWidth_succ (x : BitVec w) :
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.val < i := Nat.lt_of_le_of_ne (Nat.le_of_succ_le_succ j.isLt) 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 theorem eq_msb_cons_setWidth (x : BitVec (w+1)) : x = (cons x.msb (x.setWidth w)) := by
ext i ext i
simp only [getLsbD_cons] simp
split <;> rename_i h split <;> rename_i h
· simp [BitVec.msb, getMsbD, h] · simp [BitVec.msb, getMsbD, h]
· by_cases h' : i < w · by_cases h' : i < w
· simp_all · simp_all
· omega · omega
@[deprecated "Use the reverse direction of `cons_msb_setWidth`"]
theorem eq_msb_cons_setWidth (x : BitVec (w+1)) : x = (cons x.msb (x.setWidth w)) := by
simp
@[simp] theorem not_cons (x : BitVec w) (b : Bool) : ~~~(cons b x) = cons (!b) (~~~x) := by @[simp] theorem not_cons (x : BitVec w) (b : Bool) : ~~~(cons b x) = cons (!b) (~~~x) := by
simp [cons] simp [cons]
@@ -1619,27 +1461,12 @@ theorem getLsbD_concat (x : BitVec w) (b : Bool) (i : Nat) :
· simp [Nat.mod_eq_of_lt b.toNat_lt] · simp [Nat.mod_eq_of_lt b.toNat_lt]
· simp [Nat.div_eq_of_lt b.toNat_lt, Nat.testBit_add_one] · simp [Nat.div_eq_of_lt b.toNat_lt, Nat.testBit_add_one]
theorem getElem_concat (x : BitVec w) (b : Bool) (i : Nat) (h : i < w + 1) :
(concat x b)[i] = if i = 0 then b else x.getLsbD (i - 1) := by
simp only [concat, getElem_eq_testBit_toNat, getLsbD, toNat_append,
toNat_ofBool, Nat.testBit_or, Nat.shiftLeft_eq]
cases i
· simp [Nat.mod_eq_of_lt b.toNat_lt]
· simp [Nat.div_eq_of_lt b.toNat_lt, Nat.testBit_add_one]
@[simp] theorem getLsbD_concat_zero : (concat x b).getLsbD 0 = b := by @[simp] theorem getLsbD_concat_zero : (concat x b).getLsbD 0 = b := by
simp [getLsbD_concat] simp [getLsbD_concat]
@[simp] theorem getElem_concat_zero : (concat x b)[0] = b := by
simp [getElem_concat]
@[simp] theorem getLsbD_concat_succ : (concat x b).getLsbD (i + 1) = x.getLsbD i := by @[simp] theorem getLsbD_concat_succ : (concat x b).getLsbD (i + 1) = x.getLsbD i := by
simp [getLsbD_concat] simp [getLsbD_concat]
@[simp] theorem getElem_concat_succ {x : BitVec w} {i : Nat} (h : i < w) :
(concat x b)[i + 1] = x[i] := by
simp [getElem_concat, h, getLsbD_eq_getElem]
@[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; cases i using Fin.succRecOn <;> simp [*, Nat.succ_lt_succ]
@@ -1837,15 +1664,6 @@ theorem BitVec.mul_add {x y z : BitVec w} :
rw [Nat.mul_mod, Nat.mod_mod (y.toNat + z.toNat), rw [Nat.mul_mod, Nat.mod_mod (y.toNat + z.toNat),
Nat.mul_mod, Nat.mul_add] Nat.mul_mod, Nat.mul_add]
theorem mul_succ {x y : BitVec w} : x * (y + 1#w) = x * y + x := by simp [BitVec.mul_add]
theorem succ_mul {x y : BitVec w} : (x + 1#w) * y = x * y + y := by simp [BitVec.mul_comm, BitVec.mul_add]
theorem mul_two {x : BitVec w} : x * 2#w = x + x := by
have : 2#w = 1#w + 1#w := by apply BitVec.eq_of_toNat_eq; simp
simp [this, mul_succ]
theorem two_mul {x : BitVec w} : 2#w * x = x + x := by rw [BitVec.mul_comm, mul_two]
@[simp, bv_toNat] theorem toInt_mul (x y : BitVec w) : @[simp, bv_toNat] theorem toInt_mul (x y : BitVec w) :
(x * y).toInt = (x.toInt * y.toInt).bmod (2^w) := by (x * y).toInt = (x.toInt * y.toInt).bmod (2^w) := by
simp [toInt_eq_toNat_bmod] simp [toInt_eq_toNat_bmod]
@@ -1930,13 +1748,6 @@ protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x.umod y < y
(ofBoolListBE bs).getLsbD i = (decide (i < bs.length) && bs.getD (bs.length - 1 - i) false) := by (ofBoolListBE bs).getLsbD i = (decide (i < bs.length) && bs.getD (bs.length - 1 - i) false) := by
simp [getLsbD_eq_getMsbD] simp [getLsbD_eq_getMsbD]
@[simp] theorem getElem_ofBoolListBE (h : i < bs.length) :
(ofBoolListBE bs)[i] = bs[bs.length - 1 - i] := by
rw [ getLsbD_eq_getElem, getLsbD_ofBoolListBE]
simp only [h, decide_True, List.getD_eq_getElem?_getD, Bool.true_and]
rw [List.getElem?_eq_getElem (by omega)]
simp
@[simp] theorem getLsb_ofBoolListLE : (ofBoolListLE bs).getLsbD i = bs.getD i false := by @[simp] theorem getLsb_ofBoolListLE : (ofBoolListLE bs).getLsbD i = bs.getD i false := by
induction bs generalizing i <;> cases i <;> simp_all [ofBoolListLE] induction bs generalizing i <;> cases i <;> simp_all [ofBoolListLE]
@@ -2302,11 +2113,6 @@ theorem getLsbD_intMax (w : Nat) : (intMax w).getLsbD i = decide (i + 1 < w) :=
/-! ### Non-overflow theorems -/ /-! ### Non-overflow theorems -/
/-- If `x.toNat * y.toNat < 2^w`, then the multiplication `(x * y)` does not overflow. -/
theorem toNat_add_of_lt {w} {x y : BitVec w} (h : x.toNat + y.toNat < 2^w) :
(x + y).toNat = x.toNat + y.toNat := by
rw [BitVec.toNat_add, Nat.mod_eq_of_lt h]
/-- /--
If `y ≤ x`, then the subtraction `(x - y)` does not overflow. If `y ≤ x`, then the subtraction `(x - y)` does not overflow.
Thus, `(x - y).toNat = x.toNat - y.toNat` Thus, `(x - y).toNat = x.toNat - y.toNat`
@@ -2320,88 +2126,6 @@ theorem toNat_sub_of_le {x y : BitVec n} (h : y ≤ x) :
· have : 2 ^ n - y.toNat + x.toNat = 2 ^ n + (x.toNat - y.toNat) := by omega · have : 2 ^ n - y.toNat + x.toNat = 2 ^ n + (x.toNat - y.toNat) := by omega
rw [this, Nat.add_mod_left, Nat.mod_eq_of_lt (by omega)] rw [this, Nat.add_mod_left, Nat.mod_eq_of_lt (by omega)]
/--
If `y > x`, then the subtraction `(x - y)` *does* overflow, and the result is the wraparound.
Thus, `(x - y).toNat = 2^w - (y.toNat - x.toNat)`.
-/
theorem toNat_sub_of_lt {x y : BitVec w} (h : x < y) :
(x - y).toNat = 2^w - (y.toNat - x.toNat) := by
simp only [toNat_sub]
rw [Nat.mod_eq_of_lt (by bv_omega)]
bv_omega
/-- If `x.toNat * y.toNat < 2^w`, then the multiplication `(x * y)` does not overflow.
Thus, `(x * y).toNat = x.toNat * y.toNat`.
-/
theorem toNat_mul_of_lt {w} {x y : BitVec w} (h : x.toNat * y.toNat < 2^w) :
(x * y).toNat = x.toNat * y.toNat := by
rw [BitVec.toNat_mul, Nat.mod_eq_of_lt h]
/-! ### Decidable quantifiers -/
theorem forall_zero_iff {P : BitVec 0 Prop} :
( v, P v) P 0#0 := by
constructor
· intro h
apply h
· intro h v
obtain (rfl : v = 0#0) := (by ext i, h; simp at h)
apply h
theorem forall_cons_iff {P : BitVec (n + 1) Prop} :
( v : BitVec (n + 1), P v) ( (x : Bool) (v : BitVec n), P (v.cons x)) := by
constructor
· intro h _ _
apply h
· intro h v
have w : v = (v.setWidth n).cons v.msb := by simp
rw [w]
apply h
instance instDecidableForallBitVecZero (P : BitVec 0 Prop) :
[Decidable (P 0#0)], Decidable ( v, P v)
| .isTrue h => .isTrue fun v => by
obtain (rfl : v = 0#0) := (by ext i, h; cases h)
exact h
| .isFalse h => .isFalse (fun w => h (w _))
instance instDecidableForallBitVecSucc (P : BitVec (n+1) Prop) [DecidablePred P]
[Decidable ( (x : Bool) (v : BitVec n), P (v.cons x))] : Decidable ( v, P v) :=
decidable_of_iff' ( x (v : BitVec n), P (v.cons x)) forall_cons_iff
instance instDecidableExistsBitVecZero (P : BitVec 0 Prop) [Decidable (P 0#0)] :
Decidable ( v, P v) :=
decidable_of_iff (¬ v, ¬ P v) Classical.not_forall_not
instance instDecidableExistsBitVecSucc (P : BitVec (n+1) Prop) [DecidablePred P]
[Decidable ( (x : Bool) (v : BitVec n), ¬ P (v.cons x))] : Decidable ( v, P v) :=
decidable_of_iff (¬ v, ¬ P v) Classical.not_forall_not
/--
For small numerals this isn't necessary (as typeclass search can use the above two instances),
but for large numerals this provides a shortcut.
Note, however, that for large numerals the decision procedure may be very slow,
and you should use `bv_decide` if possible.
-/
instance instDecidableForallBitVec :
(n : Nat) (P : BitVec n Prop) [DecidablePred P], Decidable ( v, P v)
| 0, _, _ => inferInstance
| n + 1, _, _ =>
have := instDecidableForallBitVec n
inferInstance
/--
For small numerals this isn't necessary (as typeclass search can use the above two instances),
but for large numerals this provides a shortcut.
Note, however, that for large numerals the decision procedure may be very slow.
-/
instance instDecidableExistsBitVec :
(n : Nat) (P : BitVec n Prop) [DecidablePred P], Decidable ( v, P v)
| 0, _, _ => inferInstance
| n + 1, _, _ =>
have := instDecidableExistsBitVec n
inferInstance
/-! ### Deprecations -/ /-! ### Deprecations -/
set_option linter.missingDocs false set_option linter.missingDocs false

View File

@@ -14,7 +14,7 @@ instance coeToNat : CoeOut (Fin n) Nat :=
fun v => v.val fun v => v.val
/-- /--
From the empty type `Fin 0`, any desired result `α` can be derived. This is similar to `Empty.elim`. From the empty type `Fin 0`, any desired result `α` can be derived. This is simlar to `Empty.elim`.
-/ -/
def elim0.{u} {α : Sort u} : Fin 0 α def elim0.{u} {α : Sort u} : Fin 0 α
| _, h => absurd h (not_lt_zero _) | _, h => absurd h (not_lt_zero _)

View File

@@ -26,7 +26,7 @@ def hIterateFrom (P : Nat → Sort _) {n} (f : ∀(i : Fin n), P i.val → P (i.
decreasing_by decreasing_trivial_pre_omega decreasing_by decreasing_trivial_pre_omega
/-- /--
`hIterate` is a heterogeneous iterative operation that applies a `hIterate` is a heterogenous iterative operation that applies a
index-dependent function `f` to a value `init : P start` a total of index-dependent function `f` to a value `init : P start` a total of
`stop - start` times to produce a value of type `P stop`. `stop - start` times to produce a value of type `P stop`.
@@ -35,7 +35,7 @@ Concretely, `hIterate start stop f init` is equal to
init |> f start _ |> f (start+1) _ ... |> f (end-1) _ init |> f start _ |> f (start+1) _ ... |> f (end-1) _
``` ```
Because it is heterogeneous and must return a value of type `P stop`, Because it is heterogenous and must return a value of type `P stop`,
`hIterate` requires proof that `start ≤ stop`. `hIterate` requires proof that `start ≤ stop`.
One can prove properties of `hIterate` using the general theorem One can prove properties of `hIterate` using the general theorem
@@ -70,7 +70,7 @@ private theorem hIterateFrom_elim {P : Nat → Sort _}(Q : ∀(i : Nat), P i →
/- /-
`hIterate_elim` provides a mechanism for showing that the result of `hIterate_elim` provides a mechanism for showing that the result of
`hIterate` satisfies a property `Q stop` by showing that the states `hIterate` satisifies a property `Q stop` by showing that the states
at the intermediate indices `i : start ≤ i < stop` satisfy `Q i`. at the intermediate indices `i : start ≤ i < stop` satisfy `Q i`.
-/ -/
theorem hIterate_elim {P : Nat Sort _} (Q : (i : Nat), P i Prop) theorem hIterate_elim {P : Nat Sort _} (Q : (i : Nat), P i Prop)

View File

@@ -194,7 +194,7 @@ theorem fdiv_eq_tdiv {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = tdiv
@[simp, norm_cast] theorem ofNat_emod (m n : Nat) : ((m % n) : Int) = m % n := rfl @[simp, norm_cast] theorem ofNat_emod (m n : Nat) : ((m % n) : Int) = m % n := rfl
/-! ### mod definitions -/ /-! ### mod definitiions -/
theorem emod_add_ediv : a b : Int, a % b + b * (a / b) = a theorem emod_add_ediv : a b : Int, a % b + b * (a / b) = a
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div .. | ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..

View File

@@ -938,38 +938,6 @@ def foldrRecOn {motive : β → Sort _} : ∀ (l : List α) (op : α → β →
x (mem_cons_self x l) := x (mem_cons_self x l) :=
rfl rfl
/--
We can prove that two folds over the same list are related (by some arbitrary relation)
if we know that the initial elements are related and the folding function, for each element of the list,
preserves the relation.
-/
theorem foldl_rel {l : List α} {f g : β α β} {a b : β} (r : β β Prop)
(h : r a b) (h' : (a : α), a l (c c' : β), r c c' r (f c a) (g c' a)) :
r (l.foldl (fun acc a => f acc a) a) (l.foldl (fun acc a => g acc a) b) := by
induction l generalizing a b with
| nil => simp_all
| cons a l ih =>
simp only [foldl_cons]
apply ih
· simp_all
· exact fun a m c c' h => h' _ (by simp_all) _ _ h
/--
We can prove that two folds over the same list are related (by some arbitrary relation)
if we know that the initial elements are related and the folding function, for each element of the list,
preserves the relation.
-/
theorem foldr_rel {l : List α} {f g : α β β} {a b : β} (r : β β Prop)
(h : r a b) (h' : (a : α), a l (c c' : β), r c c' r (f a c) (g a c')) :
r (l.foldr (fun a acc => f a acc) a) (l.foldr (fun a acc => g a acc) b) := by
induction l generalizing a b with
| nil => simp_all
| cons a l ih =>
simp only [foldr_cons]
apply h'
· simp
· exact ih h fun a m c c' h => h' _ (by simp_all) _ _ h
/-! ### getLast -/ /-! ### getLast -/
theorem getLast_eq_getElem : (l : List α) (h : l []), theorem getLast_eq_getElem : (l : List α) (h : l []),
@@ -1314,16 +1282,11 @@ theorem map_eq_iff : map f l = l' ↔ ∀ i : Nat, l'[i]? = l[i]?.map f := by
theorem map_eq_foldr (f : α β) (l : List α) : map f l = foldr (fun a bs => f a :: bs) [] l := by theorem map_eq_foldr (f : α β) (l : List α) : map f l = foldr (fun a bs => f a :: bs) [] l := by
induction l <;> simp [*] induction l <;> simp [*]
@[simp] theorem map_set {f : α β} {l : List α} {i : Nat} {a : α} : @[simp] theorem set_map {f : α β} {l : List α} {n : Nat} {a : α} :
(l.set i a).map f = (l.map f).set i (f a) := by
induction l generalizing i with
| nil => simp
| cons b l ih => cases i <;> simp_all
@[deprecated "Use the reverse direction of `map_set`." (since := "2024-09-20")]
theorem set_map {f : α β} {l : List α} {n : Nat} {a : α} :
(map f l).set n (f a) = map f (l.set n a) := by (map f l).set n (f a) = map f (l.set n a) := by
simp induction l generalizing n with
| nil => simp
| cons b l ih => cases n <;> simp_all
@[simp] theorem head_map (f : α β) (l : List α) (w) : @[simp] theorem head_map (f : α β) (l : List α) (w) :
head (map f l) w = f (head l (by simpa using w)) := by head (map f l) w = f (head l (by simpa using w)) := by

View File

@@ -1,7 +1,7 @@
/- /-
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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Data.Nat.Bitwise.Basic import Init.Data.Nat.Bitwise.Basic

View File

@@ -36,7 +36,7 @@ private theorem two_mul_sub_one {n : Nat} (n_pos : n > 0) : (2*n - 1) % 2 = 1 :=
/-! ### Preliminaries -/ /-! ### Preliminaries -/
/-- /--
An induction principal that works on division by two. An induction principal that works on divison by two.
-/ -/
noncomputable def div2Induction {motive : Nat Sort u} noncomputable def div2Induction {motive : Nat Sort u}
(n : Nat) (ind : (n : Nat), (n > 0 motive (n/2)) motive n) : motive n := by (n : Nat) (ind : (n : Nat), (n > 0 motive (n/2)) motive n) : motive n := by

View File

@@ -84,7 +84,7 @@ decreasing_by apply div_rec_lemma; assumption
protected def mod : @& Nat @& Nat Nat protected def mod : @& Nat @& Nat Nat
/- /-
Nat.modCore is defined by well-founded recursion and thus irreducible. Nevertheless it is Nat.modCore is defined by well-founded recursion and thus irreducible. Nevertheless it is
desirable if trivial `Nat.mod` calculations, namely desireable if trivial `Nat.mod` calculations, namely
* `Nat.mod 0 m` for all `m` * `Nat.mod 0 m` for all `m`
* `Nat.mod n (m+n)` for concrete literals `n` * `Nat.mod n (m+n)` for concrete literals `n`
reduce definitionally. reduce definitionally.

View File

@@ -1,7 +1,7 @@
/- /-
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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Omega import Init.Omega
@@ -15,7 +15,7 @@ in particular
and its corollary and its corollary
`Nat.mod_pow_succ : x % b ^ (k + 1) = x % b ^ k + b ^ k * ((x / b ^ k) % b)`. `Nat.mod_pow_succ : x % b ^ (k + 1) = x % b ^ k + b ^ k * ((x / b ^ k) % b)`.
It contains the necessary preliminary results relating order and `*` and `/`, It contains the necesssary preliminary results relating order and `*` and `/`,
which should probably be moved to their own file. which should probably be moved to their own file.
-/ -/

View File

@@ -51,12 +51,6 @@ instance [Repr α] : Repr (id α) :=
instance [Repr α] : Repr (Id α) := instance [Repr α] : Repr (Id α) :=
inferInstanceAs (Repr α) inferInstanceAs (Repr α)
/-
This instance allows us to use `Empty` as a type parameter without causing instance synthesis to fail.
-/
instance : Repr Empty where
reprPrec := nofun
instance : Repr Bool where instance : Repr Bool where
reprPrec reprPrec
| true, _ => "true" | true, _ => "true"

View File

@@ -156,11 +156,11 @@ theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem d
theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
[Inhabited elem] (c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] : [Inhabited elem] (c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] :
c[i]! = c[i]'h := by c[i]! = c[i]'h := by
simp [getElem!_def, getElem?_def, h] simp only [getElem!_def, getElem?_def, h]
theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
[Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]! = default := by [Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]! = default := by
simp [getElem!_def, getElem?_def, h] simp only [getElem!_def, getElem?_def, h]
namespace Fin namespace Fin

View File

@@ -862,7 +862,7 @@ partial def decodeRawStrLitAux (s : String) (i : String.Pos) (num : Nat) : Strin
/-- /--
Takes the string literal lexical syntax parsed by the parser and interprets it as a string. Takes the string literal lexical syntax parsed by the parser and interprets it as a string.
This is where escape sequences are processed for example. This is where escape sequences are processed for example.
The string `s` is either a plain string literal or a raw string literal. The string `s` is is either a plain string literal or a raw string literal.
If it returns `none` then the string literal is ill-formed, which indicates a bug in the parser. If it returns `none` then the string literal is ill-formed, which indicates a bug in the parser.
The function is not required to return `none` if the string literal is ill-formed. The function is not required to return `none` if the string literal is ill-formed.

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Omega.Int import Init.Omega.Int

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Omega.IntList import Init.Omega.IntList

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Omega.LinearCombo import Init.Omega.LinearCombo

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Data.Int.DivMod import Init.Data.Int.DivMod

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Data.List.Zip import Init.Data.List.Zip

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Omega.Coeffs import Init.Omega.Coeffs

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.PropLemmas import Init.PropLemmas

View File

@@ -754,11 +754,10 @@ infer the proof of `Nonempty α`.
noncomputable def Classical.ofNonempty {α : Sort u} [Nonempty α] : α := noncomputable def Classical.ofNonempty {α : Sort u} [Nonempty α] : α :=
Classical.choice inferInstance Classical.choice inferInstance
instance {α : Sort u} {β : Sort v} [Nonempty β] : Nonempty (α β) := instance (α : Sort u) {β : Sort v} [Nonempty β] : Nonempty (α β) :=
Nonempty.intro fun _ => Classical.ofNonempty Nonempty.intro fun _ => Classical.ofNonempty
instance Pi.instNonempty {α : Sort u} {β : α Sort v} [(a : α) Nonempty (β a)] : instance (α : Sort u) {β : α Sort v} [(a : α) Nonempty (β a)] : Nonempty ((a : α) β a) :=
Nonempty ((a : α) β a) :=
Nonempty.intro fun _ => Classical.ofNonempty Nonempty.intro fun _ => Classical.ofNonempty
instance : Inhabited (Sort u) where instance : Inhabited (Sort u) where
@@ -767,8 +766,7 @@ instance : Inhabited (Sort u) where
instance (α : Sort u) {β : Sort v} [Inhabited β] : Inhabited (α β) where instance (α : Sort u) {β : Sort v} [Inhabited β] : Inhabited (α β) where
default := fun _ => default default := fun _ => default
instance Pi.instInhabited {α : Sort u} {β : α Sort v} [(a : α) Inhabited (β a)] : instance (α : Sort u) {β : α Sort v} [(a : α) Inhabited (β a)] : Inhabited ((a : α) β a) where
Inhabited ((a : α) β a) where
default := fun _ => default default := fun _ => default
deriving instance Inhabited for Bool deriving instance Inhabited for Bool
@@ -1212,7 +1210,7 @@ class HDiv (α : Type u) (β : Type v) (γ : outParam (Type w)) where
* For most types like `Nat`, `Int`, `Rat`, `Real`, `a / 0` is defined to be `0`. * For most types like `Nat`, `Int`, `Rat`, `Real`, `a / 0` is defined to be `0`.
* For `Nat`, `a / b` rounds downwards. * For `Nat`, `a / b` rounds downwards.
* For `Int`, `a / b` rounds downwards if `b` is positive or upwards if `b` is negative. * For `Int`, `a / b` rounds downwards if `b` is positive or upwards if `b` is negative.
It is implemented as `Int.ediv`, the unique function satisfying It is implemented as `Int.ediv`, the unique function satisfiying
`a % b + b * (a / b) = a` and `0 ≤ a % b < natAbs b` for `b ≠ 0`. `a % b + b * (a / b) = a` and `0 ≤ a % b < natAbs b` for `b ≠ 0`.
Other rounding conventions are available using the functions Other rounding conventions are available using the functions
`Int.fdiv` (floor rounding) and `Int.div` (truncation rounding). `Int.fdiv` (floor rounding) and `Int.div` (truncation rounding).
@@ -1366,7 +1364,7 @@ class Pow (α : Type u) (β : Type v) where
/-- `a ^ b` computes `a` to the power of `b`. See `HPow`. -/ /-- `a ^ b` computes `a` to the power of `b`. See `HPow`. -/
pow : α β α pow : α β α
/-- The homogeneous version of `Pow` where the exponent is a `Nat`. /-- The homogenous version of `Pow` where the exponent is a `Nat`.
The purpose of this class is that it provides a default `Pow` instance, The purpose of this class is that it provides a default `Pow` instance,
which can be used to specialize the exponent to `Nat` during elaboration. which can be used to specialize the exponent to `Nat` during elaboration.
@@ -2067,7 +2065,7 @@ The size of type `USize`, that is, `2^System.Platform.numBits`, which may
be either `2^32` or `2^64` depending on the platform's architecture. be either `2^32` or `2^64` depending on the platform's architecture.
Remark: we define `USize.size` using `(2^numBits - 1) + 1` to ensure the Remark: we define `USize.size` using `(2^numBits - 1) + 1` to ensure the
Lean unifier can solve constraints such as `?m + 1 = USize.size`. Recall that Lean unifier can solve contraints such as `?m + 1 = USize.size`. Recall that
`numBits` does not reduce to a numeral in the Lean kernel since it is platform `numBits` does not reduce to a numeral in the Lean kernel since it is platform
specific. Without this trick, the following definition would be rejected by the specific. Without this trick, the following definition would be rejected by the
Lean type checker. Lean type checker.
@@ -2570,9 +2568,7 @@ structure Array (α : Type u) where
/-- /--
Converts a `List α` into an `Array α`. Converts a `List α` into an `Array α`.
You can also use the synonym `List.toArray` when dot notation is convenient. At runtime, this constructor is implemented by `List.toArray` and is O(n) in the length of the
At runtime, this constructor is implemented by `List.toArrayImpl` and is O(n) in the length of the
list. list.
-/ -/
mk :: mk ::
@@ -2586,9 +2582,6 @@ structure Array (α : Type u) where
attribute [extern "lean_array_to_list"] Array.toList attribute [extern "lean_array_to_list"] Array.toList
attribute [extern "lean_array_mk"] Array.mk attribute [extern "lean_array_mk"] Array.mk
@[inherit_doc Array.mk, match_pattern]
abbrev List.toArray (xs : List α) : Array α := .mk xs
/-- Construct a new empty array with initial capacity `c`. -/ /-- Construct a new empty array with initial capacity `c`. -/
@[extern "lean_mk_empty_array_with_capacity"] @[extern "lean_mk_empty_array_with_capacity"]
def Array.mkEmpty {α : Type u} (c : @& Nat) : Array α where def Array.mkEmpty {α : Type u} (c : @& Nat) : Array α where
@@ -2716,10 +2709,7 @@ def Array.extract (as : Array α) (start stop : Nat) : Array α :=
let sz' := Nat.sub (min stop as.size) start let sz' := Nat.sub (min stop as.size) start
loop sz' start (mkEmpty sz') loop sz' start (mkEmpty sz')
/-- /-- Auxiliary definition for `List.toArray`. -/
Auxiliary definition for `List.toArray`.
`List.toArrayAux as r = r ++ as.toArray`
-/
@[inline_if_reduce] @[inline_if_reduce]
def List.toArrayAux : List α Array α Array α def List.toArrayAux : List α Array α Array α
| nil, r => r | nil, r => r
@@ -2735,7 +2725,7 @@ def List.redLength : List α → Nat
-- This function is exported to C, where it is called by `Array.mk` -- This function is exported to C, where it is called by `Array.mk`
-- (the constructor) to implement this functionality. -- (the constructor) to implement this functionality.
@[inline, match_pattern, pp_nodot, export lean_list_to_array] @[inline, match_pattern, pp_nodot, export lean_list_to_array]
def List.toArrayImpl (as : List α) : Array α := def List.toArray (as : List α) : Array α :=
as.toArrayAux (Array.mkEmpty as.redLength) as.toArrayAux (Array.mkEmpty as.redLength)
/-- The typeclass which supplies the `>>=` "bind" function. See `Monad`. -/ /-- The typeclass which supplies the `>>=` "bind" function. See `Monad`. -/

View File

@@ -456,7 +456,7 @@ syntax (name := change) "change " term (location)? : tactic
/-- /--
* `change a with b` will change occurrences of `a` to `b` in the goal, * `change a with b` will change occurrences of `a` to `b` in the goal,
assuming `a` and `b` are definitionally equal. assuming `a` and `b` are are definitionally equal.
* `change a with b at h` similarly changes `a` to `b` in the type of hypothesis `h`. * `change a with b at h` similarly changes `a` to `b` in the type of hypothesis `h`.
-/ -/
syntax (name := changeWith) "change " term " with " term (location)? : tactic syntax (name := changeWith) "change " term " with " term (location)? : tactic
@@ -1589,7 +1589,7 @@ macro "get_elem_tactic" : tactic =>
There is a proof embedded in the right-hand-side, and we want it to be just `hi`. There is a proof embedded in the right-hand-side, and we want it to be just `hi`.
If `omega` is used to "fill" this proof, we will have a more complex proof term that If `omega` is used to "fill" this proof, we will have a more complex proof term that
cannot be inferred by unification. cannot be inferred by unification.
We hardcoded `assumption` here to ensure users cannot accidentally break this IF We hardcoded `assumption` here to ensure users cannot accidentaly break this IF
they add new `macro_rules` for `get_elem_tactic_trivial`. they add new `macro_rules` for `get_elem_tactic_trivial`.
TODO: Implement priorities for `macro_rules`. TODO: Implement priorities for `macro_rules`.
@@ -1599,7 +1599,7 @@ macro "get_elem_tactic" : tactic =>
| get_elem_tactic_trivial | get_elem_tactic_trivial
| fail "failed to prove index is valid, possible solutions: | fail "failed to prove index is valid, possible solutions:
- Use `have`-expressions to prove the index is valid - Use `have`-expressions to prove the index is valid
- Use `a[i]!` notation instead, runtime check is performed, and 'Panic' error message is produced if index is not valid - Use `a[i]!` notation instead, runtime check is perfomed, and 'Panic' error message is produced if index is not valid
- Use `a[i]?` notation instead, result is an `Option` type - Use `a[i]?` notation instead, result is an `Option` type
- Use `a[i]'h` notation instead, where `h` is a proof that index is valid" - Use `a[i]'h` notation instead, where `h` is a proof that index is valid"
) )

View File

@@ -20,7 +20,7 @@ macro "simp_wf" : tactic =>
/-- /--
This tactic is used internally by lean before presenting the proof obligations from a well-founded This tactic is used internally by lean before presenting the proof obligations from a well-founded
definition to the user via `decreasing_by`. It is not necessary to use this tactic manually. definition to the user via `decreasing_by`. It is not necessary to use this tactic manuall.
-/ -/
macro "clean_wf" : tactic => macro "clean_wf" : tactic =>
`(tactic| simp `(tactic| simp

View File

@@ -103,7 +103,7 @@ private def mkFresh : M VarId := do
/-- /--
Helper function for applying `S`. We only introduce a `reset` if we managed Helper function for applying `S`. We only introduce a `reset` if we managed
to replace a `ctor` with `reuse` in `b`. to replace a `ctor` withe `reuse` in `b`.
-/ -/
private def tryS (x : VarId) (c : CtorInfo) (b : FnBody) : M FnBody := do private def tryS (x : VarId) (c : CtorInfo) (b : FnBody) : M FnBody := do
let w mkFresh let w mkFresh

View File

@@ -242,7 +242,7 @@ structure ExtendState where
/-- /--
A map from join point `FVarId`s to a respective map from free variables A map from join point `FVarId`s to a respective map from free variables
to `Param`s. The free variables in this map are the once that the context to `Param`s. The free variables in this map are the once that the context
of said join point will be extended by passing in the respective parameter. of said join point will be extended by by passing in the respective parameter.
-/ -/
fvarMap : Std.HashMap FVarId (Std.HashMap FVarId Param) := {} fvarMap : Std.HashMap FVarId (Std.HashMap FVarId Param) := {}

View File

@@ -35,7 +35,7 @@ def checkIsDefinition (env : Environment) (n : Name) : Except String Unit :=
match env.find? n with match env.find? n with
| (some (ConstantInfo.defnInfo _)) => Except.ok () | (some (ConstantInfo.defnInfo _)) => Except.ok ()
| (some (ConstantInfo.opaqueInfo _)) => Except.ok () | (some (ConstantInfo.opaqueInfo _)) => Except.ok ()
| none => Except.error s!"unknown declaration '{n}'" | none => Except.error s!"unknow declaration '{n}'"
| _ => Except.error s!"declaration is not a definition '{n}'" | _ => Except.error s!"declaration is not a definition '{n}'"
/-- /--

View File

@@ -195,7 +195,7 @@ def insert' (m : HashMap α β) (a : α) (b : β) : HashMap α β × Bool :=
/-- /--
Similar to `insert`, but returns `some old` if the map already had an entry `α → old`. Similar to `insert`, but returns `some old` if the map already had an entry `α → old`.
If the result is `some old`, the resulting map is equal to `m`. -/ If the result is `some old`, the the resulting map is equal to `m`. -/
def insertIfNew (m : HashMap α β) (a : α) (b : β) : HashMap α β × Option β := def insertIfNew (m : HashMap α β) (a : α) (b : β) : HashMap α β × Option β :=
match m with match m with
| m, hw => | m, hw =>

View File

@@ -28,12 +28,6 @@ instance : ToJson Json := ⟨id⟩
instance : FromJson JsonNumber := Json.getNum? instance : FromJson JsonNumber := Json.getNum?
instance : ToJson JsonNumber := Json.num instance : ToJson JsonNumber := Json.num
instance : FromJson Empty where
fromJson? j := throw (s!"type Empty has no constructor to match JSON value '{j}'. \
This occurs when deserializing a value for type Empty, \
e.g. at type Option Empty with code for the 'some' constructor.")
instance : ToJson Empty := nofun
-- looks like id, but there are coercions happening -- looks like id, but there are coercions happening
instance : FromJson Bool := Json.getBool? instance : FromJson Bool := Json.getBool?
instance : ToJson Bool := fun b => b instance : ToJson Bool := fun b => b

View File

@@ -266,7 +266,7 @@ instance [FromJson α] : FromJson (Notification α) where
let params := params? let params := params?
let param : α fromJson? (toJson params) let param : α fromJson? (toJson params)
pure $ method, param pure $ method, param
else throw "not a notification" else throw "not a notfication"
end Lean.JsonRpc end Lean.JsonRpc

View File

@@ -36,7 +36,7 @@ instance : FromJson Trace := ⟨fun j =>
| Except.ok "off" => return Trace.off | Except.ok "off" => return Trace.off
| Except.ok "messages" => return Trace.messages | Except.ok "messages" => return Trace.messages
| Except.ok "verbose" => return Trace.verbose | Except.ok "verbose" => return Trace.verbose
| _ => throw "unknown trace" | _ => throw "uknown trace"
instance Trace.hasToJson : ToJson Trace := instance Trace.hasToJson : ToJson Trace :=
fun fun

View File

@@ -239,7 +239,7 @@ structure InductiveVal extends ConstantVal where
all : List Name all : List Name
/-- List of the names of the constructors for this inductive datatype. -/ /-- List of the names of the constructors for this inductive datatype. -/
ctors : List Name ctors : List Name
/-- Number of auxiliary data types produced from nested occurrences. /-- Number of auxillary data types produced from nested occurrences.
An inductive definition `T` is nested when there is a constructor with an argument `x : F T`, An inductive definition `T` is nested when there is a constructor with an argument `x : F T`,
where `F : Type → Type` is some suitably behaved (ie strictly positive) function (Eg `Array T`, `List T`, `T × T`, ...). -/ where `F : Type → Type` is some suitably behaved (ie strictly positive) function (Eg `Array T`, `List T`, `T × T`, ...). -/
numNested : Nat numNested : Nat

View File

@@ -24,7 +24,7 @@ def elabAuxDef : CommandElab
let id := `_aux ++ ( getMainModule) ++ `_ ++ id let id := `_aux ++ ( getMainModule) ++ `_ ++ id
let id := String.intercalate "_" <| id.components.map (·.toString (escape := false)) let id := String.intercalate "_" <| id.components.map (·.toString (escape := false))
let ns getCurrNamespace let ns getCurrNamespace
-- make sure we only add a single component so that scoped works -- make sure we only add a single component so that scoped workes
let id mkAuxName (ns.mkStr id) 1 let id mkAuxName (ns.mkStr id) 1
let id := id.replacePrefix ns Name.anonymous -- TODO: replace with def _root_.id let id := id.replacePrefix ns Name.anonymous -- TODO: replace with def _root_.id
elabCommand <| elabCommand <|

View File

@@ -170,9 +170,8 @@ private def toBinderViews (stx : Syntax) : TermElabM (Array BinderView) := do
else else
throwUnsupportedSyntax throwUnsupportedSyntax
private def registerFailedToInferBinderTypeInfo (type : Expr) (ref : Syntax) : TermElabM Unit := do private def registerFailedToInferBinderTypeInfo (type : Expr) (ref : Syntax) : TermElabM Unit :=
registerCustomErrorIfMVar type ref "failed to infer binder type" registerCustomErrorIfMVar type ref "failed to infer binder type"
registerLevelMVarErrorExprInfo type ref m!"failed to infer universe levels in binder type"
def addLocalVarInfo (stx : Syntax) (fvar : Expr) : TermElabM Unit := def addLocalVarInfo (stx : Syntax) (fvar : Expr) : TermElabM Unit :=
addTermInfo' (isBinder := true) stx fvar addTermInfo' (isBinder := true) stx fvar
@@ -640,7 +639,7 @@ open Lean.Elab.Term.Quotation in
| _ => throwUnsupportedSyntax | _ => throwUnsupportedSyntax
/-- If `useLetExpr` is true, then a kernel let-expression `let x : type := val; body` is created. /-- If `useLetExpr` is true, then a kernel let-expression `let x : type := val; body` is created.
Otherwise, we create a term of the form `letFun val (fun (x : type) => body)` Otherwise, we create a term of the form `(fun (x : type) => body) val`
The default elaboration order is `binders`, `typeStx`, `valStx`, and `body`. The default elaboration order is `binders`, `typeStx`, `valStx`, and `body`.
If `elabBodyFirst == true`, then we use the order `binders`, `typeStx`, `body`, and `valStx`. -/ If `elabBodyFirst == true`, then we use the order `binders`, `typeStx`, `body`, and `valStx`. -/
@@ -651,7 +650,7 @@ def elabLetDeclAux (id : Syntax) (binders : Array Syntax) (typeStx : Syntax) (va
/- /-
We use `withSynthesize` to ensure that any postponed elaboration problem We use `withSynthesize` to ensure that any postponed elaboration problem
and nested tactics in `type` are resolved before elaborating `val`. and nested tactics in `type` are resolved before elaborating `val`.
Resolved: we want to avoid synthetic opaque metavariables in `type`. Resolved: we want to avoid synthethic opaque metavariables in `type`.
Recall that this kind of metavariable is non-assignable, and `isDefEq` Recall that this kind of metavariable is non-assignable, and `isDefEq`
may waste a lot of time unfolding declarations before failing. may waste a lot of time unfolding declarations before failing.
See issue #4051 for an example. See issue #4051 for an example.
@@ -671,9 +670,7 @@ def elabLetDeclAux (id : Syntax) (binders : Array Syntax) (typeStx : Syntax) (va
Recall that TC resolution does **not** produce synthetic opaque metavariables. Recall that TC resolution does **not** produce synthetic opaque metavariables.
-/ -/
let type withSynthesize (postpone := .partial) <| elabType typeStx let type withSynthesize (postpone := .partial) <| elabType typeStx
let letMsg := if useLetExpr then "let" else "have" registerCustomErrorIfMVar type typeStx "failed to infer 'let' declaration type"
registerCustomErrorIfMVar type typeStx m!"failed to infer '{letMsg}' declaration type"
registerLevelMVarErrorExprInfo type typeStx m!"failed to infer universe levels in '{letMsg}' declaration type"
if elabBodyFirst then if elabBodyFirst then
let type mkForallFVars fvars type let type mkForallFVars fvars type
let val mkFreshExprMVar type let val mkFreshExprMVar type

View File

@@ -381,7 +381,7 @@ unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax): CommandElabM Uni
-- Evaluate using term using `MetaEval` class. -- Evaluate using term using `MetaEval` class.
let elabMetaEval : CommandElabM Unit := do let elabMetaEval : CommandElabM Unit := do
-- Generate an action without executing it. We use `withoutModifyingEnv` to ensure -- Generate an action without executing it. We use `withoutModifyingEnv` to ensure
-- we don't pollute the environment with auxliary declarations. -- we don't polute the environment with auxliary declarations.
-- We have special support for `CommandElabM` to ensure `#eval` can be used to execute commands -- We have special support for `CommandElabM` to ensure `#eval` can be used to execute commands
-- that modify `CommandElabM` state not just the `Environment`. -- that modify `CommandElabM` state not just the `Environment`.
let act : Sum (CommandElabM Unit) (Environment Options IO (String × Except IO.Error Environment)) let act : Sum (CommandElabM Unit) (Environment Options IO (String × Except IO.Error Environment))

View File

@@ -532,7 +532,8 @@ def elabCommandTopLevel (stx : Syntax) : CommandElabM Unit := withRef stx do pro
-- We can assume that the root command snapshot is not involved in parallelism yet, so this -- We can assume that the root command snapshot is not involved in parallelism yet, so this
-- should be true iff the command supports incrementality -- should be true iff the command supports incrementality
if ( IO.hasFinished snap.new.result) then if ( IO.hasFinished snap.new.result) then
liftCoreM <| Language.ToSnapshotTree.toSnapshotTree snap.new.result.get |>.trace trace[Elab.snapshotTree]
(Language.ToSnapshotTree.toSnapshotTree snap.new.result.get |>.format)
modify fun st => { st with modify fun st => { st with
messages := initMsgs ++ msgs messages := initMsgs ++ msgs
infoState := { st.infoState with trees := initInfoTrees ++ st.infoState.trees } infoState := { st.infoState with trees := initInfoTrees ++ st.infoState.trees }

View File

@@ -120,7 +120,7 @@ section Methods
variable [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLog m] [MonadInfoTree m] [MonadLiftT IO m] variable [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLog m] [MonadInfoTree m] [MonadLiftT IO m]
/-- Elaborate declaration modifiers (i.e., attributes, `partial`, `private`, `protected`, `unsafe`, `noncomputable`, doc string)-/ /-- Elaborate declaration modifiers (i.e., attributes, `partial`, `private`, `proctected`, `unsafe`, `noncomputable`, doc string)-/
def elabModifiers (stx : Syntax) : m Modifiers := do def elabModifiers (stx : Syntax) : m Modifiers := do
let docCommentStx := stx[0] let docCommentStx := stx[0]
let attrsStx := stx[1] let attrsStx := stx[1]

View File

@@ -61,17 +61,16 @@ def expandDeclSig (stx : Syntax) : Syntax × Syntax :=
(binders, typeSpec[1]) (binders, typeSpec[1])
/-- /--
Sort the given list of `usedParams` using the following order: Sort the given list of `usedParams` using the following order:
- If it is an explicit level in `allUserParams`, then use user-given order. - If it is an explicit level `allUserParams`, then use user given order.
- All other levels come in lexicographic order after these. - Otherwise, use lexicographical.
Remark: `scopeParams` are the universe params introduced using the `universe` command. `allUserParams` contains Remark: `scopeParams` are the universe params introduced using the `universe` command. `allUserParams` contains
the universe params introduced using the `universe` command *and* the `.{...}` notation. the universe params introduced using the `universe` command *and* the `.{...}` notation.
Remark: this function return an exception if there is an `u` not in `usedParams`, that is in `allUserParams` but not in `scopeParams`. Remark: this function return an exception if there is an `u` not in `usedParams`, that is in `allUserParams` but not in `scopeParams`.
Remark: `scopeParams` and `allUserParams` are in reverse declaration order. That is, the head is the last declared parameter. Remark: `explicitParams` are in reverse declaration order. That is, the head is the last declared parameter. -/
-/
def sortDeclLevelParams (scopeParams : List Name) (allUserParams : List Name) (usedParams : Array Name) : Except String (List Name) := def sortDeclLevelParams (scopeParams : List Name) (allUserParams : List Name) (usedParams : Array Name) : Except String (List Name) :=
match allUserParams.find? fun u => !usedParams.contains u && !scopeParams.elem u with match allUserParams.find? fun u => !usedParams.contains u && !scopeParams.elem u with
| some u => throw s!"unused universe parameter '{u}'" | some u => throw s!"unused universe parameter '{u}'"

View File

@@ -59,17 +59,15 @@ where
let mut ctorArgs := #[] let mut ctorArgs := #[]
let mut rhs : Term := Syntax.mkStrLit (toString ctorInfo.name) let mut rhs : Term := Syntax.mkStrLit (toString ctorInfo.name)
rhs `(Format.text $rhs) rhs `(Format.text $rhs)
for i in [:xs.size] do -- add `_` for inductive parameters, they are inaccessible
-- Note: some inductive parameters are explicit if they were promoted from indices, for _ in [:indVal.numParams] do
-- so we process all constructor arguments in the same loop. ctorArgs := ctorArgs.push ( `(_))
let x := xs[i]! for i in [:ctorInfo.numFields] do
let a mkIdent <$> if i < indVal.numParams then pure header.argNames[i]! else mkFreshUserName `a let x := xs[indVal.numParams + i]!
if i < indVal.numParams then let a := mkIdent ( mkFreshUserName `a)
-- add `_` for inductive parameters, they are inaccessible ctorArgs := ctorArgs.push a
ctorArgs := ctorArgs.push ( `(_)) let localDecl x.fvarId!.getDecl
else if localDecl.binderInfo.isExplicit then
ctorArgs := ctorArgs.push a
if ( x.fvarId!.getBinderInfo).isExplicit then
if ( inferType x).isAppOf indVal.name then if ( inferType x).isAppOf indVal.name then
rhs `($rhs ++ Format.line ++ $(mkIdent auxFunName):ident $a:ident max_prec) rhs `($rhs ++ Format.line ++ $(mkIdent auxFunName):ident $a:ident max_prec)
else if ( isType x <||> isProof x) then else if ( isType x <||> isProof x) then

View File

@@ -18,7 +18,7 @@ private def getMonadForIn (expectedType? : Option Expr) : TermElabM Expr := do
| some expectedType => | some expectedType =>
match ( isTypeApp? expectedType) with match ( isTypeApp? expectedType) with
| some (m, _) => return m | some (m, _) => return m
| none => throwError "invalid 'for_in%' notation, expected type is not of the form `M α`{indentExpr expectedType}" | none => throwError "invalid 'for_in%' notation, expected type is not of of the form `M α`{indentExpr expectedType}"
private def throwForInFailure (forInInstance : Expr) : TermElabM Expr := private def throwForInFailure (forInInstance : Expr) : TermElabM Expr :=
throwError "failed to synthesize instance for 'for_in%' notation{indentExpr forInInstance}" throwError "failed to synthesize instance for 'for_in%' notation{indentExpr forInInstance}"
@@ -375,7 +375,7 @@ private def hasHeterogeneousDefaultInstances (f : Expr) (maxType : Expr) (lhs :
return false return false
/-- /--
Return `true` if polymorphic function `f` has a homogeneous instance of `maxType`. Return `true` if polymorphic function `f` has a homogenous instance of `maxType`.
The coercions to `maxType` only makes sense if such instance exists. The coercions to `maxType` only makes sense if such instance exists.
For example, suppose `maxType` is `Int`, and `f` is `HPow.hPow`. Then, For example, suppose `maxType` is `Int`, and `f` is `HPow.hPow`. Then,
@@ -421,9 +421,9 @@ mutual
| .binop ref kind f lhs rhs => | .binop ref kind f lhs rhs =>
/- /-
We only keep applying coercions to `maxType` if `f` is predicate or We only keep applying coercions to `maxType` if `f` is predicate or
`f` has a homogeneous instance with `maxType`. See `hasHomogeneousInstance` for additional details. `f` has a homogenous instance with `maxType`. See `hasHomogeneousInstance` for additional details.
Remark: We assume `binrel%` elaborator is only used with homogeneous predicates. Remark: We assume `binrel%` elaborator is only used with homogenous predicates.
-/ -/
if ( pure isPred <||> hasHomogeneousInstance f maxType) then if ( pure isPred <||> hasHomogeneousInstance f maxType) then
return .binop ref kind f ( go lhs f true false) ( go rhs f false false) return .binop ref kind f ( go lhs f true false) ( go rhs f false false)

View File

@@ -30,7 +30,7 @@ private def mkUserNameFor (e : Expr) : TermElabM Name := do
/-- /--
Remark: if the discriminat is `Syntax.missing`, we abort the elaboration of the `match`-expression. Remark: if the discriminat is `Systax.missing`, we abort the elaboration of the `match`-expression.
This can happen due to error recovery. Example This can happen due to error recovery. Example
``` ```
example : (p p) → p := fun h => match example : (p p) → p := fun h => match
@@ -795,7 +795,7 @@ private def elabMatchAltView (discrs : Array Discr) (alt : MatchAltView) (matchT
let rhs elabTermEnsuringType alt.rhs matchType' let rhs elabTermEnsuringType alt.rhs matchType'
-- We use all approximations to ensure the auxiliary type is defeq to the original one. -- We use all approximations to ensure the auxiliary type is defeq to the original one.
unless ( fullApproxDefEq <| isDefEq matchType' matchType) do unless ( fullApproxDefEq <| isDefEq matchType' matchType) do
throwError "type mismatch, alternative {← mkHasTypeButIsExpectedMsg matchType' matchType}" throwError "type mistmatch, alternative {← mkHasTypeButIsExpectedMsg matchType' matchType}"
let xs := altLHS.fvarDecls.toArray.map LocalDecl.toExpr ++ eqs let xs := altLHS.fvarDecls.toArray.map LocalDecl.toExpr ++ eqs
let rhs if xs.isEmpty then pure <| mkSimpleThunk rhs else mkLambdaFVars xs rhs let rhs if xs.isEmpty then pure <| mkSimpleThunk rhs else mkLambdaFVars xs rhs
trace[Elab.match] "rhs: {rhs}" trace[Elab.match] "rhs: {rhs}"

View File

@@ -98,7 +98,7 @@ private def isMultiConstant? (views : Array DefView) : Option (List Name) :=
else else
none none
private def getPendingMVarErrorMessage (views : Array DefView) : String := private def getPendindMVarErrorMessage (views : Array DefView) : String :=
match isMultiConstant? views with match isMultiConstant? views with
| some ids => | some ids =>
let idsStr := ", ".intercalate <| ids.map fun id => s!"`{id}`" let idsStr := ", ".intercalate <| ids.map fun id => s!"`{id}`"
@@ -196,7 +196,7 @@ private def elabHeaders (views : Array DefView)
if view.type?.isSome then if view.type?.isSome then
let pendingMVarIds getMVars type let pendingMVarIds getMVars type
discard <| logUnassignedUsingErrorInfos pendingMVarIds <| discard <| logUnassignedUsingErrorInfos pendingMVarIds <|
getPendingMVarErrorMessage views getPendindMVarErrorMessage views
let newHeader : DefViewElabHeaderData := { let newHeader : DefViewElabHeaderData := {
declName, shortDeclName, type, levelNames, binderIds declName, shortDeclName, type, levelNames, binderIds
numParams := xs.size numParams := xs.size
@@ -947,6 +947,45 @@ private def levelMVarToParamHeaders (views : Array DefView) (headers : Array Def
let newHeaders (process).run' 1 let newHeaders (process).run' 1
newHeaders.mapM fun header => return { header with type := ( instantiateMVars header.type) } newHeaders.mapM fun header => return { header with type := ( instantiateMVars header.type) }
partial def checkForHiddenUnivLevels (allUserLevelNames : List Name) (preDefs : Array PreDefinition) : TermElabM Unit :=
unless ( MonadLog.hasErrors) do
-- We do not report this kind of error if the declaration already contains errors
let mut sTypes : CollectLevelParams.State := {}
let mut sValues : CollectLevelParams.State := {}
for preDef in preDefs do
sTypes := collectLevelParams sTypes preDef.type
sValues := collectLevelParams sValues preDef.value
if sValues.params.all fun u => sTypes.params.contains u || allUserLevelNames.contains u then
-- If all universe level occurring in values also occur in types or explicitly provided universes, then everything is fine
-- and we just return
return ()
let checkPreDef (preDef : PreDefinition) : TermElabM Unit :=
-- Otherwise, we try to produce an error message containing the expression with the offending universe
let rec visitLevel (u : Level) : ReaderT Expr TermElabM Unit := do
match u with
| .succ u => visitLevel u
| .imax u v | .max u v => visitLevel u; visitLevel v
| .param n =>
unless sTypes.visitedLevel.contains u || allUserLevelNames.contains n do
let parent withOptions (fun o => pp.universes.set o true) do addMessageContext m!"{indentExpr (← read)}"
let body withOptions (fun o => pp.letVarTypes.setIfNotSet (pp.funBinderTypes.setIfNotSet o true) true) do addMessageContext m!"{indentExpr preDef.value}"
throwError "invalid occurrence of universe level '{u}' at '{preDef.declName}', it does not occur at the declaration type, nor it is explicit universe level provided by the user, occurring at expression{parent}\nat declaration body{body}"
| _ => pure ()
let rec visit (e : Expr) : ReaderT Expr (MonadCacheT ExprStructEq Unit TermElabM) Unit := do
checkCache { val := e : ExprStructEq } fun _ => do
match e with
| .forallE n d b c | .lam n d b c => visit d e; withLocalDecl n c d fun x => visit (b.instantiate1 x) e
| .letE n t v b _ => visit t e; visit v e; withLetDecl n t v fun x => visit (b.instantiate1 x) e
| .app .. => e.withApp fun f args => do visit f e; args.forM fun arg => visit arg e
| .mdata _ b => visit b e
| .proj _ _ b => visit b e
| .sort u => visitLevel u ( read)
| .const _ us => us.forM (visitLevel · ( read))
| _ => pure ()
visit preDef.value preDef.value |>.run {}
for preDef in preDefs do
checkPreDef preDef
def elabMutualDef (vars : Array Expr) (sc : Command.Scope) (views : Array DefView) : TermElabM Unit := def elabMutualDef (vars : Array Expr) (sc : Command.Scope) (views : Array DefView) : TermElabM Unit :=
if isExample views then if isExample views then
withoutModifyingEnv do withoutModifyingEnv do
@@ -982,12 +1021,13 @@ where
let preDefs MutualClosure.main vars headers funFVars values letRecsToLift let preDefs MutualClosure.main vars headers funFVars values letRecsToLift
for preDef in preDefs do for preDef in preDefs do
trace[Elab.definition] "{preDef.declName} : {preDef.type} :=\n{preDef.value}" trace[Elab.definition] "{preDef.declName} : {preDef.type} :=\n{preDef.value}"
let preDefs withLevelNames allUserLevelNames <| levelMVarToParamTypesPreDecls preDefs let preDefs withLevelNames allUserLevelNames <| levelMVarToParamPreDecls preDefs
let preDefs instantiateMVarsAtPreDecls preDefs let preDefs instantiateMVarsAtPreDecls preDefs
let preDefs shareCommonPreDefs preDefs let preDefs shareCommonPreDefs preDefs
let preDefs fixLevelParams preDefs scopeLevelNames allUserLevelNames let preDefs fixLevelParams preDefs scopeLevelNames allUserLevelNames
for preDef in preDefs do for preDef in preDefs do
trace[Elab.definition] "after eraseAuxDiscr, {preDef.declName} : {preDef.type} :=\n{preDef.value}" trace[Elab.definition] "after eraseAuxDiscr, {preDef.declName} : {preDef.type} :=\n{preDef.value}"
checkForHiddenUnivLevels allUserLevelNames preDefs
addPreDefinitions preDefs addPreDefinitions preDefs
processDeriving headers processDeriving headers
for view in views, header in headers do for view in views, header in headers do

View File

@@ -156,11 +156,9 @@ private def processVar (idStx : Syntax) : M Syntax := do
modify fun s => { s with vars := s.vars.push idStx, found := s.found.insert id } modify fun s => { s with vars := s.vars.push idStx, found := s.found.insert id }
return idStx return idStx
private def samePatternsVariables (startingAt : Nat) (s₁ s₂ : State) : Bool := Id.run do private def samePatternsVariables (startingAt : Nat) (s₁ s₂ : State) : Bool :=
if h : s₁.vars.size = s₂.vars.size then if h : s₁.vars.size = s₂.vars.size then
for h₂ : i in [startingAt:s.vars.size] do Array.isEqvAux s₁.vars s.vars h (.==.) startingAt
if s₁.vars[i] != s₂.vars[i]'(by obtain _, y := h₂; simp_all) then return false
true
else else
false false

View File

@@ -39,26 +39,14 @@ structure PreDefinition where
def PreDefinition.filterAttrs (preDef : PreDefinition) (p : Attribute Bool) : PreDefinition := def PreDefinition.filterAttrs (preDef : PreDefinition) (p : Attribute Bool) : PreDefinition :=
{ preDef with modifiers := preDef.modifiers.filterAttrs p } { preDef with modifiers := preDef.modifiers.filterAttrs p }
/--
Applies `Lean.instantiateMVars` to the types of values of each predefinition.
-/
def instantiateMVarsAtPreDecls (preDefs : Array PreDefinition) : TermElabM (Array PreDefinition) := def instantiateMVarsAtPreDecls (preDefs : Array PreDefinition) : TermElabM (Array PreDefinition) :=
preDefs.mapM fun preDef => do preDefs.mapM fun preDef => do
pure { preDef with type := ( instantiateMVars preDef.type), value := ( instantiateMVars preDef.value) } pure { preDef with type := ( instantiateMVars preDef.type), value := ( instantiateMVars preDef.value) }
/-- def levelMVarToParamPreDecls (preDefs : Array PreDefinition) : TermElabM (Array PreDefinition) :=
Applies `Lean.Elab.Term.levelMVarToParam` to the types of each predefinition.
-/
def levelMVarToParamTypesPreDecls (preDefs : Array PreDefinition) : TermElabM (Array PreDefinition) :=
preDefs.mapM fun preDef => do preDefs.mapM fun preDef => do
pure { preDef with type := ( levelMVarToParam preDef.type) } pure { preDef with type := ( levelMVarToParam preDef.type), value := ( levelMVarToParam preDef.value) }
/--
Collects all the level parameters in sorted order from the types and values of each predefinition.
Throws an "unused universe parameter" error if there is an unused `.{...}` parameter.
See `Lean.collectLevelParams`.
-/
private def getLevelParamsPreDecls (preDefs : Array PreDefinition) (scopeLevelNames allUserLevelNames : List Name) : TermElabM (List Name) := do private def getLevelParamsPreDecls (preDefs : Array PreDefinition) (scopeLevelNames allUserLevelNames : List Name) : TermElabM (List Name) := do
let mut s : CollectLevelParams.State := {} let mut s : CollectLevelParams.State := {}
for preDef in preDefs do for preDef in preDefs do

View File

@@ -126,7 +126,7 @@ def simpEqnType (eqnType : Expr) : MetaM Expr := do
for y in ys.reverse do for y in ys.reverse do
trace[Elab.definition] ">> simpEqnType: {← inferType y}, {type}" trace[Elab.definition] ">> simpEqnType: {← inferType y}, {type}"
if proofVars.contains y.fvarId! then if proofVars.contains y.fvarId! then
let some (_, Expr.fvar fvarId, rhs) matchEq? ( inferType y) | throwError "unexpected hypothesis in alternative{indentExpr eqnType}" let some (_, Expr.fvar fvarId, rhs) matchEq? ( inferType y) | throwError "unexpected hypothesis in altenative{indentExpr eqnType}"
eliminated := eliminated.insert fvarId eliminated := eliminated.insert fvarId
type := type.replaceFVarId fvarId rhs type := type.replaceFVarId fvarId rhs
else if eliminated.contains y.fvarId! then else if eliminated.contains y.fvarId! then

View File

@@ -53,64 +53,6 @@ private def getMVarsAtPreDef (preDef : PreDefinition) : MetaM (Array MVarId) :=
let (_, s) (collectMVarsAtPreDef preDef).run {} let (_, s) (collectMVarsAtPreDef preDef).run {}
pure s.result pure s.result
/--
Set any lingering level mvars to `.zero`, for error recovery.
-/
private def setLevelMVarsAtPreDef (preDef : PreDefinition) : PreDefinition :=
if preDef.value.hasLevelMVar then
let value' :=
preDef.value.replaceLevel fun l =>
match l with
| .mvar _ => levelZero
| _ => none
{ preDef with value := value' }
else
preDef
private partial def ensureNoUnassignedLevelMVarsAtPreDef (preDef : PreDefinition) : TermElabM PreDefinition := do
if !preDef.value.hasLevelMVar then
return preDef
else
let pendingLevelMVars := (collectLevelMVars {} ( instantiateMVars preDef.value)).result
if ( logUnassignedLevelMVarsUsingErrorInfos pendingLevelMVars) then
return setLevelMVarsAtPreDef preDef
else if !( MonadLog.hasErrors) then
-- This is a fallback in case we don't have an error info available for the universe level metavariables.
-- We try to produce an error message containing an expression with one of the universe level metavariables.
let rec visitLevel (u : Level) (e : Expr) : TermElabM Unit := do
if u.hasMVar then
let e' exposeLevelMVars e
throwError "\
declaration '{preDef.declName}' contains universe level metavariables at the expression\
{indentExpr e'}\n\
in the declaration body{indentExpr <| ← exposeLevelMVars preDef.value}"
let withExpr (e : Expr) (m : ReaderT Expr (MonadCacheT ExprStructEq Unit TermElabM) Unit) :=
withReader (fun _ => e) m
let rec visit (e : Expr) (head := false) : ReaderT Expr (MonadCacheT ExprStructEq Unit TermElabM) Unit := do
if e.hasLevelMVar then
checkCache { val := e : ExprStructEq } fun _ => do
match e with
| .forallE n d b c | .lam n d b c => withExpr e do visit d; withLocalDecl n c d fun x => visit (b.instantiate1 x)
| .letE n t v b _ => withExpr e do visit t; visit v; withLetDecl n t v fun x => visit (b.instantiate1 x)
| .mdata _ b => withExpr e do visit b
| .proj _ _ b => withExpr e do visit b
| .sort u => visitLevel u ( read)
| .const _ us => (if head then id else withExpr e) <| us.forM (visitLevel · ( read))
| .app .. => withExpr e do
if let some (args, n, t, v, b) := e.letFunAppArgs? then
visit t; visit v; withLocalDeclD n t fun x => visit (b.instantiate1 x); args.forM visit
else
e.withApp fun f args => do visit f true; args.forM visit
| _ => pure ()
try
visit preDef.value |>.run preDef.value |>.run {}
catch e =>
logException e
return setLevelMVarsAtPreDef preDef
throwAbortCommand
else
return setLevelMVarsAtPreDef preDef
private def ensureNoUnassignedMVarsAtPreDef (preDef : PreDefinition) : TermElabM PreDefinition := do private def ensureNoUnassignedMVarsAtPreDef (preDef : PreDefinition) : TermElabM PreDefinition := do
let pendingMVarIds getMVarsAtPreDef preDef let pendingMVarIds getMVarsAtPreDef preDef
if ( logUnassignedUsingErrorInfos pendingMVarIds) then if ( logUnassignedUsingErrorInfos pendingMVarIds) then
@@ -120,7 +62,7 @@ private def ensureNoUnassignedMVarsAtPreDef (preDef : PreDefinition) : TermElabM
else else
throwAbortCommand throwAbortCommand
else else
ensureNoUnassignedLevelMVarsAtPreDef preDef return preDef
/-- /--
Letrec declarations produce terms of the form `(fun .. => ..) d` where `d` is a (partial) application of an auxiliary declaration for a letrec declaration. Letrec declarations produce terms of the form `(fun .. => ..) d` where `d` is a (partial) application of an auxiliary declaration for a letrec declaration.
@@ -162,7 +104,7 @@ Checks consistency of a clique of TerminationHints:
* If not all have a hint, the hints are ignored (log error) * If not all have a hint, the hints are ignored (log error)
* If one has `structural`, check that all have it, (else throw error) * If one has `structural`, check that all have it, (else throw error)
* A `structural` should not have a `decreasing_by` (else log error) * A `structural` shold not have a `decreasing_by` (else log error)
-/ -/
def checkTerminationByHints (preDefs : Array PreDefinition) : CoreM Unit := do def checkTerminationByHints (preDefs : Array PreDefinition) : CoreM Unit := do

View File

@@ -269,7 +269,7 @@ def inferBRecOnFTypes (recArgInfos : Array RecArgInfo) (positions : Positions)
let brecOnType inferType brecOn let brecOnType inferType brecOn
-- Skip the indices and major argument -- Skip the indices and major argument
let packedFTypes forallBoundedTelescope brecOnType (some (recArgInfo.indicesPos.size + 1)) fun _ brecOnType => let packedFTypes forallBoundedTelescope brecOnType (some (recArgInfo.indicesPos.size + 1)) fun _ brecOnType =>
-- And return the types of the next arguments -- And return the types of of the next arguments
arrowDomainsN numTypeFormers brecOnType arrowDomainsN numTypeFormers brecOnType
let mut FTypes := Array.mkArray positions.numIndices (Expr.sort 0) let mut FTypes := Array.mkArray positions.numIndices (Expr.sort 0)

View File

@@ -119,7 +119,7 @@ def getRecArgInfos (fnName : Name) (xs : Array Expr) (value : Expr)
(termArg? : Option TerminationArgument) : MetaM (Array RecArgInfo × MessageData) := do (termArg? : Option TerminationArgument) : MetaM (Array RecArgInfo × MessageData) := do
lambdaTelescope value fun ys _ => do lambdaTelescope value fun ys _ => do
if let .some termArg := termArg? then if let .some termArg := termArg? then
-- User explicitly asked to use a certain argument, so throw errors eagerly -- User explictly asked to use a certain argument, so throw errors eagerly
let recArgInfo withRef termArg.ref do let recArgInfo withRef termArg.ref do
mapError (f := (m!"cannot use specified parameter for structural recursion:{indentD ·}")) do mapError (f := (m!"cannot use specified parameter for structural recursion:{indentD ·}")) do
getRecArgInfo fnName xs.size (xs ++ ys) ( termArg.structuralArg) getRecArgInfo fnName xs.size (xs ++ ys) ( termArg.structuralArg)
@@ -189,7 +189,7 @@ def argsInGroup (group : IndGroupInst) (xs : Array Expr) (value : Expr)
if ( group.isDefEq recArgInfo.indGroupInst) then if ( group.isDefEq recArgInfo.indGroupInst) then
return (.some recArgInfo) return (.some recArgInfo)
-- Can this argument be understood as the auxiliary type former of a nested inductive? -- Can this argument be understood as the auxillary type former of a nested inductive?
if nestedTypeFormers.isEmpty then return .none if nestedTypeFormers.isEmpty then return .none
lambdaTelescope value fun ys _ => do lambdaTelescope value fun ys _ => do
let x := (xs++ys)[recArgInfo.recArgPos]! let x := (xs++ys)[recArgInfo.recArgPos]!

View File

@@ -13,7 +13,7 @@ This module contains the types
* `IndGroupInst` which extends `IndGroupInfo` with levels and parameters * `IndGroupInst` which extends `IndGroupInfo` with levels and parameters
to indicate a instantiation of the group. to indicate a instantiation of the group.
One purpose of this abstraction is to make it clear when a function operates on a group as One purpose of this abstraction is to make it clear when a fuction operates on a group as
a whole, rather than a specific inductive within the group. a whole, rather than a specific inductive within the group.
-/ -/

View File

@@ -17,7 +17,7 @@ private def shouldBetaReduce (e : Expr) (recFnNames : Array Name) : Bool :=
false false
/-- /--
Preprocesses the expressions to improve the effectiveness of `elimRecursion`. Preprocesses the expessions to improve the effectiveness of `elimRecursion`.
* Beta reduce terms where the recursive function occurs in the lambda term. * Beta reduce terms where the recursive function occurs in the lambda term.
Example: Example:

View File

@@ -31,7 +31,7 @@ structure RecArgInfo where
indGroupInst : IndGroupInst indGroupInst : IndGroupInst
/-- /--
index of the inductive datatype of the argument we are recursing on. index of the inductive datatype of the argument we are recursing on.
If `< indAll.all`, a normal data type, else an auxiliary data type due to nested recursion If `< indAll.all`, a normal data type, else an auxillary data type due to nested recursion
-/ -/
indIdx : Nat indIdx : Nat
deriving Inhabited deriving Inhabited
@@ -52,7 +52,7 @@ def RecArgInfo.pickIndicesMajor (info : RecArgInfo) (xs : Array Expr) : (Array E
return (indexMajorArgs, otherArgs) return (indexMajorArgs, otherArgs)
/-- /--
Name of the recursive data type. Assumes that it is not one of the auxiliary ones. Name of the recursive data type. Assumes that it is not one of the auxillary ones.
-/ -/
def RecArgInfo.indName! (info : RecArgInfo) : Name := def RecArgInfo.indName! (info : RecArgInfo) : Name :=
info.indGroupInst.all[info.indIdx]! info.indGroupInst.all[info.indIdx]!

View File

@@ -112,7 +112,7 @@ def TerminationArgument.delab (arity : Nat) (extraParams : Nat) (termArg : Termi
let stxBody Delaborator.delab let stxBody Delaborator.delab
let hole : TSyntax `Lean.Parser.Term.hole `(hole|_) let hole : TSyntax `Lean.Parser.Term.hole `(hole|_)
-- any variable not mentioned syntactically (it may appear in the `Expr`, so do not just use -- any variable not mentioned syntatically (it may appear in the `Expr`, so do not just use
-- `e.bindingBody!.hasLooseBVar`) should be delaborated as a hole. -- `e.bindingBody!.hasLooseBVar`) should be delaborated as a hole.
let vars : TSyntaxArray [`ident, `Lean.Parser.Term.hole] := let vars : TSyntaxArray [`ident, `Lean.Parser.Term.hole] :=
Array.map (fun (i : Ident) => if stxBody.raw.hasIdent i.getId then i else hole) vars Array.map (fun (i : Ident) => if stxBody.raw.hasIdent i.getId then i else hole) vars

View File

@@ -45,7 +45,7 @@ structure TerminationHints where
decreasingBy? : Option DecreasingBy decreasingBy? : Option DecreasingBy
/-- /--
Here we record the number of parameters past the `:`. It is set by Here we record the number of parameters past the `:`. It is set by
`TerminationHints.rememberExtraParams` and used as follows: `TerminationHints.rememberExtraParams` and used as folows:
* When we guess the termination argument in `GuessLex` and want to print it in surface-syntax * When we guess the termination argument in `GuessLex` and want to print it in surface-syntax
compatible form. compatible form.

View File

@@ -12,7 +12,7 @@ namespace Lean.Elab.WF
register_builtin_option debug.rawDecreasingByGoal : Bool := { register_builtin_option debug.rawDecreasingByGoal : Bool := {
defValue := false defValue := false
descr := "Shows the raw `decreasing_by` goal including internal implementation detail \ descr := "Shows the raw `decreasing_by` goal including internal implementation detail \
instead of cleaning it up with the `clean_wf` tactic. Can be enabled for debugging \ intead of cleaning it up with the `clean_wf` tactic. Can be enabled for debugging \
purposes. Please report an issue if you have to use this option for other reasons." purposes. Please report an issue if you have to use this option for other reasons."
} }

View File

@@ -66,7 +66,7 @@ private partial def mkProof (declName : Name) (type : Expr) : MetaM Expr := do
else if let some mvarIds splitTarget? mvarId then else if let some mvarIds splitTarget? mvarId then
mvarIds.forM go mvarIds.forM go
else else
-- At some point in the past, we looked for occurrences of Wf.fix to fold on the -- At some point in the past, we looked for occurences of Wf.fix to fold on the
-- LHS (introduced in 096e4eb), but it seems that code path was never used, -- LHS (introduced in 096e4eb), but it seems that code path was never used,
-- so #3133 removed it again (and can be recovered from there if this was premature). -- so #3133 removed it again (and can be recovered from there if this was premature).
throwError "failed to generate equational theorem for '{declName}'\n{MessageData.ofGoal mvarId}" throwError "failed to generate equational theorem for '{declName}'\n{MessageData.ofGoal mvarId}"

View File

@@ -29,7 +29,7 @@ if given, or the default `decreasing_tactic`.
For mutual recursion, a single measure is not just one parameter, but one from each recursive For mutual recursion, a single measure is not just one parameter, but one from each recursive
function. Enumerating these can lead to a combinatoric explosion, so we bound function. Enumerating these can lead to a combinatoric explosion, so we bound
the number of measures tried. the nubmer of measures tried.
In addition to measures derived from `sizeOf xᵢ`, it also considers measures In addition to measures derived from `sizeOf xᵢ`, it also considers measures
that assign an order to the functions themselves. This way we can support mutual that assign an order to the functions themselves. This way we can support mutual
@@ -42,7 +42,7 @@ guessed lexicographic order.
The following optimizations are applied to make this feasible: The following optimizations are applied to make this feasible:
1. The crucial optimization is to look at each argument of each recursive call 1. The crucial optimiziation is to look at each argument of each recursive call
_once_, try to prove `<` and (if that fails `≤`), and then look at that table to _once_, try to prove `<` and (if that fails `≤`), and then look at that table to
pick a suitable measure. pick a suitable measure.
@@ -80,7 +80,7 @@ register_builtin_option showInferredTerminationBy : Bool := {
/-- /--
Given a predefinition, return the variable names in the outermost lambdas. Given a predefinition, return the variabe names in the outermost lambdas.
Includes the “fixed prefix”. Includes the “fixed prefix”.
The length of the returned array is also used to determine the arity The length of the returned array is also used to determine the arity
@@ -550,7 +550,7 @@ where
failure failure
/-- /--
Enumerate all measures we want to try. Enumerate all meausures we want to try.
All arguments (resp. combinations thereof) and All arguments (resp. combinations thereof) and
possible orderings of functions (if more than one) possible orderings of functions (if more than one)

View File

@@ -17,7 +17,7 @@ private def shouldBetaReduce (e : Expr) (recFnNames : Array Name) : Bool :=
false false
/-- /--
Preprocesses the expressions to improve the effectiveness of `wfRecursion`. Preprocesses the expessions to improve the effectiveness of `wfRecursion`.
* Floats out the RecApp markers. * Floats out the RecApp markers.
Example: Example:

View File

@@ -605,7 +605,7 @@ private partial def hasNoErrorIfUnused : Syntax → Bool
/-- /--
Given `rhss` the right-hand-sides of a `match`-syntax notation, Given `rhss` the right-hand-sides of a `match`-syntax notation,
We tag them with fresh identifiers `alt_idx`. We use them to detect whether an alternative We tag them with with fresh identifiers `alt_idx`. We use them to detect whether an alternative
has been used or not. has been used or not.
The result is a triple `(altIdxMap, ignoreIfUnused, rhssNew)` where The result is a triple `(altIdxMap, ignoreIfUnused, rhssNew)` where
- `altIdxMap` is a mapping from the `alt_idx` identifiers to right-hand-side indices. - `altIdxMap` is a mapping from the `alt_idx` identifiers to right-hand-side indices.

View File

@@ -29,7 +29,7 @@ def getRecAppSyntax? (e : Expr) : Option Syntax :=
| _ => none | _ => none
/-- /--
Checks if the `MData` is for a recursive application. Checks if the `MData` is for a recursive applciation.
-/ -/
def MData.isRecApp (d : MData) : Bool := def MData.isRecApp (d : MData) : Bool :=
d.contains recAppKey d.contains recAppKey

View File

@@ -772,7 +772,7 @@ private partial def mkCoercionToCopiedParent (levelParams : List Name) (params :
let some fieldInfo := getFieldInfo? env parentStructName fieldName | unreachable! let some fieldInfo := getFieldInfo? env parentStructName fieldName | unreachable!
if fieldInfo.subobject?.isNone then throwError "failed to build coercion to parent structure" if fieldInfo.subobject?.isNone then throwError "failed to build coercion to parent structure"
let resultType whnfD ( inferType result) let resultType whnfD ( inferType result)
unless resultType.isForall do throwError "failed to build coercion to parent structure, unexpected type{indentExpr resultType}" unless resultType.isForall do throwError "failed to build coercion to parent structure, unexpect type{indentExpr resultType}"
let fieldVal copyFields resultType.bindingDomain! let fieldVal copyFields resultType.bindingDomain!
result := mkApp result fieldVal result := mkApp result fieldVal
return result return result

View File

@@ -21,7 +21,7 @@ private def resumeElabTerm (stx : Syntax) (expectedType? : Option Expr) (errToSo
elabTerm stx expectedType? false elabTerm stx expectedType? false
/-- /--
Try to elaborate `stx` that was postponed by an elaboration method using `Exception.postpone`. Try to elaborate `stx` that was postponed by an elaboration method using `Expection.postpone`.
It returns `true` if it succeeded, and `false` otherwise. It returns `true` if it succeeded, and `false` otherwise.
It is used to implement `synthesizeSyntheticMVars`. -/ It is used to implement `synthesizeSyntheticMVars`. -/
private def resumePostponed (savedContext : SavedContext) (stx : Syntax) (mvarId : MVarId) (postponeOnError : Bool) : TermElabM Bool := private def resumePostponed (savedContext : SavedContext) (stx : Syntax) (mvarId : MVarId) (postponeOnError : Bool) : TermElabM Bool :=
@@ -86,7 +86,7 @@ private def synthesizePendingInstMVar (instMVar : MVarId) (extraErrorMsg? : Opti
example (a : Int) (b c : Nat) : a = ↑b - ↑c := sorry example (a : Int) (b c : Nat) : a = ↑b - ↑c := sorry
``` ```
We have two pending coercions for the `↑` and `HSub ?m.220 ?m.221 ?m.222`. We have two pending coercions for the `↑` and `HSub ?m.220 ?m.221 ?m.222`.
When we did not use a backtracking search here, then the homogeneous default instance for `HSub`. When we did not use a backtracking search here, then the homogenous default instance for `HSub`.
``` ```
instance [Sub α] : HSub α α α where instance [Sub α] : HSub α α α where
``` ```
@@ -306,7 +306,7 @@ inductive PostponeBehavior where
| no | no
/-- /--
Synthectic metavariables associated with type class resolution can be postponed. Synthectic metavariables associated with type class resolution can be postponed.
Motivation: this kind of metavariable are not synthetic opaque, and can be assigned by `isDefEq`. Motivation: this kind of metavariable are not synthethic opaque, and can be assigned by `isDefEq`.
Unviverse constraints can also be postponed. Unviverse constraints can also be postponed.
-/ -/
| «partial» | «partial»
@@ -512,7 +512,7 @@ private partial def withSynthesizeLightImp (k : TermElabM α) : TermElabM α :=
finally finally
modify fun s => { s with pendingMVars := s.pendingMVars ++ pendingMVarsSaved } modify fun s => { s with pendingMVars := s.pendingMVars ++ pendingMVarsSaved }
/-- Similar to `withSynthesize`, but uses `postpone := .true`, does not use `synthesizeUsingDefault` -/ /-- Similar to `withSynthesize`, but uses `postpone := .true`, does not use use `synthesizeUsingDefault` -/
@[inline] def withSynthesizeLight [MonadFunctorT TermElabM m] (k : m α) : m α := @[inline] def withSynthesizeLight [MonadFunctorT TermElabM m] (k : m α) : m α :=
monadMap (m := TermElabM) (withSynthesizeLightImp ·) k monadMap (m := TermElabM) (withSynthesizeLightImp ·) k

View File

@@ -71,7 +71,7 @@ For the second kind more steps are involved:
3. Verify that algorithm in `Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Lemmas`. 3. Verify that algorithm in `Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Lemmas`.
4. Integrate it with either the expression or predicate bitblaster and use the proof above to verify it. 4. Integrate it with either the expression or predicate bitblaster and use the proof above to verify it.
5. Add simplification lemmas for the primitive to `bv_normalize` in `Std.Tactic.BVDecide.Normalize`. 5. Add simplification lemmas for the primitive to `bv_normalize` in `Std.Tactic.BVDecide.Normalize`.
If there are multiple ways to write the primitive (e.g. with TC based notation and without) you If there are mutliple ways to write the primitive (e.g. with TC based notation and without) you
should normalize for one notation here. should normalize for one notation here.
6. Add the reflection code to `Lean.Elab.Tactic.BVDecide.Frontend.BVDecide` 6. Add the reflection code to `Lean.Elab.Tactic.BVDecide.Frontend.BVDecide`
7. Add a test! 7. Add a test!

View File

@@ -24,7 +24,7 @@ register_builtin_option sat.solver : String := {
defValue := "" defValue := ""
descr := descr :=
"Name of the SAT solver used by Lean.Elab.Tactic.BVDecide tactics.\n "Name of the SAT solver used by Lean.Elab.Tactic.BVDecide tactics.\n
1. If this is set to something besides the empty string they will use that binary.\n 1. If this is set to something besides the emtpy string they will use that binary.\n
2. If this is set to the empty string they will check if there is a cadical binary next to the\ 2. If this is set to the empty string they will check if there is a cadical binary next to the\
executing program. Usually that program is going to be `lean` itself and we do ship a\ executing program. Usually that program is going to be `lean` itself and we do ship a\
`cadical` next to it.\n `cadical` next to it.\n

View File

@@ -44,7 +44,7 @@ def bvCheck (g : MVarId) (cfg : TacticContext) : MetaM Unit := do
let unsatProver : UnsatProver := fun reflectionResult _ => do let unsatProver : UnsatProver := fun reflectionResult _ => do
withTraceNode `sat (fun _ => return "Preparing LRAT reflection term") do withTraceNode `sat (fun _ => return "Preparing LRAT reflection term") do
let proof lratChecker cfg reflectionResult.bvExpr let proof lratChecker cfg reflectionResult.bvExpr
return .ok proof, "" return proof, ""
let _ closeWithBVReflection g unsatProver let _ closeWithBVReflection g unsatProver
return () return ()

View File

@@ -35,7 +35,7 @@ Reconstruct bit by bit which value expression must have had which `BitVec` value
expression - pair values. expression - pair values.
-/ -/
def reconstructCounterExample (var2Cnf : Std.HashMap BVBit Nat) (assignment : Array (Bool × Nat)) def reconstructCounterExample (var2Cnf : Std.HashMap BVBit Nat) (assignment : Array (Bool × Nat))
(aigSize : Nat) (atomsAssignment : Std.HashMap Nat (Nat × Expr)) : (aigSize : Nat) (atomsAssignment : Std.HashMap Nat Expr) :
Array (Expr × BVExpr.PackedBitVec) := Id.run do Array (Expr × BVExpr.PackedBitVec) := Id.run do
let mut sparseMap : Std.HashMap Nat (RBMap Nat Bool Ord.compare) := {} let mut sparseMap : Std.HashMap Nat (RBMap Nat Bool Ord.compare) := {}
for (bitVar, cnfVar) in var2Cnf.toArray do for (bitVar, cnfVar) in var2Cnf.toArray do
@@ -70,7 +70,7 @@ def reconstructCounterExample (var2Cnf : Std.HashMap BVBit Nat) (assignment : Ar
if bitValue then if bitValue then
value := value ||| (1 <<< currentBit) value := value ||| (1 <<< currentBit)
currentBit := currentBit + 1 currentBit := currentBit + 1
let atomExpr := atomsAssignment.get! bitVecVar |>.snd let atomExpr := atomsAssignment.get! bitVecVar
finalMap := finalMap.push (atomExpr, BitVec.ofNat currentBit value) finalMap := finalMap.push (atomExpr, BitVec.ofNat currentBit value)
return finalMap return finalMap
@@ -79,26 +79,18 @@ structure ReflectionResult where
proveFalse : Expr M Expr proveFalse : Expr M Expr
unusedHypotheses : Std.HashSet FVarId unusedHypotheses : Std.HashSet FVarId
/--
A counter example generated from the bitblaster.
-/
structure CounterExample where
/--
The set of unused but potentially relevant hypotheses. Useful for diagnosing spurious counter
examples.
-/
unusedHypotheses : Std.HashSet FVarId
/--
The actual counter example as a list of equations denoted as `expr = value` pairs.
-/
equations : Array (Expr × BVExpr.PackedBitVec)
structure UnsatProver.Result where structure UnsatProver.Result where
proof : Expr proof : Expr
lratCert : LratCert lratCert : LratCert
abbrev UnsatProver := ReflectionResult Std.HashMap Nat (Nat × Expr) abbrev UnsatProver := ReflectionResult Std.HashMap Nat Expr MetaM UnsatProver.Result
MetaM (Except CounterExample UnsatProver.Result)
/--
Contains values that will be used to diagnose spurious counter examples.
-/
structure DiagnosisInput where
unusedHypotheses : Std.HashSet FVarId
atomsAssignment : Std.HashMap Nat Expr
/-- /--
The result of a spurious counter example diagnosis. The result of a spurious counter example diagnosis.
@@ -107,19 +99,20 @@ structure Diagnosis where
uninterpretedSymbols : Std.HashSet Expr := {} uninterpretedSymbols : Std.HashSet Expr := {}
unusedRelevantHypotheses : Std.HashSet FVarId := {} unusedRelevantHypotheses : Std.HashSet FVarId := {}
abbrev DiagnosisM : Type Type := ReaderT CounterExample <| StateRefT Diagnosis MetaM abbrev DiagnosisM : Type Type := ReaderT DiagnosisInput <| StateRefT Diagnosis MetaM
namespace DiagnosisM namespace DiagnosisM
def run (x : DiagnosisM Unit) (counterExample : CounterExample) : MetaM Diagnosis := do def run (x : DiagnosisM Unit) (unusedHypotheses : Std.HashSet FVarId)
let (_, issues) ReaderT.run x counterExample |>.run {} (atomsAssignment : Std.HashMap Nat Expr) : MetaM Diagnosis := do
let (_, issues) ReaderT.run x { unusedHypotheses, atomsAssignment } |>.run {}
return issues return issues
def unusedHyps : DiagnosisM (Std.HashSet FVarId) := do def unusedHyps : DiagnosisM (Std.HashSet FVarId) := do
return ( read).unusedHypotheses return ( read).unusedHypotheses
def equations : DiagnosisM (Array (Expr × BVExpr.PackedBitVec)) := do def atomsAssignment : DiagnosisM (Std.HashMap Nat Expr) := do
return ( read).equations return ( read).atomsAssignment
def addUninterpretedSymbol (e : Expr) : DiagnosisM Unit := def addUninterpretedSymbol (e : Expr) : DiagnosisM Unit :=
modify fun s => { s with uninterpretedSymbols := s.uninterpretedSymbols.insert e } modify fun s => { s with uninterpretedSymbols := s.uninterpretedSymbols.insert e }
@@ -138,7 +131,7 @@ Diagnose spurious counter examples, currently this checks:
- Whether all hypotheses which contain any variable that was bitblasted were included - Whether all hypotheses which contain any variable that was bitblasted were included
-/ -/
def diagnose : DiagnosisM Unit := do def diagnose : DiagnosisM Unit := do
for (expr, _) in equations do for (_, expr) in atomsAssignment do
match_expr expr with match_expr expr with
| BitVec.ofBool x => | BitVec.ofBool x =>
match x with match x with
@@ -164,8 +157,9 @@ def unusedRelevantHypothesesExplainer (d : Diagnosis) : Option MessageData := do
def explainers : List (Diagnosis Option MessageData) := def explainers : List (Diagnosis Option MessageData) :=
[uninterpretedExplainer, unusedRelevantHypothesesExplainer] [uninterpretedExplainer, unusedRelevantHypothesesExplainer]
def explainCounterExampleQuality (counterExample : CounterExample) : MetaM MessageData := do def explainCounterExampleQuality (unusedHypotheses : Std.HashSet FVarId)
let diagnosis DiagnosisM.run DiagnosisM.diagnose counterExample (atomsAssignment : Std.HashMap Nat Expr) : MetaM MessageData := do
let diagnosis DiagnosisM.run DiagnosisM.diagnose unusedHypotheses atomsAssignment
let folder acc explainer := if let some m := explainer diagnosis then acc.push m else acc let folder acc explainer := if let some m := explainer diagnosis then acc.push m else acc
let explanations := explainers.foldl (init := #[]) folder let explanations := explainers.foldl (init := #[]) folder
@@ -178,8 +172,8 @@ def explainCounterExampleQuality (counterExample : CounterExample) : MetaM Messa
return err return err
def lratBitblaster (cfg : TacticContext) (reflectionResult : ReflectionResult) def lratBitblaster (cfg : TacticContext) (reflectionResult : ReflectionResult)
(atomsAssignment : Std.HashMap Nat (Nat × Expr)) : (atomsAssignment : Std.HashMap Nat Expr) :
MetaM (Except CounterExample UnsatProver.Result) := do MetaM UnsatProver.Result := do
let bvExpr := reflectionResult.bvExpr let bvExpr := reflectionResult.bvExpr
let entry let entry
withTraceNode `bv (fun _ => return "Bitblasting BVLogicalExpr to AIG") do withTraceNode `bv (fun _ => return "Bitblasting BVLogicalExpr to AIG") do
@@ -207,10 +201,13 @@ def lratBitblaster (cfg : TacticContext) (reflectionResult : ReflectionResult)
match res with match res with
| .ok cert => | .ok cert =>
let proof cert.toReflectionProof cfg bvExpr ``verifyBVExpr ``unsat_of_verifyBVExpr_eq_true let proof cert.toReflectionProof cfg bvExpr ``verifyBVExpr ``unsat_of_verifyBVExpr_eq_true
return .ok proof, cert return proof, cert
| .error assignment => | .error assignment =>
let equations := reconstructCounterExample map assignment aigSize atomsAssignment let reconstructed := reconstructCounterExample map assignment aigSize atomsAssignment
return .error { unusedHypotheses := reflectionResult.unusedHypotheses, equations } let mut error explainCounterExampleQuality reflectionResult.unusedHypotheses atomsAssignment
for (var, value) in reconstructed do
error := error ++ m!"{var} = {value.bv}\n"
throwError error
def reflectBV (g : MVarId) : M ReflectionResult := g.withContext do def reflectBV (g : MVarId) : M ReflectionResult := g.withContext do
@@ -222,80 +219,51 @@ def reflectBV (g : MVarId) : M ReflectionResult := g.withContext do
sats := sats.push reflected sats := sats.push reflected
else else
unusedHypotheses := unusedHypotheses.insert hyp unusedHypotheses := unusedHypotheses.insert hyp
if h : sats.size = 0 then if sats.size = 0 then
let mut error := "None of the hypotheses are in the supported BitVec fragment.\n" let mut error := "None of the hypotheses are in the supported BitVec fragment.\n"
error := error ++ "There are two potential fixes for this:\n" error := error ++ "There are two potential fixes for this:\n"
error := error ++ "1. If you are using custom BitVec constructs simplify them to built-in ones.\n" error := error ++ "1. If you are using custom BitVec constructs simplify them to built-in ones.\n"
error := error ++ "2. If your problem is using only built-in ones it might currently be out of reach.\n" error := error ++ "2. If your problem is using only built-in ones it might currently be out of reach.\n"
error := error ++ " Consider expressing it in terms of different operations that are better supported." error := error ++ " Consider expressing it in terms of different operations that are better supported."
throwError error throwError error
else let sat := sats.foldl (init := SatAtBVLogical.trivial) SatAtBVLogical.and
let sat := sats[1:].foldl (init := sats[0]) SatAtBVLogical.and return {
return { bvExpr := sat.bvExpr,
bvExpr := sat.bvExpr, proveFalse := sat.proveFalse,
proveFalse := sat.proveFalse, unusedHypotheses := unusedHypotheses
unusedHypotheses := unusedHypotheses }
}
def closeWithBVReflection (g : MVarId) (unsatProver : UnsatProver) : def closeWithBVReflection (g : MVarId) (unsatProver : UnsatProver) :
MetaM (Except CounterExample LratCert) := M.run do MetaM LratCert := M.run do
g.withContext do g.withContext do
let reflectionResult let reflectionResult
withTraceNode `bv (fun _ => return "Reflecting goal into BVLogicalExpr") do withTraceNode `bv (fun _ => return "Reflecting goal into BVLogicalExpr") do
reflectBV g reflectBV g
trace[Meta.Tactic.bv] "Reflected bv logical expression: {reflectionResult.bvExpr}" trace[Meta.Tactic.bv] "Reflected bv logical expression: {reflectionResult.bvExpr}"
let atomsPairs := ( getThe State).atoms.toList.map (fun (expr, width, ident) => (ident, (width, expr))) let atomsPairs := ( getThe State).atoms.toList.map (fun (expr, _, ident) => (ident, expr))
let atomsAssignment := Std.HashMap.ofList atomsPairs let atomsAssignment := Std.HashMap.ofList atomsPairs
match unsatProver reflectionResult atomsAssignment with let bvExprUnsat, cert unsatProver reflectionResult atomsAssignment
| .ok bvExprUnsat, cert => let proveFalse reflectionResult.proveFalse bvExprUnsat
let proveFalse reflectionResult.proveFalse bvExprUnsat g.assign proveFalse
g.assign proveFalse return cert
return .ok cert
| .error counterExample => return .error counterExample
def bvUnsat (g : MVarId) (cfg : TacticContext) : MetaM (Except CounterExample LratCert) := M.run do def bvUnsat (g : MVarId) (cfg : TacticContext) : MetaM LratCert := M.run do
let unsatProver : UnsatProver := fun reflectionResult atomsAssignment => do let unsatProver : UnsatProver := fun reflectionResult atomsAssignment => do
withTraceNode `bv (fun _ => return "Preparing LRAT reflection term") do withTraceNode `bv (fun _ => return "Preparing LRAT reflection term") do
lratBitblaster cfg reflectionResult atomsAssignment lratBitblaster cfg reflectionResult atomsAssignment
closeWithBVReflection g unsatProver closeWithBVReflection g unsatProver
/--
The result of calling `bv_decide`.
-/
structure Result where structure Result where
/--
Trace of the `simp` used in `bv_decide`'s normalization procedure.
-/
simpTrace : Simp.Stats simpTrace : Simp.Stats
/--
If the normalization step was not enough to solve the goal this contains the LRAT proof
certificate.
-/
lratCert : Option LratCert lratCert : Option LratCert
/--
Try to close `g` using a bitblaster. Return either a `CounterExample` if one is found or a `Result`
if `g` is proven.
-/
def bvDecide' (g : MVarId) (cfg : TacticContext) : MetaM (Except CounterExample Result) := do
let g?, simpTrace Normalize.bvNormalize g
let some g := g? | return .ok simpTrace, none
match bvUnsat g cfg with
| .ok lratCert => return .ok simpTrace, some lratCert
| .error counterExample => return .error counterExample
/--
Call `bvDecide'` and throw a pretty error if a counter example ends up being produced.
-/
def bvDecide (g : MVarId) (cfg : TacticContext) : MetaM Result := do def bvDecide (g : MVarId) (cfg : TacticContext) : MetaM Result := do
match bvDecide' g cfg with let g?, simpTrace Normalize.bvNormalize g
| .ok result => return result let some g := g? | return simpTrace, none
| .error counterExample => let lratCert bvUnsat g cfg
let error explainCounterExampleQuality counterExample return simpTrace, some lratCert
let folder := fun error (var, value) => error ++ m!"{var} = {value.bv}\n"
throwError counterExample.equations.foldl (init := error) folder
@[builtin_tactic Lean.Parser.Tactic.bvDecide] @[builtin_tactic Lean.Parser.Tactic.bvDecide]
def evalBvTrace : Tactic := fun def evalBvTrace : Tactic := fun

View File

@@ -61,6 +61,14 @@ partial def of (h : Expr) : M (Option SatAtBVLogical) := do
return some bvLogical.bvExpr, proof, bvLogical.expr return some bvLogical.bvExpr, proof, bvLogical.expr
| _ => return none | _ => return none
/--
The trivially true `BVLogicalExpr`.
-/
def trivial : SatAtBVLogical where
bvExpr := .const true
expr := toExpr (.const true : BVLogicalExpr)
satAtAtoms := return mkApp (mkConst ``BVLogicalExpr.sat_true) ( M.atomsAssignment)
/-- /--
Logical conjunction of two `ReifiedBVLogical`. Logical conjunction of two `ReifiedBVLogical`.
-/ -/

View File

@@ -141,11 +141,10 @@ This will obtain an `LratCert` if the formula is UNSAT and throw errors otherwis
def runExternal (cnf : CNF Nat) (solver : System.FilePath) (lratPath : System.FilePath) def runExternal (cnf : CNF Nat) (solver : System.FilePath) (lratPath : System.FilePath)
(trimProofs : Bool) (timeout : Nat) (binaryProofs : Bool) (trimProofs : Bool) (timeout : Nat) (binaryProofs : Bool)
: MetaM (Except (Array (Bool × Nat)) LratCert) := do : MetaM (Except (Array (Bool × Nat)) LratCert) := do
IO.FS.withTempFile fun cnfHandle cnfPath => do IO.FS.withTempFile fun _ cnfPath => do
withTraceNode `sat (fun _ => return "Serializing SAT problem to DIMACS file") do withTraceNode `sat (fun _ => return "Serializing SAT problem to DIMACS file") do
-- lazyPure to prevent compiler lifting -- lazyPure to prevent compiler lifting
cnfHandle.putStr ( IO.lazyPure (fun _ => cnf.dimacs)) IO.FS.writeFile cnfPath ( IO.lazyPure (fun _ => cnf.dimacs))
cnfHandle.flush
let res let res
withTraceNode `sat (fun _ => return "Running SAT solver") do withTraceNode `sat (fun _ => return "Running SAT solver") do

View File

@@ -27,6 +27,18 @@ namespace Frontend.Normalize
open Lean.Meta open Lean.Meta
open Std.Tactic.BVDecide.Normalize open Std.Tactic.BVDecide.Normalize
/--
The bitblaster for multiplication introduces symbolic branches over the right hand side.
If we have an expression of the form `c * x` where `c` is constant we should change it to `x * c`
such that these symbolic branches get constant folded by the AIG framework.
-/
builtin_simproc [bv_normalize] mulConst ((_ : BitVec _) * (_ : BitVec _)) := fun e => do
let_expr HMul.hMul _ _ _ _ lhs rhs := e | return .continue
let some width, _ Lean.Meta.getBitVecValue? lhs | return .continue
let new mkAppM ``HMul.hMul #[rhs, lhs]
let proof := mkApp3 (mkConst ``BitVec.mul_comm) (toExpr width) lhs rhs
return .done { expr := new, proof? := some proof }
builtin_simproc [bv_normalize] eqToBEq (((_ : Bool) = (_ : Bool))) := fun e => do builtin_simproc [bv_normalize] eqToBEq (((_ : Bool) = (_ : Bool))) := fun e => do
let_expr Eq _ lhs rhs := e | return .continue let_expr Eq _ lhs rhs := e | return .continue
match_expr rhs with match_expr rhs with
@@ -53,7 +65,6 @@ def bvNormalize (g : MVarId) : MetaM Result := do
let sevalSimprocs Simp.getSEvalSimprocs let sevalSimprocs Simp.getSEvalSimprocs
let simpCtx : Simp.Context := { let simpCtx : Simp.Context := {
config := { failIfUnchanged := false, zetaDelta := true }
simpTheorems := #[bvThms, sevalThms] simpTheorems := #[bvThms, sevalThms]
congrTheorems := ( getSimpCongrTheorems) congrTheorems := ( getSimpCongrTheorems)
} }

View File

@@ -49,9 +49,6 @@ instance : Monad TacticM :=
let i := inferInstanceAs (Monad TacticM); let i := inferInstanceAs (Monad TacticM);
{ pure := i.pure, bind := i.bind } { pure := i.pure, bind := i.bind }
instance : Inhabited (TacticM α) where
default := fun _ _ => default
def getGoals : TacticM (List MVarId) := def getGoals : TacticM (List MVarId) :=
return ( get).goals return ( get).goals

View File

@@ -90,7 +90,6 @@ where
withAlwaysResolvedPromise fun finished => do withAlwaysResolvedPromise fun finished => do
withAlwaysResolvedPromise fun inner => do withAlwaysResolvedPromise fun inner => do
snap.new.resolve <| .mk { snap.new.resolve <| .mk {
desc := tac.getKind.toString
diagnostics := .empty diagnostics := .empty
stx := tac stx := tac
inner? := some { range?, task := inner.result } inner? := some { range?, task := inner.result }

View File

@@ -77,7 +77,7 @@ def congr (mvarId : MVarId) (addImplicitArgs := false) (nameSubgoals := true) :
-- mvarIds is the list of goals produced by congr. We only want to change the one at position `i` -- mvarIds is the list of goals produced by congr. We only want to change the one at position `i`
-- so this closes all other equality goals with `rfl.`. There are non-equality goals produced -- so this closes all other equality goals with `rfl.`. There are non-equality goals produced
-- by `congr` (e.g. dependent instances), these are kept as goals. -- by `congr` (e.g. dependent instances), thes are kept as goals.
private def selectIdx (tacticName : String) (mvarIds : List (Option MVarId)) (i : Int) : private def selectIdx (tacticName : String) (mvarIds : List (Option MVarId)) (i : Int) :
TacticM Unit := do TacticM Unit := do
if i >= 0 then if i >= 0 then

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Lean.Elab.Tactic.Basic import Lean.Elab.Tactic.Basic

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2021-2024 Gabriel Ebner and Lean FRO. All rights reserved. Copyright (c) 2021-2024 Gabriel Ebner and Lean FRO. 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: Gabriel Ebner, Joe Hendrix, Kim Morrison Authors: Gabriel Ebner, Joe Hendrix, Scott Morrison
-/ -/
prelude prelude
import Lean.Meta.Tactic.LibrarySearch import Lean.Meta.Tactic.LibrarySearch

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Lean.Elab.Tactic.Omega.Frontend import Lean.Elab.Tactic.Omega.Frontend
@@ -39,7 +39,7 @@ The `omega` tactic pre-processes the hypotheses in the following ways:
* If `x / m` appears, for some `x : Int` and literal `m : Nat`, * If `x / m` appears, for some `x : Int` and literal `m : Nat`,
replace `x / m` with a new variable `α` and add the constraints replace `x / m` with a new variable `α` and add the constraints
`0 ≤ - m * α + x ≤ m - 1`. `0 ≤ - m * α + x ≤ m - 1`.
* If `x % m` appears, similarly, introduce the same new constraints * If `x % m` appears, similarly, introduce the same new contraints
but replace `x % m` with `- m * α + x`. but replace `x % m` with `- m * α + x`.
* Split conjunctions, existentials, and subtypes. * Split conjunctions, existentials, and subtypes.
* Record, for each appearance of `(a - b : Int)` with `a b : Nat`, the disjunction * Record, for each appearance of `(a - b : Int)` with `a b : Nat`, the disjunction

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Omega.Constraint import Init.Omega.Constraint
@@ -49,7 +49,7 @@ inductive Justification : Constraint → Coeffs → Type
| combo {s t x y} (a : Int) (j : Justification s x) (b : Int) (k : Justification t y) : | combo {s t x y} (a : Int) (j : Justification s x) (b : Int) (k : Justification t y) :
Justification (Constraint.combo a s b t) (Coeffs.combo a x b y) Justification (Constraint.combo a s b t) (Coeffs.combo a x b y)
/-- /--
The justification for the constraint constructed using "balanced mod" while The justification for the constraing constructed using "balanced mod" while
eliminating an equality. eliminating an equality.
-/ -/
| bmod (m : Nat) (r : Int) (i : Nat) {x} (j : Justification (.exact r) x) : | bmod (m : Nat) (r : Int) (i : Nat) {x} (j : Justification (.exact r) x) :

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Lean.Elab.Tactic.Omega.Core import Lean.Elab.Tactic.Omega.Core
@@ -322,7 +322,7 @@ where
end end
namespace MetaProblem namespace MetaProblem
/-- The trivial `MetaProblem`, with no facts to process and a trivial `Problem`. -/ /-- The trivial `MetaProblem`, with no facts to processs and a trivial `Problem`. -/
def trivial : MetaProblem where def trivial : MetaProblem where
problem := {} problem := {}

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.BinderPredicates import Init.BinderPredicates

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved. Copyright (c) 2023 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: Kim Morrison Authors: Scott Morrison
-/ -/
prelude prelude
import Init.Omega.LinearCombo import Init.Omega.LinearCombo

View File

@@ -1,7 +1,7 @@
/- /-
Copyright (c) 2022 Mario Carneiro. 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: Mario Carneiro, Kim Morrison Authors: Mario Carneiro, Scott Morrison
-/ -/
prelude prelude
import Lean.Meta.Tactic.Repeat import Lean.Meta.Tactic.Repeat

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