Compare commits

..

89 Commits

Author SHA1 Message Date
Leonardo de Moura
9b9a031ff7 chore: update test
`congrArg` is not needed anymore.
2025-05-13 22:21:56 -04:00
Leonardo de Moura
bf08a49608 test: 2025-05-13 22:15:19 -04:00
Leonardo de Moura
19eee3bf3f feat: add propagateEtaStruct 2025-05-13 22:14:04 -04:00
Leonardo de Moura
bfc364cf67 fix: adjust validateExtAttr 2025-05-13 21:16:09 -04:00
Leonardo de Moura
076bace223 feat: add Grind.Config.etaStruct 2025-05-13 21:09:01 -04:00
Joachim Breitner
1d90eac631 test: more fundind unfolding test for #8293 (#8320) 2025-05-13 13:19:37 +00:00
Marc Huisinga
92b59ae4f6 test: goals accomplished (#8319)
This PR adds a test for the goals accomplished diagnostics so that we
notice when they break.

Follow-up for #8242.
2025-05-13 13:00:47 +00:00
Eric Wieser
aa3e7848c2 fix: correct whitespace in omit/include (#8169)
This PR makes the whitespace handling in the syntax of `omit` and
`include` consistent with `variable`.

Zulip thread: [#lean4 > Pretty printing instances in `omit` @
💬](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Pretty.20printing.20instances.20in.20.60omit.60/near/515185216)
2025-05-13 12:50:11 +00:00
Leonardo de Moura
e0a266780b feat: add instance Grind.CommRing (Fin n) (#8276)
This PR adds the instances `Grind.CommRing (Fin n)` and `Grind.IsCharP
(Fin n) n`. New tests:
```lean
example (x y z : Fin 13) :
    (x + y + z) ^ 2 = x ^ 2 + y ^ 2 + z ^ 2 + 2 * (x * y + y * z + z * x) := by
  grind +ring

example (x y : Fin 17) : (x + y) ^ 3 = x ^ 3 + y ^ 3 + 3 * x * y * (x + y) := by
  grind +ring

example (x y : Fin 19) : (x - y) * (x ^ 2 + x * y + y ^ 2) = x ^ 3 - y ^ 3 := by
  grind +ring
```

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2025-05-13 12:09:02 +00:00
Joachim Breitner
2299c3c9ec chore: post-stage0 adaptions for #8104 (#8317) 2025-05-13 11:38:21 +00:00
Kim Morrison
2cf3ac9461 feat: split Std.Classes.Ord (#8315)
This PR splits `Std.Classes.Ord` into `Std.Classes.Ord.Basic` (with few
imports) and `Std.Classes.Ord.SInt` and `Std.Classes.Ord.Vector`. These
changes avoid importing `Init.Data.BitVec.Lemmas` unnecessarily into
various basic files.
As the new import-only file `Std.Classes.Ord` imports all three of
these, end-users are not affected.
2025-05-13 11:22:19 +00:00
Kim Morrison
384c78ae13 chore: remove >6 month old deprecations (#8312) 2025-05-13 11:11:22 +00:00
Marcus Rossel
a6a2833c68 feat: lemmas about List.intersperse (#8272)
This PR adds lemmas about the length and use of `[]?` on results of
`List.intersperse`.

This was suggested by @TwoFX as discussed in
https://github.com/TwoFX/human-eval-lean/pull/164#discussion_r2074101914.

I am unsure about the correct naming of `intersperse_getElem?_even` and
`intersperse_getElem?_odd`.
2025-05-13 10:58:35 +00:00
Lean stage0 autoupdater
b04ecaefd7 chore: update stage0 2025-05-13 10:47:03 +00:00
Joachim Breitner
e575736cae feat: fun_induction to unfold function application in the goal (#8104)
This PR makes `fun_induction` and `fun_cases` (try to) unfold the
function application of interest in the goal. The old behavior can be
enabled with `set_option tactic.fun_induction.unfolding false`. For
`fun_cases` this does not work yet when the function’s result type
depends on one of the arguments, see issue #8296.
2025-05-13 09:37:39 +00:00
Markus Himmel
8eec1e4cfb feat: Option lemmas and cleanup (#8298)
This PR adds various `Option` lemmas and defines `Option.filterM` for
applicative functors.
2025-05-13 08:42:03 +00:00
Marc Huisinga
9659469998 fix: broken unknown identifier code actions (#8180)
This PR fixes the new unknown identifier code actions so that they work
in non-trivial files.

It's very unfortunate that we didn't notice this sooner.
2025-05-13 08:32:36 +00:00
Marc Huisinga
efcf94298a feat: improve workspace symbol performance (#8091)
This PR improves the performance of the workspace symbol request.

In my testing on my machine, the time to respond to the workspace symbol
request containing just `c` in Mathlib has been reduced to ~1200ms from
~11000ms.

We also serve the nearest-matching 1000 symbols instead of just the
first 100 now and use the length of the symbol as a tie-breaker for when
the fuzzy matching score is equal.

Some further improvements might be gained in the future when #8087 is
fixed and we can switch back to `qsort`.
2025-05-13 08:29:49 +00:00
Kim Morrison
f75e36dcdb chore: Vector doesn't extend Array (#8313)
This PR changes the definition of `Vector` so it no longer extends
`Array`. This prevents `Array` API from "leaking through".
2025-05-13 07:13:23 +00:00
Kim Morrison
aa647f3cd6 chore: cleaning up imports (#8314) 2025-05-13 07:09:21 +00:00
Kim Morrison
77302b6572 chore: add grind test for fastEraseDups (#8310)
This PR adds @TwoFX's `List.fastEraseDups` example, with the proof
golfed further using `grind`, as a test case for `grind`.
2025-05-13 06:55:39 +00:00
Kim Morrison
29cc75531a chore: remove accidental grind trace options (#8311) 2025-05-13 05:58:46 +00:00
Kim Morrison
a08d182359 feat: add @[grind] annotations for HashMap (#8246)
This PR add `@[grind]` annotations for HashMap and variants.
2025-05-13 04:56:41 +00:00
Cameron Zwarich
ef77434a49 fix: make new compiler's specialization closure behavior match old compiler (#8308)
This PR makes the new compiler's specialization pass compute closures
the same way as the old compiler, in particular when it comes to
variables captured by lambdas.
2025-05-12 21:31:03 +00:00
Henrik Böving
aa54390c85 fix: bv_decide preprocessing in dependently typed situations (#8306)
This PR makes it possible for `bv_decide` to tackle situations for its
enum type preprocessing where the enums themselves are use in a
dependently type context (for example inside of a `GetElem` body) and
thus not trivially accessible to `simp` for rewriting. To do this we
drop`GetElem` on `BitVec` as well as `dite` as early as possible in the
pipeline.
2025-05-12 21:03:58 +00:00
Cameron Zwarich
579d0ad15d chore: add @zwarich to the compiler CODEOWNERS (#8305) 2025-05-12 18:42:54 +00:00
Rob23oba
e212890dfc perf: optimize Lean/Compiler/IR/ToIR compilation time and size (#8286)
This PR optimizes the `ToIR.lean` module, reducing the size of the
compiled C code by a bit over a factor of 3. This significantly improves
the compilation time, making `ToIR` relatively quick to compile.

Closes #8269
2025-05-12 18:34:07 +00:00
Leonardo de Moura
1aa16f1e3c fix: missing foldProjs (#8303)
This PR fixes missing occurrences of `foldProjs` in `grind`.
2025-05-12 18:32:57 +00:00
Joachim Breitner
cc80f7943d fix: cases to fail gracefully when motive has complex argument of dependent type (#8302)
This PR lets `cases` fail gracefully when the motive has an complex
argument whose type is dependent type on the targets. While the
`induction` tactic can handle this well, `cases` does not. This change
at least gracefully degrades to not instantiating that motive parameter.
See issue #8296 for more details on this issue.
2025-05-12 16:04:26 +00:00
Joachim Breitner
c55bf5172d feat: unfolding induction theorems to unfold bif (#8301)
This PR unfolds functions in the unfolding induction principle properly
when they use `bif` (a.k.a. `Bool.cond`).
2025-05-12 16:00:30 +00:00
Leonardo de Moura
3f75f08e1d feat: abstract metavars in grind preprocessor (#8299)
This PR implements a missing preprocessing step in `grind`: abstract
metavariables in the goal
2025-05-12 14:53:54 +00:00
Markus Himmel
eda467e066 fix: typo in application type mismatch error message (#8290)
This PR fixes a typo that was introduced recently.
2025-05-12 13:35:29 +00:00
Lean stage0 autoupdater
ab5b8ffed1 chore: update stage0 2025-05-12 13:49:07 +00:00
Kim Morrison
7f6f4c889d feat: use NeZero in Fin lemmas where possible (#8291)
This PR changes the statements of `Fin` lemmas to use `[NeZero n] (i :
Fin n)` rather than `(i : Fin (n+1))` where possible.
2025-05-12 12:40:10 +00:00
Kim Morrison
294360518a chore: adjust @[grind] attributes on List lemmas (#8295) 2025-05-12 12:31:29 +00:00
Sebastian Ullrich
c7acb7e481 chore: reserve [expose] attribute (#8292)
To be used in the module system.
2025-05-12 12:19:30 +00:00
Siddharth
9105c01757 feat: BitVec.neg_ofNat_eq_ofInt_neg (#8206)
This PR shows that negating a bitvector created from a natural number
equals creating a bitvector from the the negative of that number (as an
integer).

```lean
theorem neg_ofNat_eq_ofInt_neg {w : Nat} (x : Nat) :
    - BitVec.ofNat w x = BitVec.ofInt w (- x) := by
  apply BitVec.eq_of_toInt_eq
  simp [BitVec.toInt_neg, BitVec.toInt_ofNat]
```

---------

Co-authored-by: Luisa Cicolini <48860705+luisacicolini@users.noreply.github.com>
2025-05-12 10:00:49 +00:00
Henrik Böving
d0c4d19270 fix: bv_decide can handle universe polymorphic enums (#8270)
This PR makes the enum pass of `bv_decide` handle enum types that are
universe polymorphic.
2025-05-12 08:22:57 +00:00
Kim Morrison
60ea92fdb0 chore: add failing grind tests (#8289) 2025-05-12 06:33:38 +00:00
Kim Morrison
2b4f372317 chore: add failing grind test (#8288) 2025-05-12 06:10:25 +00:00
Kim Morrison
10bda559f9 chore: begin development cycle for v4.21.0 (#8287) 2025-05-12 05:02:41 +00:00
Joachim Breitner
33aaabaed7 fix: FunInd: rewrite matches more reliably in .induct_unfolding (#8277)
This PR improves the generation of `.induct_unfolding` by rewriting
`match` statements more reliably, using the new “congruence equations”
introduced in #8284. Fixes #8195.
2025-05-11 15:26:28 +00:00
Joachim Breitner
dc1a70fa43 feat: congruence equations for matchers (#8284)
This PR adds a new variant of equations for matchers, namely “congruence
equations” that generalize the normal matcher equations. They have
unrestricted left-hand-sides, extra equality assumptions relating the
discriminiants with the patterns and thus prove heterogenous equalities.
In that sense they combine congruence with rewriting. They can be used
to rewrite matcher applications where, due to dependencies, `simp` would
fail to rewrite the discriminants, and will be used when producing the
unfolding induction theorems.
2025-05-11 13:04:59 +00:00
Joachim Breitner
ca73223d4c fix: left-over free variables in splitter (#8285)
This PR fixes “declaration has free variables” errors when generating a
splitter for a match statement with named patterns. Fixes #8274.
2025-05-11 13:04:45 +00:00
Sebastian Ullrich
1f85fd2db8 fix: rfl theorem tracking in the module system (#8215)
We need to track rfl status in both the private and public scope once
defs may become irreducible in the latter.
2025-05-11 07:57:19 +00:00
Leonardo de Moura
e681855428 feat: improve procedure for proving auxiliary type casting equalities in grind (#8281)
This PR improves the module used to prove auxiliary type cast equalities
in `grind`.
2025-05-11 04:15:41 +00:00
Leonardo de Moura
9096eb168d fix: arrow congruence in grind (#8280)
This PR the support for arrows in the congruence closure procedure used
in `grind`.
2025-05-11 03:18:18 +00:00
Cameron Zwarich
575b4786f9 feat: optimize lean_nat_shiftr for scalars (#8268)
This PR optimizes lean_nat_shiftr for scalar operands. The new compiler
converts Nat divisions into right shifts, so this now shows up as hot in
some profiles.
2025-05-11 01:39:59 +00:00
Leonardo de Moura
ddf5512c9a feat: add support for implies_congr in grind (#8275)
This PR ensures the congruence closure in `grind` and find non-dependent
arrow congruences. That is, it can apply the `implies_congr` theorem.
2025-05-10 12:09:45 +00:00
Leonardo de Moura
eabde77d84 fix: improve type-as-hole error message (#8262)
This PR improves the type-as-hole error message. Type-as-hole error for
theorem declarations should not admit the possibility of omitting the
type entirely.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2025-05-09 22:49:37 +00:00
Rob23oba
5df7770977 feat: consider universes and projections in addPPExplicitToExposeDiff (#8271)
This PR changes `addPPExplicitToExposeDiff` to show universe differences
and to visit into projections, e.g.:
```
error: tactic 'rfl' failed, the left-hand side
  (Test.mk (∀ (x : PUnit.{1}), True)).1
is not definitionally equal to the right-hand side
  (Test.mk (∀ (x : PUnit.{2}), True)).1
```
for
```lean
inductive Test where
  | mk (x : Prop)

example : (Test.mk (∀ _ : PUnit.{1}, True)).1 = (Test.mk (∀ _ : PUnit.{2}, True)).1 := by
  rfl
```
2025-05-09 15:07:50 +00:00
Joachim Breitner
0e49576fe4 feat: guard_msgs to treat trace messages separate (#8267)
This PR makes `#guard_msgs` to treat `trace` messages separate from
`info`, `warning` and `error`. It also introduce the ability to say
`#guard_msgs (pass info`, like `(drop info)` so far, and also adds
`(check info)` as the explicit form of `(info)`, for completeness.

Fixes #8266
2025-05-09 05:44:34 +00:00
Kim Morrison
33afaa061e feat: improve 'apply' unification error message (#8261)
This PR adjusts the error message when `apply` fails to unify. It is
clearer about distinguishing the term being applied and the goal, as
well as distinguishing the "conclusion" of the given term and the term
itself.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2025-05-08 16:00:42 +00:00
Markus Himmel
1db53b39c4 chore: improve application type mismatch error message (#8264)
This PR rewords the `application type mismatch` error message by more
specifically mentioning that the problem is with the final argument.
This is useful when the same argument is passed to the function multiple
times.

We decided against using a wording which specifically mentions the
"function expression", because users who are not used to currying might
not think of the `f a` in `f a b` as a function.
2025-05-08 15:34:40 +00:00
jrr6
836d7b703a feat: add labeled subcomponents and helper functions for error messages (#8225)
This PR adds additional infrastructure for error message formatting.
Specifically, it adds convenience formatters for hints and notes,
including the ability to attach code actions to hint messages using a
"Try This"-like widget, along with several convenience formatters for
message data.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2025-05-07 21:15:27 +00:00
Luisa Cicolini
732471fddf chore: fix typo in Int/DivMod/Basic (#8255)
This PR fixes the typo `Int.edivx y` to `Int.ediv x y` in
`Int/DivMod/Basic`
2025-05-07 10:00:12 +00:00
Leonardo de Moura
02cbe4969f fix: exponential compilation times due to inlined instances (#8254)
This PR fixes unintended inlining of `ToJson`, `FromJson`, and `Repr`
instances, which was causing exponential compilation times in `deriving`
clauses for large structures.
2025-05-07 08:27:14 +00:00
plp127
e602bdc80c fix: have rename ignore implementation detail hypotheses (#8241)
This PR changes the behavior of the `rename` tactic to skip over
implementation detail hypotheses when finding a hypothesis to rename.

Closes #8240.
2025-05-07 06:53:13 +00:00
Lean stage0 autoupdater
529fb5c67f chore: update stage0 2025-05-06 18:39:27 +00:00
Joachim Breitner
edcad9a14b chore: post-stage0 fixes for #8171 (#8250) 2025-05-06 17:10:45 +00:00
Cameron Zwarich
cd100b8832 chore: make builtinRuntimeTypes an Array rather than a List (#8249) 2025-05-06 16:27:05 +00:00
Lean stage0 autoupdater
c96dfa54a4 chore: update stage0 2025-05-06 10:10:59 +00:00
Joachim Breitner
898eec78cd feat: FunInd: omit cases proved by contradiction (#8171)
This PR omits cases from functional induction/cases principles that are
implemented `by contradiction` (or, more generally, `False.elim`,
`absurd` or `noConfusion). Breaking change in the sense that there are
fewer goals to prove after using functional induction.

Fixes #8103.
2025-05-06 09:07:33 +00:00
Marc Huisinga
65b37b40ff fix: broken goals accomplished (#8242)
This PR fixes the 'goals accomplished' diagnostics. They were
accidentally broken in #7902.

Regression test tbd in a future PR.
2025-05-06 08:42:36 +00:00
Sebastian Ullrich
af51e3e4b1 fix: make sure all kernel constants are persisted eventually (#8238)
This PR avoids an issue where, through other potential bugs, constants
that are tracked by `Kernel.Environment` but not `Environment` are not
persisted.
2025-05-05 17:20:55 +00:00
Sebastian Ullrich
9c7cb147b9 fix: extern_lib and precompileModules on macOS (#8236)
This PR fixes an issue where the combination of `extern_lib` and
`precompileModules` would lead to "symbol not found" errors.
2025-05-05 14:59:50 +00:00
Kim Morrison
9576e48e1a chore: update release_checklist.py to check new release notes page (#8235) 2025-05-05 13:29:53 +00:00
Kim Morrison
77b9e510fc fix: apply? produces a non-synthetic sorry (#8231)
This PR changes the behaviour of `apply?` so that the `sorry` it uses to
close the goal is non-synthetic. (Recall that correct use of synthetic
sorries requires that the tactic also generates an error message, which
we don't want to do in this situation.) Either this PR or #8230 are
sufficient to defend against the problem reported in #8212.
2025-05-05 12:31:08 +00:00
Sebastian Ullrich
cdb18f48cd fix: ld.so linking on Linux (#8228)
This PR fixes an issue where, depending on the host glibc version,
Lean-built executables fail with an assertion in `ld.so`.
2025-05-05 11:50:59 +00:00
Kim Morrison
208ff3e2b3 feat: upgrades to release_checklist.py script (#8192)
This PR includes upgrades to the `release_checklist.py` script prepared
while releasing v4.20.0-rc1.
2025-05-05 09:03:57 +00:00
Leonardo de Moura
ef603cf37d fix: simplifyBasis (#8226)
This PR fixes the `simplifyBasis` procedure in the commutative ring
procedure in `grind`.
2025-05-05 02:35:52 +00:00
Leonardo de Moura
8cc4505bb1 feat: diagnostics for comm ring procedure in grind (#8224)
This PR adds diagnostic information for the commutative ring procedure
in `grind`.
2025-05-04 22:55:40 +00:00
Mac Malone
70917fac9f feat: lean --setup (#8024)
This PR adds the `--setup` option to the `lean` CLI. It takes a path to
a JSON file containing information about a module's imports and
configuration, superseding that in the module's own file header. This
will be used by Lake to specify paths to module artifacts (e.g., oleans
and ileans) separate from the `LEAN_PATH` schema.

To facilitate JSON serialization of the header data structure, `NameMap`
JSON instances have been added to core, and `LeanOptions` now makes use
of them.
2025-05-03 23:57:37 +00:00
Kim Morrison
132c608ebc chore: more @[grind] annotations for List/Array/Vector (#8218)
This PR continues adding `@[grind]` attributes for List/Array/Vector,
particularly to the lemmas involving the `toList`/`toArray` functions.
2025-05-03 19:28:54 +00:00
Kim Morrison
d005a306f9 chore: cleanup of @[grind] lemmas for Option (#8217) 2025-05-03 18:59:30 +00:00
Kim Morrison
80349ac77b feat: complete addition of @[grind] annotations for Option (#8216)
This PR completes adding `@[grind]` annotations for `Option` lemmas, and
incidentally fills in some `Option` API gaps/defects.
2025-05-03 17:14:25 +00:00
Kim Morrison
6e2e1a4f89 chore: consistently add @[simp] to getKey_eq map lemmas (#8186)
These lemmas were inconsistently marked as `@[simp]`, but they seem
generally useful, so this uniformly marks this lemmas as `@[simp]` for
all map variants.
2025-05-03 16:12:33 +00:00
Cameron Zwarich
afab374305 feat: LCNF -> IR translation (#8211)
This PR adds support for generating IR from the LCNF representation of
the new compiler.
2025-05-03 05:34:37 +00:00
Lean stage0 autoupdater
bc1d30de38 chore: update stage0 2025-05-03 00:16:43 +00:00
Leonardo de Moura
14d647f219 fix: nondeterminism in grind (#8209)
This PR fixes a nondeterminism issue in the `grind` tactic. It was a bug
in the model-based theory combination module.
2025-05-02 20:01:38 +00:00
Henrik Böving
daf7a579ed perf: use less defeq in frequently applied bv_decide simp rules (#8208)
This PR reduces the need for defeq in frequently used bv_decide rewrite
by turning them into simprocs that work on structural equality instead.
As the intended meaning of these rewrites is to simply work with
structural equality anyways this should not change the proving power of
`bv_decide`'s rewriter but just make it faster on certain very large
problems.
2025-05-02 19:15:34 +00:00
Sebastian Ullrich
9f48af3edd fix: cadical distribution on Linux (#8201)
Compile it with the same flags as other executables
2025-05-02 18:25:16 +00:00
Kim Morrison
63cf1052f4 chore: remove grind ext lemmas for List/Array/Vector (#8207) 2025-05-02 17:41:02 +00:00
Kim Morrison
0fd516a1df feat: add simpler getElem_map statements given LawfulBEq for all HashMap variants (#8188)
This PR takes the existing `getElem_map` statements for `HashMap`
variants (also `getElem?`, `getElem!`, and `getD` statements), adds a
prime to their name and an explanatory comment, and replaces the
unprimed statement with a simpler statement that is only true with
`LawfulBEq` present. The original statements which were simp lemmas are
now low priority simp lemmas, so the nicer statements should fire when
`LawfulBEq` is available.
2025-05-02 17:16:35 +00:00
Kim Morrison
34d944c4a9 feat: add ofList_eq_insertMany_empty lemmas for map types (#8182)
This PR adds `ofList_eq_insertMany_empty` lemmas for all the hash/tree
map types, with the exception of
`Std.HashSet.Raw.ofList_eq_insertMany_empty`.
2025-05-02 17:16:23 +00:00
David Thrane Christiansen
7f4f6b3457 doc: add documentation style guide (#8199)
This PR adds a style guide for documentation, including both general
principles and docstring-specific concerns.
2025-05-02 13:05:18 +00:00
Siddharth
43e8288e3f feat: Bitvector 0 equals bitvector 1 iff width is zero (#8202)
This PR adds an inference that was repeatedly needed when proving
`BitVec.msb_sdiv`, and is the symmetric version of
`BitVec.one_eq_zero_iff`
2025-05-02 10:32:01 +00:00
Leonardo de Moura
d26d7973ad fix: theory propagation in grind (#8198)
This PR fixes an issue in the theory propagation used in `grind`. When
two equivalence classes are merged, the core may need to push additional
equalities or disequalities down to the satellite theory solvers (e.g.,
`cutsat`, `comm ring`, etc). Some solvers (e.g. `cutsat`) assume that
all of the core’s invariants hold before they receive those facts.
Propagating immediately therefore risks violating a solver’s
pre-conditions midway through the merge. To decouple the merge operation
from propagation and to keep the core solver-agnostic, this PR adds the
helper type `PendingTheoryPropagation`.
2025-05-02 02:19:56 +00:00
Leonardo de Moura
1143b4766c chore: remove dead code (#8197) 2025-05-02 01:33:41 +00:00
750 changed files with 11478 additions and 5349 deletions

View File

@@ -5,7 +5,7 @@ option(USE_MIMALLOC "use mimalloc" ON)
# store all variables passed on the command line into CL_ARGS so we can pass them to the stage builds
# https://stackoverflow.com/a/48555098/161659
# MUST be done before call to 'project'
# Use standard release build (discarding LEAN_CXX_EXTRA_FLAGS etc.) for stage0 by default since it is assumed to be "good", but still pass through CMake platform arguments (compiler, toolchain file, ..).
# Use standard release build (discarding LEAN_EXTRA_CXX_FLAGS etc.) for stage0 by default since it is assumed to be "good", but still pass through CMake platform arguments (compiler, toolchain file, ..).
# Use `STAGE0_` prefix to pass variables to stage0 explicitly.
get_cmake_property(vars CACHE_VARIABLES)
foreach(var ${vars})
@@ -39,10 +39,14 @@ endif()
# Don't do anything with cadical on wasm
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
# On CI Linux, we source cadical from Nix instead; see flake.nix
find_program(CADICAL cadical)
if(NOT CADICAL)
set(CADICAL_CXX c++)
if (CADICAL_USE_CUSTOM_CXX)
set(CADICAL_CXX ${CMAKE_CXX_COMPILER})
set(CADICAL_CXXFLAGS "${LEAN_EXTRA_CXX_FLAGS}")
set(CADICAL_LDFLAGS "-Wl,-rpath=\\$$ORIGIN/../lib")
endif()
find_program(CCACHE ccache)
if(CCACHE)
set(CADICAL_CXX "${CCACHE} ${CADICAL_CXX}")
@@ -57,8 +61,11 @@ if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
GIT_REPOSITORY https://github.com/arminbiere/cadical
GIT_TAG rel-2.1.2
CONFIGURE_COMMAND ""
# https://github.com/arminbiere/cadical/blob/master/BUILD.md#manual-build
BUILD_COMMAND $(MAKE) -f ${CMAKE_SOURCE_DIR}/src/cadical.mk CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} CXX=${CADICAL_CXX} CXXFLAGS=${CADICAL_CXXFLAGS}
BUILD_COMMAND $(MAKE) -f ${CMAKE_SOURCE_DIR}/src/cadical.mk
CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX}
CXX=${CADICAL_CXX}
CXXFLAGS=${CADICAL_CXXFLAGS}
LDFLAGS=${CADICAL_LDFLAGS}
BUILD_IN_SOURCE ON
INSTALL_COMMAND "")
set(CADICAL ${CMAKE_BINARY_DIR}/cadical/cadical${CMAKE_EXECUTABLE_SUFFIX} CACHE FILEPATH "path to cadical binary" FORCE)

View File

@@ -7,8 +7,9 @@
/.github/ @kim-em
/RELEASES.md @kim-em
/src/kernel/ @leodemoura
/src/library/compiler/ @zwarich
/src/lake/ @tydeu
/src/Lean/Compiler/ @leodemoura
/src/Lean/Compiler/ @leodemoura @zwarich
/src/Lean/Data/Lsp/ @mhuisi
/src/Lean/Elab/Deriving/ @kim-em
/src/Lean/Elab/Tactic/ @kim-em

View File

@@ -144,6 +144,10 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
- Run `script/release_steps.py v4.7.0-rc1 <repo>` (e.g. replacing `<repo>` with `batteries`), which will walk you through the following steps:
- Create a new branch off `master`/`main` (as specified in the `branch` field), called `bump_to_v4.7.0-rc1`.
- Merge `origin/bump/v4.7.0` if relevant (i.e. `bump-branch: true` appears in `release_repos.yml`).
- Otherwise, you *may* need to merge `origin/nightly-testing`.
- Note that for `verso` and `reference-manual` development happens on `nightly-testing`, so
we will merge that branch into `bump_to_v4.7.0-rc1`, but it is essential in the GitHub interface that we do a rebase merge,
in order to preserve the history.
- Update the contents of `lean-toolchain` to `leanprover/lean4:v4.7.0-rc1`.
- In the `lakefile.toml` or `lakefile.lean`, if there are dependencies on `nightly-testing`, `bump/v4.7.0`, or specific version tags, update them to the new tag.
If they depend on `main` or `master`, don't change this; you've just updated the dependency, so `lake update` will take care of modifying the manifest.
@@ -151,7 +155,7 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
- Run `lake build && if lake check-test; then lake test; fi` to check things are working.
- Commit the changes as `chore: bump toolchain to v4.7.0-rc1` and push.
- Create a PR with title "chore: bump toolchain to v4.7.0-rc1".
- Merge the PR once CI completes.
- Merge the PR once CI completes. (Recall: for `verso` and `reference-manual` you will need to do a rebase merge.)
- Re-running `script/release_checklist.py` will then create the tag `v4.7.0-rc1` from `master`/`main` and push it (unless `toolchain-tag: false` in the `release_repos.yml` file)
- We do this for the same list of repositories as for stable releases, see above for notes about special cases.
As above, there are dependencies between these, and so the process above is iterative.

1146
doc/style.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -47,10 +47,10 @@ def run_command(command, check=True, capture_output=True):
def clone_repo(repo, temp_dir):
"""Clone the repository to a temporary directory using shallow clone."""
print(f"Shallow cloning {repo}...")
# Keep the shallow clone for efficiency
clone_result = run_command(f"gh repo clone {repo} {temp_dir} -- --depth=1", check=False)
"""Clone the repository to a temporary directory."""
print(f"Cloning {repo}...")
# Remove shallow clone for better merge detection
clone_result = run_command(f"gh repo clone {repo} {temp_dir}", check=False)
if clone_result.returncode != 0:
print(f"Failed to clone repository {repo}.")
print(f"Error: {clone_result.stderr}")
@@ -95,26 +95,16 @@ def check_and_merge(repo, branch, tag, temp_dir):
if checkout_result.returncode != 0:
return False
# Try merging the tag in a dry-run to check if it can be merged cleanly
print(f"Checking if {tag} can be merged cleanly into {branch}...")
merge_check = run_command(f"git merge --no-commit --no-ff {tag}", check=False)
# Try merging the tag directly
print(f"Merging {tag} into {branch}...")
merge_result = run_command(f"git merge {tag} --no-edit", check=False)
if merge_check.returncode != 0:
if merge_result.returncode != 0:
print(f"Cannot merge {tag} cleanly into {branch}.")
print("Merge conflicts would occur. Aborting merge.")
run_command("git merge --abort")
return False
# Abort the test merge
run_command("git reset --hard HEAD")
# Now perform the actual merge and push to remote
print(f"Merging {tag} into {branch}...")
merge_result = run_command(f"git merge {tag} --no-edit")
if merge_result.returncode != 0:
print(f"Failed to merge {tag} into {branch}.")
return False
print(f"Pushing changes to remote...")
push_result = run_command(f"git push origin {branch}")
if push_result.returncode != 0:

View File

@@ -55,7 +55,8 @@ $CP $GLIBC/lib/libc_nonshared.a stage1/lib/glibc
$CP $GLIBC/lib/libpthread_nonshared.a stage1/lib/glibc
for f in $GLIBC/lib/{ld,lib{c,dl,m,rt,pthread}}-*; do b=$(basename $f); cp $f stage1/lib/glibc/${b%-*}.so; done
OPTIONS=()
echo -n " -DLEAN_STANDALONE=ON"
# We build cadical using the custom toolchain on Linux to avoid glibc versioning issues
echo -n " -DLEAN_STANDALONE=ON -DCADICAL_USE_CUSTOM_CXX=ON"
echo -n " -DCMAKE_CXX_COMPILER=$PWD/llvm-host/bin/clang++ -DLEAN_CXX_STDLIB='-Wl,-Bstatic -lc++ -lc++abi -Wl,-Bdynamic'"
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter $GLIBC_DEV/include ${EXTRA_FLAGS:-}'"
# use target compiler directly when not cross-compiling
@@ -67,8 +68,9 @@ fi
# use `-nostdinc` to make sure headers are not visible by default (in particular, not to `#include_next` in the clang headers),
# but do not change sysroot so users can still link against system libs
echo -n " -DLEANC_INTERNAL_FLAGS='--sysroot ROOT -nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
# ld.so is usually included by the libc.so linker script but we discard those
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='--sysroot ROOT -L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a ROOT/lib/glibc/libpthread_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -Wl,-Bdynamic ROOT/lib/glibc/ld.so -Wl,--no-as-needed -fuse-ld=lld'"
# ld.so is usually included by the libc.so linker script but we discard those. Make sure it is linked to only after `libc.so` like in the original
# linker script so that no libc symbols are bound to it instead.
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='--sysroot ROOT -L ROOT/lib -L ROOT/lib/glibc -lc -lc_nonshared -Wl,--as-needed -l:ld.so -Wl,--no-as-needed -lpthread_nonshared -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
# when not using the above flags, link GMP dynamically/as usual
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-Wl,--as-needed -lgmp -luv -lpthread -ldl -lrt -Wl,--no-as-needed'"
# do not set `LEAN_CC` for tests

View File

@@ -7,6 +7,7 @@ import base64
import subprocess
import sys
import os
import re # Import re module
# Import run_command from merge_remote.py
from merge_remote import run_command
@@ -58,13 +59,29 @@ def release_page_exists(repo_url, tag_name, github_token):
response = requests.get(api_url, headers=headers)
return response.status_code == 200
def get_release_notes(repo_url, tag_name, github_token):
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/releases/tags/{tag_name}"
headers = {'Authorization': f'token {github_token}'} if github_token else {}
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return response.json().get("body", "").strip()
return None
def get_release_notes(tag_name):
"""Fetch release notes page title from lean-lang.org."""
# Strip -rcX suffix if present for the URL
base_tag = tag_name.split('-')[0]
reference_url = f"https://lean-lang.org/doc/reference/latest/releases/{base_tag}/"
try:
response = requests.get(reference_url)
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
# Extract title using regex
match = re.search(r"<title>(.*?)</title>", response.text, re.IGNORECASE | re.DOTALL)
if match:
return match.group(1).strip()
else:
print(f" ⚠️ Could not find <title> tag in {reference_url}")
return None
except requests.exceptions.RequestException as e:
print(f" ❌ Error fetching release notes from {reference_url}: {e}")
return None
except Exception as e:
print(f" ❌ An unexpected error occurred while processing release notes: {e}")
return None
def get_branch_content(repo_url, branch, file_path, github_token):
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/contents/{file_path}?ref={branch}"
@@ -255,6 +272,7 @@ def main():
branch_name = f"releases/v{version_major}.{version_minor}.0"
if not branch_exists(lean_repo_url, branch_name, github_token):
print(f" ❌ Branch {branch_name} does not exist")
print(f" 🟡 After creating the branch, we'll need to check CMake version settings.")
lean4_success = False
else:
print(f" ✅ Branch {branch_name} exists")
@@ -274,14 +292,22 @@ def main():
lean4_success = False
else:
print(f" ✅ Release page for {toolchain} exists")
release_notes = get_release_notes(lean_repo_url, toolchain, github_token)
if not (release_notes and toolchain in release_notes.splitlines()[0].strip()):
previous_minor_version = version_minor - 1
previous_release = f"v{version_major}.{previous_minor_version}.0"
print(f" ❌ Release notes not published. Please run `script/release_notes.py --since {previous_release}` on branch `{branch_name}`.")
lean4_success = False
else:
print(f" ✅ Release notes look good.")
# Check the actual release notes page title
actual_title = get_release_notes(toolchain)
expected_title_prefix = f"Lean {toolchain.lstrip('v')}" # e.g., "Lean 4.19.0" or "Lean 4.19.0-rc1"
if actual_title is None:
# Error already printed by get_release_notes
lean4_success = False
elif not actual_title.startswith(expected_title_prefix):
# Construct URL for the error message (using the base tag)
base_tag = toolchain.split('-')[0]
check_url = f"https://lean-lang.org/doc/reference/latest/releases/{base_tag}/"
print(f" ❌ Release notes page title mismatch. Expected prefix '{expected_title_prefix}', got '{actual_title}'. Check {check_url}")
lean4_success = False
else:
print(f" ✅ Release notes page title looks good ('{actual_title}').")
repo_status["lean4"] = lean4_success
@@ -360,10 +386,24 @@ def main():
if check_stable and not is_release_candidate(toolchain):
if not is_merged_into_stable(url, toolchain, "stable", github_token, verbose):
org_repo = extract_org_repo_from_url(url)
print(f" ❌ Tag {toolchain} is not merged into stable")
print(f" Run `script/merge_remote.py {org_repo} stable {toolchain}` to merge it")
repo_status[name] = False
continue
if args.dry_run:
print(f" ❌ Tag {toolchain} is not merged into stable")
print(f" Run `script/merge_remote.py {org_repo} stable {toolchain}` to merge it")
repo_status[name] = False
continue
else:
print(f" … Tag {toolchain} is not merged into stable. Running `script/merge_remote.py {org_repo} stable {toolchain}`...")
# Run the script to merge the tag
subprocess.run(["script/merge_remote.py", org_repo, "stable", toolchain])
# Check again if the tag is merged now
if not is_merged_into_stable(url, toolchain, "stable", github_token, verbose):
print(f" ❌ Manual intervention required.")
repo_status[name] = False
continue
# This will print in all successful cases - whether tag was merged initially or was merged successfully
print(f" ✅ Tag {toolchain} is merged into stable")
if check_bump:

View File

@@ -21,12 +21,19 @@ repositories:
branch: master
dependencies: []
- name: lean4-cli
url: https://github.com/leanprover/lean4-cli
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: doc-gen4
url: https://github.com/leanprover/doc-gen4
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
dependencies: [lean4-cli]
- name: verso
url: https://github.com/leanprover/verso
@@ -42,20 +49,13 @@ repositories:
branch: main
dependencies: [verso]
- name: lean4-cli
url: https://github.com/leanprover/lean4-cli
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: ProofWidgets4
url: https://github.com/leanprover-community/ProofWidgets4
toolchain-tag: false
stable-branch: false
branch: main
dependencies:
- Batteries
- batteries
- name: aesop
url: https://github.com/leanprover-community/aesop
@@ -63,7 +63,7 @@ repositories:
stable-branch: true
branch: master
dependencies:
- Batteries
- batteries
- name: import-graph
url: https://github.com/leanprover-community/import-graph
@@ -71,8 +71,8 @@ repositories:
stable-branch: false
branch: main
dependencies:
- Cli
- Batteries
- lean4-cli
- batteries
- name: plausible
url: https://github.com/leanprover-community/plausible
@@ -88,10 +88,11 @@ repositories:
branch: master
bump-branch: true
dependencies:
- Aesop
- aesop
- ProofWidgets4
- lean4checker
- Batteries
- batteries
- lean4-cli
- doc-gen4
- import-graph
- plausible
@@ -102,4 +103,4 @@ repositories:
stable-branch: true
branch: master
dependencies:
- Mathlib
- mathlib4

View File

@@ -68,7 +68,7 @@ def generate_script(repo, version, config):
]
# Special cases for specific repositories
if repo_name == "REPL":
if repo_name == "repl":
script_lines.extend([
"lake update",
"cd test/Mathlib",
@@ -79,7 +79,7 @@ def generate_script(repo, version, config):
"./test.sh"
])
elif dependencies:
script_lines.append('echo "Please update the dependencies in lakefile.{lean,toml}"')
script_lines.append('perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*')
script_lines.append("lake update")
script_lines.append("")
@@ -89,13 +89,20 @@ def generate_script(repo, version, config):
""
])
if re.search(r'rc\d+$', version) and repo_name in ["Batteries", "Mathlib"]:
if re.search(r'rc\d+$', version) and repo_name in ["batteries", "mathlib4"]:
script_lines.extend([
"echo 'This repo has nightly-testing infrastructure'",
f"git merge origin/bump/{version.split('-rc')[0]}",
"echo 'Please resolve any conflicts.'",
""
])
if re.search(r'rc\d+$', version) and repo_name in ["verso", "reference-manual"]:
script_lines.extend([
"echo 'This repo does development on nightly-testing: remember to rebase merge the PR.'",
f"git merge origin/nightly-testing",
"echo 'Please resolve any conflicts.'",
""
])
if repo_name != "Mathlib":
script_lines.extend([
"lake build && if lake check-test; then lake test; fi",
@@ -104,7 +111,7 @@ def generate_script(repo, version, config):
script_lines.extend([
'gh pr create --title "chore: bump toolchain to ' + version + '" --body ""',
"echo 'Please review the PR and merge it.'",
"echo 'Please review the PR and merge or rebase it.'",
""
])

View File

@@ -10,7 +10,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 20)
set(LEAN_VERSION_MINOR 21)
set(LEAN_VERSION_PATCH 0)
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
@@ -511,7 +511,10 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# import libraries created by the stdlib.make targets
string(APPEND LEANC_SHARED_LINKER_FLAGS " -lInit_shared -lleanshared_1 -lleanshared")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
string(APPEND LEANC_SHARED_LINKER_FLAGS " -Wl,-undefined,dynamic_lookup")
# The second flag is necessary to even *load* dylibs without resolved symbols, as can happen
# if a Lake `extern_lib` depends on a symbols defined by the Lean library but is loaded even
# before definition.
string(APPEND LEANC_SHARED_LINKER_FLAGS " -Wl,-undefined,dynamic_lookup -Wl,-no_fixup_chains")
endif()
# Linux ignores undefined symbols in shared libraries by default

View File

@@ -42,24 +42,3 @@ theorem apply_ite (f : α → β) (P : Prop) [Decidable P] (x y : α) :
/-- A `dite` whose results do not actually depend on the condition may be reduced to an `ite`. -/
@[simp] theorem dite_eq_ite [Decidable P] :
(dite P (fun _ => a) (fun _ => b)) = ite P a b := rfl
@[deprecated "Use `ite_eq_right_iff`" (since := "2024-09-18")]
theorem ite_some_none_eq_none [Decidable P] :
(if P then some x else none) = none ¬ P := by
simp only [ite_eq_right_iff, reduceCtorEq]
rfl
@[deprecated "Use `Option.ite_none_right_eq_some`" (since := "2024-09-18")]
theorem ite_some_none_eq_some [Decidable P] :
(if P then some x else none) = some y P x = y := by
split <;> simp_all
@[deprecated "Use `dite_eq_right_iff" (since := "2024-09-18")]
theorem dite_some_none_eq_none [Decidable P] {x : P α} :
(if h : P then some (x h) else none) = none ¬P := by
simp
@[deprecated "Use `Option.dite_none_right_eq_some`" (since := "2024-09-18")]
theorem dite_some_none_eq_some [Decidable P] {x : P α} {y : α} :
(if h : P then some (x h) else none) = some y h : P, x h = y := by
by_cases h : P <;> simp [h]

View File

@@ -51,6 +51,9 @@ theorem Function.comp_def {α β δ} (f : β → δ) (g : α → β) : f ∘ g =
@[simp] theorem Function.false_comp {f : α β} : ((fun _ => false) f) = fun _ => false := by
rfl
@[simp] theorem Function.comp_id (f : α β) : f id = f := rfl
@[simp] theorem Function.id_comp (f : α β) : id f = f := rfl
attribute [simp] namedPattern
/--
@@ -2524,9 +2527,6 @@ class Antisymm (r : αα → Prop) : Prop where
/-- An antisymmetric relation `r` satisfies `r a b → r b a → a = b`. -/
antisymm (a b : α) : r a b r b a a = b
@[deprecated Antisymm (since := "2024-10-16"), inherit_doc Antisymm]
abbrev _root_.Antisymm (r : α α Prop) : Prop := Std.Antisymm r
/-- `Asymm X r` means that the binary relation `r` on `X` is asymmetric, that is,
`r a b → ¬ r b a`. -/
class Asymm (r : α α Prop) : Prop where

View File

@@ -56,15 +56,15 @@ well-founded recursion mechanism to prove that the function terminates.
-/
@[inline] def attach (xs : Array α) : Array {x // x xs} := xs.attachWith _ fun _ => id
@[simp] theorem _root_.List.attachWith_toArray {l : List α} {P : α Prop} {H : x l.toArray, P x} :
@[simp, grind =] theorem _root_.List.attachWith_toArray {l : List α} {P : α Prop} {H : x l.toArray, P x} :
l.toArray.attachWith P H = (l.attachWith P (by simpa using H)).toArray := by
simp [attachWith]
@[simp] theorem _root_.List.attach_toArray {l : List α} :
@[simp, grind =] theorem _root_.List.attach_toArray {l : List α} :
l.toArray.attach = (l.attachWith (· l.toArray) (by simp)).toArray := by
simp [attach]
@[simp] theorem _root_.List.pmap_toArray {l : List α} {P : α Prop} {f : a, P a β} {H : a l.toArray, P a} :
@[simp, grind =] theorem _root_.List.pmap_toArray {l : List α} {P : α Prop} {f : a, P a β} {H : a l.toArray, P a} :
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
simp [pmap]
@@ -590,7 +590,7 @@ def unattach {α : Type _} {p : α → Prop} (xs : Array { x // p x }) : Array
unfold unattach
simp
@[simp] theorem _root_.List.unattach_toArray {p : α Prop} {xs : List { x // p x }} :
@[simp, grind =] theorem _root_.List.unattach_toArray {p : α Prop} {xs : List { x // p x }} :
xs.toArray.unattach = xs.unattach.toArray := by
simp only [unattach, List.map_toArray, List.unattach]

View File

@@ -36,8 +36,6 @@ variable {α : Type u}
namespace Array
@[deprecated toList (since := "2024-09-10")] abbrev data := @toList
/-! ### Preliminary theorems -/
@[simp, grind] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
@@ -88,11 +86,11 @@ theorem ext' {xs ys : Array α} (h : xs.toList = ys.toList) : xs = ys := by
@[simp] theorem toArrayAux_eq {as : List α} {acc : Array α} : (as.toArrayAux acc).toList = acc.toList ++ as := by
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
@[simp] theorem toArray_toList {xs : Array α} : xs.toList.toArray = xs := rfl
@[simp, grind =] theorem toArray_toList {xs : Array α} : xs.toList.toArray = xs := rfl
@[simp] theorem getElem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i] := rfl
@[simp, grind =] theorem getElem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i] := rfl
@[simp] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
@[simp, grind =] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
simp [getElem?_def]
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
@@ -107,7 +105,7 @@ instance : Membership α (Array α) where
theorem mem_def {a : α} {as : Array α} : a as a as.toList :=
fun | .mk h => h, Array.Mem.mk
@[simp] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
simp [mem_def]
@[simp, grind] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] xs := by
@@ -127,18 +125,18 @@ theorem toList_toArray {as : List α} : as.toArray.toList = as := rfl
@[deprecated toList_toArray (since := "2025-02-17")]
abbrev _root_.Array.toList_toArray := @List.toList_toArray
@[simp] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
@[simp, grind] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
@[deprecated size_toArray (since := "2025-02-17")]
abbrev _root_.Array.size_toArray := @List.size_toArray
@[simp] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
@[simp, grind =] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := rfl
@[simp] theorem getElem?_toArray {xs : List α} {i : Nat} : xs.toArray[i]? = xs[i]? := by
@[simp, grind =] theorem getElem?_toArray {xs : List α} {i : Nat} : xs.toArray[i]? = xs[i]? := by
simp [getElem?_def]
@[simp] theorem getElem!_toArray [Inhabited α] {xs : List α} {i : Nat} :
@[simp, grind =] theorem getElem!_toArray [Inhabited α] {xs : List α} {i : Nat} :
xs.toArray[i]! = xs[i]! := by
simp [getElem!_def]
@@ -148,8 +146,6 @@ namespace Array
theorem size_eq_length_toList {xs : Array α} : xs.size = xs.toList.length := rfl
@[deprecated toList_toArray (since := "2024-09-09")] abbrev data_toArray := @List.toList_toArray
/-! ### Externs -/
/--
@@ -1487,8 +1483,6 @@ The resulting arrays are appended.
def flatMapM [Monad m] (f : α m (Array β)) (as : Array α) : m (Array β) :=
as.foldlM (init := empty) fun bs a => do return bs ++ ( f a)
@[deprecated flatMapM (since := "2024-10-16")] abbrev concatMapM := @flatMapM
/--
Applies a function that returns an array to each element of an array. The resulting arrays are
appended.
@@ -1501,8 +1495,6 @@ Examples:
def flatMap (f : α Array β) (as : Array α) : Array β :=
as.foldl (init := empty) fun bs a => bs ++ f a
@[deprecated flatMap (since := "2024-10-16")] abbrev concatMap := @flatMap
/--
Appends the contents of array of arrays into a single array. The resulting array contains the same
elements as the nested arrays in the same order.
@@ -2158,13 +2150,15 @@ Examples:
/-! ### Repr and ToString -/
protected def Array.repr {α : Type u} [Repr α] (xs : Array α) : Std.Format :=
let _ : Std.ToFormat α := repr
if xs.size == 0 then
"#[]"
else
Std.Format.bracketFill "#[" (Std.Format.joinSep (toList xs) ("," ++ Std.Format.line)) "]"
instance {α : Type u} [Repr α] : Repr (Array α) where
reprPrec xs _ :=
let _ : Std.ToFormat α := repr
if xs.size == 0 then
"#[]"
else
Std.Format.bracketFill "#[" (Std.Format.joinSep (toList xs) ("," ++ Std.Format.line)) "]"
reprPrec xs _ := Array.repr xs
instance [ToString α] : ToString (Array α) where
toString xs := "#" ++ toString xs.toList

View File

@@ -55,12 +55,12 @@ theorem foldlM_toList.aux [Monad m]
rfl
· rw [List.drop_of_length_le (Nat.ge_of_not_lt _)]; rfl
@[simp] theorem foldlM_toList [Monad m]
@[simp, grind =] theorem foldlM_toList [Monad m]
{f : β α m β} {init : β} {xs : Array α} :
xs.toList.foldlM f init = xs.foldlM f init := by
simp [foldlM, foldlM_toList.aux]
@[simp] theorem foldl_toList (f : β α β) {init : β} {xs : Array α} :
@[simp, grind =] theorem foldl_toList (f : β α β) {init : β} {xs : Array α} :
xs.toList.foldl f init = xs.foldl f init :=
List.foldl_eq_foldlM .. foldlM_toList ..
@@ -79,32 +79,32 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] {f : α → β → m β} {init
match xs, this with | _, .inl rfl => rfl | xs, .inr h => ?_
simp [foldrM, h, foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
@[simp] theorem foldrM_toList [Monad m]
@[simp, grind =] theorem foldrM_toList [Monad m]
{f : α β m β} {init : β} {xs : Array α} :
xs.toList.foldrM f init = xs.foldrM f init := by
rw [foldrM_eq_reverse_foldlM_toList, List.foldlM_reverse]
@[simp] theorem foldr_toList (f : α β β) {init : β} {xs : Array α} :
@[simp, grind =] theorem foldr_toList (f : α β β) {init : β} {xs : Array α} :
xs.toList.foldr f init = xs.foldr f init :=
List.foldr_eq_foldrM .. foldrM_toList ..
@[simp] theorem push_toList {xs : Array α} {a : α} : (xs.push a).toList = xs.toList ++ [a] := by
@[simp, grind =] theorem push_toList {xs : Array α} {a : α} : (xs.push a).toList = xs.toList ++ [a] := by
simp [push, List.concat_eq_append]
@[simp] theorem toListAppend_eq {xs : Array α} {l : List α} : xs.toListAppend l = xs.toList ++ l := by
@[simp, grind =] theorem toListAppend_eq {xs : Array α} {l : List α} : xs.toListAppend l = xs.toList ++ l := by
simp [toListAppend, foldr_toList]
@[simp] theorem toListImpl_eq {xs : Array α} : xs.toListImpl = xs.toList := by
@[simp, grind =] theorem toListImpl_eq {xs : Array α} : xs.toListImpl = xs.toList := by
simp [toListImpl, foldr_toList]
@[simp] theorem toList_pop {xs : Array α} : xs.pop.toList = xs.toList.dropLast := rfl
@[simp, grind =] theorem toList_pop {xs : Array α} : xs.pop.toList = xs.toList.dropLast := rfl
@[deprecated toList_pop (since := "2025-02-17")]
abbrev pop_toList := @Array.toList_pop
@[simp] theorem append_eq_append {xs ys : Array α} : xs.append ys = xs ++ ys := rfl
@[simp] theorem toList_append {xs ys : Array α} :
@[simp, grind =] theorem toList_append {xs ys : Array α} :
(xs ++ ys).toList = xs.toList ++ ys.toList := by
rw [ append_eq_append]; unfold Array.append
rw [ foldl_toList]
@@ -112,13 +112,13 @@ abbrev pop_toList := @Array.toList_pop
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
@[simp, grind] theorem append_empty {xs : Array α} : xs ++ #[] = xs := by
@[simp, grind =] theorem append_empty {xs : Array α} : xs ++ #[] = xs := by
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
@[deprecated append_empty (since := "2025-01-13")]
abbrev append_nil := @append_empty
@[simp, grind] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
@[simp, grind =] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
@[deprecated empty_append (since := "2025-01-13")]
@@ -129,7 +129,7 @@ abbrev nil_append := @empty_append
@[simp] theorem appendList_eq_append {xs : Array α} {l : List α} : xs.appendList l = xs ++ l := rfl
@[simp] theorem toList_appendList {xs : Array α} {l : List α} :
@[simp, grind =] theorem toList_appendList {xs : Array α} {l : List α} :
(xs ++ l).toList = xs.toList ++ l := by
rw [ appendList_eq_append]; unfold Array.appendList
induction l generalizing xs <;> simp [*]
@@ -159,34 +159,4 @@ theorem foldl_eq_foldl_toList {f : β → α → β} {init : β} {xs : Array α}
xs.foldl f init = xs.toList.foldl f init:= by
simp
@[deprecated foldlM_toList (since := "2024-09-09")]
abbrev foldlM_eq_foldlM_data := @foldlM_toList
@[deprecated foldl_toList (since := "2024-09-09")]
abbrev foldl_eq_foldl_data := @foldl_toList
@[deprecated foldrM_eq_reverse_foldlM_toList (since := "2024-09-09")]
abbrev foldrM_eq_reverse_foldlM_data := @foldrM_eq_reverse_foldlM_toList
@[deprecated foldrM_toList (since := "2024-09-09")]
abbrev foldrM_eq_foldrM_data := @foldrM_toList
@[deprecated foldr_toList (since := "2024-09-09")]
abbrev foldr_eq_foldr_data := @foldr_toList
@[deprecated push_toList (since := "2024-09-09")]
abbrev push_data := @push_toList
@[deprecated toListImpl_eq (since := "2024-09-09")]
abbrev toList_eq := @toListImpl_eq
@[deprecated pop_toList (since := "2024-09-09")]
abbrev pop_data := @toList_pop
@[deprecated toList_append (since := "2024-09-09")]
abbrev append_data := @toList_append
@[deprecated toList_appendList (since := "2024-09-09")]
abbrev appendList_data := @toList_appendList
end Array

View File

@@ -25,7 +25,7 @@ section countP
variable {p q : α Bool}
@[simp] theorem _root_.List.countP_toArray {l : List α} : countP p l.toArray = l.countP p := by
@[simp, grind =] theorem _root_.List.countP_toArray {l : List α} : countP p l.toArray = l.countP p := by
simp [countP]
induction l with
| nil => rfl
@@ -33,7 +33,7 @@ variable {p q : α → Bool}
simp only [List.foldr_cons, ih, List.countP_cons]
split <;> simp_all
@[simp] theorem countP_toList {xs : Array α} : xs.toList.countP p = countP p xs := by
@[simp, grind =] theorem countP_toList {xs : Array α} : xs.toList.countP p = countP p xs := by
cases xs
simp
@@ -164,10 +164,10 @@ section count
variable [BEq α]
@[simp] theorem _root_.List.count_toArray {l : List α} {a : α} : count a l.toArray = l.count a := by
@[simp, grind =] theorem _root_.List.count_toArray {l : List α} {a : α} : count a l.toArray = l.count a := by
simp [count, List.count_eq_countP]
@[simp] theorem count_toList {xs : Array α} {a : α} : xs.toList.count a = xs.count a := by
@[simp, grind =] theorem count_toList {xs : Array α} {a : α} : xs.toList.count a = xs.count a := by
cases xs
simp

View File

@@ -68,7 +68,7 @@ theorem isEqv_eq_decide (xs ys : Array α) (r) :
Bool.not_eq_true]
simpa [isEqv_iff_rel] using h'
@[simp] theorem isEqv_toList [BEq α] (xs ys : Array α) : (xs.toList.isEqv ys.toList r) = (xs.isEqv ys r) := by
@[simp, grind =] theorem isEqv_toList [BEq α] (xs ys : Array α) : (xs.toList.isEqv ys.toList r) = (xs.isEqv ys r) := by
simp [isEqv_eq_decide, List.isEqv_eq_decide]
theorem eq_of_isEqv [DecidableEq α] (xs ys : Array α) (h : Array.isEqv xs ys (fun x y => x = y)) : xs = ys := by
@@ -99,17 +99,17 @@ theorem beq_eq_decide [BEq α] (xs ys : Array α) :
decide ( (i : Nat) (h' : i < xs.size), xs[i] == ys[i]'(h h')) else false := by
simp [BEq.beq, isEqv_eq_decide]
@[simp] theorem beq_toList [BEq α] (xs ys : Array α) : (xs.toList == ys.toList) = (xs == ys) := by
@[simp, grind =] theorem beq_toList [BEq α] (xs ys : Array α) : (xs.toList == ys.toList) = (xs == ys) := by
simp [beq_eq_decide, List.beq_eq_decide]
end Array
namespace List
@[simp] theorem isEqv_toArray [BEq α] (as bs : List α) : (as.toArray.isEqv bs.toArray r) = (as.isEqv bs r) := by
@[simp, grind =] theorem isEqv_toArray [BEq α] (as bs : List α) : (as.toArray.isEqv bs.toArray r) = (as.isEqv bs r) := by
simp [isEqv_eq_decide, Array.isEqv_eq_decide]
@[simp] theorem beq_toArray [BEq α] (as bs : List α) : (as.toArray == bs.toArray) = (as == bs) := by
@[simp, grind =] theorem beq_toArray [BEq α] (as bs : List α) : (as.toArray == bs.toArray) = (as == bs) := by
simp [beq_eq_decide, Array.beq_eq_decide]
end List

View File

@@ -39,10 +39,10 @@ namespace Array
@[simp] theorem toList_eq_nil_iff {xs : Array α} : xs.toList = [] xs = #[] := by
cases xs <;> simp
@[simp] theorem mem_toList_iff {a : α} {xs : Array α} : a xs.toList a xs := by
@[simp, grind =] theorem mem_toList_iff {a : α} {xs : Array α} : a xs.toList a xs := by
cases xs <;> simp
@[simp] theorem length_toList {xs : Array α} : xs.toList.length = xs.size := rfl
@[simp, grind =] theorem length_toList {xs : Array α} : xs.toList.length = xs.size := rfl
theorem eq_toArray : xs = List.toArray as xs.toList = as := by
cases xs
@@ -78,6 +78,7 @@ theorem ne_empty_of_size_pos (h : 0 < xs.size) : xs ≠ #[] := by
cases xs
simpa using List.ne_nil_of_length_pos h
@[grind]
theorem size_eq_zero_iff : xs.size = 0 xs = #[] :=
eq_empty_of_size_eq_zero, fun h => h rfl
@@ -527,7 +528,7 @@ theorem forall_getElem {xs : Array α} {p : α → Prop} :
rcases xs with xs
simp
@[simp] theorem isEmpty_toList {xs : Array α} : xs.toList.isEmpty = xs.isEmpty := by
@[simp, grind =] theorem isEmpty_toList {xs : Array α} : xs.toList.isEmpty = xs.isEmpty := by
rcases xs with _ | _ <;> simp
theorem isEmpty_eq_false_iff_exists_mem {xs : Array α} :
@@ -592,7 +593,7 @@ theorem anyM_loop_cons [Monad m] {p : α → m Bool} {a : α} {as : List α} {st
· rw [dif_neg]
omega
@[simp] theorem anyM_toList [Monad m] {p : α m Bool} {as : Array α} :
@[simp, grind =] theorem anyM_toList [Monad m] {p : α m Bool} {as : Array α} :
as.toList.anyM p = as.anyM p :=
match as with
| [] => by simp [anyM, anyM.loop]
@@ -651,7 +652,7 @@ theorem any_iff_exists {p : α → Bool} {as : Array α} {start stop} :
rw [Bool.eq_false_iff, Ne, any_eq_true]
simp
@[simp] theorem any_toList {p : α Bool} {as : Array α} : as.toList.any p = as.any p := by
@[simp, grind =] theorem any_toList {p : α Bool} {as : Array α} : as.toList.any p = as.any p := by
rw [Bool.eq_iff_iff, any_eq_true, List.any_eq_true]
simp only [List.mem_iff_getElem, getElem_toList]
exact fun _, i, w, rfl, h => i, w, h, fun i, w, h => _, i, w, rfl, h
@@ -661,7 +662,7 @@ theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] {p : α → m Bool} {as :
dsimp [allM, anyM]
simp
@[simp] theorem allM_toList [Monad m] [LawfulMonad m] {p : α m Bool} {as : Array α} :
@[simp, grind =] theorem allM_toList [Monad m] [LawfulMonad m] {p : α m Bool} {as : Array α} :
as.toList.allM p = as.allM p := by
rw [allM_eq_not_anyM_not]
rw [ anyM_toList]
@@ -690,7 +691,7 @@ theorem all_iff_forall {p : α → Bool} {as : Array α} {start stop} :
rw [Bool.eq_false_iff, Ne, all_eq_true]
simp
@[simp] theorem all_toList {p : α Bool} {as : Array α} : as.toList.all p = as.all p := by
@[simp, grind =] theorem all_toList {p : α Bool} {as : Array α} : as.toList.all p = as.all p := by
rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]
simp only [List.mem_iff_getElem, getElem_toList]
constructor
@@ -730,18 +731,18 @@ theorem all_eq_true_iff_forall_mem {xs : Array α} : xs.all p ↔ ∀ x, x ∈ x
subst h
rw [all_toList]
theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
@[grind] theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
l.toArray.anyM p = l.anyM p := by
rw [ anyM_toList]
theorem _root_.List.any_toArray {p : α Bool} {l : List α} : l.toArray.any p = l.any p := by
@[grind] theorem _root_.List.any_toArray {p : α Bool} {l : List α} : l.toArray.any p = l.any p := by
rw [any_toList]
theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
@[grind] theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
l.toArray.allM p = l.allM p := by
rw [ allM_toList]
theorem _root_.List.all_toArray {p : α Bool} {l : List α} : l.toArray.all p = l.all p := by
@[grind] theorem _root_.List.all_toArray {p : α Bool} {l : List α} : l.toArray.all p = l.all p := by
rw [all_toList]
/-- Variant of `any_eq_true` in terms of membership rather than an array index. -/
@@ -807,7 +808,7 @@ theorem decide_forall_mem {xs : Array α} {p : α → Prop} [DecidablePred p] :
decide ( x, x xs p x) = xs.all p := by
simp [all_eq']
@[simp] theorem _root_.List.contains_toArray [BEq α] {l : List α} {a : α} :
@[simp, grind =] theorem _root_.List.contains_toArray [BEq α] {l : List α} {a : α} :
l.toArray.contains a = l.contains a := by
simp [Array.contains, List.any_beq]
@@ -1205,7 +1206,7 @@ where
induction l generalizing xs <;> simp [*]
simp [H]
@[simp] theorem _root_.List.map_toArray {f : α β} {l : List α} :
@[simp, grind =] theorem _root_.List.map_toArray {f : α β} {l : List α} :
l.toArray.map f = (l.map f).toArray := by
apply ext'
simp
@@ -1428,7 +1429,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
induction xs with simp
| cons => split <;> simp [*]
theorem toList_filter {p : α Bool} {xs : Array α} :
@[grind] theorem toList_filter {p : α Bool} {xs : Array α} :
(xs.filter p).toList = xs.toList.filter p := by
simp
@@ -1437,7 +1438,7 @@ theorem toList_filter {p : α → Bool} {xs : Array α} :
apply ext'
simp [h]
theorem _root_.List.filter_toArray {p : α Bool} {l : List α} :
@[grind] theorem _root_.List.filter_toArray {p : α Bool} {l : List α} :
l.toArray.filter p = (l.filter p).toArray := by
simp
@@ -1602,7 +1603,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
· simp_all [Id.run, List.filterMap_cons]
split <;> simp_all
theorem toList_filterMap {f : α Option β} {xs : Array α} :
@[grind] theorem toList_filterMap {f : α Option β} {xs : Array α} :
(xs.filterMap f).toList = xs.toList.filterMap f := by
simp [toList_filterMap']
@@ -1612,7 +1613,7 @@ theorem toList_filterMap {f : α → Option β} {xs : Array α} :
apply ext'
simp [h]
theorem _root_.List.filterMap_toArray {f : α Option β} {l : List α} :
@[grind] theorem _root_.List.filterMap_toArray {f : α Option β} {l : List α} :
l.toArray.filterMap f = (l.filterMap f).toArray := by
simp
@@ -2097,7 +2098,7 @@ theorem append_eq_map_iff {f : α → β} :
@[simp, grind] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
@[simp] theorem toList_flatten {xss : Array (Array α)} :
@[simp, grind] theorem toList_flatten {xss : Array (Array α)} :
xss.flatten.toList = (xss.toList.map toList).flatten := by
dsimp [flatten]
simp only [ foldl_toList]
@@ -2124,7 +2125,7 @@ theorem append_eq_map_iff {f : α → β} :
apply ext'
simp
@[simp] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
@[simp, grind] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
cases xss using array₂_induction
simp [Function.comp_def]
@@ -2307,7 +2308,7 @@ theorem flatMap_toList {xs : Array α} {f : α → List β} :
rcases xs with l
simp
@[simp] theorem toList_flatMap {xs : Array α} {f : α Array β} :
@[simp, grind =] theorem toList_flatMap {xs : Array α} {f : α Array β} :
(xs.flatMap f).toList = xs.toList.flatMap fun a => (f a).toList := by
rcases xs with l
simp
@@ -2322,7 +2323,7 @@ theorem flatMap_toArray_cons {β} {f : α → Array β} {a : α} {as : List α}
intro cs
induction as generalizing cs <;> simp_all
@[simp] theorem flatMap_toArray {β} {f : α Array β} {as : List α} :
@[simp, grind =] theorem flatMap_toArray {β} {f : α Array β} {as : List α} :
as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray := by
induction as with
| nil => simp
@@ -2652,6 +2653,7 @@ abbrev sum_mkArray_nat := @sum_replicate_nat
/-! ### Preliminaries about `swap` needed for `reverse`. -/
@[grind]
theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
simp [swap_def, getElem?_set]
@@ -2710,15 +2712,15 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
true_and, Nat.not_lt] at h
rw [List.getElem?_eq_none_iff.2 _, List.getElem?_eq_none_iff.2 (xs.toList.length_reverse _)]
@[simp] theorem _root_.List.reverse_toArray {l : List α} : l.toArray.reverse = l.reverse.toArray := by
@[simp, grind =] theorem _root_.List.reverse_toArray {l : List α} : l.toArray.reverse = l.reverse.toArray := by
apply ext'
simp only [toList_reverse]
@[simp, grind] theorem reverse_push {xs : Array α} {a : α} : (xs.push a).reverse = #[a] ++ xs.reverse := by
@[simp, grind =] theorem reverse_push {xs : Array α} {a : α} : (xs.push a).reverse = #[a] ++ xs.reverse := by
cases xs
simp
@[simp, grind] theorem mem_reverse {x : α} {xs : Array α} : x xs.reverse x xs := by
@[simp, grind =] theorem mem_reverse {x : α} {xs : Array α} : x xs.reverse x xs := by
cases xs
simp
@@ -2882,7 +2884,7 @@ theorem size_extract_loop {xs ys : Array α} {size start : Nat} :
have h := Nat.le_of_not_gt h
rw [extract_loop_of_ge (h:=h), Nat.sub_eq_zero_of_le h, Nat.min_zero, Nat.add_zero]
@[simp, grind] theorem size_extract {xs : Array α} {start stop : Nat} :
@[simp, grind =] theorem size_extract {xs : Array α} {start stop : Nat} :
(xs.extract start stop).size = min stop xs.size - start := by
simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
rw [size_extract_loop, size_empty, Nat.zero_add, Nat.sub_min_sub_right, Nat.min_assoc,
@@ -2948,7 +2950,7 @@ theorem getElem_extract_aux {xs : Array α} {start stop : Nat} (h : i < (xs.extr
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
apply Nat.sub_le_sub_right; apply Nat.min_le_right
@[simp] theorem getElem_extract {xs : Array α} {start stop : Nat}
@[simp, grind =] theorem getElem_extract {xs : Array α} {start stop : Nat}
(h : i < (xs.extract start stop).size) :
(xs.extract start stop)[i] = xs[start + i]'(getElem_extract_aux h) :=
show (extract.loop xs (min stop xs.size - start) start #[])[i]
@@ -3003,7 +3005,7 @@ theorem extract_empty_of_size_le_start {xs : Array α} {start stop : Nat} (h : x
· simp
· simp at h₁
@[simp] theorem _root_.List.extract_toArray {l : List α} {start stop : Nat} :
@[simp, grind =] theorem _root_.List.extract_toArray {l : List α} {start stop : Nat} :
l.toArray.extract start stop = (l.extract start stop).toArray := by
apply ext'
simp
@@ -3742,25 +3744,25 @@ theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.contains a a xs := by
simp
@[simp, grind]
@[simp, grind =]
theorem contains_toList [BEq α] {xs : Array α} {x : α} :
xs.toList.contains x = xs.contains x := by
rcases xs with xs
simp
@[simp, grind]
@[simp, grind =]
theorem contains_map [BEq β] {xs : Array α} {x : β} {f : α β} :
(xs.map f).contains x = xs.any (fun a => x == f a) := by
rcases xs with xs
simp
@[simp, grind]
@[simp, grind =]
theorem contains_filter [BEq α] {xs : Array α} {x : α} {p : α Bool} :
(xs.filter p).contains x = xs.any (fun a => x == a && p a) := by
rcases xs with xs
simp
@[simp, grind]
@[simp, grind =]
theorem contains_filterMap [BEq β] {xs : Array α} {x : β} {f : α Option β} :
(xs.filterMap f).contains x = xs.any (fun a => (f a).any fun b => x == b) := by
rcases xs with xs
@@ -3773,19 +3775,19 @@ theorem contains_append [BEq α] {xs ys : Array α} {x : α} :
rcases ys with ys
simp
@[simp, grind]
@[simp, grind =]
theorem contains_flatten [BEq α] {xs : Array (Array α)} {x : α} :
(xs.flatten).contains x = xs.any fun xs => xs.contains x := by
rcases xs with xs
simp [Function.comp_def]
@[simp, grind]
@[simp, grind =]
theorem contains_reverse [BEq α] {xs : Array α} {x : α} :
(xs.reverse).contains x = xs.contains x := by
rcases xs with xs
simp
@[simp, grind]
@[simp, grind =]
theorem contains_flatMap [BEq β] {xs : Array α} {f : α Array β} {x : β} :
(xs.flatMap f).contains x = xs.any fun a => (f a).contains x := by
rcases xs with xs
@@ -3798,7 +3800,7 @@ theorem pop_append {xs ys : Array α} :
(xs ++ ys).pop = if ys.isEmpty then xs.pop else xs ++ ys.pop := by
split <;> simp_all
@[simp] theorem pop_replicate {n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a := by
@[simp, grind =] theorem pop_replicate {n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a := by
ext <;> simp
@[deprecated pop_replicate (since := "2025-03-18")]
@@ -4096,6 +4098,7 @@ theorem getElem_swap' {xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs
· simp_all only [getElem_swap_left]
· split <;> simp_all
@[grind]
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
apply getElem_swap'
@@ -4361,7 +4364,10 @@ theorem foldl_toList_eq_map {l : List α} {acc : Array β} {G : α → β} :
/-! # uset -/
attribute [simp] uset
-- For verification purposes, we use `simp` to replace `uset` with `set`.
@[simp, grind =] theorem uset_eq_set {xs : Array α} {v : α} {i : USize} (h : i.toNat < xs.size) :
uset xs i v h = set xs i.toNat v h := by
simp [uset]
theorem size_uset {xs : Array α} {v : α} {i : USize} (h : i.toNat < xs.size) :
(uset xs i v h).size = xs.size := by
@@ -4378,7 +4384,7 @@ theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i
/-! # mem -/
@[simp] theorem mem_toList {a : α} {xs : Array α} : a xs.toList a xs := mem_def.symm
@[simp, grind =] theorem mem_toList {a : α} {xs : Array α} : a xs.toList a xs := mem_def.symm
@[deprecated not_mem_empty (since := "2025-03-25")]
theorem not_mem_nil (a : α) : ¬ a #[] := nofun
@@ -4421,12 +4427,12 @@ theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some
/-! ### forIn -/
@[simp] theorem forIn_toList [Monad m] {xs : Array α} {b : β} {f : α β m (ForInStep β)} :
@[simp, grind =] theorem forIn_toList [Monad m] {xs : Array α} {b : β} {f : α β m (ForInStep β)} :
forIn xs.toList b f = forIn xs b f := by
cases xs
simp
@[simp] theorem forIn'_toList [Monad m] {xs : Array α} {b : β} {f : (a : α) a xs.toList β m (ForInStep β)} :
@[simp, grind =] theorem forIn'_toList [Monad m] {xs : Array α} {b : β} {f : (a : α) a xs.toList β m (ForInStep β)} :
forIn' xs.toList b f = forIn' xs b (fun a m b => f a (mem_toList.mpr m) b) := by
cases xs
simp
@@ -4439,7 +4445,7 @@ abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a
/-! ### isPrefixOf -/
@[simp] theorem isPrefixOf_toList [BEq α] {xs ys : Array α} :
@[simp, grind =] theorem isPrefixOf_toList [BEq α] {xs ys : Array α} :
xs.toList.isPrefixOf ys.toList = xs.isPrefixOf ys := by
cases xs
cases ys
@@ -4480,32 +4486,32 @@ abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a
/-! ### findSomeM?, findM?, findSome?, find? -/
@[simp] theorem findSomeM?_toList [Monad m] [LawfulMonad m] {p : α m (Option β)} {xs : Array α} :
@[simp, grind =] theorem findSomeM?_toList [Monad m] [LawfulMonad m] {p : α m (Option β)} {xs : Array α} :
xs.toList.findSomeM? p = xs.findSomeM? p := by
cases xs
simp
@[simp] theorem findM?_toList [Monad m] [LawfulMonad m] {p : α m Bool} {xs : Array α} :
@[simp, grind =] theorem findM?_toList [Monad m] [LawfulMonad m] {p : α m Bool} {xs : Array α} :
xs.toList.findM? p = xs.findM? p := by
cases xs
simp
@[simp] theorem findSome?_toList {p : α Option β} {xs : Array α} :
@[simp, grind =] theorem findSome?_toList {p : α Option β} {xs : Array α} :
xs.toList.findSome? p = xs.findSome? p := by
cases xs
simp
@[simp] theorem find?_toList {p : α Bool} {xs : Array α} :
@[simp, grind =] theorem find?_toList {p : α Bool} {xs : Array α} :
xs.toList.find? p = xs.find? p := by
cases xs
simp
@[simp] theorem finIdxOf?_toList [BEq α] {a : α} {xs : Array α} :
@[simp, grind =] theorem finIdxOf?_toList [BEq α] {a : α} {xs : Array α} :
xs.toList.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast (by simp)) := by
cases xs
simp
@[simp] theorem findFinIdx?_toList {p : α Bool} {xs : Array α} :
@[simp, grind =] theorem findFinIdx?_toList {p : α Bool} {xs : Array α} :
xs.toList.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast (by simp)) := by
cases xs
simp
@@ -4524,10 +4530,10 @@ Our goal is to have `simp` "pull `List.toArray` outwards" as much as possible.
theorem toListRev_toArray {l : List α} : l.toArray.toListRev = l.reverse := by simp
@[simp] theorem take_toArray {l : List α} {i : Nat} : l.toArray.take i = (l.take i).toArray := by
@[simp, grind =] theorem take_toArray {l : List α} {i : Nat} : l.toArray.take i = (l.take i).toArray := by
apply Array.ext <;> simp
@[simp] theorem mapM_toArray [Monad m] [LawfulMonad m] {f : α m β} {l : List α} :
@[simp, grind =] theorem mapM_toArray [Monad m] [LawfulMonad m] {f : α m β} {l : List α} :
l.toArray.mapM f = List.toArray <$> l.mapM f := by
simp only [ mapM'_eq_mapM, mapM_eq_foldlM]
suffices xs : Array β,
@@ -4544,12 +4550,12 @@ theorem toListRev_toArray {l : List α} : l.toArray.toListRev = l.reverse := by
theorem uset_toArray {l : List α} {i : USize} {a : α} {h : i.toNat < l.toArray.size} :
l.toArray.uset i a h = (l.set i.toNat a).toArray := by simp
@[simp] theorem modify_toArray {f : α α} {l : List α} {i : Nat} :
@[simp, grind =] theorem modify_toArray {f : α α} {l : List α} {i : Nat} :
l.toArray.modify i f = (l.modify i f).toArray := by
apply ext'
simp
@[simp] theorem flatten_toArray {L : List (List α)} :
@[simp, grind =] theorem flatten_toArray {L : List (List α)} :
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
apply ext'
simp [Function.comp_def]
@@ -4624,11 +4630,11 @@ end Array
namespace List
@[simp] theorem unzip_toArray {as : List (α × β)} :
@[simp, grind =] theorem unzip_toArray {as : List (α × β)} :
as.toArray.unzip = Prod.map List.toArray List.toArray as.unzip := by
ext1 <;> simp
@[simp] theorem firstM_toArray [Alternative m] {as : List α} {f : α m β} :
@[simp, grind =] theorem firstM_toArray [Alternative m] {as : List α} {f : α m β} :
as.toArray.firstM f = as.firstM f := by
unfold Array.firstM
suffices i, i as.length firstM.go f as.toArray (as.length - i) = firstM f (as.drop (as.length - i)) by
@@ -4698,11 +4704,6 @@ theorem get!_eq_getD_getElem? [Inhabited α] (xs : Array α) (i : Nat) :
set_option linter.deprecated false in
@[deprecated get!_eq_getD_getElem? (since := "2025-02-12")] abbrev get!_eq_getElem? := @get!_eq_getD_getElem?
@[deprecated mem_of_back? (since := "2024-10-21")] abbrev mem_of_back?_eq_some := @mem_of_back?
@[deprecated getElem?_size_le (since := "2024-10-21")] abbrev get?_len_le := @getElem?_size_le
set_option linter.deprecated false in
@[deprecated "`Array.get?` is deprecated, use `a[i]?` instead." (since := "2025-02-12")]
theorem get?_eq_get?_toList (xs : Array α) (i : Nat) : xs.get? i = xs.toList.get? i := by
@@ -4711,45 +4712,11 @@ theorem get?_eq_get?_toList (xs : Array α) (i : Nat) : xs.get? i = xs.toList.ge
set_option linter.deprecated false in
@[deprecated get!_eq_getD_getElem? (since := "2025-02-12")] abbrev get!_eq_get? := @get!_eq_getD_getElem?
@[deprecated getElem?_push_lt (since := "2024-10-21")] abbrev get?_push_lt := @getElem?_push_lt
@[deprecated getElem?_push_eq (since := "2024-10-21")] abbrev get?_push_eq := @getElem?_push_eq
@[deprecated getElem?_push (since := "2024-10-21")] abbrev get?_push := @getElem?_push
@[deprecated getElem?_size (since := "2024-10-21")] abbrev get?_size := @getElem?_size
@[deprecated getElem_set_self (since := "2025-01-17")]
theorem get_set_eq (xs : Array α) (i : Nat) (v : α) (h : i < xs.size) :
(xs.set i v h)[i]'(by simp [h]) = v := by
simp only [set, getElem_toList, List.getElem_set_self]
@[deprecated foldl_toList_eq_flatMap (since := "2024-10-16")]
abbrev foldl_toList_eq_bind := @foldl_toList_eq_flatMap
@[deprecated foldl_toList_eq_flatMap (since := "2024-10-16")]
abbrev foldl_data_eq_bind := @foldl_toList_eq_flatMap
@[deprecated getElem_mem (since := "2024-10-17")]
abbrev getElem?_mem := @getElem_mem
@[deprecated getElem_fin_eq_getElem_toList (since := "2024-10-17")]
abbrev getElem_fin_eq_toList_get := @getElem_fin_eq_getElem_toList
@[deprecated "Use reverse direction of `getElem?_toList`" (since := "2024-10-17")]
abbrev getElem?_eq_toList_getElem? := @getElem?_toList
@[deprecated getElem?_swap (since := "2024-10-17")] abbrev get?_swap := @getElem?_swap
@[deprecated getElem_push (since := "2024-10-21")] abbrev get_push := @getElem_push
@[deprecated getElem_push_lt (since := "2024-10-21")] abbrev get_push_lt := @getElem_push_lt
@[deprecated getElem_push_eq (since := "2024-10-21")] abbrev get_push_eq := @getElem_push_eq
@[deprecated back!_eq_back? (since := "2024-10-31")] abbrev back_eq_back? := @back!_eq_back?
@[deprecated back!_push (since := "2024-10-31")] abbrev back_push := @back!_push
@[deprecated eq_push_pop_back!_of_size_ne_zero (since := "2024-10-31")]
abbrev eq_push_pop_back_of_size_ne_zero := @eq_push_pop_back!_of_size_ne_zero
@[deprecated set!_is_setIfInBounds (since := "2024-11-24")] abbrev set_is_setIfInBounds := @set!_eq_setIfInBounds
@[deprecated size_setIfInBounds (since := "2024-11-24")] abbrev size_setD := @size_setIfInBounds
@[deprecated getElem_setIfInBounds_eq (since := "2024-11-24")] abbrev getElem_setD_eq := @getElem_setIfInBounds_self

View File

@@ -16,11 +16,11 @@ namespace Array
/-! ### Lexicographic ordering -/
@[simp] theorem _root_.List.lt_toArray [LT α] {l₁ l₂ : List α} : l₁.toArray < l₂.toArray l₁ < l₂ := Iff.rfl
@[simp] theorem _root_.List.le_toArray [LT α] {l₁ l₂ : List α} : l₁.toArray l₂.toArray l₁ l₂ := Iff.rfl
@[simp, grind =] theorem _root_.List.lt_toArray [LT α] {l₁ l₂ : List α} : l₁.toArray < l₂.toArray l₁ < l₂ := Iff.rfl
@[simp, grind =] theorem _root_.List.le_toArray [LT α] {l₁ l₂ : List α} : l₁.toArray l₂.toArray l₁ l₂ := Iff.rfl
@[simp] theorem lt_toList [LT α] {xs ys : Array α} : xs.toList < ys.toList xs < ys := Iff.rfl
@[simp] theorem le_toList [LT α] {xs ys : Array α} : xs.toList ys.toList xs ys := Iff.rfl
@[simp, grind =] theorem lt_toList [LT α] {xs ys : Array α} : xs.toList < ys.toList xs < ys := Iff.rfl
@[simp, grind =] theorem le_toList [LT α] {xs ys : Array α} : xs.toList ys.toList xs ys := Iff.rfl
protected theorem not_lt_iff_ge [LT α] {l₁ l₂ : List α} : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : List α} :
@@ -47,7 +47,7 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
cases a == b <;> simp
· simp
@[simp] theorem _root_.List.lex_toArray [BEq α] {lt : α α Bool} {l₁ l₂ : List α} :
@[simp, grind =] theorem _root_.List.lex_toArray [BEq α] {lt : α α Bool} {l₁ l₂ : List α} :
l₁.toArray.lex l₂.toArray lt = l₁.lex l₂ lt := by
induction l₁ generalizing l₂ with
| nil => cases l₂ <;> simp [lex, Id.run]
@@ -57,7 +57,7 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
| cons y l₂ =>
rw [List.toArray_cons, List.toArray_cons y, cons_lex_cons, List.lex, ih]
@[simp] theorem lex_toList [BEq α] {lt : α α Bool} {xs ys : Array α} :
@[simp, grind =] theorem lex_toList [BEq α] {lt : α α Bool} {xs ys : Array α} :
xs.toList.lex ys.toList lt = xs.lex ys lt := by
cases xs <;> cases ys <;> simp

View File

@@ -111,11 +111,11 @@ end Array
namespace List
@[simp] theorem mapFinIdx_toArray {l : List α} {f : (i : Nat) α (h : i < l.length) β} :
@[simp, grind =] theorem mapFinIdx_toArray {l : List α} {f : (i : Nat) α (h : i < l.length) β} :
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
ext <;> simp
@[simp] theorem mapIdx_toArray {f : Nat α β} {l : List α} :
@[simp, grind =] theorem mapIdx_toArray {f : Nat α β} {l : List α} :
l.toArray.mapIdx f = (l.mapIdx f).toArray := by
ext <;> simp
@@ -132,7 +132,7 @@ namespace Array
@[deprecated getElem_zipIdx (since := "2025-01-21")]
abbrev getElem_zipWithIndex := @getElem_zipIdx
@[simp] theorem zipIdx_toArray {l : List α} {k : Nat} :
@[simp, grind =] theorem zipIdx_toArray {l : List α} {k : Nat} :
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
ext i hi₁ hi₂ <;> simp [Nat.add_comm]
@@ -454,7 +454,7 @@ end Array
namespace List
theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
@[grind] theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
{f : (i : Nat) α (h : i < l.length) m β} :
l.toArray.mapFinIdxM f = toArray <$> l.mapFinIdxM f := by
let rec go (i : Nat) (acc : Array β) (inv : i + acc.size = l.length) :
@@ -475,7 +475,7 @@ theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
simp only [Array.mapFinIdxM, mapFinIdxM]
exact go _ #[] _
theorem mapIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
@[grind] theorem mapIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
{f : Nat α m β} :
l.toArray.mapIdxM f = toArray <$> l.mapIdxM f := by
let rec go (bs : List α) (acc : Array β) (inv : bs.length + acc.size = l.length) :

View File

@@ -264,7 +264,7 @@ end Array
namespace List
theorem filterM_toArray [Monad m] [LawfulMonad m] {l : List α} {p : α m Bool} :
@[grind =] theorem filterM_toArray [Monad m] [LawfulMonad m] {l : List α} {p : α m Bool} :
l.toArray.filterM p = toArray <$> l.filterM p := by
simp only [Array.filterM, filterM, foldlM_toArray, bind_pure_comp, Functor.map_map]
conv => lhs; rw [ reverse_nil]
@@ -284,7 +284,7 @@ theorem filterM_toArray [Monad m] [LawfulMonad m] {l : List α} {p : α → m Bo
subst w
rw [filterM_toArray]
theorem filterRevM_toArray [Monad m] [LawfulMonad m] {l : List α} {p : α m Bool} :
@[grind =] theorem filterRevM_toArray [Monad m] [LawfulMonad m] {l : List α} {p : α m Bool} :
l.toArray.filterRevM p = toArray <$> l.filterRevM p := by
simp [Array.filterRevM, filterRevM]
rw [ foldlM_reverse, foldlM_toArray, Array.filterM, filterM_toArray]
@@ -296,7 +296,7 @@ theorem filterRevM_toArray [Monad m] [LawfulMonad m] {l : List α} {p : α → m
subst w
rw [filterRevM_toArray]
theorem filterMapM_toArray [Monad m] [LawfulMonad m] {l : List α} {f : α m (Option β)} :
@[grind =] theorem filterMapM_toArray [Monad m] [LawfulMonad m] {l : List α} {f : α m (Option β)} :
l.toArray.filterMapM f = toArray <$> l.filterMapM f := by
simp [Array.filterMapM, filterMapM]
conv => lhs; rw [ reverse_nil]
@@ -314,7 +314,7 @@ theorem filterMapM_toArray [Monad m] [LawfulMonad m] {l : List α} {f : α → m
subst w
rw [filterMapM_toArray]
@[simp] theorem flatMapM_toArray [Monad m] [LawfulMonad m] {l : List α} {f : α m (Array β)} :
@[simp, grind =] theorem flatMapM_toArray [Monad m] [LawfulMonad m] {l : List α} {f : α m (Array β)} :
l.toArray.flatMapM f = toArray <$> l.flatMapM (fun a => Array.toList <$> f a) := by
simp only [Array.flatMapM, bind_pure_comp, foldlM_toArray, flatMapM]
conv => lhs; arg 2; change [].reverse.flatten.toArray

View File

@@ -464,8 +464,12 @@ instance : Append (Subarray α) where
let a := x.toArray ++ y.toArray
a.toSubarray 0 a.size
/-- `Subarray` representation. -/
protected def Subarray.repr [Repr α] (s : Subarray α) : Std.Format :=
repr s.toArray ++ ".toSubarray"
instance [Repr α] : Repr (Subarray α) where
reprPrec s _ := repr s.toArray ++ ".toSubarray"
reprPrec s _ := Subarray.repr s
instance [ToString α] : ToString (Subarray α) where
toString s := toString s.toArray

View File

@@ -27,7 +27,7 @@ class EquivBEq (α) [BEq α] : Prop extends PartialEquivBEq α, ReflBEq α
theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b b == a :=
PartialEquivBEq.symm
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
@[grind] theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
Bool.eq_iff_iff.2 BEq.symm, BEq.symm
theorem bne_comm [BEq α] [PartialEquivBEq α] {a b : α} : (a != b) = (b != a) := by

View File

@@ -150,7 +150,7 @@ with `BitVec.toInt` results in the value `i.bmod (2^n)`.
protected def ofInt (n : Nat) (i : Int) : BitVec n := .ofNatLT (i % (Int.ofNat (2^n))).toNat (by
apply (Int.toNat_lt _).mpr
· apply Int.emod_lt_of_pos
exact Int.ofNat_pos.mpr (Nat.two_pow_pos _)
exact Int.natCast_pos.mpr (Nat.two_pow_pos _)
· apply Int.emod_nonneg
intro eq
apply Nat.ne_of_gt (Nat.two_pow_pos n)
@@ -199,7 +199,13 @@ protected def toHex {n : Nat} (x : BitVec n) : String :=
let t := (List.replicate ((n+3) / 4 - s.length) '0').asString
t ++ s
instance : Repr (BitVec n) where reprPrec a _ := "0x" ++ (a.toHex : Std.Format) ++ "#" ++ repr n
/-- `BitVec` representation. -/
protected def BitVec.repr (a : BitVec n) : Std.Format :=
"0x" ++ (a.toHex : Std.Format) ++ "#" ++ repr n
instance : Repr (BitVec n) where
reprPrec a _ := BitVec.repr a
instance : ToString (BitVec n) where toString a := toString (repr a)
end repr_toString
@@ -430,8 +436,6 @@ def setWidth' {n w : Nat} (le : n ≤ w) (x : BitVec n) : BitVec w :=
apply Nat.lt_of_lt_of_le x.isLt
exact Nat.pow_le_pow_right (by trivial) le)
@[deprecated setWidth' (since := "2024-09-18"), inherit_doc setWidth'] abbrev zeroExtend' := @setWidth'
/--
Returns `zeroExtend (w+n) x <<< n` without needing to compute `x % 2^(2+n)`.
-/

View File

@@ -516,7 +516,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
rw [(show w = w - 1 + 1 by omega), Int.pow_succ] at this
omega
@[simp] theorem BitVec.setWidth_neg_of_le {x : BitVec v} (h : w v) : BitVec.setWidth w (-x) = -BitVec.setWidth w x := by
@[simp] theorem setWidth_neg_of_le {x : BitVec v} (h : w v) : BitVec.setWidth w (-x) = -BitVec.setWidth w x := by
simp [ BitVec.signExtend_eq_setWidth_of_le _ h, BitVec.signExtend_neg_of_le h]
/-! ### abs -/
@@ -668,11 +668,6 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
getLsbD_zero, and_eq_false_imp, and_eq_true, decide_eq_true_eq, and_imp]
by_cases hi : x.getLsbD i <;> simp [hi] <;> omega
@[deprecated setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (since := "2024-09-18"),
inherit_doc setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow]
abbrev zeroExtend_truncate_succ_eq_zeroExtend_truncate_add_twoPow :=
@setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow
/--
Recurrence lemma: multiplying `x` with the first `s` bits of `y` is the
same as truncating `y` to `s` bits, then zero extending to the original length,
@@ -699,10 +694,6 @@ theorem mulRec_eq_mul_signExtend_setWidth (x y : BitVec w) (s : Nat) :
by_cases hy : y.getLsbD (s' + 1) <;> simp [hy]
rw [heq, BitVec.mul_add, setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow]
@[deprecated mulRec_eq_mul_signExtend_setWidth (since := "2024-09-18"),
inherit_doc mulRec_eq_mul_signExtend_setWidth]
abbrev mulRec_eq_mul_signExtend_truncate := @mulRec_eq_mul_signExtend_setWidth
theorem getLsbD_mul (x y : BitVec w) (i : Nat) :
(x * y).getLsbD i = (mulRec x y w).getLsbD i := by
simp only [mulRec_eq_mul_signExtend_setWidth]
@@ -1501,7 +1492,6 @@ theorem sdiv_intMin {x : BitVec w} :
by_cases h : x = intMin w
· subst h
simp
omega
· simp only [sdiv_eq, msb_intMin, show 0 < w by omega, h]
have := Nat.two_pow_pos (w-1)
by_cases hx : x.msb

View File

@@ -315,6 +315,12 @@ theorem ofFin_ofNat (n : Nat) :
ofFin (no_index (OfNat.ofNat n : Fin (2^w))) = OfNat.ofNat n := by
simp only [OfNat.ofNat, Fin.ofNat', BitVec.ofNat, Nat.and_two_pow_sub_one_eq_mod]
@[simp] theorem ofFin_neg {x : Fin (2 ^ w)} : ofFin (-x) = -(ofFin x) := by
rfl
@[simp, norm_cast] theorem ofFin_natCast (n : Nat) : ofFin (n : Fin (2^w)) = (n : BitVec w) := by
rfl
theorem eq_of_toFin_eq : {x y : BitVec w}, x.toFin = y.toFin x = y
| _, _, _, _, rfl => rfl
@@ -330,6 +336,9 @@ theorem toFin_zero : toFin (0 : BitVec w) = 0 := rfl
theorem toFin_one : toFin (1 : BitVec w) = 1 := by
rw [toFin_inj]; simp only [ofNat_eq_ofNat, ofFin_ofNat]
@[simp, norm_cast] theorem toFin_natCast (n : Nat) : toFin (n : BitVec w) = (n : Fin (2^w)) := by
rfl
@[simp] theorem toNat_ofBool (b : Bool) : (ofBool b).toNat = b.toNat := by
cases b <;> rfl
@@ -518,6 +527,10 @@ theorem getElem_ofBool {b : Bool} {h : i < 1}: (ofBool b)[i] = b := by
· rintro rfl
simp
/-- `0#w = 1#w` iff the width is zero. -/
@[simp] theorem zero_eq_one_iff (w : Nat) : (0#w = 1#w) (w = 0) := by
rw [ one_eq_zero_iff, eq_comm]
/-! ### msb -/
@[simp] theorem msb_zero : (0#w).msb = false := by simp [BitVec.msb, getMsbD]
@@ -668,6 +681,10 @@ theorem toInt_ne {x y : BitVec n} : x.toInt ≠ y.toInt ↔ x ≠ y := by
theorem toInt_ofNat {n : Nat} (x : Nat) : (BitVec.ofNat n x).toInt = (x : Int).bmod (2^n) := by
simp [toInt_eq_toNat_bmod, -Int.natCast_pow]
@[simp] theorem toInt_ofFin {w : Nat} (x : Fin (2^w)) :
(BitVec.ofFin x).toInt = Int.bmod x (2^w) := by
simp [toInt_eq_toNat_bmod]
@[simp] theorem toInt_ofInt {n : Nat} (i : Int) :
(BitVec.ofInt n i).toInt = i.bmod (2^n) := by
have _ := Nat.two_pow_pos n
@@ -773,7 +790,6 @@ theorem le_two_mul_toInt {w : Nat} {x : BitVec w} : -2 ^ w ≤ 2 * x.toInt := by
simp only [Nat.zero_lt_succ, Nat.mul_lt_mul_left, Int.natCast_mul, Int.cast_ofNat_Int]
norm_cast; omega
theorem le_toInt {w : Nat} (x : BitVec w) : -2 ^ (w - 1) x.toInt := by
by_cases h : w = 0
· subst h
@@ -789,6 +805,17 @@ theorem le_toInt {w : Nat} (x : BitVec w) : -2 ^ (w - 1) ≤ x.toInt := by
· simpa [Int.mul_comm _ 2] using le_two_mul_toInt
· simpa [Int.mul_comm _ 2] using two_mul_toInt_lt
@[simp] theorem toNat_intCast {w : Nat} (x : Int) : (x : BitVec w).toNat = (x % 2^w).toNat := by
change (BitVec.ofInt w x).toNat = _
simp
@[simp] theorem toInt_intCast {w : Nat} (x : Int) : (x : BitVec w).toInt = Int.bmod x (2^w) := by
rw [toInt_eq_toNat_bmod, toNat_intCast, Int.natCast_toNat_eq_self.mpr]
· have h : (2 ^ w : Int) = (2 ^ w : Nat) := by simp
rw [h, Int.emod_bmod]
· apply Int.emod_nonneg
exact Int.pow_ne_zero (by decide)
/-! ### sle/slt -/
/--
@@ -3082,10 +3109,6 @@ theorem setWidth_succ (x : BitVec w) :
· simp_all
· omega
@[deprecated "Use the reverse direction of `cons_msb_setWidth`" (since := "2024-09-23")]
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 [cons]
@@ -5312,6 +5335,14 @@ theorem msb_eq_toNat {x : BitVec w}:
x.msb = decide (x.toNat 2 ^ (w - 1)) := by
simp only [msb_eq_decide, ge_iff_le]
/-- Negating a bitvector created from a natural number equals
creating a bitvector from the the negative of that number.
-/
theorem neg_ofNat_eq_ofInt_neg {w : Nat} {x : Nat} :
- BitVec.ofNat w x = BitVec.ofInt w (- x) := by
apply BitVec.eq_of_toInt_eq
simp [BitVec.toInt_neg, BitVec.toInt_ofNat]
/-! ### abs -/
theorem abs_eq (x : BitVec w) : x.abs = if x.msb then -x else x := by rfl
@@ -5547,150 +5578,6 @@ abbrev toFin_uShiftRight := @toFin_ushiftRight
@[deprecated signExtend_eq_setWidth_of_msb_false (since := "2024-12-08")]
abbrev signExtend_eq_not_setWidth_not_of_msb_false := @signExtend_eq_setWidth_of_msb_false
@[deprecated truncate_eq_setWidth (since := "2024-09-18")]
abbrev truncate_eq_zeroExtend := @truncate_eq_setWidth
@[deprecated toNat_setWidth' (since := "2024-09-18")]
abbrev toNat_zeroExtend' := @toNat_setWidth'
@[deprecated toNat_setWidth (since := "2024-09-18")]
abbrev toNat_zeroExtend := @toNat_setWidth
@[deprecated toNat_setWidth (since := "2024-09-18")]
abbrev toNat_truncate := @toNat_setWidth
@[deprecated setWidth_eq (since := "2024-09-18")]
abbrev zeroExtend_eq := @setWidth_eq
@[deprecated setWidth_eq (since := "2024-09-18")]
abbrev truncate_eq := @setWidth_eq
@[deprecated setWidth_zero (since := "2024-09-18")]
abbrev zeroExtend_zero := @setWidth_zero
@[deprecated getElem_setWidth (since := "2024-09-18")]
abbrev getElem_zeroExtend := @getElem_setWidth
@[deprecated getElem_setWidth' (since := "2024-09-18")]
abbrev getElem_zeroExtend' := @getElem_setWidth'
@[deprecated getElem?_setWidth (since := "2024-09-18")]
abbrev getElem?_zeroExtend := @getElem?_setWidth
@[deprecated getElem?_setWidth' (since := "2024-09-18")]
abbrev getElem?_zeroExtend' := @getElem?_setWidth'
@[deprecated getLsbD_setWidth (since := "2024-09-18")]
abbrev getLsbD_zeroExtend := @getLsbD_setWidth
@[deprecated getLsbD_setWidth' (since := "2024-09-18")]
abbrev getLsbD_zeroExtend' := @getLsbD_setWidth'
@[deprecated getMsbD_setWidth_add (since := "2024-09-18")]
abbrev getMsbD_zeroExtend_add := @getMsbD_setWidth_add
@[deprecated getMsbD_setWidth' (since := "2024-09-18")]
abbrev getMsbD_zeroExtend' := @getMsbD_setWidth'
@[deprecated getElem_setWidth (since := "2024-09-18")]
abbrev getElem_truncate := @getElem_setWidth
@[deprecated getElem?_setWidth (since := "2024-09-18")]
abbrev getElem?_truncate := @getElem?_setWidth
@[deprecated getLsbD_setWidth (since := "2024-09-18")]
abbrev getLsbD_truncate := @getLsbD_setWidth
@[deprecated msb_setWidth (since := "2024-09-18")]
abbrev msb_truncate := @msb_setWidth
@[deprecated cast_setWidth (since := "2024-09-18")]
abbrev cast_zeroExtend := @cast_setWidth
@[deprecated cast_setWidth (since := "2024-09-18")]
abbrev cast_truncate := @cast_setWidth
@[deprecated setWidth_setWidth_of_le (since := "2024-09-18")]
abbrev zeroExtend_zeroExtend_of_le := @setWidth_setWidth_of_le
@[deprecated setWidth_eq (since := "2024-09-18")]
abbrev truncate_eq_self := @setWidth_eq
@[deprecated setWidth_cast (since := "2024-09-18")]
abbrev truncate_cast := @setWidth_cast
@[deprecated msb_setWidth (since := "2024-09-18")]
abbrev mbs_zeroExtend := @msb_setWidth
@[deprecated msb_setWidth' (since := "2024-09-18")]
abbrev mbs_zeroExtend' := @msb_setWidth'
@[deprecated setWidth_one_eq_ofBool_getLsb_zero (since := "2024-09-18")]
abbrev zeroExtend_one_eq_ofBool_getLsb_zero := @setWidth_one_eq_ofBool_getLsb_zero
@[deprecated setWidth_ofNat_one_eq_ofNat_one_of_lt (since := "2024-09-18")]
abbrev zeroExtend_ofNat_one_eq_ofNat_one_of_lt := @setWidth_ofNat_one_eq_ofNat_one_of_lt
@[deprecated setWidth_one (since := "2024-09-18")]
abbrev truncate_one := @setWidth_one
@[deprecated setWidth_ofNat_of_le (since := "2024-09-18")]
abbrev truncate_ofNat_of_le := @setWidth_ofNat_of_le
@[deprecated setWidth_or (since := "2024-09-18")]
abbrev truncate_or := @setWidth_or
@[deprecated setWidth_and (since := "2024-09-18")]
abbrev truncate_and := @setWidth_and
@[deprecated setWidth_xor (since := "2024-09-18")]
abbrev truncate_xor := @setWidth_xor
@[deprecated setWidth_not (since := "2024-09-18")]
abbrev truncate_not := @setWidth_not
@[deprecated signExtend_eq_setWidth_of_msb_false (since := "2024-09-18")]
abbrev signExtend_eq_not_zeroExtend_not_of_msb_false := @signExtend_eq_setWidth_of_msb_false
@[deprecated signExtend_eq_not_setWidth_not_of_msb_true (since := "2024-09-18")]
abbrev signExtend_eq_not_zeroExtend_not_of_msb_true := @signExtend_eq_not_setWidth_not_of_msb_true
@[deprecated signExtend_eq_setWidth_of_lt (since := "2024-09-18")]
abbrev signExtend_eq_truncate_of_lt := @signExtend_eq_setWidth_of_le
@[deprecated truncate_append (since := "2024-09-18")]
abbrev truncate_append := @setWidth_append
@[deprecated truncate_append_of_eq (since := "2024-09-18")]
abbrev truncate_append_of_eq := @setWidth_append_of_eq
@[deprecated truncate_cons (since := "2024-09-18")]
abbrev truncate_cons := @setWidth_cons
@[deprecated truncate_succ (since := "2024-09-18")]
abbrev truncate_succ := @setWidth_succ
@[deprecated truncate_add (since := "2024-09-18")]
abbrev truncate_add := @setWidth_add
@[deprecated setWidth_setWidth_succ_eq_setWidth_setWidth_of_getLsbD_false (since := "2024-09-18")]
abbrev zeroExtend_truncate_succ_eq_zeroExtend_truncate_of_getLsbD_false := @setWidth_setWidth_succ_eq_setWidth_setWidth_of_getLsbD_false
@[deprecated setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true (since := "2024-09-18")]
abbrev zeroExtend_truncate_succ_eq_zeroExtend_truncate_or_twoPow_of_getLsbD_true := @setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true
@[deprecated and_one_eq_setWidth_ofBool_getLsbD (since := "2024-09-18")]
abbrev and_one_eq_zeroExtend_ofBool_getLsbD := @and_one_eq_setWidth_ofBool_getLsbD
@[deprecated msb_sshiftRight (since := "2024-10-03")]
abbrev sshiftRight_msb_eq_msb := @msb_sshiftRight
@[deprecated shiftLeft_zero (since := "2024-10-27")]
abbrev shiftLeft_zero_eq := @shiftLeft_zero
@[deprecated ushiftRight_zero (since := "2024-10-27")]
abbrev ushiftRight_zero_eq := @ushiftRight_zero
@[deprecated replicate_zero (since := "2025-01-08")]
abbrev replicate_zero_eq := @replicate_zero

View File

@@ -230,6 +230,19 @@ instance : ShiftRight (Fin n) where
instance instOfNat {n : Nat} [NeZero n] {i : Nat} : OfNat (Fin n) i where
ofNat := Fin.ofNat' n i
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
protected theorem pos (i : Fin n) : 0 < n :=
Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
/-- Negation on `Fin n` -/
instance neg (n : Nat) : Neg (Fin n) :=
fun a => (n - a) % n, Nat.mod_lt _ a.pos
theorem neg_def (a : Fin n) : -a = (n - a) % n, Nat.mod_lt _ a.pos := rfl
protected theorem coe_neg (a : Fin n) : ((-a : Fin n) : Nat) = (n - a) % n :=
rfl
instance instInhabited {n : Nat} [NeZero n] : Inhabited (Fin n) where
default := 0
@@ -247,10 +260,6 @@ theorem modn_lt : ∀ {m : Nat} (i : Fin n), m > 0 → (modn i m).val < m
theorem val_lt_of_le (i : Fin b) (h : b n) : i.val < n :=
Nat.lt_of_lt_of_le i.isLt h
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
protected theorem pos (i : Fin n) : 0 < n :=
Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
/--
The greatest value of `Fin (n+1)`, namely `n`.

View File

@@ -8,6 +8,7 @@ module
prelude
import Init.Data.Fin.Basic
import Init.Data.Nat.Lemmas
import Init.Data.Int.DivMod.Lemmas
import Init.Ext
import Init.ByCases
import Init.Conv
@@ -99,6 +100,21 @@ theorem dite_val {n : Nat} {c : Prop} [Decidable c] {x y : Fin n} :
(if c then x else y).val = if c then x.val else y.val := by
by_cases c <;> simp [*]
instance (n : Nat) [NeZero n] : NatCast (Fin n) where
natCast a := Fin.ofNat' n a
def intCast [NeZero n] (a : Int) : Fin n :=
if 0 a then
Fin.ofNat' n a.natAbs
else
- Fin.ofNat' n a.natAbs
instance (n : Nat) [NeZero n] : IntCast (Fin n) where
intCast := Fin.intCast
theorem intCast_def {n : Nat} [NeZero n] (x : Int) :
(x : Fin n) = if 0 x then Fin.ofNat' n x.natAbs else -Fin.ofNat' n x.natAbs := rfl
/-! ### order -/
theorem le_def {a b : Fin n} : a b a.1 b.1 := .rfl
@@ -156,7 +172,7 @@ protected theorem eq_or_lt_of_le {a b : Fin n} : a ≤ b → a = b a < b :=
protected theorem lt_or_eq_of_le {a b : Fin n} : a b a < b a = b := by
rw [Fin.ext_iff]; exact Nat.lt_or_eq_of_le
theorem is_le (i : Fin (n + 1)) : i n := Nat.le_of_lt_succ i.is_lt
theorem is_le (i : Fin (n + 1)) : i.1 n := Nat.le_of_lt_succ i.is_lt
@[simp] theorem is_le' {a : Fin n} : a n := Nat.le_of_lt a.is_lt
@@ -174,13 +190,13 @@ theorem mk_le_of_le_val {b : Fin n} {a : Nat} (h : a ≤ b) :
@[simp] theorem mk_zero : (0, Nat.succ_pos n : Fin (n + 1)) = 0 := rfl
@[simp] theorem zero_le (a : Fin (n + 1)) : 0 a := Nat.zero_le a.val
@[simp] theorem zero_le [NeZero n] (a : Fin n) : 0 a := Nat.zero_le a.val
theorem zero_lt_one : (0 : Fin (n + 2)) < 1 := Nat.zero_lt_one
@[simp] theorem not_lt_zero (a : Fin (n + 1)) : ¬a < 0 := nofun
@[simp] theorem not_lt_zero [NeZero n] (a : Fin n) : ¬a < 0 := nofun
theorem pos_iff_ne_zero {a : Fin (n + 1)} : 0 < a a 0 := by
theorem pos_iff_ne_zero [NeZero n] {a : Fin n} : 0 < a a 0 := by
rw [lt_def, val_zero, Nat.pos_iff_ne_zero, val_ne_iff]; rfl
theorem eq_zero_or_eq_succ {n : Nat} : i : Fin (n + 1), i = 0 j : Fin n, i = j.succ
@@ -219,7 +235,7 @@ theorem rev_eq {n a : Nat} (i : Fin (n + 1)) (h : n = a + i) :
/-! ### last -/
@[simp] theorem val_last (n : Nat) : last n = n := rfl
@[simp] theorem val_last (n : Nat) : (last n).1 = n := rfl
@[simp] theorem last_zero : (Fin.last 0 : Fin 1) = 0 := by
ext
@@ -260,7 +276,7 @@ theorem subsingleton_iff_le_one : Subsingleton (Fin n) ↔ n ≤ 1 := by
(match n with | 0 | 1 | n+2 => ?_) <;> try simp
· exact nofun
· exact fun 0, _ 0, _ => rfl
· exact iff_of_false (fun h => Fin.ne_of_lt zero_lt_one (h.elim ..)) (of_decide_eq_false rfl)
· exact fun h => by have := zero_lt_one (n := n); simp_all [h.elim 0 1]
instance subsingleton_zero : Subsingleton (Fin 0) := subsingleton_iff_le_one.2 (by decide)
@@ -506,17 +522,17 @@ theorem castSucc_inj {a b : Fin n} : a.castSucc = b.castSucc ↔ a = b := by sim
theorem castSucc_lt_last (a : Fin n) : a.castSucc < last n := a.is_lt
@[simp] theorem castSucc_zero : castSucc (0 : Fin (n + 1)) = 0 := rfl
@[simp] theorem castSucc_zero [NeZero n] : castSucc (0 : Fin n) = 0 := rfl
@[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 := rfl
/-- `castSucc i` is positive when `i` is positive -/
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < i.castSucc := by
theorem castSucc_pos [NeZero n] {i : Fin n} (h : 0 < i) : 0 < i.castSucc := by
simpa [lt_def] using h
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : a.castSucc = 0 a = 0 := by simp [Fin.ext_iff]
@[simp] theorem castSucc_eq_zero_iff [NeZero n] {a : Fin n} : a.castSucc = 0 a = 0 := by simp [Fin.ext_iff]
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : a.castSucc 0 a 0 :=
theorem castSucc_ne_zero_iff [NeZero n] {a : Fin n} : a.castSucc 0 a 0 :=
not_congr <| castSucc_eq_zero_iff
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
@@ -925,6 +941,15 @@ theorem addCases_right {m n : Nat} {motive : Fin (m + n) → Sort _} {left right
have : ¬(natAdd m i : Nat) < m := Nat.not_lt.2 (le_coe_natAdd ..)
rw [addCases, dif_neg this]; exact eq_of_heq <| (eqRec_heq _ _).trans (by congr 1; simp)
/-! ### zero -/
@[simp, norm_cast]
theorem val_eq_zero_iff [NeZero n] {a : Fin n} : a.val = 0 a = 0 := by
rw [Fin.ext_iff, val_zero]
theorem val_ne_zero_iff [NeZero n] {a : Fin n} : a.val 0 a 0 :=
not_congr val_eq_zero_iff
/-! ### add -/
theorem ofNat'_add [NeZero n] (x : Nat) (y : Fin n) :
@@ -984,6 +1009,17 @@ theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b
rw [Nat.mod_eq_of_lt]
all_goals omega
/-! ### neg -/
theorem val_neg {n : Nat} [NeZero n] (x : Fin n) :
(-x).val = if x = 0 then 0 else n - x.val := by
change (n - x) % n = _
split <;> rename_i h
· simp_all
· rw [Nat.mod_eq_of_lt]
have := Fin.val_ne_zero_iff.mpr h
omega
/-! ### mul -/
theorem ofNat'_mul [NeZero n] (x : Nat) (y : Fin n) :
@@ -1002,10 +1038,12 @@ theorem val_mul {n : Nat} : ∀ a b : Fin n, (a * b).val = a.val * b.val % n
theorem coe_mul {n : Nat} : a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
| _, _, _, _ => rfl
protected theorem mul_one (k : Fin (n + 1)) : k * 1 = k := by
match n with
| 0 => exact Subsingleton.elim (α := Fin 1) ..
| n+1 => simp [Fin.ext_iff, mul_def, Nat.mod_eq_of_lt (is_lt k)]
protected theorem mul_one [i : NeZero n] (k : Fin n) : k * 1 = k := by
match n, i with
| n + 1, _ =>
match n with
| 0 => exact Subsingleton.elim (α := Fin 1) ..
| n+1 => simp [Fin.ext_iff, mul_def, Nat.mod_eq_of_lt (is_lt k)]
protected theorem mul_comm (a b : Fin n) : a * b = b * a :=
Fin.ext <| by rw [mul_def, mul_def, Nat.mul_comm]
@@ -1018,15 +1056,17 @@ protected theorem mul_assoc (a b c : Fin n) : a * b * c = a * (b * c) := by
simp only [ Nat.mul_mod, Nat.mul_assoc]
instance : Std.Associative (α := Fin n) (· * ·) := Fin.mul_assoc
protected theorem one_mul (k : Fin (n + 1)) : (1 : Fin (n + 1)) * k = k := by
protected theorem one_mul [NeZero n] (k : Fin n) : (1 : Fin n) * k = k := by
rw [Fin.mul_comm, Fin.mul_one]
instance : Std.LawfulIdentity (α := Fin (n + 1)) (· * ·) 1 where
instance [NeZero n] : Std.LawfulIdentity (α := Fin n) (· * ·) 1 where
left_id := Fin.one_mul
right_id := Fin.mul_one
protected theorem mul_zero (k : Fin (n + 1)) : k * 0 = 0 := by simp [Fin.ext_iff, mul_def]
protected theorem mul_zero [NeZero n] (k : Fin n) : k * 0 = 0 := by
simp [Fin.ext_iff, mul_def]
protected theorem zero_mul (k : Fin (n + 1)) : (0 : Fin (n + 1)) * k = 0 := by
protected theorem zero_mul [NeZero n] (k : Fin n) : (0 : Fin n) * k = 0 := by
simp [Fin.ext_iff, mul_def]
end Fin

View File

@@ -291,8 +291,11 @@ implementation.
instance : Inhabited Float where
default := UInt64.toFloat 0
protected def Float.repr (n : Float) (prec : Nat) : Std.Format :=
if n < UInt64.toFloat 0 then Repr.addAppParen (toString n) prec else toString n
instance : Repr Float where
reprPrec n prec := if n < UInt64.toFloat 0 then Repr.addAppParen (toString n) prec else toString n
reprPrec := Float.repr
instance : ReprAtom Float :=

View File

@@ -292,8 +292,11 @@ implementation.
instance : Inhabited Float32 where
default := UInt64.toFloat32 0
protected def Float32.repr (n : Float32) (prec : Nat) : Std.Format :=
if n < UInt64.toFloat32 0 then Repr.addAppParen (toString n) prec else toString n
instance : Repr Float32 where
reprPrec n prec := if n < UInt64.toFloat32 0 then Repr.addAppParen (toString n) prec else toString n
reprPrec := Float32.repr
instance : ReprAtom Float32 :=

View File

@@ -7,7 +7,8 @@ module
prelude
import Init.Data.UInt.Basic
import Init.Data.String
import Init.Data.String.Basic
import Init.Data.ByteArray.Basic
universe u
instance : Hashable Nat where

View File

@@ -108,7 +108,7 @@ theorem resolve_left_lt_lcm (a c d p x : Int) (a_pos : 0 < a) (d_pos : 0 < d) (h
resolve_left a c d p x < lcm a (a * d / gcd (a * d) c) := by
simp only [h₁, resolve_left_eq, resolve_left', add_of_le, Int.ofNat_lt]
exact Nat.mod_lt _ (Nat.pos_of_ne_zero (lcm_ne_zero (Int.ne_of_gt a_pos)
(Int.ne_of_gt (Int.ediv_pos_of_pos_of_dvd (Int.mul_pos a_pos d_pos) (Int.ofNat_nonneg _)
(Int.ne_of_gt (Int.ediv_pos_of_pos_of_dvd (Int.mul_pos a_pos d_pos) (Int.natCast_nonneg _)
(gcd_dvd_left _ _)))))
theorem resolve_left_ineq (a c d p x : Int) (a_pos : 0 < a) (b_pos : 0 < b)

View File

@@ -44,7 +44,7 @@ Integer division that uses the E-rounding convention. Usually accessed via the `
Division by zero is defined to be zero, rather than an error.
In the E-rounding convention (Euclidean division), `Int.emod x y` satisfies `0 ≤ Int.emod x y < Int.natAbs y`
for `y ≠ 0` and `Int.ediv` is the unique function satisfying `Int.emod x y + (Int.edivx y) * y = x`
for `y ≠ 0` and `Int.ediv` is the unique function satisfying `Int.emod x y + (Int.ediv x y) * y = x`
for `y ≠ 0`.
This means that `Int.ediv x y` is `⌊x / y⌋` when `y > 0` and `⌈x / y⌉` when `y < 0`.
@@ -76,7 +76,7 @@ def ediv : (@& Int) → (@& Int) → Int
Integer modulus that uses the E-rounding convention. Usually accessed via the `%` operator.
In the E-rounding convention (Euclidean division), `Int.emod x y` satisfies `0 ≤ Int.emod x y < Int.natAbs y`
for `y ≠ 0` and `Int.ediv` is the unique function satisfying `Int.emod x y + (Int.edivx y) * y = x`
for `y ≠ 0` and `Int.ediv` is the unique function satisfying `Int.emod x y + (Int.ediv x y) * y = x`
for `y ≠ 0`.
This function is overridden by the compiler with an efficient implementation. This definition is

View File

@@ -23,6 +23,8 @@ open Nat (succ)
namespace Int
@[simp high] theorem natCast_eq_zero {n : Nat} : (n : Int) = 0 n = 0 := by omega
protected theorem exists_add_of_le {a b : Int} (h : a b) : (c : Nat), b = a + c :=
(b - a).toNat, by omega
@@ -143,6 +145,20 @@ theorem dvd_of_mul_dvd_mul_left {a m n : Int} (ha : a ≠ 0) (h : a * m a *
theorem dvd_of_mul_dvd_mul_right {a m n : Int} (ha : a 0) (h : m * a n * a) : m n :=
dvd_of_mul_dvd_mul_left ha (by simpa [Int.mul_comm] using h)
@[norm_cast] theorem natCast_dvd_natCast {m n : Nat} : (m : Int) n m n where
mp := by
rintro a, h
obtain rfl | hm := m.eq_zero_or_pos
· simpa using h
have ha : 0 a := Int.not_lt.1 fun ha by
simpa [ h, Int.not_lt.2 (Int.natCast_nonneg _)]
using Int.mul_neg_of_pos_of_neg (natCast_pos.2 hm) ha
match a, ha with
| (a : Nat), _ =>
norm_cast at h
exact a, h
mpr := by rintro a, rfl; simp [Int.dvd_mul_right]
/-! ### *div zero -/
@[simp] protected theorem zero_tdiv : b : Int, tdiv 0 b = 0
@@ -1031,6 +1047,27 @@ theorem ediv_dvd_of_dvd {m n : Int} (hmn : m n) : n / m n := by
· obtain a, ha := hmn
simp [ha, Int.mul_ediv_cancel_left _ hm, Int.dvd_mul_left]
theorem emod_natAbs_of_nonneg {x : Int} (h : 0 x) {n : Nat} :
x.natAbs % n = (x % n).toNat := by
match x, h with
| (x : Nat), _ => rw [Int.natAbs_natCast, Int.ofNat_mod_ofNat, Int.toNat_natCast]
theorem emod_natAbs_of_neg {x : Int} (h : x < 0) {n : Nat} (w : n 0) :
x.natAbs % n = if (n : Int) x then 0 else n - (x % n).toNat := by
match x, h with
| -(x + 1 : Nat), _ =>
rw [Int.natAbs_neg]
rw [Int.natAbs_cast]
rw [Int.neg_emod]
simp only [Int.dvd_neg]
simp only [Int.natCast_dvd_natCast]
split <;> rename_i h
· rw [Nat.mod_eq_zero_of_dvd h]
· rw [ Int.natCast_emod]
simp only [Int.natAbs_natCast]
have : (x + 1) % n < n := Nat.mod_lt (x + 1) (by omega)
omega
/-! ### `/` and ordering -/
protected theorem ediv_mul_le (a : Int) {b : Int} (H : b 0) : a / b * b a :=
@@ -1308,7 +1345,7 @@ theorem sign_tdiv (a b : Int) : sign (a.tdiv b) = if natAbs a < natAbs b then 0
theorem ofNat_tmod (m n : Nat) : ((m % n) : Int) = tmod m n := rfl
theorem tmod_nonneg : {a : Int} (b : Int), 0 a 0 tmod a b
| ofNat _, -[_+1], _ | ofNat _, ofNat _, _ => ofNat_nonneg _
| ofNat _, -[_+1], _ | ofNat _, ofNat _, _ => natCast_nonneg _
@[simp] theorem tmod_neg (a b : Int) : tmod a (-b) = tmod a b := by
rw [tmod_def, tmod_def, Int.tdiv_neg, Int.neg_mul_neg]
@@ -1321,7 +1358,7 @@ theorem tmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : tmod a b < b :=
match a, b, eq_succ_of_zero_lt H with
| ofNat _, _, n, rfl => ofNat_lt.2 <| Nat.mod_lt _ n.succ_pos
| -[_+1], _, n, rfl => Int.lt_of_le_of_lt
(Int.neg_nonpos_of_nonneg <| Int.ofNat_nonneg _) (ofNat_pos.2 n.succ_pos)
(Int.neg_nonpos_of_nonneg <| natCast_nonneg _) (natCast_pos.2 n.succ_pos)
theorem lt_tmod_of_pos (a : Int) {b : Int} (H : 0 < b) : -b < tmod a b :=
match a, b, eq_succ_of_zero_lt H with
@@ -1724,7 +1761,7 @@ protected theorem tdiv_mul_le (a : Int) {b : Int} (hb : b ≠ 0) : a.tdiv b * b
· simp_all [tmod_nonneg]
· match b, hb with
| .ofNat (b + 1), _ =>
have := lt_tmod_of_pos a (Int.ofNat_pos.2 (b.succ_pos))
have := lt_tmod_of_pos a (natCast_pos.2 (b.succ_pos))
simp_all
omega
| .negSucc b, _ =>
@@ -2679,8 +2716,8 @@ theorem le_bmod {x : Int} {m : Nat} (h : 0 < m) : - (m/2) ≤ Int.bmod x m := by
have v : (m : Int) % 2 = 0 (m : Int) % 2 = 1 := emod_two_eq _
split <;> rename_i w
· refine Int.le_trans ?_ (Int.emod_nonneg _ ?_)
· exact Int.neg_nonpos_of_nonneg (Int.ediv_nonneg (Int.ofNat_nonneg _) (by decide))
· exact Int.ne_of_gt (ofNat_pos.mpr h)
· exact Int.neg_nonpos_of_nonneg (Int.ediv_nonneg (natCast_nonneg _) (by decide))
· exact Int.ne_of_gt (natCast_pos.mpr h)
· simp [Int.not_lt] at w
refine Int.le_trans ?_ (Int.sub_le_sub_right w _)
rw [ ediv_add_emod m 2]
@@ -2713,7 +2750,7 @@ theorem bmod_lt {x : Int} {m : Nat} (h : 0 < m) : bmod x m < (m + 1) / 2 := by
· assumption
· apply Int.lt_of_lt_of_le
· show _ < 0
have : x % m < m := emod_lt_of_pos x (ofNat_pos.mpr h)
have : x % m < m := emod_lt_of_pos x (natCast_pos.mpr h)
exact Int.sub_neg_of_lt this
· exact Int.le.intro_sub _ rfl

View File

@@ -594,4 +594,6 @@ protected theorem natCast_zero : ((0 : Nat) : Int) = (0 : Int) := rfl
protected theorem natCast_one : ((1 : Nat) : Int) = (1 : Int) := rfl
@[simp, norm_cast] theorem natAbs_cast (n : Nat) : natAbs n = n := rfl
end Int

View File

@@ -25,7 +25,7 @@ namespace Int
@[simp] protected theorem neg_nonpos_iff (i : Int) : -i 0 0 i := by omega
@[simp] theorem zero_le_ofNat (n : Nat) : 0 ((no_index (OfNat.ofNat n)) : Int) :=
ofNat_nonneg _
natCast_nonneg _
@[simp] theorem neg_natCast_le_natCast (n m : Nat) : -(n : Int) (m : Int) :=
Int.le_trans (by simp) (ofNat_zero_le m)
@@ -52,25 +52,17 @@ protected theorem ofNat_add_one_out (n : Nat) : ↑n + (1 : Int) = ↑(Nat.succ
@[norm_cast] theorem natCast_inj {m n : Nat} : (m : Int) = (n : Int) m = n := ofNat_inj
@[simp, norm_cast] theorem natAbs_cast (n : Nat) : natAbs n = n := rfl
@[norm_cast]
protected theorem natCast_sub {n m : Nat} : n m ((m - n) : Int) = m - n := ofNat_sub
@[simp high] theorem natCast_eq_zero {n : Nat} : (n : Int) = 0 n = 0 := by omega
theorem natCast_ne_zero {n : Nat} : (n : Int) 0 n 0 := by omega
theorem natCast_ne_zero_iff_pos {n : Nat} : (n : Int) 0 0 < n := by omega
@[simp high] theorem natCast_pos {n : Nat} : (0 : Int) < n 0 < n := by omega
theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_pos
@[simp high] theorem natCast_nonpos_iff {n : Nat} : (n : Int) 0 n = 0 := by omega
theorem natCast_nonneg (n : Nat) : 0 (n : Int) := ofNat_le.2 (Nat.zero_le _)
@[simp] theorem sign_natCast_add_one (n : Nat) : sign (n + 1) = 1 := rfl
@[simp, norm_cast] theorem cast_id {n : Int} : Int.cast n = n := rfl

View File

@@ -282,7 +282,6 @@ attribute [local simp] Poly.denote_addConst
theorem Poly.denote_insert (ctx : Context) (k : Int) (v : Var) (p : Poly) :
(p.insert k v).denote ctx = p.denote ctx + k * v.denote ctx := by
fun_induction p.insert k v <;>
simp only [insert, cond_true, cond_false, reduceIte, *] <;>
simp_all [ Int.add_mul]
attribute [local simp] Poly.denote_insert
@@ -299,7 +298,6 @@ attribute [local simp] Poly.denote_append
theorem Poly.denote_combine' (ctx : Context) (fuel : Nat) (p₁ p₂ : Poly) : (p₁.combine' fuel p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
fun_induction p₁.combine' fuel p₂ <;>
simp +zetaDelta only [combine', cond_true, cond_false, *] <;>
simp_all +zetaDelta [denote, Int.add_mul]
theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by

View File

@@ -77,8 +77,14 @@ theorem lt.dest {a b : Int} (h : a < b) : ∃ n : Nat, a + Nat.succ n = b :=
@[simp, norm_cast] theorem ofNat_lt {n m : Nat} : (n : Int) < m n < m := by
rw [lt_iff_add_one_le, natCast_succ, ofNat_le]; rfl
@[simp, norm_cast] theorem ofNat_pos {n : Nat} : 0 < (n : Int) 0 < n := ofNat_lt
@[simp, norm_cast] theorem natCast_pos {n : Nat} : (0 : Int) < n 0 < n := ofNat_lt
@[deprecated natCast_pos (since := "2025-05-13"), simp high]
theorem ofNat_pos {n : Nat} : 0 < (n : Int) 0 < n := ofNat_lt
theorem natCast_nonneg (n : Nat) : 0 (n : Int) := _
@[deprecated natCast_nonneg (since := "2025-05-13")]
theorem ofNat_nonneg (n : Nat) : 0 (n : Int) := _
theorem ofNat_succ_pos (n : Nat) : 0 < (succ n : Int) := ofNat_lt.2 <| Nat.succ_pos _
@@ -475,7 +481,7 @@ instance : Std.IdempotentOp (α := Int) max := ⟨Int.max_self⟩
protected theorem mul_nonneg {a b : Int} (ha : 0 a) (hb : 0 b) : 0 a * b := by
let n, hn := eq_ofNat_of_zero_le ha
let m, hm := eq_ofNat_of_zero_le hb
rw [hn, hm, natCast_mul]; apply ofNat_nonneg
rw [hn, hm, natCast_mul]; apply natCast_nonneg
protected theorem mul_pos {a b : Int} (ha : 0 < a) (hb : 0 < b) : 0 < a * b := by
let n, hn := eq_succ_of_zero_lt ha
@@ -1253,7 +1259,7 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
| 0 => rfl
| .ofNat (_ + 1) =>
simp +decide only [sign, true_iff]
exact Int.le_add_one (ofNat_nonneg _)
exact Int.le_add_one (natCast_nonneg _)
| .negSucc _ => simp +decide [sign]
@[deprecated sign_nonneg_iff (since := "2025-03-11")] abbrev sign_nonneg := @sign_nonneg_iff

View File

@@ -29,6 +29,11 @@ protected theorem pow_nonneg {n : Int} {m : Nat} : 0 ≤ n → 0 ≤ n ^ m := by
| zero => simp
| succ m ih => exact fun h => Int.mul_nonneg (ih h) h
protected theorem pow_ne_zero {n : Int} {m : Nat} : n 0 n ^ m 0 := by
induction m with
| zero => simp
| succ m ih => exact fun h => Int.mul_ne_zero (ih h) h
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left

View File

@@ -90,8 +90,6 @@ theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a,
| cons x l ih =>
rw [pmap, pmap, h _ mem_cons_self, ih fun a ha => h a (mem_cons_of_mem _ ha)]
@[deprecated pmap_congr_left (since := "2024-09-06")] abbrev pmap_congr := @pmap_congr_left
theorem map_pmap {p : α Prop} {g : β γ} {f : a, p a β} {l : List α} (H) :
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
induction l
@@ -237,11 +235,6 @@ theorem attachWith_ne_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l,
l.attachWith P H [] l [] :=
pmap_ne_nil_iff _ _
@[deprecated pmap_eq_nil_iff (since := "2024-09-06")] abbrev pmap_eq_nil := @pmap_eq_nil_iff
@[deprecated pmap_ne_nil_iff (since := "2024-09-06")] abbrev pmap_ne_nil := @pmap_ne_nil_iff
@[deprecated attach_eq_nil_iff (since := "2024-09-06")] abbrev attach_eq_nil := @attach_eq_nil_iff
@[deprecated attach_ne_nil_iff (since := "2024-09-06")] abbrev attach_ne_nil := @attach_ne_nil_iff
@[simp]
theorem getElem?_pmap {p : α Prop} {f : a, p a β} {l : List α} (h : a l, p a) (i : Nat) :
(pmap f l h)[i]? = Option.pmap f l[i]? fun x H => h x (mem_of_getElem? H) := by
@@ -776,8 +769,6 @@ and simplifies these to the function directly taking the value.
| nil => simp
| cons a l ih => simp [ih, hf]
@[deprecated flatMap_subtype (since := "2024-10-16")] abbrev bind_subtype := @flatMap_subtype
@[simp] theorem findSome?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
l.findSome? f = l.unattach.findSome? g := by
@@ -830,8 +821,6 @@ and simplifies these to the function directly taking the value.
unfold unattach
induction l <;> simp_all
@[deprecated unattach_flatten (since := "2024-10-14")] abbrev unattach_join := @unattach_flatten
@[simp] theorem unattach_replicate {p : α Prop} {n : Nat} {x : { x // p x }} :
(List.replicate n x).unattach = List.replicate n x.1 := by
simp [unattach, -map_subtype]

View File

@@ -703,8 +703,6 @@ def flatten : List (List α) → List α
@[simp, grind] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
@[simp, grind] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
@[deprecated flatten (since := "2024-10-14"), inherit_doc flatten] abbrev join := @flatten
/-! ### singleton -/
/--
@@ -717,9 +715,6 @@ Examples:
-/
@[inline] protected def singleton {α : Type u} (a : α) : List α := [a]
set_option linter.missingDocs false in
@[deprecated singleton (since := "2024-10-16")] protected abbrev pure := @singleton
/-! ### flatMap -/
/--
@@ -736,13 +731,6 @@ Examples:
@[simp, grind] theorem flatMap_cons {x : α} {xs : List α} {f : α List β} :
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [flatten, List.flatMap]
set_option linter.missingDocs false in
@[deprecated flatMap (since := "2024-10-16")] abbrev bind := @flatMap
set_option linter.missingDocs false in
@[deprecated flatMap_nil (since := "2024-10-16")] abbrev nil_flatMap := @flatMap_nil
set_option linter.missingDocs false in
@[deprecated flatMap_cons (since := "2024-10-16")] abbrev cons_flatMap := @flatMap_cons
/-! ### replicate -/
/--
@@ -2087,18 +2075,6 @@ def sum {α} [Add α] [Zero α] : List αα :=
@[simp, grind] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
@[simp, grind] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
/-- Sum of a list of natural numbers. -/
@[deprecated List.sum (since := "2024-10-17")]
protected def _root_.Nat.sum (l : List Nat) : Nat := l.foldr (·+·) 0
set_option linter.deprecated false in
@[deprecated sum_nil (since := "2024-10-17")]
theorem _root_.Nat.sum_nil : Nat.sum ([] : List Nat) = 0 := rfl
set_option linter.deprecated false in
@[deprecated sum_cons (since := "2024-10-17")]
theorem _root_.Nat.sum_cons (a : Nat) (l : List Nat) :
Nat.sum (a::l) = a + Nat.sum l := rfl
/-! ### range -/
/--
@@ -2220,8 +2196,6 @@ def min? [Min α] : List α → Option α
| [] => none
| a::as => some <| as.foldl min a
@[inherit_doc min?, deprecated min? (since := "2024-09-29")] abbrev minimum? := @min?
/-! ### max? -/
/--
@@ -2236,8 +2210,6 @@ def max? [Max α] : List α → Option α
| [] => none
| a::as => some <| as.foldl max a
@[inherit_doc max?, deprecated max? (since := "2024-09-29")] abbrev maximum? := @max?
/-! ## Other list operations
The functions are currently mostly used in meta code,
@@ -2410,8 +2382,6 @@ where
| false => loop as a [] ((b::r).reverse::acc)
| [], ag, r, acc => ((ag::r).reverse::acc).reverse
@[deprecated splitBy (since := "2024-10-30"), inherit_doc splitBy] abbrev groupBy := @splitBy
/-! ### removeAll -/
/--

View File

@@ -83,8 +83,6 @@ theorem countP_le_length : countP p l ≤ l.length := by
@[simp] theorem countP_pos_iff {p} : 0 < countP p l a l, p a := by
simp only [countP_eq_length_filter, length_pos_iff_exists_mem, mem_filter, exists_prop]
@[deprecated countP_pos_iff (since := "2024-09-09")] abbrev countP_pos := @countP_pos_iff
@[simp] theorem one_le_countP_iff {p} : 1 countP p l a l, p a :=
countP_pos_iff
@@ -165,8 +163,6 @@ theorem countP_filterMap {p : β → Bool} {f : α → Option β} {l : List α}
simp only [countP_eq_length_filter, filter_flatten]
simp [countP_eq_length_filter']
@[deprecated countP_flatten (since := "2024-10-14")] abbrev countP_join := @countP_flatten
theorem countP_flatMap {p : β Bool} {l : List α} {f : α List β} :
countP p (l.flatMap f) = sum (map (countP p f) l) := by
rw [List.flatMap, countP_flatten, map_map]
@@ -242,8 +238,6 @@ theorem count_singleton {a b : α} : count a [b] = if b == a then 1 else 0 := by
theorem count_flatten {a : α} {l : List (List α)} : count a l.flatten = (l.map (count a)).sum := by
simp only [count_eq_countP, countP_flatten, count_eq_countP']
@[deprecated count_flatten (since := "2024-10-14")] abbrev count_join := @count_flatten
@[simp] theorem count_reverse {a : α} {l : List α} : count a l.reverse = count a l := by
simp only [count_eq_countP, countP_eq_length_filter, filter_reverse, length_reverse]
@@ -268,8 +262,6 @@ theorem count_concat_self {a : α} {l : List α} : count a (concat l a) = count
theorem count_pos_iff {a : α} {l : List α} : 0 < count a l a l := by
simp only [count, countP_pos_iff, beq_iff_eq, exists_eq_right]
@[deprecated count_pos_iff (since := "2024-09-09")] abbrev count_pos_iff_mem := @count_pos_iff
@[simp] theorem one_le_count_iff {a : α} {l : List α} : 1 count a l a l :=
count_pos_iff

View File

@@ -47,8 +47,6 @@ theorem exists_of_findSome?_eq_some {l : List α} {f : α → Option β} (w : l.
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none x l, p x = none := by
induction l <;> simp [findSome?_cons]; split <;> simp [*]
@[deprecated findSome?_eq_none_iff (since := "2024-09-05")] abbrev findSome?_eq_none := @findSome?_eq_none_iff
@[simp] theorem findSome?_isSome_iff {f : α Option β} {l : List α} :
(l.findSome? f).isSome x, x l (f x).isSome := by
induction l with
@@ -386,17 +384,10 @@ abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
simp [flatMap_def, findSome?_map]; rfl
@[deprecated find?_flatMap (since := "2024-10-16")] abbrev find?_bind := @find?_flatMap
theorem find?_flatMap_eq_none_iff {xs : List α} {f : α List β} {p : β Bool} :
(xs.flatMap f).find? p = none x xs, y f x, !p y := by
simp
@[deprecated find?_flatMap_eq_none_iff (since := "2024-10-16")]
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
@[deprecated find?_flatMap_eq_none (since := "2024-10-16")] abbrev find?_bind_eq_none := @find?_flatMap_eq_none_iff
theorem find?_replicate : find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
cases n
· simp
@@ -1270,13 +1261,4 @@ theorem IsInfix.lookup_eq_none {l₁ l₂ : List (α × β)} (h : l₁ <:+: l₂
end lookup
/-! ### Deprecations -/
@[deprecated head_flatten (since := "2024-10-14")] abbrev head_join := @head_flatten
@[deprecated getLast_flatten (since := "2024-10-14")] abbrev getLast_join := @getLast_flatten
@[deprecated find?_flatten (since := "2024-10-14")] abbrev find?_join := @find?_flatten
@[deprecated find?_flatten_eq_none (since := "2024-10-14")] abbrev find?_join_eq_none := @find?_flatten_eq_none_iff
@[deprecated find?_flatten_eq_some (since := "2024-10-14")] abbrev find?_join_eq_some := @find?_flatten_eq_some_iff
@[deprecated findIdx?_flatten (since := "2024-10-14")] abbrev findIdx?_join := @findIdx?_flatten
end List

View File

@@ -92,7 +92,9 @@ open Nat
/-! ### length -/
@[grind ] theorem eq_nil_of_length_eq_zero (_ : length l = 0) : l = [] := match l with | [] => rfl
-- Note: this is not a good `grind` candidate,
-- as in some circumstances it results in many case splits.
theorem eq_nil_of_length_eq_zero (_ : length l = 0) : l = [] := match l with | [] => rfl
theorem ne_nil_of_length_eq_add_one (_ : length l = n + 1) : l [] := fun _ => nomatch l
@@ -239,15 +241,17 @@ theorem getElem!_eq_getElem?_getD [Inhabited α] {l : List α} {i : Nat} :
@[simp, grind =] theorem getElem?_nil {i : Nat} : ([] : List α)[i]? = none := rfl
@[grind =]
theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
(a :: l)[i] =
if h : i = 0 then a else l[i-1]'(match i, h with | i+1, _ => succ_lt_succ_iff.mp w) := by
cases i <;> simp
@[grind =] theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
@[simp, grind =] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
@[grind =]
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
cases i <;> simp [getElem?_cons_zero]
@@ -313,7 +317,7 @@ theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_po
match l, h with
| _ :: _, _ => rfl
@[ext, grind ext] theorem ext_getElem? {l₁ l₂ : List α} (h : i : Nat, l₁[i]? = l₂[i]?) : l₁ = l₂ :=
@[ext] theorem ext_getElem? {l₁ l₂ : List α} (h : i : Nat, l₁[i]? = l₂[i]?) : l₁ = l₂ :=
match l₁, l₂, h with
| [], [], _ => rfl
| _ :: _, [], h => by simpa using h 0
@@ -595,7 +599,7 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
@[simp] theorem all_eq_false {l : List α} : l.all p = false x, x l ¬p x := by
simp [all_eq]
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
@[grind] theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
induction l <;> simp_all [contains_cons]
/-- Variant of `any_beq` with `==` reversed. -/
@@ -603,7 +607,7 @@ theorem any_beq' [BEq α] [PartialEquivBEq α] {l : List α} :
(l.any fun x => x == a) = l.contains a := by
simp only [BEq.comm, any_beq]
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
@[grind] theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
induction l <;> simp_all [bne]
/-- Variant of `all_bne` with `!=` reversed. -/
@@ -1139,8 +1143,6 @@ theorem forall_mem_map {f : α → β} {l : List α} {P : β → Prop} :
@[simp] theorem map_eq_nil_iff {f : α β} {l : List α} : map f l = [] l = [] := by
constructor <;> exact fun _ => match l with | [] => rfl
@[deprecated map_eq_nil_iff (since := "2024-09-05")] abbrev map_eq_nil := @map_eq_nil_iff
@[grind ]
theorem eq_nil_of_map_eq_nil {f : α β} {l : List α} (h : map f l = []) : l = [] :=
map_eq_nil_iff.mp h
@@ -1182,14 +1184,10 @@ theorem map_eq_cons_iff {f : α → β} {l : List α} :
· rintro a, l₁, rfl, rfl, rfl, rfl
constructor <;> rfl
@[deprecated map_eq_cons_iff (since := "2024-09-05")] abbrev map_eq_cons := @map_eq_cons_iff
theorem map_eq_cons_iff' {f : α β} {l : List α} :
map f l = b :: l₂ l.head?.map f = some b l.tail?.map (map f) = some l₂ := by
induction l <;> simp_all
@[deprecated map_eq_cons' (since := "2024-09-05")] abbrev map_eq_cons' := @map_eq_cons_iff'
@[simp] theorem map_eq_singleton_iff {f : α β} {l : List α} {b : β} :
map f l = [b] a, l = [a] f a = b := by
simp [map_eq_cons_iff]
@@ -1214,11 +1212,6 @@ theorem map_eq_foldr {f : α → β} {l : List α} : map f l = foldr (fun a bs =
| 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 α} {i : Nat} {a : α} :
(map f l).set i (f a) = map f (l.set i a) := by
simp
@[simp] theorem head_map {f : α β} {l : List α} (w) :
(map f l).head w = f (l.head (by simpa using w)) := by
cases l
@@ -1320,8 +1313,6 @@ abbrev filter_length_eq_length := @length_filter_eq_length_iff
@[simp] theorem filter_eq_nil_iff {l} : filter p l = [] a, a l ¬p a := by
simp only [eq_nil_iff_forall_not_mem, mem_filter, not_and]
@[deprecated filter_eq_nil_iff (since := "2024-09-05")] abbrev filter_eq_nil := @filter_eq_nil_iff
theorem forall_mem_filter {l : List α} {p : α Bool} {P : α Prop} :
( (i) (_ : i l.filter p), P i) (j) (_ : j l), p j P j := by
simp
@@ -1383,8 +1374,6 @@ theorem filter_eq_cons_iff {l} {a} {as} :
· rintro l₁, l₂, rfl, h₁, h, h₂
simp [h₂, filter_cons, filter_eq_nil_iff.mpr h₁, h]
@[deprecated filter_eq_cons_iff (since := "2024-09-05")] abbrev filter_eq_cons := @filter_eq_cons_iff
theorem filter_congr {p q : α Bool} :
{l : List α}, ( x l, p x = q x) filter p l = filter q l
| [], _ => rfl
@@ -1544,8 +1533,6 @@ theorem forall_none_of_filterMap_eq_nil (h : filterMap f xs = []) : ∀ x ∈ xs
simp_all
· simp_all
@[deprecated filterMap_eq_nil_iff (since := "2024-09-05")] abbrev filterMap_eq_nil := @filterMap_eq_nil_iff
theorem filterMap_eq_cons_iff {l} {b} {bs} :
filterMap f l = b :: bs
l₁ a l₂, l = l₁ ++ a :: l₂ ( x, x l₁ f x = none) f a = some b
@@ -1568,8 +1555,6 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
· rintro l₁, a, l₂, rfl, h₁, h₂, h₃
simp_all [filterMap_eq_nil_iff.mpr h₁, filterMap_cons_some h₂]
@[deprecated filterMap_eq_cons_iff (since := "2024-09-05")] abbrev filterMap_eq_cons := @filterMap_eq_cons_iff
/-! ### append -/
@[simp] theorem nil_append_fun : (([] : List α) ++ ·) = id := rfl
@@ -1826,14 +1811,10 @@ theorem filterMap_eq_append_iff {f : α → Option β} :
· rintro l₁, l₂, rfl, rfl, rfl
simp
@[deprecated filterMap_eq_append_iff (since := "2024-09-05")] abbrev filterMap_eq_append := @filterMap_eq_append_iff
theorem append_eq_filterMap_iff {f : α Option β} :
L₁ ++ L₂ = filterMap f l l₁ l₂, l = l₁ ++ l₂ filterMap f l₁ = L₁ filterMap f l₂ = L₂ := by
rw [eq_comm, filterMap_eq_append_iff]
@[deprecated append_eq_filterMap (since := "2024-09-05")] abbrev append_eq_filterMap := @append_eq_filterMap_iff
theorem filter_eq_append_iff {p : α Bool} :
filter p l = L₁ ++ L₂ l₁ l₂, l = l₁ ++ l₂ filter p l₁ = L₁ filter p l₂ = L₂ := by
rw [ filterMap_eq_filter, filterMap_eq_append_iff]
@@ -1842,8 +1823,6 @@ theorem append_eq_filter_iff {p : α → Bool} :
L₁ ++ L₂ = filter p l l₁ l₂, l = l₁ ++ l₂ filter p l₁ = L₁ filter p l₂ = L₂ := by
rw [eq_comm, filter_eq_append_iff]
@[deprecated append_eq_filter_iff (since := "2024-09-05")] abbrev append_eq_filter := @append_eq_filter_iff
@[simp, grind] theorem map_append {f : α β} : {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
intro l₁; induction l₁ <;> intros <;> simp_all
@@ -1855,9 +1834,6 @@ theorem append_eq_map_iff {f : α → β} :
L₁ ++ L₂ = map f l l₁ l₂, l = l₁ ++ l₂ map f l₁ = L₁ map f l₂ = L₂ := by
rw [eq_comm, map_eq_append_iff]
@[deprecated map_eq_append_iff (since := "2024-09-05")] abbrev map_eq_append := @map_eq_append_iff
@[deprecated append_eq_map_iff (since := "2024-09-05")] abbrev append_eq_map := @append_eq_map_iff
/-! ### concat
Note that `concat_eq_append` is a `@[simp]` lemma, so `concat` should usually not appear in goals.
@@ -1889,8 +1865,6 @@ theorem concat_inj_left {l l' : List α} (a : α) : concat l a = concat l' a ↔
theorem concat_inj_right {l : List α} {a a' : α} : concat l a = concat l a' a = a' :=
last_eq_of_concat_eq, by simp
@[deprecated concat_inj (since := "2024-09-05")] abbrev concat_eq_concat := @concat_inj
theorem concat_append {a : α} {l₁ l₂ : List α} : concat l₁ a ++ l₂ = l₁ ++ a :: l₂ := by simp
theorem append_concat {a : α} {l₁ l₂ : List α} : l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a := by simp
@@ -2104,8 +2078,6 @@ theorem flatMap_eq_nil_iff {l : List α} {f : α → List β} : l.flatMap f = []
flatten_eq_nil_iff.trans <| by
simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
@[deprecated flatMap_eq_nil_iff (since := "2024-09-05")] abbrev bind_eq_nil := @flatMap_eq_nil_iff
theorem forall_mem_flatMap {p : β Prop} {l : List α} {f : α List β} :
( (x) (_ : x l.flatMap f), p x) (a) (_ : a l) (b) (_ : b f a), p b := by
simp only [mem_flatMap, forall_exists_index, and_imp]
@@ -2184,12 +2156,6 @@ theorem contains_replicate [BEq α] {n : Nat} {a b : α} :
simp only [replicate_succ, elem_cons]
split <;> simp_all
@[deprecated mem_replicate (since := "2024-09-05")]
theorem decide_mem_replicate [BEq α] [LawfulBEq α] {a b : α} :
{n}, decide (b replicate n a) = ((¬ n == 0) && b == a) := by
have : DecidableEq α := instDecidableEqOfLawfulBEq
simp [Bool.beq_eq_decide_eq]
@[grind ] theorem eq_of_mem_replicate {a b : α} {n} (h : b replicate n a) : b = a := (mem_replicate.1 h).2
theorem forall_mem_replicate {p : α Prop} {a : α} {n} :
@@ -2202,8 +2168,6 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[simp] theorem replicate_eq_nil_iff {n : Nat} (a : α) : replicate n a = [] n = 0 := by
cases n <;> simp
@[deprecated replicate_eq_nil_iff (since := "2024-09-05")] abbrev replicate_eq_nil := @replicate_eq_nil_iff
@[simp, grind] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
(replicate n a)[i] = a :=
eq_of_mem_replicate (getElem_mem _)
@@ -2255,8 +2219,6 @@ theorem eq_replicate_iff {a : α} {n} {l : List α} :
fun h => h length_replicate .., fun _ => eq_of_mem_replicate,
fun e, al => e eq_replicate_of_mem al
@[deprecated eq_replicate_iff (since := "2024-09-05")] abbrev eq_replicate := @eq_replicate_iff
theorem map_eq_replicate_iff {l : List α} {f : α β} {b : β} :
l.map f = replicate l.length b x l, f x = b := by
simp [eq_replicate_iff]
@@ -2298,8 +2260,6 @@ theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
{ mp := fun h => fun b m => h b (Or.inl m), fun b m => h b (Or.inr m),
mpr := fun h b x => Or.casesOn x (fun m => h.left b m) fun m => h.right b m }
@[deprecated append_eq_replicate_iff (since := "2024-09-05")] abbrev append_eq_replicate := @append_eq_replicate_iff
theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
replicate n a = l₁ ++ l₂
l₁.length + l₂.length = n l₁ = replicate l₁.length a l₂ = replicate l₂.length a := by
@@ -2479,8 +2439,6 @@ theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse :
xs.reverse = a :: ys xs = ys.reverse ++ [a] := by
rw [reverse_eq_iff, reverse_cons]
@[deprecated reverse_eq_cons_iff (since := "2024-09-05")] abbrev reverse_eq_cons := @reverse_eq_cons_iff
@[simp, grind] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
cases l <;> simp [getLast?_concat]
@@ -2531,8 +2489,6 @@ theorem getLast_of_mem_getLast? {l : List α} (hx : x ∈ l.getLast?) :
xs.reverse = ys ++ zs xs = zs.reverse ++ ys.reverse := by
rw [reverse_eq_iff, reverse_append]
@[deprecated reverse_eq_append_iff (since := "2024-09-05")] abbrev reverse_eq_append := @reverse_eq_append_iff
@[grind _=_] theorem reverse_concat {l : List α} {a : α} : (l ++ [a]).reverse = a :: l.reverse := by
rw [reverse_append]; rfl
@@ -2638,8 +2594,6 @@ theorem foldr_eq_foldrM {f : α → β → β} {b : β} {l : List α} :
theorem foldr_cons_nil {l : List α} : l.foldr cons [] = l := by simp
@[deprecated foldr_cons_nil (since := "2024-09-04")] abbrev foldr_self := @foldr_cons_nil
theorem foldl_map {f : β₁ β₂} {g : α β₂ α} {l : List β₁} {init : α} :
(l.map f).foldl g init = l.foldl (fun x y => g x (f y)) init := by
induction l generalizing init <;> simp [*]
@@ -2885,8 +2839,6 @@ theorem getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔
rw [getLast?_eq_head?_reverse, isSome_head?]
simp
@[deprecated mem_of_getLast? (since := "2024-10-21")] abbrev mem_of_getLast?_eq_some := @mem_of_getLast?
@[simp, grind] theorem getLast_reverse {l : List α} (h : l.reverse []) :
l.reverse.getLast h = l.head (by simp_all) := by
simp [getLast_eq_head_reverse]
@@ -3275,13 +3227,9 @@ theorem all_eq_not_any_not {l : List α} {p : α → Bool} : l.all p = !l.any (!
@[simp, grind] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
induction l <;> simp_all
@[deprecated any_flatten (since := "2024-10-14")] abbrev any_join := @any_flatten
@[simp, grind] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
induction l <;> simp_all
@[deprecated all_flatten (since := "2024-10-14")] abbrev all_join := @all_flatten
@[simp, grind] theorem any_flatMap {l : List α} {f : α List β} :
(l.flatMap f).any p = l.any fun a => (f a).any p := by
induction l <;> simp_all
@@ -3741,74 +3689,6 @@ theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a :=
/-! ### Deprecations -/
@[deprecated getElem_eq_getElem?_get (since := "2024-09-04")] abbrev getElem_eq_getElem? :=
@getElem_eq_getElem?_get
@[deprecated flatten_eq_nil_iff (since := "2024-09-05")] abbrev join_eq_nil := @flatten_eq_nil_iff
@[deprecated flatten_ne_nil_iff (since := "2024-09-05")] abbrev join_ne_nil := @flatten_ne_nil_iff
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons_iff := @flatten_eq_cons_iff
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons := @flatten_eq_cons_iff
@[deprecated flatten_eq_append_iff (since := "2024-09-05")] abbrev join_eq_append := @flatten_eq_append_iff
@[deprecated mem_of_getElem? (since := "2024-09-06")] abbrev getElem?_mem := @mem_of_getElem?
@[deprecated getElem_set_self (since := "2024-09-04")] abbrev getElem_set_eq := @getElem_set_self
@[deprecated getElem?_set_self (since := "2024-09-04")] abbrev getElem?_set_eq := @getElem?_set_self
@[deprecated set_eq_nil_iff (since := "2024-09-05")] abbrev set_eq_nil := @set_eq_nil_iff
@[deprecated flatten_nil (since := "2024-10-14")] abbrev join_nil := @flatten_nil
@[deprecated flatten_cons (since := "2024-10-14")] abbrev join_cons := @flatten_cons
@[deprecated length_flatten (since := "2024-10-14")] abbrev length_join := @length_flatten
@[deprecated flatten_singleton (since := "2024-10-14")] abbrev join_singleton := @flatten_singleton
@[deprecated mem_flatten (since := "2024-10-14")] abbrev mem_join := @mem_flatten
@[deprecated flatten_eq_nil_iff (since := "2024-10-14")] abbrev join_eq_nil_iff := @flatten_eq_nil_iff
@[deprecated flatten_ne_nil_iff (since := "2024-10-14")] abbrev join_ne_nil_iff := @flatten_ne_nil_iff
@[deprecated exists_of_mem_flatten (since := "2024-10-14")] abbrev exists_of_mem_join := @exists_of_mem_flatten
@[deprecated mem_flatten_of_mem (since := "2024-10-14")] abbrev mem_join_of_mem := @mem_flatten_of_mem
@[deprecated forall_mem_flatten (since := "2024-10-14")] abbrev forall_mem_join := @forall_mem_flatten
@[deprecated flatten_eq_flatMap (since := "2024-10-14")] abbrev join_eq_bind := @flatten_eq_flatMap
@[deprecated head?_flatten (since := "2024-10-14")] abbrev head?_join := @head?_flatten
@[deprecated foldl_flatten (since := "2024-10-14")] abbrev foldl_join := @foldl_flatten
@[deprecated foldr_flatten (since := "2024-10-14")] abbrev foldr_join := @foldr_flatten
@[deprecated map_flatten (since := "2024-10-14")] abbrev map_join := @map_flatten
@[deprecated filterMap_flatten (since := "2024-10-14")] abbrev filterMap_join := @filterMap_flatten
@[deprecated filter_flatten (since := "2024-10-14")] abbrev filter_join := @filter_flatten
@[deprecated flatten_filter_not_isEmpty (since := "2024-10-14")] abbrev join_filter_not_isEmpty := @flatten_filter_not_isEmpty
@[deprecated flatten_filter_ne_nil (since := "2024-10-14")] abbrev join_filter_ne_nil := @flatten_filter_ne_nil
@[deprecated flatten_append (since := "2024-10-14")] abbrev join_append := @flatten_append
@[deprecated flatten_concat (since := "2024-10-14")] abbrev join_concat := @flatten_concat
@[deprecated flatten_flatten (since := "2024-10-14")] abbrev join_join := @flatten_flatten
@[deprecated flatten_eq_append_iff (since := "2024-10-14")] abbrev join_eq_append_iff := @flatten_eq_append_iff
@[deprecated eq_iff_flatten_eq (since := "2024-10-14")] abbrev eq_iff_join_eq := @eq_iff_flatten_eq
@[deprecated flatten_replicate_nil (since := "2024-10-14")] abbrev join_replicate_nil := @flatten_replicate_nil
@[deprecated flatten_replicate_singleton (since := "2024-10-14")] abbrev join_replicate_singleton := @flatten_replicate_singleton
@[deprecated flatten_replicate_replicate (since := "2024-10-14")] abbrev join_replicate_replicate := @flatten_replicate_replicate
@[deprecated reverse_flatten (since := "2024-10-14")] abbrev reverse_join := @reverse_flatten
@[deprecated flatten_reverse (since := "2024-10-14")] abbrev join_reverse := @flatten_reverse
@[deprecated getLast?_flatten (since := "2024-10-14")] abbrev getLast?_join := @getLast?_flatten
@[deprecated flatten_eq_flatMap (since := "2024-10-16")] abbrev flatten_eq_bind := @flatten_eq_flatMap
@[deprecated flatMap_def (since := "2024-10-16")] abbrev bind_def := @flatMap_def
@[deprecated flatMap_id (since := "2024-10-16")] abbrev bind_id := @flatMap_id
@[deprecated mem_flatMap (since := "2024-10-16")] abbrev mem_bind := @mem_flatMap
@[deprecated exists_of_mem_flatMap (since := "2024-10-16")] abbrev exists_of_mem_bind := @exists_of_mem_flatMap
@[deprecated mem_flatMap_of_mem (since := "2024-10-16")] abbrev mem_bind_of_mem := @mem_flatMap_of_mem
@[deprecated flatMap_eq_nil_iff (since := "2024-10-16")] abbrev bind_eq_nil_iff := @flatMap_eq_nil_iff
@[deprecated forall_mem_flatMap (since := "2024-10-16")] abbrev forall_mem_bind := @forall_mem_flatMap
@[deprecated flatMap_singleton (since := "2024-10-16")] abbrev bind_singleton := @flatMap_singleton
@[deprecated flatMap_singleton' (since := "2024-10-16")] abbrev bind_singleton' := @flatMap_singleton'
@[deprecated head?_flatMap (since := "2024-10-16")] abbrev head_bind := @head?_flatMap
@[deprecated flatMap_append (since := "2024-10-16")] abbrev bind_append := @flatMap_append
@[deprecated flatMap_assoc (since := "2024-10-16")] abbrev bind_assoc := @flatMap_assoc
@[deprecated map_flatMap (since := "2024-10-16")] abbrev map_bind := @map_flatMap
@[deprecated flatMap_map (since := "2024-10-16")] abbrev bind_map := @flatMap_map
@[deprecated map_eq_flatMap (since := "2024-10-16")] abbrev map_eq_bind := @map_eq_flatMap
@[deprecated filterMap_flatMap (since := "2024-10-16")] abbrev filterMap_bind := @filterMap_flatMap
@[deprecated filter_flatMap (since := "2024-10-16")] abbrev filter_bind := @filter_flatMap
@[deprecated flatMap_eq_foldl (since := "2024-10-16")] abbrev bind_eq_foldl := @flatMap_eq_foldl
@[deprecated flatMap_replicate (since := "2024-10-16")] abbrev bind_replicate := @flatMap_replicate
@[deprecated reverse_flatMap (since := "2024-10-16")] abbrev reverse_bind := @reverse_flatMap
@[deprecated flatMap_reverse (since := "2024-10-16")] abbrev bind_reverse := @flatMap_reverse
@[deprecated getLast?_flatMap (since := "2024-10-16")] abbrev getLast?_bind := @getLast?_flatMap
@[deprecated any_flatMap (since := "2024-10-16")] abbrev any_bind := @any_flatMap
@[deprecated all_flatMap (since := "2024-10-16")] abbrev all_bind := @all_flatMap
@[deprecated get?_eq_none (since := "2024-11-29")] abbrev get?_len_le := @getElem?_eq_none
@[deprecated getElem?_eq_some_iff (since := "2024-11-29")]
abbrev getElem?_eq_some := @getElem?_eq_some_iff

View File

@@ -194,21 +194,4 @@ theorem foldl_max [Max α] [Std.IdempotentOp (max : ααα)] [Std.Asso
{l : List α} {a : α} : l.foldl (init := a) max = max a (l.max?.getD a) := by
cases l <;> simp [max?, foldl_assoc, Std.IdempotentOp.idempotent]
@[deprecated min?_nil (since := "2024-09-29")] abbrev minimum?_nil := @min?_nil
@[deprecated min?_cons (since := "2024-09-29")] abbrev minimum?_cons := @min?_cons
@[deprecated min?_eq_none_iff (since := "2024-09-29")] abbrev mininmum?_eq_none_iff := @min?_eq_none_iff
@[deprecated min?_mem (since := "2024-09-29")] abbrev minimum?_mem := @min?_mem
@[deprecated le_min?_iff (since := "2024-09-29")] abbrev le_minimum?_iff := @le_min?_iff
@[deprecated min?_eq_some_iff (since := "2024-09-29")] abbrev minimum?_eq_some_iff := @min?_eq_some_iff
@[deprecated min?_replicate (since := "2024-09-29")] abbrev minimum?_replicate := @min?_replicate
@[deprecated min?_replicate_of_pos (since := "2024-09-29")] abbrev minimum?_replicate_of_pos := @min?_replicate_of_pos
@[deprecated max?_nil (since := "2024-09-29")] abbrev maximum?_nil := @max?_nil
@[deprecated max?_cons (since := "2024-09-29")] abbrev maximum?_cons := @max?_cons
@[deprecated max?_eq_none_iff (since := "2024-09-29")] abbrev maximum?_eq_none_iff := @max?_eq_none_iff
@[deprecated max?_mem (since := "2024-09-29")] abbrev maximum?_mem := @max?_mem
@[deprecated max?_le_iff (since := "2024-09-29")] abbrev maximum?_le_iff := @max?_le_iff
@[deprecated max?_eq_some_iff (since := "2024-09-29")] abbrev maximum?_eq_some_iff := @max?_eq_some_iff
@[deprecated max?_replicate (since := "2024-09-29")] abbrev maximum?_replicate := @max?_replicate
@[deprecated max?_replicate_of_pos (since := "2024-09-29")] abbrev maximum?_replicate_of_pos := @max?_replicate_of_pos
end List

View File

@@ -109,6 +109,47 @@ theorem length_rightpad {n : Nat} {a : α} {l : List α} :
simp [rightpad]
omega
/-! ### intersperse -/
section intersperse
variable {l : List α} {sep : α} {i : Nat}
@[simp] theorem length_intersperse : (l.intersperse sep).length = 2 * l.length - 1 := by
fun_induction intersperse <;> simp only [intersperse, length_cons, length_nil] at *
rename_i h _
have := length_pos_iff.mpr h
omega
@[simp] theorem getElem?_intersperse_two_mul : (l.intersperse sep)[2 * i]? = l[i]? := by
induction l using intersperse.induct_unfolding sep generalizing i <;> cases i
all_goals simp [mul_succ, *]
theorem getElem?_intersperse_two_mul_add_one (h : i + 1 < l.length) :
(l.intersperse sep)[2 * i + 1]? = some sep := by
fun_induction intersperse generalizing i
· contradiction
· contradiction
· rename_i hn _
have _, tl, _ := ne_nil_iff_exists_cons.mp hn
cases tl <;> cases i <;> simp_all +arith
@[simp] theorem getElem_intersperse_two_mul (h : 2 * i < (l.intersperse sep).length) :
(l.intersperse sep)[2 * i] = l[i]'(by rw [length_intersperse] at h; omega) := by
rw [ Option.some_inj, getElem?_eq_getElem h]
simp
@[simp] theorem getElem_intersperse_two_mul_add_one (h : 2 * i + 1 < (l.intersperse sep).length) :
(l.intersperse sep)[2 * i + 1] = sep := by
rw [ Option.some_inj, getElem?_eq_getElem h, getElem?_intersperse_two_mul_add_one]
rw [length_intersperse] at h
omega
theorem getElem_eq_getElem_intersperse_two_mul (h : i < l.length) :
l[i] = (l.intersperse sep)[2 * i]'(by rw [length_intersperse]; omega) := by
simp
end intersperse
/-! ### eraseIdx -/
theorem mem_eraseIdx_iff_getElem {x : α} :
@@ -186,11 +227,4 @@ theorem le_max?_getD_of_mem {l : List Nat} {a k : Nat} (h : a ∈ l) :
a l.max?.getD k :=
Option.get_eq_getD _ le_max?_get_of_mem h
@[deprecated min?_eq_some_iff' (since := "2024-09-29")] abbrev minimum?_eq_some_iff' := @min?_eq_some_iff'
@[deprecated min?_cons' (since := "2024-09-29")] abbrev minimum?_cons' := @min?_cons'
@[deprecated min?_getD_le_of_mem (since := "2024-09-29")] abbrev minimum?_getD_le_of_mem := @min?_getD_le_of_mem
@[deprecated max?_eq_some_iff' (since := "2024-09-29")] abbrev maximum?_eq_some_iff' := @max?_eq_some_iff'
@[deprecated max?_cons' (since := "2024-09-29")] abbrev maximum?_cons' := @max?_cons'
@[deprecated le_max?_getD_of_mem (since := "2024-09-29")] abbrev le_maximum?_getD_of_mem := @le_max?_getD_of_mem
end List

View File

@@ -27,7 +27,7 @@ open Nat
/-! ### take -/
@[simp] theorem length_take : {i : Nat} {l : List α}, (take i l).length = min i l.length
@[simp, grind =] theorem length_take : {i : Nat} {l : List α}, (take i l).length = min i l.length
| 0, l => by simp [Nat.zero_min]
| succ n, [] => by simp [Nat.min_zero]
| succ n, _ :: l => by simp [Nat.succ_min_succ, length_take]
@@ -47,7 +47,7 @@ theorem getElem_take' {xs : List α} {i j : Nat} (hi : i < xs.length) (hj : i <
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
length `> i`. Version designed to rewrite from the small list to the big list. -/
@[simp] theorem getElem_take {xs : List α} {j i : Nat} {h : i < (xs.take j).length} :
@[simp, grind =] theorem getElem_take {xs : List α} {j i : Nat} {h : i < (xs.take j).length} :
(xs.take j)[i] =
xs[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
rw [length_take, Nat.lt_min] at h; rw [getElem_take' (xs := xs) _ h.1]
@@ -56,7 +56,7 @@ theorem getElem?_take_eq_none {l : List α} {i j : Nat} (h : i ≤ j) :
(l.take i)[j]? = none :=
getElem?_eq_none <| Nat.le_trans (length_take_le _ _) h
theorem getElem?_take {l : List α} {i j : Nat} :
@[grind =]theorem getElem?_take {l : List α} {i j : Nat} :
(l.take i)[j]? = if j < i then l[j]? else none := by
split
· next h => exact getElem?_take_of_lt h
@@ -184,8 +184,6 @@ theorem dropLast_take {i : Nat} {l : List α} (h : i < l.length) :
(l.take i).dropLast = l.take (i - 1) := by
simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, Nat.min_eq_left, take_take, sub_le]
@[deprecated map_eq_append_iff (since := "2024-09-05")] abbrev map_eq_append_split := @map_eq_append_iff
theorem take_eq_dropLast {l : List α} {i : Nat} (h : i + 1 = l.length) :
l.take i = l.dropLast := by
induction l generalizing i with
@@ -232,7 +230,7 @@ theorem getElem_drop' {xs : List α} {i j : Nat} (h : i + j < xs.length) :
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
@[simp] theorem getElem_drop {xs : List α} {i : Nat} {j : Nat} {h : j < (xs.drop i).length} :
@[simp, grind =] theorem getElem_drop {xs : List α} {i : Nat} {j : Nat} {h : j < (xs.drop i).length} :
(xs.drop i)[j] = xs[i + j]'(by
rw [Nat.add_comm]
exact Nat.add_lt_of_lt_sub (length_drop h)) := by
@@ -365,8 +363,6 @@ theorem drop_take : ∀ {i j : Nat} {l : List α}, drop i (take j l) = take (j -
| _, _, [] => by simp
| i+1, j+1, h :: t => by
simp [take_succ_cons, drop_succ_cons, drop_take]
congr 1
omega
@[simp] theorem drop_take_self : drop i (take i l) = [] := by
rw [drop_take]

View File

@@ -174,15 +174,11 @@ theorem pairwise_flatten {L : List (List α)} :
rw [and_comm, and_congr_left_iff]
intros; exact fun h l' b c d e => h c d e l' b, fun h c d e l' b => h l' b c d e
@[deprecated pairwise_flatten (since := "2024-10-14")] abbrev pairwise_join := @pairwise_flatten
theorem pairwise_flatMap {R : β β Prop} {l : List α} {f : α List β} :
List.Pairwise R (l.flatMap f)
( a l, Pairwise R (f a)) Pairwise (fun a₁ a₂ => x f a₁, y f a₂, R x y) l := by
simp [List.flatMap, pairwise_flatten, pairwise_map]
@[deprecated pairwise_flatMap (since := "2024-10-14")] abbrev pairwise_bind := @pairwise_flatMap
theorem pairwise_reverse {l : List α} :
l.reverse.Pairwise R l.Pairwise (fun a b => R b a) := by
induction l <;> simp [*, pairwise_append, and_comm]

View File

@@ -497,8 +497,6 @@ theorem Perm.flatten {l₁ l₂ : List (List α)} (h : l₁ ~ l₂) : l₁.flatt
| swap => simp only [flatten_cons, append_assoc, perm_append_right_iff]; exact perm_append_comm ..
| trans _ _ ih₁ ih₂ => exact trans ih₁ ih₂
@[deprecated Perm.flatten (since := "2024-10-14")] abbrev Perm.join := @Perm.flatten
theorem cons_append_cons_perm {a b : α} {as bs : List α} :
a :: as ++ b :: bs ~ b :: as ++ a :: bs := by
suffices [[a], as, [b], bs].flatten ~ [[b], as, [a], bs].flatten by simpa
@@ -511,8 +509,6 @@ theorem cons_append_cons_perm {a b : α} {as bs : List α} :
theorem Perm.flatMap_right {l₁ l₂ : List α} (f : α List β) (p : l₁ ~ l₂) : l₁.flatMap f ~ l₂.flatMap f :=
(p.map _).flatten
@[deprecated Perm.flatMap_right (since := "2024-10-16")] abbrev Perm.bind_right := @Perm.flatMap_right
theorem Perm.eraseP (f : α Bool) {l₁ l₂ : List α}
(H : Pairwise (fun a b => f a f b False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ := by
induction p with

View File

@@ -306,8 +306,6 @@ theorem sorted_mergeSort
apply sorted_mergeSort trans total
termination_by l => l.length
@[deprecated sorted_mergeSort (since := "2024-09-02")] abbrev mergeSort_sorted := @sorted_mergeSort
/--
If the input list is already sorted, then `mergeSort` does not change the list.
-/
@@ -444,9 +442,6 @@ theorem sublist_mergeSort
((fun w => Sublist.of_sublist_append_right w h') fun b m₁ m₃ =>
(Bool.eq_not_self true).mp ((rel_of_pairwise_cons hc m₁).symm.trans (h₃ b m₃))))
@[deprecated sublist_mergeSort (since := "2024-09-02")]
abbrev mergeSort_stable := @sublist_mergeSort
/--
Another statement of stability of merge sort.
If a pair `[a, b]` is a sublist of `l` and `le a b`,
@@ -458,9 +453,6 @@ theorem pair_sublist_mergeSort
(hab : le a b) (h : [a, b] <+ l) : [a, b] <+ mergeSort l le :=
sublist_mergeSort trans total (pairwise_pair.mpr hab) h
@[deprecated pair_sublist_mergeSort(since := "2024-09-02")]
abbrev mergeSort_stable_pair := @pair_sublist_mergeSort
theorem map_merge {f : α β} {r : α α Bool} {s : β β Bool} {l l' : List α}
(hl : a l, b l', r a b = s (f a) (f b)) :
(l.merge l' r).map f = (l.map f).merge (l'.map f) s := by

View File

@@ -1092,11 +1092,4 @@ theorem prefix_iff_eq_take : l₁ <+: l₂ ↔ l₁ = take (length l₁) l₂ :=
-- See `Init.Data.List.Nat.Sublist` for `suffix_iff_eq_append`, `prefix_take_iff`, and `suffix_iff_eq_drop`.
/-! ### Deprecations -/
@[deprecated sublist_flatten_of_mem (since := "2024-10-14")] abbrev sublist_join_of_mem := @sublist_flatten_of_mem
@[deprecated sublist_flatten_iff (since := "2024-10-14")] abbrev sublist_join_iff := @sublist_flatten_iff
@[deprecated flatten_sublist_iff (since := "2024-10-14")] abbrev flatten_join_iff := @flatten_sublist_iff
@[deprecated infix_of_mem_flatten (since := "2024-10-14")] abbrev infix_of_mem_join := @infix_of_mem_flatten
end List

View File

@@ -40,7 +40,7 @@ theorem drop_one : ∀ {l : List α}, l.drop 1 = l.tail
| _ + 1, [] => rfl
| _ + 1, x :: _ => congrArg (cons x) (take_append_drop ..)
@[simp] theorem length_drop : {i : Nat} {l : List α}, (drop i l).length = l.length - i
@[simp, grind =] theorem length_drop : {i : Nat} {l : List α}, (drop i l).length = l.length - i
| 0, _ => rfl
| succ i, [] => Eq.symm (Nat.zero_sub (succ i))
| succ i, x :: l => calc
@@ -131,8 +131,6 @@ theorem drop_eq_nil_iff {l : List α} {i : Nat} : l.drop i = [] ↔ l.length ≤
· simp only [drop] at h
simpa [Nat.succ_le_succ_iff] using hi h
@[deprecated drop_eq_nil_iff (since := "2024-09-10")] abbrev drop_eq_nil_iff_le := @drop_eq_nil_iff
@[simp]
theorem take_eq_nil_iff {l : List α} {k : Nat} : l.take k = [] k = 0 l = [] := by
cases l <;> cases k <;> simp [Nat.succ_ne_zero]

View File

@@ -66,7 +66,7 @@ theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArr
apply ext'
simp
@[simp] theorem push_toArray (l : List α) (a : α) : l.toArray.push a = (l ++ [a]).toArray := by
@[simp, grind =] theorem push_toArray (l : List α) (a : α) : l.toArray.push a = (l ++ [a]).toArray := by
apply ext'
simp
@@ -75,37 +75,37 @@ theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArr
funext a
simp
@[simp] theorem isEmpty_toArray (l : List α) : l.toArray.isEmpty = l.isEmpty := by
@[simp, grind =] theorem isEmpty_toArray (l : List α) : l.toArray.isEmpty = l.isEmpty := by
cases l <;> simp [Array.isEmpty]
@[simp] theorem toArray_singleton (a : α) : (List.singleton a).toArray = Array.singleton a := rfl
@[simp] theorem back!_toArray [Inhabited α] (l : List α) : l.toArray.back! = l.getLast! := by
@[simp, grind =] theorem back!_toArray [Inhabited α] (l : List α) : l.toArray.back! = l.getLast! := by
simp only [back!, size_toArray, getElem!_toArray, getLast!_eq_getElem!]
@[simp] theorem back?_toArray (l : List α) : l.toArray.back? = l.getLast? := by
@[simp, grind =] theorem back?_toArray (l : List α) : l.toArray.back? = l.getLast? := by
simp [back?, List.getLast?_eq_getElem?]
@[simp] theorem back_toArray (l : List α) (h) :
@[simp, grind =] theorem back_toArray (l : List α) (h) :
l.toArray.back = l.getLast (by simp at h; exact ne_nil_of_length_pos h) := by
simp [back, List.getLast_eq_getElem]
@[simp] theorem _root_.Array.getLast!_toList [Inhabited α] (xs : Array α) :
@[simp, grind =] theorem _root_.Array.getLast!_toList [Inhabited α] (xs : Array α) :
xs.toList.getLast! = xs.back! := by
rcases xs with xs
simp
@[simp] theorem _root_.Array.getLast?_toList (xs : Array α) :
@[simp, grind =] theorem _root_.Array.getLast?_toList (xs : Array α) :
xs.toList.getLast? = xs.back? := by
rcases xs with xs
simp
@[simp] theorem _root_.Array.getLast_toList (xs : Array α) (h) :
@[simp, grind =] theorem _root_.Array.getLast_toList (xs : Array α) (h) :
xs.toList.getLast h = xs.back (by simpa [ne_nil_iff_length_pos] using h) := by
rcases xs with xs
simp
@[simp] theorem set_toArray (l : List α) (i : Nat) (a : α) (h : i < l.length) :
@[simp, grind =] theorem set_toArray (l : List α) (i : Nat) (a : α) (h : i < l.length) :
(l.toArray.set i a) = (l.set i a).toArray := rfl
@[simp] theorem forIn'_loop_toArray [Monad m] (l : List α) (f : (a : α) a l.toArray β m (ForInStep β)) (i : Nat)
@@ -126,30 +126,30 @@ theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArr
simp only [t]
congr
@[simp] theorem forIn'_toArray [Monad m] (l : List α) (b : β) (f : (a : α) a l.toArray β m (ForInStep β)) :
@[simp, grind =] theorem forIn'_toArray [Monad m] (l : List α) (b : β) (f : (a : α) a l.toArray β m (ForInStep β)) :
forIn' l.toArray b f = forIn' l b (fun a m b => f a (mem_toArray.mpr m) b) := by
change Array.forIn' _ _ _ = List.forIn' _ _ _
rw [Array.forIn', forIn'_loop_toArray]
simp
@[simp] theorem forIn_toArray [Monad m] (l : List α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind =] theorem forIn_toArray [Monad m] (l : List α) (b : β) (f : α β m (ForInStep β)) :
forIn l.toArray b f = forIn l b f := by
simpa using forIn'_toArray l b fun a m b => f a b
theorem foldrM_toArray [Monad m] (f : α β m β) (init : β) (l : List α) :
@[grind =] theorem foldrM_toArray [Monad m] (f : α β m β) (init : β) (l : List α) :
l.toArray.foldrM f init = l.foldrM f init := by
rw [foldrM_eq_reverse_foldlM_toList]
simp
theorem foldlM_toArray [Monad m] (f : β α m β) (init : β) (l : List α) :
@[grind =] theorem foldlM_toArray [Monad m] (f : β α m β) (init : β) (l : List α) :
l.toArray.foldlM f init = l.foldlM f init := by
rw [foldlM_toList]
theorem foldr_toArray (f : α β β) (init : β) (l : List α) :
@[grind =] theorem foldr_toArray (f : α β β) (init : β) (l : List α) :
l.toArray.foldr f init = l.foldr f init := by
rw [foldr_toList]
theorem foldl_toArray (f : β α β) (init : β) (l : List α) :
@[grind =] theorem foldl_toArray (f : β α β) (init : β) (l : List α) :
l.toArray.foldl f init = l.foldl f init := by
rw [foldl_toList]
@@ -176,7 +176,7 @@ theorem foldl_toArray (f : β → α → β) (init : β) (l : List α) :
simp only [size_toArray, foldlM_toArray']
induction l <;> simp_all
@[simp]
@[simp, grind =]
theorem forM_toArray [Monad m] (l : List α) (f : α m PUnit) :
(forM l.toArray f) = l.forM f :=
forM_toArray' l f rfl
@@ -195,15 +195,15 @@ theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
subst h
rw [foldl_toList]
@[simp] theorem sum_toArray [Add α] [Zero α] (l : List α) : l.toArray.sum = l.sum := by
@[simp, grind =] theorem sum_toArray [Add α] [Zero α] (l : List α) : l.toArray.sum = l.sum := by
simp [Array.sum, List.sum]
@[simp] theorem append_toArray (l₁ l₂ : List α) :
@[simp, grind =] theorem append_toArray (l₁ l₂ : List α) :
l₁.toArray ++ l₂.toArray = (l₁ ++ l₂).toArray := by
apply ext'
simp
@[simp] theorem push_append_toArray {as : Array α} {a : α} {bs : List α} : as.push a ++ bs.toArray = as ++ (a ::bs).toArray := by
@[simp] theorem push_append_toArray {as : Array α} {a : α} {bs : List α} : as.push a ++ bs.toArray = as ++ (a :: bs).toArray := by
cases as
simp
@@ -213,7 +213,7 @@ theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
@[simp] theorem foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
rw [foldr_eq_foldl_reverse, foldl_push]
@[simp] theorem findSomeM?_toArray [Monad m] [LawfulMonad m] (f : α m (Option β)) (l : List α) :
@[simp, grind =] theorem findSomeM?_toArray [Monad m] [LawfulMonad m] (f : α m (Option β)) (l : List α) :
l.toArray.findSomeM? f = l.findSomeM? f := by
rw [Array.findSomeM?]
simp only [bind_pure_comp, map_pure, forIn_toArray]
@@ -246,7 +246,7 @@ theorem findRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : Lis
l.toArray.findRevM? f = l.reverse.findM? f := by
rw [Array.findRevM?, findSomeRevM?_toArray, findM?_eq_findSomeM?]
@[simp] theorem findM?_toArray [Monad m] [LawfulMonad m] (f : α m Bool) (l : List α) :
@[simp, grind =] theorem findM?_toArray [Monad m] [LawfulMonad m] (f : α m Bool) (l : List α) :
l.toArray.findM? f = l.findM? f := by
rw [Array.findM?]
simp only [bind_pure_comp, map_pure, forIn_toArray]
@@ -257,11 +257,11 @@ theorem findRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : Lis
congr
ext1 (_|_) <;> simp [ih]
@[simp] theorem findSome?_toArray (f : α Option β) (l : List α) :
@[simp, grind =] theorem findSome?_toArray (f : α Option β) (l : List α) :
l.toArray.findSome? f = l.findSome? f := by
rw [Array.findSome?, findSomeM?_id, findSomeM?_toArray, Id.run]
@[simp] theorem find?_toArray (f : α Bool) (l : List α) :
@[simp, grind =] theorem find?_toArray (f : α Bool) (l : List α) :
l.toArray.find? f = l.find? f := by
rw [Array.find?]
simp only [Id.run, Id, Id.pure_eq, Id.bind_eq, forIn_toArray]
@@ -297,12 +297,12 @@ private theorem findFinIdx?_loop_toArray (w : l' = l.drop j) :
simp
termination_by l.length - j
@[simp] theorem findFinIdx?_toArray (p : α Bool) (l : List α) :
@[simp, grind =] theorem findFinIdx?_toArray (p : α Bool) (l : List α) :
l.toArray.findFinIdx? p = l.findFinIdx? p := by
rw [Array.findFinIdx?, findFinIdx?, findFinIdx?_loop_toArray]
simp
@[simp] theorem findIdx?_toArray (p : α Bool) (l : List α) :
@[simp, grind =] theorem findIdx?_toArray (p : α Bool) (l : List α) :
l.toArray.findIdx? p = l.findIdx? p := by
rw [Array.findIdx?_eq_map_findFinIdx?_val, findIdx?_eq_map_findFinIdx?_val]
simp
@@ -334,21 +334,21 @@ private theorem idxAuxOf_toArray [BEq α] (a : α) (l : List α) (j : Nat) (w :
simp
termination_by l.length - j
@[simp] theorem finIdxOf?_toArray [BEq α] (a : α) (l : List α) :
@[simp, grind =] theorem finIdxOf?_toArray [BEq α] (a : α) (l : List α) :
l.toArray.finIdxOf? a = l.finIdxOf? a := by
rw [Array.finIdxOf?, finIdxOf?, findFinIdx?]
simp [idxAuxOf_toArray]
@[simp] theorem idxOf?_toArray [BEq α] (a : α) (l : List α) :
@[simp, grind =] theorem idxOf?_toArray [BEq α] (a : α) (l : List α) :
l.toArray.idxOf? a = l.idxOf? a := by
rw [Array.idxOf?, idxOf?]
simp [finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem findIdx_toArray {as : List α} {p : α Bool} :
@[simp, grind =] theorem findIdx_toArray {as : List α} {p : α Bool} :
as.toArray.findIdx p = as.findIdx p := by
rw [Array.findIdx, findIdx?_toArray, findIdx_eq_getD_findIdx?]
@[simp] theorem idxOf_toArray [BEq α] {as : List α} {a : α} :
@[simp, grind =] theorem idxOf_toArray [BEq α] {as : List α} {a : α} :
as.toArray.idxOf a = as.idxOf a := by
rw [Array.idxOf, findIdx_toArray, idxOf]
@@ -383,7 +383,7 @@ theorem isPrefixOfAux_toArray_zero [BEq α] (l₁ l₂ : List α) (hle : l₁.le
| a::l₁, b::l₂ =>
simp [isPrefixOf_cons₂, isPrefixOfAux_toArray_succ', isPrefixOfAux_toArray_zero]
@[simp] theorem isPrefixOf_toArray [BEq α] (l₁ l₂ : List α) :
@[simp, grind =] theorem isPrefixOf_toArray [BEq α] (l₁ l₂ : List α) :
l₁.toArray.isPrefixOf l₂.toArray = l₁.isPrefixOf l₂ := by
rw [Array.isPrefixOf]
split <;> rename_i h
@@ -429,12 +429,12 @@ theorem zipWithAux_toArray_zero (f : α → β → γ) (as : List α) (bs : List
| a :: as, b :: bs =>
simp [zipWith_cons_cons, zipWithAux_toArray_succ', zipWithAux_toArray_zero, push_append_toArray]
@[simp] theorem zipWith_toArray (as : List α) (bs : List β) (f : α β γ) :
@[simp, grind =] theorem zipWith_toArray (as : List α) (bs : List β) (f : α β γ) :
Array.zipWith f as.toArray bs.toArray = (List.zipWith f as bs).toArray := by
rw [Array.zipWith]
simp [zipWithAux_toArray_zero]
@[simp] theorem zip_toArray (as : List α) (bs : List β) :
@[simp, grind =] theorem zip_toArray (as : List α) (bs : List β) :
Array.zip as.toArray bs.toArray = (List.zip as bs).toArray := by
simp [Array.zip, zipWith_toArray, zip]
@@ -472,16 +472,16 @@ theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → O
termination_by max as.length bs.length - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[simp] theorem zipWithAll_toArray (f : Option α Option β γ) (as : List α) (bs : List β) :
@[simp, grind =] theorem zipWithAll_toArray (f : Option α Option β γ) (as : List α) (bs : List β) :
Array.zipWithAll f as.toArray bs.toArray = (List.zipWithAll f as bs).toArray := by
simp [Array.zipWithAll, zipWithAll_go_toArray]
@[simp] theorem toArray_appendList (l₁ l₂ : List α) :
@[simp, grind =] theorem toArray_appendList (l₁ l₂ : List α) :
l₁.toArray ++ l₂ = (l₁ ++ l₂).toArray := by
apply ext'
simp
@[simp] theorem pop_toArray (l : List α) : l.toArray.pop = l.dropLast.toArray := by
@[simp, grind =] theorem pop_toArray (l : List α) : l.toArray.pop = l.dropLast.toArray := by
apply ext'
simp
@@ -513,7 +513,7 @@ theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
split <;> simp_all
· simp_all [drop_eq_nil_of_le]
@[simp] theorem takeWhile_toArray (p : α Bool) (l : List α) :
@[simp, grind =] theorem takeWhile_toArray (p : α Bool) (l : List α) :
l.toArray.takeWhile p = (l.takeWhile p).toArray := by
simp [Array.takeWhile, takeWhile_go_toArray]
@@ -528,11 +528,11 @@ private theorem popWhile_toArray_aux (p : α → Bool) (l : List α) :
· rfl
· simp
@[simp] theorem popWhile_toArray (p : α Bool) (l : List α) :
@[simp, grind =] theorem popWhile_toArray (p : α Bool) (l : List α) :
l.toArray.popWhile p = (l.reverse.dropWhile p).reverse.toArray := by
simp [ popWhile_toArray_aux]
@[simp] theorem setIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
@[simp, grind =] theorem setIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
l.toArray.setIfInBounds i a = (l.set i a).toArray := by
apply ext'
simp only [setIfInBounds]
@@ -540,7 +540,7 @@ private theorem popWhile_toArray_aux (p : α → Bool) (l : List α) :
· simp
· simp_all [List.set_eq_of_length_le]
@[simp] theorem toArray_replicate (n : Nat) (v : α) :
@[simp, grind =] theorem toArray_replicate (n : Nat) (v : α) :
(List.replicate n v).toArray = Array.replicate n v := rfl
theorem _root_.Array.replicate_eq_toArray_replicate :
@@ -550,7 +550,7 @@ theorem _root_.Array.replicate_eq_toArray_replicate :
@[deprecated _root_.Array.replicate_eq_toArray_replicate (since := "2025-03-18")]
abbrev _root_.Array.mkArray_eq_toArray_replicate := @_root_.Array.replicate_eq_toArray_replicate
@[simp] theorem flatMap_empty {β} (f : α Array β) : (#[] : Array α).flatMap f = #[] := rfl
@[simp, grind =] theorem flatMap_empty {β} (f : α Array β) : (#[] : Array α).flatMap f = #[] := rfl
theorem flatMap_toArray_cons {β} (f : α Array β) (a : α) (as : List α) :
(a :: as).toArray.flatMap f = f a ++ as.toArray.flatMap f := by
@@ -562,7 +562,7 @@ theorem flatMap_toArray_cons {β} (f : α → Array β) (a : α) (as : List α)
intro xs
induction as generalizing xs <;> simp_all
@[simp] theorem flatMap_toArray {β} (f : α Array β) (as : List α) :
@[simp, grind =] theorem flatMap_toArray {β} (f : α Array β) (as : List α) :
as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray := by
induction as with
| nil => simp
@@ -570,12 +570,12 @@ theorem flatMap_toArray_cons {β} (f : α → Array β) (a : α) (as : List α)
apply ext'
simp [ih, flatMap_toArray_cons]
@[simp] theorem swap_toArray (l : List α) (i j : Nat) {hi hj}:
@[simp, grind =] theorem swap_toArray (l : List α) (i j : Nat) {hi hj}:
l.toArray.swap i j hi hj = ((l.set i l[j]).set j l[i]).toArray := by
apply ext'
simp
@[simp] theorem eraseIdx_toArray (l : List α) (i : Nat) (h : i < l.toArray.size) :
@[simp, grind =] theorem eraseIdx_toArray (l : List α) (i : Nat) (h : i < l.toArray.size) :
l.toArray.eraseIdx i h = (l.eraseIdx i).toArray := by
rw [Array.eraseIdx]
split <;> rename_i h'
@@ -593,19 +593,19 @@ decreasing_by
simp
omega
@[simp] theorem eraseIdxIfInBounds_toArray (l : List α) (i : Nat) :
@[simp, grind =] theorem eraseIdxIfInBounds_toArray (l : List α) (i : Nat) :
l.toArray.eraseIdxIfInBounds i = (l.eraseIdx i).toArray := by
rw [Array.eraseIdxIfInBounds]
split
· simp
· simp_all [eraseIdx_eq_self.2]
@[simp] theorem eraseP_toArray {as : List α} {p : α Bool} :
@[simp, grind =] theorem eraseP_toArray {as : List α} {p : α Bool} :
as.toArray.eraseP p = (as.eraseP p).toArray := by
rw [Array.eraseP, List.eraseP_eq_eraseIdx, findFinIdx?_toArray]
split <;> simp [*, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem erase_toArray [BEq α] {as : List α} {a : α} :
@[simp, grind =] theorem erase_toArray [BEq α] {as : List α} {a : α} :
as.toArray.erase a = (as.erase a).toArray := by
rw [Array.erase, finIdxOf?_toArray, List.erase_eq_eraseIdx]
rw [idxOf?_eq_map_finIdxOf?_val]
@@ -635,7 +635,7 @@ private theorem insertIdx_loop_toArray (i : Nat) (l : List α) (j : Nat) (hj : j
subst this
simp
@[simp] theorem insertIdx_toArray (l : List α) (i : Nat) (a : α) (h : i l.toArray.size):
@[simp, grind =] theorem insertIdx_toArray (l : List α) (i : Nat) (a : α) (h : i l.toArray.size):
l.toArray.insertIdx i a = (l.insertIdx i a).toArray := by
rw [Array.insertIdx]
rw [insertIdx_loop_toArray (h := h)]
@@ -658,7 +658,7 @@ private theorem insertIdx_loop_toArray (i : Nat) (l : List α) (j : Nat) (hj : j
congr
omega
@[simp] theorem insertIdxIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
@[simp, grind =] theorem insertIdxIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
l.toArray.insertIdxIfInBounds i a = (l.insertIdx i a).toArray := by
rw [Array.insertIdxIfInBounds]
split <;> rename_i h'
@@ -666,7 +666,7 @@ private theorem insertIdx_loop_toArray (i : Nat) (l : List α) (j : Nat) (hj : j
· simp only [size_toArray, Nat.not_le] at h'
rw [List.insertIdx_of_length_lt (h := h')]
@[simp]
@[simp, grind =]
theorem replace_toArray [BEq α] [LawfulBEq α] (l : List α) (a b : α) :
l.toArray.replace a b = (l.replace a b).toArray := by
rw [Array.replace]
@@ -700,11 +700,11 @@ theorem replace_toArray [BEq α] [LawfulBEq α] (l : List α) (a b : α) :
exact i, by omega, h.1
· rfl
@[simp] theorem leftpad_toArray (n : Nat) (a : α) (l : List α) :
@[simp, grind =] theorem leftpad_toArray (n : Nat) (a : α) (l : List α) :
Array.leftpad n a l.toArray = (leftpad n a l).toArray := by
simp [leftpad, Array.leftpad, toArray_replicate]
@[simp] theorem rightpad_toArray (n : Nat) (a : α) (l : List α) :
@[simp, grind =] theorem rightpad_toArray (n : Nat) (a : α) (l : List α) :
Array.rightpad n a l.toArray = (rightpad n a l).toArray := by
simp [rightpad, Array.rightpad, toArray_replicate]

View File

@@ -524,8 +524,6 @@ theorem and_lt_two_pow (x : Nat) {y n : Nat} (right : y < 2^n) : (x &&& y) < 2^n
@[deprecated and_two_pow_sub_one_eq_mod (since := "2025-03-18")]
abbrev and_pow_two_sub_one_eq_mod := @and_two_pow_sub_one_eq_mod
@[deprecated and_two_pow_sub_one_eq_mod (since := "2024-09-11")]
abbrev and_pow_two_is_mod := @and_two_pow_sub_one_eq_mod
theorem and_two_pow_sub_one_of_lt_two_pow {x : Nat} (lt : x < 2^n) : x &&& 2^n - 1 = x := by
rw [and_two_pow_sub_one_eq_mod]
@@ -533,8 +531,6 @@ theorem and_two_pow_sub_one_of_lt_two_pow {x : Nat} (lt : x < 2^n) : x &&& 2^n -
@[deprecated and_two_pow_sub_one_of_lt_two_pow (since := "2025-03-18")]
abbrev and_pow_two_sub_one_of_lt_two_pow := @and_two_pow_sub_one_of_lt_two_pow
@[deprecated and_two_pow_sub_one_of_lt_two_pow (since := "2024-09-11")]
abbrev and_two_pow_identity := @and_two_pow_sub_one_of_lt_two_pow
@[simp] theorem and_mod_two_eq_one : (a &&& b) % 2 = 1 a % 2 = 1 b % 2 = 1 := by
simp only [mod_two_eq_one_iff_testBit_zero]

View File

@@ -14,3 +14,4 @@ import Init.Data.Option.Lemmas
import Init.Data.Option.Attach
import Init.Data.Option.List
import Init.Data.Option.Monadic
import Init.Data.Option.Array

View File

@@ -0,0 +1,26 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
module
prelude
import Init.Data.Array.Lemmas
import Init.Data.Option.List
namespace Option
@[simp]
theorem toList_toArray {o : Option α} : o.toArray.toList = o.toList := by
cases o <;> simp
@[simp]
theorem toArray_toList {o : Option α} : o.toList.toArray = o.toArray := by
cases o <;> simp
theorem toArray_filter {o : Option α} {p : α Bool} :
(o.filter p).toArray = o.toArray.filter p := by
rw [ toArray_toList, toList_filter, List.filter_toArray, toArray_toList]
end Option

View File

@@ -138,7 +138,7 @@ theorem toList_attach (o : Option α) :
o.attach.toList = o.toList.attach.map fun x, h => x, by simpa using h := by
cases o <;> simp
@[simp] theorem attach_toList (o : Option α) :
@[simp, grind =] theorem attach_toList (o : Option α) :
o.toList.attach = (o.attach.map fun a, h => a, by simpa using h).toList := by
cases o <;> simp
@@ -195,7 +195,7 @@ theorem attach_filter {o : Option α} {p : α → Bool} :
| some a =>
simp only [filter_some, attach_some]
ext
simp only [attach_eq_some_iff, ite_none_right_eq_some, some.injEq, some_bind,
simp only [attach_eq_some_iff, ite_none_right_eq_some, some.injEq, bind_some,
dite_none_right_eq_some]
constructor
· rintro h, w
@@ -207,6 +207,10 @@ theorem filter_attach {o : Option α} {p : {x // o = some x} → Bool} :
o.attach.filter p = o.pbind fun a h => if p a, h then some a, h else none := by
cases o <;> simp [filter_some]
theorem toList_pbind {o : Option α} {f : (a : α) o = some a Option β} :
(o.pbind f).toList = o.attach.toList.flatMap (fun x, h => (f x h).toList) := by
cases o <;> simp
/-! ## unattach
`Option.unattach` is the (one-sided) inverse of `Option.attach`. It is a synonym for `Option.map Subtype.val`.

View File

@@ -13,11 +13,20 @@ namespace Option
deriving instance DecidableEq for Option
deriving instance BEq for Option
@[simp, grind] theorem getD_none : getD none a = a := rfl
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind] theorem map_none (f : α β) : none.map f = none := rfl
@[simp, grind] theorem map_some (a) (f : α β) : (some a).map f = some (f a) := rfl
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
def getM [Alternative m] : Option α m α
| none => failure
| some a => pure a
@[simp, grind] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
@[simp, grind] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
/-- Returns `true` on `some x` and `false` on `none`. -/
@[inline] def isSome : Option α Bool
| some _ => true
@@ -75,6 +84,14 @@ Examples:
| none, _ => none
| some a, f => f a
@[simp, grind] theorem bind_none (f : α Option β) : none.bind f = none := rfl
@[simp, grind] theorem bind_some (a) (f : α Option β) : (some a).bind f = f a := rfl
@[deprecated bind_none (since := "2025-05-03")]
abbrev none_bind := @bind_none
@[deprecated bind_some (since := "2025-05-03")]
abbrev some_bind := @bind_some
/--
Runs the monadic action `f` on `o`'s value, if any, and returns the result, or `none` if there is
no value.
@@ -90,6 +107,9 @@ resulting collections are empty.
return none
/--
Applies a function in some applicative functor to an optional value, returning `none` with no
effects if the value is missing.
Runs a monadic function `f` on an optional value, returning the result. If the optional value is
`none`, the function is not called and the result is also `none`.
@@ -102,6 +122,9 @@ This function only requires `m` to be an applicative functor. An alias `Option.m
| none => pure none
| some x => some <$> f x
@[simp, grind] theorem mapM_none [Applicative m] (f : α m β) : none.mapM f = pure none := rfl
@[simp, grind] theorem mapM_some [Applicative m] (x) (f : α m β) : (some x).mapM f = some <$> f x := rfl
/--
Applies a function in some applicative functor to an optional value, returning `none` with no
effects if the value is missing.
@@ -111,9 +134,23 @@ This is an alias for `Option.mapM`, which already works for applicative functors
@[inline] protected def mapA [Applicative m] (f : α m β) : Option α m (Option β) :=
Option.mapM f
/-- For verification purposes, we replace `mapA` with `mapM`. -/
@[simp, grind] theorem mapA_eq_mapM [Applicative m] {f : α m β} : Option.mapA f o = Option.mapM f o := rfl
@[simp, grind]
theorem map_id : (Option.map id : Option α Option α) = id :=
funext (fun o => match o with | none => rfl | some _ => rfl)
/--
Keeps an optional value only if it satisfies a monadic Boolean predicate.
If `Option` is thought of as a collection that contains at most one element, then `Option.filterM`
is analogous to `List.filterM`.
-/
@[inline] protected def filterM [Applicative m] (p : α m Bool) : Option α m (Option α)
| none => pure none
| some a => (fun b => if b then some a else none) <$> p a
/--
Keeps an optional value only if it satisfies a Boolean predicate.
@@ -142,6 +179,9 @@ Examples:
| some a => p a
| none => true
@[simp, grind] theorem all_none : Option.all p none = true := rfl
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
/--
Checks whether an optional value is not `none` and satisfies a Boolean predicate.
@@ -154,6 +194,9 @@ Examples:
| some a => p a
| none => false
@[simp, grind] theorem any_none : Option.any p none = false := rfl
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
/--
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
`some a`, otherwise evaluates and returns the second argument.
@@ -164,6 +207,9 @@ See also `or` for a version that is strict in the second argument.
| some a, _ => some a
| none, b => b ()
@[simp, grind] theorem orElse_some : (some a).orElse b = some a := rfl
@[simp, grind] theorem orElse_none : none.orElse b = b () := rfl
instance : OrElse (Option α) where
orElse := Option.orElse
@@ -230,15 +276,6 @@ def merge (fn : ααα) : Option α → Option α → Option α
| none , some y => some y
| some x, some y => some <| fn x y
@[simp, grind] theorem getD_none : getD none a = a := rfl
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind] theorem map_none (f : α β) : none.map f = none := rfl
@[simp, grind] theorem map_some (a) (f : α β) : (some a).map f = some (f a) := rfl
@[simp, grind] theorem none_bind (f : α Option β) : none.bind f = none := rfl
@[simp, grind] theorem some_bind (a) (f : α Option β) : (some a).bind f = f a := rfl
/--
A case analysis function for `Option`.
@@ -262,9 +299,9 @@ Extracts the value from an option that can be proven to be `some`.
@[inline] def get {α : Type u} : (o : Option α) isSome o α
| some x, _ => x
@[simp] theorem some_get : {x : Option α} (h : isSome x), some (x.get h) = x
@[simp, grind] theorem some_get : {x : Option α} (h : isSome x), some (x.get h) = x
| some _, _ => rfl
@[simp] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
@[simp, grind] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
/--
Returns `none` if a value doesn't satisfy a Boolean predicate, or the value itself otherwise.
@@ -340,7 +377,10 @@ Examples:
* `(some none).join = none`
* `(some (some v)).join = some v`
-/
@[simp, inline] def join (x : Option (Option α)) : Option α := x.bind id
@[inline] def join (x : Option (Option α)) : Option α := x.bind id
@[simp, grind] theorem join_none : (none : Option (Option α)).join = none := rfl
@[simp, grind] theorem join_some : (some o).join = o := rfl
/--
Converts an optional monadic computation into a monadic computation of an optional value.
@@ -363,7 +403,10 @@ some "world"
-/
@[inline] def sequence [Applicative m] {α : Type u} : Option (m α) m (Option α)
| none => pure none
| some fn => some <$> fn
| some f => some <$> f
@[simp, grind] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
@[simp, grind] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
/--
A monadic case analysis function for `Option`.
@@ -388,6 +431,9 @@ This is the monadic analogue of `Option.getD`.
| some a => pure a
| none => y
@[simp, grind] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
@[simp, grind] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
rfl {x} :=
match x with
@@ -400,12 +446,6 @@ instance (α) [BEq α] [LawfulBEq α] : LawfulBEq (Option α) where
| some x, some y => rw [LawfulBEq.eq_of_beq (α := α) h]
| none, none => rfl
@[simp, grind] theorem all_none : Option.all p none = true := rfl
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
@[simp, grind] theorem any_none : Option.any p none = false := rfl
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
/--
The minimum of two optional values, with `none` treated as the least element. This function is
usually accessed through the `Min (Option α)` instance, rather than directly.
@@ -428,10 +468,18 @@ protected def min [Min α] : Option α → Option α → Option α
instance [Min α] : Min (Option α) where min := Option.min
@[simp] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp] theorem min_some_none [Min α] {a : α} : min (some a) none = none := rfl
@[simp] theorem min_none_some [Min α] {b : α} : min none (some b) = none := rfl
@[simp] theorem min_none_none [Min α] : min (none : Option α) none = none := rfl
@[simp, grind] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp, grind] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
cases o <;> rfl
@[simp, grind] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
cases o <;> rfl
@[deprecated min_none_right (since := "2025-05-12")]
theorem min_some_none [Min α] {a : α} : min (some a) none = none := rfl
@[deprecated min_none_left (since := "2025-05-12")]
theorem min_none_some [Min α] {b : α} : min none (some b) = none := rfl
@[deprecated min_none_left (since := "2025-05-12")]
theorem min_none_none [Min α] : min (none : Option α) none = none := rfl
/--
The maximum of two optional values.
@@ -453,10 +501,18 @@ protected def max [Max α] : Option α → Option α → Option α
instance [Max α] : Max (Option α) where max := Option.max
@[simp] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp] theorem max_some_none [Max α] {a : α} : max (some a) none = some a := rfl
@[simp] theorem max_none_some [Max α] {b : α} : max none (some b) = some b := rfl
@[simp] theorem max_none_none [Max α] : max (none : Option α) none = none := rfl
@[simp, grind] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp, grind] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
cases o <;> rfl
@[simp, grind] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
cases o <;> rfl
@[deprecated max_none_right (since := "2025-05-12")]
theorem max_some_none [Max α] {a : α} : max (some a) none = some a := rfl
@[deprecated max_none_left (since := "2025-05-12")]
theorem max_none_some [Max α] {b : α} : max none (some b) = some b := rfl
@[deprecated max_none_left (since := "2025-05-12")]
theorem max_none_none [Max α] : max (none : Option α) none = none := rfl
end Option
@@ -481,6 +537,7 @@ instance : Alternative Option where
failure := Option.none
orElse := Option.orElse
-- This is a duplicate of `Option.getM`; one may be deprecated in the future.
def liftOption [Alternative m] : Option α m α
| some a => pure a
| none => failure

View File

@@ -12,7 +12,7 @@ universe u v
namespace Option
theorem eq_of_eq_some {α : Type u} : {x y : Option α}, (z, x = some z y = some z) x = y
theorem eq_of_eq_some {α : Type u} : {x y : Option α}, ( z, x = some z y = some z) x = y
| none, none, _ => rfl
| none, some z, h => Option.noConfusion ((h z).2 rfl)
| some z, none, h => Option.noConfusion ((h z).1 rfl)

View File

@@ -91,8 +91,6 @@ theorem eq_some_unique {o : Option α} {a b : α} (ha : o = some a) (hb : o = so
| some _, _, H => ((H _).1 rfl).symm
| _, some _, H => (H _).2 rfl
set_option Elab.async false
theorem eq_none_iff_forall_ne_some : o = none a, o some a := by
cases o <;> simp
@@ -174,15 +172,15 @@ theorem forall_ne_none {p : Option α → Prop} : (∀ x (_ : x ≠ none), p x)
@[deprecated forall_ne_none (since := "2025-04-04")]
abbrev ball_ne_none := @forall_ne_none
@[simp] theorem pure_def : pure = @some α := rfl
@[simp, grind] theorem pure_def : pure = @some α := rfl
@[simp] theorem bind_eq_bind : bind = @Option.bind α β := rfl
@[simp, grind] theorem bind_eq_bind : bind = @Option.bind α β := rfl
@[simp] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
@[simp, grind] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
@[simp] theorem bind_some (x : Option α) : x.bind some = x := by cases x <;> rfl
@[simp, grind] theorem bind_fun_some (x : Option α) : x.bind some = x := by cases x <;> rfl
@[simp] theorem bind_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
@[simp] theorem bind_fun_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
cases x <;> rfl
theorem bind_eq_some_iff : x.bind f = some b a, x = some a f a = some b := by
@@ -201,7 +199,7 @@ theorem bind_eq_none' {o : Option α} {f : α → Option β} :
o.bind f = none b a, o = some a f a some b := by
cases o <;> simp [eq_none_iff_forall_ne_some]
theorem mem_bind_iff {o : Option α} {f : α Option β} :
@[grind] theorem mem_bind_iff {o : Option α} {f : α Option β} :
b o.bind f a, a o b f a := by
cases o <;> simp
@@ -209,6 +207,7 @@ theorem bind_comm {f : α → β → Option γ} (a : Option α) (b : Option β)
(a.bind fun x => b.bind (f x)) = b.bind fun y => a.bind fun x => f x y := by
cases a <;> cases b <;> rfl
@[grind]
theorem bind_assoc (x : Option α) (f : α Option β) (g : β Option γ) :
(x.bind f).bind g = x.bind fun y => (f y).bind g := by cases x <;> rfl
@@ -216,10 +215,16 @@ theorem bind_congr {α β} {o : Option α} {f g : α → Option β} :
(h : a, o = some a f a = g a) o.bind f = o.bind g := by
cases o <;> simp
@[grind]
theorem isSome_bind {α β : Type _} (x : Option α) (f : α Option β) :
(x.bind f).isSome = x.any (fun x => (f x).isSome) := by
cases x <;> rfl
@[grind]
theorem isNone_bind {α β : Type _} (x : Option α) (f : α Option β) :
(x.bind f).isNone = x.all (fun x => (f x).isNone) := by
cases x <;> rfl
theorem isSome_of_isSome_bind {α β : Type _} {x : Option α} {f : α Option β}
(h : (x.bind f).isSome) : x.isSome := by
cases x <;> trivial
@@ -228,13 +233,15 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α
(h : (x.bind f).isSome) : (f (x.get (isSome_of_isSome_bind h))).isSome := by
cases x <;> trivial
@[simp] theorem get_bind {α β : Type _} {x : Option α} {f : α Option β} (h : (x.bind f).isSome) :
@[simp, grind] theorem get_bind {α β : Type _} {x : Option α} {f : α Option β} (h : (x.bind f).isSome) :
(x.bind f).get h = (f (x.get (isSome_of_isSome_bind h))).get
(isSome_apply_of_isSome_bind h) := by
cases x <;> trivial
theorem join_eq_bind_id {x : Option (Option α)} : x.join = x.bind id := rfl
theorem join_eq_some_iff : x.join = some a x = some (some a) := by
simp [bind_eq_some_iff]
simp [join_eq_bind_id, bind_eq_some_iff]
@[deprecated join_eq_some_iff (since := "2025-04-10")]
abbrev join_eq_some := @join_eq_some_iff
@@ -246,14 +253,14 @@ theorem join_ne_none' : ¬x.join = none ↔ ∃ z, x = some (some z) :=
join_ne_none
theorem join_eq_none_iff : o.join = none o = none o = some none :=
match o with | none | some none | some (some _) => by simp
match o with | none | some none | some (some _) => by simp [join_eq_bind_id]
@[deprecated join_eq_none_iff (since := "2025-04-10")]
abbrev join_eq_none := @join_eq_none_iff
theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
@[grind] theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
@[simp] theorem map_eq_map : Functor.map f = Option.map f := rfl
@[simp, grind] theorem map_eq_map : Functor.map f = Option.map f := rfl
@[deprecated map_none (since := "2025-04-10")]
abbrev map_none' := @map_none
@@ -295,28 +302,28 @@ theorem map_congr {x : Option α} (h : ∀ a, x = some a → f a = g a) :
x.map f = x.map g := by
cases x <;> simp only [map_none, map_some, h]
@[simp] theorem map_id_fun {α : Type u} : Option.map (id : α α) = id := by
@[simp, grind] theorem map_id_fun {α : Type u} : Option.map (id : α α) = id := by
funext; simp [map_id]
theorem map_id' {x : Option α} : (x.map fun a => a) = x := congrFun map_id x
@[simp] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
@[simp, grind] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
funext; simp [map_id']
theorem get_map {f : α β} {o : Option α} {h : (o.map f).isSome} :
@[simp, grind] theorem get_map {f : α β} {o : Option α} {h : (o.map f).isSome} :
(o.map f).get h = f (o.get (by simpa using h)) := by
cases o with
| none => simp at h
| some a => simp
@[simp] theorem map_map (h : β γ) (g : α β) (x : Option α) :
@[simp, grind _=_] theorem map_map (h : β γ) (g : α β) (x : Option α) :
(x.map g).map h = x.map (h g) := by
cases x <;> simp only [map_none, map_some, ··]
theorem comp_map (h : β γ) (g : α β) (x : Option α) : x.map (h g) = (x.map g).map h :=
(map_map ..).symm
@[simp] theorem map_comp_map (f : α β) (g : β γ) :
@[simp, grind _=_] theorem map_comp_map (f : α β) (g : β γ) :
Option.map g Option.map f = Option.map (g f) := by funext x; simp
theorem mem_map_of_mem (g : α β) (h : a x) : g a Option.map g x := h.symm map_some ..
@@ -342,6 +349,12 @@ theorem map_inj_right {f : α → β} {o o' : Option α} (w : ∀ x y, f x = f y
@[grind] theorem filter_some : Option.filter p (some a) = if p a then some a else none := rfl
theorem filter_some_pos (h : p a) : Option.filter p (some a) = some a := by
rw [filter_some, if_pos h]
theorem filter_some_neg (h : p a = false) : Option.filter p (some a) = none := by
rw [filter_some, if_neg] <;> simpa
theorem isSome_of_isSome_filter (p : α Bool) (o : Option α) (h : (o.filter p).isSome) :
o.isSome := by
cases o <;> simp at h
@@ -373,6 +386,11 @@ abbrev filter_eq_none := @filter_eq_none_iff
@[deprecated filter_eq_some_iff (since := "2025-04-10")]
abbrev filter_eq_some := @filter_eq_some_iff
theorem filter_some_eq_some : Option.filter p (some a) = some a p a := by simp
theorem filter_some_eq_none : Option.filter p (some a) = none ¬p a := by simp
@[grind]
theorem mem_filter_iff {p : α Bool} {a : α} {o : Option α} :
a o.filter p a o p a := by
simp
@@ -381,12 +399,68 @@ theorem filter_eq_bind (x : Option α) (p : α → Bool) :
x.filter p = x.bind (Option.guard p) := by
cases x <;> rfl
@[simp] theorem all_guard (a : α) :
@[simp] theorem any_filter : (o : Option α)
(Option.filter p o).any q = Option.any (fun a => p a && q a) o
| none => rfl
| some a =>
match h : p a with
| false => by simp [filter_some_neg h, h]
| true => by simp [filter_some_pos h, h]
@[simp] theorem all_filter : (o : Option α)
(Option.filter p o).all q = Option.all (fun a => !p a || q a) o
| none => rfl
| some a =>
match h : p a with
| false => by simp [filter_some_neg h, h]
| true => by simp [filter_some_pos h, h]
@[simp] theorem isNone_filter :
Option.isNone (Option.filter p o) = Option.all (fun a => !p a) o :=
match o with
| none => rfl
| some a =>
match h : p a with
| false => by simp [filter_some_neg h, h]
| true => by simp [filter_some_pos h, h]
@[simp, grind] theorem isSome_filter : Option.isSome (Option.filter p o) = Option.any p o :=
match o with
| none => rfl
| some a =>
match h : p a with
| false => by simp [filter_some_neg h, h]
| true => by simp [filter_some_pos h, h]
@[simp] theorem filter_filter :
Option.filter q (Option.filter p o) = Option.filter (fun x => p x && q x) o := by
cases o <;> repeat (simp_all [filter_some]; try split)
theorem filter_bind {f : α Option β} :
(Option.bind x f).filter p = (x.filter (fun a => (f a).any p)).bind f := by
cases x with
| none => simp
| some a =>
simp only [bind_some, filter_some]
cases h : f a with
| none => simp
| some b =>
simp only [any_some, filter_some]
split <;> simp [h]
theorem eq_some_of_filter_eq_some {o : Option α} {a : α} (h : o.filter p = some a) : o = some a :=
filter_eq_some_iff.1 h |>.1
theorem filter_map {f : α β} {p : β Bool} :
(Option.map f x).filter p = (x.filter (p f)).map f := by
cases x <;> simp [filter_some]
@[simp, grind] theorem all_guard (a : α) :
Option.all q (guard p a) = (!p a || q a) := by
simp only [guard]
split <;> simp_all
@[simp] theorem any_guard (a : α) : Option.any q (guard p a) = (p a && q a) := by
@[simp, grind] theorem any_guard (a : α) : Option.any q (guard p a) = (p a && q a) := by
simp only [guard]
split <;> simp_all
@@ -425,33 +499,45 @@ theorem any_eq_false_iff_get (p : α → Bool) (x : Option α) :
theorem isSome_of_any {x : Option α} {p : α Bool} (h : x.any p) : x.isSome := by
cases x <;> trivial
@[grind]
theorem any_map {α β : Type _} {x : Option α} {f : α β} {p : β Bool} :
(x.map f).any p = x.any (fun a => p (f a)) := by
cases x <;> rfl
@[grind]
theorem all_map {α β : Type _} {x : Option α} {f : α β} {p : β Bool} :
(x.map f).all p = x.all (fun a => p (f a)) := by
cases x <;> rfl
theorem bind_map_comm {α β} {x : Option (Option α)} {f : α β} :
x.bind (Option.map f) = (x.map (Option.map f)).bind id := by cases x <;> simp
theorem bind_map {f : α β} {g : β Option γ} {x : Option α} :
@[grind] theorem bind_map {f : α β} {g : β Option γ} {x : Option α} :
(x.map f).bind g = x.bind (g f) := by cases x <;> simp
@[simp] theorem map_bind {f : α Option β} {g : β γ} {x : Option α} :
@[simp, grind] theorem map_bind {f : α Option β} {g : β γ} {x : Option α} :
(x.bind f).map g = x.bind (Option.map g f) := by cases x <;> simp
theorem join_map_eq_map_join {f : α β} {x : Option (Option α)} :
@[grind] theorem join_map_eq_map_join {f : α β} {x : Option (Option α)} :
(x.map (Option.map f)).join = x.join.map f := by cases x <;> simp
theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join).join := by
@[grind _=_] theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join).join := by
cases x <;> simp
theorem mem_of_mem_join {a : α} {x : Option (Option α)} (h : a x.join) : some a x :=
h.symm join_eq_some_iff.1 h
@[simp, grind] theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
@[deprecated orElse_some (since := "2025-05-03")]
theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
@[simp, grind] theorem none_orElse (f : Unit Option α) : none.orElse f = f () := rfl
@[deprecated orElse_none (since := "2025-05-03")]
theorem none_orElse (f : Unit Option α) : none.orElse f = f () := rfl
@[simp] theorem orElse_none (x : Option α) : x.orElse (fun _ => none) = x := by cases x <;> rfl
@[simp] theorem orElse_fun_none (x : Option α) : x.orElse (fun _ => none) = x := by cases x <;> rfl
@[simp] theorem orElse_fun_some (x : Option α) (a : α) :
x.orElse (fun _ => some a) = some (x.getD a) := by
cases x <;> simp
theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
(o.orElse f) = some x o = some x o = none f () = some x := by
@@ -460,7 +546,7 @@ theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
theorem orElse_eq_none_iff (o : Option α) (f) : (o.orElse f) = none o = none f () = none := by
cases o <;> simp
theorem map_orElse {x : Option α} {y} :
@[grind] theorem map_orElse {x : Option α} {y} :
(x.orElse y).map f = (x.map f).orElse (fun _ => (y ()).map f) := by
cases x <;> simp
@@ -479,9 +565,6 @@ abbrev guard_isSome := @isSome_guard
@[simp] theorem guard_eq_none_iff : Option.guard p a = none p a = false :=
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
@[deprecated guard_eq_none_iff (since := "2025-04-10")]
abbrev guard_eq_none := @guard_eq_none_iff
@[simp] theorem guard_pos (h : p a) : Option.guard p a = some a := by
simp [Option.guard, h]
@@ -504,7 +587,7 @@ theorem guard_comp {p : α → Bool} {f : β → α} :
ext1 b
simp [guard]
theorem bind_guard (x : Option α) (p : α Bool) :
@[grind] theorem bind_guard (x : Option α) (p : α Bool) :
x.bind (Option.guard p) = x.filter p := by
simp only [Option.filter_eq_bind, decide_eq_true_eq]
@@ -513,9 +596,41 @@ theorem guard_eq_map (p : α → Bool) :
funext x
simp [Option.guard]
@[grind]
theorem guard_def (p : α Bool) :
Option.guard p = fun x => if p x then some x else none := rfl
theorem guard_eq_ite {p : α Bool} {x : α} :
Option.guard p x = if p x then some x else none := rfl
theorem guard_eq_filter {p : α Bool} {x : α} :
Option.guard p x = Option.filter p (some x) := rfl
@[simp] theorem filter_guard {p q : α Bool} {x : α} :
(Option.guard p x).filter q = Option.guard (fun y => p y && q y) x := by
rw [guard_eq_ite]
split <;> simp_all [filter_some, guard_eq_ite]
theorem join_filter {p : Option α Bool} : {o : Option (Option α)}
(o.filter p).join = o.join.filter (fun a => p (some a))
| none => by simp
| some none => by
simp only [join_some, filter_some]
split <;> simp
| some (some a) => by
simp only [join_some, filter_some]
split <;> simp
theorem filter_join {p : α Bool} : {o : Option (Option α)}
o.join.filter p = (o.filter (Option.any p)).join
| none => by simp
| some none => by
simp only [join_some, filter_some]
split <;> simp
| some (some a) => by
simp only [join_some, filter_some, any_some]
split <;> simp
theorem merge_eq_or_eq {f : α α α} (h : a b, f a b = a f a b = b) :
o₁ o₂, merge f o₁ o₂ = o₁ merge f o₁ o₂ = o₂
| none, none => .inl rfl
@@ -569,6 +684,15 @@ instance lawfulIdentity_merge (f : ααα) : Std.LawfulIdentity (merge
@[simp, grind] theorem elim_some (x : β) (f : α β) (a : α) : (some a).elim x f = f a := rfl
theorem elim_filter {o : Option α} {b : β} :
Option.elim (Option.filter p o) b f = Option.elim o b (fun a => if p a then f a else b) :=
match o with
| none => rfl
| some a =>
match h : p a with
| false => by simp [filter_some_neg h, h]
| true => by simp [filter_some_pos, h]
@[simp, grind] theorem getD_map (f : α β) (x : α) (o : Option α) :
(o.map f).getD (f x) = f (getD o x) := by cases o <;> rfl
@@ -585,23 +709,38 @@ Otherwise, it is `none`.
noncomputable def choice (α : Type _) : Option α :=
if h : Nonempty α then some (Classical.choice h) else none
theorem choice_eq {α : Type _} [Subsingleton α] (a : α) : choice α = some a := by
theorem choice_eq_some [Subsingleton α] (a : α) : choice α = some a := by
simp [choice]
rw [dif_pos (a : Nonempty α)]
simp; apply Subsingleton.elim
theorem isSome_choice_iff_nonempty {α : Type _} : (choice α).isSome Nonempty α :=
@[deprecated choice_eq_some (since := "2025-05-12")]
abbrev choice_eq := @choice_eq_some
@[simp]
theorem choice_eq_default [Subsingleton α] [Inhabited α] : choice α = some default :=
choice_eq_some _
theorem choice_eq_none_iff_not_nonempty : choice α = none ¬Nonempty α := by
simp [choice]
theorem isSome_choice_iff_nonempty : (choice α).isSome Nonempty α :=
fun h => (choice α).get h, fun h => by simp only [choice, dif_pos h, isSome_some]
@[deprecated isSome_choice_iff_nonempty (since := "2025-03-18")]
abbrev choice_isSome_iff_nonempty := @isSome_choice_iff_nonempty
theorem isNone_choice_iff_not_nonempty : (choice α).isNone ¬Nonempty α := by
rw [isNone_iff_eq_none, choice_eq_none_iff_not_nonempty]
end choice
@[simp, grind] theorem toList_some (a : α) : (some a).toList = [a] := rfl
@[simp, grind] theorem toList_none (α : Type _) : (none : Option α).toList = [] := rfl
@[simp, grind] theorem toArray_some (a : α) : (some a).toArray = #[a] := rfl
@[simp, grind] theorem toArray_none (α : Type _) : (none : Option α).toArray = #[] := rfl
-- See `Init.Data.Option.List` for lemmas about `toList`.
@[simp, grind] theorem some_or : (some a).or o = some a := rfl
@@ -610,10 +749,14 @@ end choice
theorem or_eq_right_of_none {o o' : Option α} (h : o = none) : o.or o' = o' := by
cases h; simp
@[deprecated some_or (since := "2024-11-03")] theorem or_some : (some a).or o = some a := rfl
@[simp, grind] theorem or_some {o : Option α} : o.or (some a) = some (o.getD a) := by
cases o <;> rfl
/-- This will be renamed to `or_some` once the existing deprecated lemma is removed. -/
@[simp, grind] theorem or_some' {o : Option α} : o.or (some a) = some (o.getD a) := by
@[deprecated or_some (since := "2025-05-03")]
abbrev or_some' := @or_some
@[simp, grind]
theorem or_none : or o none = o := by
cases o <;> rfl
theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
@@ -637,14 +780,10 @@ abbrev or_eq_none := @or_eq_none_iff
@[deprecated or_eq_some_iff (since := "2025-04-10")]
abbrev or_eq_some := @or_eq_some_iff
theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
@[grind] theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
cases o₁ <;> cases o₂ <;> rfl
instance : Std.Associative (or (α := α)) := @or_assoc _
@[simp, grind]
theorem or_none : or o none = o := by
cases o <;> rfl
theorem or_eq_left_of_none {o o' : Option α} (h : o' = none) : o.or o' = o := by
cases h; simp
@@ -679,16 +818,24 @@ theorem getD_or {o o' : Option α} {fallback : α} :
(o.or o').getD fallback = o.getD (o'.getD fallback) := by
cases o <;> simp
@[simp] theorem filter_or_filter {o o' : Option α} {f : α Bool} :
(o.or (o'.filter f)).filter f = (o.or o').filter f := by
cases o <;> cases o' <;> simp
/-! ### beq -/
section beq
variable [BEq α]
@[simp] theorem none_beq_none : ((none : Option α) == none) = true := rfl
@[simp] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
@[simp] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
@[simp] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
@[simp, grind] theorem none_beq_none : ((none : Option α) == none) = true := rfl
@[simp, grind] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
@[simp, grind] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
@[simp, grind] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
/-- We simplify away `isEqSome` in terms of `==`. -/
@[simp, grind] theorem isEqSome_eq_beq_some {o : Option α} : isEqSome o y = (o == some y) := by
cases o <;> simp [isEqSome]
@[simp] theorem reflBEq_iff : ReflBEq (Option α) ReflBEq α := by
constructor
@@ -802,14 +949,7 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
end ite
theorem isSome_filter {α : Type _} {x : Option α} {f : α Bool} :
(x.filter f).isSome = x.any f := by
cases x
· rfl
· rw [Bool.eq_iff_iff]
simp only [Option.any_some, Option.filter, Option.isSome_ite]
@[simp] theorem get_filter {α : Type _} {x : Option α} {f : α Bool} (h : (x.filter f).isSome) :
@[simp, grind] theorem get_filter {α : Type _} {x : Option α} {f : α Bool} (h : (x.filter f).isSome) :
(x.filter f).get h = x.get (isSome_of_isSome_filter f x h) := by
cases x
· contradiction
@@ -821,16 +961,16 @@ theorem isSome_filter {α : Type _} {x : Option α} {f : α → Bool} :
@[simp, grind] theorem pbind_none : pbind none f = none := rfl
@[simp, grind] theorem pbind_some : pbind (some a) f = f a rfl := rfl
@[simp] theorem map_pbind {o : Option α} {f : (a : α) o = some a Option β}
@[simp, grind] theorem map_pbind {o : Option α} {f : (a : α) o = some a Option β}
{g : β γ} : (o.pbind f).map g = o.pbind (fun a h => (f a h).map g) := by
cases o <;> rfl
@[simp] theorem pbind_map {α β γ : Type _} (o : Option α)
@[simp, grind] theorem pbind_map {α β γ : Type _} (o : Option α)
(f : α β) (g : (x : β) o.map f = some x Option γ) :
(o.map f).pbind g = o.pbind (fun x h => g (f x) (h rfl)) := by
cases o <;> rfl
@[simp] theorem pbind_eq_bind {α β : Type _} (o : Option α)
@[simp, grind] theorem pbind_eq_bind {α β : Type _} (o : Option α)
(f : α Option β) : o.pbind (fun x _ => f x) = o.bind f := by
cases o <;> rfl
@@ -890,16 +1030,16 @@ theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → o = some a → Optio
· rintro h, rfl
rfl
@[simp]
@[simp, grind]
theorem pmap_eq_map (p : α Prop) (f : α β) (o : Option α) (H) :
@pmap _ _ p (fun a _ => f a) o H = Option.map f o := by
cases o <;> simp
theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (o H) :
@[grind] theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (o H) :
Option.map g (pmap f o H) = pmap (fun a h => g (f a h)) o H := by
cases o <;> simp
theorem pmap_map (o : Option α) (f : α β) {p : β Prop} (g : b, p b γ) (H) :
@[grind] theorem pmap_map (o : Option α) (f : α β) {p : β Prop} (g : b, p b γ) (H) :
pmap g (o.map f) H =
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some_iff.2 _, m, rfl)) := by
cases o <;> simp
@@ -938,15 +1078,29 @@ theorem pmap_congr {α : Type u} {β : Type v}
@[simp, grind] theorem pelim_none : pelim none b f = b := rfl
@[simp, grind] theorem pelim_some : pelim (some a) b f = f a rfl := rfl
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
@[simp, grind] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
cases o <;> simp
@[simp] theorem elim_pmap {p : α Prop} (f : (a : α) p a β) (o : Option α)
@[simp, grind] theorem elim_pmap {p : α Prop} (f : (a : α) p a β) (o : Option α)
(H : (a : α), o = some a p a) (g : γ) (g' : β γ) :
(o.pmap f H).elim g g' =
o.pelim g (fun a h => g' (f a (H a h))) := by
cases o <;> simp
theorem pelim_congr_left {o o' : Option α } {b : β} {f : (a : α) (a o) β} (h : o = o') :
pelim o b f = pelim o' b (fun a ha => f a (h ha)) := by
cases h; rfl
theorem pelim_filter {o : Option α} {b : β} {f : (a : α) a o.filter p β} :
Option.pelim (Option.filter p o) b f =
Option.pelim o b (fun a h => if hp : p a then f a (Option.mem_filter_iff.2 h, hp) else b) :=
match o with
| none => rfl
| some a =>
match h : p a with
| false => by simp [pelim_congr_left (filter_some_neg h), h]
| true => by simp [pelim_congr_left (filter_some_pos h), h]
/-! ### pfilter -/
@[congr]
@@ -978,7 +1132,7 @@ theorem isSome_of_isSome_pfilter {α : Type _} {o : Option α} {p : (a : α) →
(h : (o.pfilter p).isSome) : o.isSome :=
(isSome_pfilter_iff_get.mp h).1
@[simp] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) o = some a Bool}
@[simp, grind] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) o = some a Bool}
(h : (o.pfilter p).isSome) :
(o.pfilter p).get h = o.get (isSome_of_isSome_pfilter h) := by
cases o <;> simp
@@ -996,13 +1150,54 @@ theorem pfilter_eq_some_iff {α : Type _} {o : Option α} {p : (a : α) → o =
· rintro h, rfl, h'
exact o.get h, h, rfl, h', rfl
@[simp] theorem pfilter_eq_filter {α : Type _} {o : Option α} {p : α Bool} :
theorem eq_some_of_pfilter_eq_some {o : Option α} {p : (a : α) o = some a Bool}
{a : α} (h : o.pfilter p = some a) : o = some a :=
pfilter_eq_some_iff.1 h |>.1
theorem filter_pbind {f : (a : α) o = some a Option β} :
(Option.pbind o f).filter p =
(o.pfilter (fun a h => (f a h).any p)).pbind (fun a h => f a (eq_some_of_pfilter_eq_some h)) := by
cases o with
| none => simp
| some a =>
simp only [pbind_some, pfilter_some]
obtain (h|b, h) := Option.eq_none_or_eq_some (f a rfl)
· simp [h]
· simp only [h, filter_some, any_some]
split <;> simp [h]
@[simp, grind] theorem pfilter_eq_filter {α : Type _} {o : Option α} {p : α Bool} :
o.pfilter (fun a _ => p a) = o.filter p := by
cases o with
| none => rfl
| some a =>
simp only [pfilter, Option.filter, Bool.cond_eq_ite_iff]
@[simp] theorem pfilter_filter {o : Option α} {p : α Bool} {q : (a : α) o.filter p = some a Bool} :
(o.filter p).pfilter q = o.pfilter (fun a h => if h' : p a then q a (Option.filter_eq_some_iff.2 h, h') else false) := by
cases o with
| none => simp
| some a =>
simp only [filter_some, pfilter_some]
split <;> simp
@[simp] theorem filter_pfilter {o : Option α} {p : (a : α) o = some a Bool} {q : α Bool} :
(o.pfilter p).filter q = o.pfilter (fun a h => p a h && q a) := by
cases o with
| none => simp
| some a =>
simp only [pfilter_some, Bool.and_eq_true]
split <;> simp [filter_some, *]
@[simp] theorem pfilter_pfilter {o : Option α} {p : (a : α) o = some a Bool}
{q : (a : α) o.pfilter p = some a Bool} :
(o.pfilter p).pfilter q = o.pfilter (fun a h => if h' : p a h then q a (Option.pfilter_eq_some_iff.2 h, h') else false) := by
cases o with
| none => simp
| some a =>
simp only [pfilter_some]
split <;> simp
theorem pfilter_eq_pbind_ite {α : Type _} {o : Option α}
{p : (a : α) o = some a Bool} :
o.pfilter p = o.pbind (fun a h => if p a h then some a else none) := by
@@ -1012,13 +1207,23 @@ theorem pfilter_eq_pbind_ite {α : Type _} {o : Option α}
/-! ### LT and LE -/
@[simp] theorem not_lt_none [LT α] {a : Option α} : ¬ a < none := by cases a <;> simp [LT.lt, Option.lt]
@[simp] theorem none_lt_some [LT α] {a : α} : none < some a := by simp [LT.lt, Option.lt]
@[simp] theorem some_lt_some [LT α] {a b : α} : some a < some b a < b := by simp [LT.lt, Option.lt]
@[simp, grind] theorem not_lt_none [LT α] {a : Option α} : ¬ a < none := by cases a <;> simp [LT.lt, Option.lt]
@[simp, grind] theorem none_lt_some [LT α] {a : α} : none < some a := by simp [LT.lt, Option.lt]
@[simp] theorem none_lt [LT α] {a : Option α} : none < a a.isSome := by cases a <;> simp
@[simp, grind] theorem some_lt_some [LT α] {a b : α} : some a < some b a < b := by simp [LT.lt, Option.lt]
@[simp] theorem none_le [LE α] {a : Option α} : none a := by cases a <;> simp [LE.le, Option.le]
@[simp] theorem not_some_le_none [LE α] {a : α} : ¬ some a none := by simp [LE.le, Option.le]
@[simp] theorem some_le_some [LE α] {a b : α} : some a some b a b := by simp [LE.le, Option.le]
@[simp, grind] theorem none_le [LE α] {a : Option α} : none a := by cases a <;> simp [LE.le, Option.le]
@[simp, grind] theorem not_some_le_none [LE α] {a : α} : ¬ some a none := by simp [LE.le, Option.le]
@[simp] theorem le_none [LE α] {a : Option α} : a none a = none := by cases a <;> simp
@[simp, grind] theorem some_le_some [LE α] {a b : α} : some a some b a b := by simp [LE.le, Option.le]
/-! ### Rel -/
@[simp] theorem rel_some_some {r : α β Prop} : Rel r (some a) (some b) r a b :=
fun | .some h => h, .some
@[simp] theorem not_rel_some_none {r : α β Prop} : ¬Rel r (some a) none := nofun
@[simp] theorem not_rel_none_some {r : α β Prop} : ¬Rel r none (some a) := nofun
@[simp] theorem rel_none_none {r : α β Prop} : Rel r none none := .none
/-! ### min and max -/
@@ -1086,4 +1291,11 @@ theorem max_le [LE α] [Max α] (max_le : ∀ x y z : α, max x y ≤ z ↔ x
{a b c : Option α} : max a b c a c b c := by
cases a <;> cases b <;> cases c <;> simp_all
@[simp]
theorem merge_max [Max α] : merge (α := α) max = max := by
funext a b; cases a <;> cases b <;> rfl
instance [Max α] : Std.LawfulIdentity (α := Option α) max none := by
rw [ merge_max]; infer_instance
end Option

View File

@@ -10,63 +10,54 @@ import Init.Data.List.Lemmas
namespace Option
@[simp] theorem mem_toList {a : α} {o : Option α} : a o.toList o = some a := by
@[simp, grind] theorem mem_toList {a : α} {o : Option α} : a o.toList o = some a := by
cases o <;> simp [eq_comm]
@[simp] theorem forIn'_none [Monad m] (b : β) (f : (a : α) a none β m (ForInStep β)) :
forIn' none b f = pure b := by
rfl
@[simp] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp] theorem forIn_none [Monad m] (b : β) (f : α β m (ForInStep β)) :
forIn none b f = pure b := by
rfl
@[simp] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn, forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toList β m (ForInStep β)) :
@[simp, grind] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toList β m (ForInStep β)) :
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
cases o <;> rfl
@[simp] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
forIn o.toList b f = forIn o b f := by
cases o <;> rfl
@[simp] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
@[simp, grind] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
cases o <;> simp
@[simp] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
@[simp, grind] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
cases o <;> simp
@[simp] theorem foldl_toList (o : Option β) (a : α) (f : α β α) :
@[simp, grind] theorem foldl_toList (o : Option β) (a : α) (f : α β α) :
o.toList.foldl f a = o.elim a (fun b => f a b) := by
cases o <;> simp
@[simp] theorem foldr_toList (o : Option β) (a : α) (f : β α α) :
@[simp, grind] theorem foldr_toList (o : Option β) (a : α) (f : β α α) :
o.toList.foldr f a = o.elim a (fun b => f b a) := by
cases o <;> simp
@[simp]
@[simp, grind]
theorem pairwise_toList {P : α α Prop} {o : Option α} : o.toList.Pairwise P := by
cases o <;> simp
@[simp]
@[simp, grind]
theorem head?_toList {o : Option α} : o.toList.head? = o := by
cases o <;> simp
theorem toList_filter {o : Option α} {p : α Bool} : (o.filter p).toList = o.toList.filter p :=
match o with
| none => rfl
| some a =>
match h : p a with
| false => by simp [filter_some_neg h, h]
| true => by simp [filter_some_pos h, h]
theorem toList_bind {o : Option α} {f : α Option β} :
(o.bind f).toList = o.toList.flatMap (Option.toList f) := by
cases o <;> simp
theorem toList_join {o : Option (Option α)} : o.join.toList = o.toList.flatMap Option.toList := by
simp [toList_bind, join_eq_bind_id]
end Option

View File

@@ -12,16 +12,47 @@ import Init.Control.Lawful.Basic
namespace Option
@[simp] theorem forM_none [Monad m] (f : α m PUnit) :
none.forM f = pure .unit := rfl
@[simp, grind] theorem bindM_none [Monad m] (f : α m (Option β)) : none.bindM f = pure none := rfl
@[simp, grind] theorem bindM_some [Monad m] [LawfulMonad m] (a) (f : α m (Option β)) : (some a).bindM f = f a := by
simp [Option.bindM]
@[simp] theorem forM_some [Monad m] (f : α m PUnit) (a : α) :
(some a).forM f = f a := rfl
-- We simplify `Option.forM` to `forM`.
@[simp] theorem forM_eq_forM [Monad m] : @Option.forM m α _ = forM := rfl
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α β) (f : β m PUnit) :
(o.map g).forM f = o.forM (fun a => f (g a)) := by
@[simp, grind] theorem forM_none [Monad m] (f : α m PUnit) :
forM none f = pure .unit := rfl
@[simp, grind] theorem forM_some [Monad m] (f : α m PUnit) (a : α) :
forM (some a) f = f a := rfl
@[simp, grind] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α β) (f : β m PUnit) :
forM (o.map g) f = forM o (fun a => f (g a)) := by
cases o <;> simp
@[simp, grind] theorem forIn'_none [Monad m] (b : β) (f : (a : α) a none β m (ForInStep β)) :
forIn' none b f = pure b := by
rfl
@[simp, grind] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp, grind] theorem forIn_none [Monad m] (b : β) (f : α β m (ForInStep β)) :
forIn none b f = pure b := by
rfl
@[simp, grind] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn, forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[congr] theorem forIn'_congr [Monad m] [LawfulMonad m] {as bs : Option α} (w : as = bs)
{b b' : β} (hb : b = b')
{f : (a' : α) a' as β m (ForInStep β)}
@@ -60,7 +91,7 @@ theorem forIn'_eq_pelim [Monad m] [LawfulMonad m]
o.pelim b (fun a h => f a h b) := by
cases o <;> simp
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
@[simp, grind] theorem forIn'_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : (b : β) b o.map g γ m (ForInStep γ)) :
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases o <;> simp
@@ -89,11 +120,34 @@ theorem forIn_eq_elim [Monad m] [LawfulMonad m]
o.elim b (fun a => f a b) := by
cases o <;> simp
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
@[simp, grind] theorem forIn_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
cases o <;> simp
@[simp] theorem mapA_eq_mapM : @Option.mapA = @Option.mapM := rfl
@[simp] theorem elimM_pure [Monad m] [LawfulMonad m] (x : Option α) (y : m β) (z : α m β) :
Option.elimM (pure x : m (Option α)) y z = x.elim y z := by
simp [Option.elimM]
@[simp] theorem elimM_bind [Monad m] [LawfulMonad m] (x : m α) (f : α m (Option β))
(y : m γ) (z : β m γ) : Option.elimM (x >>= f) y z = (do Option.elimM (f ( x)) y z) := by
simp [Option.elimM]
@[simp] theorem elimM_map [Monad m] [LawfulMonad m] (x : m α) (f : α Option β)
(y : m γ) (z : β m γ) : Option.elimM (f <$> x) y z = (do Option.elim (f ( x)) y z) := by
simp [Option.elimM]
@[simp] theorem tryCatch_none (alternative : Unit Option α) :
(tryCatch none alternative) = alternative () := rfl
@[simp] theorem tryCatch_some (a : α) (alternative : Unit Option α) :
(tryCatch (some a) alternative) = some a := rfl
@[simp] theorem throw_eq_none : throw () = (none : Option α) := rfl
@[simp, grind] theorem filterM_none [Applicative m] (p : α m Bool) :
none.filterM p = pure none := rfl
theorem filterM_some [Applicative m] (p : α m Bool) (a : α) :
(some a).filterM p = (fun b => if b then some a else none) <$> p a := rfl
end Option

View File

@@ -7,7 +7,7 @@ Authors: Dany Fabian, Sebastian Ullrich
module
prelude
import Init.Data.String
import Init.Data.String.Basic
import Init.Data.Array.Basic
import Init.Data.SInt.Basic
import Init.Data.Vector.Basic

View File

@@ -55,10 +55,12 @@ This instance allows us to use `Empty` as a type parameter without causing insta
instance : Repr Empty where
reprPrec := nofun
protected def Bool.repr : Bool Nat Format
| true, _ => "true"
| false, _ => "false"
instance : Repr Bool where
reprPrec
| true, _ => "true"
| false, _ => "false"
reprPrec := Bool.repr
def Repr.addAppParen (f : Format) (prec : Nat) : Format :=
if prec >= max_prec then
@@ -66,10 +68,12 @@ def Repr.addAppParen (f : Format) (prec : Nat) : Format :=
else
f
protected def Decidable.repr : Decidable p Nat Format
| .isTrue _, prec => Repr.addAppParen "isTrue _" prec
| .isFalse _, prec => Repr.addAppParen "isFalse _" prec
instance : Repr (Decidable p) where
reprPrec
| Decidable.isTrue _, prec => Repr.addAppParen "isTrue _" prec
| Decidable.isFalse _, prec => Repr.addAppParen "isFalse _" prec
reprPrec := Decidable.repr
instance : Repr PUnit.{u+1} where
reprPrec _ _ := "PUnit.unit"
@@ -109,8 +113,11 @@ export ReprTuple (reprTuple)
instance [Repr α] : ReprTuple α where
reprTuple a xs := repr a :: xs
protected def Prod.reprTuple [Repr α] [ReprTuple β] : α × β List Format List Format
| (a, b), xs => reprTuple b (repr a :: xs)
instance [Repr α] [ReprTuple β] : ReprTuple (α × β) where
reprTuple | (a, b), xs => reprTuple b (repr a :: xs)
reprTuple := Prod.reprTuple
protected def Prod.repr [Repr α] [ReprTuple β] : α × β Nat Format
| (a, b), _ => Format.bracket "(" (Format.joinSep (reprTuple b [repr a]).reverse ("," ++ Format.line)) ")"
@@ -118,8 +125,11 @@ protected def Prod.repr [Repr α] [ReprTuple β] : α × β → Nat → Format
instance [Repr α] [ReprTuple β] : Repr (α × β) where
reprPrec := Prod.repr
protected def Sigma.repr {β : α Type v} [Repr α] [(x : α) Repr (β x)] : Sigma β Nat Format
| a, b, _ => Format.bracket "" (repr a ++ ", " ++ repr b) ""
instance {β : α Type v} [Repr α] [(x : α) Repr (β x)] : Repr (Sigma β) where
reprPrec | a, b, _ => Format.bracket "" (repr a ++ ", " ++ repr b) ""
reprPrec := Sigma.repr
instance {p : α Prop} [Repr α] : Repr (Subtype p) where
reprPrec s prec := reprPrec s.val prec

View File

@@ -85,6 +85,8 @@ Examples:
-/
@[extern "lean_uint8_mod"]
protected def UInt8.mod (a b : UInt8) : UInt8 := BitVec.umod a.toBitVec b.toBitVec
-- Note: This is deprecated, but still used in the `HMod` instance below.
set_option linter.missingDocs false in
@[deprecated UInt8.mod (since := "2024-09-23")]
protected def UInt8.modn (a : UInt8) (n : Nat) : UInt8 := Fin.modn a.toFin n
@@ -297,6 +299,8 @@ Examples:
-/
@[extern "lean_uint16_mod"]
protected def UInt16.mod (a b : UInt16) : UInt16 := BitVec.umod a.toBitVec b.toBitVec
-- Note: This is deprecated, but still used in the `HMod` instance below.
set_option linter.missingDocs false in
@[deprecated UInt16.mod (since := "2024-09-23")]
protected def UInt16.modn (a : UInt16) (n : Nat) : UInt16 := Fin.modn a.toFin n
@@ -511,6 +515,8 @@ Examples:
-/
@[extern "lean_uint32_mod"]
protected def UInt32.mod (a b : UInt32) : UInt32 := BitVec.umod a.toBitVec b.toBitVec
-- Note: This is deprecated, but still used in the `HMod` instance below.
set_option linter.missingDocs false in
@[deprecated UInt32.mod (since := "2024-09-23")]
protected def UInt32.modn (a : UInt32) (n : Nat) : UInt32 := Fin.modn a.toFin n
@@ -687,6 +693,8 @@ Examples:
-/
@[extern "lean_uint64_mod"]
protected def UInt64.mod (a b : UInt64) : UInt64 := BitVec.umod a.toBitVec b.toBitVec
-- Note: This is deprecated, but still used in the `HMod` instance below.
set_option linter.missingDocs false in
@[deprecated UInt64.mod (since := "2024-09-23")]
protected def UInt64.modn (a : UInt64) (n : Nat) : UInt64 := Fin.modn a.toFin n
@@ -894,6 +902,8 @@ Examples:
-/
@[extern "lean_usize_mod"]
protected def USize.mod (a b : USize) : USize := a.toBitVec % b.toBitVec
-- Note: This is deprecated, but still used in the `HMod` instance below.
set_option linter.missingDocs false in
@[deprecated USize.mod (since := "2024-09-23")]
protected def USize.modn (a : USize) (n : Nat) : USize := Fin.modn a.toFin n

View File

@@ -575,15 +575,15 @@ expression `(a >>> b).toUInt8` is not a function of `a.toUInt8` and `b.toUInt8`.
BitVec.toNat_umod, toNat_toBitVec, toNat_ofNat', BitVec.toNat_ofNat, Nat.mod_two_pow_self]
rw [Nat.mod_mod_of_dvd _ (by cases System.Platform.numBits_eq <;> simp_all)]
@[simp] theorem UInt8.ofFin_shiftLeft (a b : Fin UInt8.size) (hb : b < 8) : UInt8.ofFin (a <<< b) = UInt8.ofFin a <<< UInt8.ofFin b :=
@[simp] theorem UInt8.ofFin_shiftLeft (a b : Fin UInt8.size) (hb : b.val < 8) : UInt8.ofFin (a <<< b) = UInt8.ofFin a <<< UInt8.ofFin b :=
UInt8.toFin_inj.1 (by simp [UInt8.toFin_shiftLeft (ofFin a) (ofFin b) hb])
@[simp] theorem UInt16.ofFin_shiftLeft (a b : Fin UInt16.size) (hb : b < 16) : UInt16.ofFin (a <<< b) = UInt16.ofFin a <<< UInt16.ofFin b :=
@[simp] theorem UInt16.ofFin_shiftLeft (a b : Fin UInt16.size) (hb : b.val < 16) : UInt16.ofFin (a <<< b) = UInt16.ofFin a <<< UInt16.ofFin b :=
UInt16.toFin_inj.1 (by simp [UInt16.toFin_shiftLeft (ofFin a) (ofFin b) hb])
@[simp] theorem UInt32.ofFin_shiftLeft (a b : Fin UInt32.size) (hb : b < 32) : UInt32.ofFin (a <<< b) = UInt32.ofFin a <<< UInt32.ofFin b :=
@[simp] theorem UInt32.ofFin_shiftLeft (a b : Fin UInt32.size) (hb : b.val < 32) : UInt32.ofFin (a <<< b) = UInt32.ofFin a <<< UInt32.ofFin b :=
UInt32.toFin_inj.1 (by simp [UInt32.toFin_shiftLeft (ofFin a) (ofFin b) hb])
@[simp] theorem UInt64.ofFin_shiftLeft (a b : Fin UInt64.size) (hb : b < 64) : UInt64.ofFin (a <<< b) = UInt64.ofFin a <<< UInt64.ofFin b :=
@[simp] theorem UInt64.ofFin_shiftLeft (a b : Fin UInt64.size) (hb : b.val < 64) : UInt64.ofFin (a <<< b) = UInt64.ofFin a <<< UInt64.ofFin b :=
UInt64.toFin_inj.1 (by simp [UInt64.toFin_shiftLeft (ofFin a) (ofFin b) hb])
@[simp] theorem USize.ofFin_shiftLeft (a b : Fin USize.size) (hb : b < System.Platform.numBits) : USize.ofFin (a <<< b) = USize.ofFin a <<< USize.ofFin b :=
@[simp] theorem USize.ofFin_shiftLeft (a b : Fin USize.size) (hb : b.val < System.Platform.numBits) : USize.ofFin (a <<< b) = USize.ofFin a <<< USize.ofFin b :=
USize.toFin_inj.1 (by simp [USize.toFin_shiftLeft (ofFin a) (ofFin b) hb])
@[simp] theorem UInt8.ofFin_shiftLeft_mod (a b : Fin UInt8.size) : UInt8.ofFin (a <<< (b % 8)) = UInt8.ofFin a <<< UInt8.ofFin b :=
@@ -670,15 +670,15 @@ expression `(a >>> b).toUInt8` is not a function of `a.toUInt8` and `b.toUInt8`.
BitVec.toNat_umod, toNat_toBitVec, toNat_ofNat', BitVec.toNat_ofNat, Nat.mod_two_pow_self]
rw [Nat.mod_mod_of_dvd _ (by cases System.Platform.numBits_eq <;> simp_all)]
@[simp] theorem UInt8.ofFin_shiftRight (a b : Fin UInt8.size) (hb : b < 8) : UInt8.ofFin (a >>> b) = UInt8.ofFin a >>> UInt8.ofFin b :=
@[simp] theorem UInt8.ofFin_shiftRight (a b : Fin UInt8.size) (hb : b.val < 8) : UInt8.ofFin (a >>> b) = UInt8.ofFin a >>> UInt8.ofFin b :=
UInt8.toFin_inj.1 (by simp [UInt8.toFin_shiftRight (ofFin a) (ofFin b) hb])
@[simp] theorem UInt16.ofFin_shiftRight (a b : Fin UInt16.size) (hb : b < 16) : UInt16.ofFin (a >>> b) = UInt16.ofFin a >>> UInt16.ofFin b :=
@[simp] theorem UInt16.ofFin_shiftRight (a b : Fin UInt16.size) (hb : b.val < 16) : UInt16.ofFin (a >>> b) = UInt16.ofFin a >>> UInt16.ofFin b :=
UInt16.toFin_inj.1 (by simp [UInt16.toFin_shiftRight (ofFin a) (ofFin b) hb])
@[simp] theorem UInt32.ofFin_shiftRight (a b : Fin UInt32.size) (hb : b < 32) : UInt32.ofFin (a >>> b) = UInt32.ofFin a >>> UInt32.ofFin b :=
@[simp] theorem UInt32.ofFin_shiftRight (a b : Fin UInt32.size) (hb : b.val < 32) : UInt32.ofFin (a >>> b) = UInt32.ofFin a >>> UInt32.ofFin b :=
UInt32.toFin_inj.1 (by simp [UInt32.toFin_shiftRight (ofFin a) (ofFin b) hb])
@[simp] theorem UInt64.ofFin_shiftRight (a b : Fin UInt64.size) (hb : b < 64) : UInt64.ofFin (a >>> b) = UInt64.ofFin a >>> UInt64.ofFin b :=
@[simp] theorem UInt64.ofFin_shiftRight (a b : Fin UInt64.size) (hb : b.val < 64) : UInt64.ofFin (a >>> b) = UInt64.ofFin a >>> UInt64.ofFin b :=
UInt64.toFin_inj.1 (by simp [UInt64.toFin_shiftRight (ofFin a) (ofFin b) hb])
@[simp] theorem USize.ofFin_shiftRight (a b : Fin USize.size) (hb : b < System.Platform.numBits) : USize.ofFin (a >>> b) = USize.ofFin a >>> USize.ofFin b :=
@[simp] theorem USize.ofFin_shiftRight (a b : Fin USize.size) (hb : b.val < System.Platform.numBits) : USize.ofFin (a >>> b) = USize.ofFin a >>> USize.ofFin b :=
USize.toFin_inj.1 (by simp [USize.toFin_shiftRight (ofFin a) (ofFin b) hb])
@[simp] theorem UInt8.ofFin_shiftRight_mod (a b : Fin UInt8.size) : UInt8.ofFin (a >>> (b % 8)) = UInt8.ofFin a >>> UInt8.ofFin b :=

View File

@@ -184,20 +184,6 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
· apply toNat_lt_size
· simpa using h2
open $typeName (toNat_mod_lt modn) in
set_option linter.deprecated false in
@[deprecated toNat_mod_lt (since := "2024-09-24")]
protected theorem modn_lt {m : Nat} : (u : $typeName), m > 0 toNat (u % m) < m := by
intro u
simp only [(· % ·)]
simp only [gt_iff_lt, toNat, modn, Fin.modn_val, BitVec.natCast_eq_ofNat, BitVec.toNat_ofNat,
Nat.reducePow]
rw [Nat.mod_eq_of_lt]
· apply Nat.mod_lt
· apply Nat.lt_of_le_of_lt
· apply Nat.mod_le
· apply Fin.is_lt
protected theorem mod_lt (a : $typeName) {b : $typeName} : 0 < b a % b < b := by
simp only [lt_iff_toBitVec_lt, mod_def]
apply BitVec.umod_lt

View File

@@ -69,7 +69,8 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
@[simp] theorem toList_attachWith {xs : Vector α n} {P : α Prop} {H : x xs, P x} :
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa using H) := by
simp [attachWith]
rcases xs with xs, rfl
simp
@[simp] theorem toList_attach {xs : Vector α n} :
xs.attach.toList = xs.toList.attachWith (· xs) (by simp) := by
@@ -77,7 +78,8 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
@[simp] theorem toList_pmap {xs : Vector α n} {P : α Prop} {f : a, P a β} {H : a xs, P a} :
(xs.pmap f H).toList = xs.toList.pmap f (fun a m => H a (by simpa using m)) := by
simp [pmap]
rcases xs with xs, rfl
simp
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
@[inline] private def pmapImpl {P : α Prop} (f : a, P a β) (xs : Vector α n) (H : a xs, P a) :
@@ -492,7 +494,8 @@ def unattach {α : Type _} {p : α → Prop} (xs : Vector { x // p x } n) : Vect
@[simp] theorem toList_unattach {p : α Prop} {xs : Vector { x // p x } n} :
xs.unattach.toList = xs.toList.unattach := by
simp [unattach]
rcases xs with xs, rfl
simp
@[simp] theorem unattach_attach {xs : Vector α n} : xs.attach.unattach = xs := by
rcases xs with xs, rfl

View File

@@ -24,12 +24,14 @@ set_option linter.listVariables true -- Enforce naming conventions for `List`/`A
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
/-- `Vector α n` is an `Array α` with size `n`. -/
structure Vector (α : Type u) (n : Nat) extends Array α where
structure Vector (α : Type u) (n : Nat) where
/-- The underlying array. -/
toArray : Array α
/-- Array size. -/
size_toArray : toArray.size = n
deriving Repr, DecidableEq
attribute [simp] Vector.size_toArray
attribute [simp, grind] Vector.size_toArray
/--
Converts an array to a vector. The resulting vector's size is the array's size.
@@ -38,6 +40,9 @@ abbrev Array.toVector (xs : Array α) : Vector α xs.size := .mk xs rfl
namespace Vector
/-- The size of a vector. -/
abbrev size {α n} (_ : Vector α n) : Nat := n
/-- Syntax for `Vector α n` -/
syntax (name := «term#v[_,]») "#v[" withoutPosition(term,*,?) "]" : term
@@ -48,6 +53,9 @@ macro_rules
recommended_spelling "empty" for "#v[]" in [Vector.mk, «term#v[_,]»]
recommended_spelling "singleton" for "#v[x]" in [Vector.mk, «term#v[_,]»]
/-- Convert a vector to a list. -/
def toList (xs : Vector α n) : List α := xs.toArray.toList
/-- Custom eliminator for `Vector α n` through `Array α` -/
@[elab_as_elim]
def elimAsArray {motive : Vector α n Sort u}
@@ -469,6 +477,16 @@ to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
@[inline] def replace [BEq α] (xs : Vector α n) (a b : α) : Vector α n :=
xs.toArray.replace a b, by simp
/--
Computes the sum of the elements of a vector.
Examples:
* `#v[a, b, c].sum = a + (b + (c + 0))`
* `#v[1, 2, 5].sum = 8`
-/
@[inline] def sum [Add α] [Zero α] (xs : Vector α n) : α :=
xs.toArray.sum
/--
Pad a vector on the left with a given element.

View File

@@ -66,8 +66,8 @@ theorem countP_le_size {xs : Vector α n} : countP p xs ≤ n := by
cases xs
simp
@[simp] theorem countP_eq_size {p} : countP p xs = xs.size a xs, p a := by
cases xs
@[simp] theorem countP_eq_size {p} {xs : Vector α n} : countP p xs = n a xs, p a := by
rcases xs with xs, rfl
simp
@[simp] theorem countP_cast (p : α Bool) (xs : Vector α n) : countP p (xs.cast h) = countP p xs := by
@@ -213,7 +213,7 @@ theorem not_mem_of_count_eq_zero {a : α} {xs : Vector α n} (h : count a xs = 0
theorem count_eq_zero {xs : Vector α n} : count a xs = 0 a xs :=
not_mem_of_count_eq_zero, count_eq_zero_of_not_mem
theorem count_eq_size {xs : Vector α n} : count a xs = xs.size b xs, a = b := by
theorem count_eq_size {xs : Vector α n} : count a xs = n b xs, a = b := by
rcases xs with xs, rfl
simp [Array.count_eq_size]

View File

@@ -58,7 +58,7 @@ theorem beq_eq_decide [BEq α] (xs ys : Vector α n) :
(mk xs ha == mk ys hb) = (xs == ys) := by
simp [BEq.beq]
@[simp] theorem beq_toArray [BEq α] (xs ys : Vector α n) : (xs.toArray == ys.toArray) = (xs == ys) := by
@[simp, grind =] theorem beq_toArray [BEq α] (xs ys : Vector α n) : (xs.toArray == ys.toArray) = (xs == ys) := by
simp [beq_eq_decide, Array.beq_eq_decide]
@[simp] theorem beq_toList [BEq α] (xs ys : Vector α n) : (xs.toList == ys.toList) = (xs == ys) := by

View File

@@ -88,7 +88,7 @@ theorem extract_set {xs : Vector α n} {i j k : Nat} (h : k < n) {a : α} :
(xs.set k a).extract i j =
if _ : k < i then
xs.extract i j
else if _ : k < min j xs.size then
else if _ : k < min j n then
(xs.extract i j).set (k - i) a (by omega)
else xs.extract i j := by
rcases xs with xs, rfl

View File

@@ -196,20 +196,6 @@ theorem get_find?_mem {xs : Vector α n} (h) : (xs.find? p).get h ∈ xs := by
cases xs
simp [Array.get_find?_mem]
@[simp] theorem find?_filter {xs : Vector α n} (p q : α Bool) :
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
cases xs; simp
@[simp] theorem getElem?_zero_filter {p : α Bool} {xs : Vector α n} :
(xs.filter p)[0]? = xs.find? p := by
cases xs; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem_zero_filter {p : α Bool} {xs : Vector α n} (h) :
(xs.filter p)[0] =
(xs.find? p).get (by cases xs; simpa [ Array.countP_eq_size_filter] using h) := by
cases xs
simp [List.getElem_zero_eq_head]
@[simp] theorem find?_map {f : β α} {xs : Vector β n} :
find? p (xs.map f) = (xs.find? (p f)).map f := by
cases xs; simp
@@ -323,7 +309,7 @@ theorem findFinIdx?_push {xs : Vector α n} {a : α} {p : α → Bool} :
theorem findFinIdx?_append {xs : Vector α n₁} {ys : Vector α n₂} {p : α Bool} :
(xs ++ ys).findFinIdx? p =
((xs.findFinIdx? p).map (Fin.castLE (by simp))).or
((ys.findFinIdx? p).map (Fin.natAdd xs.size) |>.map (Fin.cast (by simp))) := by
((ys.findFinIdx? p).map (Fin.natAdd n₁)) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
simp [Array.findFinIdx?_append, Option.map_or, Function.comp_def]

View File

@@ -104,7 +104,7 @@ theorem getElem?_insertIdx {xs : Vector α n} {x : α} {i k : Nat} (h : i ≤ n)
xs[k]?
else
if k = i then
if k xs.size then some x else none
if k n then some x else none
else
xs[k-1]? := by
rcases xs with xs, rfl

View File

@@ -63,9 +63,6 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
(Vector.mk xs h == Vector.mk ys h') = (xs == ys) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, h, h']
@[simp] theorem allDiff_mk [BEq α] {xs : Array α} (h : xs.size = n) :
(Vector.mk xs h).allDiff = xs.allDiff := rfl
@[simp] theorem mk_append_mk {xs ys : Array α} (h : xs.size = n) (h' : ys.size = m) :
Vector.mk xs h ++ Vector.mk ys h' = Vector.mk (xs ++ ys) (by simp [h, h']) := rfl
@@ -253,6 +250,9 @@ abbrev zipWithIndex_mk := @zipIdx_mk
@[simp] theorem replace_mk [BEq α] {xs : Array α} (h : xs.size = n) {a b} :
(Vector.mk xs h).replace a b = Vector.mk (xs.replace a b) (by simp [h]) := rfl
@[simp] theorem sum_mk [Add α] [Zero α] {xs : Array α} (h : xs.size = n) :
(Vector.mk xs h).sum = xs.sum := rfl
@[simp] theorem eq_mk : xs = Vector.mk as h xs.toArray = as := by
cases xs
simp
@@ -263,57 +263,59 @@ abbrev zipWithIndex_mk := @zipIdx_mk
/-! ### toArray lemmas -/
@[simp] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
@[simp, grind] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := by
cases xs
simp
@[simp] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
@[simp, grind] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
xs.toArray[i]? = xs[i]? := by
cases xs
simp
@[simp] theorem toArray_append {xs : Vector α m} {ys : Vector α n} :
@[simp, grind _=_] theorem toArray_append {xs : Vector α m} {ys : Vector α n} :
(xs ++ ys).toArray = xs.toArray ++ ys.toArray := rfl
@[simp] theorem toArray_drop {xs : Vector α n} {i} :
(xs.drop i).toArray = xs.toArray.extract i xs.size := rfl
set_option linter.indexVariables false in
@[simp, grind] theorem toArray_drop {xs : Vector α n} {i} :
(xs.drop i).toArray = xs.toArray.extract i n := by
simp [drop]
@[simp] theorem toArray_empty : (#v[] : Vector α 0).toArray = #[] := rfl
@[simp, grind] theorem toArray_empty : (#v[] : Vector α 0).toArray = #[] := rfl
@[simp] theorem toArray_emptyWithCapacity {cap} :
@[simp, grind] theorem toArray_emptyWithCapacity {cap} :
(Vector.emptyWithCapacity (α := α) cap).toArray = Array.emptyWithCapacity cap := rfl
@[deprecated toArray_emptyWithCapacity (since := "2025-03-12")]
abbrev toArray_mkEmpty := @toArray_emptyWithCapacity
@[simp] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
@[simp, grind] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
(xs.eraseIdx i h).toArray = xs.toArray.eraseIdx i (by simp [h]) := rfl
@[simp] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
@[simp, grind] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
(xs.eraseIdx! i).toArray = xs.toArray.eraseIdx! i := by
cases xs; simp_all [Array.eraseIdx!]
@[simp] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
@[simp, grind] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
(xs.insertIdx i x h).toArray = xs.toArray.insertIdx i x (by simp [h]) := rfl
@[simp] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i n) :
@[simp, grind] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i n) :
(xs.insertIdx! i x).toArray = xs.toArray.insertIdx! i x := by
cases xs; simp_all [Array.insertIdx!]
@[simp] theorem toArray_cast {xs : Vector α n} (h : n = m) :
@[simp, grind] theorem toArray_cast {xs : Vector α n} (h : n = m) :
(xs.cast h).toArray = xs.toArray := rfl
@[simp] theorem toArray_extract {xs : Vector α n} {start stop} :
@[simp, grind] theorem toArray_extract {xs : Vector α n} {start stop} :
(xs.extract start stop).toArray = xs.toArray.extract start stop := rfl
@[simp] theorem toArray_map {f : α β} {xs : Vector α n} :
@[simp, grind] theorem toArray_map {f : α β} {xs : Vector α n} :
(xs.map f).toArray = xs.toArray.map f := rfl
@[simp] theorem toArray_mapIdx {f : Nat α β} {xs : Vector α n} :
@[simp, grind] theorem toArray_mapIdx {f : Nat α β} {xs : Vector α n} :
(xs.mapIdx f).toArray = xs.toArray.mapIdx f := rfl
@[simp] theorem toArray_mapFinIdx {f : (i : Nat) α (h : i < n) β} {xs : Vector α n} :
@[simp, grind] theorem toArray_mapFinIdx {f : (i : Nat) α (h : i < n) β} {xs : Vector α n} :
(xs.mapFinIdx f).toArray =
xs.toArray.mapFinIdx (fun i a h => f i a (by simpa [xs.size_toArray] using h)) :=
rfl
@@ -331,145 +333,145 @@ theorem toArray_mapM_go [Monad m] [LawfulMonad m] {f : α → m β} {xs : Vector
rfl
· simp
@[simp] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α m β} {xs : Vector α n} :
@[simp, grind] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α m β} {xs : Vector α n} :
toArray <$> xs.mapM f = xs.toArray.mapM f := by
rcases xs with xs, rfl
unfold mapM
rw [toArray_mapM_go]
rfl
@[simp] theorem toArray_ofFn {f : Fin n α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
@[simp, grind] theorem toArray_ofFn {f : Fin n α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
@[simp] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
@[simp, grind] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
@[simp] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
@[simp, grind] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
@[simp] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
@[simp, grind] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
(xs.toArray == ys.toArray) = (xs == ys) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, xs.2, ys.2]
@[simp] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
@[simp, grind] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
@[simp] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
@[simp, grind] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
@[simp] theorem toArray_set {xs : Vector α n} {i x} (h) :
@[simp, grind] theorem toArray_set {xs : Vector α n} {i x} (h) :
(xs.set i x).toArray = xs.toArray.set i x (by simpa using h):= rfl
@[simp] theorem toArray_set! {xs : Vector α n} {i x} :
@[simp, grind] theorem toArray_set! {xs : Vector α n} {i x} :
(xs.set! i x).toArray = xs.toArray.set! i x := rfl
@[simp] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
@[simp, grind] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
(xs.setIfInBounds i x).toArray = xs.toArray.setIfInBounds i x := rfl
@[simp] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
@[simp, grind] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
@[simp] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
@[simp, grind] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
xs.toArray.swap i j (by simp [hi, hj]) (by simp [hi, hj]) := rfl
@[simp] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
@[simp, grind] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
(xs.swapIfInBounds i j).toArray = xs.toArray.swapIfInBounds i j := rfl
@[simp] theorem toArray_swapAt {xs : Vector α n} {i x} (h) :
theorem toArray_swapAt {xs : Vector α n} {i x} (h) :
((xs.swapAt i x).fst, (xs.swapAt i x).snd.toArray) =
((xs.toArray.swapAt i x (by simpa using h)).fst,
(xs.toArray.swapAt i x (by simpa using h)).snd) := rfl
@[simp] theorem toArray_swapAt! {xs : Vector α n} {i x} :
theorem toArray_swapAt! {xs : Vector α n} {i x} :
((xs.swapAt! i x).fst, (xs.swapAt! i x).snd.toArray) =
((xs.toArray.swapAt! i x).fst, (xs.toArray.swapAt! i x).snd) := rfl
@[simp] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
@[simp, grind] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
@[simp] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
@[simp, grind] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
(xs.zipIdx k).toArray = xs.toArray.zipIdx k := rfl
@[simp] theorem toArray_zipWith {f : α β γ} {as : Vector α n} {bs : Vector β n} :
@[simp, grind] theorem toArray_zipWith {f : α β γ} {as : Vector α n} {bs : Vector β n} :
(Vector.zipWith f as bs).toArray = Array.zipWith f as.toArray bs.toArray := rfl
@[simp] theorem anyM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem anyM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.anyM p = xs.anyM p := by
cases xs
simp
@[simp] theorem allM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem allM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.allM p = xs.allM p := by
cases xs
simp
@[simp] theorem any_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem any_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.any p = xs.any p := by
cases xs
simp
@[simp] theorem all_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem all_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.all p = xs.all p := by
cases xs
simp
@[simp] theorem countP_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem countP_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.countP p = xs.countP p := by
cases xs
simp
@[simp] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
@[simp, grind] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
xs.toArray.count a = xs.count a := by
cases xs
simp
@[simp] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
@[simp, grind] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
xs.toArray.replace a b = (xs.replace a b).toArray := rfl
@[simp] theorem find?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem find?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.find? p = xs.find? p := by
cases xs
simp
@[simp] theorem findSome?_toArray {f : α Option β} {xs : Vector α n} :
@[simp, grind] theorem findSome?_toArray {f : α Option β} {xs : Vector α n} :
xs.toArray.findSome? f = xs.findSome? f := by
cases xs
simp
@[simp] theorem findRev?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem findRev?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.findRev? p = xs.findRev? p := by
cases xs
simp
@[simp] theorem findSomeRev?_toArray {f : α Option β} {xs : Vector α n} :
@[simp, grind] theorem findSomeRev?_toArray {f : α Option β} {xs : Vector α n} :
xs.toArray.findSomeRev? f = xs.findSomeRev? f := by
cases xs
simp
@[simp] theorem findM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem findM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.findM? p = xs.findM? p := by
cases xs
simp
@[simp] theorem findSomeM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
@[simp, grind] theorem findSomeM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
xs.toArray.findSomeM? f = xs.findSomeM? f := by
cases xs
simp
@[simp] theorem findRevM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem findRevM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.findRevM? p = xs.findRevM? p := by
rcases xs with xs, rfl
simp
@[simp] theorem findSomeRevM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
@[simp, grind] theorem findSomeRevM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
xs.toArray.findSomeRevM? f = xs.findSomeRevM? f := by
rcases xs with xs, rfl
simp
@[simp] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
@[simp, grind] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
xs.toArray.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast xs.size_toArray.symm) := by
rcases xs with xs, rfl
simp
@[simp] theorem findFinIdx?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem findFinIdx?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast xs.size_toArray.symm) := by
rcases xs with xs, rfl
simp
@[simp] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
@[simp, grind] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
@[deprecated toArray_replicate (since := "2025-03-18")]
abbrev toArray_mkVector := @toArray_replicate
@@ -483,7 +485,7 @@ abbrev toArray_mkVector := @toArray_replicate
`Vector.ext` is an extensionality theorem.
Vectors `a` and `b` are equal to each other if their elements are equal for each valid index.
-/
@[ext, grind ext]
@[ext]
protected theorem ext {xs ys : Vector α n} (h : (i : Nat) (_ : i < n) xs[i] = ys[i]) : xs = ys := by
apply Vector.toArray_inj.1
apply Array.ext
@@ -498,7 +500,13 @@ protected theorem ext {xs ys : Vector α n} (h : (i : Nat) → (_ : i < n) → x
/-! ### toList -/
theorem toArray_toList {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl
@[simp, grind] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
rcases xs with xs, rfl
simp [toList]
@[grind =_] theorem toList_toArray {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl
@[simp, grind] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
@[simp] theorem getElem_toList {xs : Vector α n} {i : Nat} (h : i < xs.toList.length) :
xs.toList[i] = xs[i]'(by simpa using h) := by
@@ -511,11 +519,11 @@ theorem toArray_toList {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl
simp
theorem toList_append {xs : Vector α m} {ys : Vector α n} :
(xs ++ ys).toList = xs.toList ++ ys.toList := by simp
(xs ++ ys).toList = xs.toList ++ ys.toList := by simp [toList]
@[simp] theorem toList_drop {xs : Vector α n} {i} :
(xs.drop i).toList = xs.toList.drop i := by
simp [List.take_of_length_le]
simp [toList, List.take_of_length_le]
theorem toList_empty : (#v[] : Vector α 0).toList = [] := rfl
@@ -526,14 +534,14 @@ theorem toList_emptyWithCapacity {cap} :
abbrev toList_mkEmpty := @toList_emptyWithCapacity
theorem toList_eraseIdx {xs : Vector α n} {i} (h) :
(xs.eraseIdx i h).toList = xs.toList.eraseIdx i := by simp
(xs.eraseIdx i h).toList = xs.toList.eraseIdx i := by simp [toList]
@[simp] theorem toList_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
(xs.eraseIdx! i).toList = xs.toList.eraseIdx i := by
cases xs; simp_all [Array.eraseIdx!]
theorem toList_insertIdx {xs : Vector α n} {i x} (h) :
(xs.insertIdx i x h).toList = xs.toList.insertIdx i x := by simp
(xs.insertIdx i x h).toList = xs.toList.insertIdx i x := by simp [toList]
theorem toList_insertIdx! {xs : Vector α n} {i x} (hi : i n) :
(xs.insertIdx! i x).toList = xs.toList.insertIdx i x := by
@@ -544,39 +552,39 @@ theorem toList_cast {xs : Vector α n} (h : n = m) :
theorem toList_extract {xs : Vector α n} {start stop} :
(xs.extract start stop).toList = (xs.toList.drop start).take (stop - start) := by
simp
simp [toList]
theorem toList_map {f : α β} {xs : Vector α n} :
(xs.map f).toList = xs.toList.map f := by simp
(xs.map f).toList = xs.toList.map f := by simp [toList]
theorem toList_mapIdx {f : Nat α β} {xs : Vector α n} :
(xs.mapIdx f).toList = xs.toList.mapIdx f := by simp
(xs.mapIdx f).toList = xs.toList.mapIdx f := by simp [toList]
theorem toList_mapFinIdx {f : (i : Nat) α (h : i < n) β} {xs : Vector α n} :
(xs.mapFinIdx f).toList =
xs.toList.mapFinIdx (fun i a h => f i a (by simpa [xs.size_toArray] using h)) := by
simp
simp [toList]
theorem toList_ofFn {f : Fin n α} : (Vector.ofFn f).toList = List.ofFn f := by simp
theorem toList_ofFn {f : Fin n α} : (Vector.ofFn f).toList = List.ofFn f := by simp [toList]
theorem toList_pop {xs : Vector α n} : xs.pop.toList = xs.toList.dropLast := rfl
theorem toList_pop {xs : Vector α n} : xs.pop.toList = xs.toList.dropLast := by simp [toList]
theorem toList_push {xs : Vector α n} {x} : (xs.push x).toList = xs.toList ++ [x] := by simp
theorem toList_push {xs : Vector α n} {x} : (xs.push x).toList = xs.toList ++ [x] := by simp [toList]
@[simp] theorem toList_beq_toList [BEq α] {xs : Vector α n} {ys : Vector α n} :
(xs.toList == ys.toList) = (xs == ys) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, xs.2, ys.2]
simp [toList]
theorem toList_range : (Vector.range n).toList = List.range n := by simp
theorem toList_range : (Vector.range n).toList = List.range n := by simp [toList]
theorem toList_reverse {xs : Vector α n} : xs.reverse.toList = xs.toList.reverse := by simp
theorem toList_reverse {xs : Vector α n} : xs.reverse.toList = xs.toList.reverse := by simp [toList]
theorem toList_set {xs : Vector α n} {i x} (h) :
(xs.set i x).toList = xs.toList.set i x := rfl
@[simp] theorem toList_setIfInBounds {xs : Vector α n} {i x} :
(xs.setIfInBounds i x).toList = xs.toList.set i x := by
simp [Vector.setIfInBounds]
simp [toList, Vector.setIfInBounds]
theorem toList_singleton {x : α} : (Vector.singleton x).toList = [x] := rfl
@@ -584,7 +592,7 @@ theorem toList_swap {xs : Vector α n} {i j} (hi hj) :
(xs.swap i j).toList = (xs.toList.set i xs[j]).set j xs[i] := rfl
@[simp] theorem toList_take {xs : Vector α n} {i} : (xs.take i).toList = xs.toList.take i := by
simp [List.take_of_length_le]
simp [toList, List.take_of_length_le]
@[simp] theorem toList_zipWith {f : α β γ} {as : Vector α n} {bs : Vector β n} :
(Vector.zipWith f as bs).toList = List.zipWith f as.toList bs.toList := by
@@ -664,16 +672,14 @@ theorem toList_inj {xs ys : Vector α n} : xs.toList = ys.toList ↔ xs = ys :=
@[simp] theorem toList_eq_nil_iff {xs : Vector α n} : xs.toList = [] n = 0 := by
rcases xs with xs, h
simp only [Array.toList_eq_nil_iff]
simp only [toList, Array.toList_eq_nil_iff]
exact by rintro rfl; simp_all, by rintro rfl; simpa using h
@[deprecated toList_eq_nil_iff (since := "2025-04-04")]
abbrev toList_eq_empty_iff {α n} (xs) := @toList_eq_nil_iff α n xs
@[simp] theorem mem_toList_iff {a : α} {xs : Vector α n} : a xs.toList a xs := by
simp
theorem length_toList {α n} (xs : Vector α n) : xs.toList.length = n := by simp
simp [toList]
/-! ### empty -/
@@ -1320,7 +1326,7 @@ theorem getElem?_setIfInBounds_self {xs : Vector α n} {x : α} :
@[simp] theorem getElem?_setIfInBounds_ne {xs : Vector α n} {x : α} (h : i j) :
(xs.setIfInBounds i x)[j]? = xs[j]? := by simp [getElem?_setIfInBounds, h]
theorem setIfInBounds_eq_of_size_le {xs : Vector α n} {i : Nat} (h : xs.size i) {a : α} :
theorem setIfInBounds_eq_of_size_le {xs : Vector α n} {i : Nat} (h : n i) {a : α} :
xs.setIfInBounds i a = xs := by
rcases xs with xs, rfl
simp [Array.setIfInBounds_eq_of_size_le (by simpa using h)]
@@ -1864,7 +1870,7 @@ set_option linter.listVariables false in
induction l generalizing i with
| nil => simp at hi
| cons xs l ih =>
simp only [List.map_cons, List.map_map, List.flatten_cons]
simp only [List.map_cons, List.map_map, List.flatten_cons, toList_toArray]
by_cases h : i < m
· rw [List.getElem_append_left (by simpa)]
have h₁ : i / m = 0 := Nat.div_eq_of_lt h
@@ -1872,13 +1878,13 @@ set_option linter.listVariables false in
simp [h₁, h₂]
· have h₁ : xs.toList.length i := by simp; omega
rw [List.getElem_append_right h₁]
simp only [Array.length_toList, size_toArray]
simp only [length_toList]
specialize ih (i := i - m) (by simp_all [Nat.add_one_mul]; omega)
have h₂ : i / m = (i - m) / m + 1 := by
conv => lhs; rw [show i = i - m + m by omega]
rw [Nat.add_div_right]
exact Nat.pos_of_lt_mul_left hi
simp only [Array.length_toList, size_toArray] at h₁
simp only [length_toList] at h₁
have h₃ : (i - m) % m = i % m := (Nat.mod_eq_sub_mod h₁).symm
simp_all
@@ -2215,7 +2221,7 @@ theorem flatMap_replicate {f : α → Vector β m} : (replicate n a).flatMap f =
abbrev flatMap_mkVector := @flatMap_replicate
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
simp [toArray_replicate]
simp [sum, toArray_replicate]
@[deprecated sum_replicate_nat (since := "2025-03-18")]
abbrev sum_mkVector := @sum_replicate_nat
@@ -2233,10 +2239,6 @@ theorem reverse_empty : reverse (#v[] : Vector α 0) = #v[] := rfl
cases as
simp
@[simp] theorem isEmpty_reverse {xs : Vector α n} : xs.reverse.isEmpty = xs.isEmpty := by
rcases xs with xs, rfl
simp
@[simp, grind] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
(xs.reverse)[i] = xs[n - 1 - i] := by
rcases xs with xs, rfl
@@ -2448,14 +2450,16 @@ theorem foldr_map {f : α₁ → α₂} {g : α₂ → β → β} {xs : Vector
(xs.map f).foldr g init = xs.foldr (fun x y => g (f x) y) init := by
cases xs; simp [Array.foldr_map']
@[deprecated "Deprecated without replacement; `filterMap` is not part of the `Vector` API." (since := "2025-05-09")]
theorem foldl_filterMap {f : α Option β} {g : γ β γ} {xs : Vector α n} {init : γ} :
(xs.filterMap f).foldl g init = xs.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
(xs.toArray.filterMap f).foldl g init = xs.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
rcases xs with xs, rfl
simp [Array.foldl_filterMap']
rfl
@[deprecated "Deprecated without replacement; `filterMap` is not part of the `Vector` API." (since := "2025-05-09")]
theorem foldr_filterMap {f : α Option β} {g : β γ γ} {xs : Vector α n} {init : γ} :
(xs.filterMap f).foldr g init = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
(xs.toArray.filterMap f).foldr g init = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
cases xs; simp [Array.foldr_filterMap']
rfl
@@ -2555,12 +2559,12 @@ theorem foldr_rel {xs : Vector α n} {f g : α → β → β} {a b : β} {r : β
simpa using Array.foldr_rel h (by simpa using h')
@[simp] theorem foldl_add_const {xs : Vector α n} {a b : Nat} :
xs.foldl (fun x _ => x + a) b = b + a * xs.size := by
xs.foldl (fun x _ => x + a) b = b + a * n := by
rcases xs with xs, rfl
simp
@[simp] theorem foldr_add_const {xs : Vector α n} {a b : Nat} :
xs.foldr (fun _ x => x + a) b = b + a * xs.size := by
xs.foldr (fun _ x => x + a) b = b + a * n := by
rcases xs with xs, rfl
simp
@@ -2697,15 +2701,15 @@ theorem contains_map [BEq β] {xs : Vector α n} {x : β} {f : α → β} :
rcases xs with xs
simp
@[simp, grind]
@[deprecated "Deprecated without replacement; `filter` is not part of the `Vector` API." (since := "2025-05-09")]
theorem contains_filter [BEq α] {xs : Vector α n} {x : α} {p : α Bool} :
(xs.filter p).contains x = xs.any (fun a => x == a && p a) := by
(xs.toArray.filter p).contains x = xs.any (fun a => x == a && p a) := by
rcases xs with xs, rfl
simp
@[simp, grind]
@[deprecated "Deprecated without replacement; `filterMap` is not part of the `Vector` API." (since := "2025-05-09")]
theorem contains_filterMap [BEq β] {xs : Vector α n} {x : β} {f : α Option β} :
(xs.filterMap f).contains x = xs.any (fun a => (f a).any fun b => x == b) := by
(xs.toArray.filterMap f).contains x = xs.any (fun a => (f a).any fun b => x == b) := by
rcases xs with xs, rfl
simp
@@ -2835,24 +2839,28 @@ theorem any_eq_not_all_not {xs : Vector α n} {p : α → Bool} : xs.any p = !xs
rcases xs with xs, rfl
simp
@[simp] theorem any_filter {xs : Vector α n} {p q : α Bool} :
(xs.filter p).any q = xs.any fun a => p a && q a := by
@[deprecated "Deprecated without replacement; `filter` is not part of the `Vector` API." (since := "2025-05-09")]
theorem any_filter {xs : Vector α n} {p q : α Bool} :
(xs.toArray.filter p).any q = xs.any fun a => p a && q a := by
rcases xs with xs, rfl
simp
@[simp] theorem all_filter {xs : Vector α n} {p q : α Bool} :
(xs.filter p).all q = xs.all fun a => !(p a) || q a := by
@[deprecated "Deprecated without replacement; `filter` is not part of the `Vector` API." (since := "2025-05-09")]
theorem all_filter {xs : Vector α n} {p q : α Bool} :
(xs.toArray.filter p).all q = xs.all fun a => !(p a) || q a := by
rcases xs with xs, rfl
simp
@[simp] theorem any_filterMap {xs : Vector α n} {f : α Option β} {p : β Bool} :
(xs.filterMap f).any p = xs.any fun a => match f a with | some b => p b | none => false := by
@[deprecated "Deprecated without replacement; `filterMap` is not part of the `Vector` API." (since := "2025-05-09")]
theorem any_filterMap {xs : Vector α n} {f : α Option β} {p : β Bool} :
(xs.toArray.filterMap f).any p = xs.any fun a => match f a with | some b => p b | none => false := by
rcases xs with xs, rfl
simp
rfl
@[simp] theorem all_filterMap {xs : Vector α n} {f : α Option β} {p : β Bool} :
(xs.filterMap f).all p = xs.all fun a => match f a with | some b => p b | none => true := by
@[deprecated "Deprecated without replacement; `filterMap` is not part of the `Vector` API." (since := "2025-05-09")]
theorem all_filterMap {xs : Vector α n} {f : α Option β} {p : β Bool} :
(xs.toArray.filterMap f).all p = xs.all fun a => match f a with | some b => p b | none => true := by
rcases xs with xs, rfl
simp
rfl
@@ -3051,7 +3059,7 @@ set_option linter.indexVariables false in
ext i
by_cases h : i < n
· simp [h]
· replace h : i = xs.size - 1 := by rw [size_toArray]; omega
· replace h : i = n := by omega
subst h
simp [back]
@@ -3082,7 +3090,7 @@ set_option linter.indexVariables false in
/-! ### swap -/
theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
@[grind] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
cases xs
simp_all [Array.getElem_swap]
@@ -3099,6 +3107,13 @@ theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k <
(hi' : k i) (hj' : k j) : (xs.swap i j hi hj)[k] = xs[k] := by
simp_all [getElem_swap]
@[grind]
theorem getElem?_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
rcases xs with xs, rfl
simp [Array.getElem?_swap]
@[simp] theorem swap_swap {xs : Vector α n} {i j : Nat} (hi hj) :
(xs.swap i j hi hj).swap i j hi hj = xs := by
cases xs
@@ -3112,14 +3127,14 @@ theorem swap_comm {xs : Vector α n} {i j : Nat} (hi hj) :
/-! ### take -/
@[simp] theorem getElem_take {xs : Vector α n} {j : Nat} (hi : i < min j n) :
@[simp, grind =] theorem getElem_take {xs : Vector α n} {j : Nat} (hi : i < min j n) :
(xs.take j)[i] = xs[i] := by
cases xs
simp
/-! ### drop -/
@[simp] theorem getElem_drop {xs : Vector α n} {j : Nat} (hi : i < n - j) :
@[simp, grind =] theorem getElem_drop {xs : Vector α n} {j : Nat} (hi : i < n - j) :
(xs.drop j)[i] = xs[j + i] := by
cases xs
simp

View File

@@ -18,8 +18,8 @@ namespace Vector
/-! ### Lexicographic ordering -/
@[simp] theorem lt_toArray [LT α] {xs ys : Vector α n} : xs.toArray < ys.toArray xs < ys := Iff.rfl
@[simp] theorem le_toArray [LT α] {xs ys : Vector α n} : xs.toArray ys.toArray xs ys := Iff.rfl
@[simp, grind =] theorem lt_toArray [LT α] {xs ys : Vector α n} : xs.toArray < ys.toArray xs < ys := Iff.rfl
@[simp, grind =] theorem le_toArray [LT α] {xs ys : Vector α n} : xs.toArray ys.toArray xs ys := Iff.rfl
@[simp] theorem lt_toList [LT α] {xs ys : Vector α n} : xs.toList < ys.toList xs < ys := Iff.rfl
@[simp] theorem le_toList [LT α] {xs ys : Vector α n} : xs.toList ys.toList xs ys := Iff.rfl
@@ -40,7 +40,7 @@ protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {xs ys
simp [Vector.lex, Array.lex, n₁, n₂]
rfl
@[simp] theorem lex_toArray [BEq α] {lt : α α Bool} {xs ys : Vector α n} :
@[simp, grind =] theorem lex_toArray [BEq α] {lt : α α Bool} {xs ys : Vector α n} :
xs.toArray.lex ys.toArray lt = xs.lex ys lt := by
cases xs
cases ys

View File

@@ -134,7 +134,7 @@ theorem mapFinIdx_append {xs : Vector α n} {ys : Vector α m} {f : (i : Nat)
@[simp]
theorem mapFinIdx_push {xs : Vector α n} {a : α} {f : (i : Nat) α (h : i < n + 1) β} :
mapFinIdx (xs.push a) f =
(mapFinIdx xs (fun i a h => f i a (by omega))).push (f xs.size a (by simp)) := by
(mapFinIdx xs (fun i a h => f i a (by omega))).push (f n a (by simp)) := by
simp [ append_singleton, mapFinIdx_append]
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) α (h : i < 1) β} :
@@ -255,14 +255,14 @@ theorem mapIdx_eq_zipIdx_map {xs : Vector α n} {f : Nat → α → β} :
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
theorem mapIdx_append {xs : Vector α n} {ys : Vector α m} :
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx fun i => f (i + xs.size) := by
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx fun i => f (i + n) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
simp [Array.mapIdx_append]
@[simp]
theorem mapIdx_push {xs : Vector α n} {a : α} :
mapIdx f (xs.push a) = (mapIdx f xs).push (f xs.size a) := by
mapIdx f (xs.push a) = (mapIdx f xs).push (f n a) := by
simp [ append_singleton, mapIdx_append]
theorem mapIdx_singleton {a : α} : mapIdx f #v[a] = #v[f 0 a] := by
@@ -284,7 +284,7 @@ theorem exists_of_mem_mapIdx {b : β} {xs : Vector α n}
theorem mapIdx_eq_push_iff {xs : Vector α (n + 1)} {b : β} :
mapIdx f xs = ys.push b
(a : α) (zs : Vector α n), xs = zs.push a mapIdx f zs = ys f zs.size a = b := by
(a : α) (zs : Vector α n), xs = zs.push a mapIdx f zs = ys f n a = b := by
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_push_iff]
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
constructor
@@ -302,7 +302,7 @@ theorem mapIdx_eq_append_iff {xs : Vector α (n + m)} {f : Nat → α → β} {y
mapIdx f xs = ys ++ zs
(ys' : Vector α n) (zs' : Vector α m), xs = ys' ++ zs'
ys'.mapIdx f = ys
zs'.mapIdx (fun i => f (i + ys'.size)) = zs := by
zs'.mapIdx (fun i => f (i + n)) = zs := by
rcases xs with xs, h
rcases ys with ys, rfl
rcases zs with zs, rfl
@@ -342,12 +342,12 @@ theorem mapIdx_eq_mapIdx_iff {xs : Vector α n} :
simp
@[simp] theorem back?_mapIdx {xs : Vector α n} {f : Nat α β} :
(mapIdx f xs).back? = (xs.back?).map (f (xs.size - 1)) := by
(mapIdx f xs).back? = (xs.back?).map (f (n - 1)) := by
rcases xs with xs, rfl
simp
@[simp] theorem back_mapIdx [NeZero n] {xs : Vector α n} {f : Nat α β} :
(mapIdx f xs).back = f (xs.size - 1) (xs.back) := by
(mapIdx f xs).back = f (n - 1) (xs.back) := by
rcases xs with xs, rfl
simp
@@ -364,7 +364,7 @@ theorem mapIdx_eq_replicate_iff {xs : Vector α n} {f : Nat → α → β} {b :
abbrev mapIdx_eq_mkVector_iff := @mapIdx_eq_replicate_iff
@[simp] theorem mapIdx_reverse {xs : Vector α n} {f : Nat α β} :
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
xs.reverse.mapIdx f = (mapIdx (fun i => f (n - 1 - i)) xs).reverse := by
rcases xs with xs, rfl
simp [Array.mapIdx_reverse]

View File

@@ -70,32 +70,6 @@ theorem foldrM_map [Monad m] [LawfulMonad m] {f : β₁ → β₂} {g : β₂
rcases xs with xs, rfl
simp [Array.foldrM_map]
theorem foldlM_filterMap [Monad m] [LawfulMonad m] {f : α Option β} {g : γ β m γ} {xs : Vector α n} {init : γ} :
(xs.filterMap f).foldlM g init =
xs.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
rcases xs with xs, rfl
simp [Array.foldlM_filterMap]
rfl
theorem foldrM_filterMap [Monad m] [LawfulMonad m] {f : α Option β} {g : β γ m γ} {xs : Vector α n} {init : γ} :
(xs.filterMap f).foldrM g init =
xs.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
rcases xs with xs, rfl
simp [Array.foldrM_filterMap]
rfl
theorem foldlM_filter [Monad m] [LawfulMonad m] {p : α Bool} {g : β α m β} {xs : Vector α n} {init : β} :
(xs.filter p).foldlM g init =
xs.foldlM (fun x y => if p y then g x y else pure x) init := by
rcases xs with xs, rfl
simp [Array.foldlM_filter]
theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α Bool} {g : α β m β} {xs : Vector α n} {init : β} :
(xs.filter p).foldrM g init =
xs.foldrM (fun x y => if p x then g x y else pure y) init := by
rcases xs with xs, rfl
simp [Array.foldrM_filter]
@[simp] theorem foldlM_attachWith [Monad m]
{xs : Vector α n} {q : α Prop} (H : a, a xs q a) {f : β { x // q x} m β} {b} :
(xs.attachWith q H).foldlM f b = xs.attach.foldlM (fun b a, h => f b a, H _ h) b := by

View File

@@ -140,7 +140,7 @@ theorem range_add {n m : Nat} : range (n + m) = range n ++ (range m).map (n + ·
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 (s := 0)).symm
theorem reverse_range' {s n : Nat} : reverse (range' s n) = map (s + n - 1 - ·) (range n) := by
simp [ toList_inj, List.reverse_range']
simp [ toArray_inj, Array.reverse_range']
@[simp]
theorem mem_range {m n : Nat} : m range n m < n := by

View File

@@ -243,7 +243,7 @@ theorem map_prod_right_eq_zip {xs : Vector α n} {f : α → β} :
theorem zip_eq_append_iff {as : Vector α (n + m)} {bs : Vector β (n + m)} {xs : Vector (α × β) n} {ys : Vector (α × β) m} :
zip as bs = xs ++ ys
as₁ as₂ bs₁ bs₂, as.size = bs₁.size as = as₁ ++ as₂ bs = bs₁ ++ bs₂ xs = zip as₁ bs₁ ys = zip as₂ bs₂ := by
as₁ as₂ bs₁ bs₂, as = as₁ ++ as₂ bs = bs₁ ++ bs₂ xs = zip as₁ bs₁ ys = zip as₂ bs₂ := by
simp [zip_eq_zipWith, zipWith_eq_append_iff]
@[simp] theorem zip_replicate {a : α} {b : β} {n : Nat} :

View File

@@ -27,3 +27,23 @@ instance (priority := 300) One.toOfNat1 {α} [One α] : OfNat α (nat_lit 1) whe
instance (priority := 200) One.ofOfNat1 {α} [OfNat α (nat_lit 1)] : One α where
one := 1
/--
The fundamental power operation in a monoid.
`npowRec n a = a*a*...*a` n times.
This function should not be used directly; it is often used to implement a `Pow M Nat` instance,
but end users should use the `a ^ n` notation instead.
-/
def npowRec [One M] [Mul M] : Nat M M
| 0, _ => 1
| n + 1, a => npowRec n a * a
/--
The fundamental scalar multiplication in an additive monoid.
`nsmulRec n a = a+a+...+a` n times.
This function should not be used directly;
it is often used to implement an instance for scalar multiplication.
-/
def nsmulRec [Zero M] [Add M] : Nat M M
| 0, _ => 0
| n + 1, a => nsmulRec n a + a

View File

@@ -81,7 +81,6 @@ end Lean
attribute [ext] Prod PProd Sigma PSigma
attribute [ext] funext propext Subtype.eq Array.ext
attribute [grind ext] Array.ext
@[ext] protected theorem PUnit.ext (x y : PUnit) : x = y := rfl
protected theorem Unit.ext (x y : Unit) : x = y := rfl

View File

@@ -10,5 +10,6 @@ import Init.Grind.CommRing.Basic
import Init.Grind.CommRing.Int
import Init.Grind.CommRing.UInt
import Init.Grind.CommRing.SInt
import Init.Grind.CommRing.Fin
import Init.Grind.CommRing.BitVec
import Init.Grind.CommRing.Poly

View File

@@ -0,0 +1,110 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module
prelude
import Init.Grind.CommRing.Basic
import Init.Data.Fin.Lemmas
namespace Lean.Grind
namespace Fin
instance (n : Nat) [NeZero n] : NatCast (Fin n) where
natCast a := Fin.ofNat' n a
def intCast [NeZero n] (a : Int) : Fin n :=
if 0 a then
Fin.ofNat' n a.natAbs
else
- Fin.ofNat' n a.natAbs
instance (n : Nat) [NeZero n] : IntCast (Fin n) where
intCast := Fin.intCast
theorem intCast_def {n : Nat} [NeZero n] (x : Int) :
(x : Fin n) = if 0 x then Fin.ofNat' n x.natAbs else -Fin.ofNat' n x.natAbs := rfl
-- TODO: we should replace this at runtime with either repeated squaring,
-- or a GMP accelerated function.
def npow [NeZero n] (x : Fin n) (y : Nat) : Fin n := npowRec y x
instance [NeZero n] : HPow (Fin n) Nat (Fin n) where
hPow := Fin.npow
@[simp] theorem pow_zero [NeZero n] (a : Fin n) : a ^ 0 = 1 := rfl
@[simp] theorem pow_succ [NeZero n] (a : Fin n) (n : Nat) : a ^ (n+1) = a ^ n * a := rfl
theorem add_assoc (a b c : Fin n) : a + b + c = a + (b + c) := by
cases a; cases b; cases c; simp [Fin.add_def, Nat.add_assoc]
theorem add_comm (a b : Fin n) : a + b = b + a := by
cases a; cases b; simp [Fin.add_def, Nat.add_comm]
theorem add_zero [NeZero n] (a : Fin n) : a + 0 = a := by
cases a; simp [Fin.add_def]
next h => rw [Nat.mod_eq_of_lt h]
theorem neg_add_cancel [NeZero n] (a : Fin n) : -a + a = 0 := by
cases a; simp [Fin.add_def, Fin.neg_def, Fin.sub_def]
next h => rw [Nat.sub_add_cancel (Nat.le_of_lt h), Nat.mod_self]
theorem mul_assoc (a b c : Fin n) : a * b * c = a * (b * c) := by
cases a; cases b; cases c; simp [Fin.mul_def, Nat.mul_assoc]
theorem mul_comm (a b : Fin n) : a * b = b * a := by
cases a; cases b; simp [Fin.mul_def, Nat.mul_comm]
theorem zero_mul [NeZero n] (a : Fin n) : 0 * a = 0 := by
cases a; simp [Fin.mul_def]
theorem mul_one [NeZero n] (a : Fin n) : a * 1 = a := by
cases a; simp [Fin.mul_def, OfNat.ofNat]
next h => rw [Nat.mod_eq_of_lt h]
theorem left_distrib (a b c : Fin n) : a * (b + c) = a * b + a * c := by
cases a; cases b; cases c; simp [Fin.mul_def, Fin.add_def, Nat.left_distrib]
theorem ofNat_succ [NeZero n] (a : Nat) : OfNat.ofNat (α := Fin n) (a+1) = OfNat.ofNat a + 1 := by
simp [OfNat.ofNat, Fin.add_def, Fin.ofNat']
theorem sub_eq_add_neg [NeZero n] (a b : Fin n) : a - b = a + -b := by
cases a; cases b; simp [Fin.neg_def, Fin.sub_def, Fin.add_def, Nat.add_comm]
private theorem neg_neg [NeZero n] (a : Fin n) : - - a = a := by
cases a; simp [Fin.neg_def, Fin.sub_def];
next a h => cases a; simp; next a =>
rw [Nat.self_sub_mod n (a+1)]
have : NeZero (n - (a + 1)) := by omega
rw [Nat.self_sub_mod, Nat.sub_sub_eq_min, Nat.min_eq_right (Nat.le_of_lt h)]
theorem intCast_neg [NeZero n] (i : Int) : Int.cast (R := Fin n) (-i) = - Int.cast (R := Fin n) i := by
simp [Int.cast, IntCast.intCast, Fin.intCast]; split <;> split <;> try omega
next h₁ h₂ => simp [Int.le_antisymm h₁ h₂, Fin.neg_def]
next => simp [Fin.neg_neg]
instance (n : Nat) [NeZero n] : CommRing (Fin n) where
add_assoc := Fin.add_assoc
add_comm := Fin.add_comm
add_zero := Fin.add_zero
neg_add_cancel := Fin.neg_add_cancel
mul_assoc := Fin.mul_assoc
mul_comm := Fin.mul_comm
mul_one := Fin.mul_one
left_distrib := Fin.left_distrib
zero_mul := Fin.zero_mul
pow_zero _ := rfl
pow_succ _ _ := rfl
ofNat_succ := Fin.ofNat_succ
sub_eq_add_neg := Fin.sub_eq_add_neg
intCast_neg := Fin.intCast_neg
instance (n : Nat) [NeZero n] : IsCharP (Fin n) n where
ofNat_eq_zero_iff x := by simp only [OfNat.ofNat, Fin.ofNat']; simp
end Fin
end Lean.Grind

View File

@@ -584,12 +584,14 @@ theorem Mon.eq_of_revlexWF {m₁ m₂ : Mon} : m₁.revlexWF m₂ = .eq → m₁
simp [h, eq_of_powerRevlex h₂]
theorem Mon.eq_of_revlexFuel {fuel : Nat} {m₁ m₂ : Mon} : revlexFuel fuel m₁ m₂ = .eq m₁ = m₂ := by
fun_induction revlexFuel <;> simp [revlexFuel, *, then_gt, then_lt, then_eq]
next => apply eq_of_revlexWF
next p₁ m₁ p₂ m₂ h ih =>
fun_induction revlexFuel
case case1 => apply eq_of_revlexWF
case case5 p₁ m₁ p₂ m₂ h ih =>
simp [then_eq]
cases p₁; cases p₂; intro h₁ h₂; simp [ih h₁, h]
simp at h h₂
simp [h, eq_of_powerRevlex h₂]
all_goals simp [then_eq]
theorem Mon.eq_of_revlex {m₁ m₂ : Mon} : revlex m₁ m₂ = .eq m₁ = m₂ := by
apply eq_of_revlexFuel
@@ -665,11 +667,11 @@ theorem Poly.denote_combine {α} [CommRing α] (ctx : Context α) (p₁ p₂ : P
unfold combine; generalize hugeFuel = fuel
fun_induction combine.go
<;> simp [combine.go, *, denote_concat, denote_addConst, denote, intCast_add, cond_eq_if, add_comm, add_left_comm, add_assoc]
next hg _ h _ =>
simp +zetaDelta at h; simp [*]
case case5 hg _ h _ =>
simp +zetaDelta at h
rw [ add_assoc, Mon.eq_of_grevlex hg, right_distrib, intCast_add, h, intCast_zero, zero_mul, zero_add]
next hg _ h _ =>
simp +zetaDelta at h; simp [*, denote, intCast_add]
case case6 hg k h _ =>
simp +zetaDelta [k, intCast_add]
rw [right_distrib, Mon.eq_of_grevlex hg, add_assoc]
theorem Poly.denote_mul_go {α} [CommRing α] (ctx : Context α) (p₁ p₂ acc : Poly)
@@ -683,7 +685,8 @@ theorem Poly.denote_mul {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
theorem Poly.denote_pow {α} [CommRing α] (ctx : Context α) (p : Poly) (k : Nat)
: (pow p k).denote ctx = p.denote ctx ^ k := by
fun_induction pow <;> simp [pow, denote, intCast_one, pow_zero]
fun_induction pow
next => simp [denote, intCast_one, pow_zero]
next => simp [pow_succ, pow_zero, one_mul]
next => simp [denote_mul, *, pow_succ, mul_comm]
@@ -810,12 +813,11 @@ theorem Poly.denote_mulConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context
fun_induction mulConstC.go <;> simp [mulConstC.go, denote, IsCharP.intCast_emod, cond_eq_if, *]
next => rw [intCast_mul]
next h _ =>
simp +zetaDelta at h; simp [*]
simp +zetaDelta at h
rw [left_distrib, mul_assoc, intCast_mul, IsCharP.intCast_emod (x := k * _) (p := c),
h, intCast_zero, zero_mul, zero_add]
next h _ =>
simp +zetaDelta at h
simp [*, denote, IsCharP.intCast_emod, intCast_mul, mul_assoc, left_distrib]
simp +zetaDelta [IsCharP.intCast_emod, intCast_mul, mul_assoc, left_distrib]
theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
: (mulMonC k m p c).denote ctx = k * m.denote ctx * p.denote ctx := by
@@ -828,14 +830,13 @@ theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context
next h =>
simp at h; simp [*, Mon.denote, mul_one, denote_mulConstC, IsCharP.intCast_emod]
next =>
fun_induction mulMonC.go <;> simp [mulMonC.go, denote, *, cond_eq_if]
fun_induction mulMonC.go <;> simp [denote, cond_eq_if]
next h =>
simp +zetaDelta at h; simp [*, denote]
simp +zetaDelta at h
rw [mul_assoc, mul_left_comm, intCast_mul, IsCharP.intCast_emod (x := k * _) (p := c), h]
simp [intCast_zero, mul_zero]
next h =>
simp +zetaDelta at h; simp [*, denote, IsCharP.intCast_emod]
simp [intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
simp +zetaDelta [IsCharP.intCast_emod, intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
next h _ =>
simp +zetaDelta at h; simp [*, denote, left_distrib]
rw [mul_left_comm]
@@ -843,8 +844,7 @@ theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context
rw [Int.mul_comm] at h
simp [h, intCast_zero, zero_mul, zero_add]
next h _ =>
simp +zetaDelta at h
simp [*, denote, IsCharP.intCast_emod, Mon.denote_mul, intCast_mul, left_distrib,
simp +zetaDelta [*, denote, IsCharP.intCast_emod, Mon.denote_mul, intCast_mul, left_distrib,
mul_comm, mul_left_comm, mul_assoc]
theorem Poly.denote_combineC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
@@ -854,12 +854,12 @@ theorem Poly.denote_combineC {α c} [CommRing α] [IsCharP α c] (ctx : Context
<;> simp [combineC.go, *, denote_concat, denote_addConstC, denote, intCast_add,
cond_eq_if, add_comm, add_left_comm, add_assoc, IsCharP.intCast_emod]
next hg _ h _ =>
simp +zetaDelta at h; simp [*]
simp +zetaDelta at h
rw [ add_assoc, Mon.eq_of_grevlex hg, right_distrib, intCast_add,
IsCharP.intCast_emod (p := c),
h, intCast_zero, zero_mul, zero_add]
next hg _ h _ =>
simp +zetaDelta at h; simp [*, denote, intCast_add, IsCharP.intCast_emod]
simp +zetaDelta only [IsCharP.intCast_emod, intCast_add]
rw [right_distrib, Mon.eq_of_grevlex hg, add_assoc]
theorem Poly.denote_mulC_go {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ acc : Poly)
@@ -873,7 +873,8 @@ theorem Poly.denote_mulC {α c} [CommRing α] [IsCharP α c] (ctx : Context α)
theorem Poly.denote_powC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Nat)
: (powC p k c).denote ctx = p.denote ctx ^ k := by
fun_induction powC <;> simp [powC, denote, intCast_one, pow_zero]
fun_induction powC
next => simp [denote, intCast_one, pow_zero]
next => simp [pow_succ, pow_zero, one_mul]
next => simp [denote_mulC, *, pow_succ, mul_comm]

View File

@@ -76,6 +76,12 @@ structure Config where
/-- If `extAll` is `true`, `grind` uses any extensionality theorems available in the environment. -/
extAll : Bool := false
/--
If `etaStruct` is `true`, then for each term `t : S` such that `S` is a structure,
and is tagged with `[grind ext]`, `grind` adds the equation `t = ⟨t.1, ..., t.n⟩`
which holds by reflexivity. Moreover, the extensionality theorem for `S` is not used.
-/
etaStruct : Bool := true
/--
If `funext` is `true`, `grind` creates new opportunities for applying function extensionality by case-splitting
on equalities between lambda expressions.
-/

View File

@@ -621,9 +621,6 @@ This is the same as `#eval show MetaM Unit from do discard doSeq`.
-/
syntax (name := runMeta) "run_meta " doSeq : command
set_option linter.missingDocs false in
syntax guardMsgsFilterSeverity := &"info" <|> &"warning" <|> &"error" <|> &"all"
/--
`#reduce <expression>` reduces the expression `<expression>` to its normal form. This
involves applying reduction rules until no further reduction is possible.
@@ -640,15 +637,27 @@ of expressions.
-/
syntax (name := reduceCmd) "#reduce " (atomic("(" &"proofs" " := " &"true" ")"))? (atomic("(" &"types" " := " &"true" ")"))? term : command
set_option linter.missingDocs false in
syntax guardMsgsFilterAction := &"check" <|> &"drop" <|> &"pass"
set_option linter.missingDocs false in
syntax guardMsgsFilterSeverity := &"trace" <|> &"info" <|> &"warning" <|> &"error" <|> &"all"
/--
A message filter specification for `#guard_msgs`.
- `info`, `warning`, `error`: capture messages with the given severity level.
- `all`: capture all messages (the default).
- `drop info`, `drop warning`, `drop error`: drop messages with the given severity level.
- `drop all`: drop every message.
These filters are processed in left-to-right order.
- `info`, `warning`, `error`: capture (non-trace) messages with the given severity level.
- `trace`: captures trace messages
- `all`: capture all messages.
The filters can be prefixed with
- `check` (the default): capture and check the message
- `drop`: drop the message
- `pass`: let the message pass through
If no filter is specified, `check all` is assumed. Otherwise, these filters are processed in
left-to-right order, with an implicit `pass all` at the end.
-/
syntax guardMsgsFilter := &"drop"? guardMsgsFilterSeverity
syntax guardMsgsFilter := guardMsgsFilterAction ? guardMsgsFilterSeverity
set_option linter.missingDocs false in
syntax guardMsgsWhitespaceArg := &"exact" <|> &"normalized" <|> &"lax"
@@ -719,13 +728,20 @@ In general, `#guard_msgs` accepts a comma-separated list of configuration clause
```
#guard_msgs (configElt,*) in cmd
```
By default, the configuration list is `(all, whitespace := normalized, ordering := exact)`.
By default, the configuration list is `(check all, whitespace := normalized, ordering := exact)`.
Message filters (processed in left-to-right order):
- `info`, `warning`, `error`: capture messages with the given severity level.
- `all`: capture all messages (the default).
- `drop info`, `drop warning`, `drop error`: drop messages with the given severity level.
- `drop all`: drop every message.
Message filters select messages by severity:
- `info`, `warning`, `error`: (non-trace) messages with the given severity level.
- `trace`: trace messages
- `all`: all messages.
The filters can be prefixed with the action to take:
- `check` (the default): capture and check the message
- `drop`: drop the message
- `pass`: let the message pass through
If no filter is specified, `check all` is assumed. Otherwise, these filters are processed in
left-to-right order, with an implicit `pass all` at the end.
Whitespace handling (after trimming leading and trailing whitespace):
- `whitespace := exact` requires an exact whitespace match.

View File

@@ -121,7 +121,7 @@ theorem ofNat_natAbs (a : Int) : (a.natAbs : Int) = if 0 ≤ a then a else -a :=
rw [Int.natAbs.eq_def]
split <;> rename_i n
· simp only [Int.ofNat_eq_coe]
rw [if_pos (Int.ofNat_nonneg n)]
rw [if_pos (Int.natCast_nonneg n)]
· simp; rfl
theorem natAbs_dichotomy {a : Int} : 0 a a.natAbs = a a < 0 a.natAbs = -a := by

View File

@@ -10,6 +10,7 @@ import Init.System.IOError
import Init.System.FilePath
import Init.System.ST
import Init.Data.Ord
import Init.Data.String.Extra
open System

View File

@@ -940,8 +940,8 @@ You can use `with` to provide the variables names for each constructor.
syntax (name := cases) "cases " elimTarget,+ (" using " term)? (inductionAlts)? : tactic
/--
The `fun_induction` tactic is a convenience wrapper of the `induction` tactic when using a functional
induction principle.
The `fun_induction` tactic is a convenience wrapper around the `induction` tactic to use the the
functional induction principle.
The tactic invocation
```
@@ -949,10 +949,10 @@ fun_induction f x₁ ... xₙ y₁ ... yₘ
```
where `f` is a function defined by non-mutual structural or well-founded recursion, is equivalent to
```
induction y₁, ... yₘ using f.induct x₁ ... xₙ
induction y₁, ... yₘ using f.induct_unfolding x₁ ... xₙ
```
where the arguments of `f` are used as arguments to `f.induct` or targets of the induction, as
appropriate.
where the arguments of `f` are used as arguments to `f.induct_unfolding` or targets of the
induction, as appropriate.
The form
```
@@ -964,6 +964,10 @@ become targets are free variables.
The forms `fun_induction f x y generalizing z₁ ... zₙ` and
`fun_induction f x y with | case1 => tac₁ | case2 x' ih => tac₂` work like with `induction.`
Under `set_option tactic.fun_induction.unfolding true` (the default), `fun_induction` uses the
`f.induct_unfolding` induction principle, which will try to automatically unfold the call to `f` in
the goal. With `set_option tactic.fun_induction.unfolding false`, it uses `f.induct` instead.
-/
syntax (name := funInduction) "fun_induction " term
(" generalizing" (ppSpace colGt term:max)+)? (inductionAlts)? : tactic
@@ -978,10 +982,10 @@ fun_cases f x ... y ...`
```
is equivalent to
```
cases y, ... using f.fun_cases x ...
cases y, ... using f.fun_cases_unfolding x ...
```
where the arguments of `f` are used as arguments to `f.fun_cases` or targets of the case analysis, as
appropriate.
where the arguments of `f` are used as arguments to `f.fun_cases_unfolding` or targets of the case
analysis, as appropriate.
The form
```
@@ -992,6 +996,10 @@ these arguments. An application of `f` is eligible if it is saturated and the ar
become targets are free variables.
The form `fun_cases f x y with | case1 => tac₁ | case2 x' ih => tac₂` works like with `cases`.
Under `set_option tactic.fun_induction.unfolding true` (the default), `fun_induction` uses the
`f.fun_cases_unfolding` theorem, which will try to automatically unfold the call to `f` in
the goal. With `set_option tactic.fun_induction.unfolding false`, it uses `f.fun_cases` instead.
-/
syntax (name := funCases) "fun_cases " term (inductionAlts)? : tactic

View File

@@ -93,9 +93,13 @@ def addDecl (decl : Declaration) : CoreM Unit := do
let mut exportedKind? := none
let (name, info, kind) match decl with
| .thmDecl thm =>
if ( getEnv).header.isModule && !isSimpleRflProof thm.value &&
-- TODO: this is horrible...
!looksLikeRelevantTheoremProofType thm.type then
let exportProof := !( getEnv).header.isModule ||
-- We should preserve rfl theorems but also we should not override a decision to hide by the
-- MutualDef elaborator via `withoutExporting`
( getEnv).isExporting && isSimpleRflProof thm.value ||
-- TODO: this is horrible...
looksLikeRelevantTheoremProofType thm.type
if !exportProof then
exportedInfo? := some <| .axiomInfo { thm with isUnsafe := false }
exportedKind? := some .axiom
pure (thm.name, .thmInfo thm, .thm)

View File

@@ -22,6 +22,7 @@ import Lean.Compiler.IR.ElimDeadBranches
import Lean.Compiler.IR.EmitC
import Lean.Compiler.IR.CtorLayout
import Lean.Compiler.IR.Sorry
import Lean.Compiler.IR.ToIR
-- The following imports are not required by the compiler. They are here to ensure that there
-- are no orphaned modules.

View File

@@ -0,0 +1,412 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Cameron Zwarich
-/
prelude
import Lean.Compiler.LCNF.Basic
import Lean.Compiler.LCNF.CompilerM
import Lean.Compiler.LCNF.PhaseExt
import Lean.Compiler.IR.Basic
import Lean.Compiler.IR.CompilerM
import Lean.Compiler.IR.CtorLayout
import Lean.CoreM
import Lean.Environment
namespace Lean.IR
open Lean.Compiler (LCNF.AltCore LCNF.Arg LCNF.Code LCNF.Decl LCNF.DeclValue LCNF.LCtx LCNF.LetDecl
LCNF.LetValue LCNF.LitValue LCNF.Param LCNF.getMonoDecl?)
namespace ToIR
inductive FVarClassification where
| var (id : VarId)
| joinPoint (id : JoinPointId)
| erased
structure BuilderState where
fvars : Std.HashMap FVarId FVarClassification := {}
nextId : Nat := 1
abbrev M := StateRefT BuilderState CoreM
def M.run (x : M α) : CoreM α := do
x.run' {}
def bindVar (fvarId : FVarId) : M VarId := do
modifyGet fun s =>
let varId := { idx := s.nextId }
varId, { s with fvars := s.fvars.insertIfNew fvarId (.var varId),
nextId := s.nextId + 1 }
def bindVarToVarId (fvarId : FVarId) (varId : VarId) : M Unit := do
modify fun s => { s with fvars := s.fvars.insertIfNew fvarId (.var varId) }
def newVar : M VarId := do
modifyGet fun s =>
let varId := { idx := s.nextId }
varId, { s with nextId := s.nextId + 1 }
def bindJoinPoint (fvarId : FVarId) : M JoinPointId := do
modifyGet fun s =>
let joinPointId := { idx := s.nextId }
joinPointId, { s with fvars := s.fvars.insertIfNew fvarId (.joinPoint joinPointId),
nextId := s.nextId + 1 }
def bindErased (fvarId : FVarId) : M Unit := do
modify fun s => { s with fvars := s.fvars.insertIfNew fvarId .erased }
def findDecl (n : Name) : M (Option Decl) :=
return findEnvDecl ( Lean.getEnv) n
def addDecl (d : Decl) : M Unit :=
Lean.modifyEnv fun env => declMapExt.addEntry (env.addExtraName d.name) d
def lowerLitValue (v : LCNF.LitValue) : LitVal :=
match v with
| .natVal n => .num n
| .strVal s => .str s
-- TODO: This should be cached.
def lowerEnumToScalarType (name : Name) : M (Option IRType) := do
let env Lean.getEnv
let some (.inductInfo inductiveVal) := env.find? name | return none
let ctorNames := inductiveVal.ctors
let numCtors := ctorNames.length
for ctorName in ctorNames do
let some (.ctorInfo ctorVal) := env.find? ctorName | panic! "expected valid constructor name"
if ctorVal.type.isForall then return none
return if numCtors == 1 then
none
else if numCtors < Nat.pow 2 8 then
some .uint8
else if numCtors < Nat.pow 2 16 then
some .uint16
else if numCtors < Nat.pow 2 32 then
some .uint32
else
none
def lowerType (e : Lean.Expr) : M IRType := do
match e with
| .const name .. =>
match name with
| ``UInt8 | ``Bool => return .uint8
| ``UInt16 => return .uint16
| ``UInt32 => return .uint32
| ``UInt64 => return .uint64
| ``USize => return .usize
| ``Float => return .float
| ``Float32 => return .float32
| ``lcErased => return .irrelevant
| _ =>
if let some scalarType lowerEnumToScalarType name then
return scalarType
else
return .object
| .app f _ =>
if let .const name _ := f.headBeta then
if let some scalarType lowerEnumToScalarType name then
return scalarType
else
return .object
else
return .object
| .forallE .. => return .object
| _ => panic! "invalid type"
-- TODO: This should be cached.
def getCtorInfo (name : Name) : M (CtorInfo × (Array CtorFieldInfo)) := do
match getCtorLayout ( Lean.getEnv) name with
| .ok ctorLayout =>
return {
name,
cidx := ctorLayout.cidx,
size := ctorLayout.numObjs,
usize := ctorLayout.numUSize,
ssize := ctorLayout.scalarSize
}, ctorLayout.fieldInfo.toArray
| .error .. => panic! "unrecognized constructor"
def lowerArg (a : LCNF.Arg) : M Arg := do
match a with
| .fvar fvarId =>
match ( get).fvars[fvarId]? with
| some (.var varId) => return .var varId
| some .erased => return .irrelevant
| some (.joinPoint ..) | none => panic! "unexpected value"
| .erased | .type .. => return .irrelevant
inductive TranslatedProj where
| expr (e : Expr)
| erased
deriving Inhabited
def lowerProj (base : VarId) (ctorInfo : CtorInfo) (field : CtorFieldInfo)
: TranslatedProj × IRType :=
match field with
| .object i => .expr (.proj i base), .object
| .usize i => .expr (.uproj i base), .usize
| .scalar _ offset irType => .expr (.sproj (ctorInfo.size + ctorInfo.usize) offset base), irType
| .irrelevant => .erased, .irrelevant
def lowerParam (p : LCNF.Param) : M Param := do
let x bindVar p.fvarId
let ty lowerType p.type
return { x, borrow := p.borrow, ty }
mutual
partial def lowerCode (c : LCNF.Code) : M FnBody := do
match c with
| .let decl k => lowerLet decl k
| .jp decl k =>
let joinPoint bindJoinPoint decl.fvarId
let params decl.params.mapM lowerParam
let body lowerCode decl.value
return .jdecl joinPoint params body ( lowerCode k)
| .jmp fvarId args =>
match ( get).fvars[fvarId]? with
| some (.joinPoint joinPointId) =>
return .jmp joinPointId ( args.mapM lowerArg)
| some (.var ..) | some .erased | none => panic! "unexpected value"
| .cases cases =>
match ( get).fvars[cases.discr]? with
| some (.var varId) =>
return .case cases.typeName
varId
( lowerType cases.resultType)
( cases.alts.mapM (lowerAlt varId))
| some (.joinPoint ..) | some .erased | none => panic! "unexpected value"
| .return fvarId =>
let arg := match ( get).fvars[fvarId]? with
| some (.var varId) => .var varId
| some .erased => .irrelevant
| some (.joinPoint ..) | none => panic! "unexpected value"
return .ret arg
| .unreach .. => return .unreachable
| .fun .. => panic! "all local functions should be λ-lifted"
partial def lowerLet (decl : LCNF.LetDecl) (k : LCNF.Code) : M FnBody := do
-- temporary fix: the old compiler inlines these too much as regular `let`s
let rec mkVar (v : VarId) : M FnBody := do
bindVarToVarId decl.fvarId v
lowerCode k
let rec mkExpr (e : Expr) : M FnBody := do
let var bindVar decl.fvarId
let type match e with
| .ctor .. | .pap .. | .proj .. => pure <| .object
| _ => lowerType decl.type
return .vdecl var type e ( lowerCode k)
let rec mkErased (_ : Unit) : M FnBody := do
bindErased decl.fvarId
lowerCode k
let rec mkPartialApp (e : Expr) (restArgs : Array Arg) : M FnBody := do
let var bindVar decl.fvarId
let tmpVar newVar
let type match e with
| .ctor .. | .pap .. | .proj .. => pure <| .object
| _ => lowerType decl.type
return .vdecl tmpVar .object e (.vdecl var type (.ap tmpVar restArgs) ( lowerCode k))
let rec tryIrDecl? (name : Name) (args : Array Arg) : M (Option FnBody) := do
if let some decl LCNF.getMonoDecl? name then
let numArgs := args.size
let numParams := decl.params.size
if numArgs < numParams then
return some ( mkExpr (.pap name args))
else if numArgs == numParams then
return some ( mkExpr (.fap name args))
else
let firstArgs := args.extract 0 numParams
let restArgs := args.extract numParams numArgs
return some ( mkPartialApp (.fap name firstArgs) restArgs)
else
return none
match decl.value with
| .value litValue =>
mkExpr (.lit (lowerLitValue litValue))
| .proj typeName i fvarId =>
match ( get).fvars[fvarId]? with
| some (.var varId) =>
-- TODO: have better pattern matching here
let some (.inductInfo { ctors, .. }) := ( Lean.getEnv).find? typeName
| panic! "projection of non-inductive type"
let ctorName := ctors[0]!
let ctorInfo, fields getCtorInfo ctorName
let result, type := lowerProj varId ctorInfo fields[i]!
match result with
| .expr e =>
let var bindVar decl.fvarId
return .vdecl var type e ( lowerCode k)
| .erased =>
bindErased decl.fvarId
lowerCode k
| some .erased =>
bindErased decl.fvarId
lowerCode k
| some (.joinPoint ..) | none => panic! "unexpected value"
| .const ``Nat.succ _ args =>
let irArgs args.mapM lowerArg
let var bindVar decl.fvarId
let tmpVar newVar
let k := (.vdecl var .object (.fap ``Nat.add #[irArgs[0]!, (.var tmpVar)]) ( lowerCode k))
return .vdecl tmpVar .object (.lit (.num 1)) k
| .const name _ args =>
let irArgs args.mapM lowerArg
if let some code tryIrDecl? name irArgs then
return code
else
let env Lean.getEnv
match env.find? name with
| some (.ctorInfo ctorVal) =>
if isExtern env name then
if let some code tryIrDecl? name irArgs then
return code
else
mkExpr (.fap name irArgs)
else
let ctorInfo, fields getCtorInfo name
let args := args.extract (start := ctorVal.numParams)
let objArgs : Array Arg do
let mut result : Array Arg := #[]
for i in [0:fields.size] do
match args[i]! with
| .fvar fvarId =>
if let some (.var varId) := ( get).fvars[fvarId]? then
if fields[i]! matches .object .. then
result := result.push (.var varId)
| .type _ | .erased =>
if fields[i]! matches .object .. then
result := result.push .irrelevant
pure result
let objVar bindVar decl.fvarId
let rec lowerNonObjectFields (_ : Unit) : M FnBody :=
let rec loop (usizeCount : Nat) (i : Nat) : M FnBody := do
match args[i]? with
| some (.fvar fvarId) =>
match ( get).fvars[fvarId]? with
| some (.var varId) =>
match fields[i]! with
| .usize .. =>
let k loop (usizeCount + 1) (i + 1)
return .uset objVar (ctorInfo.size + usizeCount) varId k
| .scalar _ offset argType =>
let k loop usizeCount (i + 1)
return .sset objVar (ctorInfo.size + ctorInfo.usize) offset varId argType k
| .object .. | .irrelevant => loop usizeCount (i + 1)
| _ => loop usizeCount (i + 1)
| some (.type _) | some .erased => loop usizeCount (i + 1)
| none => lowerCode k
loop 0 0
return .vdecl objVar .object (.ctor ctorInfo objArgs) ( lowerNonObjectFields ())
| some (.axiomInfo ..) =>
if name == ``Quot.lcInv then
match irArgs[2]! with
| .var varId => mkVar varId
| .irrelevant => mkErased ()
else if name == ``lcUnreachable then
return .unreachable
else if let some irDecl findDecl name then
let numArgs := irArgs.size
let numParams := irDecl.params.size
if numArgs < numParams then
mkExpr (.pap name irArgs)
else if numArgs == numParams then
mkExpr (.fap name irArgs)
else
let firstArgs := irArgs.extract 0 numParams
let restArgs := irArgs.extract numParams irArgs.size
mkPartialApp (.fap name firstArgs) restArgs
else
throwError f!"axiom '{name}' not supported by code generator; consider marking definition as 'noncomputable'"
| some (.quotInfo ..) =>
if name == ``Quot.mk then
match irArgs[2]! with
| .var varId => mkVar varId
| .irrelevant => mkErased ()
else
throwError f!"quot {name} unsupported by code generator"
| some (.defnInfo ..) | some (.opaqueInfo ..) =>
if let some code tryIrDecl? name irArgs then
return code
else
mkExpr (.fap name irArgs)
| some (.recInfo ..) =>
throwError f!"code generator does not support recursor '{name}' yet, consider using 'match ... with' and/or structural recursion"
| some (.inductInfo ..) => panic! "induct unsupported by code generator"
| some (.thmInfo ..) => panic! "thm unsupported by code generator"
| none => panic! "reference to unbound name"
| .fvar fvarId args =>
match ( get).fvars[fvarId]? with
| some (.var id) =>
let irArgs args.mapM lowerArg
mkExpr (.ap id irArgs)
| some .erased => mkErased ()
| some (.joinPoint ..) | none => panic! "unexpected value"
| .erased => mkErased ()
partial def lowerAlt (discr : VarId) (a : LCNF.AltCore LCNF.Code) : M (AltCore FnBody) := do
match a with
| .alt ctorName params code =>
let ctorInfo, fields getCtorInfo ctorName
let lowerParams (params : Array LCNF.Param) (fields : Array CtorFieldInfo) : M FnBody := do
let rec loop (i : Nat) : M FnBody := do
match params[i]?, fields[i]? with
| some param, some field =>
let result, type := lowerProj discr ctorInfo field
match result with
| .expr e =>
return .vdecl ( bindVar param.fvarId)
type
e
( loop (i + 1))
| .erased =>
bindErased param.fvarId
loop (i + 1)
| none, none => lowerCode code
| _, _ => panic! "mismatched fields and params"
loop 0
let body lowerParams params fields
return .ctor ctorInfo body
| .default code =>
return .default ( lowerCode code)
end
def lowerResultType (type : Lean.Expr) (arity : Nat) : M IRType :=
lowerType (resultTypeForArity type arity)
where resultTypeForArity (type : Lean.Expr) (arity : Nat) : Lean.Expr :=
if arity == 0 then
type
else
match type with
| .forallE _ _ b _ => resultTypeForArity b (arity - 1)
| .const ``lcErased _ => mkConst ``lcErased
| _ => panic! "invalid arity"
def lowerDecl (d : LCNF.Decl) : M (Option Decl) := do
let params d.params.mapM lowerParam
let resultType lowerResultType d.type d.params.size
match d.value with
| .code code =>
let body lowerCode code
pure <| some <| .fdecl d.name params resultType body {}
| .extern externAttrData =>
if externAttrData.entries.isEmpty then
-- TODO: This matches the behavior of the old compiler, but we should
-- find a better way to handle this.
addDecl (mkDummyExternDecl d.name params resultType)
pure <| none
else
pure <| some <| .extern d.name params resultType externAttrData
end ToIR
def toIR (decls: Array LCNF.Decl) : CoreM (Array Decl) := do
let mut irDecls := #[]
for decl in decls do
if let some irDecl ToIR.lowerDecl decl |>.run then
irDecls := irDecls.push irDecl
return irDecls
end Lean.IR

View File

@@ -29,6 +29,10 @@ structure Context where
Remark: the lambda lifting pass abstracts all `let`/`fun`-declarations.
-/
abstract : FVarId Bool
/--
Indicates whether we are processing terms beneath a binder.
-/
isUnderBinder : Bool
/--
State for the `ClosureM` monad.
@@ -93,7 +97,11 @@ mutual
-/
partial def collectCode (c : Code) : ClosureM Unit := do
match c with
| .let decl k => collectType decl.type; collectLetValue decl.value; collectCode k
| .let decl k =>
collectType decl.type
withReader (fun ctx => { ctx with isUnderBinder := ctx.isUnderBinder || decl.type.isForall })
do collectLetValue decl.value
collectCode k
| .fun decl k | .jp decl k => collectFunDecl decl; collectCode k
| .cases c =>
collectType c.resultType
@@ -110,7 +118,8 @@ mutual
partial def collectFunDecl (decl : FunDecl) : ClosureM Unit := do
collectType decl.type
collectParams decl.params
collectCode decl.value
withReader (fun ctx => { ctx with isUnderBinder := true }) do
collectCode decl.value
/--
Process the given free variable.
@@ -119,10 +128,11 @@ mutual
partial def collectFVar (fvarId : FVarId) : ClosureM Unit := do
unless ( get).visited.contains fvarId do
markVisited fvarId
if ( read).inScope fvarId then
let ctx read
if ctx.inScope fvarId then
/- We only collect the variables in the scope of the function application being specialized. -/
if let some funDecl findFunDecl? fvarId then
if ( read).abstract funDecl.fvarId then
if ctx.isUnderBinder || ctx.abstract funDecl.fvarId then
modify fun s => { s with params := s.params.push <| { funDecl with borrow := false } }
else
collectFunDecl funDecl
@@ -132,7 +142,7 @@ mutual
modify fun s => { s with params := s.params.push param }
else if let some letDecl findLetDecl? fvarId then
collectType letDecl.type
if ( read).abstract letDecl.fvarId then
if ctx.isUnderBinder || ctx.abstract letDecl.fvarId then
modify fun s => { s with params := s.params.push <| { letDecl with borrow := false } }
else
collectLetValue letDecl.value
@@ -147,9 +157,16 @@ mutual
end
def run (x : ClosureM α) (inScope : FVarId Bool) (abstract : FVarId Bool := fun _ => true) : CompilerM (α × Array Param × Array CodeDecl) := do
let (a, s) x { inScope, abstract } |>.run {}
return (a, s.params, s.decls)
let (a, s) x { inScope, abstract, isUnderBinder := false } |>.run {}
-- If we've abstracted an fvar into a param, exclude its definition. Note that this still allows
-- for other decls the removed decl depends upon to be included, but they will be removed later
-- for having no users.
let mut paramFVars : FVarIdSet := {}
for param in s.params do
paramFVars := paramFVars.insert param.fvarId
let filteredDecls := s.decls.filter fun decl => !(paramFVars.contains decl.fvarId)
return (a, s.params, filteredDecls)
end Closure
end Lean.Compiler.LCNF
end Lean.Compiler.LCNF

View File

@@ -6,6 +6,10 @@ Authors: Leonardo de Moura
prelude
import Lean.Compiler.Options
import Lean.Compiler.ExternAttr
import Lean.Compiler.IR
import Lean.Compiler.IR.Basic
import Lean.Compiler.IR.Checker
import Lean.Compiler.IR.ToIR
import Lean.Compiler.LCNF.PassManager
import Lean.Compiler.LCNF.Passes
import Lean.Compiler.LCNF.PrettyPrinter
@@ -62,7 +66,7 @@ def checkpoint (stepName : Name) (decls : Array Decl) : CompilerM Unit := do
namespace PassManager
def run (declNames : Array Name) : CompilerM (Array Decl) := withAtLeastMaxRecDepth 8192 do
def run (declNames : Array Name) : CompilerM (Array IR.Decl) := withAtLeastMaxRecDepth 8192 do
/-
Note: we need to increase the recursion depth because we currently do to save phase1
declarations in .olean files. Then, we have to recursively compile all dependencies,
@@ -83,11 +87,25 @@ def run (declNames : Array Name) : CompilerM (Array Decl) := withAtLeastMaxRecDe
-- We display the declaration saved in the environment because the names have been normalized
let some decl' getDeclAt? decl.name .mono | unreachable!
Lean.addTrace `Compiler.result m!"size: {decl.size}\n{← ppDecl' decl'}"
return decls
let opts getOptions
-- If the new compiler is disabled, then all of the saved IR was built with the old compiler,
-- which causes IR type mismatches with IR generated by the new compiler.
if !(compiler.enableNew.get opts) then
return #[]
let irDecls IR.toIR decls
let env getEnv
let log, res := IR.compile env opts irDecls
for msg in log do
addTrace `Compiler.IR m!"{msg}"
match res with
| .ok env =>
setEnv env
return irDecls
| .error s => throwError s
end PassManager
def compile (declNames : Array Name) : CoreM (Array Decl) :=
def compile (declNames : Array Name) : CoreM (Array IR.Decl) :=
CompilerM.run <| PassManager.run declNames
def showDecl (phase : Phase) (declName : Name) : CoreM Format := do

View File

@@ -77,7 +77,7 @@ def getCtorArity? (declName : Name) : CoreM (Option Nat) := do
/--
List of types that have builtin runtime support
-/
def builtinRuntimeTypes : List Name := [
def builtinRuntimeTypes : Array Name := #[
``String,
``UInt8, ``UInt16, ``UInt32, ``UInt64, ``USize,
``Float, ``Float32,

View File

@@ -612,20 +612,21 @@ where doCompile := do
return
let opts getOptions
if compiler.enableNew.get opts then
compileDeclsNew decls
let res withTraceNode `compiler (fun _ => return m!"compiling old: {decls}") do
return compileDeclsOld ( getEnv) opts decls
match res with
| Except.ok env => setEnv env
| Except.error (.other msg) =>
if logErrors then
if let some decl := ref? then
checkUnsupported decl -- Generate nicer error message for unsupported recursors and axioms
throwError msg
| Except.error ex =>
if logErrors then
throwKernelException ex
try compileDeclsNew decls catch e =>
if logErrors then throw e else return ()
else
let res withTraceNode `compiler (fun _ => return m!"compiling old: {decls}") do
return compileDeclsOld ( getEnv) opts decls
match res with
| Except.ok env => setEnv env
| Except.error (.other msg) =>
if logErrors then
if let some decl := ref? then
checkUnsupported decl -- Generate nicer error message for unsupported recursors and axioms
throwError msg
| Except.error ex =>
if logErrors then
throwKernelException ex
def compileDecl (decl : Declaration) (logErrors := true) : CoreM Unit := do
compileDecls (Compiler.getDeclNamesForCodeGen decl) decl logErrors

View File

@@ -47,54 +47,97 @@ instance : ToJson String := ⟨fun s => s⟩
instance : FromJson System.FilePath := fun j => System.FilePath.mk <$> Json.getStr? j
instance : ToJson System.FilePath := fun p => p.toString
instance [FromJson α] : FromJson (Array α) where
fromJson?
| Json.arr a => a.mapM fromJson?
| j => throw s!"expected JSON array, got '{j}'"
protected def _root_.Array.fromJson? [FromJson α] : Json Except String (Array α)
| Json.arr a => a.mapM fromJson?
| j => throw s!"expected JSON array, got '{j}'"
instance [ToJson α] : ToJson (Array α) :=
fun a => Json.arr (a.map toJson)
instance [FromJson α] : FromJson (Array α) where
fromJson? := Array.fromJson?
protected def _root_.Array.toJson [ToJson α] (a : Array α) : Json :=
Json.arr (a.map toJson)
instance [ToJson α] : ToJson (Array α) where
toJson := Array.toJson
protected def _root_.List.fromJson? [FromJson α] (j : Json) : Except String (List α) :=
(fromJson? j (α := Array α)).map Array.toList
instance [FromJson α] : FromJson (List α) where
fromJson? j := (fromJson? j (α := Array α)).map Array.toList
fromJson? := List.fromJson?
protected def _root_.List.toJson [ToJson α] (a : List α) : Json :=
toJson a.toArray
instance [ToJson α] : ToJson (List α) where
toJson xs := toJson xs.toArray
toJson := List.toJson
protected def _root_.Option.fromJson? [FromJson α] : Json Except String (Option α)
| Json.null => Except.ok none
| j => some <$> fromJson? j
instance [FromJson α] : FromJson (Option α) where
fromJson?
| Json.null => Except.ok none
| j => some <$> fromJson? j
fromJson? := Option.fromJson?
instance [ToJson α] : ToJson (Option α) :=
fun
| none => Json.null
| some a => toJson a
protected def _root_.Option.toJson [ToJson α] : Option α Json
| none => Json.null
| some a => toJson a
instance [ToJson α] : ToJson (Option α) where
toJson := Option.toJson
protected def _root_.Prod.fromJson? {α : Type u} {β : Type v} [FromJson α] [FromJson β] : Json Except String (α × β)
| Json.arr #[ja, jb] => do
let a : ULift.{v} α := (fromJson? ja).map ULift.up
let b : ULift.{u} β := (fromJson? jb).map ULift.up
return (a, b)
| j => throw s!"expected pair, got '{j}'"
instance {α : Type u} {β : Type v} [FromJson α] [FromJson β] : FromJson (α × β) where
fromJson?
| Json.arr #[ja, jb] => do
let a : ULift.{v} α := (fromJson? ja).map ULift.up
let b : ULift.{u} β := (fromJson? jb).map ULift.up
return (a, b)
| j => throw s!"expected pair, got '{j}'"
fromJson? := Prod.fromJson?
protected def _root_.Prod.toJson [ToJson α] [ToJson β] : α × β Json
| (a, b) => Json.arr #[toJson a, toJson b]
instance [ToJson α] [ToJson β] : ToJson (α × β) where
toJson := fun (a, b) => Json.arr #[toJson a, toJson b]
toJson := Prod.toJson
protected def Name.fromJson? (j : Json) : Except String Name := do
let s j.getStr?
if s == "[anonymous]" then
return Name.anonymous
else
let n := s.toName
if n.isAnonymous then throw s!"expected a `Name`, got '{j}'"
return n
instance : FromJson Name where
fromJson? j := do
let s j.getStr?
if s == "[anonymous]" then
return Name.anonymous
else
let n := s.toName
if n.isAnonymous then throw s!"expected a `Name`, got '{j}'"
return n
fromJson? := Name.fromJson?
instance : ToJson Name where
toJson n := toString n
protected def NameMap.fromJson? [FromJson α] : Json Except String (NameMap α)
| .obj obj => obj.foldM (init := {}) fun m k v => do
if k == "[anonymous]" then
return m.insert .anonymous ( fromJson? v)
else
let n := k.toName
if n.isAnonymous then
throw s!"expected a `Name`, got '{k}'"
else
return m.insert n ( fromJson? v)
| j => throw s!"expected a `NameMap`, got '{j}'"
instance [FromJson α] : FromJson (NameMap α) where
fromJson? := NameMap.fromJson?
protected def NameMap.toJson [ToJson α] (m : NameMap α) : Json :=
Json.obj <| m.fold (fun n k v => n.insert compare k.toString (toJson v)) .leaf
instance [ToJson α] : ToJson (NameMap α) where
toJson := NameMap.toJson
/-- Note that `USize`s and `UInt64`s are stored as strings because JavaScript
cannot represent 64-bit numbers. -/
def bignumFromJson? (j : Json) : Except String Nat := do
@@ -106,58 +149,77 @@ def bignumFromJson? (j : Json) : Except String Nat := do
def bignumToJson (n : Nat) : Json :=
toString n
protected def _root_.USize.fromJson? (j : Json) : Except String USize := do
let n bignumFromJson? j
if n USize.size then
throw "value '{j}' is too large for `USize`"
return USize.ofNat n
instance : FromJson USize where
fromJson? j := do
let n bignumFromJson? j
if n USize.size then
throw "value '{j}' is too large for `USize`"
return USize.ofNat n
fromJson? := USize.fromJson?
instance : ToJson USize where
toJson v := bignumToJson (USize.toNat v)
protected def _root_.UInt64.fromJson? (j : Json) : Except String UInt64 := do
let n bignumFromJson? j
if n UInt64.size then
throw "value '{j}' is too large for `UInt64`"
return UInt64.ofNat n
instance : FromJson UInt64 where
fromJson? j := do
let n bignumFromJson? j
if n UInt64.size then
throw "value '{j}' is too large for `UInt64`"
return UInt64.ofNat n
fromJson? := UInt64.fromJson?
instance : ToJson UInt64 where
toJson v := bignumToJson (UInt64.toNat v)
protected def _root_.Float.toJson (x : Float) : Json :=
match JsonNumber.fromFloat? x with
| Sum.inl e => Json.str e
| Sum.inr n => Json.num n
instance : ToJson Float where
toJson x :=
match JsonNumber.fromFloat? x with
| Sum.inl e => Json.str e
| Sum.inr n => Json.num n
toJson := Float.toJson
protected def _root_.Float.fromJson? : Json Except String Float
| (Json.str "Infinity") => Except.ok (1.0 / 0.0)
| (Json.str "-Infinity") => Except.ok (-1.0 / 0.0)
| (Json.str "NaN") => Except.ok (0.0 / 0.0)
| (Json.num jn) => Except.ok jn.toFloat
| _ => Except.error "Expected a number or a string 'Infinity', '-Infinity', 'NaN'."
instance : FromJson Float where
fromJson? := fun
| (Json.str "Infinity") => Except.ok (1.0 / 0.0)
| (Json.str "-Infinity") => Except.ok (-1.0 / 0.0)
| (Json.str "NaN") => Except.ok (0.0 / 0.0)
| (Json.num jn) => Except.ok jn.toFloat
| _ => Except.error "Expected a number or a string 'Infinity', '-Infinity', 'NaN'."
fromJson? := Float.fromJson?
protected def RBMap.toJson [ToJson α] (m : RBMap String α cmp) : Json :=
Json.obj <| RBNode.map (fun _ => toJson) <| m.val
instance [ToJson α] : ToJson (RBMap String α cmp) where
toJson m := Json.obj <| RBNode.map (fun _ => toJson) <| m.val
toJson := RBMap.toJson
protected def RBMap.fromJson? [FromJson α] (j : Json) : Except String (RBMap String α cmp) := do
let o j.getObj?
o.foldM (fun x k v => x.insert k <$> fromJson? v)
instance {cmp} [FromJson α] : FromJson (RBMap String α cmp) where
fromJson? j := do
let o j.getObj?
o.foldM (fun x k v => x.insert k <$> fromJson? v)
fromJson? := RBMap.fromJson?
namespace Json
instance : FromJson Structured := fun
| arr a => return Structured.arr a
| obj o => return Structured.obj o
| j => throw s!"expected structured object, got '{j}'"
protected def Structured.fromJson? : Json Except String Structured
| .arr a => return Structured.arr a
| .obj o => return Structured.obj o
| j => throw s!"expected structured object, got '{j}'"
instance : ToJson Structured := fun
| Structured.arr a => arr a
| Structured.obj o => obj o
instance : FromJson Structured where
fromJson? := Structured.fromJson?
protected def Structured.toJson : Structured Json
| .arr a => .arr a
| .obj o => .obj o
instance : ToJson Structured where
toJson := Structured.toJson
def toStructured? [ToJson α] (v : α) : Except String Structured :=
fromJson? (toJson v)

View File

@@ -18,6 +18,8 @@ def NameMap (α : Type) := RBMap Name α Name.quickCmp
namespace NameMap
variable {α : Type}
instance [Repr α] : Repr (NameMap α) := inferInstanceAs (Repr (RBMap Name α Name.quickCmp))
instance (α : Type) : EmptyCollection (NameMap α) := mkNameMap α
instance (α : Type) : Inhabited (NameMap α) where

View File

@@ -25,25 +25,34 @@ namespace Lean.Elab.Command
modifyEnv fun env => addMainModuleDoc env doc, range
| _ => throwErrorAt stx "unexpected module doc string{indentD stx[1]}"
private def addScope (isNewNamespace : Bool) (isNoncomputable : Bool) (header : String) (newNamespace : Name) : CommandElabM Unit := do
private def addScope (isNewNamespace : Bool) (header : String) (newNamespace : Name)
(isNoncomputable : Bool := false) (attrs : List (TSyntax ``Parser.Term.attrInstance) := []) :
CommandElabM Unit := do
modify fun s => { s with
env := s.env.registerNamespace newNamespace,
scopes := { s.scopes.head! with header := header, currNamespace := newNamespace, isNoncomputable := s.scopes.head!.isNoncomputable || isNoncomputable } :: s.scopes
scopes := { s.scopes.head! with
header := header, currNamespace := newNamespace
isNoncomputable := s.scopes.head!.isNoncomputable || isNoncomputable
attrs := s.scopes.head!.attrs ++ attrs
} :: s.scopes
}
pushScope
if isNewNamespace then
activateScoped newNamespace
private def addScopes (isNewNamespace : Bool) (isNoncomputable : Bool) : Name CommandElabM Unit
private def addScopes (header : Name) (isNewNamespace : Bool) (isNoncomputable : Bool := false)
(attrs : List (TSyntax ``Parser.Term.attrInstance) := []) : CommandElabM Unit :=
go header
where go
| .anonymous => pure ()
| .str p header => do
addScopes isNewNamespace isNoncomputable p
go p
let currNamespace getCurrNamespace
addScope isNewNamespace isNoncomputable header (if isNewNamespace then Name.mkStr currNamespace header else currNamespace)
addScope isNewNamespace header (if isNewNamespace then Name.mkStr currNamespace header else currNamespace) isNoncomputable attrs
| _ => throwError "invalid scope"
private def addNamespace (header : Name) : CommandElabM Unit :=
addScopes (isNewNamespace := true) (isNoncomputable := false) header
addScopes (isNewNamespace := true) (isNoncomputable := false) (attrs := []) header
def withNamespace {α} (ns : Name) (elabFn : CommandElabM α) : CommandElabM α := do
addNamespace ns
@@ -76,14 +85,16 @@ private def checkEndHeader : Name → List Scope → Option Name
@[builtin_command_elab «section»] def elabSection : CommandElab := fun stx => do
match stx with
| `(section $header:ident) => addScopes (isNewNamespace := false) (isNoncomputable := false) header.getId
| `(section) => addScope (isNewNamespace := false) (isNoncomputable := false) "" ( getCurrNamespace)
| _ => throwUnsupportedSyntax
@[builtin_command_elab noncomputableSection] def elabNonComputableSection : CommandElab := fun stx => do
match stx with
| `(noncomputable section $header:ident) => addScopes (isNewNamespace := false) (isNoncomputable := true) header.getId
| `(noncomputable section) => addScope (isNewNamespace := false) (isNoncomputable := true) "" ( getCurrNamespace)
| `($[@[expose%$expTk]]? $[noncomputable%$ncTk]? section $(header?)?) =>
-- TODO: allow more attributes?
let attrs if expTk.isSome then
pure [ `(Parser.Term.attrInstance| expose)]
else
pure []
if let some header := header? then
addScopes (isNewNamespace := false) (isNoncomputable := ncTk.isSome) (attrs := attrs) header.getId
else
addScope (isNewNamespace := false) (isNoncomputable := ncTk.isSome) (attrs := attrs) "" ( getCurrNamespace)
| _ => throwUnsupportedSyntax
@[builtin_command_elab «end»] def elabEnd : CommandElab := fun stx => do
@@ -448,7 +459,7 @@ def failIfSucceeds (x : CommandElabM Unit) : CommandElabM Unit := do
let mut msg : Array MessageData := #[]
-- Noncomputable
if scope.isNoncomputable then
msg := msg.push <| `(command| noncomputable section)
msg := msg.push <| `(Parser.Command.section| noncomputable section)
-- Namespace
if !scope.currNamespace.isAnonymous then
msg := msg.push <| `(command| namespace $(mkIdent scope.currNamespace))

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