Compare commits

...

971 Commits

Author SHA1 Message Date
Kim Morrison
66b47a843b feat: deprecate Array.mkArray in favour of Array.replicate 2025-03-24 10:30:32 +11:00
Kim Morrison
cff19d7edf chore: update stage0 2025-03-24 10:25:35 +11:00
Kim Morrison
600b5c5f9c feat: add Array.replicate 2025-03-24 10:21:22 +11:00
Kyle Miller
414ba28cef fix: make pretty printed structure instances hoverable (#7648)
This PR fixes a bug introduced in #7589, causing pretty printed
structure instances to not be hoverable in the Infoview.

This was caused by a choice node being introduced, since `{ $fields,* }`
is ambiguous syntax.
2025-03-23 19:36:13 +00:00
Henrik Böving
d24dfa1031 perf: add a cache to bv_decide's reflection procedure (#7644)
This PR adds a cache to the reflection procedure of bv_decide.

This was motivated by the following profile on QF_BV SMTLIB problem
`sage/app12/bench_3564.smt2`: https://share.firefox.dev/4iTG8KX. After
this change we roughly get a 10x speedup and `simp` is the bottleneck
again: https://share.firefox.dev/4iuezYT
2025-03-23 13:56:00 +00:00
Henrik Böving
f241cc832b perf: bv_decide don't drop the expression level cache (#7636)
This PR makes sure that the expression level cache in bv_decide is
maintained across the entire bitblaster instead of just locally per
BitVec expression.

The PR was split off from the first one (#7606) as this mostly entails
pulling the invariant through and is thus much more mechanical.
2025-03-23 13:05:01 +00:00
Kyle Miller
e663eb1b7a feat: structure autoParam inheritance (#7640)
This PR implements the main logic for inheriting and overriding
autoParam fields in the `structure`/`class` commands, pending being
enabled in the structure instance notation elaborator. Adds term info to
overridden fields, so they now can be hovered over, and "go to
definition" goes to the structure the field is originally defined in.

Implementation notes:
- The inherited autoParams are all recorded in the flat constructor.
Defined/overridden autoParam auxiliary tactic declarations now have
names of the form `StructName.fieldName._autoParam`
- The field `StructureFieldInfo.autoParam?` is soon to be deprecated.
The elaborator is still setting it for now, since the structure instance
notation elaborator is still using it.
2025-03-23 06:04:00 +00:00
Leonardo de Moura
06d6dbff5d feat: model-based theory combination in grind (#7641)
This PR implements basic model-based theory combination in `grind`.
`grind` can now solve examples such as
```lean
example (f : Int → Int) (x : Int)
    : 0 ≤ x → x ≠ 0 → x ≤ 1 → f x = 2 → f 1 = 2 := by
  grind
```
2025-03-23 04:06:09 +00:00
Mac Malone
66e0a5440b refactor: lake: unified configuration (#7504)
This PR augments the Lake configuration data structures declarations
(e.g., `PackageConfig`, `LeanLibConfig`) to produce additional metadata
which is used to automatically generate the Lean & TOML encoders and
decoders via metaprograms.

**Warning:** This refactor should not produce any significant
user-facing breaking changes. However, configurations have been tweaked,
so there is a chance something may have slipped through.

Lake TOML decoding and Lean syntax manipulation utilities have also
undergone significant rework to facilitate this PR. Such utilities are
considered internal and thus little has been done to mitigate possible
downstream breakages.
2025-03-23 02:49:57 +00:00
Lean stage0 autoupdater
7f362c8e8a chore: update stage0 2025-03-23 00:37:25 +00:00
Kyle Miller
cde237daea feat: change structure command to elaborate fields as if structures are flat (#7302)
This PR changes how fields are elaborated in the `structure`/`class`
commands and also makes default values respect the structure resolution
order when there is diamond inheritance. Before, the details of
subobjects were exposed during elaboration, and in the local context any
fields that came from a subobject were defined to be projections of the
subobject field. Now, every field is represented as a local variable.
All parents (not just subobject parents) are now represented in the
local context, and they are now local variables defined to be parent
constructors applied to field variables (inverting the previous
relationship). Other notes:
- The entire collection of parents is processed, and all parent
projection names are checked for consistency. Every parent appears in
the local context now.
- For classes, every parent now contributes an instance, not just the
parents represented as subobjects.
- Default values are now processed according to the parent resolution
order. Default value definition/override auxiliary definitions are
stored at `StructName.fieldName._default`, and inherited values are
stored at `StructName.fieldName._inherited_default`. Metaprograms no
longer need to look at parents when doing calculations on default
values.
- Default value omission for structure instance notation pretty printing
has been updated in consideration of this.
- Now the elaborator generates a `_flat_ctor` constructor that will be
used for structure instance elaboration. All types in this constructor
are put in "field normal form" (projections of parent constructors are
reduced, and parent constructors are eta reduced), and all fields with
autoParams are annotated as such. This is not meant for users, but it
may be useful for metaprogramming.
- While elaborating fields, any metavariables whose type is one of the
parents is assigned to that parent. The hypothesis is that, for the
purpose of elaborating structure fields, parents are fixed: there is
only *one* instance of any given parent under consideration. See the
`Magma` test for an example of this being necessary. The hypothesis may
not be true when there are recursive structures, since different values
of the structure might not agree on parent fields.

Other notes:
- The elaborator has been refactored, and it now uses a monad to keep
track of the elaboration state.
- This PR was motivation for #7100, since we need to be able to make all
parents have consistent projection names when there is diamond
inheritance.

Still to do:
- Handle autoParams like we do default values. Inheritance for these is
not correct when there is diamond inheritance.
- Avoid splitting apart parents if the overlap is only on proof fields.
- Non-subobject parent projections do not have parameter binder kinds
that are consistent with other projections (i.e., all implicit by
default, no inst implicits). This needs to wait on adjustments to the
synthOrder algorithm.
- We could elide parents with no fields, letting their projections be
constant functions. This causes some trouble for defeq checking however
(maybe #2258 would address this).
2025-03-22 22:33:10 +00:00
Henrik Böving
b97a7ef4cb perf: bv_decide introduce an expression level bitblasting cache (#7606)
This PR introduces an expression level bitblasting cache to bv_decide.
2025-03-22 13:25:52 +00:00
Leonardo de Moura
eb0c015e7c perf: quadratic behavior in whnfCore (#7630)
This PR fixes a performance issue in the `whnfCore` procedure.
2025-03-21 22:29:21 +00:00
David Thrane Christiansen
b768e44ba7 doc: further missing docstrings (#7613)
This PR adds a variety of docstrings for names that appear in the
manual.
2025-03-21 22:20:07 +00:00
Lean stage0 autoupdater
385c6db4ce chore: update stage0 2025-03-21 21:12:34 +00:00
David Thrane Christiansen
aef6c6d518 doc: review docstrings for fixed-width integer types (#7602)
This PR adds missing docstrings for fixed-width integer operations and
makes their style consistent.
2025-03-21 20:16:28 +00:00
Sebastian Ullrich
d57cbdfb95 chore: CI: bring back coredump tracing (#7625) 2025-03-21 15:25:45 +00:00
Sebastian Ullrich
7240d910d3 chore: more core proof benchmarks 2025-03-21 15:59:14 +01:00
Joachim Breitner
6931e91bf0 fix: mark Nat.div and Nat.modCore irreducible (#7614)
This PR marks `Nat.div` and `Nat.modCore` as `irreducible`, to recover 
the behavior from from before #7558.

Fixes #7612. H't to @tobiasgrosser for the good bug report.
2025-03-21 14:23:03 +00:00
Sebastian Ullrich
501bd64a89 chore: CI: avoid empty matrix error (#7620) 2025-03-21 13:30:58 +00:00
Marc Huisinga
2b11c8d9a4 chore: bump server version to 0.3.0 (#7624)
This PR bumps the server version so that clients like NeoVim can detect
whether the server supports our recent language server extensions
(modulo the time that has passed since these extension PRs).

I'd like to have server capabilities for this at some point, but this
will have to do for now.
2025-03-21 12:56:59 +00:00
Joachim Breitner
770af38c14 fix: fun_induction: correctly identify params and targets (#7622)
This PR fixes `fun_induction` when used on structurally recursive
functions where there are targets occurring before fixed parameters.

Fixes #7550
2025-03-21 12:12:15 +00:00
Sebastian Ullrich
7b787c81f3 perf: avoid contended access to IO.Ref in isTracingEnabledFor (#7601) 2025-03-21 12:07:25 +00:00
Joachim Breitner
bd01461b5f chore: run awaiting-mathlib.yml on more events (#7621)
so that we can make it a required check
2025-03-21 11:37:35 +00:00
Henrik Böving
1afd678100 perf: handle more symmetries in bv_decide bitblasting (#7617)
This PR adds the known bits optimization from the multiplication circuit
to the add one, allowing us to discover potentially even more symmetries
before going to the SAT solver.
2025-03-21 10:45:06 +00:00
Henrik Böving
677d26a581 refactor: apply fording to BVExpr to enable deriving DecidableEq (#7619)
This PR applies fording to bv_decide's BVExpr type to enable deriving
DecidableEq.
2025-03-21 10:29:04 +00:00
Henrik Böving
f673facdbe feat: add BV_EXTRACT_ADD to bv_decide (#7615)
This PR adds the ADD part of bitwuzlas BV_EXTRACT_ADD_MUL rule to
bv_decide's preprocessor.
2025-03-21 09:31:12 +00:00
Siddharth
9fc991da33 feat: add BV De Morgan's (extended) theorems from Hacker's Delight, 2.1 (#7604)
This PR adds bitvector theorems that to push negation into other
operations, following Hacker's Delight: Ch2.1.
2025-03-21 08:58:18 +00:00
Sebastian Ullrich
3d0f41e323 chore: fix interpreter lean_assert 2025-03-21 09:38:50 +01:00
David Thrane Christiansen
7e1ee70b7c doc: add docstrings for String.drop and String.dropRight (#7607)
This PR adds docstrings for `String.drop` and `String.dropRight`.
2025-03-21 05:38:07 +00:00
Mac Malone
131b458236 chore: lake: revert use of Lake plugin (#7608)
This PR removes the use of the Lake plugin in the Lake build and in
configuration files.

With #7399, the plugin is no longer necessary and may be the source of
some persistent intermittent Lake test failures.
2025-03-21 00:59:43 +00:00
Kim Morrison
74ffa1e413 chore: remove the old Lean.Data.HashMap implementation (#7519)
This PR removes `Lean.Data.HashMap` and `HashSet`. These have been
deprecated for 6 months, replaced by `Std.Data.HashMap` and `HashSet`.
2025-03-20 23:49:55 +00:00
Siddharth
42bbc4b6e2 feat: BitVec.extractLsb'_add_eq (#7595)
This PR implements the addition rewrite from the Bitwuzla rewrite
[BV_EXTRACT_ADD_MUL](e09c50818b/src/rewrite/rewrites_bv.cpp (L1495-L1510)),
which witness that the high bits at `i >= len` do not affect the bits of
the sum upto `len`:

```lean
theorem extractLsb'_add {w len} {x y : BitVec w} (hlen : len ≤ w) : 
    (x + y).extractLsb' 0 len = x.extractLsb' 0 len + y.extractLsb' 0 len
```

---------

Co-authored-by: Luisa Cicolini <48860705+luisacicolini@users.noreply.github.com>
2025-03-20 22:51:21 +00:00
Tobias Grosser
7c62881a95 feat: bv_decide short-circuit a * x = b * x (#6496)
This PR adds short-circuit support to bv_decide to accelerate
multiplications with shared coefficients. In particular, `a * x = b * x`
can be extended to `a = b v (a * x = b * x)`. The latter is faster if `a
= b` is true, as `a = b` may be evaluated without considering the
multiplication circuit. On the other hand, we require the multiplication
circuit, as `a * x = b * x -> a = b` is not always true due to two's
complement wrapping.

We support multiplications through acNF, which takes into account shared
terms across equality canonicalizing `a * (b * c1) = a * (b * c2)` to
`(a * b) * c1 = (a * b) * c2`. As a result, the non-shared terms are
lifted to the top such that canonical rewrites for binary multiplication
with shared terms on the left/right are sufficient.

We add an option `bv_decide +shortCircuit` which controls this feature
(currently disabled by default).

---------

Co-authored-by: Siddharth Bhat <siddu.druid@gmail.com>
Co-authored-by: Henrik Böving <hargonix@gmail.com>
2025-03-20 19:51:53 +00:00
Henrik Böving
c66cb00c0f refactor: turn the AIG framework's RefVec from Array to Vector (#7603)
This PR uses the new `Vector` API inside of the AIG framework's `RefVec`
datatype.
2025-03-20 16:57:04 +00:00
Kyle Miller
c066b5cf1c feat: pretty printing structures, omit default values (#7589)
This PR changes the structure instance notation pretty printer so that
fields are omitted if their value is definitionally equal to the default
value for the field (up to reducible transparancy). Setting
`pp.structureInstances.defaults` to true forces such fields to be pretty
printed anyway.

Closes #1100
2025-03-20 15:32:13 +00:00
Henrik Böving
3221ca1704 fix: interaction of enums and fixedInt in bv_decide (#7596)
This PR fixes an interaction between the enums and fixedInt pass in
bv_decide.

Marked as no changelog as this feature isn't released yet.
2025-03-20 15:12:52 +00:00
David Thrane Christiansen
c279c088c8 doc: review Int docstrings (#7568)
This PR adds missing `Int` docstrings and makes the style of all of them
consistent.
2025-03-20 14:04:56 +00:00
Sebastian Ullrich
086d45f27c perf: interpreter: use global native symbol cache (#7575)
With parallelism, a thread-local cache is not sufficient anymore.
2025-03-20 12:51:27 +00:00
Luisa Cicolini
637d8b2a2d feat: add BitVec.(negOverflow, negOverflow_eq) (#7554)
This PR adds SMT-LIB operators to detect overflow `BitVec.negOverflow`,
according to the [SMTLIB
standard](https://github.com/SMT-LIB/SMT-LIB-2/blob/2.7/Theories/FixedSizeBitVectors.smt2),
and the theorem proving equivalence of such definition with the `BitVec`
library functions (`negOverflow_eq`).

Co-authored by @bollu and @alexkeizer

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
2025-03-20 12:43:43 +00:00
David Thrane Christiansen
d8cbf1cefc doc: docstring review for monads and transformers (#7548)
This PR adds missing monad transformer docstrings and makes their style
consistent.

---------

Co-authored-by: Bhavik Mehta <bm489@cam.ac.uk>
2025-03-20 12:18:46 +00:00
Sebastian Ullrich
edbb84d23b chore: CI: USE_LAKE secondary build job (#7505)
As preparation for the module system, and in hopes it will be faster
than and replace the Nix CI. Secondary build jobs do not block merging.

Also makes macOS aarch64 a secondary build job on the PR level, where it
is the current bottleneck.

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2025-03-20 12:16:53 +00:00
Sebastian Ullrich
756fd66745 chore: CI: relax check-stage0 check 2025-03-20 13:16:43 +01:00
David Thrane Christiansen
99f296a2e7 doc: review docstrings for universe lifting operators (#7564)
This PR updates the docstrings for `ULift` and `PLift`, making their
style consistent with the others.
2025-03-20 10:52:48 +00:00
Paul Reichert
d2c35fd39d feat: more tree map lemmas for minKey? (#7556)
This PR provides lemmas about the tree map function `minKey?` and its
interaction with other functions for which lemmas already exist.

---------

Co-authored-by: Paul Reichert <datokrat@users.noreply.github.com>
2025-03-20 10:40:30 +00:00
David Thrane Christiansen
cbfb9e482f doc: review of Nat docstrings (#7552)
This PR adds missing `Nat` docstrings and makes their style consistent.

---------

Co-authored-by: Bhavik Mehta <bm489@cam.ac.uk>
2025-03-20 09:13:36 +00:00
Sebastian Ullrich
1fb4a32c8d fix: avoid follow-up kernel errors (#7570)
Asynchronous elaboration means that constants can exist in the elab
environment while failing to be added to the kernel environment, avoid
the latter by falling back to axioms there
2025-03-20 09:11:25 +00:00
Sebastian Ullrich
f42a28f718 chore: revert "perf: avoid taking mutex on task deactivation" (#7590)
Likely introduced segfaults.

Reverts leanprover/lean4#7572
2025-03-20 07:04:50 +00:00
Mac Malone
160ca476a1 chore: USE_LAKE touchups (#7581)
This PR adds some documentation to the Lean's `lakefile.toml` and makes
a few tweaks required to get `USE_LAKE` working properly on Windows. It
also adds a `stage1-configure` step target so the Lake configuration
files can be generated without performing a build of stage 1. This
enables one to build stage 0 and configure Lake via CMake and then use
Lake instead of CMake to build stage 1.

Partly adapted from #7505.
2025-03-20 06:27:22 +00:00
Lean stage0 autoupdater
17f67df257 chore: update stage0 2025-03-20 05:52:03 +00:00
Mac Malone
10f0adc9f9 feat: lake: thin libraries for static.export (#7586)
This PR changes the `static.export` facet for Lean libraries to produce
thin static libraries.

Static libraries with explicitly exported symbols are only necessary on
Windows (where symbol counts are a concern) and are usually used as part
of local build process and not distributed (as they are in Lean's
build). Thus, it seems reasonable to make them unilaterally thin. They
also need to be thin for the Lean build with Lake.
2025-03-20 04:53:35 +00:00
Mac Malone
a67de7ebda fix: lake: use response files on Windows to avoid CLI length limits (#7576)
This PR changes Lake to produce and use response files on Windows when
building executables and libraries (static and shared). This is done to
avoid potentially exceeding Windows command line length limits.

Closes #4159.
2025-03-20 02:58:10 +00:00
Leonardo de Moura
08af091a1c chore: missing normalization rules for cutsat (#7583) 2025-03-20 01:39:16 +00:00
Leonardo de Moura
22b327f077 test: cutsat (#7582)
Additional tests for cutsat
2025-03-20 00:46:07 +00:00
Leonardo de Moura
497ac70c38 feat: improve cutsat counterexamples (#7579)
This PR improves the counterexamples produced by the cutsat procedure,
and adds proper support for `Nat`. Before this PR, the assignment for an
natural variable `x` would be represented as `NatCast.natCast x`.
2025-03-19 19:27:40 +00:00
Sebastian Ullrich
a5348f4bdc perf: avoid taking mutex on task deactivation (#7572) 2025-03-19 15:59:45 +00:00
Sofia Rodrigues
d7d1754e69 feat: socket support using LibUV (#6683)
This PR introduces TCP socket support using the LibUV library, enabling
asynchronous I/O operations with it.

---------

Co-authored-by: Henrik Böving <hargonix@gmail.com>
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
2025-03-19 13:54:51 +00:00
Kim Morrison
720f6fca94 chore: fix name of Nat.mul_add_lt_is_or (#7563) 2025-03-19 11:23:03 +00:00
Paul Reichert
a634b96f6d feat: tree map lemmas for minKey? (#7437)
This PR provides (some but not all) lemmas about the tree map function
`minKey?`.
2025-03-19 09:54:33 +00:00
Lean stage0 autoupdater
9821bd9707 chore: update stage0 2025-03-19 10:13:04 +00:00
Kim Morrison
0f781136e7 chore: remove @[simp] from Int.neg_mul and Int.mul_neg (#7559)
This PR removes `@[simp]` from `Int.neg_mul` and `Int.mul_neg`. These
simp lemmas were interfering with normalization of numerals in `simp
+arith`.
2025-03-19 09:21:18 +00:00
Joachim Breitner
41a2e9af19 feat: well-founded recursion: opaque well-foundedness proofs (#5182)
This PR makes functions defined by well-founded recursion use an
`opaque` well-founded proof by default. This reliably prevents kernel
reduction of such definitions and proofs, which tends to be
prohibitively slow (fixes #2171), and which regularly causes
hard-to-debug kernel type-checking failures. This changes renders
`unseal` ineffective for such definitions. To avoid the opaque proof,
annotate the function definition with `@[semireducible]`.
2025-03-19 09:21:04 +00:00
Paul Reichert
bf241f9e86 feat: List.min? lemmas and Option.bind_congr (#7529)
This PR upstreams `bind_congr` from Mathlib and proves that the minimum
of a sorted list is its head and weakens the antisymmetry condition of
`min?_eq_some_iff`. Instead of requiring an `Std.Antisymm` instance,
`min?_eq_some_iff` now only expects a proof that the relation is
antisymmetric *on the elements of the list*. If the new premise is left
out, an autoparam will try to derive it from `Std.Antisymm`, so existing
usages of the theorem will most likely continue to work.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-19 07:33:49 +00:00
David Thrane Christiansen
a97813e11f doc: review docstrings for syntax-related operators in manual (#7534)
This PR adds missing `Syntax`-related docstrings and makes the existing
ones consistent in style with the others.
2025-03-19 05:15:05 +00:00
David Thrane Christiansen
1b0168d7b3 doc: docstring review for System and System.FilePath (#7523)
This PR adds missing docstrings and makes docstring style consistent for
`System` and `System.FilePath`.
2025-03-19 05:14:35 +00:00
David Thrane Christiansen
dc57365e95 doc: review docstrings for Thunk (#7528)
This PR makes the docstrings for `Thunk` consistent with the style of
the others.
2025-03-19 05:14:20 +00:00
Leonardo de Moura
174145929f test: omega test suite with grind (#7562)
We have removed tests about `Fin` and `BitVec` since these features are
not supported in `grind` yet.
2025-03-19 02:04:03 +00:00
Mac Malone
75300d30d3 refactor: lake: unified target config declarations (#7543)
This PR unifies the configuration declarations of dynamic targets,
external libraries, Lean libraries, and Lean executables into a single
data type stored in a unified map within a package.

As a side-effect of these changes, auto-completion now also works on an
empty configuration (after the `where`).

**Breaking change:** Users can no longer define multiple targets with
the same name but different kinds (e.g., a Lean executable and a Lean
library both named `foo`). This should not effect most users as the Lake
DSL already discouraged this.
2025-03-19 01:14:02 +00:00
Leonardo de Moura
2946ba04d5 fix: assert that nonlinear Nat terms are nonneg in cutsat (#7561)
This PR fixes the support for nonlinear `Nat` terms in cutsat. For
example, cutsat was failing in the following example
```lean
example (i j k l : Nat) : i / j + k + l - k = i / j + l := by grind
```
because we were not adding the fact that `i / j` is non negative when we
inject the `Nat` expression into `Int`.
2025-03-19 00:52:04 +00:00
Joachim Breitner
3857603dbb feat: Nat.{div,mod} to use fuel, not fix (#7558)
This PR changes the definition of `Nat.div` and `Nat.mod` to use a
structurally recursive, fuel-based implementation rather than
well-founded recursion. This leads to more predicable reduction behavior
in the kernel.

`Nat.div` and `Nat.mod` are somewhat special because the kernel has
native reduction for them when applied to literals. But sometimes this
does not kick in, and the kernel has to unfold `Nat.div`/`Nat.mod` (e.g.
in `lazy_delta_reduction` when there are open terms around). In these
cases we want a well-behaved definition.

We really do not want to reduce proofs in the kernel, which we want to
prevent anyways well-founded recursion (to be prevented by #5182).

Hence we avoid well-founded recursion here, and use a (somewhat
standard) translation to a fuel-based definition.

(If this idiom is needed more often we could even support it in Lean
with `termination_by +fuel <measure>` rather easily.)
2025-03-18 23:08:42 +00:00
Leonardo de Moura
389537cf0e fix: consistent term order in linear integer normalization (#7560)
This PR ensures that we use the same ordering to normalize linear `Int`
terms and relations. This change affects `simp +arith` and `grind`
normalizer.

This consistency is important in the cutsat procedure. We want to avoid
a situation where the cutsat state contains both "atoms":
- `「(NatCast.natCast x + NatCast.natCast y) % 8」`
- `「(NatCast.natCast y + NatCast.natCast x) % 8」`

This was happening because we were using different orderings for
(nested) terms and relations (`=`, `<=`).
2025-03-18 23:04:06 +00:00
Wojciech Rozowski
134d11f1a3 fix: ignore optParams in isNatCmp (#7551)
This PR changes `isNatCmp` to ignore optional arguments annotations,
when checking for `<`-like comparison between elements of `Nat`. That
previously caused `guessLex` to fail when checking termination of a
function, whose signature involved an optional argument of the type
`Nat`.

Closes https://github.com/leanprover/lean4/issues/7458
2025-03-18 21:21:43 +00:00
David Thrane Christiansen
404a931219 doc: review funext docstring (#7535)
This PR revises the docstring for `funext`, making it more concise and
adding a reference to the manual for more details.

This revised docstring is less technical, while still capturing the most
important points of the prior one.
2025-03-18 20:26:36 +00:00
Leonardo de Moura
e288e9266b fix: bad normalization rule in grind, and missing dsimproc (#7553)
This PR removes a bad normalization rule in `grind`, and adds a missing
dsimproc.
2025-03-18 18:32:25 +00:00
Sebastian Ullrich
53fcae031e perf: async optimizations for Init.Data.BitVec.Lemmas (#7546) 2025-03-18 12:56:16 +00:00
Markus Himmel
d66abc0fc0 feat: lemmas about operations on finite unsigned integers (#7484)
This PR adds some lemmas about operations defined on `UIntX`
2025-03-18 10:52:54 +00:00
Markus Himmel
6a202f5acb feat: Nat, Fin and BitVec theorems required for unsigned integers (#7522)
This PR splits off the required theory about `Nat`, `Fin` and `BitVec`
from #7484.
2025-03-18 08:35:02 +00:00
Siddharth
4e83f23955 feat: bv_normalize pass: AC normalization of multiplication (#7461)
This PR introduces a bitvector associativity/commutativity normalization
on bitvector terms of the form `(a * b) = (c * d)` for `a, b, c, d`
bitvectors. This mirrors Bitwuzla's `PassNormalize::process`'s
`PassNormalize::normalize_eq_add_mul`.

For example, `x₁ * (y₁ * z) = x₂ * (y₂ * z)` is normalized to `z * (x₁ *
y₁) = z * (x₂ * y₂)`,
pulling the shared variable `z` to the front on both sides. The PR also
replaces the use of `ac_nf` in the normalization pass of `bv_decide`.

Note that this is based on Bitwuzla's normalizer, and we eventually want
to have support for bitvector addition normalization as well. However,
since we currently lack a `ring` equivalent for bitvectors, we cannot
currently justify rewrites such as `x + x + x → 3 * x`. Similarly, we
leave the implementation of `PassNormalize::normalize_comm_assoc`, which
is called when the toplevel terms are different for a subsequent patch.

For posterity, we record the precise location in Bitwuzla where the
implemented codepath occurs:
```cpp
-- d1f1bc2ad3/src/preprocess/pass/normalize.cpp (L1550-L1554)
        Kind k = cur.kind();
        if (k == Kind::EQUAL && children[0].kind() == children[1].kind()
            && (children[0].kind() == Kind::BV_ADD
                || children[0].kind() == Kind::BV_MUL))
        {
          auto [res, norm] = normalize_eq_add_mul(children[0], children[1]);
          ...
```

---------

Co-authored-by: Henrik Böving <hargonix@gmail.com>
Co-authored-by: Tobias Grosser <github@grosser.es>
2025-03-18 08:28:35 +00:00
David Thrane Christiansen
5d91ed01b7 doc: review String docstrings (#7506)
This PR adds missing `String` docstrings and makes the existing ones
consistent in style.
2025-03-18 04:36:49 +00:00
Kim Morrison
ce138e1cec fix: correct names in library lemmas (#7541)
This PR corrects names of a number of lemmas, where the incorrect name
was identified automatically by a
[tool](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/automatic.20spelling.20generation.20.26.20comparison/near/505760384)
written by @Rob23oba.
2025-03-18 03:50:03 +00:00
Leonardo de Moura
0e598c96c9 feat: add [grind cases eager] Subtype (#7540)
This PR adds `[grind cases eager]` attribute to `Subtype`. See new test.
2025-03-18 01:19:22 +00:00
Leonardo de Moura
dad9b18d49 fix: missing reset at decision stack in cutsat (#7538)
This PR fixes a bug in the cutsat model construction. It was not
resetting the decision stack at the end of the search.
2025-03-18 00:21:56 +00:00
Leonardo de Moura
a638e2e207 feat: Int.toNat and Int.natAbst in cutsat (#7537)
This PR implements support for `Int.natAbs` and `Int.toNat` in the
cutsat procedure.
2025-03-17 23:29:21 +00:00
Leonardo de Moura
a0acbd77ea feat: not divides in cutsat (#7536)
This PR implements support for `¬ d ∣ p` in the cutsat procedure.
2025-03-17 22:29:42 +00:00
Joachim Breitner
a26084c433 refactor: Int.div: avoid using unseal (#7533)
In preparation for #5182 (and arguably good practice anyways).
2025-03-17 20:29:27 +00:00
Leonardo de Moura
798da80459 fix: grind push new fact (#7532)
This PR fixes the procedure for putting new facts into the `grind`
"to-do" list. It ensures the new facts are preprocessed. This PR also
removes some of the clutter in the `Nat.sub` support.
2025-03-17 19:14:08 +00:00
Lean stage0 autoupdater
5513f6a468 chore: update stage0 2025-03-17 19:01:29 +00:00
David Thrane Christiansen
70fb253739 doc: review of Array docstrings for manual (#7492)
This PR adds missing `Array` docstrings and makes their style
consistent.
2025-03-17 18:22:01 +00:00
jrr6
4b406b6d5f chore: remove comment from src/stdlib_flags.h (#7531)
This PR removes a misplaced comment from `src/stdlib_flags.h` introduced
by #7425 that was intended to (ephemerally) go in
`stage0/src/stdlib_flags.h`.
2025-03-17 18:07:58 +00:00
David Thrane Christiansen
1a3614616d doc: review docstrings for IO (#7476)
This PR adds missing docstrings for `IO` and related code and makes the
style of the existing docstrings consistent.
2025-03-17 17:59:44 +00:00
David Thrane Christiansen
c53b0c99de fix: broken docstring examples (#7526)
This PR fixes docstring breakage from #7516.
2025-03-17 17:59:03 +00:00
Henrik Böving
5a5e83c26c refactor: the AIG framework to track negations in a more efficient way (#7381)
This PR refactors the AIG datastructures that underly bv_decide in order
to allow a better tracking of negations in the circuit. This refactor
has two effects, for one adding full constant folding to the AIG
framework and secondly enabling us to add further simplifications from
the Brummayer Biere paper in the future which was previously
architecturally impossible.
2025-03-17 17:33:49 +00:00
Henrik Böving
5e0648fe98 feat: bv_decide rewrites around concat, extract and multplication (#7527)
This PR adds the BV_EXTRACT_CONCAT_LHS_RHS, NORM_BV_ADD_MUL and
NORM_BV_SHL_NEG rewrite from Bitwuzla as well as a reduction from
getLsbD to extractLsb' to bv_decide.
2025-03-17 16:01:15 +00:00
Henrik Böving
49819dad16 perf: Add RefVec.emptyWithCapacity to the AIG framework (#7521)
This PR adds the equivalent of `Array.emptyWithCapacity` to the AIG
framework and applies it to `bv_decide`. This is particularly useful as
we are only working with capacities that are always known at run time so
we should never have to reallocate a `RefVec`.
2025-03-17 13:02:51 +00:00
Luisa Cicolini
594587541c feat: add Bitvec.[(toInt, toFin)_twoPow, toNat_twoPow_of_le, toNat_twoPow_of_lt, toNat_twoPow_eq_ite] (#7225)
This PR contains `BitVec.(toInt, toFin)_twoPow` theorems, completing the
API for `BitVec.*_twoPow`. It also expands the `toNat_twoPow` API with
`toNat_twoPow_of_le`, `toNat_twoPow_of_lt`, as well as
`toNat_twoPow_eq_if` and moves `msb_twoPow` up, as it is used in the
`toInt_msb` proof.

---------

Co-authored-by: Henrik Böving <hargonix@gmail.com>
2025-03-17 12:51:58 +00:00
Siddharth
6df6011641 feat: BitVec.shiftLeft_neg_eq_neg_shiftLeft (#7508)
This PR shows that negation commutes with left shift, which is the
Bitwuzla rewrite
[NORM_BV_SHL_NEG](e09c50818b/src/rewrite/rewrites_bv_norm.cpp (L142-L148)).

```lean
theorem shiftLeft_neg_eq_neg_shiftLeft {x : BitVec w} {y : Nat} :
    (-x) <<< y = - (x <<< y)
```

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2025-03-17 11:54:43 +00:00
Rob23oba
e77b528ef5 perf: reduce elaboration time and proof size of tree map internals (#7459)
There are several things done here:
1. Use the modified `simp_to_model` which already exists in hash maps.
This version of `simp_to_model` allows specifying the query operations
to use in addition to the modifying operations. This is mostly to
improve elaboration time and actually increases olean size.
2. Instead of proving `toListModel_balance` directly, we write
`toListModel_balanceₘ` and use that instead (this saves ~3 MB).
3. Use `fun_cases` and `dsimp` instead of `rw [x.eq_def]` more
frequently in `Balancing.olean` (this saves a bit over 2 MB).
4. Mark `updateCell` and other functions dependent on it as
`noncomputable`. The main problem with `updateCell` is how other
functions, in particular `glue`, get recursively inlined, which blows
the size of the IR (this saves ~1 MB).
5. Instead of using `simp_to_model` to prove results on `insert!`,
`erase!`, etc., `simpa`s are used now, e.g. `simpa only
[insert_eq_insert!] using isEmpty_insert h`. This mainly improves
elaboration time although the olean size also goes down by ~0.3 MB.
2025-03-17 10:05:49 +00:00
Markus Himmel
6153474c00 feat: Neg instance for unsigned integers (#7487)
This PR adds the instance `Neg UInt8`.

This useful if you want to think about finite unsigned integers as a
commutative ring.
2025-03-17 09:06:14 +00:00
Siddharth
654c3781c4 feat: BitVec.neg_mul_not_eq_add_mul (#7493)
This PR implements the Bitwuzla rewrite rule
[NORM_BV_ADD_MUL](e09c50818b/src/rewrite/rewrites_bv_norm.cpp (L19-L23)),
and the associated lemmas to allow for expedient rewriting:

```lean
theorem neg_add_mul_eq_mul_not {x y : BitVec w} : - (x + x * y) = x * ~~~ y
```

---------

Co-authored-by: Henrik Böving <hargonix@gmail.com>
2025-03-17 08:54:56 +00:00
Kim Morrison
d32a7b250a chore: remove >6 month old deprecations (#7518) 2025-03-17 04:42:05 +00:00
Kim Morrison
53abb99a81 fix: make List/Array modify argument order consistent (#7516)
This PR changes the order of arguments for `List.modify` and
`List.insertIdx`, making them consistent with `Array`.
2025-03-17 04:36:05 +00:00
Leonardo de Moura
e7cde1180b fix: simp +arith (#7515)
This PR fixes another bug in `simp +arith`. This bug was affecting
`grind`. See new test for an example.
2025-03-17 03:11:48 +00:00
Leonardo de Moura
318c782ea7 feat: missing normalization rules for div and mod in grind (#7514)
This PR adds more missing normalization rules for `div` and `mod` to
`grind`.
2025-03-16 23:00:12 +00:00
Leonardo de Moura
0da54f517a fix: missing Nat div and mod norm rules in grind (#7512)
This PR adds missing normalization rules for `Nat` div and mod to the
`grind` tactic.
2025-03-16 21:23:49 +00:00
Leonardo de Moura
1284d43ad7 fix: simp +arith (#7511)
This PR fixes two bugs in `simp +arith` that were preventing specific
subterms from being normalized.
2025-03-16 20:24:51 +00:00
Leonardo de Moura
71b2b67a12 feat: exfalso in grind (#7510)
This PR ensures that `grind` can be used as a more powerful
`contradiction` tactic, sparing the user from having to type `exfalso;
grind` or `intros; exfalso; grind`.
2025-03-16 17:25:19 +00:00
Henrik Böving
84a4e37f1b perf: disable implicitDefEqProofs in bv_decide (#7509)
This PR disables the `implicitDefEqProofs` simp option in the
preprocessor of `bv_decide` in order to account for regressions caused
by #7387.

These regressions were noticed by @abdoo8080 while benchmarking on
SMTLIB:
- 07/03/2025: 30,661 with kernel, 35,153 without kernel
- 14/03/2025: 26,405 with kernel, 35,797 without kernel

I performed testing on a bunch of randomly failing problems from the
regressed set and all of them seem to pass again.

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
2025-03-16 14:45:28 +00:00
Henrik Böving
6f16a535f8 perf: speedup bv_decide's LRAT checker by improving input validaton (#7491)
This PR achieves a speed up in bv_decide's LRAT checker by improving its
input validation.

When the LRAT checker works on a clause it needs to know that the clause
has no duplicate literals and is not tautological (i.e. doesn't contain
the same variable in different polarities). Previously this was done
using a naive quadratic algorithm, now we check the property using a
HashMap in linear time. Beyond this there is also a few micro
optimizations.
Together they improve the runtime on the SMTLIB problem
`non-incremental/QF_BV/20210312-Bouvier/vlsat3_a15.smt2` from `1:25.31`
to `1:01.32` minutes (where 39 seconds of this run time are the SAT
solver and thus completely unaffected by the optimization)

Co-authored-by: @JOSHCLUNE

---------

Co-authored-by: JOSHCLUNE <josh.seth.clune@gmail.com>
2025-03-16 14:29:33 +00:00
Leonardo de Moura
6cbb8876d6 feat: Nat.sub in cutsat (#7503)
This PR implements support for `Nat.sub` in cutsat
2025-03-16 03:03:36 +00:00
Leonardo de Moura
ae81567fbe feat: Nat div/mod in cutsat (#7502)
This PR implements support for `Nat` div and mod in the cutsat
procedure.
2025-03-16 00:29:43 +00:00
Leonardo de Moura
b7354aacaa feat: Nat equalities and disequalities in cutsat (#7501)
This PR implements support for `Nat` equalities and disequalities in the
cutsat procedure.
2025-03-15 21:24:04 +00:00
Sebastian Ullrich
1dc3626ff7 perf: remove most remaining async blockers in Init.Data.List.Sublist (#7500) 2025-03-15 15:26:06 +00:00
Sebastian Ullrich
a788e6aa67 perf: remove more async blockers (#7497) 2025-03-15 11:07:04 +00:00
Sebastian Ullrich
0f06393149 chore: USE_LAKE: integrate into CMake (#4466)
With `USE_LAKE=ON`, only linking is now left to the Makefile.

TODO:
* include stage 0 changes in Lake's trace. This is an issue already on
master but prevents us from using this PR to put .oleans in an Actions
cache.
2025-03-15 08:58:01 +00:00
Sebastian Ullrich
141e52685c fix: include async elaboration time in elaboration profile (#7496) 2025-03-15 07:59:03 +00:00
Lean stage0 autoupdater
10b7c4e46e chore: update stage0 2025-03-15 08:02:41 +00:00
Sebastian Ullrich
41c58002f1 feat: enable Elab.async by default (#7485)
...after successful test on Mathlib
2025-03-15 07:24:52 +00:00
Leonardo de Moura
d5f01f2db1 feat: Nat divisibility constraints in cutsat (#7495)
This PR implements support for `Nat` divisibility constraints in the
cutsat procedure.
2025-03-15 03:46:47 +00:00
Leonardo de Moura
c8aae00847 feat: Nat inequalities in cutsat (#7494)
This PR implements support for `Nat` inequalities in the cutsat
procedure.
2025-03-15 00:43:18 +00:00
Siddharth
1bbd2c183b feat: BitVec.extract_Lsb'_append_[ite|of_lt|of_le] (#7482)
This PR implements the
[BV_EXTRACT_CONCAT](6a1a768987/src/rewrite/rewrites_bv.cpp (L1264))
rule from Bitwuzla, which explains how to extract bits from an append.
We first prove a 'master theorem' which has the full case analysis, from
which we rapidly derive the necessary `BV_EXTRACT_CONCAT` theorems:

```lean
theorem extractLsb'_append_eq_ite {v w} {xhi : BitVec v} {xlo : BitVec w} {start len : Nat} :
    extractLsb' start len (xhi ++ xlo) =
    if hstart : start < w
    then
      if hlen : start + len < w
      then extractLsb' start len xlo
      else
        (((extractLsb' (start - w) (len - (w - start)) xhi) ++
            extractLsb' start (w - start) xlo)).cast (by omega)
    else
      extractLsb' (start - w) len xhi

theorem extractLsb'_append_eq_of_lt {v w} {xhi : BitVec v} {xlo : BitVec w}
    {start len : Nat} (h : start + len < w) :
    extractLsb' start len (xhi ++ xlo) = extractLsb' start len xlo

theorem extractLsb'_append_eq_of_le {v w} {xhi : BitVec v} {xlo : BitVec w}
    {start len : Nat} (h : w ≤ start) :
    extractLsb' start len (xhi ++ xlo) = extractLsb' (start - w) len xhi
```

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2025-03-14 18:25:50 +00:00
Henrik Böving
b55a5b0826 feat: add BitVec.add_neg_mul to bv_decide (#7486)
This PR adds the BitVec.add_neg_mul rule introduced in #7481 to
bv_decide's preprocessor.
2025-03-14 15:28:20 +00:00
Sebastian Ullrich
eeca0ce96b perf: Environment blocker removals from async-proofs branch (#7483) 2025-03-14 13:37:01 +00:00
Siddharth
2cb89823f3 feat: BitVec.BV_ADD_NEG_MUL (#7481)
This PR implements the Bitwuzla rewrites [BV_ADD_NEG_MUL](), and
associated lemmas to make the proof streamlined. ```bvneg (bvadd a
(bvmul a b)) = (bvmul a (bvnot b))```, or spelled as lean:

```lean
theorem neg_add_mul_eq_mul_not {x y : BitVec w} :
    - (x + x * y) = (x * ~~~ y)
```

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2025-03-14 13:21:17 +00:00
Henrik Böving
297be24c0d feat: bv_decide rewrites around ult, signExtend and extractLsb (#7480)
This PR adds the necessary rewrites for the Bitwuzla rules
BV_ULT_SPECIAL_CONST, BV_SIGN_EXTEND_ELIM, TODO.
2025-03-14 09:55:44 +00:00
Lean stage0 autoupdater
e59f487bf0 chore: update stage0 2025-03-14 08:29:06 +00:00
Sebastian Ullrich
e1d15946f7 feat: elaborate theorem bodies in parallel (#7084)
This PR enables the elaboration of theorem bodies, i.e. proofs, to
happen in parallel to each other as well as to other elaboration tasks.

Specifically, to be eligible for parallel proof elaboration,
* the theorem must not be in a `mutual` block
* `deprecated.oldSectionVars` must not be set
* `Elab.async` must be set (currently defaults to `true` in the language
server, `false` on the cmdline)

To be activated for downstream projects (i.e. in stage 1) pending
further Mathlib validation.
2025-03-14 07:50:42 +00:00
Eric Wieser
5c333d88c0 feat: mark forIn_pure_yield lemmas simp (#7433)
This PR makes `simp` able to simplify basic `for` loops in monads other
than `Id`.

This is some prework for #7352, where the `Id` lemmas will be
deprecated.
2025-03-14 00:28:23 +00:00
Sebastian Ullrich
07ee2eea21 fix: report replay kernel errors as standard diagnostics (#7471)
Avoids panics from follow-up cancellation errors

Fixes #7462
2025-03-13 18:45:46 +00:00
Henrik Böving
af82d75e86 fix: bv_decide don't analyze terms under binders by accident (#7477)
This PR ensures that bv_decide doesn't accidentally operate on terms
underneath binders. As there is currently no binder construct that is in
the supported fragment of bv_decide this changes nothing about the proof
power.

Closes #7475
2025-03-13 16:47:20 +00:00
David Thrane Christiansen
25179352b4 doc: review List docstrings for manual (#7452)
This PR makes the style of all `List` docstrings that appear in the
language reference consistent.

Relies on #7240 for links and example formatting.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2025-03-13 16:10:06 +00:00
David Thrane Christiansen
06c57826ae doc: manual docstring review for smaller namespaces (#7365)
This PR updates docstrings and adds some that are missing.
2025-03-13 16:09:37 +00:00
Sebastian Ullrich
044e3b1b56 fix: heartbeats from realizeConst should be ignored (#7473)
Avoids nondeterministic counting from racing threads
2025-03-13 15:10:29 +00:00
Sebastian Ullrich
96f9ee2a41 feat: allow async elab tasks to contribute to info trees reported to linters and request handlers (#7457)
This PR ensures info tree users such as linters and request handlers
have access to info subtrees created by async elab task by introducing
API to leave holes filled by such tasks.

**Breaking change**: other metaprogramming users of
`Command.State.infoState` may need to call `InfoState.substituteLazy` on
it manually to fill all holes.
2025-03-13 15:09:00 +00:00
Sebastian Ullrich
0f3d426591 chore: fix confusing Environment.replayConsts parameter order (#7472) 2025-03-13 12:35:45 +00:00
Sebastian Ullrich
a014ae1001 fix: make Term.mkAuxName async-compatible (#7468) 2025-03-13 12:24:24 +00:00
Lean stage0 autoupdater
137f559520 chore: update stage0 2025-03-13 11:55:08 +00:00
Siddharth
3d6d51d2c6 feat: BitVec.lt_allOnes (#7465)
This PR adds the theorem:  
```lean
theorem lt_allOnes_iff {x : BitVec w} : x < allOnes w ↔ x ≠ allOnes w
```
to simplify comparisons against `-1#w`. This is a corollary of the
existing lemma:
```lean
theorem allOnes_le_iff {x : BitVec w} : allOnes w ≤ x ↔ x = allOnes w
```
2025-03-13 09:43:17 +00:00
Sebastian Ullrich
3786ad6d0c chore: reset stdlib_flags (#7469)
Changed accidentally at
a2cb435aa1 (diff-83fe8b23d47dfed772cebbb2d0f7809b137482ab0d5c5aea66fb5b8ccefa1898)
2025-03-13 09:40:27 +00:00
Paul Reichert
b16769f5a0 feat: new tree map lemmas for getKey (#7412)
This PR provides lemmas about the tree map that have been introduced to
the hash map in #7289.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-13 08:13:18 +00:00
Markus Himmel
4262ea14d6 fix: Repr instance for Int32 (#7467)
This PR fixes the `Repr Int32` instance, which was previously repeating
the `Repr Int16` instance due to a copy-and-paste error.
2025-03-13 06:24:42 +00:00
Kim Morrison
816da7120e feat: cleanup of Int simp lemmas (#7466)
This PR further cleans up simp lemmas for `Int`.
2025-03-13 06:07:19 +00:00
Kim Morrison
38ed354cdb feat: Nat.add_div_of_dvd_add_add_one (#7432)
This PR adds a consequence of `Nat.add_div` using a divisibility
hypothesis.
2025-03-13 05:40:34 +00:00
Kim Morrison
56ac94b591 chore: rename Array.mkEmpty to emptyWithCapacity (#7445)
This PR renames `Array.mkEmpty` to `emptyWithCapacity`. (Similarly for
`ByteArray` and `FloatArray`.)
2025-03-12 23:19:17 +00:00
Lean stage0 autoupdater
b78352ec9d chore: update stage0 2025-03-12 23:48:59 +00:00
Kim Morrison
1feae7abe1 fix: indenting in release notes script (#7326)
This PR updates the release notes script to better indent PR
descriptions.
2025-03-12 23:02:02 +00:00
Kim Morrison
a2cb435aa1 chore: rename HashMap.empty to HashMap.emptyWithCapacity (#7447)
This PR renames `.empty` with `.emptyWithCapacity`. This is a companion
to #7445 for `Array`.
2025-03-12 23:01:18 +00:00
David Thrane Christiansen
c3f61ba3a2 chore: fix typo in test (#7460)
This PR fixes a minor typo in a test.
2025-03-12 16:43:35 +00:00
Siddharth
8850f9e9aa feat: BitVec.signExtend_eq_append_extractLsb' (#7454)
This PR implements the bitwuzla rule
[BV_SIGN_EXTEND_ELIM](https://github.com/bitwuzla/bitwuzla/blob/main/src/rewrite/rewrites_bv.cpp#L3638-L3663),
which rewrites a `signExtend x` as an `append` of the appropriate sign
bits, followed by the bits of `x`.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
2025-03-12 15:40:23 +00:00
Pim Otte
2363d2fa87 chore: readd "(kernel)" to kernel error message (#7453)
This PR adds "(kernel)" to the message for the kernel-level application
type mismatch error.

It appears to have been accidentally removed in
b705142ae4.
2025-03-12 11:27:42 +00:00
Lean stage0 autoupdater
d1d2f215ad chore: update stage0 2025-03-12 10:19:24 +00:00
David Thrane Christiansen
eb58f46ce7 feat: language reference links and examples in docstrings (#7240)
This PR adds a canonical syntax for linking to sections in the language
reference along with formatting of examples in docstrings according to
the docstring style guide.


Docstrings are now pre-processed as follows:

* Output included as part of examples is shown with leading line comment
indicators in hovers

* URLs of the form `lean-manual://section/section-id` are rewritten to
links that point at the corresponding section in the Lean reference
manual. The reference manual's base URL is configured when Lean is built
and can be overridden with the `LEAN_MANUAL_ROOT` environment variable.
This way, releases can point documentation links to the correct
snapshot, and users can use their own, e.g. for offline reading.

Manual URLs in docstrings are validated when the docstring is added. The
presence of a URL starting with `lean-manual://` that is not a
syntactically valid section link causes the docstring to be rejected.
This allows for future extensibility to the set of allowed links. There
is no validation that the linked-to section actually exists. To provide
the best possible error messages in case of validation failures,
`Lean.addDocString` now takes a `TSyntax ``docComment` instead of a
string; clients should adapt by removing the step that extracts the
string, or by calling the lower-level `addDocStringCore` in cases where
the docstring in question is obtained from the environment and has thus
already had its links validated.

A stage0 update is required to make the documentation site configurable
at build time and for releases. A local commit on top of a stage0 update
that will be sent in a followup PR includes the configurable reference
manual root and updates to the release checklist.

---------

Co-authored-by: Marc Huisinga <mhuisi@protonmail.com>
2025-03-12 09:17:27 +00:00
Markus Himmel
1a2345b47f chore: rename insert_emptyc_eq to insert_empty_eq (#7451)
This PR renames the member `insert_emptyc_eq` of the `LawfulSingleton`
typeclass to `insert_empty_eq` to conform to the recommended spelling of
`∅` as `empty`.

See also #7447.
2025-03-12 09:14:05 +00:00
Kim Morrison
c1d145e9d7 feat: revision of Nat/Int lemmas (#7435)
This PR reviews the `Nat` and `Int` API, making the interfaces more
consistent.
2025-03-12 05:52:09 +00:00
Kim Morrison
3a308324f6 chore: use notation in favour of .empty functions (#7446)
This PR prefers using `∅` instead of `.empty` functions. We may later
rename `.empty` functions to avoid the naming clash with
`EmptyCollection`, and to better express semantics of functions which
take an optional capacity argument.
2025-03-12 04:22:40 +00:00
Kim Morrison
bc2561f538 chore: better hypothesis for Vector.getElem_take (#7449)
Fixes a problematic hypothesis as reported on zulip: 
[#lean4 > Vector refactor @
💬](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Vector.20refactor/near/500330457).
2025-03-12 04:16:22 +00:00
Kim Morrison
ed89c2611e chore: fix duplicated namespaces (#7448) 2025-03-12 04:14:31 +00:00
Henrik Böving
2952cf81e6 feat: bv_decide rewrites for concatenation and extraction (#7441)
This PR adds the BV_CONCAT_CONST, BV_CONCAT_EXTRACT and ELIM_ZERO_EXTEND
rule from Bitwuzla to bv_decide.
2025-03-11 22:24:05 +00:00
Bhavik Mehta
589eff6187 doc: correct typo in PSigma projection docstrings (#7443)
These docstrings are for PSigma projections, so change them to refer to
PSigma rather than Sigma.
2025-03-11 18:36:24 +00:00
Sebastian Ullrich
7c5b423659 chore: unconditionally re-enable realizeConst (#7334)
To be merged when Mathlib adaption passes
2025-03-11 16:39:17 +00:00
jrr6
b1bd2c931c feat: allow turnstiles anywhere in location sequences (#7431)
This PR changes the syntax of location modifiers for tactics like `simp`
and `rw` (e.g., `simp at h ⊢`) to allow the turnstile `⊢` to appear
anywhere in the sequence of locations.

Closes #2278.
2025-03-11 15:34:40 +00:00
Henrik Böving
ce614bd830 chore: don't run MacOS aarch64 in merge queue (#7439)
This PR skips running MacOS aarch64 CI in merge queue but leaves it
enabled in PR and release CI.
2025-03-11 14:35:10 +00:00
Henrik Böving
1731f2f850 feat: add more constant related rewrites to bv_decide (#7438)
This PR adds the EQUAL_CONST_BV_ADD and BV_AND_CONST rules to
bv_decide's preprocessor.
2025-03-11 13:37:12 +00:00
Siddharth
bfe7b1fb34 feat: BitVec.extractLsb'_append_extractLsb'_eq_extractLsb' (#7427)
This PR implements the bitwuzla rule
[`BV_CONCAT_EXTRACT`](https://github.com/bitwuzla/bitwuzla/blob/main/src/rewrite/rewrites_bv.cpp#L1146-L1176).
This will be used by the bitblaster to simplify adjacent `extract`s
into a single `extract`.

We also implement the negated version of the rule,
which allows adjacent `not (extractLsb' _)` to be simplified into a
single `not (extractLsb' _)`.
2025-03-11 12:27:39 +00:00
Siddharth
0a14ec0978 feat: BitVec.setWidth_eq_append (#7424)
This PR proves Bitwuzla's rule
[`BV_ZERO_EXTEND_ELIM`](6a1a768987/src/rewrite/rewrites_bv.cpp (L4021-L4033)):

```lean
theorem setWidth_eq_append {v : Nat} {x : BitVec v} {w : Nat} (h : v ≤ w) :
    x.setWidth w = ((0#(w - v)) ++ x).cast (by omega) := by
```

We introduce a more general helper lemma for the above:

```lean
theorem setWidth_eq_append_extractLsb' {v : Nat} {x : BitVec v} {w : Nat} :
    x.setWidth w = ((0#(w - v)) ++ x.extractLsb' 0 (min v w)).cast (by omega)
```

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2025-03-11 12:26:30 +00:00
Henrik Böving
bb47469d1a feat: add simprocs for turning shifts by constants into extracts to bv_decide (#7436)
This PR adds simprocs that turn left and right shifts by constants into
extracts to bv_decide.
2025-03-11 10:09:16 +00:00
Tobias Grosser
e7e57d40c4 feat: add BitVec.[toNat|toFin|toInt]_[sshiftRight|sshiftRight'] (#7104)
This PR adds `BitVec.[toNat|toFin|toInt]_[sshiftRight|sshiftRight']`
plus variants with `of_msb_*`. While at it, we also add
`toInt_zero_length` and `toInt_of_zero_length`. In support of our main
theorem we add `toInt_shiftRight_lt` and `le_toInt_shiftRight`, which
make the main theorem automatically derivable via omega.

We also add four shift lemmas for `Int`: `le_shiftRight_of_nonpos`,
`shiftRight_le_of_nonneg`, `le_shiftRight_of_nonneg`,
`shiftRight_le_of_nonpos`, as well as `emod_eq_add_self_emod`,
`ediv_nonpos_of_nonpos_of_neg `, and`bmod_eq_emod_of_lt `. For `Nat` we
add `shiftRight_le`.

Beyond the lemmas directly needed in the proof, we added a couple more
to ensure the API is complete.

We also fix the casing of `toFin_ushiftRight` and rename `lt_toInt` to
`two_mul_lt_toInt` to avoid `'`-ed lemmas.
2025-03-11 09:51:37 +00:00
Parth Shastri
7c0b72e2c5 fix: make the Subsingleton instance for Squash work for an arbitrary Sort (#7406)
This PR makes the instance for `Subsingleton (Squash α)` work for `α :
Sort u`.

Closes #7405

The fix removes some unused `section`/`variable` commands. They were
mistakenly kept when `EqvGen` was removed in 1d338c4.
2025-03-11 08:41:30 +00:00
Tobias Grosser
8fc8e8ed19 chore: generalize BitVec.toInt_[lt|le]' (#7420)
This PR generalizes `BitVec.toInt_[lt|le]'` to not require `0 < w`.
2025-03-11 06:20:27 +00:00
Kim Morrison
96947280df doc: reference mkEmpty in Array doc-string (#7430)
This PR explains how to use `Array.mkEmpty` to specify the capacity of a
new array, from the `Array` doc-string.
2025-03-10 22:28:22 +00:00
Henrik Böving
0af15f9b1d feat: bv_decide add BV_EXTRACT_FULL preprocessing rule (#7429)
This PR adds the BV_EXTRACT_FULL preprocessing rule from Bitwuzla to
bv_decide.
2025-03-10 22:08:59 +00:00
Lean stage0 autoupdater
dab4908317 chore: update stage0 2025-03-10 22:14:37 +00:00
jrr6
aca1d54514 refactor: add definitions to allow turnstiles anywhere in locations (#7425)
This PR adds definitions that will be required to allow to appear
turnstiles anywhere in tactic location specifiers.

This is the first (pre-stage0 update) half of #6992.
2025-03-10 21:18:00 +00:00
Lean stage0 autoupdater
817772e97b chore: update stage0 2025-03-10 20:18:34 +00:00
Siddharth
af8ec41014 feat: BitVec.extractLsb'_eq_self (#7426)
This PR adds the Bitwuzla rewrite rule
[`BV_EXTRACT_FULL`](6a1a768987/src/rewrite/rewrites_bv.cpp (L1236-L1253)),
which is useful for the bitblaster to simplify `extractLsb'` based
expressions.

```lean
theorem extractLsb'_eq_self (x : BitVec w) : x.extractLsb' 0 w = x
```
2025-03-10 19:16:25 +00:00
Marc Huisinga
51794c384a feat: parallel watchdog requests (#7223)
This PR implements parallel watchdog request processing so that requests
that are processed by the watchdog cannot block the main thread of the
watchdog anymore.

Since this shares the `References` data structure in the watchdog, we
adjust the `References` architecture to use `Std.TreeMap` instead of
`Std.HashMap`, so that updates to the data structure can still be
reasonably fast despite the sharing. This PR also optimizes the
`References` data structure a bit.
2025-03-10 18:46:25 +00:00
jrr6
acfc11ae42 fix: correctly collect let-rec fvars through delayed-assigned mvar (#7304)
This PR fixes an issue where nested `let rec` declarations within
`match` expressions or tactic blocks failed to compile if they were
nested within, and recursively called, a `let rec` that referenced a
variable bound by a containing declaration.

Closes #6927

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2025-03-10 18:13:48 +00:00
Sebastian Ullrich
9d39942189 fix: find realizations from other env branches (#7385) 2025-03-10 18:04:38 +00:00
Joachim Breitner
829522ba55 test: expand f91 test (#7421) 2025-03-10 17:15:54 +00:00
Lean stage0 autoupdater
d538e1cd90 chore: update stage0 2025-03-10 17:45:27 +00:00
Mac Malone
77609dcdc7 feat: lake: config field autocomplete in whitespace (#7393)
This PR adds autocompletion support for Lake configuration fields in the
Lean DSL at the indented whitespace after an existing field.
Autocompletion in the absence of any fields is currently still not
supported.

**Breaking change:** The nonstandard braced configuration syntax now
uses a semicolon `;` rather than a comma `,` as a separator. Indentation
can still be used as an alternative to the separator.
2025-03-10 15:37:39 +00:00
Lean stage0 autoupdater
22b6b49a43 chore: update stage0 2025-03-10 15:29:45 +00:00
Paul Reichert
f3c507ec57 feat: tree map lemmas for modify (#7419)
This PR provides lemmas about the tree map function `modify` and its
interactions with other functions for which lemmas already exist.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-10 14:35:24 +00:00
Henrik Böving
e0fa6a1792 feat: bv_decide support enum inductive matches with default branches (#7417)
This PR adds support for enum inductive matches with default branches to
bv_decide.
2025-03-10 14:05:04 +00:00
Eric Wieser
9a435b4f4a feat: lemmas about pure for {List,Array,Vector}.{mapM,foldlM,foldrM,anyM,allM,findM?,findSomeM?} (#7356)
This PR adds lemmas reducing monadic operations with `pure` to the
non-monadic counterparts.
2025-03-10 13:55:17 +00:00
Marc Huisinga
80b1ce8cad fix: language server dropping requests (#7178)
This PR fixes a race condition in the language server that would
sometimes cause it to drop requests and never respond to them when
editing the header of a file. This in turn could cause semantic
highlighting to stop functioning in VS Code, as VS Code would stop
emitting requests when a prior request was dropped, and also cause the
InfoView to become defective. It would also cause import auto-completion
to feel a bit wonky, since these requests were sometimes dropped. This
race condition has been present in the language server since its first
version in 2020.

This PR also reverts the futile fix attempt in #7130.

The specific race condition was that if the file worker crashed or had
to be restarted while a request was in flight in the file worker, then
we wouldn't correctly replay it in our watchdog crash-restart logic.
This PR adjusts this logic to fix this.
2025-03-10 13:45:17 +00:00
Paul Reichert
2ac0e4c061 fix: use getElem instead of get in the statements of hash map lemmas (#7418)
This PR renames several hash map lemmas (`get` -> `getElem`) and uses
`m[k]?` instead of `get? m k` (and also for `get!` and `get`).

BREAKING CHANGE: While many lemmas were renamed and the lemma with the
old signature was simply deprecated, some lemmas were changed without
renaming them. They now use the `getElem` variants instead of `get`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-10 13:31:30 +00:00
Markus Himmel
cdfec6971f feat: remaining lemmas about iterated conversions of finite types (#7414)
This PR adds the remaining lemmas about iterated conversions of finite
type that go through signed or unsigned bounded integers.
2025-03-10 12:58:30 +00:00
Markus Himmel
7365600cf8 feat: BitVec conversion lemmas (#7415)
This PR adds a few lemmas about the interactions of `BitVec` with `Fin`
and `Nat`.
2025-03-10 12:58:13 +00:00
Joachim Breitner
754bab442a feat: omega to abstract its own proofs (#5998)
This PR lets `omega` always abstract its own proofs into an auxiliary
definition. The size of the olean of Vector.Extract goes down from 20MB
to 5MB with this, overall stdlib olean size and build instruction count
go down 5%.

Needs #7362.
2025-03-10 12:39:30 +00:00
Marc Huisinga
4593ff50f0 fix: only log goals accomplished in language server (#7416)
This PR addresses a performance regression noticed at
https://github.com/leanprover/lean4/pull/7366#issuecomment-2708162029.
It also ensures that we also consider the current message log when
logging the goals accomplished message.


`Language.Lean.internal.cmdlineSnapshots` in `Lean.Language.Lean` is
moved to `Lean.internal.cmdlineSnapshots` in `Lean.CoreM` to make the
option available in the elaborator.
2025-03-10 12:17:10 +00:00
Sebastian Ullrich
6ecce365e9 feat: make more constructions async-compatible (#7384) 2025-03-10 09:56:30 +00:00
Paul Reichert
1d17119710 refactor: make DHashMap.Raw.foldRev(M) internal (#7380)
This PR moves `DHashMap.Raw.foldRev(M)` into `DHashMap.Raw.Internal`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-10 09:51:41 +00:00
Paul Reichert
9233d7a4d7 feat: tree map lemmas for alter (#7367)
This PR provides lemmas for the tree map functions `alter` and `modify`
and their interactions with other functions for which lemmas already
exist.

BREAKING CHANGE: The signature of `size_alter` was corrected for all
four hash map types. Instead of relying on the boolean operations
`contains` and `&&` in the if statements, we now use the `Prop`-based
operations `Membership` and `And`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-10 09:42:25 +00:00
Sebastian Ullrich
060e137599 chore: enforce awaiting-mathlib label (#7342) 2025-03-10 09:27:43 +00:00
Markus Himmel
7bfa8f6296 feat: finite type conversions (Nat/Int/Fin/BitVec -> IntX -> *) (#7368)
This PR adds lemmas for iterated conversions between finite types,
starting with something of type `Nat`/`Int`/`Fin`/`BitVec` and going
through `IntX`.
2025-03-10 05:53:41 +00:00
Leonardo de Moura
84c7e5db1f test: cutsat (#7411) 2025-03-10 03:30:36 +00:00
Joachim Breitner
c797525d2a fix: WellFounded preprocessing: use dsimp (#7409)
This PR allows the use of `dsimp` during preprocessing of well-founded
definitions. This fixes regressions when using `if-then-else` without
giving a name to the condition, but where the condition is needed for
the termination proof, in cases where that subexpression is reachable
only by dsimp, but not by simp (e.g. inside a dependent let)

Also fixes some preprocessing lemmas to not be bad simp lemmas (with
lambdas on the LHS, due to dot notation and unfortunate argument order)

This fixes #7408.
2025-03-09 22:19:16 +00:00
Henrik Böving
0714a7150b feat: add more multiplication lemmas to bv_normalize (#7407)
This PR adds rules for `-1#w * a = -a` and `a * -1#w = -a` to
bv_normalize as seen in Bitwuzla's BV_MUL_SPECIAL_CONST.

This allows us to solve 
```lean
example {a : BitVec 32} : a + -1 * a = 0 := by bv_normalize
```
which would previously time out.
2025-03-09 18:14:30 +00:00
Leonardo de Moura
9c36901728 chore: cutsat minor improvements (#7404) 2025-03-09 14:50:55 +00:00
Leonardo de Moura
da2d877019 fix: cutsat conflict resolution bug (#7403) 2025-03-09 03:58:30 +00:00
Mac Malone
ffc7ba0829 chore: lake: revert builtin inits, elabs, & macros (#7399)
This PR reverts the new builtin initializers, elaborators, and macros in
Lake back to non-builtin.

That is, it reverts the significant change of #7171. This is done to
potential solve the intermittent test failures Lake has been
experiencing on `master`, which I suspect may be caused by this change.
2025-03-09 01:52:50 +00:00
Leonardo de Moura
09161f6fdd chore: remove workaround (#7402) 2025-03-09 01:46:17 +00:00
Leonardo de Moura
8dc3c53240 feat: tight inequalities using divisibility constraints in cutsat (#7401)
This PR improves the cutsat model search procedure by tightening
inequalities using divisibility constraints.
2025-03-09 00:23:32 +00:00
Joachim Breitner
dd91d7e2e2 fix: bv_omega to use -implicitDefEqProofs (#7387)
This PR uses `-implicitDefEqProofs` in `bv_omega` to ensure it is not
affected by the change in #7386.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2025-03-09 00:13:14 +00:00
David Thrane Christiansen
599444e27e doc: docstrings for Id (#7204)
This PR adds docstrings for the `Id` monad.
2025-03-08 22:17:32 +00:00
David Thrane Christiansen
1a0d2b6fc1 doc: Char docstring proofreading (#7198)
This PR makes the docstrings in the `Char` namespace follow the
documentation conventions.

---------

Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
2025-03-08 22:17:01 +00:00
Cameron Zwarich
8d0093b43f fix: properly handle scoping of join point candidates in cce (#7398)
This PR fixes a scoping error in the cce (Common Case Elimination) pass
of the old code generator. This pass would create a join point for
common minor premises even if some of those premises were in the bodies
of locally defined functions, which results in an improperly scoped
reference to a join point. The fix is to save/restore candidates when
visiting a lambda.
2025-03-08 18:10:41 +00:00
Leonardo de Moura
d07897fc36 fix: Poly.mul p 0 (#7397)
This PR ensures that `Poly.mul p 0` always returns `Poly.num 0`.
2025-03-08 16:57:13 +00:00
Leonardo de Moura
bfe8e5a958 fix: bug in cutsat model construction (#7396)
This PR fixes a bug in the cutsat model construction. It was searching
for a solution in the wrong direction.
2025-03-08 15:58:20 +00:00
Rob23oba
b9f8a859e7 feat: equivalence on hash maps (#7341)
This PR adds an equivalence relation to the hash map with several lemmas
for it.
2025-03-08 10:44:12 +00:00
Leonardo de Moura
0d3ae7fde5 feat: infrastructure for supporting Nat in cutsat (#7394)
This PR adds infrastructure necessary for supporting `Nat` in the cutsat
procedure. It also makes the `grind` more robust.
2025-03-08 08:36:58 +00:00
David Thrane Christiansen
1bfccf88da doc: add missing Bool docstrings and review existing ones (#7246)
This PR updates existing docstrings for Bool and adds the missing ones.
2025-03-08 08:16:13 +00:00
Leonardo de Moura
565c6f3eb2 fix: if-then-else split + normalization issue in grind (#7392)
This PR fixes an issue in the `grind` tactic when case splitting on
if-then-else expressions.

It adds a new marker gadget that prevents `grind` for re-normalizing the
condition `c` of an if-then-else
expression. Without this marker, the negated condition `¬c` might be
rewritten into
an alternative form `c'`, which `grind` may not recognize as equivalent
to `¬c`.
As a result, `grind` could fail to propagate that `if c then a else b`
simplifies to `b`
in the `¬c` branch.
2025-03-07 23:05:59 +00:00
Henrik Böving
77ae842496 feat: bv_decide remove casts (#7390)
This PR makes bv_decide's preprocessing handle casts, as we are in the
constant BitVec fragment we should be able to always remove them using
BitVec.cast_eq.
2025-03-07 22:40:53 +00:00
Sebastian Ullrich
250b977616 feat: support weak options coming from lake setup-file (#7376)
This PR ensures `weak` options do not have to be repeated in both Lake
`leanOptions` and `moreServerOptions`.
2025-03-07 20:55:53 +00:00
Markus Himmel
a8a5c6cff1 feat: integer prerequisites for finite type lemmas (#7378)
This PR adds lemmas about `Int` that will be required in #7368.

Most notably, we add
```lean
@[simp] theorem neg_nonpos_iff (i : Int) : -i ≤ 0 ↔ 0 ≤ i
```
which causes some breakage but gets us closer to mathlib which has a
more general version of this that applies to `Int`.

Note also that the mathlib adaptation branch deletes the (unused in
mathlib) mathib lemma `Int.zero_le_ofNat` as there is now a
syntactically different (but definitionally equal) `Int.zero_le_ofNat`
in core.
2025-03-07 16:09:03 +00:00
Lean stage0 autoupdater
555f3d86fb chore: update stage0 2025-03-07 15:15:36 +00:00
Marc Huisinga
dc5eb40ca3 feat: 'unsolved goals' & 'goals accomplished' diagnostics (#7366)
This PR adds server-side support for dedicated 'unsolved goals' and
'goals accomplished' diagnostics that will have special support in the
Lean 4 VS Code extension. The special 'unsolved goals' diagnostic is
adapted from the 'unsolved goals' error diagnostic, while the 'goals
accomplished' diagnostic is issued when a `theorem` or `Prop`-typed
`example` has no errors or `sorry`s. The Lean 4 VS Code extension
companion PR is at leanprover/vscode-lean4#585.

Specifically, this PR extends the diagnostics served by the language
server with the following fields:
- `leanTags`: Custom tags that denote the kind of diagnostic that is
being served. As opposed to the `code`, `leanTags` should never be
displayed in the UI. Examples introduced by this PR are a tag to
distinguish 'unsolved goals' errors from other diagnostics, as well as a
tag to distinguish the new 'goals accomplished' diagnostic from other
diagnostics.
- `isSilent`: Whether a diagnostic should not be displayed as a regular
diagnostic in the editor. In VS Code, this means that the diagnostic is
displayed in the InfoView under 'Messages', but that it will not be
displayed under 'All Messages' and that it will also not be displayed
with a squiggly line.

The `isSilent` field is also implemented for `Message` so that silent
diagnostics can be logged in the elaborator. All code paths except for
the language server that display diagnostics to users are adjusted to
filter `Message`s with `isSilent := true`.
2025-03-07 13:50:56 +00:00
Henrik Böving
20571a938b feat: bv_decide support for simple pattern matching on enum inductives (#7329)
This PR adds support to bv_decide for simple pattern matching on enum
inductives. By simple we mean non dependent match statements with all
arms written out.

This PR enables use cases such as:
```lean
namespace PingPong

inductive Direction where
  | goingDown
  | goingUp

structure State where
  val : BitVec 16
  low : BitVec 16
  high : BitVec 16
  direction : Direction

def State.step (s : State) : State :=
  match s.direction with
  | .goingDown =>
    if s.val = s.low then
      { s with direction := .goingUp }
    else
      { s with val := s.val - 1 }
  | .goingUp =>
    if s.val = s.high then
      { s with direction := .goingDown }
    else
      { s with val := s.val + 1 }

def State.steps (s : State) (n : Nat) : State :=
  match n with
  | 0 => s
  | n + 1 => (State.steps s n).step

def Inv (s : State) : Prop := s.low ≤ s.val ∧ s.val ≤ s.high ∧ s.low < s.high

example (s : State) (h : Inv s) (n : Nat) : Inv (State.steps s n) := by
  induction n with
  | zero => simp only [State.steps, Inv] at *; bv_decide
  | succ n ih =>
    simp only [State.steps, State.step, Inv] at *
    bv_decide
```

There is an important thing to consider in this implementation. As the
enums pass can now deal with control flow there is a tension between the
structures and enums pass at play:
1. Enums should run before structures as it could convert matches on
enums into `cond`
chains. This in turn can be used by the structures pass to float
projections into control
   flow which might be necessary.
2. Structures should run before enums as it could reveal new facts about
enums that we might
need to handle. For example a structure might contain a field that
contains a fact about
   some enum. This fact needs to be processed properly by the enums pass

To resolve this tension we do the following:
1. Run the structures pass (if enabled)
2. Run the enums pass (if enabled)
3. Within the enums pass we rerun the part of the structures pass (if
enabled) that could profit from the
enums pass as described above. This comes down to adding a few more
lemmas to a simp
invocation that is going to happen in the enums pass anyway and should
thus be cheap.
2025-03-07 09:23:48 +00:00
Leonardo de Moura
e9f2e1861e feat: cutsat missing case: disequality+inequality+divisibility conflict (#7373)
This PR implements the last missing case for the cutsat procedure and
fixes a bug. During model construction, we may encounter a bounded
interval containing integer solutions that satisfy the divisibility
constraint but fail to satisfy known disequalities.
2025-03-07 01:36:29 +00:00
Leonardo de Moura
905b2eedcd test: cutsat (#7372)
Additional tests for cutsat
2025-03-07 00:31:49 +00:00
Leonardo de Moura
00a4503c4f feat: combine two cutsat proof steps (#7371)
This PR combines two cutsat proof steps that often appear together.
2025-03-06 23:28:49 +00:00
JovanGerb
11aff52fb1 fix: abstractNestedProofs should see into the head of an application (#7353)
This PR changes `abstractNestedProofs` so that it also visits the
subterms in the head of an application.

This oversight caused some definitions in mathlib to have unabstracted
proofs, such as
[CategoryTheory.StructuredArrow.commaMapEquivalenceInverse](https://leanprover-community.github.io/mathlib4_docs/Mathlib/CategoryTheory/Comma/StructuredArrow/CommaMap.html#CategoryTheory.StructuredArrow.commaMapEquivalenceInverse)

Mathlib
[bench](https://github.com/leanprover-community/mathlib4/pull/22613#issuecomment-2704288815):
build instructions -0,166 %
lint instructions -0.72 %

This speedup comes from files containing `CategoryTheory.Functor`, which
contains beta unreduced expressions, where abstracting proofs used to
not happen.

Zulip:
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/dsimp.20simplifies.20proofs.2C.20which.20is.20slow/near/503630173
2025-03-06 20:08:38 +00:00
Leonardo de Moura
ec127a780e feat: simplify cooper case-split proof (#7370)
This PR simplifies the proof term due to the Cooper's conflict
resolution in cutsat.
2025-03-06 19:52:48 +00:00
Leonardo de Moura
b958109d06 feat: let-decls for polynomials in cutsat proof terms (#7369)
This PR uses `let`-declarations for each polynomial occurring in a proof
term generated by the cutsat procedure.
2025-03-06 18:34:26 +00:00
Paul Reichert
d0f4e7c590 feat: tree map lemmas for ofList (#7360)
This PR provides lemmas about the tree map function `ofList` and
interactions with other functions for which lemmas already exist.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-06 16:20:52 +00:00
Joachim Breitner
20d191bc8e fix: allow simp dischargers to add aux decls to the environment (#7362)
This PR allows simp dischargers to add aux decls to the environment.
This enables tactics like `native_decide` to be used here, and unblocks
improvements to omega in #5998.

Fixes #7318
2025-03-06 16:00:59 +00:00
Sebastian Ullrich
24db5b598b feat: use realizeConst for all equation, unfold, induction, and partial fixpoint theorems (#7261)
This PR ensures all equation, unfold, induction, and partial fixpoint
theorem generators in core are compatible with parallelism.

Stacked on #7247
2025-03-06 15:38:04 +00:00
Sebastian Ullrich
141e519009 feat: add async support to more extensions and constructions (#7363) 2025-03-06 14:27:45 +00:00
Kim Morrison
c5cec10788 feat: parity between Int.ediv/tdiv/fdiv theorems (#7358)
This PR fills further gaps in the integer division API, and mostly
achieves parity between the three variants of integer division. There
are still some inequality lemmas about `tdiv` and `fdiv` that are
missing, but as they would have quite awkward statements I'm hoping that
for now no one is going to miss them.
2025-03-06 12:04:14 +00:00
Sebastian Ullrich
950ab377c6 fix: remove incorrect Environment.findAsyncCore? shortcut (#7361)
Breaks with parallel elaboration
2025-03-06 11:07:21 +00:00
Paul Reichert
0c898742f6 feat: tree map lemmas for insertMany (#7331)
This PR provides lemmas about the tree map function `insertMany` and its
interaction with other functions for which lemmas already exist. Most
lemmas about `ofList`, which is related to `insertMany`, are not
included.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-06 08:54:42 +00:00
Kim Morrison
ca0d822619 chore: protect Int.sub_eq_iff_eq_add (#7359)
Minor problems introduced in #7274.
2025-03-06 05:42:12 +00:00
Kitamado
e2a80875c9 fix: doc in List.removeAll (#7288)
This PR fixes the doc of `List.removeAll`
2025-03-06 05:25:19 +00:00
Leonardo de Moura
061ebe1dca feat: mod and div in cutsat (#7357)
This PR adds support for `/` and `%` to the cutsat procedure.
2025-03-06 04:15:28 +00:00
Leonardo de Moura
7a8c8a4fb3 fix: markNestedProofs (#7355)
This PR fixes a bug in the `markNestedProofs` preprocessor used in the
`grind` tactic.
2025-03-06 00:51:13 +00:00
Leonardo de Moura
3ff10c6cdd test: cutsat cooper resolution (#7354) 2025-03-06 00:40:38 +00:00
Leonardo de Moura
9ae2ac39c9 feat: avoid cooper case analysis for univariate polynomials (#7351)
This PR ensures cutsat does not have to perform case analysis in the
univariate polynomial case. That it, it can close a goal whenever there
is no solution for a divisibility constraint in an interval. Example of
theorem that is now proved in a single step by cutsat:
```lean
example (x : Int) : 100 ≤ x → x ≤ 10000 → 20000 ∣ 3*x → False := by
  grind
```
2025-03-05 20:37:29 +00:00
Wojciech Rozowski
2c8fb9d3fc fix: strip optional parameters when elaborating the termination hints (#7335)
This PR modifies `elabTerminationByHints` in a way that the type of the
recursive function used for elaboration of the termination measure is
striped of from optional parameters. It prevents introducing
dependencies between the default values for arguments, that can cause
the termination checker to fail.

Closes https://github.com/leanprover/lean4/issues/6351.
2025-03-05 18:15:49 +00:00
Henrik Böving
dc7358b4df feat: upgrade cadical to 2.1.2 (#7347)
This PR upgrades the CaDiCal we ship and use for bv_decide to version
2.1.2. Additionally it enables binary LRAT proofs on windows by default
as https://github.com/arminbiere/cadical/issues/112 has been fixed.

Version 2.1.3 is already available but as the Bitwuzla authors [have
pointed out](https://github.com/bitwuzla/bitwuzla/pull/129) one needs to
be careful when upgrading CaDiCal so we just move to a version [they
confirmed](6e93389d86)
is fine for now.
2025-03-05 17:58:58 +00:00
Sebastian Ullrich
44a518b331 fix: never transfer constants from checked environment into elab branches (#7306)
Otherwise we may lose the environment extension state of the constant
2025-03-05 17:12:27 +00:00
Markus Himmel
68f3fc6d5d feat: finite type conversions (Nat/Int/Fin/BitVec -> UIntX -> *) (#7340)
This PR adds lemmas for iterated conversions between finite types which
start with `Nat`/`Int`/`Fin`/`BitVec` and then go through `UIntX`.
2025-03-05 15:35:36 +00:00
Sebastian Ullrich
72c4630aab feat: use realizeConst for all equation and unfold theorems (#7348)
This PR ensures all equation and unfold theorem generators in core are
compatible with parallelism.
2025-03-05 14:56:50 +00:00
Lean stage0 autoupdater
db0abe89cf chore: update stage0 2025-03-05 13:37:40 +00:00
Marc Huisinga
2b44a4f0d9 fix: inlay hint assertion violation when deleting open file (#7346)
This PR fixes an issue where the language server would run into an inlay
hint assertion violation when deleting a file that is still open in the
language server.
2025-03-05 12:40:21 +00:00
Marc Huisinga
72f4098156 feat: combined auto-implicit inlay hint tooltip (#7344)
This PR combines the auto-implicit inlay hint tooltips into a single
tooltip. This works around an issue in VS Code where VS Code fails to
update hovers for tooltips in adjacent inlay hint parts when moving the
mouse.
2025-03-05 12:23:58 +00:00
Marc Huisinga
f0f7c3ff01 fix: inlay hints inserted at wrong position after edit (#7343)
This PR mitigates an issue where inserting an inlay hint in VS Code by
double-clicking would insert the inlay hint at the wrong position right
after an edit.

This bug was originally reported by @plp127 at
https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/v4.2E18.2E0.20-.20inlay.20hints/near/503362330.

The cause of this bug is that when VS Code hasn't yet received a new set
of inlay hints for a new document state, it will happily move around the
displayed inlay hint, but it won't move around any of the other
position-dependent properties of the inlay hint, like the property
describing where to insert the inlay hint. Since we delay responses
after an edit by an edit delay of 3000ms to prevent inlay hint
flickering while typing, the window for this bug is relatively large.

To work around this bug, we now always immediately respond to the first
inlay hint request after an edit with the old state of the inlay hints,
which we already update correctly on edits on the server-side so that we
can serve old inlay hints for parts of the file that are still
in-progress. Essentially, we are just telling VS Code how it should have
moved all position-dependent properties of each inlay hint.

Even with this mitigation, there is still a small window for this bug to
occur, namely the window from an edit to when VS Code receives the old
inlay hints from the server. In practice, this window should be a couple
of milliseconds at most, so I'd hope it doesn't cause many problems.
There's nothing we can do about this in either vscode-lean4 or the
language server, unfortunately.
2025-03-05 12:23:53 +00:00
Kim Morrison
5536281238 feat: force-mathlib-ci label (#7337)
This PR adds support for a `force-mathlib-ci` label, which attempts full
Mathlib CI even if the PR branch is not based off the
`nightly-with-mathlib` branch, or if the relevant
`nightly-testing-YYYY-MM-DD` branch is not present at Batteries or
Mathlib.
2025-03-05 06:36:38 +00:00
Markus Himmel
8de6233326 feat: IntX conversion lemmas (#7274)
This PR adds lemmas about iterated conversions between finite types,
starting with something of type `IntX`.
2025-03-05 06:27:53 +00:00
Leonardo de Moura
f312170f21 feat: cooper resolution in cutsat (#7339)
This PR implements cooper conflict resolution in the cutsat procedure.
It also fixes several bugs in the proof term construction. We still need
to add more tests, but we can already solve the following example that
`omega` fails to solve:
```lean
example (x y : Int) :
    27 ≤ 11*x + 13*y →
    11*x + 13*y ≤ 45 →
    -10 ≤ 7*x - 9*y →
    7*x - 9*y ≤ 4 → False := by
  grind
```
2025-03-05 03:37:45 +00:00
Kim Morrison
6d1bda6ff2 feat: add @[simp] to Int.neg_inj (#7338)
This PR adds @[simp] to `Int.neg_inj`.
2025-03-05 02:53:41 +00:00
Joachim Breitner
f45c19b428 feat: identify more fixed parameters (#7166)
This PR extends the notion of “fixed parameter” of a recursive function
also to parameters that come after varying function. The main benefit is
that we get nicer induction principles.


Before the definition

```lean
def app (as : List α) (bs : List α) : List α :=
  match as with
  | [] => bs
  | a::as => a :: app as bs
```

produced

```lean
app.induct.{u_1} {α : Type u_1} (motive : List α → List α → Prop) (case1 : ∀ (bs : List α), motive [] bs)
  (case2 : ∀ (bs : List α) (a : α) (as : List α), motive as bs → motive (a :: as) bs) (as bs : List α) : motive as bs
```
and now you get
```lean
app.induct.{u_1} {α : Type u_1} (motive : List α → Prop) (case1 : motive [])
  (case2 : ∀ (a : α) (as : List α), motive as → motive (a :: as)) (as : List α) : motive as
```
because `bs` is fixed throughout the recursion (and can completely be
dropped from the principle).

This is a breaking change when such an induction principle is used
explicitly. Using `fun_induction` makes proof tactics robust against
this change.

The rules for when a parameter is fixed are now:

1. A parameter is fixed if it is reducibly defq to the the corresponding
argument in each recursive call, so we have to look at each such call.
2. With mutual recursion, it is not clear a-priori which arguments of
another function correspond to the parameter. This requires an analysis
with some graph algorithms to determine.
3. A parameter can only be fixed if all parameters occurring in its type
are fixed as well.
This dependency graph on parameters can be different for the different
functions in a recursive group, even leading to cycles.
4. For structural recursion, we kinda want to know the fixed parameters
before investigating which argument to actually recurs on. But once we
have that we may find that we fixed an index of the recursive
parameter’s type, and these cannot be fixed. So we have to un-fix them
5. … and all other fixed parameters that have dependencies on them.

Lean tries to identify the largest set of parameters that satisfies
these criteria.

Note that in a definition like
```lean
def app : List α → List α → List α
  | [], bs => bs
  | a::as, bs => a :: app as bs
```
the `bs` is not considered fixes, as it goes through the matcher
machinery.


Fixes #7027
Fixes #2113
2025-03-04 22:26:20 +00:00
Joachim Breitner
e2ee629022 fix: allow aux decls to be generated by decreasing_by tactics (#7333)
This PR allows aux decls (like generated by `match`) to be generated by
decreasing_by tactics.

Fixes #7332.
2025-03-04 18:42:36 +00:00
Sebastian Ullrich
64731b71aa fix: enable realizations for inductives as late as possible (#7336)
Realizations on them were missing access to e.g. `recOn`
2025-03-04 17:57:51 +00:00
Joachim Breitner
23b5baa5ec feat: WF/Fix.lean: only refine fix’s ih for atomic discriminant onlys (#7324)
This PR changes the internal construction of well-founded recursion, to
not change the type of `fix`’s induction hypothesis in non-defeq ways.

Fixes #7322 and hopefully unblocks #7166.
2025-03-04 13:49:01 +00:00
Sebastian Ullrich
f58e893e63 chore: Mathlib fixes (#7327)
* chore: revert changes to Environment.replay 
* chore: disable realizeConst for now when Elab.async is not set
2025-03-04 13:41:30 +00:00
Rob23oba
a856518265 perf: optimize elaboration of HashMap verification files (#7323)
This PR improves the elaboration time of
`Std.Data.DHashMap.Internal.RawLemmas` and
`Std.Data.DHashMap.RawLemmas`.
2025-03-04 13:30:15 +00:00
Joachim Breitner
45806017e5 feat: allow cond to be used in proofs (#7141)
This PR generalizes `cond` to allow the motive to be in `Sort u`, not
just `Type u`.
2025-03-04 12:10:29 +00:00
Paul Reichert
058e63a3d6 feat: tree map lemmas for foldlM, foldl, foldrM and foldr (#7270)
This PR provides lemmas about the tree map functions `foldlM`, `foldl`,
`foldrM` and `foldr` and their interactions with other functions for
which lemmas already exist. Additionally, it generalizes the
`fold*`/`keys` lemmas to arbitrary tree maps, which were previously
stated only for the `DTreeMap α Unit` case.

A later PR will make the hash map functions `fold` and `revFold`
internal and also update their signature to conform to the tree map and
list API. This is out of scope for this PR.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-03-04 11:44:41 +00:00
Kim Morrison
e8e6c4716f chore: copy v4.17.0 release notes from releases/v4.17.0 branch (#7325) 2025-03-04 11:24:51 +00:00
Lean stage0 autoupdater
3ce8c73315 chore: update stage0 2025-03-04 11:40:02 +00:00
Kim Morrison
88edd13642 feat: alignment of Int.ediv/fdiv/tdiv lemmas (#7319)
This PR continues alignment of lemmas about `Int.ediv/fdiv/tdiv`,
including adding notes about "missing" lemmas that do not apply in one
case. Also lemmas about `emod/fmod/tmod`. There's still more to do.
2025-03-04 10:41:01 +00:00
Sebastian Ullrich
c70e614a5b chore: harden use of panics in Lean.Environment (#7321)
* avoid `panic!`s that return `Unit` or some otherwise unused value lest
they get optimized away
* make some fallback values explicit to avoid follow-up errors
* avoid redundant declaration names in panic messages
2025-03-04 10:29:54 +00:00
Joachim Breitner
aa8faae576 feat: allow cond to be used in proofs (stage0 update prep) (#7320)
This PR prepares for #7141.
2025-03-04 10:26:12 +00:00
euprunin
2f8901d6d0 chore: add missing period to grind warning message (#7317)
Co-authored-by: euprunin <euprunin@users.noreply.github.com>
2025-03-04 09:42:17 +00:00
Leonardo de Moura
9ff8c5ac2d feat: cooper conflict resolution in cutsat (#7315)
This PR implements the Cooper conflict resolution in cutsat. We still
need to implement the backtracking and disequality case.
2025-03-04 03:23:14 +00:00
Kyle Miller
48491e5262 chore: re-enable synthesis checkpoint for structure parent elaboration (#7314)
This PR changes elaboration of `structure` parents so that each must be
fully elaborated before the next one is processed.

In particular, it re-adds synthesizing synthetic mvars between
`structure` parents, in the same manner as other fields. This synthesis
step was removed in #5842 because I had thought parents were like type
parameters and would participate in header elaboration, but in the end
it made more sense elaborating parents after the headers are done, since
they're like fields.

We want this enabled because it will help ensure that all the necessary
reductions are done to types of fields as they're added to the
structure.
2025-03-04 02:49:30 +00:00
Leonardo de Moura
9f5cc7262b feat: proof generation for cooper_dvd_left and variants in cutsat (#7312)
This PR implements proof term generation for `cooper_dvd_left` and its
variants in the cutsat procedure for linear integer arithmetic.
2025-03-04 00:40:31 +00:00
Kim Morrison
957beb02bc chore: deprecate Environment.replay; use lean4checker (#7311) 2025-03-04 00:23:36 +00:00
Henrik Böving
017a1f2b94 fix: bv_decide structures pass instantiate mvars (#7309)
This PR fixes a bug where bv_decide's new structure support would
sometimes not case split on all available structure fvars as their type
was an mvar.
2025-03-03 21:27:53 +00:00
Lean stage0 autoupdater
f8f1b2212a chore: update stage0 2025-03-03 20:17:14 +00:00
Sebastian Ullrich
dab6a161bd feat: realizeConst for match equations (#7247)
This PR makes generation of `match` equations and splitters compatible
with parallelism.
2025-03-03 17:18:29 +00:00
Sebastian Ullrich
8e47d29bf9 feat: debug_assert! (#7256)
This PR introduces the `assert!` variant `debug_assert!` that is
activated when compiled with `buildType` `debug`.

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2025-03-03 16:34:44 +00:00
jrr6
e337129108 fix: move auxDeclToFullName to LocalContext to fix name (un)resolution (#7075)
This PR ensures that names suggested by tactics like `simp?` are not
shadowed by auxiliary declarations in the local context and that names
of `let rec` and `where` declarations are correctly resolved in tactic
blocks.

This PR contains the following potentially breaking changes:
* Moves the `auxDeclToFullName` map from `TermElab.Context` to
`LocalContext`.
* Refactors `Lean.Elab.Term.resolveLocalName : Name → TermElabM …` to
`Lean.resolveLocalName [MonadResolveName m] [MonadEnv m] [MonadLCtx m] :
Name → m …`.
* Refactors the `TermElabM` action `Lean.Elab.Term.withAuxDecl` to a
monad-polymorphic action `Lean.Meta.withAuxDecl`.
* Adds an optional `filter` argument to `Lean.unresolveNameGlobal`.

Closes #6706, closes #7073.
2025-03-03 16:10:54 +00:00
Rob23oba
d3eb2fe13c feat: HashMap getKey lemmas (#7289)
This PR adds `getKey_beq`, `getKey_congr` and variants to the hashmap
api.
2025-03-03 15:06:58 +00:00
Markus Himmel
d2239a5770 feat: IntX simprocs (#7228)
This PR adds simprocs to reduce expressions involving `IntX`.
2025-03-03 13:37:57 +00:00
Sebastian Ullrich
a244b06882 feat: use realizeConst for bv_decide helper constants (#7276)
This PR ensures helper constants generated by `bv_decide` are compatible
with parallelism.
2025-03-03 12:36:25 +00:00
Sebastian Ullrich
0a55f4bf36 fix: more realizeConst fixes (#7300)
Found and debugged while working on stage 2 of #7247
2025-03-03 12:10:40 +00:00
Kim Morrison
e7a411a66d chore: begin development cycle for v4.19.0 (#7299) 2025-03-03 11:01:21 +00:00
Henrik Böving
783671261d feat: bv_decide add rewrites around ite + operations (#7298)
This PR adds rewrites to bv_decide's preprocessing that concern
combinations of if-then-else and operation such as multiplication or
negation.
2025-03-03 10:51:19 +00:00
Sebastian Ullrich
01d951c3fc fix: cancel computations within command elaboration as soon as reuse is ruled out (#7241)
The other part of #7175
2025-03-03 10:37:10 +00:00
Eric Wieser
6cf3402f1c perf: use free_sized in mpz.cpp (#6825)
The performance win here is pretty negligible (and of course irrelevant
with the small allocator enabled), but this is consistent with it being
used elsewhere.

Follow-up to #6598
2025-03-03 08:47:15 +00:00
Kyle Miller
e3c6909ad5 chore: reimplement mk_projections in Lean (#7295)
This PR translates `lean::mk_projections` into Lean, adding
`Lean.Meta.mkProjections`. It also puts `hasLooseBVarInExplicitDomain`
back in sync with the kernel version. Deletes
`src/library/constructions/projection.{h,cpp}`.
2025-03-03 01:10:27 +00:00
Sean McLaughlin
255810db64 fix: Float32.ofInt (#7277)
This PR fixes a bug in Float32.ofInt, which previously returned a
Float(64).

Closes https://github.com/leanprover/lean4/issues/7264
2025-03-02 23:22:35 +00:00
Leonardo de Moura
f094652481 fix: Rat.floor and Rat.ceil (#7294)
This PR fixes bugs in `Std.Internal.Rat.floor` and
`Std.Internal.Rat.ceil`.
2025-03-02 22:50:36 +00:00
Leonardo de Moura
3eb07cac44 feat: cooper_right helper theorem for cutsat (#7293)
This PR adds support theorems for the Cooper-Right conflict resolution
rule used in the cutsat procedure. During model construction, when
attempting to extend the model to a variable x, cutsat may find a
conflict that involves two inequalities (the lower and upper bounds for
x). This is a special case of Cooper-Dvd-Right when there is no
divisibility constraint.
2025-03-02 19:21:08 +00:00
Mac Malone
58034bf237 feat: lake: display newest job in monitor (#7291)
This PR changes the Lake job monitor to display the last (i.e., newest)
running/unfinished job rather than the first. This avoids the monitor
focusing too long on any one job (e.g., "Running job computation").
2025-03-02 18:38:23 +00:00
Leonardo de Moura
7ba7ea4e16 feat: helper theorems for cooper_dvd_right (#7292)
This PR adds support theorems for the **Cooper-Dvd-Right** conflict
resolution rule used in the cutsat procedure. During model construction,
when attempting to extend the model to a variable `x`, cutsat may find a
conflict that involves two inequalities (the lower and upper bounds for
`x`) and a divisibility constraint.
2025-03-02 18:09:55 +00:00
Leonardo de Moura
4877e84031 feat: cooper_left helper theorem for cutsat (#7290)
This PR adds support theorems for the **Cooper-Left** conflict
resolution rule used in the cutsat procedure. During model
construction,when attempting to extend the model to a variable `x`,
cutsat may find a conflict that involves two inequalities (the lower and
upper bounds for `x`). This is a special case of Cooper-Dvd-Left when
there is no divisibility constraint.
2025-03-02 16:34:48 +00:00
Henrik Böving
9c47f395c8 refactor: change iff lowering rule in bv_decide (#7287)
This PR uses a better lowering rule for iff in bv_decide's
preprocessing.
2025-03-02 12:20:27 +00:00
Kim Morrison
3f98b4835c chore: add Fin.mk_eq_zero simp lemma (#7286) 2025-03-02 11:11:23 +00:00
Leonardo de Moura
a86145b6bb feat: non-chronological backtracking for cutsat (#7284)
This PR implements non-choronological backtracking for the cutsat
procedure. The procedure has two main kinds of case-splits:
disequalities and Cooper resolvents. This PR focus on the first kind.
2025-03-01 23:19:11 +00:00
dependabot[bot]
c4d3a74f32 chore: CI: bump dawidd6/action-download-artifact from 8 to 9 (#7285)
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 8 to 9.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dawidd6/action-download-artifact/releases">dawidd6/action-download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v9</h2>
<h2>What's Changed</h2>
<ul>
<li>add merge_multiple option by <a
href="https://github.com/timostroehlein"><code>@​timostroehlein</code></a>
in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/327">dawidd6/action-download-artifact#327</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/timostroehlein"><code>@​timostroehlein</code></a>
made their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/327">dawidd6/action-download-artifact#327</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v8...v9">https://github.com/dawidd6/action-download-artifact/compare/v8...v9</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="07ab29fd4a"><code>07ab29f</code></a>
add merge_multiple option (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/327">#327</a>)</li>
<li>See full diff in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v8...v9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dawidd6/action-download-artifact&package-manager=github_actions&previous-version=8&new-version=9)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-01 20:47:28 +00:00
Leonardo de Moura
c74865fbe2 feat: helper theorems for cooper_dvd_left (#7279)
This PR adds support theorems for the **Cooper-Dvd-Left** conflict
resolution rule used in the cutsat procedure. During model construction,
when attempting to extend the model to a variable `x`, cutsat may find a
conflict that involves two inequalities (the lower and upper bounds for
`x`) and a divisibility constraint:

```lean
a * x + p ≤ 0
b * x + q ≤ 0
d ∣ c * x + s
```

We apply Cooper's quantifier elimination to produce:

```lean
OrOver (Int.lcm a (a * d / Int.gcd(a * d) c)) fun k =>
     b * p + (-a) * q + b * k ≤ 0 ∧
     a ∣ p + k ∧
     a * d ∣ c * p + (-a) * s + c * k
```

Here, `OrOver` is a "big-or" operator. This PR introduces the following
theorem, which encapsulates the above approach via reflection:

```lean
theorem cooper_dvd_left (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (n : Nat)
    : cooper_dvd_left_cert p₁ p₂ p₃ d n
      → p₁.denote' ctx ≤ 0
      → p₂.denote' ctx ≤ 0
      → d ∣ p₃.denote' ctx
      → OrOver n (cooper_dvd_left_split ctx p₁ p₂ p₃ d) :=
```

For each `0 <= k < n`, we generate the three implied facts using:

```lean
theorem cooper_dvd_left_split_ineq (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (k : Nat) (b : Int) (p' : Poly)
    : cooper_dvd_left_split ctx p₁ p₂ p₃ d k
      → cooper_dvd_left_split_ineq_cert p₁ p₂ k b p'
      → p'.denote ctx ≤ 0

theorem cooper_dvd_left_split_dvd1 (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (k : Nat) (a : Int) (p' : Poly)
    : cooper_dvd_left_split ctx p₁ p₂ p₃ d k
      → cooper_dvd_left_split_dvd1_cert p₁ p' a k
      → a ∣ p'.denote ctx

theorem cooper_dvd_left_split_dvd2 (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (k : Nat) (d' : Int) (p' : Poly)
    : cooper_dvd_left_split ctx p₁ p₂ p₃ d k
      → cooper_dvd_left_split_dvd2_cert p₁ p₃ d k d' p'
      → d' ∣ p'.denote ctx
```

Two helper `OrOver` theorems are used to process the `OrOver`:

```lean
theorem orOver_unsat {p} : ¬ OrOver 0 p

theorem orOver_resolve {n p} : OrOver (n+1) p → ¬ p n → OrOver n p
```

Where `p` is instantiated using `cooper_dvd_left_split ctx p₁ p₂ p₃ d`.
2025-03-01 02:18:12 +00:00
Leonardo de Moura
93a908469c feat: cutsat counterexamples (#7278)
This PR adds counterexamples for linear integer constraints in the
`grind` tactic. This feature is implemented in the cutsat procedure.
2025-02-28 19:05:27 +00:00
Joachim Breitner
903fe29863 chore: release_notes.py: report on all commit types (#7258)
I missed a few that we should not be shy of.
2025-02-28 17:39:18 +00:00
Henrik Böving
84da113355 feat: add all bitwuzla level 1 if rewrites to bv_decide (#7275)
This PR adds all level 1 rewrites from Bitwuzla to the preprocessor of
bv_decide.
2025-02-28 16:04:09 +00:00
Markus Himmel
75df4c0b52 fix: statement of a UIntX conversion lemma (#7273)
This PR fixes the statement of a `UIntX` conversion lemma.
2025-02-28 15:15:58 +00:00
Sebastian Ullrich
ad5a746cdd fix: realizeConst fixes (#7272)
Emerged and fixed while adding more `realizeConst` callers
2025-02-28 14:59:13 +00:00
Paul Reichert
2bd3ce5463 fix: harmonize foldr signature of the tree map with that of List (#7271)
This PR changes the order of arguments of the folding function expected
by the tree map's `foldr` and `foldrM` functions so that they are
consistent with the API of `List`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-28 14:36:56 +00:00
Henrik Böving
2b752ec245 feat: add IntX and ISize support for bv_decide (#7269)
This PR implements support for `IntX` and `ISize` in `bv_decide`.
2025-02-28 10:33:11 +00:00
Paul Reichert
909ee719aa feat: tree map lemmas for keys and toList (#7260)
This PR provides lemmas about the tree map functions `keys` and `toList`
and their interactions with other functions for which lemmas already
exist. Moreover, a bug in `foldr` (calling `foldlM` instead of `foldrM`)
is fixed.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-28 10:14:13 +00:00
Markus Himmel
7dd5e957da feat: ToExpr IntX (#7268)
This PR implements `Lean.ToExpr` for finite signed integers.
2025-02-28 09:32:30 +00:00
Markus Himmel
d67e0eea47 feat: IntX theory for simprocs and bv_decide (#7259)
This PR contains theorems about `IntX` that are required for `bv_decide`
and the `IntX` simprocs.

A more comprehensive set of theorems about `IntX` will be part of future
PRs.
2025-02-28 07:04:52 +00:00
Kim Morrison
10bfeba2d9 chore: aligning Int.ediv/fdiv/tdiv theorems (#7266)
This PR begins the alignment of `Int.ediv/fdiv/tdiv` theorems.
2025-02-28 05:27:40 +00:00
Leonardo de Moura
4285f8ba05 feat: improve cutsat model search procedure (#7267)
This PR improves the cutsat search procedure. It adds support for find
an approximate rational solution, checks disequalities, and adds stubs
for all missing cases.
2025-02-28 04:26:53 +00:00
Leonardo de Moura
d8be3ef7a8 doc: cutsat procedure (#7262) 2025-02-27 21:15:34 +00:00
Paul Reichert
c924768879 fix: add @[specialize] annotations to helpers used in alter and modify of the hash map (#7245)
This PR adds missing `@[specialize]` annotations to the `alter` and
`modify` functions in `Std.Data.DHashMap.Internal.AssocList`, which are
used by the corresponding hash map functions.

Zulip thread:
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/.60Std.2EHashMap.2Emodify.60.20and.20.60alter.60.20do.20not.20inline.20the.20function

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-27 15:43:05 +00:00
Henrik Böving
c1e76e8976 perf: optimize LRAT trimming in bv_decide (#7257)
This PR improves performance of LRAT trimming in bv_decide.

The underlying idea is taken from LRAT trimming as implemented in
[`lrat-trim`](https://github.com/arminbiere/lrat-trim/t): As we only
filter about half to two thirds of the LRAT proof steps anyway, there is
no need to use tree or hash maps to store information about them and we
can instead use arrays indexed by the proof step directly. This does not
meaningfully increase the amount of memory required but makes the
trimming step basically disappear from profiles, e.g.
`smt/non-incremental/QF_BV/20210312-Bouvier/vlsat3_a72.smt2` [used
to](https://share.firefox.dev/41kJTle) have 8% of its time spent in
trimming [now](https://share.firefox.dev/3QAKI4w) 1.5%.
2025-02-27 13:47:21 +00:00
Paul Reichert
60a9f8e492 feat: well-formedness lemmas for raw tree map operations (#7237)
This PR provides proofs that the raw tree map operations are well-formed
and refactors the file structure of the tree map, introducing new
modules `Std.{DTreeMap,TreeMap,TreeSet}.Raw` and splittting
`AdditionalOperations` into separate files for bundled and raw types.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-27 13:08:41 +00:00
Kim Morrison
604133d189 chore: cleanup of remaining Array-specific material (#7253)
This PR takes Array-specific lemmas at the end of `Array/Lemmas.lean`
(i.e. material that does not have exact correspondences with
`List/Lemmas.lean`) and moves them to more appropriate homes. More to
come.
2025-02-27 10:51:30 +00:00
Kim Morrison
d3781bb787 fix: definition of Min (Option α), and basic lemmas (#7255)
This PR fixes the definition of `Min (Option α)`. This is a breaking
change. This treats `none` as the least element,
so `min none x = min x none = none` for all `x : Option α`. Prior to
nightly-2025-02-27, we instead had `min none (some x) = min (some x)
none = some x`. Also adds basic lemmas relating `min`, `max`, `≤` and
`<` on `Option`.
2025-02-27 10:44:44 +00:00
Sebastian Ullrich
87e8da5230 chore: temporarily disable Elab.async in the server (#7254)
...pending further testing of #7241 post-release
2025-02-27 08:31:54 +00:00
Kim Morrison
727c696d9f chore: add @[simp] to List.getElem_append_left|right (#7216)
Helps with confluence.
2025-02-27 03:01:33 +00:00
Mac Malone
cf2b7f4c1b feat: lake: builtin inits, elabs, & macros for DSL (#7171)
This PR changes the Lake DSL to use builtin elaborators, macros, and
initializers.

This works out of the box for the Lake executable and is supported in
interactive contexts through the Lake plugin.
2025-02-27 02:34:14 +00:00
Leonardo de Moura
cd4383b6f3 feat: refine inequalites using disequalities in cutsat (#7252)
This PR implements inequality refinement using disequalities. It
minimizes the number of case splits cutsat will have to perform.
2025-02-27 01:33:58 +00:00
Cameron Zwarich
0d9859370a fix: make extern decls evaluate as ⊤ instead of ⊥ in LCNF.elimDeadBranches (#6928)
This PR makes extern decls evaluate as ⊤ rather than the default value
of ⊥ in the LCNF elimDeadBranches analysis.
2025-02-27 01:24:47 +00:00
Cameron Zwarich
c292ae2e0e fix: don't create reduced arity LCNF decls with no params (#7086)
This PR makes the arity reduction pass in the new code generator match
the old one when it comes to the behavior of decls with no used
parameters. This is important, because otherwise we might create a
top-level decl with no params that contains unreachable code, which
would get evaluated unconditionally during initialization. This actually
happens when initializing Init.Core built with the new code generator.
2025-02-27 01:23:34 +00:00
Kim Morrison
3113847806 chore: reenable Vector variable name linters (#7251) 2025-02-26 23:59:28 +00:00
Kim Morrison
d275455674 chore: alignment of a List/Array/Vector.reverse lemma (#7250)
Minor lemma alignment missed earlier.
2025-02-26 23:59:06 +00:00
Kim Morrison
a4d10742d3 feat: align List/Array/Vector.any/all theorems (#7249)
This PR completes alignment of theorems about
`List/Array/Vector.any/all`.
2025-02-26 23:53:53 +00:00
Leonardo de Moura
777fba495a feat: cutsat implied equalities (#7248)
This PR implements simple equality propagation in cutsat `p <= 0 -> -p
<= 0 -> p = 0`
2025-02-26 22:52:37 +00:00
Sebastian Ullrich
2e66341f69 feat: Environment.realizeConst (#7076)
This PR introduces the central parallelism API for ensuring that helper
declarations can be generated lazily without duplicating work or
creating conflicts across threads.
2025-02-26 19:32:21 +00:00
Mac Malone
2e44585ce9 fix: set CP_UTF8 on Windows (#7213)
This PR adds `SetConsoleOutputCP(CP_UTF8)` during runtime initialization
to properly display Unicode on the Windows console. This effects both
the Lean executable itself and user executables (including Lake).

Closes #4291.
2025-02-26 18:36:32 +00:00
Leonardo de Moura
e2f0e14b04 feat: disequalities in cutsat (#7244)
This PR adds support for disequalities in the cutsat procedure used in
`grind`.
2025-02-26 17:26:59 +00:00
Henrik Böving
e801dc96ca chore: cleanup non terminal simps in LRAT (#7243)
This PR cleans up non terminal simps in the LRAT checking module.
2025-02-26 15:02:57 +00:00
Henrik Böving
56a3ac1814 feat: bv_decide structure projections and if (#7242)
This PR makes sure bv_decide can work with projections applied to `ite`
and `cond` in its structures pass.
2025-02-26 14:47:44 +00:00
Paul Reichert
6c62f720c8 feat: tree map lemmas for getThenInsertIfNew? (#7229)
This PR provides lemmas for the tree map function `getThenInsertIfNew?`.

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-26 10:29:51 +00:00
Eric Wieser
a57efd0a88 fix: free memory from lib_uv requests (#7151)
This PR fixes a memory leak in `IO.FS.createTempFile`
2025-02-26 07:52:34 +00:00
Paul Reichert
7e2d6e2254 feat: tree map lemmas for the getKey variants and insertIfNew functions (#7221)
This PR provides lemmas about the tree map functions `getKey?`,
`getKey`, `getKey!`, `getKeyD` and `insertIfNew` and their interaction
with other functions for which lemmas already exist.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-26 07:36:28 +00:00
Kim Morrison
4603e1a6ad feat: add Array/Vector.replace (#7235)
This PR adds `Array.replace` and `Vector.replace`, proves the
correspondences with `List.replace`, and reproduces the basic API. In
order to do so, it fills in some gaps in the `List.findX` APIs.
2025-02-26 06:03:45 +00:00
Mac Malone
550d2918b8 feat: Lake plugin w/ USE_LAKE (#7233)
This PR uses the Lake plugin when Lake is built with Lake via
`USE_LAKE`.
2025-02-26 04:05:15 +00:00
Leonardo de Moura
eb5ad2c03a feat: disequality propagation from grind core module to cutsat (#7234)
This PR implements dIsequality propagation from `grind` core module to
cutsat.
2025-02-26 03:34:39 +00:00
Leonardo de Moura
769fe4ebf6 feat: add Grind.mkDiseqProof? (#7231)
This PR implements functions for constructing disequality proofs in
`grind`.
2025-02-25 23:40:07 +00:00
Joachim Breitner
8130fdc474 feat: induction tactic to err on extra targets (#7224)
This PR make `induction … using` and `cases … using` complain if more
targets were given than expected by that eliminator.
2025-02-25 20:53:16 +00:00
Markus Himmel
41bba59868 feat: UIntX conversion lemmas (part 2/2) (#7210)
This PR adds the remaining lemmas about iterated conversions between
finite types starting with something of type `UIntX`.

In the near future, we will add similar lemmas when starting with
something of type `IntX`, `Nat`, `Int`, `BitVec` or `Fin`.
2025-02-25 18:52:17 +00:00
Eric Wieser
115f06c32a fix: missing indents in Try this message (#7191)
This PR fixes the indentation of "Try this" suggestions in widget-less
multiline messages, as they appear in `#guard_msgs` outputs.
2025-02-25 16:55:50 +00:00
Sebastian Ullrich
1e1e17cb35 fix: be consistent in not reporting newlines between trace nodes to info view (#7143)
This PR makes the server consistently not report newlines between trace
nodes to the info view, enabling it to render them on dedicates lines
without extraneous spacing between them in all circumstances.

The info view code will separately need to be adjusted to this new
behavior, until then this change will make adjacent trace node leafs
consistently be rendered *on the same line* if there is sufficient
space. The cmdline should be unaffected in any case.
2025-02-25 16:16:35 +00:00
Paul Reichert
831e8d768b feat: tree map lemmas for get, get! and getD (#7207)
This PR provides lemmas for the tree map functions `get`, `get!` and
`getD` in relation to the other operations for which lemmas already
exist.

Internally, the `simp_to_model` tactic was provided two new simp lemmas
to eliminate some common complications that require `rw`'ing before
using `simp_to_model`. However, it is still necessary to sometimes
`revert` some hypotheses.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-25 15:26:50 +00:00
jrr6
b4b878b2d0 fix: prevent exact? and apply? from suggesting invalid tactics (#7192)
This PR prevents `exact?` and `apply?` from suggesting tactics that
correspond to correct proofs but do not elaborate, and it allows these
tactics to suggest `expose_names` when needed.

These tactics now indicate that a non-compiling term was generated but
do not suggest that that term be inserted. `exact?` also no longer
suggests that the user try `apply?` if no partial suggestions were
found.

This addresses part of #5407 but does not achieve the exact expected
behavior therein (due to #6122).
2025-02-25 15:24:09 +00:00
Paul Reichert
2377f35426 fix: replace the compare_self simp lemma with a less generic one (#7222)
This PR removes the `simp` attribute from `ReflCmp.compare_self` because
it matches arbitrary function applications. Instead, a new `simp` lemma
`ReflOrd.compare_self` is introduced, which only matches applications of
`compare`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-25 10:08:23 +00:00
Lean stage0 autoupdater
c7f706baeb chore: update stage0 2025-02-25 08:57:53 +00:00
Cameron Zwarich
c3402b85ab fix: make the stage2 Leanc build use stage2 oleans rather than stage1 oleans (#7190)
This PR makes the stage2 Leanc build use the stage2 oleans rather than
stage1 oleans. This was happening because Leanc's own OLEAN_OUT is at
the build root rather than the lib/lean subdirectory, so when the build
added this OLEAN_OUT to LEAN_PATH no oleans were found there and the
search fell back to the stage1 installation location.
2025-02-25 06:20:50 +00:00
Mac Malone
a68b986616 feat: lake: compute jobs asynchronously (#7211)
This PR changes the job monitor to perform run job computation itself as
a separate job. Now progress will be reported eagerly, even before all
outstanding jobs have been discovered. Thus, the total job number
reported can now grow while jobs are still being computed (e.g., the `Y`
in `[X/Y[` may increase).
2025-02-25 04:03:17 +00:00
Leonardo de Moura
a2dc17055b feat: missing cases for equality propagation from core to cutsat (#7220)
This PR implements the missing cases for equality propagation from the
`grind` core to the cutsat module.
2025-02-25 01:09:05 +00:00
Kim Morrison
c9c85c7d83 chore: List.leftpad typo (#7219) 2025-02-25 00:53:37 +00:00
Kim Morrison
d615e615d9 chore: align List.dropLast/Array.pop lemmas (#7208)
This PR aligns lemmas for `List.dropLast` / `Array.pop` / `Vector.pop`.
2025-02-25 00:13:00 +00:00
Leonardo de Moura
a84639f63e feat: improve equality support in cutsat (#7217)
This PR improves the support for equalities in cutsat.
2025-02-24 23:35:04 +00:00
Kim Morrison
d9ab758af5 chore: re-enable List variable linter (#7215)
Turns back on the variable names linters across List/Array/Vector.
2025-02-24 23:34:01 +00:00
Leonardo de Moura
5cbeb22564 feat: add ForIn instance for PHashSet (#7214)
This PR adds a `ForIn` instance for the `PersistentHashSet` type.
2025-02-24 20:37:45 +00:00
Tobias Grosser
77e0fa4efe chore: use getElem in RHS of getElem theorems (#7187)
This PR moves the RHS of getElem theorems to use getElem. This is a
cleanup after the recent move to getElem as simp normal form.

We also turn `((!decide (i < n)) && getLsbD x (i - n))` into `if h' : i
< n then false else x[i - n]` to preserve the bounds, but keep the
decide if the dependent if is not needed to maintain a getElem on the
RHS.
2025-02-24 18:32:48 +00:00
Mac Malone
69efb78319 fix: lake: MSYS2 OSTYPE change (#7209)
This PR fixes broken Lake tests on Windows' new MSYS2. As of MSYS2
0.0.20250221, `OSTYPE` is now reported as `cygwin` instead of `msys`,
which must be accounted for in a few Lake tests.

See https://www.msys2.org/news/#2025-02-14-moving-msys2-closer-to-cygwin
for more details.
2025-02-24 17:10:13 +00:00
Luisa Cicolini
32a9392a11 feat: add BitVec.toFin_abs (#7206)
This PR adds theorem `BitVec.toFin_abs`, completing the API for
`BitVec.*_abs`.

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2025-02-24 17:02:51 +00:00
Paul Reichert
af741abbf5 feat: TreeMap lemmas for 'get?' (#7167)
This PR provides tree map lemmas for the interaction of `get?` with the
other operations for which lemmas already exist.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-24 15:34:37 +00:00
Markus Himmel
36723d38b9 feat: UIntX conversion lemmas (part 1/n) (#7174)
This PR adds the first batch of lemmas about iterated conversions
between finite types starting with something of type `UIntX`.
2025-02-24 12:48:37 +00:00
Kim Morrison
3ebce4e190 feat: align lemmas about List.getLast(!?) with Array/Vector.back(!?) (#7205)
This PR completes alignment of
`List.getLast`/`List.getLast!`/`List.getLast?` lemmas with the
corresponding lemmas for Array and Vector.
2025-02-24 11:48:43 +00:00
Paul Reichert
c934e6c247 feat: tree map lemmas about containsThenInsert(IfNew) (#7165)
This PR provides tree map lemmas about the interaction of
`containsThenInsert(IfNew)` with `contains` and `insert(IfNew)`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-24 09:01:45 +00:00
Eric Wieser
57c8ab269b feat: allow line-wrapping when printing DiscrTree.Keys (#7200)
This PR allows the debug form of DiscrTree.Key to line-wrap.
2025-02-24 07:52:47 +00:00
Leonardo de Moura
e7dc0d31f4 feat: improve support for equations in cutsat (#7203)
This PR improves the support for equalities in cutsat. It also
simplifies a few support theorems used to justify cutsat rules.
2025-02-24 04:48:14 +00:00
Leonardo de Moura
1819dc88ff feat: cutsat relevant-term internalization (#7202)
This PR adds support for internalizing terms relevant to the cutsat
module. This is required to implement equality propagation.
2025-02-24 01:49:51 +00:00
Kim Morrison
e1fade23ec feat: align List/Array/Vector.leftpad (#7201)
This PR adds `Array/Vector.left/rightpad`. These will not receive any
verification theorems; simp just unfolds them to an `++` operation.
2025-02-24 01:39:01 +00:00
Kim Morrison
27e1391e6d feat: complete comparison theorems for ediv/tdiv/fdiv and emod/tmod/fmod (#7199)
This PR adds theorems comparing `Int.ediv` with `tdiv` and `fdiv`, for
all signs of arguments. (Previously we just had the statements about the
cases in which they agree.)
2025-02-24 01:01:40 +00:00
Kim Morrison
da32bdd79c chore: additional newline before 'additional diagnostic information' message (#7169)
This PR adds an addition newline before the "Additional diagnostic
information may be available using the `set_option ... true` command."
messages, to provide better visual separation from the main error
message.
2025-02-23 23:27:33 +00:00
Kyle Miller
b863ca9ae9 chore: post-#7100 cleanup (#7196)
This PR does some stage0 cleanup after #7100, and enables a warning when
the old `structure S extends P : Type` syntax is used. It also updates
the library to put resulting types in the new correct place (`structure
S : Type extends P`).

The `structure` elaborator also has some additional docstrings, and
`StructFieldKind.fromParent` is renamed to
`StructFieldKind.fromSubobject`.
2025-02-23 22:46:22 +00:00
euprunin
c3b01fbd53 doc: remove Trepplein example (Lean 3) (#7197)
This PR removes a reference to Trepplein (Lean 3) in the documentation.

Co-authored-by: euprunin <euprunin@users.noreply.github.com>
2025-02-23 21:39:45 +00:00
Leonardo de Moura
ad1e04c826 feat: simp diagnostics in grind (#6902)
This PR ensures `simp` diagnostic information in included in the `grind`
diagnostic message.
2025-02-23 17:55:17 +00:00
Leonardo de Moura
c8dc66b6c1 feat: helper theorems for solving equality in cutsat (#7194)
This PR adds support theorems for solving equality in cutsat.
2025-02-23 03:26:12 +00:00
Leonardo de Moura
d234b78cc0 chore: cutsat equality infrastructure (#7193)
This PR adds basic infrastructure for adding support for equalities in
cutsat.
2025-02-23 02:27:53 +00:00
Leonardo de Moura
1ae084b5f8 chore: cutsat cleanup (#7189)
This PR also removes unnecessary `mkExpectedTypeHint`s.
2025-02-22 18:35:02 +00:00
Leonardo de Moura
ddeb5ac535 refactor: cutsat (#7186)
This PR simplifies the proofs and data structures used by cutsat.
2025-02-22 17:25:42 +00:00
Sebastian Ullrich
6ff5c4c278 chore: don't forget about namespace reservation for async-unsupported constant kinds (#6987) 2025-02-22 16:45:40 +00:00
Sebastian Ullrich
087f0b4a69 perf: optimize sorry detection in unused variables linter (#7129)
This PR optimizes the performance of the unused variables linter in the
case of a definition with a huge `Expr` representation
2025-02-22 16:43:39 +00:00
Marc Huisinga
a7bdc55244 fix: inlay hint race conditions (#7188)
This PR fixes several inlay hint race conditions that could result in a
violation of the monotonic progress assumption, introduced in #7149.

Specifically:
- In rare circumstances, it could happen that stateful LSP requests were
executed out-of-order with their `didChange` handlers, as both requests
and the `didChange` handlers waited on `lake setup-file` to complete,
with the latter running those handlers in a dedicated task afterwards.
This meant that a request could be added to the stateful LSP handler
request queue before the corresponding `didChange` call that actually
came before it. This PR resolves this issue by folding the task that
waits for `lake setup-file` into the `RequestContext`, which ensures
that we only need to wait for it when actually executing the request
handler.
- While #7164 fixed the monotonic progress assertion violation that was
caused by `$/cancelRequest`, it did not account for our internal notion
of silent request cancellation in stateful LSP requests, which we use to
cancel the inlay hint edit delay when VS Code fails to emit a
`$/cancelRequest` notification. This issue is resolved by always
producing the full finished prefix of the command snapshot queue, even
on cancellation. Additionally, this also fixes an issue where in the
same circumstances, the language server could produce an empty inlay
hint response when a request was cancelled by our internal notion of
silent request cancellation.
- For clients that use `fullChange` `didChange` notifications (e.g. not
VS Code), we would get several aspects of stateful LSP request
`didChange` state handling wrong, which is also addressed by this PR.
2025-02-22 16:35:30 +00:00
Cameron Zwarich
647573d269 feat: support LEAN_BACKTRACE on macOS (#7184)
This PR adds support for LEAN_BACKTRACE on macOS. This previously only
worked with glibc, but it can not be enabled for all Unix-like systems,
since e.g. Musl does not support it.
2025-02-22 15:29:37 +00:00
Sebastian Ullrich
788a7ec502 test: avoid re-elaboration of interactive runner (#7177)
Before/after:
```
make -C build/release test ARGS="-j$(nproc) -R interactive"  208.10s user 20.93s system 1982% cpu 11.552 total
make -C build/release test ARGS="-j$(nproc) -R interactive"  87.22s user 22.58s system 1454% cpu 7.548 total
```
2025-02-22 10:36:25 +00:00
Mac Malone
3aef45c45b fix: lake: setup-file on an invalid Lean config (#7182)
This PR makes `lake setup-file` succeed on an invalid Lean configuration
file.

The server will disable interactivity if `setup-file` fails. When
editing the workspace configuration file, this behavior has the prior
effect of making the configuration file noninteractive if saved with an
invalid configuration.
2025-02-22 04:48:48 +00:00
Leonardo de Moura
1f5c66db79 feat: improve cutsat model search procedure (#7183)
This PR improves the cutsat model search procedure.
2025-02-21 23:51:53 +00:00
Sebastian Ullrich
d42d6c5246 fix: do not cancel async elaboration tasks (#7175)
This PR fixes an `Elab.async` regression where elaboration tasks are
cancelled on document edit even though their result may be reused in the
new document version, reporting an incomplete result.

While this PR fixes the functional regression, it does so as an
over-approximation by never cancelling such tasks. A follow-up PR will
implement the correct behavior of only cancelling the tasks that are not
reused.
2025-02-21 17:24:36 +00:00
Leonardo de Moura
d1aba29b57 feat: model construction for divisibility constraints in cutsat (#7176)
This PR implements model construction for divisibility constraints in
the cutsat procedure.
2025-02-21 16:17:32 +00:00
Johannes Tantow
0c35ca2e39 feat: verify fold/for variants for Hashmaps (#7137)
This PR verifies the various fold and for variants for hashmaps.

---------

Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
2025-02-21 16:08:33 +00:00
Sebastian Ullrich
6e77bee098 feat: Elab.Deriving trace on applyDerivingHandlers (#7173)
This PR introduces a trace node for each deriving handlers invocation
for the benefit of `trace.profiler`
2025-02-21 09:27:41 +00:00
Mac Malone
1ee21c17fc feat: use Lake plugin for Lake imports (#7157)
This PR changes `lake setup-file` to now use Lake as a plugin for files
which import Lake (or one of its submodules). Thus, the server will now
load Lake as a plugin when editing a Lake configuration written in Lean.
This further enables the use of builtin language extensions in Lake.
2025-02-21 05:07:13 +00:00
Mac Malone
aea58113cb feat: run setup-file on lakefiles (#7153)
This PR changes the server to run `lake setup-file` on Lake
configuration files (e.g., `lakefile.lean`).

This is needed to support Lake passing the server its own Lake plugin to
load when elaborating the configuration file.
2025-02-21 04:04:10 +00:00
Mac Malone
36c798964e feat: staged CMake build with Lake as a plugin (#6929)
This PR passes the shared library of the previous stage's Lake as a
plugin to the next stage's Lake in the CMake build. This enables Lake to
use its own builtin elaborators / initializers at build time.
2025-02-21 04:03:50 +00:00
Kim Morrison
6c609028b3 feat: upgrade Int.tdiv_eq_ediv to an unconditional equivalence (#7163)
This PR gives an unconditional theorem expressing `Int.tdiv` in terms of
`Int.ediv`, not just for non-negative arguments.
2025-02-20 23:46:11 +00:00
Paul Reichert
a3a99d3875 feat: more tree map lemmas about empty, isEmpty, contains, size, insert, erase (#7161)
This PR adds all missing tree map lemmas about the interactions of the
functions `empty`, `isEmpty`, `contains`, `size`, `insert(IfNew)` and
`erase`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-20 15:33:41 +00:00
Marc Huisinga
970732ea11 fix: inlay hint assertion violation (#7164)
This PR fixes an assertion violation introduced in #7149 where the
monotonic progress assumption was violated by request cancellation.
2025-02-20 13:03:44 +00:00
Kim Morrison
2eb478787f chore: split Int.DivModLemmas into Bootstrap and Lemmas (#7162)
This PR splits `Int.DivModLemmas` into a `Bootstrap` and `Lemmas` file,
where it is possible to use `omega` in `Lemmas`.

I'm going to add more theory, particularly about `fdiv` and `tdiv` to
the `Lemmas` file, and would prefer to have access to `omega`.
2025-02-20 12:05:09 +00:00
Marc Huisinga
b49ec19167 feat: more robust server parallelism (#7087)
This PR ensures that all tasks in the language server either use
dedicated tasks or reuse an existing thread from the thread pool. This
ensures that elaboration tasks cannot prevent language server tasks from
being scheduled. This is especially important with parallelism right
around the corner and elaboration becoming more likely to starve the
language server of computation, which could drive up language server
latencies significantly on machines with few cores.

Specifically, all language server tasks are refactored to use a new thin
`ServerTask` API wrapper with a single "costly" vs "cheap" dimension,
where costly tasks are always scheduled as dedicated tasks, and cheap
tasks are always made to either run on the calling thread or to reuse
the thread of the task being mapped on by using the `sync` flag.

ProofWidgets4 adaption PR:
https://github.com/leanprover-community/ProofWidgets4/pull/106

### Other changes
- This PR makes several tasks dedicated that weren't dedicated before,
and uses `sync := true` for some others. The rules for this are
described in the module docstring of `ServerTask.lean`.
- Most notably, the reporting task in the file worker was *not* a
dedicated task before this PR, which could easily lead to thread pool
starvation on successive changes. It also did not support cancellation.
This PR ensures that it does.

### Breaking changes

- `RequestTask` and the request-oriented snapshot API are refactored to
use `ServerTask` instead of `Task`. All functions in `Task` have close
analogues in `ServerTask`, and functions on `RequestTask` now need to
distinguish between whether a `map` or a `bind` is cheap or costly. This
affects all downstream users of `RequestM`, e.g. tools that extend the
language server with their own requests, or some users of the RPC
mechanism.
- The following unused functions of the `AsyncList` API have been
deleted: `append`, `unfoldAsync`, `getAll`, `waitHead?`, `cancel`
2025-02-20 10:54:22 +00:00
Paul Reichert
adcba851f0 feat: modify and alter functions for the tree map (#7118)
This PR implements the functions `modify` and `alter` on the tree map.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-20 09:50:10 +00:00
Marc Huisinga
cc94cff735 feat: fast path for inlay hints (#7149)
This PR adds a fast path to the inlay hint request that makes it re-use
already computed inlay hints from previous requests instead of
re-computing them. This is necessary because for some reason VS Code
emits an inlay hint request for every line you scroll, so we need to be
able to respond to these requests against the same document state
quickly. Otherwise, every single scrolled line would result in a request
that can take a few dozen ms to be responded to in long files, putting
unnecessary pressure on the CPU.
It also filters the result set by the inlay hints that have been
requested.
2025-02-20 09:26:16 +00:00
Kim Morrison
2960b384af feat: strengthen Int.tdiv_eq_ediv (#7158)
This PR strengthens `Int.tdiv_eq_ediv`, by dropping an unnecessary
hypothesis, in preparation for further work on `ediv`/`tdiv`/`fdiv`
lemmas.
2025-02-20 05:57:47 +00:00
Leonardo de Moura
2c2b3641f1 feat: helper theorem for cutsat (#7156)
This PR adds a helper theorem that will be used in divisibility
constraint conflict resolution during model construction.
2025-02-20 05:39:49 +00:00
Leonardo de Moura
746e3a9f42 feat: model search skeleton for cutsat (#7155)
This PR implements some infrastructure for the model search procedure in
cutsat.
2025-02-20 03:41:39 +00:00
Kim Morrison
6a4225bf04 chore: complete variable name linting for Vector (#7154) 2025-02-20 02:42:50 +00:00
Leonardo de Moura
c86073830f feat: infrastructure for inequalities constraints in cutsat (#7152)
This PR implements the infrastructure for supporting integer inequality
constraints in the cutsat procedure.
2025-02-19 23:09:12 +00:00
Joachim Breitner
8672186a4e refactor: use more fun_induction in Init.Data.Int.Linear (#7142)
This uses the improved functional induction theorems from #7140.
2025-02-19 22:56:23 +00:00
Joachim Breitner
5bee3288ac refactor: update proofs after stage0 update for #7140 2025-02-19 20:59:01 +01:00
Joachim Breitner
eeb74ecf4d chore: update stage0 2025-02-19 20:59:01 +01:00
Joachim Breitner
36704e33bd feat: FunInd to split on bif as well
This PR treats `bif` (aka `cond`) like `if` in functional induction principles. It
introduces the `Bool.dcond` definition, with a docstring indicating that
this is for internal use.
2025-02-19 20:59:01 +01:00
Kim Morrison
8a2e21cfc4 chore: linting variable names in List/Array (#7146) 2025-02-19 12:45:02 +00:00
Lean stage0 autoupdater
3deda3c6df chore: update stage0 2025-02-19 12:38:31 +00:00
Joachim Breitner
e288e9c57e test: add f91 definition using partial_fixpoint (#7144) 2025-02-19 11:13:53 +00:00
Marc Huisinga
26dba92ce9 feat: faster auto-completion (#7134)
This PR significantly improves the performance of auto-completion by
optimizing individual requests by a factor of ~2 and by giving language
clients like VS Code the opportunity to reuse the state of previous
completion requests, thus greatly reducing the latency for the
auto-completion list to update when adding more characters to an
identifier.

In my testing: 
- The latency of completing `C` in a file with `import Mathlib` was
reduced from ~1650ms to ~800ms
- The latency of completing `Cat` in a file with `import Mathlib` was
reduced from ~800ms to ~430ms
- The latency of completing dot notation was mostly unaffected
- Successive completions are now practically instant, e.g. if we were to
complete `C` and then type it out to `Cat`, before it would take roughly
~1650ms + ~800ms, whereas now there is only a significant latency for
completing `C` (~800ms) and the completion list is updated practically
instantly when typing out `Cat`.

<details> 
  <summary>(Video) Auto-completion latency before this PR</summary>

![Auto-completion latency before this
PR](https://github.com/user-attachments/assets/125bc1ba-b14c-477b-9580-d8067c641342)
</details>

<details> 
  <summary>(Video) Auto-completion latency after this PR</summary>

![Auto-completion latency after this
PR](https://github.com/user-attachments/assets/43d4b587-d51f-4877-aaef-424ecc771490)
</details>

In detail, this PR makes the following changes:
- Set `isIncomplete` to `false` in non-synthetic completion responses so
that the client can re-use these completion states.
- Replace the server side fuzzy matching with a simple and fast check
that all characters in the identifier thus far are present in the same
order in the declaration to match against. There are some examples where
the simple and fast check yields a completion item that the fuzzy
matching would filter, but since VS Code filters the completion items
with its own fuzzy matching after that anyways, these extra completion
items are never actually displayed to the user.
- Remove all notions of scoring and sorting completion items from the
language server. We now rely entirely on the client to sort the
completion items as it sees fit. In my testing, the only significant
change as a result of this is that while the language server would
sometimes penalize namespaces with lots of components, VS Code instead
uses a strictly alphabetic order. Even before this change, we never
actually really prioritized local variables over global variables, so
the penalty wasn't very helpful in practice. We might add some small
form of local variable prioritization in the future, though.
- Remove the empty completion list hack that was introduced in #1885. It
does not appear to be necessary anymore.
2025-02-19 10:05:18 +00:00
Leonardo de Moura
1cbd2bd199 feat: create a let-expression for storing the context in cutsat proofs (#7139)
This PR uses a `let`-expression for storing the (shared) context in
proofs produced by the cutsat procedure in `grind`.
2025-02-19 03:36:13 +00:00
Mac Malone
a41fb49e25 feat: smarter plugin loading (#7090)
This PR strips `lib` prefixes and `_shared` suffixes from plugin names.
It also moves most of the dynlib processing code to Lean to make such
preprocessing more standard.
2025-02-18 23:03:52 +00:00
Leonardo de Moura
dfce31e2a2 feat: proof production for divisibility constraint solver in grind (#7138)
This PR implements proof generation for the divisibility constraint
solver in `grind`.
2025-02-18 22:38:30 +00:00
Kim Morrison
1d9b19189a chore: deprecate Array.get
fix test
2025-02-19 08:48:33 +11:00
Kim Morrison
d3c36bd7cf chore: use as[i] instead of as.get i 2025-02-19 08:48:33 +11:00
Kim Morrison
950fbc9d8f chore: update stage0 2025-02-19 08:48:33 +11:00
Kim Morrison
167e0ab301 chore: add Array.getInternal, also @[extern] 2025-02-19 08:48:33 +11:00
Joachim Breitner
2fed93462d feat: try? to use fun_induction (#7082)
This PR makes `try?` use `fun_induction` instead of `induction … using
foo.induct`. It uses the argument-free short-hand `fun_induction foo` if
that is unambiguous. Avoids `expose_names` if not necessary by simply
trying without first.
2025-02-18 16:06:58 +00:00
Kyle Miller
2d4c0017b8 chore: review uses of generalize (#7126)
This PR looks at some uses of the `generalize` tactic, especially when
used in conjunction with `induction`.
2025-02-18 14:07:40 +00:00
Markus Himmel
3a22035dad feat: IntX.abs (#7131)
This PR adds `IntX.abs` functions. These are specified by `BitVec.abs`,
so they map `IntX.minValue` to `IntX.minValue`, similar to Rust's
`i8::abs`. In the future we might also have versions which take values
in `UIntX` and/or `Nat`.
2025-02-18 13:16:30 +00:00
Johannes Tantow
010c6c36f1 feat: verify toList for hash maps (#6954)
This PR verifies the `toList`function for hash maps and dependent hash
maps.
2025-02-18 13:10:03 +00:00
Joachim Breitner
a3b76aa825 feat: fun_induction foo (no arguments) (#7101)
This PR implements `fun_induction foo`, which is like `fun_induction foo
x y z`, only that it picks the arguments to use from a unique suitable
call to `foo` in the goal.
2025-02-18 12:27:21 +00:00
Lean stage0 autoupdater
9d5f565119 chore: update stage0 2025-02-18 12:15:21 +00:00
Joachim Breitner
f3baff8dce fix: fun_induction to generalize like induction does (#7127)
This PR follows up on #7103 which changes the generaliziation behavior
of `induction`, to keep `fun_induction` in sync. Also fixes a `Syntax`
indexing off-by-one error.
2025-02-18 11:03:56 +00:00
Markus Himmel
a26c937650 feat: Repr and Hashable for IntX (#7128)
This PR adds `Repr` and `Hashable` instances for `IntX`.
2025-02-18 11:03:53 +00:00
Marc Huisinga
0929cb3902 chore: remove semantic highlighting timeout (#7130)
Shot in the dark to resolve semantic highlighting issues. We don't
really need the timeout for semantic tokens anyways.
2025-02-18 10:24:49 +00:00
Paul Reichert
403e942f37 feat: getKey functions for the tree map (#7116)
This PR implements the `getKey` functions on the tree map. It also fixes
the naming of the `entryAtIdx` function on the tree set, which should
have been called `atIdx`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-18 09:29:57 +00:00
Paul Reichert
d9e7ded5af feat: getThenInsertIfNew? and partition functions for the tree map (#7109)
This PR implements the `getThenInsertIfNew?` and `partition` functions
on the tree map.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-18 08:29:24 +00:00
Eric Wieser
4e10e4e02e feat: make linter names clickable in trace messages (#7119)
This PR makes linter names clickable in the `trace.profiler` output.
2025-02-18 07:58:47 +00:00
Kyle Miller
7557542bc2 feat: make structure parent projections nameable (#7100)
This PR modifies the `structure` syntax so that parents can be named,
like in
```lean
structure S extends toParent : P
```
**Breaking change:** The syntax is also modified so that the resultant
type comes *before* the `extends` clause, for example `structure S :
Prop extends P`. This is necessary to prevent a parsing ambiguity, but
also this is the natural place for the resultant type. Implements RFC
#7099.

Will need followup PRs for cleanup after a stage0 update.
2025-02-18 07:38:13 +00:00
Kyle Miller
219f36f499 chore: cleanup after stage0 update for #7103 (#7125)
This PR cleans up the bootstrapping workarounds introduced in #7103
(`induction` target generalization equation names).
2025-02-18 05:55:49 +00:00
Leonardo de Moura
b5bf7d4b87 feat: cutsat divisibility constraint solver proof by reflection theorems (#7124)
This PR adds the helper theorems for justifying the divisibility
constraint solver in the cutsat procedure used by the `grind` tactic.
2025-02-18 04:30:09 +00:00
Lean stage0 autoupdater
d6b3da5e72 chore: update stage0 2025-02-18 04:53:24 +00:00
Kyle Miller
6a59926592 feat: add generalization hypotheses to induction tactic (#7103)
This PR gives the `induction` tactic the ability to name hypotheses to
use when generalizing targets, just like in `cases`. For example,
`induction h : xs.length` leads to goals with hypotheses `h : xs.length
= 0` and `h : xs.length = n + 1`. Target handling is also slightly
modified for multi-target induction principles: it used to be that if
any target was not a free variable, all of the targets would be
generalized (thus causing free variables to lose their connection to the
local hypotheses they appear in); now only the non-free-variable targets
are generalized.

This gives `induction` the last basic feature of the mathlib
`induction'` tactic, which has been long-requested. Recent Zulip
discussion:
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/To.20replace.20.60induction'.20h.20.3A.20f.20x.60/near/499482173
2025-02-18 03:46:23 +00:00
Kim Morrison
b5b407343a chore: make internal List getters private (#7123) 2025-02-18 03:24:25 +00:00
Leonardo de Moura
97fb0b82bb feat: add divisibility constraint solver to grind (#7122)
This PR implements the divisibility constraint solver for the cutsat
procedure in the `grind` tactic.
2025-02-18 02:43:35 +00:00
Kim Morrison
ca253ae4cf chore: repair defeqs for List GetElem instances (#7121)
This PR repairs some defeq breakages from #7059.
2025-02-18 02:19:08 +00:00
Kim Morrison
4b307914fc chore: cleanup duplicate theorems (#7113) 2025-02-18 01:46:12 +00:00
Joachim Breitner
2cdf4b14e1 chore: update code after #7110 2025-02-17 18:21:10 +01:00
Joachim Breitner
1a374ceab2 chore: update stage0 2025-02-17 18:21:10 +01:00
Joachim Breitner
2a7b1162af fix: FunInd to clear match discriminants if possible
This PR tries to remove from functional induction principles hypotheses
that have been matched, as we expect the corresponding pattern to be
more useful. This avoids duplicate hypotheses due to the way `match`
refines hypotheses. Fixes #6281.
2025-02-17 18:21:10 +01:00
Paul Reichert
16e9700224 feat: values and valuesArray functions for the tree map (#7114)
This PR implements the methods `values` and `valuesArray` on the tree
map.

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-17 15:57:11 +00:00
Markus Himmel
5a8b4459c8 feat: conversions between Float and finite integers (#7083)
This PR adds (value-based, not bitfield-based) conversion functions
between `Float`/`Float32` and `IntX`/`UIntX`.
2025-02-17 15:42:10 +00:00
Marc Huisinga
3825c48405 feat: auto-implicit inlay hint tooltip & instance inlay hints (#7112)
This PR adds a tooltip describing what the auto-implicit inlay hints
denote, as well as auto-implicit inlay hints for instances.
2025-02-17 15:34:35 +00:00
Kim Morrison
f07e72fad7 chore: linting variable names for List (#7107) 2025-02-17 14:50:43 +00:00
Paul Reichert
3599e43284 feat: min, max, minKey, maxKey, atIndex, getEntryLE, getKeyLE, ... functions for the tree map (#7070)
This PR implements the methods `min`, `max`, `minKey`, `maxKey`,
`atIndex`, `getEntryLE`, `getKeyLE` and consorts on the tree map.

In order to implement the proof-based functions such as `min` and
`getEntryLT` in `Queries.lean`, it was necessary to extract `Balanced`
and `Ordered` into new files so that they can be used from
`Queries.lean`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-17 14:00:42 +00:00
Markus Himmel
88fb7c0199 doc: style guide additions (#7111)
This PR extends the standard library style guide with guidance on
universe variables, notations and Unicode usage, and structure
definitions.
2025-02-17 11:57:22 +00:00
Sebastian Ullrich
2649d1510e fix: race condition led to (sync := true) tasks being spawned as separate dedicated tasks (#7089)
If the first task finished between the first check and taking the task
manager lock, the second task would be enqueued as if given
`Priority.max` instead of being run inline.
2025-02-17 09:52:40 +00:00
Paul Reichert
5d7cf08260 feat: tree map lemmas about empty, isEmpty, insert, contains (#6850)
This PR adds some lemmas about the new tree map. These lemmas are about
the interactions of `empty`, `isEmpty`, `insert`, `contains`. Some
lemmas about the interaction of `contains` with the others will follow
in a later PR.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-17 08:44:52 +00:00
Kim Morrison
88664e4a99 feat: complete aligning List/Array/Vector.finRange (#7106)
This PR completes the alignment of `List/Array/Vector.finRange` lemmas.
2025-02-17 06:11:43 +00:00
Kim Morrison
9d1fb9f4fa feat: align Array/Vector.extract lemmas with List (#7105)
This PR completes aligning `Array/Vector.extract` lemmas with the lemmas
for `List.take` and `List.drop`.
2025-02-17 04:56:04 +00:00
Luisa Cicolini
6a17e62523 feat: add BitVec.[(getMsbD, msb)_extractLsb', (getLsbD, getMsbD, msb)_extractLsb] , add and_eq_decide, or_eq_decide, decide_eq_true_iff to bool_to_prop (#6792)
This PR adds theorems `BitVec.(getMsbD, msb)_(extractLsb', extractLsb),
getMsbD_extractLsb'_eq_getLsbD`.

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
Co-authored-by: Alex Keizer <alex@keizer.dev>
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Tobias Grosser <tobias@grosser.es>
Co-authored-by: Tobias Grosser <github@grosser.es>
2025-02-17 03:02:37 +00:00
Kim Morrison
1ce7047bf5 feat: cleanup of get and back functions on List/Array (#7059)
This PR moves away from using `List.get` / `List.get?` / `List.get!` and
`Array.get!`, in favour of using the `GetElem` mediated getters. In
particular it deprecates `List.get?`, `List.get!` and `Array.get?`. Also
adds `Array.back`, taking a proof, matching `List.getLast`.
2025-02-17 01:43:45 +00:00
Leonardo de Moura
ef759d874f fix: grind using reducible transparency setting (#7102)
This PR modifies `grind` to run with the `reducible` transparency
setting. We do not want `grind` to unfold arbitrary terms during
definitional equality tests. This PR also fixes several issues
introduced by this change. The most common problem was the lack of a
hint in proofs, particularly in those constructed using proof by
reflection. This PR also introduces new sanity checks when `set_option
grind.debug true` is used.
2025-02-16 22:30:04 +00:00
Kitamado
6f5bb3e896 fix: allow trailing comma in array syntax (#7055)
This PR improves array and vector literal syntax by allowing trailing
commas. For example, `#[1, 2, 3,]`.

see: [Why Are Trailing Commas Not Allowed in Array
Literals?](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Why.20Are.20Trailing.20Commas.20Not.20Allowed.20in.20Array.20Literals.3F)

Note: we need to preserve the current name for the array syntax
(`«term#[_,]»`) to avoid a bootstrapping issue. The `FromJson`/`ToJson`
deriving handlers use array syntax in macros, and the stage0 version is
used in most of the prelude.
2025-02-16 19:26:23 +00:00
Joachim Breitner
96c6f9dc96 feat: fun_induction and fun_cases tactics (#7069)
This PR adds the `fun_induction` and `fun_cases` tactics, which add
convenience around using functional induction and functional cases
principles.

```
fun_induction foo  x y z
```
elaborates `foo x y z`, then looks up `foo.induct`, and then essentially
does
```
induction z using foo.induct y
```
including and in particular figuring out which arguments are parameters,
targets or dropped. This only works for non-mutual functions so far.

Likewise there is the `fun_cases` tactic using `foo.fun_cases`.
2025-02-16 10:59:56 +00:00
Leonardo de Moura
f50b863868 feat: cutsat helper functions (#7098)
This PR adds some helper functions for cutsat in the `grind` tactic.
2025-02-16 05:32:46 +00:00
Leonardo de Moura
dd3652ecdc feat: cutsat preparations (#7097)
This PR implements several modifications for the cutsat procedure in
`grind`.
- The maximal variable is now at the beginning of linear polynomials. 
- The old `LinearArith.Solver` was deleted, and the normalizer was moved
to `Simp`.
- cutsat first files were created, and basic infrastructure for
representing divisibility constraints was added.
2025-02-16 02:52:14 +00:00
Tobias Grosser
a9efbf04f4 feat: make BitVec.getElem the simp normal form and use it in ext (#5498)
This PR makes `BitVec.getElem` the simp normal form in case a proof is
available and changes `ext` to return `x[i]` + a hypothesis that proves
that we are in-bounds. This aligns `BitVec` further with the API
conventions of the Lean standard datatypes.

We move our proofs to this new normal form, which results in slightly
smaller proofs. With the exception of `getElem_ofFin`, no new API
surface is added as the `getElem` API has already been completed over
the previous months. We also move `getElem_shiftConcat_*` a bit higher
as they are needed in earlier proofs. To keep the changeset small, we do
not update the API of `BVDecide` but insert `←
BitVec.getLsbD_eq_getElem` at the few locations where it is needed.
Finally, we add a simproc for getElem, mirroring the existing ones for
getLsbD/getMsdD.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
2025-02-16 00:04:56 +00:00
Leonardo de Moura
3a76ac5620 chore: cleanup and missing grind normalization rules (#7095)
This PR adds missing `grind` normalization rules, and removes dead
theorems.
2025-02-15 23:45:35 +00:00
Leonardo de Moura
747ea91c3a refactor: add denote' functions to Int/Linear.lean (#7094)
This PR adds the functions `Poly.denote'`, `RelCnstr.denote'`, and
`DvdCnstr.denote'`. These functions are useful for representing the
denotation of normalized results in `simp +arith` and the `grind`
preprocessor. This PR also adjusts all auxiliary normalization theorems
to use them to represent the normalized constraints. Previously, we were
converting `RelCnstr` and `DvdCnstr` back into raw constraints. While
this overhead was reasonable for `simp +arith`, it is not for the cutsat
procedure, which has no need for raw constraints. All constraints have
already been normalized by the time they reach cutsat.
2025-02-15 22:10:23 +00:00
Leonardo de Moura
ecdc2d57f2 refactor: Int.Linear module (#7093)
This PR cleans up the `Int.Linear` module by normalizing function and
type names and adding documentation strings. We will use it to implement
cutsat in the `grind` tactic.
2025-02-15 19:20:18 +00:00
Leonardo de Moura
f4afcfc923 feat: divisibility constraint normalizer (#7092)
This PR implements divisibility constraint normalization in `simp
+arith`.
2025-02-15 04:20:40 +00:00
jrr6
9cce0ce8d9 fix: ensure get_elem_tactic works in absence of goals (#7088)
This PR fixes the behavior of the indexed-access notation `xs[i]` in
cases where the proof of `i`'s validity is filled in during unification.

Closes #6999.
2025-02-15 03:00:36 +00:00
Leonardo de Moura
57aadf8af9 feat: add helper theorems for normalizing divisibility constraints (#7091)
This PR adds helper theorems for normalizing divisibility constraints.
They are going to be used to implement the cutsat procedure in the
`grind` tactic.
2025-02-15 02:44:49 +00:00
Kyle Miller
1babe9fc67 feat: make binders in #check be hoverable (#7074)
This PR modifies the signature pretty printer to add hover information
for parameters in binders. This makes the binders be consistent with the
hovers in pi types.

Suggested by @david-christiansen
2025-02-14 17:28:54 +00:00
Markus Himmel
dd1a4188a0 feat: Fin.toNat (#7079)
This PR introduces `Fin.toNat` as an alias for `Fin.val`. We add this
function for discoverability and consistency reasons. The normal form
for proofs remains `Fin.val`, and there is a `simp` lemma rewriting
`Fin.toNat` to `Fin.val`.
2025-02-14 11:59:44 +00:00
Markus Himmel
ed42d068d4 feat: UIntX.ofNatTruncate (#7080)
This PR adds the functions `UIntX.ofNatTruncate` (the version for
`UInt32` already exists).
2025-02-14 11:59:41 +00:00
Markus Himmel
784444c7a9 feat: IntX.minValue, IntX.maxValue, IntX.ofIntLE, IntX.ofIntTruncate (#7081)
This PR adds functions `IntX.ofIntLE`, `IntX.ofIntTruncate`, which are
analogous to the unsigned counterparts `UIntX.ofNatLT` and
`UInt.ofNatTruncate`.
2025-02-14 11:59:37 +00:00
Marc Huisinga
05fb67af90 feat: request cancellation (#7054)
This PR adds language server support for request cancellation to the
following expensive requests: Code actions, auto-completion, document
symbols, folding ranges and semantic highlighting. This means that when
the client informs the language server that a request is stale (e.g.
because it belongs to a previous state of the document), the language
server will now prematurely cancel the computation of the response in
order to reduce the CPU load for requests that will be discarded by the
client anyways.
2025-02-14 11:55:43 +00:00
Marc Huisinga
22d1d04059 fix: incremental goal state requests select incomplete snapshot (#6887)
This PR fixes a bug where the goal state selection would sometimes
select incomplete incremental snapshots on whitespace, leading to an
incorrect "no goals" response. Fixes #6594, a regression that was
originally introduced in 4.11.0 by #4727.

The fundamental cause of #6594 was that the snapshot selection would
always select the first snapshot with a range that contains the cursor
position. For tactics, whitespace had to be included in this range.
However, in the test case of #6594, this meant that the snapshot
selection would also sometimes pick a snapshot before the cursor that
still contains the cursor in its whitespace, but which also does not
necessarily contain all the information needed to produce a correct goal
state. Specifically, at the `InfoTree`-level, when the cursor is in
whitespace, we distinguish competing goal states by their level of
indentation. The snapshot selection did not have access to this
information, so it necessarily had to do the wrong thing in some cases.

This PR fixes the issue by adjusting the snapshot selection for goals to
explicitly account for whitespace and indentation, and refactoring the
language processor architecture to thread enough information through to
the snapshot selection so that it can decide which snapshots to use
without having to force too many tasks, which would destroy
incrementality in goal state requests.

Specifically, this PR makes the following adjustments:
- Refactor `SnapshotTask` to contain both a `Syntax` and a `Range`.
Before, `SnapshotTask`s had a single range that was used both for
displaying file progress information and for selecting snapshots in
server requests. For most snapshots, this range did not include
whitespace, though for tactics it did. Now, the `reportingRange` field
of `SnapshotTask` is intended exclusively for reporting file progress
information, and the `Syntax` is used for selecting snapshots in server
requests. Importantly, the `Syntax` contains the full range information
of the snapshot, i.e. its regular range and its range including
whitespace.
- Adjust all call-sites of `SnapshotTask` to produce a reasonable
`Syntax`.
- Adjust the goal snapshot selection to account for whitespace and
indentation, as the `InfoTree` goal selection does.
- Fix a bug in the snapshot tree tracing that would cause it to render
the `Info` of a snapshot at the wrong location when `trace.Elab.info`
was also set.

This PR is based on #6329.
2025-02-14 11:53:24 +00:00
Paul Reichert
36ac6eb912 feat: insertMany, ofList, ofArray, foldr, foldM functions for the tree map (#7051)
This PR implements the methods `insertMany`, `ofList`, `ofArray`,
`foldr` and `foldrM` on the tree map.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-14 08:24:33 +00:00
Markus Himmel
47548aa171 chore: rename UIntX.ofNatCore, UIntX.ofNat' -> UIntX.ofNatLT (#7071)
This PR unifies the existing functions `UIntX.ofNatCore` and
`UIntX.ofNat'` under a new name, `UIntX.ofNatLT`.
2025-02-14 06:58:15 +00:00
Leonardo de Moura
b26b781992 feat: simprocs for Int and Nat divides predicates (#7078)
This PR implements simprocs for `Int` and `Nat` divides predicates.
2025-02-14 05:43:38 +00:00
Mac Malone
c9c3366521 feat: lake: support plugins (#7001)
This PR adds support for plugins to Lake. Precompiled modules are now
loaded as plugins rather than via `--load-dynlib`.

Additional plugins can be added through an experimental `plugins`
configuration option. The syntax for specifying this is not yet
convenient, and will be improved in future changes. A parallel `dynlibs`
configuration option has been added for specifying additional dynamic
libraries to build and pass to `--load-dynlib`.

This PR also changes the default directory for `.olean`, `.ilean`, and
module dynamic libraries (i.e., `leanLibDir`) to `lib/lean` instead of
the previous default of `lib`. This avoids potential name clashes
between single module shared libraries and the shared libraries of a
full `lean_lib`.

On non-Windows systems, module dynamic libraries are no longer linked to
their imports or external symbols. Symbols from those libraries are left
unresolved until load time. This avoids nesting these dependencies
within the shared library and means Lake no longer needs to augment the
shared library path to allow Lean to resolve such nested dependencies on
load.
2025-02-14 04:57:31 +00:00
Leonardo de Moura
2c2a3a65b2 feat: support theorems for cutsat Div-Solve rule (#7077)
This PR proves the helper theorems for justifying the "Div-Solve" rule
in the cutsat procedure.
2025-02-14 04:55:58 +00:00
Kim Morrison
8cefb2cf65 feat: premise selection API (#7061)
This PR provides a basic API for a premise selection tool, which can be
provided in downstream libraries. It does not implement premise
selection itself!
2025-02-14 04:08:18 +00:00
Lean stage0 autoupdater
80c8837f49 chore: update stage0 2025-02-13 16:00:29 +00:00
Markus Himmel
40c6dfa3ae chore: dsimproc for UIntX.ofNatLT (#7068)
This PR is a follow-up to #7057 and adds a builtin dsimproc for
`UIntX.ofNatLT` which it turns out we need in stage0 before we can get
the deprecation of `UIntX.ofNatCore` in favor of `UIntX.ofNatLT` off the
ground.
2025-02-13 14:51:42 +00:00
Bulhwi Cha
cc76c46244 doc: fix typo (#7067) 2025-02-13 13:21:18 +00:00
Markus Himmel
b38da34db2 chore: rename BitVec.ofNatLt -> BitVec.ofNatLT (#7064)
This PR renames `BitVec.ofNatLt` to `BitVec.ofNatLT` and sets up
deprecations for the old name.
2025-02-13 12:52:31 +00:00
Markus Himmel
4a900cc65c chore: rename IntX.toNat -> IntX.toNatClampNeg (#7066)
This PR renames `IntX.toNat` to `IntX.toNatClampNeg` (to reduce
surprises) and sets up a deprecation.
2025-02-13 12:14:28 +00:00
Markus Himmel
a3fd2eb0fe chore: make IntX constructor private, provide UIntX.toIntX (#7062)
This PR introduces the functions `UIntX.toIntX` as the public API to
obtain the `IntX` that is 2's complement equivalent to a given `UIntX`.
2025-02-13 11:29:31 +00:00
Paul Reichert
6ac530aa1a feat: deprecated find, fold, foldM, mergeBy functions for the tree map (#7036)
This PR adds some deprecated function aliases to the tree map in order
to ease the transition from the `RBMap` to the tree map.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-13 11:12:22 +00:00
Markus Himmel
04fe72fee0 feat: missing conversion functions for ISize (#7063)
This PR adds `ISize.toInt8`, `ISize.toInt16`, `Int8.toISize`,
`Int16.toISize`.
2025-02-13 11:02:00 +00:00
Joachim Breitner
a833afa935 feat: binderNameHint in congr (#7053)
This PR makes `simp` heed the `binderNameHint` also in the assumptions
of congruence rules. Fixes #7052.
2025-02-13 09:38:42 +00:00
Markus Himmel
7c9454edd2 feat: UIntX.ofFin (#7056)
This PR adds the `UIntX.ofFin` conversion functions.
2025-02-13 08:45:01 +00:00
Markus Himmel
1ecb4a43ae chore: rename UIntX.val -> UIntX.toFin (#7050)
This PR renames the functions `UIntX.val` to `UIntX.toFin`.
2025-02-13 07:50:47 +00:00
Kim Morrison
ae9d12aeaa chore: upstream an Int lemma (#7060) 2025-02-13 03:19:02 +00:00
Leonardo de Moura
e617ce7e4f refactor: move grind offset constraint module to Grind/Arith/Offset (#7058)
This PR moves the `grind` offset constraint module to the
`Grind/Arith/Offset` subdirectory in preparation to the full linear
integer arithmetic module.
2025-02-12 23:16:07 +00:00
Lean stage0 autoupdater
b9894b40af chore: update stage0 2025-02-12 17:09:23 +00:00
Markus Himmel
9ff4d53d0b chore: rename UIntX.mk -> UIntX.ofBitVec (#7046)
This PR renames `UIntX.mk` to `UIntX.ofBitVec` and adds deprecations.
2025-02-12 16:08:03 +00:00
Markus Himmel
1e262c2c0e chore: add UIntX.ofNatLT (#7057)
This PR adds the function `UIntX.ofNatLT`. This is supposed to be a
replacement for `UIntX.ofNatCore` and `UIntX.ofNat'`, but for
bootstrapping reasons we need this function to exist in stage0 before we
can proceed with the renaming and deprecations, so this PR just adds the
function.
2025-02-12 15:12:29 +00:00
Markus Himmel
b08fc5dfda feat: IntX.ofBitVec (#7048)
This PR adds the functions `IntX.ofBitVec`.
2025-02-12 14:49:31 +00:00
Joachim Breitner
761c88f10e feat: propagate wfParam through let (#7039)
This PR improves the well-founded definition preprocessing to propagate
`wfParam` through let expressions.

Fixes #7038.
2025-02-12 13:22:08 +00:00
Sebastian Ullrich
07b0e5b7fe chore: compile against glibc 2.26 (#7037)
This PR relaxes the minimum required glibc version for Lean and Lean
executables to 2.26 on x86-64 Linux
2025-02-12 09:29:51 +00:00
Sebastian Ullrich
f7e207a824 chore: remove save tactic (#7047)
This PR removes the `save` and `checkpoint` tactics that have been
superseded by incremental elaboration
2025-02-12 09:19:30 +00:00
Cameron Zwarich
f61e2989a2 fix: make several LCNF environment extensions have asyncMode of .sync (#7041)
This PR marks several LCNF-specific environment extensions as having an
asyncMode of .sync rather than the default of .mainOnly, so they work
correctly even in async contexts.
2025-02-12 09:13:49 +00:00
Joachim Breitner
bdf4b792a8 feat: wf_preprocess for {List,Array}.Monadic functions (#7034)
This PR adds `wf_preprocess` theorems for
`{List,Array}.{foldlM,foldrM,mapM,filterMapM,flatMapM}`
2025-02-12 09:06:12 +00:00
Sebastian Ullrich
d3af1268a7 test: fix simp_arith1 benchmark (#7049) 2025-02-12 10:22:32 +00:00
Lean stage0 autoupdater
01be97309e chore: update stage0 2025-02-12 09:15:43 +00:00
Kim Morrison
3cf6fb2405 chore: fix linter.listVariables naming (#7044) 2025-02-12 05:17:39 +00:00
Leonardo de Moura
2a67a49f31 chore: simp_arith has been deprecated (#7043)
This PR deprecates the tactics `simp_arith`, `simp_arith!`,
`simp_all_arith` and `simp_all_arith!`. Users can just use the `+arith`
option.
2025-02-12 03:55:45 +00:00
Leonardo de Moura
fb2e5e5555 chore: remove dead code from Nat/Linear.lean (#7042) 2025-02-12 02:14:00 +00:00
Leonardo de Moura
b87c01b1c0 feat: simp +arith sorts linear atoms (#7040)
This PR ensures that terms such as `f (2*x + y)` and `f (y + x + x)`
have the same normal form when using `simp +arith`
2025-02-11 23:37:30 +00:00
Paul Reichert
0f1133fe69 feat: tree map data structures and operations (#6914)
This PR introduces ordered map data structures, namely `DTreeMap`,
`TreeMap`, `TreeSet` and their `.Raw` variants, into the standard
library. There are still some operations missing that the hash map has.
As of now, the operations are unverified, but the corresponding lemmas
will follow in subsequent PRs. While the tree map has already been
optimized, more micro-optimization will follow as soon as the new code
generator is ready.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-11 14:47:47 +00:00
Henrik Böving
f348a082da feat: present bv_decide counter examples for UIntX and enums better (#7033)
This PR improves presentation of counter examples for UIntX and enum
inductives in bv_decide.
2025-02-11 11:01:40 +00:00
Leonardo de Moura
befee896b3 feat: linear integer inequality normalization using gcd of coefficients (#7030)
This PR adds completes the linear integer inequality normalizer for
`grind`. The missing normalization step replaces a linear inequality of
the form `a_1*x_1 + ... + a_n*x_n + b <= 0` with `a_1/k * x_1 + ... +
a_n/k * x_n + ceil(b/k) <= 0` where `k = gcd(a_1, ..., a_n)`.
`ceil(b/k)` is implemented using the helper `cdiv b k`.
2025-02-11 03:45:25 +00:00
Mac Malone
e7fa5891ea feat: lake: provide help on Elan's + option (#7024)
This PR documents how to use Elan's `+` option with `lake new|init`. It
also provides an more informative error message if a `+` option leaks
into Lake (e.g., if a user provides the option to a Lake run without
Elan).
2025-02-11 00:43:38 +00:00
Sebastian Ullrich
3927445973 chore: build Lean with Elab.async (#6989) 2025-02-10 18:16:20 +00:00
Henrik Böving
7d1d761148 feat: bv_decide rewrite multiplication with power of two to shift (#7029)
This PR adds simprocs to bv_decide's preprocessor that rewrite
multiplication with powers of two to constant shifts.
2025-02-10 17:42:59 +00:00
Sebastian Ullrich
7790420cae chore: trivial changes from async-proofs branch (#7028) 2025-02-10 16:44:05 +00:00
Joachim Breitner
4016a80f66 feat: nested well-founded recursion via automatic preprocessing (#6744)
This PR extend the preprocessing of well-founded recursive definitions
to bring assumptions like `h✝ : x ∈ xs` into scope automatically.

This fixes #5471, and follows (roughly) the design written there.
See the module docs at `src/Lean/Elab/PreDefinition/WF/AutoAttach.lean`
for details on the implementation.

This only works for higher-order functions that have a suitable setup.
See for example section “Well-founded recursion preprocessing setup” in
`src/Init/Data/List/Attach.lean`.

This does not change the `decreasing_tactic`, so in some cases there is
still the need for a manual termination proof some cases. We expect a
better termination tactic in the near future.
2025-02-10 16:43:41 +00:00
Lean stage0 autoupdater
feb8cc2d4a chore: update stage0 2025-02-10 16:30:51 +00:00
Markus Himmel
5eed373feb doc: misc. style guide and naming scheme additions (#7026)
This PR clarifies the styling of `do` blocks, and enhanes the naming
conventions with information about the `ext` and `mono` name components
as well as advice about primed names and naming of simp sets.
2025-02-10 15:27:30 +00:00
Sebastian Ullrich
895cdce9bc fix: codegen was allowed improper env ext accesses (#7023) 2025-02-10 15:08:02 +00:00
Kim Morrison
3411518548 chore: rename simp sets (#7017)
This PR renames the simp set `boolToPropSimps` to `bool_to_prop` and
`bv_toNat` to `bitvec_to_nat`. I'll be adding more similarly named simp
sets.
2025-02-10 14:20:18 +00:00
Kim Morrison
13b4b11657 chore: deprecated compile_time_search_path% (#7022)
This PR deprecates `compile_time_search_path%`; it didn't prove useful,
and we've shot ourselves in the foot with it more than once.
2025-02-10 13:49:17 +00:00
Henrik Böving
fa05bccd58 feat: add basic extract theorems for bv_decide (#7021)
This PR adds theorems for interactions of extractLsb with `&&&`, `^^^`,
`~~~` and `bif` to bv_decide's preprocessor.
2025-02-10 13:48:20 +00:00
Kim Morrison
c307e8a04f feat: improvements to simp confluence (#7013)
This PR makes improvements to the simp set for List/Array/Vector/Option
to improve confluence, in preparation for `simp_lc`.
2025-02-10 12:17:44 +00:00
Henrik Böving
2aca375cd9 fix: correct trace nodes in bv_decide (#7019)
This PR properly spells out the trace nodes in bv_decide so they are
visible with just `trace.Meta.Tactic.bv` and `trace.Meta.Tactic.sat`
instead of always having to enable the profiler.
2025-02-10 11:24:52 +00:00
Lean stage0 autoupdater
46ae4c0d7c chore: update stage0 2025-02-10 11:58:06 +00:00
Sebastian Ullrich
6f445a1c05 chore: Task.get block profiling (#7016)
* `--profile` now reports `blocking` time spent in `Task.get` inside
other profiling categories
* environment variable `LEAN_TRACE_TASK_GET_BLOCKED` when set makes
`lean` dump stack traces of `Task.get` blocks
2025-02-10 10:56:49 +00:00
Kim Morrison
80cf782bc6 chore: rename simp sets (#7018)
This is preliminary to #7017; we'll need an update-stage0 before the
actual rename can take place.
2025-02-10 10:56:20 +00:00
Kim Morrison
1622f578c9 chore: replace HashMap.get_ lemmas with getElem_ versions (#7004)
This PR replaces various `HashMap.get_X` with `getElem_X` versions. Now
the left hand sides are in simp normal form (and this fixes some
confluence problems).
2025-02-10 10:37:21 +00:00
Kim Morrison
47814f9da1 chore: add @[simp] to List.flatten_toArray (#7014) 2025-02-10 10:30:41 +00:00
Henrik Böving
0d95bf68cc feat: basic support for handling enum inductives in bv_decide (#6946)
This PR implements basic support for handling of enum inductives in
`bv_decide`. It now supports equality on enum inductive variables (or
other uninterpreted atoms) and constants.
2025-02-10 10:00:20 +00:00
Leonardo de Moura
d61f506da2 feat: simp +arith normalizes coefficient in linear integer polynomials (#7015)
This PR makes sure `simp +arith` normalizes coefficients in linear
integer polynomials. There is still one todo: tightening the bound of
inequalities.
2025-02-10 06:13:28 +00:00
Kim Morrison
7f3e170509 chore: unprotect List.foldlM (#7003) 2025-02-09 22:54:51 +00:00
Leonardo de Moura
bcffbdd3a1 chore: improve withAbstractAtoms (#7012)
We should not abstract free variables
2025-02-09 22:46:09 +00:00
Leonardo de Moura
e14c593003 feat: simp +arith for integers (#7011)
This PR adds `simp +arith` for integers. It uses the new `grind`
normalizer for linear integer arithmetic. We still need to implement
support for dividing the coefficients by their GCD. It also fixes
several bugs in the normalizer.
2025-02-09 21:41:58 +00:00
Leonardo de Moura
bcde913a96 chore: improve expose_names doc string (#7010) 2025-02-09 17:24:07 +00:00
Leonardo de Moura
33b45132a4 feat: bv_decide hint (#7009)
This PR ensures users get an error message saying which module to import
when they try to use `bv_decide`.
2025-02-09 17:11:28 +00:00
Kim Morrison
ef4c6ed83c chore: remove unused Int simp lemmas (#7005) 2025-02-09 16:20:38 +00:00
Leonardo de Moura
cd3eb9125c feat: linear integer arith normalizer (#7002)
This PR implements the normalizer for linear integer arithmetic
expressions. It is not connect to `simp +arith` yet because of some
spurious `[simp]` attributes.
2025-02-09 04:32:54 +00:00
Leonardo de Moura
f6c5aed7ef feat: add Int.Linear normalization support (#7000)
This PR adds helper theorems for justifying the linear integer
normalizer.
2025-02-08 23:01:01 +00:00
Kyle Miller
dd293d1fbd doc: mention Props are equal to True or False (#6998)
This PR modifies the `Prop` docstring to point out that every
proposition is propositionally equal to either `True` or `False`. This
will help point users toward seeing that `Prop` is like `Bool`.

I considered mentioning `Classical.propComplete`, but it's probably
better not making it seem like that's how you should work with
propositions.
2025-02-08 18:11:26 +00:00
Bolton Bailey
4989a60af3 chore: change Lake configuration error message (#6829)
This PR changes the error message for Lake configuration failure to
reflect that issues do not always arise from an invalid lakefile, but
sometimes arise from other issues like network errors. The new error
message encompasses all of these possibilities.

Closes #6827
2025-02-08 15:04:39 +00:00
Joachim Breitner
7c809a94af refactor: elaborate forIn notation without extra let (#6977)
This PR avoids a `let` in the elaboration of `forIn`. It was introduced
in https://github.com/leanprover/lean4/commit/f51328ff112 but nothing
seems to break when I simplify the code. This removes an unexpected `let
col✝ :=…` from the “Expected type” view in the Info View and from the
termination proofs.
2025-02-08 10:32:34 +00:00
Leonardo de Moura
5eca093a89 feat: exact? in try? (#6995)
This PR implements support for `exact?` in the `try?` tactic.
2025-02-07 22:43:30 +00:00
Leonardo de Moura
6d46e31ad8 feat: compress try? suggestions (#6994)
This PR adds the `Try.Config.merge` flag (`true` by default) to the
`try?` tactic. When set to `true`, `try?` compresses suggestions such
as:
```lean
· induction xs, ys using bla.induct
    · grind only [List.length_reverse]
    · grind only [bla]
```
into:
```lean
induction xs, ys using bla.induct <;> grind only [List.length_reverse, bla]
```

This PR also ensures `try?` does not generate suggestions that mixes
`grind` and `grind only`, or `simp` and `simp only` tactics.

This PR also adds the `try? +harder` option (previously called `lib`),
but it has not been fully implemented yet.
2025-02-07 19:17:25 +00:00
Leonardo de Moura
605b9e63c9 chore: disable broken test
It is timing out on OSX, and `master` is failing to build.
This is a temporary "fix."
2025-02-07 11:13:50 -08:00
Sebastian Ullrich
0d1907c1df feat: parallel progress notifications (#6329)
This PR enables the language server to present multiple disjoint line
ranges as being worked on. Even before parallelism lands, we make use of
this feature to show post-elaboration tasks such as kernel checking on
the first line of a declaration to distinguish them from the final
tactic step.


![image](https://github.com/user-attachments/assets/f6170689-6835-40c0-baba-df067a60b605)
2025-02-07 16:50:31 +00:00
Leonardo de Moura
2b67ef451a feat: improve try? suggestion (#6991)
This PR improves how suggestions for the `<;>` combinator are generated.
2025-02-07 16:33:25 +00:00
Sebastian Ullrich
bfe2d28c50 chore: re-enable Elab.async in the server (#6990) 2025-02-07 16:12:31 +00:00
Sebastian Ullrich
de24063c4b fix: convert kernel interrupt into elab interrupt (#6988)
This PR ensures interrupting the kernel does not lead to wrong, sticky
error messages in the editor
2025-02-07 15:55:32 +00:00
Sebastian Ullrich
7c79f05cd4 feat: API to avoid deadlocks from dropped promises (#6958)
This PR improves the `Promise` API by considering how dropped promises
can lead to never-finished tasks.
2025-02-07 15:33:10 +00:00
Sebastian Ullrich
1248a55d32 perf: avoid taking mutex on already-resolved promises (#6984) 2025-02-07 10:14:35 +00:00
Sebastian Ullrich
ac9708051a feat: respect Task.map/bind (sync := true) after waiting (#6976)
This PR extends the behavior of the `sync` flag for `Task.map/bind` etc.
to encompass synchronous execution even when they first have to wait on
completion of the first task, drastically lowering the overhead of such
tasks. Thus the flag is now equivalent to e.g. .NET's
`TaskContinuationOptions.ExecuteSynchronously`.
2025-02-07 09:06:57 +00:00
Kim Morrison
af385d7c10 feat: improve monadic Array lemmas (#6982)
This PR improves some lemmas about monads and monadic operations on
Array/Vector, using @Rob23oa's work in
https://github.com/leanprover-community/batteries/pull/1109, and
adding/generalizing some additional lemmas.
2025-02-07 04:02:02 +00:00
Kim Morrison
92f0d31ed7 chore: linting List (#6970) 2025-02-07 01:44:51 +00:00
Leonardo de Moura
0376cae739 feat: try? tactic improvements (#6981)
This PR adds new configuration options to `try?`.
- `try? -only` omits `simp only` and `grind only` suggestions
- `try? +missing` enables partial solutions where some subgoals are
"solved" using `sorry`, and must be manually proved by the user.
- `try? (max:=<num>)` sets the maximum number of suggestions produced
(default is 8).
2025-02-07 01:35:41 +00:00
Leonardo de Moura
c92425f98d feat: try? validation and cleanup (#6980)
This PR improves the `try?` tactic runtime validation and error
messages. It also simplifies the implementation, and removes unnecessary
code.
2025-02-06 23:59:38 +00:00
Sofia Rodrigues
52198837df feat: improve some files separation and standardize error messages in UV modules (#6830)
This PR improves some files separation and standardize error messages in
UV modules
2025-02-06 23:24:42 +00:00
Leonardo de Moura
eab09084a3 feat: try? composite suggestions (#6979)
This PR adds support for more complex suggestions in `try?`. Example:
```lean
example (as : List α) (a : α) : concat as a = as ++ [a] := by
  try?
```
suggestion
```
Try this: · induction as, a using concat.induct
  · rfl
  · simp_all
```
2025-02-06 21:56:14 +00:00
Marc Huisinga
45d39422bc fix: inlay hints in untitled files (#6978)
This PR fixes a bug where both the inlay hint change invalidation logic
and the inlay hint edit delay logic were broken in untitled files.
Thanks to @Julian for spotting this!
2025-02-06 19:26:11 +00:00
Lean stage0 autoupdater
06d022b9c0 chore: update stage0 2025-02-06 17:39:42 +00:00
Marc Huisinga
dcd70cbfba feat: inlay hint refinements (#6959)
This PR implements a number of refinements for the auto-implicit inlay
hints implemented in #6768.
Specifically:
- In #6768, there was a bug where the inlay hint edit delay could
accumulate on successive edits, which meant that it could sometimes take
much longer for inlay hints to show up. This PR implements the basic
infrastructure for request cancellation and implements request
cancellation for semantic tokens and inlay hints to resolve the issue.
With this edit delay bug fixed, it made more sense to increase the edit
delay slightly from 2000ms to 3000ms.
- In #6768, we applied the edit delay to every single inlay hint request
in order to reduce the amount of inlay hint flickering. This meant that
the edit delay also had a significant effect on how far inlay hints
would lag behind the file progress bar. This PR adjusts the edit delay
logic so that it only affects requests sent directly after a
corresponding `didChange` notification. Once the edit delay is used up,
all further semantic token requests are responded to without delay, so
that the only latency that affects how far the inlay hints lag behind
the progress bar is how often we emit refresh requests and how long VS
Code takes to respond to them.
- For inlay hints, refresh requests are now emitted 500ms after a
response to an inlay hint request, not 2000ms, which means that after
the edit delay, inlay hints should only lag behind the progress bar by
about up to 500ms. This is justifiable for inlay hints because the
response should be much smaller than e.g. is the case for semantic
tokens.
- In #6768, 'Restart File' did not prompt a refresh, but it does now.
- VS Code does not immediately remove old inlay hints from the document
when they are applied. In #6768, this meant that inlay hints would
linger around for a bit once applied. To mitigate this issue, this PR
adjusts the inlay hint edit delay logic to identify edits sent from the
client as being inlay hint applications, and sets the edit delay to 0ms
for the inlay hint requests following it. This means that inlay hints
are now applied immediately.
- In #6768, hovering over single-letter auto-implicit inlay hints was a
bit finicky because VS Code uses the regular cursor icon on inlay hints,
not the thin text cursor icon, which means that it is easy to put the
cursor in the wrong spot. We now add the separation character (` ` or
`{`) preceding an auto-implicit to the hover range as well, which makes
hovering over inlay hints much smoother.
2025-02-06 16:43:56 +00:00
Lean stage0 autoupdater
07c880f7ff chore: update stage0 2025-02-06 12:27:11 +00:00
Joachim Breitner
2e6206bbeb refactor: rename auto_attach attribute to wf_preprocess (#6972)
As per dicussion with team colleages, the feature shouldn’t be called
“auto attach” but rather “well-founded recursion preprocessing” to avoid
(imprecise) jargon.
2025-02-06 11:28:23 +00:00
Henrik Böving
4540a6436f refactor: bv_decide's type analysis to prepare for enum support (#6971)
This PR does some refactoring on bv_decide's type analysis in
preparation for enum support in #6946.
2025-02-06 11:16:57 +00:00
Joachim Breitner
dc001a01e5 feat: binderNameHint (#6947)
This PR adds the `binderNameHint` gadget. It can be used in rewrite and
simp rules to preserve a user-provided name where possible.

The expression `binderNameHint v binder e` defined to be `e`.

If it is used on the right-hand side of an equation that is applied by a
tactic like `rw` or `simp`,
and `v` is a local variable, and `binder` is an expression that (after
beta-reduction) is a binder
(so `fun w => …` or `∀ w, …`), then it will rename `v` to the name used
in the binder, and remove
the `binderNameHint`.

A typical use of this gadget would be as follows; the gadget ensures
that after rewriting, the local
variable is still `name`, and not `x`:
```
theorem all_eq_not_any_not (l : List α) (p : α → Bool) :
    l.all p = !l.any fun x => binderNameHint x p (!p x) := sorry

example (names : List String) : names.all (fun name => "Waldo".isPrefixOf name) = true := by
  rw [all_eq_not_any_not]
  -- ⊢ (!names.any fun name => !"Waldo".isPrefixOf name) = true
```

This gadget is supported by `simp`, `dsimp` and `rw` in the
right-hand-side of an equation, but not
in hypotheses or by other tactics.
2025-02-06 11:03:27 +00:00
Kim Morrison
a00cc12436 chore: rename Nat.not_eq_zero_of_lt (#6968)
Renames a lemma.

Closes #6714
2025-02-06 10:20:17 +00:00
Markus Himmel
947cd742bf doc: style guide and naming convention for the standard library (#6950)
This PR adds a style guide and a naming convention for the standard
library.
2025-02-06 08:33:48 +00:00
Lean stage0 autoupdater
ee42e8cf24 chore: update stage0 2025-02-06 08:27:23 +00:00
Leonardo de Moura
b01ca8ee23 feat: use expose_names in try? (#6967)
This PR ensures `try?` can suggest tactics that need to reference
inaccessible local names.
Example: 
```lean
/--
info: Try these:
• · expose_names; induction as, bs_1 using app.induct <;> grind [= app]
• · expose_names; induction as, bs_1 using app.induct <;> grind only [app]
-/
#guard_msgs (info) in
example : app (app as bs) cs = app as (app bs cs) := by
  have bs := 20 -- shadows `bs` in the target
  try?
```
2025-02-06 05:44:25 +00:00
Kim Morrison
fd4599fd7a feat: add internal linter for List/Array/Vector variable names (#6966)
This PR adds an internal-use-only strict linter for the variable names
of `List`/`Array`/`Vector` variables, and begins cleaning up.
2025-02-06 04:49:21 +00:00
Leonardo de Moura
fbeec32c2b feat: implement try? using evalAndSuggest (#6965)
This PR re-implements the `try?` tactic using the new `evalAndSuggest`
infrastructure.
2025-02-06 04:47:26 +00:00
Kim Morrison
de99c8015a feat: #info_trees in command (#6964)
This PR adds a convenience command `#info_trees in`, which prints the
info trees generated by the following command. It is useful for
debugging or learning about `InfoTree`.
2025-02-06 03:11:53 +00:00
Kim Morrison
49297f12a5 chore: further cleanup of index variable naming in List (#6963) 2025-02-06 02:39:06 +00:00
Kim Morrison
8fd107c10f doc: improve List.toArray doc-string (#6962)
This PR improves the doc-string for `List.toArray`.

Thanks to @jt0202 for pointing this out.
2025-02-06 01:56:47 +00:00
Leonardo de Moura
13b1f56f88 feat: evalAndSuggest helper tactic (#6961)
This PR adds the auxiliary tactic `evalAndSuggest`. It will be used to
refactor `try?`.
2025-02-05 22:13:47 +00:00
Lean stage0 autoupdater
20e67945ea chore: update stage0 2025-02-05 16:42:25 +00:00
jrr6
60aeb79a75 feat: allow updating binders to and from strict- and instance-implicit (#6634)
This PR adds support for changing the binder annotations of existing
variables to and from strict-implicit and instance-implicit using the
`variable` command.

This PR requires a stage0 update to fully take effect.

Closes #6078
2025-02-05 15:43:54 +00:00
Lean stage0 autoupdater
f1ed830b9a chore: update stage0 2025-02-05 14:42:28 +00:00
Joachim Breitner
255d931e0c feat: add auto_attach simp set (no functionality yet) (#6956)
this PR helps with bootstrapping #6744.
2025-02-05 13:33:35 +00:00
Kim Morrison
53ed233f38 chore: fix variable names in List lemmas (#6953)
This PR starts on the process of cleaning up variable names across
List/Array/Vector. For now, we just rename "numerical index" variables
in one file. This is driven by a custom linter.
2025-02-05 09:49:14 +00:00
Luisa Cicolini
0ed493e748 feat: add SMT-LIB overflow on addition for bitvectors BitVec.(uadd_overflow, sadd_overflow, uadd_overflow_eq, sadd_overflow_eq) and support theorems (#6628)
This PR adds SMT-LIB operators to detect overflow
`BitVec.(uadd_overflow, sadd_overflow)`, according to the definitions
[here](https://github.com/SMT-LIB/SMT-LIB-2/blob/2.7/Theories/FixedSizeBitVectors.smt2),
and the theorems proving equivalence of such definitions with the
`BitVec` library functions (`uaddOverflow_eq`, `saddOverflow_eq`).
Support theorems for these proofs are `BitVec.toNat_mod_cancel_of_lt,
BitVec.toInt_lt, BitVec.le_toInt, Int.bmod_neg_iff`. The PR also
includes a set of tests.

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
Co-authored-by: Alex Keizer <alex@keizer.dev>
Co-authored-by: Tobias Grosser <tobias@grosser.es>
Co-authored-by: Siddharth Bhat <siddu.druid@gmail.com>
2025-02-05 09:36:56 +00:00
jrr6
1f956ad1af fix: show error messages on name conflicts in mutual blocks (#6939)
This PR adds error messages for `inductive` declarations with
conflicting constructor names and `mutual` declarations with conflicting
names.

Closes #6694.
2025-02-05 04:23:24 +00:00
Mac Malone
ebba1e04d0 feat: frontend & server support for plugins (#6893)
This PR adds support for plugins to the frontend and server.

Implementation-wise, this adds a `plugins` argument to `runFrontend`,
`processHeader`, amd `importModules`, a `plugins` field to
`SetupImportsResult` and `FileSetupResult`. and a `pluginsPath` field to
`LeanPaths`, and then threads the value through these.
2025-02-04 23:36:18 +00:00
Joachim Breitner
33baaccb20 test: more equational theorem generation tests (#6952)
This includes the examples from issues #2961, #3219 and #5667 in our
test suite, so that we know when (accidentially) fix them.

In fact this closes #3219, which (judging from the nightlies) was fixed
last week by #6901.
2025-02-04 22:18:35 +00:00
Cameron Zwarich
63ac27e9b9 chore: restore example after stage0 update (#6942) 2025-02-04 18:02:59 +00:00
Lean stage0 autoupdater
897e9c5388 chore: update stage0 2025-02-04 18:30:41 +00:00
Marc Huisinga
95aee36fab feat: inlay hints for auto-implicits (#6768)
This PR adds preliminary support for inlay hints, as well as support for
inlay hints that denote the auto-implicits of a function. Hovering over
an auto-implicit displays its type and double-clicking the auto-implicit
inserts it into the text document.

![Inlay hints for
auto-implicits](https://github.com/user-attachments/assets/fb204c42-5997-4f10-9617-c65f1042d732)

This PR is an extension of #3910.

### Known issues

- In VS Code, when inserting an inlay hint, the inlay hint may linger
for a couple of seconds before it disappears. This is a defect of the VS
Code implementation of inlay hints and cannot adequately be resolved by
us.
- When making a change to the document, it may take a couple of seconds
until the inlay hints respond to the change. This is deliberate and
intended to reduce the amount of inlay hint flickering while typing. VS
Code has a mechanism of its own for this, but in my experience it is
still far too sensitive without additional latency.
- Inserting an auto-implicit inlay hint that depends on an auto-implicit
meta-variable causes a "failed to infer binder type" error. We can't
display these meta-variables in the inlay hint because they don't have a
user-displayable name, so it is not clear how to resolve this problem.
- Inlay hints are currently always resolved eagerly, i.e. we do not
support the `textDocument/inlayHint/resolve` request yet. Implementing
support for this request is future work.

### Other changes
- Axioms did not support auto-implicits due to an oversight in the
implementation. This PR ensures they do.
- In order to reduce the amount of inlay hint flickering when making a
change to the document, the language server serves old inlay hints for
parts of the file that have not been processed yet. This requires LSP
request handler state (that sometimes must be invalidated on
`textDocument/didChange`), so this PR introduces the notion of a
stateful LSP request handler.
- The partial response mechanism that we use for semantic tokens, where
we simulate incremental LSP responses by periodically emitting refresh
requests to the client, is generalized to accommodate both inlay hints
and semantic tokens. Additionally, it is made more robust to ensure that
we never emit refresh requests while a corresponding request is in
flight, which causes VS Code to discard the respond of the request, as
well as to ensure that we keep prompting VS Code to send another request
if it spuriously decides not to respond to one of our refresh requests.
- The synthetic identifier of an `example` had the full declaration as
its (non-canonical synthetic) range. Since we need a reasonable position
for the identifier to insert an inlay hint for the auto-implicits of an
`example`, we change the (canonical synthetic) range of the synthetic
identifier to that of the `example` keyword.
- The semantic highlighting request handling is moved to a separate
file.

### Breaking changes
- The semantic highlighting request handler is not a pure request
handler anymore, but a stateful one. Notably, this means that clients
that extend the semantic highlighting of the Lean language server with
the `chainLspRequestHandler` function must now use the
`chainStatefulLspRequestHandler` function instead.
2025-02-04 17:36:49 +00:00
jrr6
8304bfe237 feat: allow anonymous equality proofs in match expressions (#6853)
This PR adds support for anonymous equality proofs in `match`
expressions of the form `match _ : e with ...`.

Closes #6759.
2025-02-04 16:09:21 +00:00
Luisa Cicolini
3b41e43264 feat: add BitVec.(getElem_umod_of_lt, getElem_umod, getLsbD_umod, getMsbD_umod) (#6795)
This PR adds theorems `BitVec.(getElem_umod_of_lt, getElem_umod,
getLsbD_umod, getMsbD_umod)`. For the defiition of these theorems we
rely on `divRec`, excluding the case where `d=0#w`, which is treated
separately because there is no infrastructure to reason about this case
within `divRec`. In particular, our implementation follows the mathlib
standard [where division by 0 yields
0](c7c1e091c9/src/Init/Data/BitVec/Basic.lean (L217)),
while in [SMTLIB this yields
`allOnes`](c7c1e091c9/src/Init/Data/BitVec/Basic.lean (L237)).

Co-authored by @bollu.

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
2025-02-04 16:07:29 +00:00
Joachim Breitner
da2b91558e feat: improve simp trace formatting (#6951)
This PR adds line breaks and indentations to simp's trace messages to
make them easier to read (IMHO).
2025-02-04 15:47:01 +00:00
Jakob von Raumer
6d63f6305e feat: add Hashable instances for PUnit and PEmpty (#6866)
This PR adds missing `Hashable` instances for `PUnit` and `PEmpty`.
2025-02-04 14:40:31 +00:00
Kyle Miller
23bd9dfb09 fix: make rewrite/rw tactic abort on elaboration errors (#6891)
This PR modifies `rewrite`/`rw` to abort rewriting if the elaborated
lemma has any immediate elaboration errors (detected by presence of
synthetic sorries). Rewriting still proceeds if there are elaboration
issues arising from pending synthetic metavariables, like instance
synthesis failures. The purpose of the change is to avoid obscure
"tactic 'rewrite' failed, equality or iff proof expected ?m.5" errors
when for example a lemma does not exist.

This helps error reporting for the natural number game.
https://leanprover.zulipchat.com/#narrow/channel/113489-new-members/topic/Why.20doesn't.20add_left_comm.20work.20here.3F/near/497060022
2025-02-04 14:40:11 +00:00
Luisa Cicolini
ba2b9f63ad feat: add BitVec.(getMsbD, msb)_replicate, replicate_one (#6326)
This PR adds `BitVec.(getMsbD, msb)_replicate, replicate_one` theorems,
corrects a non-terminal `simp` in `BitVec.getLsbD_replicate` and
simplifies the proof of `BitVec.getElem_replicate` using the `cases`
tactic.

Co-authored with @bollu.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
2025-02-04 13:55:53 +00:00
Eric Wieser
0d7e126a01 chore: re-land "perf: use C23's free_sized when available" (#6844)
Unreverts #6598

I'll combine #6825 into this before merging.
2025-02-04 12:43:56 +00:00
Kim Morrison
2385abc282 feat: align List/Array/Vector.insertIdx lemmas (#6948)
This PR completes the alignment of `List/Array/Vectors` lemmas for
`insertIdx`.
2025-02-04 12:23:27 +00:00
dependabot[bot]
baeb325611 chore: CI: bump dawidd6/action-download-artifact from 7 to 8 (#6903)
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 7 to 8.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dawidd6/action-download-artifact/releases">dawidd6/action-download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v8</h2>
<h2>New features</h2>
<ul>
<li><code>use_unzip</code> boolean input (defaulting to false) - if set
to true, the action will use system provided <code>unzip</code> utility
for unpacking downloaded artifact(s) (note that the action will first
download the .zip artifact file, then unpack it and remove the .zip
file)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>README: v7 by <a
href="https://github.com/haines"><code>@​haines</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/318">dawidd6/action-download-artifact#318</a></li>
<li>Unzip by <a
href="https://github.com/dawidd6"><code>@​dawidd6</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/325">dawidd6/action-download-artifact#325</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/haines"><code>@​haines</code></a> made
their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/318">dawidd6/action-download-artifact#318</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v7...v8">https://github.com/dawidd6/action-download-artifact/compare/v7...v8</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="20319c5641"><code>20319c5</code></a>
README: v8</li>
<li><a
href="e58a9e5d14"><code>e58a9e5</code></a>
Unzip (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/325">#325</a>)</li>
<li><a
href="6d05268723"><code>6d05268</code></a>
node_modules: update</li>
<li><a
href="c03fb0c928"><code>c03fb0c</code></a>
README: v7 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/318">#318</a>)</li>
<li>See full diff in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v7...v8">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dawidd6/action-download-artifact&package-manager=github_actions&previous-version=7&new-version=8)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 10:41:44 +00:00
JovanGerb
2c6eacee30 fix: #discr_tree_simp_key shouldn't look into lhs of (#6936)
This PR fixes the `#discr_tree_simp_key` command, because it displays
the keys for just `lhs` in `lhs ≠ rhs`, but it should be `lhs = rhs`,
since that is what simp indexes.
2025-02-04 08:43:12 +00:00
Johan Commelin
412389f71f chore: add commit hash to error message in script/release_notes.py (#6944)
This PR adds a commit hash to the message that `script/release_notes.py`
prints when it can not find a PR number.
2025-02-04 06:10:08 +00:00
Johan Commelin
b385949dd4 chore: begin development cycle for v4.18.0 (#6943)
This PR begins the development cycle for v4.18.0.
2025-02-04 05:47:20 +00:00
Kim Morrison
80f824ce6b chore: more updates to release_checklist.py (#6941) 2025-02-04 05:38:42 +00:00
Leonardo de Moura
cd722567ed feat: improve grind case-split on Iff (#6940)
This PR improves how the `grind` tactic performs case splits on `p <->
q`.
2025-02-04 04:41:04 +00:00
Leonardo de Moura
6f8c13ba39 feat: improve grind error messages (#6937)
This PR improves `grind` error and trace messages by cleaning up local
declaration names.
2025-02-04 03:44:17 +00:00
Cameron Zwarich
cb6adb0259 fix: don't strip macro scopes in names of specialized LCNF decls (#6930)
This PR changes the name generation of specialized LCNF decls so they
don't strip macro scopes. This avoids name collisions for
specializations created in distinct macro scopes. Since the normal
Name.append function checks for the presence of macro scopes, we need to
use appendCore.
2025-02-04 03:43:18 +00:00
Kim Morrison
8b2a9cd74d chore: release_checklist.py checks if 'begin dev cycle' PR is needed (#6934)
This PR adds a check to `release_checklist.py`, to check whether
`CMakeLists.txt` on `master` has been updated, and if not reminds that a
"begin dev cycle" PR (as documented in `release_checklist.md` is needed.
2025-02-04 00:59:26 +00:00
Leonardo de Moura
b81dd3e7ad feat: expose_names tactic (#6935)
This PR adds the tactic `expose_names`. It creates a new goal whose
local context has been "exposed" so that every local declaration has a
clear, accessible name. If no local declarations require renaming, the
original goal is returned unchanged.

This tactic will be used to improve `try?`.
2025-02-04 00:53:31 +00:00
Kim Morrison
2477bb9705 chore: fix simp lemmas with bad keys 2025-02-04 11:47:08 +11:00
Kim Morrison
99f514dc5e chore: release_checklist.py checks for bump/v4.X.0 branches (#6933)
Some downstream repositories require a `bump/v4.X.0` branch to exist for
their integration CI. This PR updates `release_checklist.py` to check
for the existence of these branches, when needed.
2025-02-03 23:46:26 +00:00
Kim Morrison
838dcc496f chore: release notes use more paragraphs when needed (#6932)
Often PR descriptions end with a colon, followed by a new paragraph
containing a code block. Currently in the release notes these get
dropped. This PR attempts to include them. It's not particularly robust,
but I'll review during the next release.
2025-02-03 23:26:46 +00:00
Kim Morrison
800c60d77a chore: report total commits by category in release notes (#6931)
This PR reports a sentence like:

```quote
For this release, 201 changes landed. In addition to the 74 feature additions and 44 fixes listed below there were 7 refactoring changes, 5 documentation improvements and 62 chores.
```

in the automatically generated release notes.
2025-02-03 23:24:33 +00:00
Violetta Sim
a40bcee14f doc: add highlights section to v4.16.0 release notes (#6925)
This PR adds the highlights section to v4.16.0 release notes.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
Co-authored-by: Kim Morrison <kim@tqft.net>
2025-02-03 23:18:08 +00:00
Henrik Böving
142874d863 feat: bv_decide lower ||| to &&& and add and_eq_allOnes (#6741)
This PR implements two rules for bv_decide's preprocessor, lowering
`|||` to `&&&` in order to enable more term sharing + application of
rules about `&&&` as well as rewrites of the form `(a &&& b == -1#w) =
(a == -1#w && b == -1#w)` in order to preserve rewriting behavior that
already existed before this lowering.
2025-02-03 22:10:31 +00:00
Henrik Böving
c6cb2f52f0 feat: bv_decide implement BV_EQUAL_CONST_NOT rules (#6926)
This PR adds the BV_EQUAL_CONST_NOT rules from Bitwuzla to the
preprocessor of bv_decide.

Stacked on top of #6924
2025-02-03 18:19:34 +00:00
Sebastian Ullrich
d01e038210 feat: asynchronous code generation (#6770)
This PR enables code generation to proceed in parallel to further
elaboration.

It does not aim to make further refinements such as generating code for
different declarations in parallel or removing the dependency on kernel
checking.
2025-02-03 17:17:18 +00:00
Henrik Böving
a4ad409ae0 feat: bv_decide implement EQUAL_ITE rules (#6924)
This PR adds the EQUAL_ITE rules from Bitwuzla to the preprocessor of
bv_decide.
2025-02-03 15:51:03 +00:00
Joachim Breitner
a0776c33f0 refactor: FunInd: erase, not clear (#6923)
previously we did not include the “old” IH in the local context, so that
creating a MVar would not pick it up. But this always felt like a hack,
and prevented us from inferring types. So lets's try keeping them in the
context and using `withErasedFVars` only when creating metavariables.
2025-02-03 15:47:30 +00:00
Markus Himmel
ffa1e9e9ae doc: add recommended spellings for many term notations (#6886)
This PR adds recommended spellings for many notations defined in Lean
core, using the `recommended_spelling` command from #6869.
2025-02-03 13:46:39 +00:00
Kim Morrison
030daffba6 feat: LawfulBEq instances for Array and Vector (#6922)
This PR adds `LawfulBEq` instances for `Array` and `Vector`.

(Note this replaces a contribution of @mehbark to Batteries for the
LawfulBEq instance for Vector, which was dropped during the release
process due to conflicts. Thanks for that contribution!)
2025-02-03 13:44:25 +00:00
Kim Morrison
8f5418dbda chore: update release_checklist.md (#6919)
This PR updates the release checklist, reflecting changes noted while
@jcommelin has been releasing v4.16.0.

---------

Co-authored-by: Johan Commelin <johan@commelin.net>
2025-02-03 12:31:52 +00:00
Lean stage0 autoupdater
5930f430f4 chore: update stage0 2025-02-03 12:12:03 +00:00
Markus Himmel
0f5dceda4b feat: recommended_spelling command (#6869)
This PR adds a `recommended_spelling` command, which can be used for
recording the recommended spelling of a notation (for example, that the
recommended spelling of `∧` in identifiers is `and`). This information
is then appended to the relevant docstrings for easy lookup.

The function `Lean.Elab.Term.Doc.allRecommendedSpellings` may be used to
obtain a list of all recommended spellings, for example to create a
table that is part of a style guide. In the future, it might be
desirable to be able to partition such a table into smaller tables by
category. This can be added in a future PR.

The implementation is heavily inspired by #4490.
2025-02-03 11:15:52 +00:00
Johan Commelin
13e2a0291c chore: split RELEASES.md into releases/ folder (#6918)
This will make it more straightforward to check automatically that the
release notes in the repository match the release notes on github.
2025-02-03 11:04:09 +00:00
Joachim Breitner
8edaddd70c refactor: post-stage0 clean-up for #6898 (#6920) 2025-02-03 11:04:07 +00:00
Lean stage0 autoupdater
eab91e68c5 chore: update stage0 2025-02-03 10:10:49 +00:00
Joachim Breitner
a5a525f6a1 refactor: WF: create unfold theorems eagerly (#6898)
This PR changes how the unfold theorems for well-founded recursion are
created. They are created eagerly (anticipating that the behaivor may be
affected by simp sets soon), and without the detour of going through
equational theorems.
2025-02-03 09:05:22 +00:00
Vlad Tsyrklevich
bc54db2af1 chore: undo small change (#6917)
In #6818, I removed this small section of reductions from BitVec to Nat
since it seemed unnecessary. Since then, I saw that there are equivalent
sections for shiftLeft/sshiftRight that are more substantial and that I
should have not made this change.
2025-02-03 08:39:13 +00:00
Paul Reichert
6e7b76c097 feat: builtin as_aux_lemma tactic and tree_tac simp attribute (#6823)
This PR adds a builtin tactic and a builtin attribute that are required
for the tree map. The tactic, `as_aux_lemma`, can generally be used to
wrap the proof term generated by a tactic sequence into a separate
auxiliary lemma in order to keep the proof term small. This can, in rare
cases, be necessary if the proof term will appear multiple times in the
encompassing term. The new attribute, `Std.Internal.tree_tac`, is
internal and should not be used outside of `Std`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-03 08:34:29 +00:00
Johan Commelin
a1d522ab14 chore: add a few lines to the v4.16.0 release notes (#6916) 2025-02-03 08:22:33 +00:00
Kim Morrison
809ae9aac3 chore: use --since in release_notes.py (#6915)
The semantics of `release_notes.py` was slightly confusing. It is meant
to be run a `script/release_notes.py v4.15.0` on the `releases/v4.16.0`
branch. To help, I've changed the usage to `script/release_notes.py
--since v4.15.0`.
2025-02-03 08:03:40 +00:00
Kim Morrison
832d7c500d chore: fix release_checklist.py tag lookup bug (#6913) 2025-02-03 06:07:53 +00:00
Kim Morrison
f6df23f2a7 feat: align findX theorems across List/Array/Vector (#6912)
This PR aligns current coverage of `find`-type theorems across
`List`/`Array`/`Vector`. There are still quite a few holes in this API,
which will be filled later.
2025-02-03 04:36:20 +00:00
Leonardo de Moura
1abac9aca6 chore: improve grind case-split trace (#6911) 2025-02-03 04:00:45 +00:00
Leonardo de Moura
40d9f49d68 chore: improve grind pattern pretty printer (#6910) 2025-02-03 03:04:33 +00:00
Leonardo de Moura
15f1aeed6e test: grind_guide.lean (#6908) 2025-02-03 02:11:41 +00:00
Kim Morrison
c193195a05 chore: fixing short-circuiting issue in Ordering.then (#6907)
Thanks to @PatrickMassot for noticing the bug, and @digama0 for
diagnosing, fixing, and testing.
2025-02-03 00:44:45 +00:00
Kyle Miller
1f6abcaf6c feat: make all app unexpanders respond to pp.tagAppFns (#6730)
This PR changes how app unexpanders are invoked. Before the ref was
`.missing`, but now the ref is the head constant's delaborated syntax.
This way, when `pp.tagAppFns` is true, then tokens in app unexpanders
are annotated with the head constant. The consequence is that in docgen,
tokens will be linkified. This new behavior is consistent with how
`notation` defines app unexpanders.

In a followup PR we can slightly simplify the `notation` unexpander
macro to not set the ref.
2025-02-02 23:29:12 +00:00
Kyle Miller
89d897a34d feat: make coeFun delaborator respect pp.tagAppFns (#6729)
This PR makes the pretty printer for `.coeFun`-tagged functions respect
`pp.tagAppFns`. The effect is that in docgen, when an expression pretty
prints as `f x y z` with `f` a coerced function, then if `f` is a
constant it will be linkified.
2025-02-02 22:54:23 +00:00
Kyle Miller
3fb264b569 feat: modify delaborator to tag generalized field notation (#6703)
This PR modifies the delaborator so that in `pp.tagAppFns` mode,
generalized field notation is tagged with the head constant. The effect
is that docgen documentation will linkify dot notation. Internal change:
now formatted `rawIdent` can be tagged.
2025-02-02 21:34:49 +00:00
Sebastian Ullrich
d68c2ce28b chore: remove stray profiler option from test 2025-02-02 09:54:57 +01:00
Leonardo de Moura
64b5bedc8c feat: try? tactic (#6905)
This PR adds the `try?` tactic. This is the first draft, but it can
already solve examples such as:
```lean
example (e : Expr) : e.simplify.eval σ = e.eval σ := by
  try?
```
in `grind_constProp.lean`. In the example above, it suggests:
```lean
induction e using Expr.simplify.induct <;> grind?
``` 
In the same test file, we have
```lean
example (σ₁ σ₂ : State) : σ₁.join σ₂ ≼ σ₂ := by
  try?
```
and the following suggestion is produced
```lean
induction σ₁, σ₂ using State.join.induct <;> grind? 
```
2025-02-02 06:37:49 +00:00
Leonardo de Moura
38086a83cb feat: add Grind.Config.verbose and reportIssue! macro (#6904)
This PR adds the `grind` configuration option `verbose`. For example,
`grind -verbose` disables all diagnostics. We are going to use this flag
to implement `try?`.
2025-02-01 21:12:00 +00:00
Joachim Breitner
deb3299263 refactor: simpMatch to not etaStruct (#6901)
This PR changes the `simpMatch` function, used inside the equation
generator for WF-rec functions, to not do eta-expansion.

This makes the process a bit more robust and disciplined, and avoids
removing match-statements (and introduce projections and dependencies)
that we'd rather split instead.

Also adds more tracing to the equational theorem generator.

Extracted from #6898.
2025-02-01 19:04:05 +00:00
Malvin Gattinger
2b0e75748b doc: correct docstring for TransGen.tail and TransGen.trans (#6900)
This PR only modifies docstrings and should fix issue #6899
2025-02-01 13:52:52 +00:00
Vlad Tsyrklevich
ca96ea331e feat: teach bv_normalize to rewrite subtractions to additions (#6890)
This PR teaches bv_normalize to replace subtractions on one side of an
equality with an addition on the other side, this re-write eliminates a
not + addition in the normalized form so it is easier on the solver.

Note that I also make a point to normalize (1 + ~~~x) to (~~~x + 1) to
limit the amount of boilerplate symmetry theorems we require.
2025-02-01 10:56:54 +00:00
Leonardo de Moura
66471ba6e2 feat: attributes [grind =>] and [grind <=] (#6897)
This PR adds the new attributes `[grind =>]` and `[grind <=]` for
controlling pattern selection and minimizing the number of places where
we have to use verbose `grind_pattern` command. It also fixes a bug in
the new pattern selection procedure, and improves the automatic pattern
selection for local lemmas.

The tests `grind_constProp.lean` and `no_grind_constProp.lean` are the
same use case with and without `grind`.
2025-02-01 04:41:19 +00:00
Leonardo de Moura
425c7a12d0 fix: grind issues exposed by grind_constProp (#6895)
This PR fixes a few `grind` issues exposed by the `grind_constProp.lean`
test.
- Support for equational theorem hypotheses created before invoking
`grind`. Example: applying an induction principle.s
- Support of `Unit`-like types. 
- Missing recursion depth checks.
2025-02-01 01:35:12 +00:00
Henrik Böving
1776758971 perf: inline a few functions in the bv_decide circuit cache (#6889)
This PR inlines a few functions in the `bv_decide` circuit cache.
2025-01-31 22:25:15 +00:00
Leonardo de Moura
5286b21126 feat: bug in pattern selection heuristic in grind (#6892)
This PR fixes a bug in the pattern selection heuristic used in `grind`.
It was unfolding definitions/abstractions that were not supposed to be
unfolded. See `grind_constProp.lean` for examples affected by this bug.
2025-01-31 20:22:49 +00:00
Leonardo de Moura
5900f39638 feat: add [grind intro] attribute (#6888)
This PR adds the `[grind intro]` attribute. It instructs `grind` to mark
the introduction rules of an inductive predicate as E-matching theorems.
2025-01-31 17:03:54 +00:00
Sebastian Ullrich
b3a8d5b04e feat: async modes for environment access (#6852)
This PR allows environment extensions to opt into access modes that do
not block on the entire environment up to this point as a necessary
prerequisite for parallel proof elaboration.
2025-01-31 16:35:50 +00:00
Vlad Tsyrklevich
a3f7d44593 chore: small clean-up in DivModLemmas (#6877)
As a follow-up to #6718, refactor a few bmod proofs to be shorter and
exactly match their emod* equivalents for uniformity.
2025-01-31 16:17:16 +00:00
Vlad Tsyrklevich
7bd12c71c8 feat: add or/and/xor lemmas for BitVec/bv_normalize (#6872)
This PR adds lemmas for xor injectivity and when and/or/xor equal
allOnes or zero. Then I plumb support for the new lemmas through to
bv_normalize.
2025-01-31 13:27:43 +00:00
François G. Dorais
9b5813eeda feat: add BitVec lemmas about msb and shiftConcat (#6875)
This PR adds a lemma relating `msb` and `getMsbD`, and three lemmas
regarding `getElem` and `shiftConcat`. These lemmas were needed in
[Batteries#1078](https://github.com/leanprover-community/batteries/pull/1078)
and the request to upstream was made in the review of that PR.

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
2025-01-31 12:07:57 +00:00
Markus Himmel
fe3a78d262 fix: name of Int.tdiv in HDiv.hDiv docstring (#6885)
This PR fixes the name of the truncating integer division function in
the `HDiv.hDiv` docstring (which is shown when hovering over `/`). It
was changed from `Int.div` to `Int.tdiv` in #5301.
2025-01-31 08:52:22 +00:00
Kim Morrison
6c2573fc38 feat: alignment of lemmas about monadic functions on List/Array/Vector (#6883)
This PR completes the alignment of lemmas about monadic functions on
`List/Array/Vector`. Amongst other changes, we change the simp normal
form from `List.forM` to `ForM.forM`, and correct the definition of
`List.flatMapM`, which previously was returning results in the incorrect
order. There remain many gaps in the verification lemmas for monadic
functions; this PR only makes the lemmas uniform across
`List/Array/Vector`.
2025-01-31 07:25:24 +00:00
Paul Reichert
ad48761032 feat: add simple Ordering lemmas (#6821)
This PR adds basic lemmas about `Ordering`, describing the interaction
of `isLT`/`isLE`/`isGE`/`isGT`, `swap` and the constructors.
Additionally, it refactors the instance derivation code such that a
`LawfulBEq Ordering` instance is also derived automatically.

Some of these lemmas are helpful for the `TreeMap` verification.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-01-31 06:32:53 +00:00
Johan Commelin
0a42a47ea8 chore: mark Mul.mul and HMul.hMul as match_pattern (#6863)
This PR allows fixing regressions in mathlib introduced in
nightly-2024-02-25 by allowing the use of `x * y` in match patterns.
There are currently 11 instances in mathlib explicitly flagging the lack
of this match pattern.

This issue was previously pointed out in the following Zulip threads:

-
https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Algebra.2EFree/near/321482426
-
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/match_pattern.20attribute.20on.20Mul.2Emul/near/321505298
-
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/.40.5Bmatch_pattern.5D.20for.20basic.20binary.20operators/near/423734085
-
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Mul.20match_pattern/near/430635623
2025-01-31 05:39:33 +00:00
Leonardo de Moura
d70a596887 feat: hide grind auxiliary gadgets in messages (#6882)
This PR ensures `grind` auxiliary gadgets are "hidden" in error and
diagnostic messages.
2025-01-31 05:10:59 +00:00
Cameron Zwarich
3331ed9bb1 fix: add Float32 to LCNF.builtinRuntimeTypes list (#6837)
This PR adds Float32 to the LCNF builtinRuntimeTypes list. This was
missed during the initial Float32 implementation, but this omission has
the side effect of lowering Float32 to obj in the IR.
2025-01-31 04:53:49 +00:00
Leonardo de Moura
b3be4ea66e feat: include Case analyses trace in the grind error message (#6881)
This PR improves the `grind` error message by including a trace of the
terms on which `grind` applied `cases`-like operations.
2025-01-31 04:22:50 +00:00
Leonardo de Moura
b329c4b5db feat: improve pattern selection heuristic in grind (#6880)
This PR improves the E-matching pattern selection heuristic used in
`grind`.
2025-01-31 02:16:15 +00:00
Leonardo de Moura
a2155e0741 fix: bug in mkMatchCondProf? in grind (#6879)
This PR fixes a bug in `mkMatchCondProf?` used by the `grind` tactic.
This bug was introducing a failure in the test `grind_constProp.lean`.
2025-01-31 01:18:49 +00:00
Kim Morrison
40eefb1df6 feat: alignment of List/Array/Vector lemmas about range, range', zipIdx (#6878)
This PR completes alignments of `List/Array/Vector` lemmas about
`range`, `range'`, and `zipIdx`.
2025-01-31 00:06:51 +00:00
Leonardo de Moura
146f6e6b2f feat: use profileitM in grind (#6876) 2025-01-30 22:15:27 +00:00
Kim Morrison
52a27697be feat: Cooper resolution (#6862)
This PR defines Cooper resolution with a divisibility constraint as
formulated in
"Cutting to the Chase: Solving Linear Integer Arithmetic" by Dejan
Jovanović and Leonardo de Moura,
DOI 10.1007/s10817-013-9281-x.
2025-01-30 18:47:14 +00:00
Leonardo de Moura
270934cbb6 test: constProp using grind (#6873)
It has many TODOs
2025-01-30 18:28:54 +00:00
Leonardo de Moura
731551d670 chore: cleanup grind tests (#6871) 2025-01-30 17:51:45 +00:00
Leonardo de Moura
2fedd7144a feat: normalize != and == in grind (#6870)
This PR adds two new normalization steps in `grind` that reduces `a !=
b` and `a == b` to `decide (¬ a = b)` and `decide (a = b)`,
respectively.
2025-01-30 16:00:18 +00:00
Kim Morrison
5bd75695f4 feat: align List/Array/Vector eraseP/erase/eraseIdx lemmas (#6868)
This PR completes the alignment across `List/Array/Vector` of lemmas
about the `eraseP/erase/eraseIdx` operations.
2025-01-30 12:29:55 +00:00
Joachim Breitner
cd62b8cd80 refactor: WF.Eqns: rewrite fix without duplicating F (#6859)
This PR changes how WF.Eqns unfolds the fixpoint. Instead of delta'ing
until we have `fix`, and then blindly applying `fix_eq`, we delta one
step less and preserve the function on the right hand side. This leads
to smaller terms in the next step, so easier to debug, possibly faster,
possibly more robust.
2025-01-30 10:23:18 +00:00
Vlad Tsyrklevich
dc445d7af6 feat: add BitVec multiplication simp lemmas (#6718)
This PR adds BitVec lemmas required to cancel multiplicative negatives,
and plumb support through to bv_normalize to make use of this result in
the normalized twos-complement form.

I include some bmod lemmas I found useful to prove this result, the two
helper lemmas I add use the same naming/proofs as their emod
equivalents.
2025-01-30 08:24:18 +00:00
Kim Morrison
e7d8948fa6 feat: lemmas relating findIdx?/findFinIdx?/idxOf?/findIdxOf?/eraseP/erase on List and Array (#6864)
This PR adds lemmas relating the operations on
findIdx?/findFinIdx?/idxOf?/findIdxOf?/eraseP/erase on List and on
Array. It's preliminary to aligning the verification lemmas for
`find...` and `erase...`.
2025-01-30 07:04:50 +00:00
Leonardo de Moura
e922edfc21 feat: Bool.and, Bool.or, and Bool.not propagation in grind (#6861)
This PR adds propagation rules for `Bool.and`, `Bool.or`, and `Bool.not`
to the `grind` tactic.
2025-01-30 02:47:06 +00:00
Kim Morrison
5b1c6b558a feat: align take/drop/extract across List/Array/Vector (#6860)
This PR makes `take`/`drop`/`extract` available for each of
`List`/`Array`/`Vector`. The simp normal forms differ, however: in
`List`, we simplify `extract` to `take+drop`, while in `Array` and
`Vector` we simplify `take` and `drop` to `extract`. We also provide
`Array/Vector.shrink`, which simplifies to `take`, but is implemented by
repeatedly popping. Verification lemmas for `Array/Vector.extract` to
follow in a subsequent PR.
2025-01-30 01:24:25 +00:00
Kim Morrison
21e8a99eff feat: refactor of find functions on List/Array/Vector (#6833)
This PR makes the signatures of `find` functions across
`List`/`Array`/`Vector` consistent. Verification lemmas will follow in
subsequent PRs.

We were previously quite inconsistent about the signature of
`indexOf`/`findIdx` functions across `List` and `Array`. Moreover, there
are still quite large gaps in the verification lemma coverage for these
even at the `List` level.

My intention is to make the signatures consistent by providing:
`findIdx` / `findIdx?` / `findFinIdx?` (these all take a predicate, and
return respectively a `Nat`, `Option Nat`, `Option (Fin l.length)`) and
similarly `idxOf` / `idxOf?` / `finIdxOf?` (which look for an element)
for each of List/Array/Vector. I've seen enough examples by now where
each variant is genuinely the most convenient at the call-site, so I'm
going to accept the cost of having many closely related functions.
*Hopefully* for the verification lemmas we can simp all of these into
"projections" of the `Option (Fin l.length)` versions, and then only
have to specify that.

However, I will not plan on immediately either filling in the missing
verification lemmas (or even deciding what the simp normal forms
relating these operations are), and just reach parity amongst
List/Array/Vector for what is already there.
2025-01-30 01:14:21 +00:00
Leonardo de Moura
49fe87e0d1 feat: missing propagation rules in grind (#6858)
This PR adds new propagation rules for `decide` and equality in `grind`.
It also adds new tests and cleans old ones
2025-01-29 23:40:33 +00:00
Henrik Böving
61c843a3c7 refactor: pull out some LRAT functionality from bv_decide (#6856)
This PR refactors a bit of the functionality in bv_decide's frontend to
make it accessible for external users.
2025-01-29 20:47:47 +00:00
Lean stage0 autoupdater
ca3c7571e5 chore: update stage0 2025-01-29 19:45:27 +00:00
Leonardo de Moura
5075153c15 feat: better support for inductive predicates in grind (#6854)
This PR adds a convenience for inductive predicates in `grind`. Now,
give an inductive predicate `C`, `grind [C]` marks `C` terms as
case-split candidates **and** `C` constructors as E-matching theorems.
Here is an example:
```lean
example {B S T s t} (hcond : B s) : (ifThenElse B S T, s) ==> t → (S, s) ==> t := by
  grind [BigStep]
```
Users can still use `grind [cases BigStep]` to only mark `C` as a case
split candidate.
2025-01-29 18:17:34 +00:00
Henrik Böving
c7dec60428 feat: support UIntX and USize in bv_decide (#6711)
This PR adds support for `UIntX` and `USize` in `bv_decide` by adding a
preprocessor that turns them into `BitVec` of their corresponding size.
2025-01-29 15:41:38 +00:00
Henrik Böving
41fe7bc71a feat: bv_normalize rewrite shifts by BitVec const to shift by Nat const (#6851)
This PR makes `bv_normalize` rewrite shifts by `BitVec` constants to
shifts by `Nat` constants. This is part of the greater effort in
providing good support for constant shift simplification in
`bv_normalize`.
2025-01-29 15:17:39 +00:00
Arthur Adjedj
2c00f8fe2f fix: consume mdata in casesOnStuckLHS when checking that major is fvar (#6791)
This PR fixes #6789 by ensuring metadata generated for inaccessible
variables in pattern-matches is consumed in `casesOnStuckLHS`
accordingly.

Closes #6789
2025-01-29 14:32:11 +00:00
Sebastian Ullrich
68653297d1 chore: re-enable Lake 2025-01-29 15:59:05 +01:00
Sebastian Ullrich
729d6e5d5c chore: update stage0 2025-01-29 15:59:05 +01:00
Sebastian Ullrich
c6677e0b6f perf: avoid environment extension indirection 2025-01-29 15:59:05 +01:00
Vlad Tsyrklevich
0c43f05047 feat: add BitVec add_self/self_add lemmas (#6848)
This PR adds simp lemmas proving `x + y = x ↔ x = 0` for BitVec, along
with symmetries, and then adds these to the bv_normalize simpset.
2025-01-29 13:52:57 +00:00
Kim Morrison
3c8cf7a905 chore: remove unneeded LawfulBEq hypotheses (#6847) 2025-01-29 12:24:36 +00:00
Kim Morrison
51b56b20ec feat: missing monadic functions on List/Array/Vector (#6845)
This PR adds missing monadic higher order functions on
`List`/`Array`/`Vector`. Only the most basic verification lemmas
(relating the operations on the three container types) are provided for
now.
2025-01-29 12:19:30 +00:00
Vlad Tsyrklevich
5c0231f508 feat: add BitVec add/sub injectivity lemmas (#6828)
This PR adds add/sub injectivity lemmas for BitVec, and then adds
specialized forms with additional symmetries for the `bv_normalize`
normal form.

Since I need `neg_inj`, I add `not_inj`/`neg_inj` at once, and use it in
`BitVec.not_beq_not` instead of re-proving it.
2025-01-29 10:35:44 +00:00
Sebastian Ullrich
a35bf7ee4c chore: revert "perf: use C23's free_sized when available" (#6841)
Reverts leanprover/lean4#6598, which broke Windows CI
2025-01-29 09:11:23 +00:00
Kim Morrison
bc234f9f8d feat: align List/Array/Vector.zip/zipWith/zipWithAll/unzip (#6840)
This PR completes the alignment of
`List/Array/Vector.zip/zipWith/zipWithAll/unzip` lemmas.
2025-01-29 07:58:17 +00:00
Leonardo de Moura
08ec2541c7 feat: add support for constructors and axioms to the grind E-matching module (#6839)
This PR ensures `grind` can use constructors and axioms for heuristic
instantiation based on E-matching. It also allows patterns without
pattern variables for theorems such as `theorem evenz : Even 0`.
2025-01-29 05:22:05 +00:00
Kim Morrison
e05131122b feat: finish aligning List/Array/Vector.ofFn lemmas (#6838)
This PR completes aligning the (limited) verification API for
`List/Array/Vector.ofFn`.
2025-01-29 04:53:33 +00:00
Kim Morrison
e4749eb6b5 chore: preparation for Array.erase lemmas (#6836)
This PR rearranges some material, and adds some missing lemmas, in
preparation for aligning `List/Array/Vector.erase(P)`.
2025-01-29 04:07:51 +00:00
Kim Morrison
84311122ac feat: align List/Array/Vector lemmas for isEqv and == (#6831)
This PR completes the alignment of `List/Array/Vector` lemmas about
`isEqv` and `==`.
2025-01-29 03:12:02 +00:00
Kim Morrison
c93012faa1 feat: add Vector.mapM, ForIn/ToStream instances (#6835)
This PR fills some gaps in the `Vector` API, adding `mapM`, `zip`, and
`ForIn'` and `ToStream` instances.
2025-01-29 02:58:40 +00:00
Leonardo de Moura
aa65107523 feat: "performance" counters for grind (#6834)
This PR adds "performance" counters (e.g., number of instances per
theorem) to `grind`. The counters are always reported on failures, and
on successes when `set_option diagnostics true`.
2025-01-29 02:12:31 +00:00
Kim Morrison
07e2b7d913 chore: update some Array doc-strings (#6832) 2025-01-29 01:32:41 +00:00
Kim Morrison
9b5fadd275 chore: remove unnecessary simp priorities (#6812)
This PR remove simp priorities that are not needed. Some of these will
probably cause complaints from the `simpNF` linter downstream in
Batteries, which I will re-address separately.
2025-01-28 23:50:33 +00:00
Kim Morrison
7e8af0fc9d feat: rename List.enum(From) to List.zipIdx, and Array/Vector.zipWithIndex to zipIdx (#6800)
This PR uniformizes the naming of `enum`/`enumFrom` (on `List`) and
`zipWithIndex` (on `Array` on `Vector`), replacing all with `zipIdx`. At
the same time, we generalize to add an optional `Nat` parameter for the
initial value of the index (which previously existed, only for `List`,
as the separate function `enumFrom`).
2025-01-28 23:34:30 +00:00
Kim Morrison
f10d0d07d9 feat: lemmas about BitVec.setWidth (#6808)
This PR adds simp lemmas replacing `BitVec.setWidth'` with `setWidth`,
and conditionally simplifying `setWidth v (setWidth w v)`.

---------

Co-authored-by: Tobias Grosser <tobias@grosser.es>
2025-01-28 23:33:45 +00:00
Joachim Breitner
312759e369 fix: injectivity theorems for more prelude inductives (#6826)
This PR adds injectivity theorems for inductives that did not get them
automatically (because they are defined too early) but also not yet
manuall later.

It also adds a test case to notice when new ones fall through.o

It does not add them for clearly meta-programming related types that are
not yet defined in `Init/Core.lean`, and uses `#guard_msgs` as an
allowlist.

---------

Co-authored-by: Kim Morrison <scott.morrison@gmail.com>
2025-01-28 23:09:28 +00:00
Vlad Tsyrklevich
1d9439752c feat: teach bv_normalize that (x >> x) = 0 (#6818)
This PR adds a BitVec lemma that `(x >> x) = 0` and plumbs it through to
bv_normalize. I also move some theorems I found useful to the top of the
ushiftRight section.
2025-01-28 20:56:21 +00:00
Leonardo de Moura
9f5a9a071a feat: add %reset_grind_attrs (#6824)
This PR introduces the auxiliary command `%reset_grind_attrs` for
debugging purposes. It is particularly useful for writing self-contained
tests.
2025-01-28 18:29:02 +00:00
Leonardo de Moura
26bc8c5b2a feat: builtin case splits for grind (#6822)
This PR adds a few builtin case-splits for `grind`. They are similar to
builtin `simp` theorems. They reduce the noise in the tactics produced
by `grind?`.
2025-01-28 17:30:36 +00:00
Kim Morrison
eea2d49078 chore: lower List/Array/Vector.mem_map simp priority (#6815)
This PR lowers the simp priority of `List/Array/Vector.mem_map`, as
downstream in Mathlib many lemmas currently need their priority raised
to fire before this.
2025-01-28 12:23:24 +00:00
Markus Himmel
f9d3deaafe perf: improve elaboration performance of Std.Data.DHashMap.Internal.RawLemmas (#6814)
This PR optimizes the proofs in the internal file
`Std/Data/DHashMap/Internal/RawLemmas.lean` so that the file is quicker
to elaborate.
2025-01-28 11:04:42 +00:00
Sebastian Ullrich
e4364e747f chore: temporarily disable async in server (#6813)
... pending an interruption bug fix and further testing
2025-01-28 10:42:17 +00:00
Eric Wieser
6aa6407af1 perf: use C23's free_sized when available (#6598)
See https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2699.htm for an
explanation of this feature.

---------

Co-authored-by: Chris Kennelly <ckennelly@google.com>
2025-01-28 10:17:15 +00:00
Eric Wieser
9247206c0e doc: clarify that lean_initialize_runtime_module is implied by lean_initialize (#6677)
Calling both runs the initializers twice, resulting in a memory leak
2025-01-28 10:12:59 +00:00
Vlad Tsyrklevich
c7c1e091c9 feat: add BitVec comparison lemmas to bv_normalize (#6799)
This PR adds a number of simple comparison lemmas to the top/bottom
element for BitVec. Then they are applied to teach bv_normalize that
`(a<1) = (a==0)` and to remove an intermediate proof that is no longer
necessary along the way.
2025-01-28 08:48:11 +00:00
Leonardo de Moura
20c616503a feat: add grind? (#6810)
This PR implements a basic `grind?` tactic companion for `grind`. We
will add more bells and whistles later.
2025-01-28 04:17:25 +00:00
Kim Morrison
104b3519d7 feat: add Fin.ofNat'_zero (#6806)
This PR adds a simp lemma for `Fin.ofNat'`.
2025-01-28 02:00:01 +00:00
Kim Morrison
d8fcfead97 feat: add LawfulMonad helper simp lemmas (#6805)
This PR adds to helper lemmas in the `LawfulMonad` namespace, which
sometimes fire via `simp` when the original versions taking
`LawfulApplicative` or `Functor` do not fire.
2025-01-28 01:59:55 +00:00
Kim Morrison
d0b947bf52 chore: add @[simp] to Option.not_mem_none (#6804)
This PR improves simp lemma confluence.
2025-01-28 01:59:47 +00:00
Mac Malone
5f0fea60a6 refactor: lake: deprecate -U (#6798)
This PR deprecates the `-U` shorthand for the `--update` option.

It is likely the `-U` option will be used for something different in the
future, so deprecating it now seems wise.
2025-01-28 01:54:55 +00:00
Mac Malone
3e54597db4 feat: lake query (#6323)
This PR adds a new Lake CLI command, `lake query`, that both builds
targets and outputs their results. It can produce raw text or JSON
-formatted output (with `--json` / `-J`).

This PR removes the `lean.` prefix from the module import facets (for
ease-of-use in the `lake query` CLII). It also renames the package
`deps` facet, `transDeps`. The new `deps` facet just returns the
package's direct dependencies.
2025-01-28 01:43:03 +00:00
Kim Morrison
eb1c9b9ab2 chore: two BitVec lemmas that help simp confluence (#6807)
This PR adds two simple `BitVec` lemmas which improve `simp` local
confluence.
2025-01-28 01:12:05 +00:00
Kim Morrison
4d66e7bdc0 feat: add List.modifyHead_dropLast (#6803)
This PR adds the simp lemma `List.modifyHead_dropLast`. This is one of
many small PRs that will improve simp lemma confluence.
2025-01-28 00:25:58 +00:00
Kim Morrison
f8660485d7 feat: Option.elim_pmap, improving simp confluence (#6802)
This PR adds the simp lemma `Option.elim_pmap`. This is one of many
small PRs that will improve simp lemma confluence.
2025-01-28 00:21:10 +00:00
Leonardo de Moura
64766f8724 fix: offset constraint propagation in grind (#6801)
This PR fixes a bug in the exhaustive offset constraint propagation
module used in `grind`.
2025-01-27 23:43:31 +00:00
Marc Huisinga
f64bce6ef1 fix: auto-completion performance regression (#6794)
This PR fixes a significant auto-completion performance regression that
was introduced in #5666, i.e. v4.14.0.

#5666 introduced tactic docstrings, which were attempted to be collected
for every single completion item. This is slow for hundreds of thousands
of completion items. To fix this, this PR moves the docstring
computation into the completion item resolution, which is only called
when users select a specific completion item in the UI.

A downside of this approach is that we currently can't test completion
item resolution, so we lose a few tests that cover docstrings in
completions in this PR.
2025-01-27 21:15:09 +00:00
Marc Huisinga
0160aa1a89 test: identifier completion benchmark (#6796)
Adds a basic identifier completion benchmark so that bugs like the one
in #6794 are caught earlier.
2025-01-27 19:31:32 +00:00
Joachim Breitner
3418d6db8e fix: more robust equational theorems generation for partial_fixpoint (#6790)
This PR fixes an issue with the generation of equational theorems from
`partial_fixpoint` when case-splitting is necessary. Fixes #6786.
2025-01-27 14:00:55 +00:00
Vlad Tsyrklevich
3aea0fd810 feat: add comparison lemmas to bv_normalize (#6788)
This PR teaches bv_normalize that !(x < x) and !(x < 0).
2025-01-27 13:44:44 +00:00
Joachim Breitner
4ca98dcca2 doc: typos in partial_fixpoint related docstrings (#6787)
H'T David
2025-01-27 09:43:09 +00:00
Markus Himmel
55b0bed5df doc: standard library vision and call for contributions (#6762) 2025-01-27 09:07:02 +00:00
Henrik Böving
d86a408944 feat: bv_decide can reason about equality of structures (#6740)
This PR extends `bv_decide`'s structure reasoning support for also
reasoning about equalities of supported structures.
2025-01-27 08:11:43 +00:00
Leonardo de Moura
69a73a18fb feat: grind? infrastructure (#6785)
This PR adds infrastructure for the `grind?` tactic. It also adds the
new modifier `usr` which allows users to write `grind only [usr
thmName]` to instruct `grind` to only use theorem `thmName`, but using
the patterns specified with the command `grind_pattern`.
2025-01-27 01:31:25 +00:00
Leonardo de Moura
98bd162ad4 feat: close goals using match-expression conditions in grind (#6783)
This PR adds support for closing goals using `match`-expression
conditions that are known to be true in the `grind` tactic state.
`grind` can now solve goals such as:
```lean
def f : List Nat → List Nat → Nat
  | _, 1 :: _ :: _ => 1
  | _, _ :: _ => 2
  | _, _  => 0

example : z = a :: as → y = z → f x y > 0
```
Without `grind`, we would use the `split` tactic. The first two goals,
corresponding to the first two alternatives, are closed using `simp`,
and the the third using the `match`-expression condition produced by
`split`. The proof would proceed as follows.
```lean
example : z = a :: as → y = z → f x y > 0 := by
  intros
  unfold f
  split
  next => simp
  next => simp
  next h =>
    /-
    ...
    _ : z = a :: as
    _ : y = z
    ...
    h : ∀ (head : Nat) (tail : List Nat), y = head :: tail → False
    |- 0 > 0
    -/
    subst_vars
    /-
    ...
    h : ∀ (head : Nat) (tail : List Nat), a :: as = head :: tail → False
    |- 0 > 0
    -/
    have : False := h a as rfl
    contradiction
```
Here is the same proof using `grind`.
```lean
example : z = a :: as → y = z → f x y > 0 := by
  grind [f.eq_def]
```
2025-01-26 17:13:11 +00:00
Joachim Breitner
ba95dbc36b feat: zetaUnused option (implementation) (#6755)
This PR implements the `zetaUnused` simp and reduction option (added in
#6754).

True by default, and implied by `zeta`, this can be turned off to make
simp even more careful about preserving the expression structure,
including unused let and have expressions.

Breaking change: The `split` tactic no longer removes unused let and
have expressions as a side-effect, in rare cases this may break proofs.
`dsimp only` can be used to remove unused have and let expressions.
2025-01-26 11:14:12 +00:00
Mac Malone
6278839534 refactor: lake: all targets produce jobs (#6780)
This PR makes all targets and all `fetch` calls produce a `Job` of some
value. As part of this change, facet definitions (e.g., `library_data`,
`module_data`, `package_data`) and Lake type families (e.g.,
`FamilyOut`) should no longer include `Job` in their types (as this is
now implicit).
2025-01-26 05:03:07 +00:00
Leonardo de Moura
849a252b20 fix: case split on data in grind (#6781)
This PR fixes the support for case splitting on data in the `grind`
tactic. The following example works now:
```lean
inductive C where
  | a | b | c

def f : C → Nat
  | .a => 2
  | .b => 3
  | .c => 4

example : f x > 1 := by
  grind [
      f, -- instructs `grind` to use `f`-equation theorems, 
      C -- instructs `grind` to case-split on free variables of type `C`
  ]
```
2025-01-26 02:14:08 +00:00
Leonardo de Moura
ca56c5ecc0 feat: improve support for match-expressions in grind (#6779)
This PR improves the support for `match`-expressions in the `grind`
tactic.
2025-01-26 00:50:29 +00:00
Leonardo de Moura
d10666731c fix: assignment for offset constraints in grind (#6778)
This PR fixes the assignment produced by `grind` to satisfy the offset
constraints in a goal.
2025-01-25 23:21:53 +00:00
Leonardo de Moura
6dbb54d221 fix: offset terms internalization (#6777)
This PR fixes a bug in the internalization of offset terms in the
`grind` tactic. For example, `grind` was failing to solve the following
example because of this bug.
```lean
example (f : Nat → Nat) : f (a + 1) = 1 → a = 0 → f 1 = 1 := by
  grind
```
2025-01-25 21:14:48 +00:00
Cameron Zwarich
cc260dd231 feat: support for csimp theorems in toLCNF (#6757)
This PR adds support for applying crimp theorems in toLCNF.
2025-01-25 21:07:08 +00:00
Leonardo de Moura
9565334c0e fix: Grind.MatchCond in checkParents (#6776)
This PR fixes the `checkParents` sanity checker used in `grind`. It did
not have support for checking the auxiliary gadget `Grind.MatchCond`.
2025-01-25 19:53:26 +00:00
Markus Himmel
2fa38e6ceb fix: suggest correct trace option name in partial_fixpoint error message (#6774)
This PR fixes a `partial_fixpoint` error message to suggest the option
`trace.Elab.Tactic.monotonicity` rather than the nonexistent
`trace.Elab.Tactic.partial_monotonicity`.
2025-01-25 14:42:15 +00:00
Markus Himmel
056d1dbeef fix: typo in partial_fixpoint docstring (#6775)
This PR fixes a typo in the `partial_fixpoint` hover docstring.
2025-01-25 14:41:52 +00:00
Rob23oba
e8bbba06b7 fix: fix builtin simproc Nat.reduceAnd (#6773)
This PR fixes a typo that prevented `Nat.reduceAnd` from working
correctly.

Closes #6772
2025-01-25 12:57:24 +00:00
Mac Malone
58c7a4f15e feat: lake: lift FetchM into JobM (and vice versa) (#6771)
This PR enables `FetchM` to be run from `JobM` / `SpawnM` and
vice-versa. This allows calls of `fetch` to asynchronously depend on the
outputs of other jobs.
2025-01-25 03:59:47 +00:00
Mac Malone
c8be581bc8 refactor: lake: use Job for all builtin facets (#6418)
This PR alters all builtin Lake facets to produce `Job` objects.
2025-01-25 02:53:21 +00:00
Siddharth
c6e244d811 feat: BitVec.shift x (n#w) -> shift x (n % 2^w) (#6767)
This PR adds lemmas to rewrite
`BitVec.shiftLeft,shiftRight,sshiftRight'` by a `BitVec.ofNat` into a
shift-by-natural number. This will be used to canonicalize shifts by
constant bitvectors into shift by constant numbers, which have further
rewrites on them if the number is a power of two.
2025-01-24 17:12:34 +00:00
Siddharth
044bf85fe9 feat: commute BitVec.extractLsb(')? with bitwise ops (#6747)
This PR adds the ability to push `BitVec.extractLsb` and
`BitVec.extractLsb'` with bitwise operations. This is useful for
constant-folding extracts.
2025-01-24 15:23:30 +00:00
Siddharth
1059e25ca2 feat: BitVec.shiftLeft in terms of extractLsb' (#6743)
This PR adds rewrites that normalizes left shifts by extracting bits and
concatenating zeroes. If the shift amount is larger than the bit-width,
then the resulting bitvector is zero.

```lean
theorem shiftLeft_eq_zero {x : BitVec w} {n : Nat} (hn : w ≤ n) : x <<< n = 0#w

theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
    x <<< n = ((x.extractLsb' 0 (w-n)).append (BitVec.zero n)).cast (by omega)
```
2025-01-24 15:14:50 +00:00
Leonardo de Moura
c70f4064b4 fix: heterogenenous equality support in match conditions within grind (#6761)
This PR fixes issues in `grind` when processing `match`-expressions with
indexed families.
2025-01-24 04:08:29 +00:00
Sebastian Ullrich
757899a7d1 chore: run test suite with Elab.async for more coverage 2025-01-23 19:07:31 -07:00
Sebastian Ullrich
a901e34362 perf: avoid cross-thread environment extension state synchronization for now 2025-01-23 19:07:31 -07:00
Sebastian Ullrich
bab10cc2b5 feat: asynchronous kernel checking 2025-01-23 19:07:31 -07:00
Sebastian Ullrich
d26dbe73d5 fix: do not double-report snapshotTasks after wrapAsyncAsSnapshot 2025-01-23 19:07:31 -07:00
Sebastian Ullrich
214093e6c4 fix: prevent Task.get deadlocks from threadpool starvation (#6758)
This PR prevents deadlocks from non-cyclical task waits that may
otherwise occur during parallel elaboration with small threadpool sizes.
2025-01-23 23:01:39 +00:00
Lean stage0 autoupdater
ebda2d4d25 chore: update stage0 2025-01-23 15:28:44 +00:00
Joachim Breitner
7e03920bbb feat: zetaUnused option (option only) (#6754)
This PR adds the `+zetaUnused` option.

Implementation to follow after the stage0 update.
2025-01-23 14:37:41 +00:00
Jon Eugster
d033804190 doc: remove duplicated sentense in Lean.Syntax.node (#6752) 2025-01-23 11:43:48 +00:00
Joachim Breitner
56733b953e refactor: TerminationArgument → TerminationMeasure (#6727)
this PR aligns the terminology of the code with the one use in the
reference manual, as developed with and refined by @david-christiansen.
2025-01-23 10:41:38 +00:00
Lean stage0 autoupdater
c073da20ce chore: update stage0 2025-01-23 08:33:17 +00:00
damiano
d8bcd6a32e doc: correspondence ModuleIdx <--> Environment.moduleNames (#6749)
This PR documents the equality between the `ModuleIdx` of an module and
the index in the array of `moduleNames` of the same module.

I asked about this in the Office hours and it was confirmed that this is
a current feature and one that is likely not to change!
2025-01-23 07:47:38 +00:00
Leonardo de Moura
f35a602070 feat: use cast to "fix" types in the E-matching module within grind (#6750)
This PR adds support for fixing type mismatches using `cast` while
instantiating quantifiers in the E-matching module used by the grind
tactic.
2025-01-23 03:36:20 +00:00
Leonardo de Moura
14841ad1ed fix: bugs in grind (#6748)
This PR fixes a few bugs in the `grind` tactic: missing issues, bad
error messages, incorrect threshold in the canonicalizer, and bug in the
ground pattern internalizer.
2025-01-22 21:59:58 +00:00
Siddharth
5f3c0daf3d feat: BitVec.ushiftRight in terms of extractLsb' (#6745)
This PR supports rewriting `ushiftRight` in terms of `extractLsb'`. This
is the companion PR to #6743 which adds the similar lemmas about
`shiftLeft`.


```lean
theorem ushiftRight_eq_zero {x : BitVec w} {n : Nat} (hn : w ≤ n) :
    x >>> n = 0#w

theorem ushiftRight_eq_extractLsb'_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
    x >>> n = ((0#n) ++ (x.extractLsb' n (w - n))).cast (by omega)
```
2025-01-22 19:14:20 +00:00
Siddharth
6befda831d feat: add twoPow multiplication lemmas (#6742)
This PR adds the lemmas that show what happens when multiplying by
`twoPow` to an arbitrary term, as well to another `twoPow`.

This will be followed up by a PR that uses these to build a simproc to
canonicalize `twoPow w i * x` and `x * twoPow w i`.
2025-01-22 19:05:17 +00:00
Leonardo de Moura
6595ca8f29 feat: improve equation theorem support in grind (#6746)
This PR ensures that conditional equation theorems for function
definitions are handled correctly in `grind`. We use the same
infrastructure built for `match`-expression equations. Recall that in
both cases, these theorems are conditional when there are overlapping
patterns.
2025-01-22 18:41:09 +00:00
Sebastian Ullrich
91e261da38 chore: disable Elab.async on the cmdline for now (#6722)
Avoids build time overhead until the option is proven to speed up
average projects. Adds Init.Prelude (many tiny declarations, "worst
case") and Init.List.Sublist (many nontrivial theorems, "best case")
under -DElab.async=true as new benchmarks for tracking.
2025-01-22 18:25:47 +00:00
Henrik Böving
6ebce42142 perf: fast path for multiplication with constants in bv_decide (#6739)
This PR adds a fast path for bitblasting multiplication with constants
in `bv_decide`.

While the circuit generated is the same (as the AIG already performs
constant folding) this avoids calling out to the shift and addition
bitblaster unless required. Thus the overall time to generate the
circuit is reduced. Inspired by
[bitwuzla](25d77f819c/src/lib/bitblast/bitblaster.h (L454)).
2025-01-22 10:32:47 +00:00
Henrik Böving
b6db90a316 doc: mention subscript j in the lexical structure (#6738)
This PR updates our lexical structure documentation to mention the newly
supported ⱼ which lives in a separate unicode block and is thus not
captured by the current ranges.
2025-01-22 09:10:31 +00:00
Henrik Böving
7706b876f6 feat: bv_decide support for structures of supported types (#6724)
This PR adds support for `bv_decide` to automatically split up
non-recursive structures that contain information about supported types.
It can be controlled using the new `structures` field in the `bv_decide`
config.
2025-01-22 09:01:43 +00:00
Leonardo de Moura
9b74c07767 feat: lazy ite branch internalization in grind (#6737)
This PR ensures that the branches of an `if-then-else` term are
internalized only after establishing the truth value of the condition.
This change makes its behavior consistent with the `match`-expression
and dependent `if-then-else` behavior in `grind`.
This feature is particularly important for recursive functions defined
by well-founded recursion and `if-then-else`. Without lazy
`if-then-else` branch internalization, the equation theorem for the
recursive function would unfold until reaching the generation depth
threshold, and before performing any case analysis. See new tests for an
example.
2025-01-22 05:22:31 +00:00
Leonardo de Moura
533af01dab feat: improve grind canonicalizer (#6736)
This PR ensures the canonicalizer used in `grind` does not waste time
checking whether terms with different types are definitionally equal.
2025-01-22 03:59:45 +00:00
Leonardo de Moura
de31faa470 feat: case splitting match-expressions with overlapping patterns in grind (#6735)
This PR adds support for case splitting on `match`-expressions with
overlapping patterns to the `grind` tactic. `grind` can now solve
examples such as:
```
inductive S where
  | mk1 (n : Nat)
  | mk2 (n : Nat) (s : S)
  | mk3 (n : Bool)
  | mk4 (s1 s2 : S)

def g (x y : S) :=
  match x, y with
  | .mk1 a, _ => a + 2
  | _, .mk2 1 (.mk4 _ _) => 3
  | .mk3 _, .mk4 _ _ => 4
  | _, _ => 5

example : g a b > 1 := by
  grind [g.eq_def]
```
2025-01-22 02:59:42 +00:00
Leonardo de Moura
3881f21df1 fix: redundant information in the offset constraint module (#6734)
This PR ensures there are no redundant entries in the offset constraint
model produced by `grind`
2025-01-21 22:19:24 +00:00
Leonardo de Moura
c9a03c7613 feat: overlapping match patterns in grind (#6733)
This PR adds better support for overlapping `match` patterns in `grind`.
`grind` can now solve examples such as
```lean
inductive S where
  | mk1 (n : Nat)
  | mk2 (n : Nat) (s : S)
  | mk3 (n : Bool)
  | mk4 (s1 s2 : S)

def f (x y : S) :=
  match x, y with
  | .mk1 _, _ => 2
  | _, .mk2 1 (.mk4 _ _) => 3
  | .mk3 _, _ => 4
  | _, _ => 5

example : b = .mk2 y1 y2 → y1 = 2 → a = .mk4 y3 y4 → f a b = 5 := by
  unfold f
  grind (splits := 0)
```

---------

Co-authored-by: Leonardo de Moura <leodemoura@amazon.com>
2025-01-21 22:05:15 +00:00
Luisa Cicolini
0c2fb34c82 chore: remove useless Nat.mul_one from proof (#6728)
This PR removes theorems `Nat.mul_one` to simplify a rewrite in the
proof of `BitVec.getMsbD_rotateLeft_of_lt`
2025-01-21 17:00:19 +00:00
Martin Dvořák
eb30249b11 doc: make description of pp.analyze more precise (#6726)
As @nomeata told me, it should be "try to (...)" because even with
`pp.analyze` roundtripping often fails.
2025-01-21 15:03:48 +00:00
Paul Reichert
31929c0acd feat: lemmas for HashMap.alter and .modify (#6620)
This PR adds lemmas about HashMap.alter and .modify. These lemmas
describe the interaction of alter and modify with the read methods of
the HashMap. The additions affect the HashMap, the DHashMap and their
respective raw versions. Moreover, the raw versions of alter and modify
are defined.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-01-21 12:34:19 +00:00
Joachim Breitner
3569797377 feat: functional cases theorem for non-recursive functions (#6261)
This PR adds `foo.fun_cases`, an automatically generated theorem that
splits the goal according to the branching structure of `foo`, much like
the Functional Induction Principle, but for all functions (not just
recursive ones), and without providing inductive hypotheses.

The design isn't quite final yet as to which function parameters should
become targets of the motive, and which parameters of the theorem, but
the current version is already proven to be useful, so start with this
and iterate later.
2025-01-21 10:16:42 +00:00
Joachim Breitner
7b813d4f5d feat: partial_fixpoint: partial functions with equations (#6355)
This PR adds the ability to define possibly non-terminating functions
and still be able to reason about them equationally, as long as they are
tail-recursive or monadic.

Typical uses of this feature are
```lean4
def ack : (n m : Nat) → Option Nat
  | 0,   y   => some (y+1)
  | x+1, 0   => ack x 1
  | x+1, y+1 => do ack x (← ack (x+1) y)
partial_fixpiont

def whileSome (f : α → Option α) (x : α) : α :=
  match f x with
  | none => x
  | some x' => whileSome f x'
partial_fixpiont

def computeLfp {α : Type u} [DecidableEq α] (f : α → α) (x : α) : α :=
  let next := f x
  if x ≠ next then
    computeLfp f next
  else
    x
partial_fixpiont

noncomputable def geom : Distr Nat := do
  let head ← coin
  if head then
    return 0
  else
    let n ← geom
    return (n + 1)
partial_fixpiont
```

This PR contains

* The necessary fragment of domain theory, up to (a variant of)
Knaster–Tarski theorem (merged as
https://github.com/leanprover/lean4/pull/6477)
* A tactic to solve monotonicity goals compositionally (a bit like
mathlib’s `fun_prop`) (merged as
https://github.com/leanprover/lean4/pull/6506)
* An attribute to extend that tactic (merged as
https://github.com/leanprover/lean4/pull/6506)
* A “derecursifier” that uses that machinery to define recursive
function, including support for dependent functions and mutual
recursion.
* Fixed-point induction principles (technical, tedious to use)
* For `Option`-valued functions: Partial correctness induction theorems
that hide all the domain theory

This is heavily inspired by [Isabelle’s `partial_function`
command](https://isabelle.in.tum.de/doc/codegen.pdf).
2025-01-21 09:54:30 +00:00
Luisa Cicolini
edeae18f5e feat: add Bitvec reverse definition, getLsbD_reverse, getMsbD_reverse, reverse_append, reverse_replicate and Nat.mod_sub_eq_sub_mod (#6476)
This PR defines `reverse` for bitvectors and implements a first subset
of theorems (`getLsbD_reverse, getMsbD_reverse, reverse_append,
reverse_replicate, reverse_cast, msb_reverse`). We also include some
necessary related theorems (`cons_append, cons_append_append,
append_assoc, replicate_append_self, replicate_succ'`) and deprecate
theorems`replicate_zero_eq` and `replicate_succ_eq`.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
Co-authored-by: Kim Morrison <kim@tqft.net>
2025-01-21 08:44:50 +00:00
Kim Morrison
91bae2e064 feat: align {List/Array/Vector}.{attach,attachWith,pmap} lemmas (#6723)
This PR completes the alignment of
{List/Array/Vector}.{attach,attachWith,pmap} lemmas. I had to fill in a
number of gaps in the List API.
2025-01-21 06:36:36 +00:00
Luisa Cicolini
f9e904af50 feat: add BitVec.[getMsbD_mul, getElem_udiv, getLsbD_udiv, getMsbD_udiv] (#6674)
This PR adds theorems `BitVec.[getMsbD_mul, getElem_udiv, getLsbD_udiv,
getMsbD_udiv]`

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
2025-01-21 03:59:27 +00:00
Henrik Böving
8375d00d8c fix: allow ⱼ in identifiers (#6679)
This PR changes the identifier parser to allow for the ⱼ unicode
character which was forgotten as it lives by itself in a codeblock with
coptic characters.
2025-01-21 03:51:51 +00:00
Kim Morrison
16bd7ea455 chore: deprecate List.iota (#6708)
This PR deprecates `List.iota`, which we make no essential use of. `iota
n` can be replaced with `(range' 1 n).reverse`. The verification lemmas
for `range'` already have better coverage than those for `iota`.
Any downstream projects using it (I am not aware of any) are encouraged
to adopt it.
2025-01-21 02:32:35 +00:00
Cameron Zwarich
c54287fb0d feat: add proper erasure of type dependencies in LCNF (#6678)
This PR modifies LCNF.toMonoType to use a more refined type erasure
scheme, which distinguishes between irrelevant/erased information
(represented by lcErased) and erased type dependencies (represented by
lcAny). This corresponds to the irrelevant/object distinction in the old
code generator.
2025-01-21 02:07:16 +00:00
Cameron Zwarich
e3771e3ad6 fix: don't generate code for decls with an implemented_by attribute (#6680)
This PR makes the new code generator skip generating code for decls with
an implemented_by decl, just like the old code generator.
2025-01-21 02:06:41 +00:00
Sebastian Ullrich
4935829abe feat: generalize infoview.maxTraceChildren to the cmdline (#6716)
This PR renames the option `infoview.maxTraceChildren` to
`maxTraceChildren` and applies it to the cmdline driver and language
server clients lacking an info view as well. It also implements the
common idiom of the option value `0` meaning "unlimited".
2025-01-21 02:06:24 +00:00
Leonardo de Moura
778333c667 fix: match equality generation (#6719)
This PR fixes a bug in the equational theorem generator for
`match`-expressions. See new test for an example.

Signed-off-by: Leonardo de Moura <leodemoura@amazon.com>
Co-authored-by: Leonardo de Moura <leodemoura@amazon.com>
2025-01-21 02:05:37 +00:00
Leonardo de Moura
189f5d41fb feat: case splitting in grind (#6717)
This PR introduces a new feature that allows users to specify which
inductive datatypes the `grind` tactic should perform case splits on.
The configuration option `splitIndPred` is now set to `false` by
default. The attribute `[grind cases]` is used to mark inductive
datatypes and predicates that `grind` may case split on during the
search. Additionally, the attribute `[grind cases eager]` can be used to
mark datatypes and predicates for case splitting both during
pre-processing and the search.

Users can also write `grind [HasType]` or `grind [cases HasType]` to
instruct `grind` to perform case splitting on the inductive predicate
`HasType` in a specific instance. Similarly, `grind [-Or]` can be used
to instruct `grind` not to case split on disjunctions.

Co-authored-by: Leonardo de Moura <leodemoura@amazon.com>
2025-01-20 22:44:56 +00:00
Vlad Tsyrklevich
c07f64a621 doc: Fix (and expand) docstrings for bmod/bdiv (#6713)
The current text is missing a negative sign on the bottom of the
interval that `Int.bmod` can return. While I'm here, I added
illustrative example outputs to match docs for tdiv/ediv/fdiv/etc.
2025-01-20 13:03:34 +00:00
Kim Morrison
22117f21e3 feat: align List/Array/Vector.count theorems (#6712)
This PR aligns `List`/`Array`/`Vector` theorems for `countP` and
`count`.
2025-01-20 10:20:16 +00:00
Sofia Rodrigues
1d03cd6a6b fix: negative timestamps and PlainDateTimes before 1970 (#6668)
This PR fixes negative timestamps and `PlainDateTime`s before 1970.
2025-01-20 07:52:13 +00:00
Kim Morrison
ac6a29ee83 feat: complete alignment of {List,Array,Vector}.{mapIdx,mapFinIdx} (#6701)
This PR completes aligning `mapIdx` and `mapFinIdx` across
`List/Array/Vector`.
2025-01-20 04:06:37 +00:00
Kim Morrison
57f0006c9b feat: align {List/Array/Vector}.{foldl, foldr, foldlM, foldrM} lemmas (#6707)
This PR completes aligning lemmas for `List` / `Array` / `Vector` about
`foldl`, `foldr`, and their monadic versions.
2025-01-20 04:05:31 +00:00
Lean stage0 autoupdater
e40e0892c1 chore: update stage0 2025-01-20 03:43:04 +00:00
Leonardo de Moura
1fcdd7ad9a feat: add [grind cases] and [grind cases eager] attributes (#6705)
This PR adds the attributes `[grind cases]` and `[grind cases eager]`
for controlling case splitting in `grind`. They will replace the
`[grind_cases]` and the configuration option `splitIndPred`.

After update stage0, we will push the second part of this PR.
2025-01-20 03:01:40 +00:00
Leonardo de Moura
9b7bd58c14 feat: add [grind ←=] attribute (#6702)
This PR adds support for equality backward reasoning to `grind`. We can
illustrate the new feature with the following example. Suppose we have a
theorem:
```lean
theorem inv_eq {a b : α} (w : a * b = 1) : inv a = b
```
and we want to instantiate the theorem whenever we are tying to prove
`inv t = s` for some terms `t` and `s`
The attribute `[grind ←]` is not applicable in this case because, by
default, `=` is not eligible for E-matching. The new attribute `[grind
←=]` instructs `grind` to use the equality and consider disequalities in
the `grind` proof state as candidates for E-matching.
2025-01-20 01:16:01 +00:00
Leonardo de Moura
a062eea204 feat: beta reduction in grind (#6700)
This PR adds support for beta reduction in the `grind` tactic. `grind`
can now solve goals such as
```lean
example (f : Nat → Nat) : f = (fun x : Nat => x + 5) → f 2 > 5 := by
  grind
```
2025-01-19 21:29:24 +00:00
Sebastian Ullrich
645bdea23c perf: optimize setImportedEntries (#6698)
A small boost before #6691 made `modifyState` more complex, a larger
boost after.
2025-01-19 14:27:18 +00:00
Kim Morrison
35bbb48916 feat: refactor List/Array.mapFinIdx to unbundle the Fin argument (#6697)
This PR changes the arguments of `List/Array.mapFinIdx` from `(f : Fin
as.size → α → β)` to `(f : (i : Nat) → α → (h : i < as.size) → β)`, in
line with the API design elsewhere for `List/Array`.
2025-01-19 10:30:18 +00:00
Kim Morrison
b289b660c7 chore: remove deprecations from 2024-06 (#6696)
This PR removes deprecations in the standard library from June 2024.
2025-01-19 08:46:24 +00:00
Kim Morrison
75c104ce06 feat: align List/Array/Vector.reverse lemmas (#6695)
This PR aligns `List/Array/Vector.reverse` lemmas.
2025-01-19 08:40:06 +00:00
Lean stage0 autoupdater
74bd40d34d chore: update stage0 2025-01-19 03:03:18 +00:00
Leonardo de Moura
4213862b0e chore: remove [grind_norm] attribute (#6692)
This PR removes the `[grind_norm]` attribute. The normalization theorems
used by `grind` are now fixed and cannot be modified by users. We use
normalization theorems to ensure the built-in procedures receive term
wish expected "shapes". We use it for types that have built-in support
in grind. Users could misuse this feature as a simplification rule. For
example, consider the following example:

```lean
def replicate : (n : Nat) → (a : α) → List α
  | 0,   _ => []
  | n+1, a => a :: replicate n a

-- I want `grind` to instantiate the equations theorems for me.
attribute [grind] replicate

-- I want it to use the equation theorems as simplication rules too.
attribute [grind_norm] replicate

/--
info: [grind.assert] n = 0
[grind.assert] ¬replicate n xs = []
[grind.ematch.instance] replicate.eq_1: replicate 0 xs = []
[grind.assert] True
-/
set_option trace.grind.ematch.instance true in
set_option trace.grind.assert true in
example (xs : List α) : n = 0 → replicate n xs = [] := by
  grind -- fails :(
```

In this example, `grind` starts by asserting the two propositions as
expected: `n = 0`, and `¬replicate n xs = []`. The normalizer cannot
reduce `replicate n xs` as expected.
Then, the E-matching module finds the instance `replicate 0 xs = []` for
the equation theorem `replicate.eq_1` also as expected. But, then the
normalizer kicks in and reduces the new instance to `True`. By removing
`[grind_norm]` we elimninate this kind of misuse. Users that want to
preprocess a formula before invoking `grind` should use `simp` instead.
2025-01-19 02:12:01 +00:00
Sebastian Ullrich
4d8bc22228 feat: Environment.addConstAsync (#6691)
This PR introduces the central API for making parallel changes to the
environment
2025-01-19 02:00:16 +00:00
Lean stage0 autoupdater
7ee938290b chore: update stage0 2025-01-19 01:04:01 +00:00
Leonardo de Moura
478d42105f feat: init_grind_norm elaborator (#6690)
Motivation: we will remove the `[grind_norm]` attribute.
2025-01-19 00:15:13 +00:00
Kim Morrison
5998ba545b feat: regression tests for grind adapted from lean-egg (#6688)
Adapts, with permission, unit tests from `lean-egg` written by Marcus
Rossel as regression tests for `grind`.
2025-01-18 23:46:55 +00:00
Sebastian Ullrich
8a8417f6e1 refactor: getUnfoldableConst*? (#5997)
Continuation from #5429: eliminates uses of these two functions that
care about something other than reducible defs/theorems, then restricts
the function definition to these cases to be more true to its name.
2025-01-18 23:30:40 +00:00
Lean stage0 autoupdater
26941793ff chore: update stage0 2025-01-18 23:46:01 +00:00
Leonardo de Moura
70050c3798 chore: init_grind_norm command parser (#6689) 2025-01-18 23:07:54 +00:00
Sebastian Ullrich
50a0a97b49 refactor: move registration of namespaces on kernel add into elaborator (#6214)
Kernel checking will be moved to a different thread but namespace
registration should stay on the elaboration thread
2025-01-18 23:01:29 +00:00
Lean stage0 autoupdater
5fb2e892c8 chore: update stage0 2025-01-18 19:28:20 +00:00
Sebastian Ullrich
3770808b58 feat: split Lean.Kernel.Environment from Lean.Environment (#5145)
This PR splits the environment used by the kernel from that used by the
elaborator, providing the foundation for tracking of asynchronously
elaborated declarations, which will exist as a concept only in the
latter.

Minor changes:
* kernel diagnostics are moved from an environment extension to a direct
environment as they are the only extension used directly by the kernel
* `initQuot` is moved from an environment header field to a direct
environment as it is the only header field used by the kernel; this also
makes the remaining header immutable after import
2025-01-18 18:42:57 +00:00
Andrés Goens
5e63dd292f chore: fix typo in docstring of mkMVar (#6687)
This PR fixes a very small typo in the docstring of `mkMVar` that
misspelled the function it recommends to use instead.
2025-01-18 12:28:33 +00:00
Kitamado
98e3d6f663 fix: make #check_failure's output be info (#6685)
This PR fixes the issue that `#check_failure`'s output is warning

Closes #6684
2025-01-18 07:27:44 +00:00
Leonardo de Moura
d4070d4bfb fix: grind parameter issues and configuration (#6686)
This PR fixes parameter processing, initialization, and attribute
handling issues in the `grind` tactic.
2025-01-18 03:15:59 +00:00
Leonardo de Moura
4d4c0941be feat: extensionality theorems in grind (#6682)
This PR adds support for extensionality theorems (using the `[ext]`
attribute) to the `grind` tactic. Users can disable this functionality
using `grind -ext` . Below are examples that demonstrate problems now
solvable by `grind`.

```lean
open List in
example : (replicate n a).map f = replicate n (f a) := by
  grind only [Option.map_some', Option.map_none', getElem?_map, getElem?_replicate]
```

```lean
@[ext] structure S where
  a : Nat
  b : Bool

example (x y : S) : x.a = y.a → y.b = x.b → x = y := by
  grind
```
2025-01-17 23:59:36 +00:00
Leonardo de Moura
9b629cc81f chore: update stage0
Manual update stage0 is required to get the test suite green.
2025-01-17 12:31:14 -08:00
Leonardo de Moura
f374ef154e refactor: move ext environment extension to Lean.Meta.Tactic 2025-01-17 12:31:14 -08:00
Lean stage0 autoupdater
e3fd954318 chore: update stage0 2025-01-17 04:30:58 +00:00
Cameron Zwarich
b7815b5684 feat: add lcAny constant to Prelude (#6665)
This PR adds a new lcAny constant to Prelude, which is meant for use in
LCNF to represent types whose dependency on another term has been erased
during compilation. This is in addition to the existing lcErased
constant, which represents types that are irrelevant.
2025-01-17 01:33:35 +00:00
Cameron Zwarich
7f0ae22e43 fix: don't filter out local instances in LCNF toMono pass (#6664)
This PR changes the toMono pass to longer filter out type class
instances, because they may actually be needed for later compilation.
2025-01-17 01:32:49 +00:00
Leonardo de Moura
35a4da28ac feat: add simp-like parameters to grind (#6675)
This PR adds `simp`-like parameters to `grind`, and `grind only` similar
to `simp only`.
2025-01-17 01:08:45 +00:00
Henrik Böving
60142c967c chore: remove unneeded instance (#6671)
This PR removes an `Inhabited` instance from the imported LRAT checker
code that is unneeded but also potentially triggers for each `Inhabited`
query.
2025-01-16 18:32:37 +00:00
Leonardo de Moura
17c0187252 fix: add workaround for MessageData limitations (#6669)
This PR adds a workaround for the discrepancy between Terminal/Emacs and
VS Code when displaying info trees.
2025-01-16 16:58:20 +00:00
Leonardo de Moura
e42f7d9fc3 feat: equality resolution for grind (#6663)
This PR implements a basic equality resolution procedure for the `grind`
tactic.
2025-01-16 16:33:11 +00:00
Luisa Cicolini
906aa1be4b feat: add Nat.[shiftLeft_or_distrib, shiftLeft_xor_distrib, shiftLeft_and_distrib, testBit_mul_two_pow, bitwise_mul_two_pow, shiftLeft_bitwise_distrib] (#6630)
This PR adds theorems `Nat.[shiftLeft_or_distrib`,
shiftLeft_xor_distrib`, shiftLeft_and_distrib`, `testBit_mul_two_pow`,
`bitwise_mul_two_pow`, `shiftLeft_bitwise_distrib]`, to prove
`Nat.shiftLeft_or_distrib` by emulating the proof strategy of
`shiftRight_and_distrib`.

In particular, `Nat.shiftLeft_or_distrib` is necessary to simplify the
proofs in #6476.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
2025-01-16 10:59:00 +00:00
Kim Morrison
f01527142e feat: align List.replicate/Array.mkArray/Vector.mkVector lemmas (#6667)
This PR aligns `List.replicate`/`Array.mkArray`/`Vector.mkVector`
lemmas.
2025-01-16 09:48:01 +00:00
Kim Morrison
f4c9934171 feat: Vector.getElem_flatMap (#6661)
This PR adds array indexing lemmas for `Vector.flatMap`. (These were not
available for `List` and `Array` due to variable lengths.)
2025-01-16 06:33:54 +00:00
Kim Morrison
80ddbf45eb feat: align List/Array/Vector.flatMap (#6660)
This PR defines `Vector.flatMap`, changes the order of arguments in
`List.flatMap` for consistency, and aligns the lemmas for
`List`/`Array`/`Vector` `flatMap`.
2025-01-16 05:19:28 +00:00
Leonardo de Moura
3a6c5cf4f1 feat: canonicalizer diagnostics (#6662)
This PR improves the canonicalizer used in the `grind` tactic and the
diagnostics it produces. It also adds a new configuration option,
`canonHeartbeats`, to address (some of) the issues. Here is an example
illustrating the new diagnostics, where we intentionally create a
problem by using a very small number of heartbeats.

<img width="1173" alt="image"
src="https://github.com/user-attachments/assets/484005c8-dcaa-4164-8fbf-617864ed7350"
/>
2025-01-16 04:59:18 +00:00
Leonardo de Moura
af4a7d7e98 fix: grind term preprocessor (#6659)
This PR fixes a bug in the `grind` term preprocessor. It was abstracting
nested proofs **before** reducible constants were unfolded.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2025-01-16 01:22:06 +00:00
Leonardo de Moura
6259b4742c feat: improve case-split heuristic used in grind (#6658)
This PR ensures that `grind` avoids case-splitting on terms congruent to
those that have already been case-split.
2025-01-16 00:17:27 +00:00
Mac Malone
0050e9369c refactor: lake: use StateRefT for BuildStore (#6290)
This PR uses `StateRefT` instead of `StateT` to equip the Lake build
monad with a build store.

As a IO reference, different threads may now contend with the build
store. However, benchmark results indicate that this does not have a
significant performance impact. On a synchronization front, the lack of
a mutex should not be a concern because the build store is a
memorization data structure and thus order is theoretically irrelevant.
2025-01-15 23:42:32 +00:00
Leonardo de Moura
64cf5e5e6a feat: improve grind search procedure (#6657)
This PR improves the `grind` search procedure, and adds the new
configuration option: `failures`.
2025-01-15 23:08:41 +00:00
Kim Morrison
127b3f9191 feat: more grind tests (#6650)
This PR adds some tests for `grind`, working on `List` lemmas.
2025-01-15 23:00:23 +00:00
Leonardo de Moura
65175dc7d4 feat: improvegrind diagnostic information (#6656)
This PR improves the diagnostic information provided in `grind` failure
states. We now include the list of issues found during the search, and
all search thresholds that have been reached. This PR also improves its
formatting.
2025-01-15 20:57:28 +00:00
Leonardo de Moura
54f06ccd64 feat: better support for partial applications in the E-matching procedure (#6654)
This PR improves the support for partial applications in the E-matching
procedure used in `grind`.
2025-01-15 18:31:34 +00:00
Leonardo de Moura
b3f8feffd3 fix: improve E-matching pattern selection heuristics (#6653)
This PR improves the E-matching pattern selection heuristics in the
`grind` tactic. They now take into account type predicates and
transformers.
2025-01-15 16:43:59 +00:00
Lukas Gerlach
6665837232 feat: verify insertMany method for adding lists to HashMaps (#6211)
This PR verifies the `insertMany` method on `HashMap`s for the special
case of inserting lists.

---------

Co-authored-by: jt0202 <johannes.tantow@gmail.com>
Co-authored-by: monsterkrampe <monsterkrampe@users.noreply.github.com>
Co-authored-by: Johannes Tantow <44068763+jt0202@users.noreply.github.com>
2025-01-15 14:57:26 +00:00
Henrik Böving
c7fd873333 feat: tag lemmas 2025-01-15 15:17:36 +01:00
Henrik Böving
a10ce9492f chore: update stage0 2025-01-15 15:17:36 +01:00
Henrik Böving
838ad281f2 feat: add the int_toBitVec simpset 2025-01-15 15:17:36 +01:00
Henrik Böving
a1ef26bd8b perf: improve bv_decide preprocessing based on Bitwuzla optimisations (#6641)
This PR implements several optimisation tricks from Bitwuzla's
preprocessing passes into the Lean equivalent in `bv_decide`. Note that
these changes are mostly geared towards large proof states as for
example seen in SMT-Lib.
2025-01-15 12:09:43 +00:00
Leonardo de Moura
a955708b6c fix: grind canonicalizer state management (#6649)
This PR fixes a bug in the term canonicalizer used in the `grind`
tactic.
2025-01-15 05:51:54 +00:00
Kim Morrison
0f7f80aff5 fix: indicate dependency on pkgconf in ubuntu docs (#6646)
This PR changes the ubuntu docs to indicate that Lean now requires
pkgconf to build.

This is a companion to #6643, but I can't push directly to that branch.
2025-01-15 05:30:20 +00:00
Leonardo de Moura
8d69909b18 feat: literals, lower and upper bounds in the offset constraint module within grind (#6648)
This PR adds support for numerals, lower & upper bounds to the offset
constraint module in the `grind` tactic. `grind` can now solve examples
such as:
```
example (f : Nat → Nat) :
        f 2 = a →
        b ≤ 1 → b ≥ 1 →
        c = b + 1 →
        f c = a := by
  grind
```
In the example above, the literal `2` and the lower&upper bounds, `b ≤
1` and `b ≥ 1`, are now processed by offset constraint module.
2025-01-15 02:53:31 +00:00
Kim Morrison
f95d8108f4 chore: fib_correct monadic reasoning example as a test (#6647)
This PR records the `fib_impl n = fib_spec n` example, and a proof using
current technologies, as a test.

I'd like to think about eliminating `MProd` from the terms produced by
`do` notation; it seems (at least) a simproc would be required.
2025-01-15 01:58:15 +00:00
Kim Morrison
5d6bf75795 feat: align List/Array/Vector flatten lemmas (#6640)
This PR completes aligning `List`/`Array`/`Vector` lemmas about
`flatten`. `Vector.flatten` was previously missing, and has been added
(for rectangular sizes only). A small number of missing `Option` lemmas
were also need to get the proofs to go through.
2025-01-15 01:16:19 +00:00
Leonardo de Moura
563d5e8bcf feat: offset equalities in grind (#6645)
This PR implements support for offset equality constraints in the
`grind` tactic and exhaustive equality propagation for them. The `grind`
tactic can now solve problems such as the following:

```lean
example (f : Nat → Nat) (a b c d e : Nat) :
        f (a + 3) = b →
        f (c + 1) = d →
        c ≤ a + 2 →
        a + 1 ≤ e →
        e < c →
        b = d := by
  grind
```
2025-01-14 23:45:46 +00:00
Cameron Zwarich
3da7f70014 fix: indicate dependency on pkgconf in macOS docs (#6643)
This PR changes the macOS docs to indicate that Lean now requires
pkgconf to build.
2025-01-14 23:40:26 +00:00
Cameron Zwarich
8e5a3e416b chore: remove duplicate branch in LCNF.toMonoType (#6644) 2025-01-14 23:32:54 +00:00
Henrik Böving
9dbe5e6f9c refactor: bv_normalize simp set and implementation (#6639)
This PR puts the `bv_normalize` simp set into simp_nf and splits up the
bv_normalize implementation across multiple files in preparation for
upcoming changes.
2025-01-14 12:06:01 +00:00
Luisa Cicolini
c12b1d0a55 chore: fix docstring in Bitvec.toNat_add_of_lt (#6638)
This PR correct the docstring of theorem `Bitvec.toNat_add_of_lt`
2025-01-14 10:56:48 +00:00
Kim Morrison
85294b800f chore: update release checklist (#6637)
This PR updates the release checklist script to:
* validate the `releases/v4.X.0` branch
* check that the release has been tagged
* appears on the releases list
* and has release notes (and if not, prompts to run the script
* and when checking downstream repositories, if something is not tagged
properly, suggests the script to run to push the missing tag.
2025-01-14 10:18:46 +00:00
Paul Reichert
821c9b7af9 feat: faster, linear HashMap.alter and modify (#6573)
This PR replaces the existing implementations of `(D)HashMap.alter` and
`(D)HashMap.modify` with primitive, more efficient ones and in
particular provides proofs that they yield well-formed hash maps (`WF`
typeclass).

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-01-14 07:47:58 +00:00
Henrik Böving
e9bd9807ef fix: Windows stage0 linking (#6622)
This PR fixes stage0 linking on Windows against winsock.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2025-01-14 09:09:50 +01:00
Leonardo de Moura
05aa256c99 feat: model construction for offset constraints (#6636)
This PR implements model construction for offset constraints in the
`grind` tactic.
2025-01-14 03:28:58 +00:00
Leonardo de Moura
d6f0c324c3 chore: display E-matching theorems in goalToMessageData (#6635)
This PR includes the activated E-matching theorems and their patterns in
`goalToMessageData`
2025-01-14 02:25:30 +00:00
Leonardo de Moura
f57745e9d4 feat: improve grind failure message (#6633)
This PR improves the failure message produced by the `grind` tactic. We
now include information about asserted facts, propositions that are
known to be true and false, and equivalence classes.
2025-01-14 01:10:47 +00:00
Mac Malone
749a82a8ce fix: lake: set MACOSX_DEPLOYMENT_TARGET for shared libs (#6631)
This PR sets `MACOSX_DEPLOYMENT_TARGET` for shared libraries (it was
previously only set for executables).
2025-01-13 21:18:09 +00:00
Cameron Zwarich
85560da3e4 chore: remove functions for compiling decls from Environment (#6600)
This PR removes functions from compiling decls from Environment, and
moves all users to functions on CoreM. This is required for supporting
the new code generator, since its implementation uses CoreM.
2025-01-13 18:51:06 +00:00
Henrik Böving
e6a643770f feat: implement basic async IO with timers (#6505)
This PR implements a basic async framework as well as asynchronously
running timers using libuv.

---------

Co-authored-by: Sofia Rodrigues <sofia@algebraic.dev>
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
Co-authored-by: Markus Himmel <markus@lean-fro.org>
2025-01-13 18:11:04 +00:00
Mac Malone
30ba383744 feat: lean --src-deps (#6427)
This PR adds the Lean CLI option `--src-deps` which parallels `--deps`.
It parses the Lean code's header and prints out the paths to the
(transitively) imported modules' source files (deduced from
`LEAN_SRC_PATH`).
2025-01-13 16:00:19 +00:00
Henrik Böving
734fca7b6a feat: UIntX.toBitVec lemmas (#6625)
This PR adds lemmas describing the behavior of `UIntX.toBitVec` on
`UIntX` operations.

I did not define them for the `IntX` half yet as that lemma file is non
existent so far and we can start working on `UIntX` in `bv_decide` with
this, then add `IntX` when we grow the `IntX` API.
2025-01-13 14:33:38 +00:00
Mac Malone
a6eea4b650 fix: lake: v4.16.0-rc1 trace issues (#6627)
This PR aims to fix the trace issues reported by Mathlib that are
breaking `lake exe cache` in downstream projects.
2025-01-13 14:16:07 +00:00
Sofia Rodrigues
8483ac7258 fix: adjustments to the datetime library (#6431)
This PR fixes the `Repr` instance of the `Timestamp` type and changes
the `PlainTime` type so that it always represents a clock time that may
be a leap second.

- Fix timestamp `Repr`.
- The `PlainTime` type now always represents a clock time that may be a
leap second.
- Changed `readlink -f` to `IO.FS.realPath`

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
2025-01-13 11:02:30 +00:00
Sebastian Ullrich
5f41cc71ff fix: trace indentation in info view (#6597)
This PR fixes the indentation of nested traces nodes in the info view.


![image](https://github.com/user-attachments/assets/c13ac2a2-e994-4900-9201-0d86889f6a1b)

Fixes #6389
2025-01-13 10:36:01 +00:00
Leonardo de Moura
2421f7f799 feat: exhaustive offset constraint propagation in the grind tactic (#6618)
This PR implements exhaustive offset constraint propagation in the
`grind` tactic. This enhancement minimizes the number of case splits
performed by `grind`. For instance, it can solve the following example
without performing any case splits:

```lean
example (p q r s : Prop) (a b : Nat) : (a + 1 ≤ c ↔ p) → (a + 2 ≤ c ↔ s) → (a ≤ c ↔ q) → (a ≤ c + 4 ↔ r) → a ≤ b → b + 2 ≤ c → p ∧ q ∧ r ∧ s := by
  grind (splits := 0)
```

TODO: support for equational offset constraints.
2025-01-13 04:38:14 +00:00
Kim Morrison
40efbb9b7a doc: commit conventions and Mathlib CI (#6605)
This PR updates the commit conventions documentation to describe the new
changelog conventions, and adds brief documentation of integrated
Mathlib CI, with a link for further explanation.
2025-01-13 02:29:46 +00:00
Kim Morrison
603108e34c feat: finish alignment of List/Array/Vector.append lemmas (#6617)
This PR completes alignment of `List`/`Array`/`Vector` `append` lemmas.
2025-01-13 02:00:49 +00:00
Leonardo de Moura
aa95a1c03f chore: cleaunp grind tests (#6616)
Tests using `logInfo` were taking an additional two seconds on my
machine. This is a performance issue with the old code generator, where
we spend all this time specializing the logging functions for `GoalM`. I
have not checked whether the new code generator is also affected by this
performance issue.

Here is a small example that exposes the issue:
```lean
import Lean

set_option profiler true
open Lean Meta Grind in
def test (e : Expr): GoalM Unit := do
  logInfo e
```

cc @zwarich
2025-01-13 00:07:48 +00:00
Leonardo de Moura
af8f3d1ec1 feat: avoid some redundant proof terms in grind (#6615)
This PR adds two auxiliary functions `mkEqTrueCore` and `mkOfEqTrueCore`
that avoid redundant proof terms in proofs produced by `grind`.
2025-01-12 23:09:39 +00:00
Leonardo de Moura
c7939cfb03 feat: offset constraints support for the grind tactic (#6603)
This PR implements support for offset constraints in the `grind` tactic.
Several features are still missing, such as constraint propagation and
support for offset equalities, but `grind` can already solve examples
like the following:

```lean
example (a b c : Nat) : a ≤ b → b + 2 ≤ c → a + 1 ≤ c := by
  grind
example (a b c : Nat) : a ≤ b → b ≤ c → a ≤ c := by
  grind
example (a b c : Nat) : a + 1 ≤ b → b + 1 ≤ c → a + 2 ≤ c := by
  grind
example (a b c : Nat) : a + 1 ≤ b → b + 1 ≤ c → a + 1 ≤ c := by
  grind
example (a b c : Nat) : a + 1 ≤ b → b ≤ c + 2 → a ≤ c + 1 := by
  grind
example (a b c : Nat) : a + 2 ≤ b → b ≤ c + 2 → a ≤ c := by
  grind
```

---------

Co-authored-by: Kim Morrison <scott.morrison@gmail.com>
2025-01-12 20:38:39 +00:00
Parth Shastri
0da3624ec9 fix: allow dot idents to resolve to local names (#6602)
This PR allows the dot ident notation to resolve to the current
definition, or to any of the other definitions in the same mutual block.
Existing code that uses dot ident notation may need to have `nonrec`
added if the ident has the same name as the definition.

Closes #6601
2025-01-12 17:18:22 +00:00
Leonardo de Moura
349da6cae2 feat: improve [grind =] attribute (#6614)
This PR improves the usability of the `[grind =]` attribute by
automatically handling
forbidden pattern symbols. For example, consider the following theorem
tagged with this attribute:
```
getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔ ∃ ys, xs = ys ++ [a]
```
Here, the selected pattern is `xs.getLast? = some a`, but `Eq` is a
forbidden pattern symbol.
Instead of producing an error, this function converts the pattern into a
multi-pattern,
allowing the attribute to be used conveniently.
2025-01-12 16:51:09 +00:00
Leonardo de Moura
541902564b feat: improve case split heuristic used in grind (#6613)
This PR improves the case split heuristic used in the `grind` tactic,
ensuring it now avoids unnecessary case-splits on `Iff`.
2025-01-12 15:40:36 +00:00
Kim Morrison
8b1aabbb1e feat: lemmas about Array.append (#6612)
This PR adds lemmas about `Array.append`, improving alignment with the
`List` API.
2025-01-12 10:19:50 +00:00
Leonardo de Moura
ce1ff03af0 fix: checkParents in grind (#6611)
This PR fixes one of the sanity check tests used in `grind`.
2025-01-12 05:30:41 +00:00
Leonardo de Moura
c5c1278315 fix: bug in the grind propagator (#6610)
This PR fixes a bug in the `grind` core module responsible for merging
equivalence classes and propagating constraints.
2025-01-12 05:14:41 +00:00
Leonardo de Moura
5119528d20 feat: improve case-split heuristic used in grind (#6609)
This PR improves the case-split heuristic used in grind, prioritizing
case-splits with fewer cases.
2025-01-12 04:21:04 +00:00
Leonardo de Moura
4636091571 fix: simp_arith (#6608)
This PR fixes a bug in the `simp_arith` tactic. See new test.
2025-01-12 03:27:13 +00:00
Leonardo de Moura
7ea5504af2 feat: add support for splitting on <-> to grind (#6607)
This PR adds support for case-splitting on `<->` (and `@Eq Prop`) in the
`grind` tactic.
2025-01-12 02:25:02 +00:00
Leonardo de Moura
acad587938 fix: pattern selection for local lemmas (#6606)
This PR fixes a bug in the pattern selection in the `grind`.
2025-01-12 01:29:32 +00:00
Kim Morrison
8791a9ce06 chore: add lean4-cli to release checklist (#6596)
Users have requested toolchain tags on `lean4-cli`, so let's add it to
the release checklist to make sure these get added regularly.

Previously, `lean4-cli` has used more complicated tags, but going
forward we're going to just use the simple `v4.16.0` style tags, with no
repository-specific versioning.

---------

Co-authored-by: Markus Himmel <markus@lean-fro.org>
2025-01-11 00:32:43 +00:00
David Thrane Christiansen
03081a5b6f doc: update FFI description for Int and signed fixed-width ints (#6599)
The FFI description didn't mention Int or signed integers.

This PR adds `Int` and signed integers to the FFI document.
2025-01-11 00:11:20 +00:00
Alex Keizer
918924c16b feat: BitVec.{toFin, toInt, msb}_umod (#6404)
This PR adds a `toFin` and `msb` lemma for unsigned bitvector modulus.
Similar to #6402, we don't provide a general `toInt_umod` lemmas, but
instead choose to provide more specialized rewrites, with extra
side-conditions.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2025-01-10 23:23:58 +00:00
Lean stage0 autoupdater
58cd01154b chore: update stage0 2025-01-10 16:42:03 +00:00
Harun Khan
0b5d97725c feat: BitVec.toNat theorems for rotateLeft and rotateRight (#6347)
This PR adds `BitVec.toNat_rotateLeft` and `BitVec.toNat_rotateLeft`.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2025-01-10 11:03:58 +00:00
Sofia Rodrigues
ed309dc2a4 feat: add decidable instances for comparison operation of time offset types (#6587)
This PR adds decidable instances for the `LE` and `LT` instances for the
`Offset` types defined in `Std.Time`.
2025-01-10 07:34:46 +00:00
Alex Keizer
d2c4471cfa feat: BitVec.{toInt, toFin, msb}_udiv (#6402)
This PR adds a `toFin` and `msb` lemma for unsigned bitvector division.
We *don't* have `toInt_udiv`, since the only truly general statement we
can make does no better than unfolding the definition, and it's not
uncontroversially clear how to unfold `toInt` (see
`toInt_eq_msb_cond`/`toInt_eq_toNat_cond`/`toInt_eq_toNat_bmod` for a
few options currently provided). Instead, we do have `toInt_udiv_of_msb`
that's able to provide a more meaningful rewrite given an extra
side-condition (that `x.msb = false`).

This PR also upstreams a minor `Nat` theorem (`Nat.div_le_div_left`)
needed for the above from Mathlib.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2025-01-10 02:31:16 +00:00
jrr6
c07948a168 feat: add simp? and dsimp? in conversion mode (#6593)
This PR adds support for the `simp?` and `dsimp?` tactics in conversion
mode.

Closes #6164
2025-01-10 01:42:17 +00:00
Leonardo de Moura
d369976474 feat: improve inequality offset support theorems for grind (#6595)
This PR improves the theorems used to justify the steps performed by the
inequality offset module. See new test for examples of how they are
going to be used.
2025-01-09 20:43:30 +00:00
Henrik Böving
a6789a73ff feat: Std.Net.Addr (#6563)
This PR implements `Std.Net.Addr` which contains structures around IP
and socket addresses.

While we could implement our own parser instead of going through the
`addr_in`/`addr_in6` route we will need to implement these conversions
to make proper system calls anyway. Hence this is likely the approach
with the least amount of non trivial code overall. The only thing I am
uncertain about is whether `ofString` should return `Option` or
`Except`, unfortunately `libuv` doesn't hand out error messages on IP
parsing.
2025-01-09 09:33:03 +00:00
David Thrane Christiansen
1b4272821d feat: add UInt32.{lt, le} (#6591)
This PR adds less-than and less-than-or-equal-to relations to `UInt32`,
consistent with the other `UIntN` types.
2025-01-09 07:01:35 +00:00
Leonardo de Moura
dd6445515d feat: improve grind canonicalizer diagnostics (#6588)
This PR improves the `grind` canonicalizer diagnostics.

---------

Co-authored-by: Kim Morrison <scott.morrison@gmail.com>
2025-01-09 06:21:42 +00:00
Kim Morrison
827c6676fd feat: align List/Array lemmas for filter/filterMap (#6589)
This PR continues aligning `List/Array` lemmas, finishing `filter` and
`filterMap`.
2025-01-09 04:15:47 +00:00
Kim Morrison
623dec1047 feat: aligning List/Array/Vector lemmas for map (#6586)
This PR continues aligning `List/Array/Vector` lemmas, finishing up
lemmas about `map`.
2025-01-09 02:27:20 +00:00
Leonardo de Moura
cb9f198f01 fix: grind canonicalizer (#6585)
This PR fixes a bug in the `grind` canonicalizer.
2025-01-09 02:23:46 +00:00
Leonardo de Moura
c5314da28e feat: add helper theorems for handling offsets in grind (#6584)
This PR adds helper theorems to implement offset constraints in grind.
2025-01-09 01:32:49 +00:00
Leonardo de Moura
0afa1d1e5d feat: apply E-matching for local lemmas in grind (#6582)
This PR adds support for creating local E-matching theorems for
universal propositions known to be true. It allows `grind` to
automatically solve examples such as:

```lean
example (b : List α) (p : α → Prop) (h₁ : ∀ a ∈ b, p a) (h₂ : ∃ a ∈ b, ¬p a) : False := by
  grind
```
2025-01-08 21:37:29 +00:00
Leonardo de Moura
ddd454c9c1 feat: add grind configuration options to control case-splitting (#6581)
This PR adds the following configuration options to `Grind.Config`:
`splitIte`, `splitMatch`, and `splitIndPred`.
2025-01-08 20:52:21 +00:00
Leonardo de Moura
5be241cba0 fix: forall propagation in grind (#6578)
This PR fixes and improves the propagator for forall-expressions in the
`grind` tactic.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2025-01-08 18:03:31 +00:00
Sebastian Ullrich
034bc26740 feat: make classical tactic incremental (#6575)
This PR ensures tactics are evaluated incrementally in the body of
`classical`.
2025-01-08 13:04:31 +00:00
Sebastian Ullrich
680ede7a89 fix: set LLVM sysroot consistently (#6574)
This PR actually prevents Lake from accidentally picking up other
toolchains installed on the machine.

Fixes regression introduced in #6176
2025-01-08 12:56:27 +00:00
Henrik Böving
48eb3084a0 perf: speed up JSON serialisation (#6479)
This PR speeds up JSON serialisation by using a lookup table to check
whether a string needs to be escaped.

The approach is based on
https://byroot.github.io/ruby/json/2024/12/15/optimizing-ruby-json-part-1.html.
2025-01-08 12:06:25 +00:00
Sebastian Graf
f01471f620 fix: proper "excess binders" error locations for rintro and intro (#6565)
This PR fixes the location of the error emitted when the `rintro` and
`intro` tactics cannot introduce the requested number of binders.

This patch adds a few `withRef` wrappers to invocations of
`MVarId.intro` to fix error locations. Perhaps `MVarId.intro` should
take a syntax object to set the location itself in the future; however
there are a couple other call sites which would need non-trivial fixup.

Closes  #5659.
2025-01-08 08:36:45 +00:00
Leonardo de Moura
00ef231a6e feat: split on match-expressions in the grind tactic (#6569)
This PR adds support for case splitting on `match`-expressions in
`grind`.
We still need to add support for resolving the antecedents of
`match`-conditional equations.
2025-01-08 03:10:11 +00:00
Tobias Grosser
9040108e2f feat: add BitVec.[toNat|toInt|toFin|getLsbD|getMsbD|getElem|msb]_fill (#6177)
This PR implements `BitVec.*_fill`.

We also add `toInt_allOnes` and `toFin_allOnes` as the former is needed
here. This completes the allOnes API.
2025-01-08 02:57:53 +00:00
Harun Khan
91cbd7c80e feat: BitVec.toInt_shiftLeft theorem (#6346)
This PR completes the toNat/Int/Fin family for `shiftLeft`.
2025-01-08 02:55:50 +00:00
Kyle Miller
18b183f62b feat: let induction take zero alteratives (#6486)
This PR modifies the `induction`/`cases` syntax so that the `with`
clause does not need to be followed by any alternatives. This improves
friendliness of these tactics, since this lets them surface the names of
the missing alternatives:
```lean
example (n : Nat) : True := by
  induction n with
/-            ~~~~
alternative 'zero' has not been provided
alternative 'succ' has not been provided
-/
```

Related to issue #3555
2025-01-08 02:25:21 +00:00
Vlad Tsyrklevich
78ed072ab0 feat: add Int.emod_sub_emod and Int.sub_emod_emod (#6507)
This PR adds the subtraction equivalents for `Int.emod_add_emod` (`(a %
n + b) % n = (a + b) % n`) and `Int.add_emod_emod` (`(a + b % n) % n =
(a + b) % n`). These are marked @[simp] like their addition equivalents.

Discussed on Zulip in

https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Adding.20some.20sub_emod.20lemmas.20to.20DivModLemmas
2025-01-08 02:20:43 +00:00
Leonardo de Moura
22a799524f feat: add support for cast, Eq.rec, Eq.ndrec to grind (#6568)
This PR adds basic support for cast-like operators to the grind tactic.
Example:
```lean
example (α : Type) (β : Type) (a₁ a₂ : α) (b₁ b₂ : β)
        (h₁ : α = β)
        (h₂ : h₁ ▸ a₁ = b₁)
        (h₃ : a₁ = a₂)
        (h₄ : b₁ = b₂)
        : HEq a₂ b₂ := by
  grind
```
2025-01-08 00:21:13 +00:00
Leonardo de Moura
5decd2ce20 feat: trace messages for working and closing goals in the grind tactic (#6567)
This PR adds support for erasing the `[grind]` attribute used to mark
theorems for heuristic instantiation in the `grind` tactic.
2025-01-07 23:27:36 +00:00
Leonardo de Moura
0da5be1ba1 feat: add support for erasing the [grind] attribute (#6566)
This PR adds support for erasing the `[grind]` attribute used to mark
theorems for heuristic instantiation in the `grind` tactic.
2025-01-07 19:35:31 +00:00
Kim Morrison
83098cdaec chore: typos / improvements to grind messages (#6561)
This PR fixes some typos and makes minor improvements to grind
doc-strings and messages.
2025-01-07 14:25:01 +00:00
Sebastian Ullrich
a2a525f5c7 fix: set absolute linker path (#6547)
This PR should prevent Lake from accidentally picking up other linkers
installed on the machine.
2025-01-07 14:06:24 +00:00
Leonardo de Moura
97d07a54a3 feat: basic case-split for grind (#6559)
This PR adds a basic case-splitting strategy for the `grind` tactic. We
still need to add support for user customization.
2025-01-07 01:53:04 +00:00
Kim Morrison
a424029475 feat: Array lemma alignment; fold and map (#6546)
This PR continues aligning `Array` and `Vector` lemmas with `List`,
working on `fold` and `map` operations.
2025-01-06 22:20:09 +00:00
Leonardo de Moura
db3ab39e05 feat: propagate implication in the grind tactic (#6556)
This PR adds propagators for implication to the `grind` tactic. It also
disables the normalization rule: `(p → q) = (¬ p ∨ q)`
2025-01-06 21:31:12 +00:00
Kim Morrison
8dec57987a feat: grind tests for basic category theory (#6543)
This PR adds additional tests for `grind`, demonstrating that we can
automate some manual proofs from Mathlib's basic category theory
library, with less reliance on Mathlib's `@[reassoc]` trick.

In several places I've added bidirectional patterns for equational
lemmas.

I've updated some other files to use the new `@[grind_eq]` attribute
(but left as is all cases where we are inspecting the info messages from
`grind_pattern`).

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2025-01-06 16:29:50 +00:00
Leonardo de Moura
3ca3f848a8 fix: avoid new tokens _=_ and =_ (#6554)
This PR an issue introduced by the `[grind _=_]` attribute.
2025-01-06 16:18:44 +00:00
Bhavik Mehta
2c9641f621 doc: modify aesop usage example of omegaDefault (#6549)
This PR fixes #6548.
2025-01-06 13:13:16 +00:00
Kim Morrison
78ddee9112 feat: release checklist script (#6542)
This PR introduces a script that automates checking whether major
downstream repositories have been updated for a new toolchain release.

Sample output:
```
% ./release_checklist.py v4.16.0-rc1

Repository: Batteries
   On compatible toolchain (>= v4.16.0-rc1)
   Tag v4.16.0-rc1 exists

Repository: lean4checker
   On compatible toolchain (>= v4.16.0-rc1)
   Tag v4.16.0-rc1 exists

Repository: doc-gen4
   On compatible toolchain (>= v4.16.0-rc1)
   Tag v4.16.0-rc1 exists

Repository: Verso
   Not on target toolchain (needs ≥ v4.16.0-rc1, but main is on leanprover/lean4:v4.15.0)

Repository: ProofWidgets4
   On compatible toolchain (>= v4.16.0-rc1)

Repository: Aesop
   On compatible toolchain (>= v4.16.0-rc1)
   Tag v4.16.0-rc1 exists

Repository: import-graph
   On compatible toolchain (>= v4.16.0-rc1)
   Tag v4.16.0-rc1 exists

Repository: plausible
   On compatible toolchain (>= v4.16.0-rc1)
   Tag v4.16.0-rc1 exists

Repository: Mathlib
   On compatible toolchain (>= v4.16.0-rc1)
   Tag v4.16.0-rc1 exists

Repository: REPL
   Not on target toolchain (needs ≥ v4.16.0-rc1, but master is on leanprover/lean4:v4.14.0)
```
2025-01-06 06:37:01 +00:00
Leonardo de Moura
2ed77f3b26 feat: attribute [grind] (#6545)
This PR introduces the parametric attribute `[grind]` for annotating
theorems and definitions. It also replaces `[grind_eq]` with `[grind
=]`. For definitions, `[grind]` is equivalent to `[grind =]`.

The new attribute supports the following variants:

- **`[grind =]`**: Uses the left-hand side of the theorem's conclusion
as the pattern for E-matching.
- **`[grind =_]`**: Uses the right-hand side of the theorem's conclusion
as the pattern for E-matching.
- **`[grind _=_]`**: Creates two patterns. One for the left-hand side
and one for the right-hand side.
- **`[grind →]`**: Searches for (multi-)patterns in the theorem's
antecedents, stopping once a usable multi-pattern is found.
- **`[grind ←]`**: Searches for (multi-)patterns in the theorem's
conclusion, stopping once a usable multi-pattern is found.
- **`[grind]`**: Searches for (multi-)patterns in both the theorem's
conclusion and antecedents. It starts with the conclusion and stops once
a usable multi-pattern is found.

The `grind_pattern` command remains available for cases where these
attributes do not yield the desired result.
2025-01-06 03:05:20 +00:00
Sebastian Ullrich
76f883b999 fix: remove unused -static-libgcc MinGW linker arg (#6535)
This PR avoids a linker warning on Windows.

The argument may have been superfluous ever since the initial
implementation.
2025-01-05 21:57:56 +00:00
Leonardo de Moura
675244de76 feat: [grind_eq] attribute for the grind tactic (#6539)
This PR introduces the `[grind_eq]` attribute, designed to annotate
equational theorems and functions for heuristic instantiations in the
`grind` tactic.
When applied to an equational theorem, the `[grind_eq]` attribute
instructs the `grind` tactic to automatically use the annotated theorem
to instantiate patterns during proof search. If applied to a function,
it marks all equational theorems associated with that function.

```lean
@[grind_eq]
theorem foo_idempotent : foo (foo x) = foo x := ...

@[grind_eq] def f (a : Nat) :=
  match a with
  | 0 => 10
  | x+1 => g (f x)
```

In the example above, the `grind` tactic will add instances of the
theorem `foo_idempotent` to the local context whenever it encounters the
pattern `foo (foo x)`. Similarly, functions annotated with `[grind_eq]`
will propagate this annotation to their associated equational theorems.
2025-01-05 21:38:05 +00:00
Leonardo de Moura
fd091d1dfe feat: pattern normalization in the grind tactic (#6538)
This PR ensures patterns provided by users are normalized. See new test
to understand why this is needed.
2025-01-05 19:35:52 +00:00
Leonardo de Moura
7b29f488df fix: E-matching thresholds in the grind tactic (#6536)
This PR fixes different thresholds for controlling E-matching in the
`grind` tactic.
2025-01-05 17:34:56 +00:00
Leonardo de Moura
fb506b957c fix: allow projections in E-matching patterns (#6534)
This PR ensures that users can utilize projections in E-matching
patterns within the `grind` tactic.
2025-01-05 16:20:54 +00:00
Leonardo de Moura
dc5c8097b5 feat: add term offset support to the grind E-matching modulo (#6533)
This PR adds support to E-matching offset patterns. For example, we want
to be able to E-match the pattern `f (#0 + 1)` with term `f (a + 2)`.
2025-01-05 02:20:17 +00:00
Kim Morrison
9dcbc330fd chore: fix signature of perm_insertIdx (#6532) 2025-01-04 23:43:23 +00:00
Leonardo de Moura
d22233fc7b fix: let_fun support in grind (#6531)
This PR fixes the support for `let_fun` in `grind`.
2025-01-04 22:22:55 +00:00
Leonardo de Moura
a5b1ed906c fix: nondeterministic failure in grind (#6530)
This PR fixes nondeterministic failures in the (WIP) `grind` tactic.
2025-01-04 21:40:32 +00:00
Leonardo de Moura
ad2c16dade feat: add support for let-declarations to grind (#6529)
This PR adds support for `let`-declarations to the (WIP) `grind` tactic.
2025-01-04 19:24:56 +00:00
Leonardo de Moura
37127ead07 fix: missing propagation in grind (#6528)
This PR adds a missing propagation rule to the (WIP) `grind` tactic.
2025-01-04 18:45:55 +00:00
Kitamado
31435e9cd1 doc: fix broken code blocks in RELEASES.md (#6527)
just fix markdown
2025-01-04 08:08:12 +00:00
Kim Morrison
639e6e92a4 chore: cleanup imports in Lean.Lsp (#6523)
This PR splits a definition out of `Lean.Lsp.Basic`, with the effect
that material about JSON is not needed for `Lean.Meta.Sorry` and its
dependencies.
2025-01-04 04:33:24 +00:00
Kim Morrison
9080df3110 chore: import cleanup in Init (#6522)
This PR avoids unnecessarily importing "kitchen sink" files.
2025-01-04 04:13:13 +00:00
Kim Morrison
cdeb958afd chore: add plausible to release checklist (#6525) 2025-01-04 04:08:21 +00:00
Kim Morrison
d2189542b5 chore: upstream some List.Perm lemmas (#6524)
This PR upstreams some remaining `List.Perm` lemmas from Batteries.
2025-01-04 04:04:13 +00:00
Leonardo de Moura
ad593b36d9 feat: add support for match-expressions to grind (#6521)
This PR adds support for activating relevant `match`-equations as
E-matching theorems. It uses the `match`-equation lhs as the pattern.
2025-01-04 02:18:43 +00:00
Kim Morrison
28a7098728 feat: add script for generating release notes (#6519)
This PR adds a script to automatically generate release notes using the
new `changelog-*` labels and "This PR ..." conventions.

Usage:
```
script/release_notes.py v4.X.0
```
where `v4.X.0` is the **previous** release, i.e. the script will process
all commits *since* that tag.
2025-01-04 01:31:02 +00:00
Kim Morrison
d991feddad chore: cherry-pick release notes from releases/v4.15.0 and releases/v4.16.0 (#6520)
These release notes were automatically generated by the script in #6519.
2025-01-04 01:25:33 +00:00
Henrik Böving
58d178e68f fix: cond reflection bug in bv_decide (#6517)
This PR fixes a slight bug that was created in the reflection of `bif`
in `bv_decide`.

Tagged as changelog-no as the code in question isn't in an RC yet.
2025-01-03 19:35:58 +00:00
Leonardo de Moura
7b496bf44b feat: improve cases tactic used in grind (#6516)
This PR enhances the `cases` tactic used in the `grind` tactic and
ensures that it can be applied to arbitrary expressions.
2025-01-03 15:54:55 +00:00
Mitchell Lee
10b2f6b27e feat: bdiv and bmod lemmas (#6494)
This PR proves the basic theorems about the functions `Int.bdiv` and
`Int.bmod`.

For all integers `x` and all natural numbers `m`, we have:
- `Int.bdiv_add_bmod`: `m * bdiv x m + bmod x m = x` (which is stated in
the docstring for docs#Int.bdiv)
- `Int.bmod_add_bdiv`: `bmod x m + m * bdiv x m = x`
- `Int.bdiv_add_bmod'`: `bdiv x m * m + bmod x m = x`
- `Int.bmod_add_bdiv'`: `bmod x m + bdiv x m * m = x`
- `Int.bmod_eq_self_sub_mul_bdiv`: `bmod x m = x - m * bdiv x m`
- `Int.bmod_eq_self_sub_bdiv_mul`: `bmod x m = x - bdiv x m * m`

These theorems are all equivalent to each other by the basic properties
of addition, multiplication, and subtraction of integers.

The names `Int.bdiv_add_bmod`, `Int.bmod_add_bdiv`,
`Int.bdiv_add_bmod'`, and `Int.bmod_add_bdiv'` are meant to parallel the
names of the existing theorems docs#Int.tmod_add_tdiv,
docs#Int.tdiv_add_tmod, docs#Int.tmod_add_tdiv', and
docs#Int.tdiv_add_tmod'.

The names `Int.bmod_eq_self_sub_mul_bdiv` and
`Int.bmod_eq_self_sub_bdiv_mul` follow mathlib's naming conventions.
Note that there is already a theorem called docs#Int.bmod_def, so it
would not have been possible to parallel the name of the existing
theorem docs#Int.tmod_def.

See
https://leanprover.zulipchat.com/#narrow/channel/217875-Is-there-code-for-X.3F/topic/bdiv.20and.20bmod.

Closes #6493.
2025-01-03 09:37:02 +00:00
Leonardo de Moura
19078655bc perf: avoid unnecessary assert/intro pairs in grind (#6514)
This PR enhances the assertion of new facts in `grind` by avoiding the
creation of unnecessary metavariables.
2025-01-03 02:16:08 +00:00
Leonardo de Moura
df9ed20385 feat: ite and dite support in grind (#6513)
This PR adds support for (dependent) if-then-else terms (i.e., `ite` and
`dite` applications) in the `grind` tactic.
2025-01-03 01:05:44 +00:00
Leonardo de Moura
3e2f1faebf feat: add user-defined fallback procedure for the grind tactic (#6512)
This PR introduces support for user-defined fallback code in the `grind`
tactic. The fallback code can be utilized to inspect the state of
failing `grind` subgoals and/or invoke user-defined automation. Users
can now write `grind on_failure <code>`, where `<code>` should have the
type `GoalM Unit`. See the modified tests in this PR for examples.
2025-01-02 23:56:51 +00:00
Leonardo de Moura
9d622270a1 feat: custom congruence rule for equality in grind (#6510)
This PR adds a custom congruence rule for equality in `grind`. The new
rule takes into account that `Eq` is a symmetric relation. In the
future, we will add support for arbitrary symmetric relations. The
current rule is important for propagating disequalities effectively in
`grind`.
2025-01-02 22:08:19 +00:00
Leonardo de Moura
e46b5f39bf fix: congruence closure in the grind tactic (#6509)
This PR fixes a bug in the congruence closure data structure used in the
`grind` tactic. The new test includes an example that previously caused
a panic. A similar panic was also occurring in the test
`grind_nested_proofs.lean`.
2025-01-02 19:08:02 +00:00
Leonardo de Moura
3cba17140f fix: missing case in checkParents (#6508)
This PR fixes a bug in the sanity checkers for the `grind` tactic. See
the new test for an example of a case where it was panicking.
2025-01-02 16:06:52 +00:00
Lean stage0 autoupdater
092449adb8 chore: update stage0 2025-01-02 12:29:37 +00:00
Joachim Breitner
e9f069146c feat: partial_fixpoint: monotonicity tactic (#6506)
This PR adds the `monotonicity` tactic, intended to be used inside the
`partial_fixpoint` feature.

Part of #6355.
2025-01-02 11:07:05 +00:00
Joachim Breitner
7d0c0d4d92 feat: partial_fixpoint: theory (#6477)
This PR adds the necessary domain theory that backs the
`partial_fixpoint` feature.

Part of #6355.
2025-01-02 09:39:18 +00:00
Eric Wieser
9eb173e444 fix: ignore no_index around OfNat.ofNat in norm_cast (#6438)
This PR ensures `norm_cast` doesn't fail to act in the presence of
`no_index` annotations

While leanprover/lean4#2867 exists, it is necessary to put `no_index`
around `OfNat.ofNat` in simp lemmas.
This results in extra `Expr.mdata` nodes, which must be removed before
checking for `ofNat` numerals.
2025-01-02 09:10:27 +00:00
Leonardo de Moura
8d9d81453b feat: grind simple strategy (#6503)
This PR adds a simple strategy to the (WIP) `grind` tactic. It just
keeps internalizing new theorem instances found by E-matching. The
simple strategy can solve examples such as:

```lean
grind_pattern Array.size_set => Array.set a i v h
grind_pattern Array.get_set_eq  => a.set i v h
grind_pattern Array.get_set_ne => (a.set i v hi)[j]

example (as bs : Array α) (v : α)
        (i : Nat)
        (h₁ : i < as.size)
        (h₂ : bs = as.set i v)
        : as.size = bs.size := by
  grind

example (as bs cs : Array α) (v : α)
        (i : Nat)
        (h₁ : i < as.size)
        (h₂ : bs = as.set i v)
        (h₃ : cs = bs)
        (h₄ : i ≠ j)
        (h₅ : j < cs.size)
        (h₆ : j < as.size)
        : cs[j] = as[j] := by
  grind


opaque R : Nat → Nat → Prop
theorem Rtrans (a b c : Nat) : R a b → R b c → R a c := sorry

grind_pattern Rtrans => R a b, R b c

example : R a b → R b c → R c d → R d e → R a d := by
  grind
```
2025-01-02 05:36:01 +00:00
Leonardo de Moura
a08379ce2e fix: proof generation for grind tactic (#6502)
This PR fixes a bug in the proof assembly procedure utilized by the
`grind` tactic.
2025-01-02 04:42:31 +00:00
Leonardo de Moura
f0c59364f4 feat: add PersistentHashSet.toList (#6501)
This PR adds `PersistentHashSet.toList`
2025-01-02 03:52:21 +00:00
Leonardo de Moura
c0d67e2a65 fix: bug in markNestedProofs within grind (#6500)
This PR fixes a bug in the `markNestedProofs` used in `grind`. See new
test.
2025-01-02 02:14:45 +00:00
Leonardo de Moura
a8d09dad1b fix: proof canonicalizer in grind (#6499)
This PR fixes the proof canonicalizer for `grind`.
2025-01-02 01:26:39 +00:00
Leonardo de Moura
f7c4edc2b7 feat: dependent forall propagator in grind (#6498)
This PR adds support in the `grind` tactic for propagating dependent
forall terms `forall (h : p), q[h]` where `p` is a proposition.
2025-01-02 00:08:36 +00:00
Leonardo de Moura
82bae24e59 fix: another bug in theorem instantiation in grind (#6497)
This PR fixes another theorem instantiation bug in the `grind` tactic.
It also moves new instances to be processed to `Goal`.
2025-01-01 23:09:21 +00:00
Leonardo de Moura
fedaf850bb fix: theorem instantiation in grind (#6492)
This PR fixes a bug in the theorem instantiation procedure in the (WIP)
`grind` tactic. For example, it was missing the following instance in
one of the tests:

```lean
[grind.ematch.instance] Array.get_set_ne: ∀ (hj : i < bs.size), j ≠ i → (bs.set j w ⋯)[i] = bs[i]
```

This PR also renames the `grind` base monad to `GrindCoreM`.
2025-01-01 17:56:27 +00:00
Kyle Miller
6d447156c4 fix: make sure parent structure projections have 'go to definition' information (#6487)
This PR adds source position information for `structure` parent
projections, supporting "go to definition". Closes #3063.
2024-12-31 21:59:38 +00:00
Leonardo de Moura
3427630a14 feat: configuration options for the grind tactic (#6490)
This PR adds basic configuration options for the `grind` tactic.
2024-12-31 21:09:41 +00:00
Leonardo de Moura
5ba476116f fix: E-matching module for grind (#6488)
This PR fixes and refactors the E-matching module for the (WIP) `grind`
tactic.

Next step: top-level search procedure for `grind`.
2024-12-31 20:07:27 +00:00
Leonardo de Moura
8899c7ed8c feat: instantiate ematch theorems in grind (#6485)
This PR implements `Grind.EMatch.instantiateTheorem` in the (WIP)
`grind` tactic.
2024-12-31 19:25:12 +00:00
Kyle Miller
640b356a04 chore: add missing diff-exposing in type/value mismatch errors (#6484)
This PR addresses a few error messages where diffs weren't being
exposed.
2024-12-31 17:47:12 +00:00
Kyle Miller
8f5ce3a356 feat: upstream ToExpr deriving handler from Mathlib (#6473)
This PR adds a deriving handler for the `ToExpr` class. It can handle
mutual and nested inductive types, however it falls back to creating
`partial` instances in such cases. This is upstreamed from the Mathlib
deriving handler written by @kmill, but has fixes to handle autoimplicit
universe level variables.

This is a followup to #6285 (adding the `ToLevel` class). This PR
supersedes #5906.

Co-authored-by: Alex Keizer <alex@keizer.dev>

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
2024-12-31 15:11:53 +00:00
Leonardo de Moura
2c87905d77 feat: E-matching procedure for the grind tactic (#6481)
This PR implements E-matching for the (WIP) `grind` tactic. We still
need to finalize and internalize the new instances.
2024-12-31 02:46:09 +00:00
Cameron Zwarich
32dc16590b chore: reduce churn in tests/lean/run/meta5.lean (#6480) 2024-12-31 02:32:56 +00:00
Leonardo de Moura
7e8e22e2bd fix: internalize nested ground patterns when activating ematch theorems (#6478)
This PR internalize nested ground patterns when activating ematch
theorems in the (WIP) `grind` tactic.
2024-12-30 16:13:47 +00:00
Leonardo de Moura
9b28c5879a feat: ematch theorem activation for grind (#6475)
This PR adds support for activating relevant theorems for the (WIP)
`grind` tactic. We say a theorem is relevant to a `grind` goal if the
symbols occurring in its patterns also occur in the goal.
2024-12-30 09:57:33 +00:00
Leonardo de Moura
24a8561ec4 feat: check pattern coverage in the grind_pattern command (#6474)
This PR adds pattern validation to the `grind_pattern` command. The new
`checkCoverage` function will also be used to implement the attributes
`@[grind_eq]`, `@[grind_fwd]`, and `@[grind_bwd]`.
2024-12-30 03:40:43 +00:00
Lean stage0 autoupdater
3c326d771c chore: update stage0 2024-12-29 21:10:53 +00:00
Leonardo de Moura
7433e74fc4 feat: theorem patterns for heuristic instantiation in grind (#6472)
This PR implements the command `grind_pattern`. The new command allows
users to associate patterns with theorems. These patterns are used for
performing heuristic instantiation with e-matching. In the future, we
will add the attributes `@[grind_eq]`, `@[grind_fwd]`, and
`@[grind_bwd]` to compute the patterns automatically for theorems.
2024-12-29 20:26:58 +00:00
Eric Wieser
11eea84fd5 doc: explain app_delab (#6450)
This PR adds a docstring to the `@[app_delab]` attribute.

---------

Co-authored-by: Kyle Miller <kmill31415@gmail.com>
2024-12-29 15:06:55 +00:00
Lean stage0 autoupdater
536c6a8ea6 chore: update stage0 2024-12-29 01:19:00 +00:00
Leonardo de Moura
9c0ef2a282 feat: add grind_pattern command (#6470)
This PR introduces a command for specifying patterns used in the
heuristic instantiation of global theorems in the `grind` tactic. Note
that this PR only adds the parser.
2024-12-29 00:44:40 +00:00
Leonardo de Moura
a781f9858c feat: missing data for grind e-match (#6469)
This PR adds support code for implementing e-match in the (WIP) `grind`
tactic.
2024-12-29 00:33:25 +00:00
2849 changed files with 158192 additions and 33747 deletions

20
.github/workflows/awaiting-mathlib.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Check awaiting-mathlib label
on:
merge_group:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
jobs:
check-awaiting-mathlib:
runs-on: ubuntu-latest
steps:
- name: Check awaiting-mathlib label
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const { labels } = context.payload.pull_request;
if (labels.some(label => label.name == "awaiting-mathlib") && !labels.some(label => label.name == "builds-mathlib")) {
core.setFailed('PR is marked "awaiting-mathlib" but "builds-mathlib" label has not been applied yet by the bot');
}

246
.github/workflows/build-template.yml vendored Normal file
View File

@@ -0,0 +1,246 @@
name: build-template
on:
workflow_call:
inputs:
check-level:
type: string
required: true
config:
type: string
required: true
nightly:
type: string
required: true
LEAN_VERSION_MAJOR:
type: string
required: true
LEAN_VERSION_MINOR:
type: string
required: true
LEAN_VERSION_PATCH:
type: string
required: true
LEAN_SPECIAL_VERSION_DESC:
type: string
required: true
RELEASE_TAG:
type: string
required: true
jobs:
build:
if: github.event_name != 'schedule' || github.repository == 'leanprover/lean4'
strategy:
matrix:
include: ${{fromJson(inputs.config)}}
# complete all jobs
fail-fast: false
runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.shell || 'nix develop -c bash -euxo pipefail {0}' }}
name: ${{ matrix.name }}
env:
# must be inside workspace
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_COMPRESS: true
# current cache limit
CCACHE_MAXSIZE: 200M
# squelch error message about missing nixpkgs channel
NIX_BUILD_SHELL: bash
LSAN_OPTIONS: max_leaks=10
# somehow MinGW clang64 (or cmake?) defaults to `g++` even though it doesn't exist
CXX: c++
MACOSX_DEPLOYMENT_TARGET: 10.15
steps:
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
if: runner.os == 'Linux' && !matrix.cmultilib
- name: Install MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: clang64
# `:` means do not prefix with msystem
pacboy: "make: python: cmake clang ccache gmp libuv git: zip: unzip: diffutils: binutils: tree: zstd tar:"
if: runner.os == 'Windows'
- name: Install Brew Packages
run: |
brew install ccache tree zstd coreutils gmp libuv
if: runner.os == 'macOS'
- name: Checkout
uses: actions/checkout@v4
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}
- name: Open Nix shell once
run: true
if: runner.os == 'Linux'
# Do check out some CI-relevant files from virtual merge commit to accommodate CI changes on
# master (as the workflow files themselves are always taken from the merge)
# (needs to be after "Install *" to use the right shell)
- name: CI Merge Checkout
run: |
git fetch --depth=1 origin ${{ github.sha }}
git checkout FETCH_HEAD flake.nix flake.lock
if: github.event_name == 'pull_request'
# (needs to be after "Checkout" so files don't get overridden)
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v14
with:
version: 3.1.44
actions-cache-folder: emsdk
if: matrix.wasm
- name: Install 32bit c libs
run: |
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib ccache libuv1-dev:i386 pkgconf:i386
if: matrix.cmultilib
- name: Cache
if: matrix.name != 'Linux Lake'
uses: actions/cache@v4
with:
path: |
.ccache
key: ${{ matrix.name }}-build-v3-${{ github.event.pull_request.head.sha }}
# fall back to (latest) previous cache
restore-keys: |
${{ matrix.name }}-build-v3
save-always: true
- name: Cache
if: matrix.name == 'Linux Lake'
uses: actions/cache@v4
with:
path: |
.ccache
build/stage1/**/*.trace
build/stage1/**/*.olean
build/stage1/**/*.ilean
build/stage1/**/*.c
build/stage1/**/*.c.o*
key: ${{ matrix.name }}-build-v3-${{ github.event.pull_request.head.sha }}
# fall back to (latest) previous cache
restore-keys: |
${{ matrix.name }}-build-v3
save-always: true
# open nix-shell once for initial setup
- name: Setup
run: |
ccache --zero-stats
if: runner.os == 'Linux'
- name: Set up NPROC
run: |
echo "NPROC=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)" >> $GITHUB_ENV
- name: Build
run: |
ulimit -c unlimited # coredumps
[ -d build ] || mkdir build
cd build
# arguments passed to `cmake`
# this also enables githash embedding into stage 1 library
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
OPTIONS+=(-DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true)
if [[ -n '${{ matrix.cross_target }}' ]]; then
# used by `prepare-llvm`
export EXTRA_FLAGS=--target=${{ matrix.cross_target }}
OPTIONS+=(-DLEAN_PLATFORM_TARGET=${{ matrix.cross_target }})
fi
if [[ -n '${{ matrix.prepare-llvm }}' ]]; then
wget -q ${{ matrix.llvm-url }}
PREPARE="$(${{ matrix.prepare-llvm }})"
eval "OPTIONS+=($PREPARE)"
fi
if [[ -n '${{ matrix.release }}' && -n '${{ inputs.nightly }}' ]]; then
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ inputs.nightly }})
fi
if [[ -n '${{ matrix.release }}' && -n '${{ inputs.RELEASE_TAG }}' ]]; then
OPTIONS+=(-DLEAN_VERSION_MAJOR=${{ inputs.LEAN_VERSION_MAJOR }})
OPTIONS+=(-DLEAN_VERSION_MINOR=${{ inputs.LEAN_VERSION_MINOR }})
OPTIONS+=(-DLEAN_VERSION_PATCH=${{ inputs.LEAN_VERSION_PATCH }})
OPTIONS+=(-DLEAN_VERSION_IS_RELEASE=1)
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ inputs.LEAN_SPECIAL_VERSION_DESC }})
fi
# contortion to support empty OPTIONS with old macOS bash
cmake .. --preset ${{ matrix.CMAKE_PRESET || 'release' }} -B . ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
time make -j$NPROC
- name: Install
run: |
make -C build install
- name: Check Binaries
run: ${{ matrix.binary-check }} lean-*/bin/* || true
- name: Count binary symbols
run: |
for f in lean-*/bin/*; do
echo "$f: $(nm $f | grep " T " | wc -l) exported symbols"
done
if: matrix.name == 'Windows'
- name: List Install Tree
run: |
# omit contents of Init/, ...
tree --du -h lean-*-* | grep -E ' (Init|Lean|Lake|LICENSE|[a-z])'
- name: Pack
run: |
dir=$(echo lean-*-*)
mkdir pack
# high-compression tar.zst + zip for release, fast tar.zst otherwise
if [[ '${{ startsWith(github.ref, 'refs/tags/') && matrix.release }}' == true || -n '${{ inputs.nightly }}' || -n '${{ inputs.RELEASE_TAG }}' ]]; then
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -19 -o pack/$dir.tar.zst
zip -rq pack/$dir.zip $dir
else
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -o pack/$dir.tar.zst
fi
- uses: actions/upload-artifact@v4
if: matrix.release
with:
name: build-${{ matrix.name }}
path: pack/*
- name: Lean stats
run: |
build/stage1/bin/lean --stats src/Lean.lean
if: ${{ !matrix.cross }}
- name: Test
id: test
run: |
ulimit -c unlimited # coredumps
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
if: (matrix.wasm || !matrix.cross) && inputs.check-level >= 1
- name: Test Summary
uses: test-summary/action@v2
with:
paths: build/stage1/test-results.xml
# prefix `if` above with `always` so it's run even if tests failed
if: always() && steps.test.conclusion != 'skipped'
- name: Check Test Binary
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
if: (!matrix.cross) && steps.test.conclusion != 'skipped'
- name: Build Stage 2
run: |
make -C build -j$NPROC stage2
if: matrix.test-speedcenter
- name: Check Stage 3
run: |
make -C build -j$NPROC check-stage3
if: matrix.test-speedcenter
- name: Test Speedcenter Benchmarks
run: |
# Necessary for some timing metrics but does not work on Namespace runners
# and we just want to test that the benchmarks run at all here
#echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
export BUILD=$PWD/build PATH=$PWD/build/stage1/bin:$PATH
cd tests/bench
nix shell .#temci -c temci exec --config speedcenter.yaml --included_blocks fast --runs 1
if: matrix.test-speedcenter
- name: Check rebootstrap
run: |
# clean rebuild in case of Makefile changes
make -C build update-stage0 && rm -rf build/stage* && make -C build -j$NPROC
if: matrix.name == 'Linux' && inputs.check-level >= 1
- name: CCache stats
run: ccache -s
- name: Show stacktrace for coredumps
if: failure() && runner.os == 'Linux'
run: |
for c in $(find . -name core); do
progbin="$(file $c | sed "s/.*execfn: '\([^']*\)'.*/\1/")"
echo bt | $GDB/bin/gdb -q $progbin $c || true
done

View File

@@ -20,9 +20,7 @@ jobs:
- name: Identify stage0 changes
run: |
git diff "${BASE:-HEAD^}..HEAD" --name-only -- stage0 |
grep -v -x -F $'stage0/src/stdlib_flags.h\nstage0/src/lean.mk.in' \
> "$RUNNER_TEMP/stage0" || true
git diff "${BASE:-HEAD^}..HEAD" --name-only -- stage0/stdlib > "$RUNNER_TEMP/stage0" || true
if test -s "$RUNNER_TEMP/stage0"
then
echo "CHANGES=yes" >> "$GITHUB_ENV"

View File

@@ -36,7 +36,9 @@ jobs:
# 2: PRs with `release-ci` label, releases (incl. nightlies)
check-level: ${{ steps.set-level.outputs.check-level }}
# The build matrix, dynamically generated here
matrix: ${{ steps.set-matrix.outputs.result }}
matrix: ${{ steps.set-matrix.outputs.matrix }}
# secondary build jobs that should not block the CI success/merge queue
matrix-secondary: ${{ steps.set-matrix.outputs.matrix-secondary }}
# Should we make a nightly release? If so, this output contains the lean version string, else it is empty
nightly: ${{ steps.set-nightly.outputs.nightly }}
# Should this be the CI for a tagged release?
@@ -135,9 +137,9 @@ jobs:
console.log(`level: ${level}`);
// use large runners where available (original repo)
let large = ${{ github.repository == 'leanprover/lean4' }};
const isPr = "${{ github.event_name }}" == "pull_request";
let matrix = [
{
// portable release build: use channel with older glibc (2.27)
"name": "Linux LLVM",
"os": "ubuntu-latest",
"release": false,
@@ -152,6 +154,7 @@ jobs:
"CMAKE_OPTIONS": "-DLLVM=ON -DLLVM_CONFIG=${GITHUB_WORKSPACE}/build/llvm-host/bin/llvm-config"
},
{
// portable release build: use channel with older glibc (2.26)
"name": "Linux release",
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
"release": true,
@@ -163,6 +166,14 @@ jobs:
// foreign code may be linked against more recent glibc
"CTEST_OPTIONS": "-E 'foreign'"
},
{
"name": "Linux Lake",
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
// just a secondary PR build job for now
"check-level": isPr ? 0 : 3,
"secondary": true,
"CMAKE_OPTIONS": "-DUSE_LAKE=ON"
},
{
"name": "Linux",
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
@@ -175,8 +186,8 @@ jobs:
"os": "ubuntu-latest",
"check-level": 2,
"CMAKE_PRESET": "debug",
// exclude seriously slow tests
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest|bv_bitblast_stress'"
// exclude seriously slow/stackoverflowing tests
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest|bv_bitblast_stress|3807'"
},
// TODO: suddenly started failing in CI
/*{
@@ -204,12 +215,18 @@ jobs:
"os": "macos-14",
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
"release": true,
"check-level": 0,
"shell": "bash -euxo pipefail {0}",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-apple-darwin.tar.zst",
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
"binary-check": "otool -L",
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
"tar": "gtar", // https://github.com/actions/runner-images/issues/2619
// Special handling for MacOS aarch64, we want:
// 1. To run it in PRs so Mac devs get PR toolchains (so secondary is sufficient)
// 2. To skip it in merge queues as it takes longer than the Linux build and adds
// little value in the merge queue
// 3. To run it in release (obviously)
"check-level": isPr ? 0 : 2,
"secondary": isPr,
},
{
"name": "Windows",
@@ -238,7 +255,7 @@ jobs:
"name": "Linux 32bit",
"os": "ubuntu-latest",
// Use 32bit on stage0 and stage1 to keep oleans compatible
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/",
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DPKG_CONFIG_EXECUTABLE=/usr/bin/i386-linux-gnu-pkg-config",
"cmultilib": true,
"release": true,
"check-level": 2,
@@ -260,196 +277,41 @@ jobs:
// "CTEST_OPTIONS": "-R \"leantest_1007\\.lean|leantest_Format\\.lean|leanruntest\\_1037.lean|leanruntest_ac_rfl\\.lean|leanruntest_tempfile.lean\\.|leanruntest_libuv\\.lean\""
// }
];
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`)
return matrix.filter((job) => level >= job["check-level"])
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`);
matrix = matrix.filter((job) => level >= job["check-level"]);
core.setOutput('matrix', matrix.filter((job) => !job["secondary"]));
core.setOutput('matrix-secondary', matrix.filter((job) => job["secondary"]));
build:
needs: [configure]
if: github.event_name != 'schedule' || github.repository == 'leanprover/lean4'
strategy:
matrix:
include: ${{fromJson(needs.configure.outputs.matrix)}}
# complete all jobs
fail-fast: false
runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.shell || 'nix develop -c bash -euxo pipefail {0}' }}
name: ${{ matrix.name }}
env:
# must be inside workspace
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_COMPRESS: true
# current cache limit
CCACHE_MAXSIZE: 200M
# squelch error message about missing nixpkgs channel
NIX_BUILD_SHELL: bash
LSAN_OPTIONS: max_leaks=10
# somehow MinGW clang64 (or cmake?) defaults to `g++` even though it doesn't exist
CXX: c++
MACOSX_DEPLOYMENT_TARGET: 10.15
steps:
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
if: runner.os == 'Linux' && !matrix.cmultilib
- name: Install MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: clang64
# `:` means do not prefix with msystem
pacboy: "make: python: cmake clang ccache gmp libuv git: zip: unzip: diffutils: binutils: tree: zstd tar:"
if: runner.os == 'Windows'
- name: Install Brew Packages
run: |
brew install ccache tree zstd coreutils gmp libuv
if: runner.os == 'macOS'
- name: Checkout
uses: actions/checkout@v4
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}
# Do check out some CI-relevant files from virtual merge commit to accommodate CI changes on
# master (as the workflow files themselves are always taken from the merge)
# (needs to be after "Install *" to use the right shell)
- name: CI Merge Checkout
run: |
git fetch --depth=1 origin ${{ github.sha }}
git checkout FETCH_HEAD flake.nix flake.lock
if: github.event_name == 'pull_request'
# (needs to be after "Checkout" so files don't get overridden)
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v14
with:
version: 3.1.44
actions-cache-folder: emsdk
if: matrix.wasm
- name: Install 32bit c libs
run: |
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib ccache libuv1-dev:i386
if: matrix.cmultilib
- name: Cache
uses: actions/cache@v4
with:
path: .ccache
key: ${{ matrix.name }}-build-v3-${{ github.event.pull_request.head.sha }}
# fall back to (latest) previous cache
restore-keys: |
${{ matrix.name }}-build-v3
save-always: true
# open nix-shell once for initial setup
- name: Setup
run: |
ccache --zero-stats
if: runner.os == 'Linux'
- name: Set up NPROC
run: |
echo "NPROC=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)" >> $GITHUB_ENV
- name: Build
run: |
mkdir build
cd build
# arguments passed to `cmake`
# this also enables githash embedding into stage 1 library
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
OPTIONS+=(-DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true)
if [[ -n '${{ matrix.cross_target }}' ]]; then
# used by `prepare-llvm`
export EXTRA_FLAGS=--target=${{ matrix.cross_target }}
OPTIONS+=(-DLEAN_PLATFORM_TARGET=${{ matrix.cross_target }})
fi
if [[ -n '${{ matrix.prepare-llvm }}' ]]; then
wget -q ${{ matrix.llvm-url }}
PREPARE="$(${{ matrix.prepare-llvm }})"
eval "OPTIONS+=($PREPARE)"
fi
if [[ -n '${{ matrix.release }}' && -n '${{ needs.configure.outputs.nightly }}' ]]; then
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ needs.configure.outputs.nightly }})
fi
if [[ -n '${{ matrix.release }}' && -n '${{ needs.configure.outputs.RELEASE_TAG }}' ]]; then
OPTIONS+=(-DLEAN_VERSION_MAJOR=${{ needs.configure.outputs.LEAN_VERSION_MAJOR }})
OPTIONS+=(-DLEAN_VERSION_MINOR=${{ needs.configure.outputs.LEAN_VERSION_MINOR }})
OPTIONS+=(-DLEAN_VERSION_PATCH=${{ needs.configure.outputs.LEAN_VERSION_PATCH }})
OPTIONS+=(-DLEAN_VERSION_IS_RELEASE=1)
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ needs.configure.outputs.LEAN_SPECIAL_VERSION_DESC }})
fi
# contortion to support empty OPTIONS with old macOS bash
cmake .. --preset ${{ matrix.CMAKE_PRESET || 'release' }} -B . ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
time make -j$NPROC
- name: Install
run: |
make -C build install
- name: Check Binaries
run: ${{ matrix.binary-check }} lean-*/bin/* || true
- name: Count binary symbols
run: |
for f in lean-*/bin/*; do
echo "$f: $(nm $f | grep " T " | wc -l) exported symbols"
done
if: matrix.name == 'Windows'
- name: List Install Tree
run: |
# omit contents of Init/, ...
tree --du -h lean-*-* | grep -E ' (Init|Lean|Lake|LICENSE|[a-z])'
- name: Pack
run: |
dir=$(echo lean-*-*)
mkdir pack
# high-compression tar.zst + zip for release, fast tar.zst otherwise
if [[ '${{ startsWith(github.ref, 'refs/tags/') && matrix.release }}' == true || -n '${{ needs.configure.outputs.nightly }}' || -n '${{ needs.configure.outputs.RELEASE_TAG }}' ]]; then
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -19 -o pack/$dir.tar.zst
zip -rq pack/$dir.zip $dir
else
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -o pack/$dir.tar.zst
fi
- uses: actions/upload-artifact@v4
if: matrix.release
with:
name: build-${{ matrix.name }}
path: pack/*
- name: Lean stats
run: |
build/stage1/bin/lean --stats src/Lean.lean
if: ${{ !matrix.cross }}
- name: Test
id: test
run: |
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
if: (matrix.wasm || !matrix.cross) && needs.configure.outputs.check-level >= 1
- name: Test Summary
uses: test-summary/action@v2
with:
paths: build/stage1/test-results.xml
# prefix `if` above with `always` so it's run even if tests failed
if: always() && steps.test.conclusion != 'skipped'
- name: Check Test Binary
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
if: (!matrix.cross) && steps.test.conclusion != 'skipped'
- name: Build Stage 2
run: |
make -C build -j$NPROC stage2
if: matrix.test-speedcenter
- name: Check Stage 3
run: |
make -C build -j$NPROC check-stage3
if: matrix.test-speedcenter
- name: Test Speedcenter Benchmarks
run: |
# Necessary for some timing metrics but does not work on Namespace runners
# and we just want to test that the benchmarks run at all here
#echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
export BUILD=$PWD/build PATH=$PWD/build/stage1/bin:$PATH
cd tests/bench
nix shell .#temci -c temci exec --config speedcenter.yaml --included_blocks fast --runs 1
if: matrix.test-speedcenter
- name: Check rebootstrap
run: |
# clean rebuild in case of Makefile changes
make -C build update-stage0 && rm -rf build/stage* && make -C build -j$NPROC
if: matrix.name == 'Linux' && needs.configure.outputs.check-level >= 1
- name: CCache stats
run: ccache -s
needs: [configure]
uses: ./.github/workflows/build-template.yml
with:
config: ${{needs.configure.outputs.matrix}}
check-level: ${{ needs.configure.outputs.check-level }}
nightly: ${{ needs.configure.outputs.nightly }}
LEAN_VERSION_MAJOR: ${{ needs.configure.outputs.LEAN_VERSION_MAJOR }}
LEAN_VERSION_MINOR: ${{ needs.configure.outputs.LEAN_VERSION_MINOR }}
LEAN_VERSION_PATCH: ${{ needs.configure.outputs.LEAN_VERSION_PATCH }}
LEAN_SPECIAL_VERSION_DESC: ${{ needs.configure.outputs.LEAN_SPECIAL_VERSION_DESC }}
RELEASE_TAG: ${{ needs.configure.outputs.RELEASE_TAG }}
secrets: inherit
# build jobs that should not be considered by `all-done` below
build-secondary:
needs: [configure]
if: needs.configure.outputs.matrix-secondary != '[]'
uses: ./.github/workflows/build-template.yml
with:
config: ${{needs.configure.outputs.matrix-secondary}}
check-level: ${{ needs.configure.outputs.check-level }}
nightly: ${{ needs.configure.outputs.nightly }}
LEAN_VERSION_MAJOR: ${{ needs.configure.outputs.LEAN_VERSION_MAJOR }}
LEAN_VERSION_MINOR: ${{ needs.configure.outputs.LEAN_VERSION_MINOR }}
LEAN_VERSION_PATCH: ${{ needs.configure.outputs.LEAN_VERSION_PATCH }}
LEAN_SPECIAL_VERSION_DESC: ${{ needs.configure.outputs.LEAN_SPECIAL_VERSION_DESC }}
RELEASE_TAG: ${{ needs.configure.outputs.RELEASE_TAG }}
secrets: inherit
# This job collects results from all the matrix jobs
# This can be made the "required" job, instead of listing each

View File

@@ -34,7 +34,7 @@ jobs:
- name: Download artifact from the previous workflow.
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
id: download-artifact
uses: dawidd6/action-download-artifact@v7 # https://github.com/marketplace/actions/download-workflow-artifact
uses: dawidd6/action-download-artifact@v9 # https://github.com/marketplace/actions/download-workflow-artifact
with:
run_id: ${{ github.event.workflow_run.id }}
path: artifacts
@@ -155,6 +155,20 @@ jobs:
fi
if [[ -n "$MESSAGE" ]]; then
# Check if force-mathlib-ci label is present
LABELS="$(curl --retry 3 --location --silent \
-H "Authorization: token ${{ secrets.MATHLIB4_COMMENT_BOT }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/labels" \
| jq -r '.[].name')"
if echo "$LABELS" | grep -q "^force-mathlib-ci$"; then
echo "force-mathlib-ci label detected, forcing CI despite issues"
MESSAGE="Forcing Mathlib CI because the \`force-mathlib-ci\` label is present, despite problem: $MESSAGE"
FORCE_CI=true
else
MESSAGE="$MESSAGE You can force Mathlib CI using the \`force-mathlib-ci\` label."
fi
echo "Checking existing messages"
@@ -201,7 +215,12 @@ jobs:
else
echo "The message already exists in the comment body."
fi
echo "mathlib_ready=false" >> "$GITHUB_OUTPUT"
if [[ "$FORCE_CI" == "true" ]]; then
echo "mathlib_ready=true" >> "$GITHUB_OUTPUT"
else
echo "mathlib_ready=false" >> "$GITHUB_OUTPUT"
fi
else
echo "mathlib_ready=true" >> "$GITHUB_OUTPUT"
fi
@@ -252,7 +271,7 @@ jobs:
if git ls-remote --heads --tags --exit-code origin "nightly-testing-${MOST_RECENT_NIGHTLY}" >/dev/null; then
BASE="nightly-testing-${MOST_RECENT_NIGHTLY}"
else
echo "This shouldn't be possible: couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' tag at Batteries. Falling back to 'nightly-testing'."
echo "Couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' tag at Batteries. Falling back to 'nightly-testing'."
BASE=nightly-testing
fi
@@ -316,7 +335,7 @@ jobs:
if git ls-remote --heads --tags --exit-code origin "nightly-testing-${MOST_RECENT_NIGHTLY}" >/dev/null; then
BASE="nightly-testing-${MOST_RECENT_NIGHTLY}"
else
echo "This shouldn't be possible: couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' branch at Mathlib. Falling back to 'nightly-testing'."
echo "Couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' branch at Mathlib. Falling back to 'nightly-testing'."
BASE=nightly-testing
fi

View File

@@ -15,7 +15,7 @@ foreach(var ${vars})
# must forward options that generate incompatible .olean format
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
endif()
if("${var}" MATCHES "LLVM*")
if("${var}" MATCHES "LLVM*|PKG_CONFIG|USE_LAKE")
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
endif()
elseif(("${var}" MATCHES "CMAKE_.*") AND NOT ("${var}" MATCHES "CMAKE_BUILD_TYPE") AND NOT ("${var}" MATCHES "CMAKE_HOME_DIRECTORY"))
@@ -44,10 +44,11 @@ if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
string(APPEND CADICAL_CXXFLAGS " -DNUNLOCKED")
endif()
string(APPEND CADICAL_CXXFLAGS " -DNCLOSEFROM")
ExternalProject_add(cadical
PREFIX cadical
GIT_REPOSITORY https://github.com/arminbiere/cadical
GIT_TAG rel-1.9.5
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}
@@ -64,8 +65,8 @@ ExternalProject_add(stage0
SOURCE_SUBDIR src
BINARY_DIR stage0
# do not rebuild stage0 when git hash changes; it's not from this commit anyway
# (however, `CHECK_OLEAN_VERSION=ON` in CI will override this as we need to
# embed the githash into the stage 1 library built by stage 0)
# (however, CI will override this as we need to embed the githash into the stage 1 library built
# by stage 0)
CMAKE_ARGS -DSTAGE=0 -DUSE_GITHASH=OFF ${PLATFORM_ARGS} ${STAGE0_ARGS}
BUILD_ALWAYS ON # cmake doesn't auto-detect changes without a download method
INSTALL_COMMAND "" # skip install
@@ -79,6 +80,7 @@ ExternalProject_add(stage1
BUILD_ALWAYS ON
INSTALL_COMMAND ""
DEPENDS stage0
STEP_TARGETS configure
)
ExternalProject_add(stage2
SOURCE_DIR "${LEAN_SOURCE_DIR}"

View File

@@ -26,7 +26,7 @@
"displayName": "Sanitize build config",
"cacheVariables": {
"LEAN_EXTRA_CXX_FLAGS": "-fsanitize=address,undefined",
"LEANC_EXTRA_FLAGS": "-fsanitize=address,undefined -fsanitize-link-c++-runtime",
"LEANC_EXTRA_CC_FLAGS": "-fsanitize=address,undefined -fsanitize-link-c++-runtime",
"SMALL_ALLOCATOR": "OFF",
"BSYMBOLIC": "OFF"
},

File diff suppressed because it is too large Load Diff

View File

@@ -590,9 +590,9 @@ This table should be read as follows:
* No other proofs were attempted, either because the parameter has a type without a non-trivial ``WellFounded`` instance (parameter 3), or because it is already clear that no decreasing measure can be found.
Lean will print the termination argument it found if ``set_option showInferredTerminationBy true`` is set.
Lean will print the termination measure it found if ``set_option showInferredTerminationBy true`` is set.
If Lean does not find the termination argument, or if you want to be explicit, you can append a `termination_by` clause to the function definition, after the function's body, but before the `where` clause if present. It is of the form
If Lean does not find the termination measure, or if you want to be explicit, you can append a `termination_by` clause to the function definition, after the function's body, but before the `where` clause if present. It is of the form
```
termination_by e
```
@@ -672,7 +672,7 @@ def num_consts_lst : List Term → Nat
end
```
In a set of mutually recursive function, either all or no functions must have an explicit termination argument (``termination_by``). A change of the default termination tactic (``decreasing_by``) only affects the proofs about the recursive calls of that function, not the other functions in the group.
In a set of mutually recursive function, either all or no functions must have an explicit termination measure (``termination_by``). A change of the default termination tactic (``decreasing_by``) only affects the proofs about the recursive calls of that function, not the other functions in the group.
```
mutual
@@ -764,11 +764,12 @@ Structures and Records
The ``structure`` command in Lean is used to define an inductive data type with a single constructor and to define its projections at the same time. The syntax is as follows:
```
structure Foo (a : α) extends Bar, Baz : Sort u :=
structure Foo (a : α) : Sort u extends Bar, Baz :=
constructor :: (field₁ : β₁) ... (fieldₙ : βₙ)
```
Here ``(a : α)`` is a telescope, that is, the parameters to the inductive definition. The name ``constructor`` followed by the double colon is optional; if it is not present, the name ``mk`` is used by default. The keyword ``extends`` followed by a list of previously defined structures is also optional; if it is present, an instance of each of these structures is included among the fields to ``Foo``, and the types ``βᵢ`` can refer to their fields as well. The output type, ``Sort u``, can be omitted, in which case Lean infers to smallest non-``Prop`` sort possible. Finally, ``(field₁ : β₁) ... (fieldₙ : βₙ)`` is a telescope relative to ``(a : α)`` and the fields in ``bar`` and ``baz``.
Here ``(a : α)`` is a telescope, that is, the parameters to the inductive definition. The name ``constructor`` followed by the double colon is optional; if it is not present, the name ``mk`` is used by default. The keyword ``extends`` followed by a list of previously defined structures is also optional; if it is present, an instance of each of these structures is included among the fields to ``Foo``, and the types ``βᵢ`` can refer to their fields as well. The output type, ``Sort u``, can be omitted, in which case Lean infers to smallest non-``Prop`` sort possible (unless all the fields are ``Prop``, in which case it infers ``Prop``).
Finally, ``(field₁ : β₁) ... (fieldₙ : βₙ)`` is a telescope relative to ``(a : α)`` and the fields in ``bar`` and ``baz``.
The declaration above is syntactic sugar for an inductive type declaration, and so results in the addition of the following constants to the environment:

View File

@@ -33,6 +33,9 @@ Format of the commit message
- chore (maintain, ex: travis-ci)
- perf (performance improvement, optimization, ...)
Every `feat` or `fix` commit must have a `changelog-*` label, and a commit message
beginning with "This PR " that will be included in the changelog.
``<subject>`` has the following constraints:
- use imperative, present tense: "change" not "changed" nor "changes"
@@ -44,6 +47,7 @@ Format of the commit message
- just as in ``<subject>``, use imperative, present tense
- includes motivation for the change and contrasts with previous
behavior
- If a `changelog-*` label is present, the body must begin with "This PR ".
``<footer>`` is optional and may contain two items:
@@ -60,17 +64,21 @@ Examples
fix: add declarations for operator<<(std::ostream&, expr const&) and operator<<(std::ostream&, context const&) in the kernel
This PR adds declarations `operator<<` for raw printing.
The actual implementation of these two operators is outside of the
kernel. They are implemented in the file 'library/printer.cpp'. We
declare them in the kernel to prevent the following problem. Suppose
there is a file 'foo.cpp' that does not include 'library/printer.h',
but contains
kernel. They are implemented in the file 'library/printer.cpp'.
expr a;
...
std::cout << a << "\n";
...
We declare them in the kernel to prevent the following problem.
Suppose there is a file 'foo.cpp' that does not include 'library/printer.h',
but contains
```cpp
expr a;
...
std::cout << a << "\n";
...
```
The compiler does not generate an error message. It silently uses the
operator bool() to coerce the expression into a Boolean. This produces
counter-intuitive behavior, and may confuse developers.

View File

@@ -49,8 +49,9 @@ In the case of `@[extern]` all *irrelevant* types are removed first; see next se
is represented by the representation of that parameter's type.
For example, `{ x : α // p }`, the `Subtype` structure of a value of type `α` and an irrelevant proof, is represented by the representation of `α`.
* `Nat` is represented by `lean_object *`.
Its runtime value is either a pointer to an opaque bignum object or, if the lowest bit of the "pointer" is 1 (`lean_is_scalar`), an encoded unboxed natural number (`lean_box`/`lean_unbox`).
Similarly, the signed integer types `Int8`, ..., `Int64`, `ISize` are also represented by the unsigned C types `uint8_t`, ..., `uint64_t`, `size_t`, respectively, because they have a trivial structure.
* `Nat` and `Int` are represented by `lean_object *`.
Their runtime values is either a pointer to an opaque bignum object or, if the lowest bit of the "pointer" is 1 (`lean_is_scalar`), an encoded unboxed natural number or integer (`lean_box`/`lean_unbox`).
* A universe `Sort u`, type constructor `... → Sort u`, or proposition `p : Prop` is *irrelevant* and is either statically erased (see above) or represented as a `lean_object *` with the runtime value `lean_box(0)`
* Any other type is represented by `lean_object *`.
Its runtime value is a pointer to an object of a subtype of `lean_object` (see the "Inductive types" section below) or the unboxed value `lean_box(cidx)` for the `cidx`th constructor of an inductive type if this constructor does not have any relevant parameters.
@@ -139,7 +140,7 @@ lean_object * initialize_C(uint8_t builtin, lean_object *);
...
lean_initialize_runtime_module();
//lean_initialize(); // necessary if you (indirectly) access the `Lean` package
//lean_initialize(); // necessary (and replaces `lean_initialize_runtime_module`) if you (indirectly) access the `Lean` package
lean_object * res;
// use same default as for Lean executables

View File

@@ -80,3 +80,10 @@ Unlike most Lean projects, all submodules of the `Lean` module begin with the
`prelude` keyword. This disables the automated import of `Init`, meaning that
developers need to figure out their own subset of `Init` to import. This is done
such that changing files in `Init` doesn't force a full rebuild of `Lean`.
### Testing against Mathlib/Batteries
You can test a Lean PR against Mathlib and Batteries by rebasing your PR
on to `nightly-with-mathlib` branch. (It is fine to force push after rebasing.)
CI will generate a branch of Mathlib and Batteries called `lean-pr-testing-NNNN`
that uses the toolchain for your PR, and will report back to the Lean PR with results from Mathlib CI.
See https://leanprover-community.github.io/contribute/tags_and_branches.html for more details.

View File

@@ -5,11 +5,8 @@ See below for the checklist for release candidates.
We'll use `v4.6.0` as the intended release version as a running example.
- One week before the planned release, ensure that
(1) someone has written the release notes and
(2) someone has written the first draft of the release blog post.
If there is any material in `./releases_drafts/` on the `releases/v4.6.0` branch, then the release notes are not done.
(See the section "Writing the release notes".)
- Run `scripts/release_checklist.py v4.6.0` to check the status of the release.
This script is purely informational, idempotent, and safe to run at any stage of the release process.
- `git checkout releases/v4.6.0`
(This branch should already exist, from the release candidates.)
- `git pull`
@@ -25,14 +22,28 @@ We'll use `v4.6.0` as the intended release version as a running example.
- This step can take up to an hour.
- If you are intending to cut the next release candidate on the same day,
you may want to start on the release candidate checklist now.
- Next we need to prepare the release notes.
- If the stable release is identical to the last release candidate (this should usually be the case),
you can reuse the release notes from `RELEASES.md`.
- If you want to regenerate the release notes,
use `script/release_notes.py --since v4.5.0`, run on the `releases/v4.6.0` branch,
and see the section "Writing the release notes" below for more information.
- Release notes should go in `RELEASES.md` on the `releases/v4.6.0` branch,
and should also be PR'd to `master` (suggested title: "chore: update release notes for v4.6.0").
- Go to https://github.com/leanprover/lean4/releases and verify that the `v4.6.0` release appears.
- Edit the release notes on Github to select the "Set as the latest release".
- Follow the instructions in creating a release candidate for the "GitHub release notes" step,
now that we have a written `RELEASES.md` section.
Do a quick sanity check.
- Verify on Github that "Set as the latest release" is checked.
- Copy the generated release note into the text box, adding the header
```
v4.6.0
----------
```
- Next, we will move a curated list of downstream repos to the latest stable release.
- In order to have the access rights to push to these repositories and merge PRs,
you will need to be a member of the `lean-release-managers` team at both `leanprover-community` and `leanprover`.
Contact Kim Morrison (@kim-em) to arrange access.
- For each of the repositories listed below:
- Make a PR to `master`/`main` changing the toolchain to `v4.6.0`
- The usual branch name would be `bump_to_v4.6.0`.
- Update the toolchain file
- In the Lakefile, if there are dependencies on specific version tags of dependencies that you've already pushed as part of this process, update them to the new tag.
If they depend on `main` or `master`, don't change this; you've just updated the dependency, so it will work and be saved in the manifest
@@ -42,16 +53,38 @@ We'll use `v4.6.0` as the intended release version as a running example.
- Create the tag `v4.6.0` from `master`/`main` and push it.
- Merge the tag `v4.6.0` into the `stable` branch and push it.
- We do this for the repositories:
- [lean4checker](https://github.com/leanprover/lean4checker)
- No dependencies
- Toolchain bump PR
- Create and push the tag
- Merge the tag into `stable`
- [Batteries](https://github.com/leanprover-community/batteries)
- No dependencies
- Toolchain bump PR
- Create and push the tag
- Merge the tag into `stable`
- [lean4checker](https://github.com/leanprover/lean4checker)
- No dependencies
- Toolchain bump PR
- Create and push the tag
- Merge the tag into `stable`
- [quote4](https://github.com/leanprover-community/quote4)
- No dependencies
- Toolchain bump PR
- Create and push the tag
- Merge the tag into `stable`
- [doc-gen4](https://github.com/leanprover/doc-gen4)
- Dependencies: exist, but they're not part of the release workflow
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [Verso](https://github.com/leanprover/verso)
- Dependencies: exist, but they're not part of the release workflow
- The `SubVerso` dependency should be compatible with _every_ Lean release simultaneously, rather than following this workflow
- Warnings during `lake update` and `lake build` are expected.
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [Cli](https://github.com/leanprover/lean4-cli)
- No dependencies
- Toolchain bump PR
- Create and push the tag
- There is no `stable` branch; skip this step
- [ProofWidgets4](https://github.com/leanprover-community/ProofWidgets4)
- Dependencies: `Batteries`
- Note on versions and branches:
@@ -66,27 +99,19 @@ We'll use `v4.6.0` as the intended release version as a running example.
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- Merge the tag into `stable`
- [doc-gen4](https://github.com/leanprover/doc-gen4)
- Dependencies: exist, but they're not part of the release workflow
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [Verso](https://github.com/leanprover/verso)
- Dependencies: exist, but they're not part of the release workflow
- The `SubVerso` dependency should be compatible with _every_ Lean release simultaneously, rather than following this workflow
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [import-graph](https://github.com/leanprover-community/import-graph)
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [plausible](https://github.com/leanprover-community/plausible)
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [Mathlib](https://github.com/leanprover-community/mathlib4)
- Dependencies: `Aesop`, `ProofWidgets4`, `lean4checker`, `Batteries`, `doc-gen4`, `import-graph`
- Dependencies: `Aesop`, `ProofWidgets4`, `lean4checker`, `Batteries`, `doc-gen4`, `quote4`, `import-graph`
- Toolchain bump PR notes:
- In addition to updating the `lean-toolchain` and `lakefile.lean`,
in `.github/workflows/lean4checker.yml` update the line
`git checkout v4.6.0` to the appropriate tag.
- Upstream dependencies should use their `main` or `master` branch, not toolchain tags.
(Unlike for other repos.)
- Push the PR branch to the main Mathlib repository rather than a fork, or CI may not work reliably
- Create and push the tag
- Create a new branch from the tag, push it, and open a pull request against `stable`.
@@ -98,16 +123,12 @@ We'll use `v4.6.0` as the intended release version as a running example.
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- Merge the tag into `stable`
- The `v4.6.0` section of `RELEASES.md` is out of sync between
`releases/v4.6.0` and `master`. This should be reconciled:
- Replace the `v4.6.0` section on `master` with the `v4.6.0` section on `releases/v4.6.0`
and commit this to `master`.
- Merge the release announcement PR for the Lean website - it will be deployed automatically
- Run `script/release_checklist.py v4.6.0` again to check that everything is in order.
- Finally, make an announcement!
This should go in https://leanprover.zulipchat.com/#narrow/stream/113486-announce, with topic `v4.6.0`.
Please see previous announcements for suggested language.
You will want a few bullet points for main topics from the release notes.
Link to the blog post from the Zulip announcement.
If there is a blog post, link to that from the zulip announcement.
- Make sure that whoever is handling social media knows the release is out.
## Optimistic(?) time estimates:
@@ -127,6 +148,8 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
- Decide which nightly release you want to turn into a release candidate.
We will use `nightly-2024-02-29` in this example.
- It is essential to choose the nightly that will become the release candidate as early as possible, to avoid confusion.
- Throughout this process you can use `script/release_checklist.py v4.7.0-rc1` to track progress.
- It is essential that Batteries and Mathlib already have reviewed branches compatible with this nightly.
- Check that both Batteries and Mathlib's `bump/v4.7.0` branch contain `nightly-2024-02-29`
in their `lean-toolchain`.
@@ -139,24 +162,19 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
git checkout -b releases/v4.7.0
```
- In `RELEASES.md` replace `Development in progress` in the `v4.7.0` section with `Release notes to be written.`
- We will rely on automatically generated release notes for release candidates,
and the written release notes will be used for stable versions only.
It is essential to choose the nightly that will become the release candidate as early as possible, to avoid confusion.
- In `src/CMakeLists.txt`,
- verify that you see `set(LEAN_VERSION_MINOR 7)` (for whichever `7` is appropriate); this should already have been updated when the development cycle began.
- `set(LEAN_VERSION_IS_RELEASE 1)` (this should be a change; on `master` and nightly releases it is always `0`).
- change the `LEAN_VERSION_IS_RELEASE` line to `set(LEAN_VERSION_IS_RELEASE 1)` (this should be a change; on `master` and nightly releases it is always `0`).
- Commit your changes to `src/CMakeLists.txt`, and push.
- `git tag v4.7.0-rc1`
- `git push origin v4.7.0-rc1`
- Ping the FRO Zulip that release notes need to be written. The release notes do not block completing the rest of this checklist.
- Now wait, while CI runs.
- You can monitor this at `https://github.com/leanprover/lean4/actions/workflows/ci.yml`, looking for the `v4.7.0-rc1` tag.
- This step can take up to an hour.
- (GitHub release notes) Once the release appears at https://github.com/leanprover/lean4/releases/
- Verify that the release is marked as a prerelease (this should have been done automatically by the CI release job).
- In the "previous tag" dropdown, select `v4.6.0`, and click "Generate release notes".
This will add a list of all the commits since the last stable version.
- Delete "update stage0" commits, and anything with a completely inscrutable commit message.
- Generate release notes by running `script/release_notes.py --since v4.6.0` on the `releases/v4.7.0` branch.
See the section "Writing the release notes" below for more information.
- Next, we will move a curated list of downstream repos to the release candidate.
- This assumes that for each repository either:
* There is already a *reviewed* branch `bump/v4.7.0` containing the required adaptations.
@@ -181,10 +199,11 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
- We do this for the same list of repositories as for stable releases, see above.
As above, there are dependencies between these, and so the process above is iterative.
It greatly helps if you can merge the `bump/v4.7.0` PRs yourself!
It is essential for Mathlib CI that you then create the next `bump/v4.8.0` branch
- It is essential for Mathlib and Batteries CI that you then create the next `bump/v4.8.0` branch
for the next development cycle.
Set the `lean-toolchain` file on this branch to same `nightly` you used for this release.
- For Batteries/Aesop/Mathlib, which maintain a `nightly-testing` branch, make sure there is a tag
- (Note: we're currently uncertain if we really want to do this step. Check with Kim Morrison if you're unsure.)
For Batteries/Aesop/Mathlib, which maintain a `nightly-testing` branch, make sure there is a tag
`nightly-testing-2024-02-29` with date corresponding to the nightly used for the release
(create it if not), and then on the `nightly-testing` branch `git reset --hard master`, and force push.
- Make an announcement!
@@ -248,15 +267,26 @@ Please read https://leanprover-community.github.io/contribute/tags_and_branches.
# Writing the release notes
We are currently trying a system where release notes are compiled all at once from someone looking through the commit history.
The exact steps are a work in progress.
Here is the general idea:
Release notes are automatically generated from the commit history, using `script/release_notes.py`.
* The work is done right on the `releases/v4.6.0` branch sometime after it is created but before the stable release is made.
The release notes for `v4.6.0` will later be copied to `master` when we begin a new development cycle.
* There can be material for release notes entries in commit messages.
* There can also be pre-written entries in `./releases_drafts`, which should be all incorporated in the release notes and then deleted from the branch.
Run this as `script/release_notes.py --since v4.6.0`, where `v4.6.0` is the *previous* release version.
This script should be run on the `releases/v4.7.0` branch.
This will generate output for all commits since that tag.
Note that there is output on both stderr, which should be manually reviewed,
and on stdout, which should be manually copied to `RELEASES.md`.
The output on stderr should mostly be about commits for which the script could not find an associated PR,
usually because a PR was rebase-merged because it contained an update to stage0.
Some judgement is required here: ignore commits which look minor,
but manually add items to the release notes for significant PRs that were rebase-merged.
There can also be pre-written entries in `./releases_drafts`, which should be all incorporated in the release notes and then deleted from the branch.
See `./releases_drafts/README.md` for more information.
* The release notes should be written from a downstream expert user's point of view.
This section will be updated when the next release notes are written (for `v4.10.0`).
# `release_checklist.py`
The script `script/release_checklist.py` attempts to automate checking the status of the release.
Future improvements:
* We check the release notes have been posted on Github,
but do not check that they are present in `RELEASES.md` on the release branch or on `master`.

View File

@@ -179,7 +179,7 @@ local macro "have_eq " lhs:term:max rhs:term:max : tactic =>
`(tactic|
(have h : $lhs = $rhs :=
-- TODO: replace with linarith
by simp_arith at *; apply Nat.le_antisymm <;> assumption
by simp +arith at *; apply Nat.le_antisymm <;> assumption
try subst $lhs))
/-!

View File

@@ -61,7 +61,7 @@ Parts of atomic names can be escaped by enclosing them in pairs of French double
letterlike_symbols: [℀-⅏]
escaped_ident_part: "«" [^«»\r\n\t]* "»"
atomic_ident_rest: atomic_ident_start | [0-9'ⁿ] | subscript
subscript: [₀-₉ₐ-ₜᵢ-ᵪ]
subscript: [₀-₉ₐ-ₜᵢ-ᵪ]
```
String Literals

View File

@@ -32,12 +32,13 @@ following to use `g++`.
cmake -DCMAKE_CXX_COMPILER=g++ ...
```
## Required Packages: CMake, GMP, libuv
## Required Packages: CMake, GMP, libuv, pkgconf
```bash
brew install cmake
brew install gmp
brew install libuv
brew install pkgconf
```
## Recommended Packages: CCache

View File

@@ -8,5 +8,5 @@ follow the [generic build instructions](index.md).
## Basic packages
```bash
sudo apt-get install git libgmp-dev libuv1-dev cmake ccache clang
sudo apt-get install git libgmp-dev libuv1-dev cmake ccache clang pkgconf
```

View File

@@ -4,7 +4,7 @@
Platforms built & tested by our CI, available as binary releases via elan (see below)
* x86-64 Linux with glibc 2.27+
* x86-64 Linux with glibc 2.26+
* x86-64 macOS 10.15+
* aarch64 (Apple Silicon) macOS 10.15+
* x86-64 Windows 11 (any version), Windows 10 (version 1903 or higher), Windows Server 2022

9
doc/std/README.md Normal file
View File

@@ -0,0 +1,9 @@
# The Lean standard library
This directory contains development information about the Lean standard library. The user-facing documentation of the standard library
is part of the [Lean Language Reference](https://lean-lang.org/doc/reference/latest/).
Here you will find
* the [standard library vision document](./vision.md), including the call for contributions,
* the [standard library style guide](./style.md), and
* the [standard library naming conventions](./naming.md).

3
doc/std/naming-tree.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 68 KiB

260
doc/std/naming.md Normal file
View File

@@ -0,0 +1,260 @@
# Standard library naming conventions
The easiest way to access a result in the standard library is to correctly guess the name of the declaration (possibly with the help of identifier autocompletion). This is faster and has lower friction than more sophisticated search tools, so easily guessable names (which are still reasonably short) make Lean users more productive.
The guide that follows contains very few hard rules, many heuristics and a selection of examples. It cannot and does not present a deterministic algorithm for choosing good names in all situations. It is intended as a living document that gets clarified and expanded as situations arise during code reviews for the standard library. If applying one of the suggestions in this guide leads to nonsensical results in a certain situation, it is
probably safe to ignore the suggestion (or even better, suggest a way to improve the suggestion).
## Prelude
Identifiers use a mix of `UpperCamelCase`, `lowerCamelCase` and `snake_case`, used for types, data, and theorems, respectively.
Structure fields should be named such that the projections have the correct names.
## Naming convention for types
When defining a type, i.e., a (possibly 0-ary) function whose codomain is Sort u for some u, it should be named in UpperCamelCase. Examples include `List`, and `List.IsPrefix`.
When defining a predicate, prefix the name by `Is`, like in `List.IsPrefix`. The `Is` prefix may be omitted if
* the resulting name would be ungrammatical, or
* the predicate depends on additional data in a way where the `Is` prefix would be confusing (like `List.Pairwise`), or
* the name is an adjective (like `Std.Time.Month.Ordinal.Valid`)
## Namespaces and generalized projection notation
Almost always, definitions and theorems relating to a type should be placed in a namespace with the same name as the type. For example, operations and theorems about lists should be placed in the `List` namespace, and operations and theorems about `Std.Time.PlainDate` should be placed in the `Std.Time.PlainDate` namespace.
Declarations in the root namespace will be relatively rare. The most common type of declaration in the root namespace are declarations about data and properties exported by notation type classes, as long as they are not about a specific type implementing that type class. For example, we have
```lean
theorem beq_iff_eq [BEq α] [LawfulBEq α] {a b : α} : a == b a = b := sorry
```
in the root namespace, but
```lean
theorem List.cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
```
belongs in the `List` namespace.
Subtleties arise when multiple namespaces are in play. Generally, place your theorem in the most specific namespace that appears in one of the hypotheses of the theorem. The following names are both correct according to this convention:
```lean
theorem List.Sublist.reverse : l₁ <+ l₂ l₁.reverse <+ l₂.reverse := sorry
theorem List.reverse_sublist : l₁.reverse <+ l₂.reverse l₁ <+ l₂ := sorry
```
Notice that the second theorem does not have a hypothesis of type `List.Sublist l` for some `l`, so the name `List.Sublist.reverse_iff` would be incorrect.
The advantage of placing results in a namespace like `List.Sublist` is that it enables generalized projection notation, i.e., given `h : l₁ <+ l₂`,
one can write `h.reverse` to obtain a proof of `l₁.reverse <+ l₂.reverse`. Thinking about which dot notations are convenient can act as a guideline
for deciding where to place a theorem, and is, on occasion, a good reason to duplicate a theorem into multiple namespaces.
### The `Std` namespace
New types that are added will usually be placed in the `Std` namespace and in the `Std/` source directory, unless there are good reasons to place
them elsewhere.
Inside the `Std` namespace, all internal declarations should be `private` or else have a name component that clearly marks them as internal, preferably
`Internal`.
## Naming convention for data
When defining data, i.e., a (possibly 0-ary) function whose codomain is not Sort u, but has type Type u for some u, it should be named in lowerCamelCase. Examples include `List.append` and `List.isPrefixOf`.
If your data is morally fully specified by its type, then use the naming procedure for theorems described below and convert the result to lower camel case.
If your function returns an `Option`, consider adding `?` as a suffix. If your function may panic, consider adding `!` as a suffix. In many cases, there will be multiple variants of a function; one returning an option, one that may panic and possibly one that takes a proof argument.
## Naming algorithm for theorems and some definitions
There is, in principle, a general algorithm for naming a theorem. The problem with this algorithm is that it produces very long and unwieldy names which need to be shortened. So choosing a name for a declaration can be thought of as consisting of a mechanical part and a creative part.
Usually the first part is to decide which namespace the result should live in, according to the guidelines described above.
Next, consider the type of your declaration as a tree. Inner nodes of this tree are function types or function applications. Leaves of the tree are 0-ary functions or bound variables.
As an example, consider the following result from the standard library:
```lean
example {α : Type u} {β : Type v} [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α]
[Inhabited β] {m : Std.HashMap α β} {a : α} {h' : a m} : m[a]? = some (m[a]'h') :=
sorry
```
The correct namespace is clearly `Std.HashMap`. The corresponding tree looks like this:
![](naming-tree.svg)
The preferred spelling of a notation can be looked up by hovering over the notation.
Now traverse the tree and build a name according to the following rules:
* When encountering a function type, first turn the result type into a name, then all of the argument types from left to right, and join the names using `_of_`.
* When encountering a function that is neither an infix notation nor a structure projection, first put the function name and then the arguments, joined by an underscore.
* When encountering an infix notation, join the arguments using the name of the notation, separated by underscores.
* When encountering a structure projection, proceed as for normal functions, but put the name of the projection last.
* When encountering a name, put it in lower camel case.
* Skip bound variables and proofs.
* Type class arguments are also generally skipped.
When encountering namespaces names, concatenate them in lower camel case.
Applying this algorithm to our example yields the name `Std.HashMap.getElem?_eq_optionSome_getElem_of_mem`.
From there, the name should be shortened, using the following heuristics:
* The namespace of functions can be omitted if it is clear from context or if the namespace is the current one. This is almost always the case.
* For infix operators, it is possible to leave out the RHS or the name of the notation and the RHS if they are clear from context.
* Hypotheses can be left out if it is clear that they are required or if they appear in the conclusion.
Based on this, here are some possible names for our example:
1. `Std.HashMap.getElem?_eq`
2. `Std.HashMap.getElem?_eq_of_mem`
3. `Std.HashMap.getElem?_eq_some`
4. `Std.HashMap.getElem?_eq_some_of_mem`
5. `Std.HashMap.getElem?_eq_some_getElem`
6. `Std.Hashmap.getElem?_eq_some_getElem_of_mem`
Choosing a good name among these then requires considering the context of the lemma. In this case it turns out that the first four options are underspecified as there is also a lemma relating `m[a]?` and `m[a]!` which could have the same name. This leaves the last two options, the first of which is shorter, and this is how the lemma is called in the Lean standard library.
Here are some additional examples:
```lean
example {x y : List α} (h : x <+: y) (hx : x []) :
x.head hx = y.head (h.ne_nil hx) := sorry
```
Since we have an `IsPrefix` parameter, this should live in the `List.IsPrefix` namespace, and the algorithm suggests `List.IsPrefix.head_eq_head_of_ne_nil`, which is shortened to `List.IsPrefix.head`. Note here the difference between the namespace name (`IsPrefix`) and the recommended spelling of the corresponding notation (`prefix`).
```lean
example : l₁ <+: l₂ reverse l₁ <:+ reverse l₂ := sorry
```
Again, this result should be in the `List.IsPrefix` namespace; the algorithm suggests `List.IsPrefix.reverse_prefix_reverse`, which becomes `List.IsPrefix.reverse`.
The following examples show how the traversal order often matters.
```lean
theorem Nat.mul_zero (n : Nat) : n * 0 = 0 := sorry
theorem Nat.zero_mul (n : Nat) : 0 * n = 0 := sorry
```
Here we see that one name may be a prefix of another name:
```lean
theorem Int.mul_ne_zero {a b : Int} (a0 : a 0) (b0 : b 0) : a * b 0 := sorry
theorem Int.mul_ne_zero_iff {a b : Int} : a * b 0 a 0 b 0 := sorry
```
It is usually a good idea to include the `iff` in a theorem name even if the name would still be unique without the name. For example,
```lean
theorem List.head?_eq_none_iff : l.head? = none l = [] := sorry
```
is a good name: if the lemma was simply called `List.head?_eq_none`, users might try to `apply` it when the goal is `l.head? = none`, leading
to confusion.
The more common you expect (or want) a theorem to be, the shorter you should try to make the name. For example, we have both
```lean
theorem Std.HashMap.getElem?_eq_none_of_contains_eq_false {a : α} : m.contains a = false m[a]? = none := sorry
theorem Std.HashMap.getElem?_eq_none {a : α} : ¬a m m[a]? = none := sorry
```
As users of the hash map are encouraged to use ∈ rather than contains, the second lemma gets the shorter name.
## Special cases
There are certain special “keywords” that may appear in identifiers.
| Keyword | Meaning | Example |
| :---- | :---- | :---- |
| `def` | Unfold a definition. Avoid this for public APIs. | `Nat.max_def` |
| `refl` | Theorems of the form `a R a`, where R is a reflexive relation and `a` is an explicit parameter | `Nat.le_refl` |
| `rfl` | Like `refl`, but with `a` implicit | `Nat.le_rfl` |
| `irrefl` | Theorems of the form `¬a R a`, where R is an irreflexive relation | `Nat.lt_irrefl` |
| `symm` | Theorems of the form `a R b → b R a`, where R is a symmetric relation (compare `comm` below) | `Eq.symm` |
| `trans` | Theorems of the form `a R b → b R c → a R c`, where R is a transitive relation (R may carry data) | `Eq.trans` |
| `antisymmm` | Theorems of the form `a R b → b R a → a = b`, where R is an antisymmetric relation | `Nat.le_antisymm` |
| `congr` | Theorems of the form `a R b → f a S f b`, where R and S are usually equivalence relations | `Std.HashMap.mem_congr` |
| `comm` | Theorems of the form `f a b = f b a` (compare `symm` above) | `Eq.comm`, `Nat.add_comm` |
| `assoc` | Theorems of the form `g (f a b) c = f a (g b c)` (note the order! In most cases, we have f = g) | `Nat.add_sub_assoc` |
| `distrib` | Theorems of the form `f (g a b) = g (f a) (f b)` | `Nat.add_left_distrib` |
| `self` | May be used if a variable appears multiple times in the conclusion | `List.mem_cons_self` |
| `inj` | Theorems of the form `f a = f b ↔ a = b`. | `Int.neg_inj`, `Nat.add_left_inj` |
| `cancel` | Theorems which have one of the forms `f a = f b → a = b` or `g (f a) = a`, where `f` and `g` usually involve a binary operator | `Nat.add_sub_cancel` |
| `cancel_iff` | Same as `inj`, but with different conventions for left and right (see below) | `Nat.add_right_cancel_iff` |
| `ext` | Theorems of the form `f a = f b → a = b`, where `f` usually involves some kind of projection | `List.ext_getElem`
| `mono` | Theorems of the form `a R b → f a R f b`, where `R` is a transitive relation | `List.countP_mono_left`
### Left and right
The keywords left and right are useful to disambiguate symmetric variants of theorems.
```lean
theorem imp_congr_left (h : a b) : (a c) (b c) := sorry
theorem imp_congr_right (h : a (b c)) : (a b) (a c) := sorry
```
It is not always obvious which version of a theorem should be “left” and which should be “right”.
Heuristically, the theorem should name the side which is “more variable”, but there are exceptions. For some of the special keywords discussed in this section, there are conventions which should be followed, as laid out in the following examples:
```lean
theorem Nat.left_distrib (n m k : Nat) : n * (m + k) = n * m + n * k := sorry
theorem Nat.right_distrib (n m k : Nat) : (n + m) * k = n * k + m * k := sorry
theorem Nat.add_left_cancel {n m k : Nat} : n + m = n + k m = k := sorry
theorem Nat.add_right_cancel {n m k : Nat} : n + m = k + m n = k := sorry
theorem Nat.add_left_cancel_iff {m k n : Nat} : n + m = n + k m = k := sorry
theorem Nat.add_right_cancel_iff {m k n : Nat} : m + n = k + n m = k := sorry
theorem Nat.add_left_inj {m k n : Nat} : m + n = k + n m = k := sorry
theorem Nat.add_right_inj {m k n : Nat} : n + m = n + k m = k := sorry
```
Note in particular that the convention is opposite for `cancel_iff` and `inj`.
```lean
theorem Nat.add_sub_self_left (a b : Nat) : (a + b) - a = b := sorry
theorem Nat.add_sub_self_right (a b : Nat) : (a + b) - b = a := sorry
theorem Nat.add_sub_cancel (n m : Nat) : (n + m) - m = n := sorry
```
## Primed names
Avoid disambiguating variants of a concept by appending the `'` character (e.g., introducing both `BitVec.sshiftRight` and `BitVec.sshiftRight'`), as it is impossible to tell the difference without looking at the type signature, the documentation or even the code, and even if you know what the two variants are there is no way to tell which is which. Prefer descriptive pairs `BitVec.sshiftRightNat`/`BitVec.sshiftRight`.
## Acronyms
For acronyms which are three letters or shorter, all letters should use the same case as dictated by the convention. For example, `IO` is a correct name for a type and the name `IO.Ref` may become `IORef` when used as part of a definition name and `ioRef` when used as part of a theorem name.
For acronyms which are at least four letters long, switch to lower case starting from the second letter. For example, `Json` is a correct name for a type, as is `JsonRPC`.
If an acronym is typically spelled using mixed case, this mixed spelling may be used in identifiers (for example `Std.Net.IPv4Addr`).
## Simp sets
Simp sets centered around a conversion function should be called `source_to_target`. For example, a simp set for the `BitVec.toNat` function, which goes from `BitVec` to
`Nat`, should be called `bitvec_to_nat`.
## Variable names
We make the following recommendations for variable names, but without insisting on them:
* Simple hypotheses should be named `h`, `h'`, or using a numerical sequence `h₁`, `h₂`, etc.
* Another common name for a simple hypothesis is `w` (for "witness").
* `List`s should be named `l`, `l'`, `l₁`, etc, or `as`, `bs`, etc.
(Use of `as`, `bs` is encouraged when the lists are of different types, e.g. `as : List α` and `bs : List β`.)
`xs`, `ys`, `zs` are allowed, but it is better if these are reserved for `Array` and `Vector`.
A list of lists may be named `L`.
* `Array`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the arrays are of different types, e.g. `as : Array α` and `bs : Array β`.
An array of arrays may be named `xss`.
* `Vector`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the vectors are of different types, e.g. `as : Vector α n` and `bs : Vector β n`.
A vector of vectors may be named `xss`.
* A common exception for `List` / `Array` / `Vector` is to use `acc` for an accumulator in a recursive function.
* `i`, `j`, `k` are preferred for numerical indices.
Descriptive names such as `start`, `stop`, `lo`, and `hi` are encouraged when they increase readability.
* `n`, `m` are preferred for sizes, e.g. in `Vector α n` or `xs.size = n`.
* `w` is preferred for the width of a `BitVec`.

522
doc/std/style.md Normal file
View File

@@ -0,0 +1,522 @@
# Standard library style
Please take some time to familiarize yourself with the stylistic conventions of
the project and the specific part of the library you are planning to contribute
to. While the Lean compiler may not enforce strict formatting rules,
consistently formatted code is much easier for others to read and maintain.
Attention to formatting is more than a cosmetic concern—it reflects the same
level of precision and care required to meet the deeper standards of the Lean 4
standard library.
Below we will give specific formatting prescriptions for various language constructs. Note that this style guide only applies to the Lean standard library, even though some examples in the guide are taken from other parts of the Lean code base.
## Basic whitespace rules
Syntactic elements (like `:`, `:=`, `|`, `::`) are surrounded by single spaces, with the exception of `,` and `;`, which are followed by a space but not preceded by one. Delimiters (like `()`, `{}`) do not have spaces on the inside, with the exceptions of subtype notation and structure instance notation.
Examples of correctly formatted function parameters:
* `{α : Type u}`
* `[BEq α]`
* `(cmp : αα → Ordering)`
* `(hab : a = b)`
* `{d : { l : List ((n : Nat) × Vector Nat n) // l.length % 2 = 0 }}`
Examples of correctly formatted terms:
* `1 :: [2, 3]`
* `letI : Ord α := ⟨cmp⟩; True`
* `(⟨2, 3⟩ : Nat × Nat)`
* `((2, 3) : Nat × Nat)`
* `{ x with fst := f (4 + f 0), snd := 4, .. }`
* `match 1 with | 0 => 0 | _ => 0`
* `fun ⟨a, b⟩ _ _ => by cases hab <;> apply id; rw [hbc]`
Configure your editor to remove trailing whitespace. If you have set up Visual Studio Code for Lean development in the recommended way then the correct setting is applied automatically.
## Splitting terms across multiple lines
When splitting a term across multiple lines, increase indentation by two spaces starting from the second line. When splitting a function application, try to split at argument boundaries. If an argument itself needs to be split, increase indentation further as appropriate.
When splitting at an infix operator, the operator goes at the end of the first line, not at the beginning of the second line. When splitting at an infix operator, you may or may not increase indentation depth, depending on what is more readable.
When splitting an `if`-`then`-`else` expression, the `then` keyword wants to stay with the condition and the `else` keyword wants to stay with the alternative term. Otherwise, indent as if the `if` and `else` keywords were arguments to the same function.
When splitting a comma-separated bracketed sequence (i.e., anonymous constructor application, list/array/vector literal, tuple) it is allowed to indent subsequent lines for alignment, but indenting by two spaces is also allowed.
Do not orphan parentheses.
Correct:
```lean
def MacroScopesView.isPrefixOf (v₁ v₂ : MacroScopesView) : Bool :=
v₁.name.isPrefixOf v₂.name &&
v₁.scopes == v₂.scopes &&
v₁.mainModule == v₂.mainModule &&
v₁.imported == v₂.imported
```
Correct:
```lean
theorem eraseP_eq_iff {p} {l : List α} :
l.eraseP p = l'
(( a l, ¬ p a) l = l')
a l₁ l₂, ( b l₁, ¬ p b) p a
l = l₁ ++ a :: l₂ l' = l₁ ++ l₂ :=
sorry
```
Correct:
```lean
example : Nat :=
functionWithAVeryLongNameSoThatSomeArgumentsWillNotFit firstArgument secondArgument
(firstArgumentWithAnEquallyLongNameAndThatFunctionDoesHaveMoreArguments firstArgument
secondArgument)
secondArgument
```
Correct:
```lean
theorem size_alter [LawfulBEq α] {k : α} {f : Option (β k) Option (β k)} (h : m.WF) :
(m.alter k f).size =
if m.contains k && (f (m.get? k)).isNone then
m.size - 1
else if !m.contains k && (f (m.get? k)).isSome then
m.size + 1
else
m.size := by
simp_to_raw using Raw₀.size_alter
```
Correct:
```lean
theorem get?_alter [LawfulBEq α] {k k' : α} {f : Option (β k) Option (β k)} (h : m.WF) :
(m.alter k f).get? k' =
if h : k == k' then
cast (congrArg (Option β) (eq_of_beq h)) (f (m.get? k))
else m.get? k' := by
simp_to_raw using Raw₀.get?_alter
```
Correct:
```lean
example : Nat × Nat :=
imagineThisWasALongTerm,
imagineThisWasAnotherLongTerm
```
Correct:
```lean
example : Nat × Nat :=
imagineThisWasALongTerm,
imagineThisWasAnotherLongTerm
```
Correct:
```lean
example : Vector Nat :=
#v[imagineThisWasALongTerm,
imagineThisWasAnotherLongTerm]
```
## Basic file structure
Every file should start with a copyright header, imports (in the standard library, this always includes a `prelude` declaration) and a module documentation string. There should not be a blank line between the copyright header and the imports. There should be a blank line between the imports and the module documentation string.
If you explicitly declare universe variables, do so at the top of the file, after the module documentation.
Correct:
```lean
/-
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro,
Yury Kudryashov
-/
prelude
import Init.Data.List.Pairwise
import Init.Data.List.Find
/-!
**# Lemmas about `List.eraseP` and `List.erase`.**
-/
universe u u'
```
Syntax that is not supposed to be user-facing must be scoped. New public syntax must always be discussed explicitly in an RFC.
## Top-level commands and declarations
All top-level commands are unindented. Sectioning commands like `section` and `namespace` do not increase the indentation level.
Attributes may be placed on the same line as the rest of the command or on a separate line.
Multi-line declaration headers are indented by four spaces starting from the second line. The colon that indicates the type of a declaration may not be placed at the start of a line or on its own line.
Declaration bodies are indented by two spaces. Short declaration bodies may be placed on the same line as the declaration type.
Correct:
```lean
theorem eraseP_eq_iff {p} {l : List α} :
l.eraseP p = l'
(( a l, ¬ p a) l = l')
a l₁ l₂, ( b l₁, ¬ p b) p a
l = l₁ ++ a :: l₂ l' = l₁ ++ l₂ :=
sorry
```
Correct:
```lean
@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl
```
Correct:
```lean
@[simp]
theorem eraseP_nil : [].eraseP p = [] := rfl
```
### Documentation comments
Note to external contributors: this is a section where the Lean style and the mathlib style are different.
Declarations should be documented as required by the `docBlame` linter, which may be activated in a file using
`set_option linter.missingDocs true` (we allow these to stay in the file).
Single-line documentation comments should go on the same line as `/--`/`-/`, while multi-line documentation strings
should have these delimiters on their own line, with the documentation comment itself unindented.
Documentation comments must be written in the indicative mood. Use American orthography.
Correct:
```lean
/-- Carries out a monadic action on each mapping in the hash map in some order. -/
@[inline] def forM (f : (a : α) β a m PUnit) (b : Raw α β) : m PUnit :=
b.buckets.forM (AssocList.forM f)
```
Correct:
```lean
/--
Monadically computes a value by folding the given function over the mappings in the hash
map in some order.
-/
@[inline] def foldM (f : δ (a : α) β a m δ) (init : δ) (b : Raw α β) : m δ :=
b.buckets.foldlM (fun acc l => l.foldlM f acc) init
```
### Where clauses
The `where` keyword should be unindented, and all declarations bound by it should be indented with two spaces.
Blank lines before and after `where` and between declarations bound by `where` are optional and should be chosen
to maximize readability.
Correct:
```lean
@[simp] theorem partition_eq_filter_filter (p : α Bool) (l : List α) :
partition p l = (filter p l, filter (not p) l) := by
simp [partition, aux]
where
aux (l) {as bs} : partition.loop p l (as, bs) =
(as.reverse ++ filter p l, bs.reverse ++ filter (not p) l) :=
match l with
| [] => by simp [partition.loop, filter]
| a :: l => by cases pa : p a <;> simp [partition.loop, pa, aux, filter, append_assoc]
```
### Termination arguments
The `termination_by`, `decreasing_by`, `partial_fixpoint` keywords should be unindented. The associated terms should be indented like declaration bodies.
Correct:
```lean
@[inline] def multiShortOption (handle : Char m PUnit) (opt : String) : m PUnit := do
let rec loop (p : String.Pos) := do
if h : opt.atEnd p then
return
else
handle (opt.get' p h)
loop (opt.next' p h)
termination_by opt.utf8ByteSize - p.byteIdx
decreasing_by
simp [String.atEnd] at h
apply Nat.sub_lt_sub_left h
simp [String.lt_next opt p]
loop 1
```
Correct:
```lean
def substrEq (s1 : String) (off1 : String.Pos) (s2 : String) (off2 : String.Pos) (sz : Nat) : Bool :=
off1.byteIdx + sz s1.endPos.byteIdx && off2.byteIdx + sz s2.endPos.byteIdx && loop off1 off2 { byteIdx := off1.byteIdx + sz }
where
loop (off1 off2 stop1 : Pos) :=
if _h : off1.byteIdx < stop1.byteIdx then
let c₁ := s1.get off1
let c₂ := s2.get off2
c₁ == c₂ && loop (off1 + c₁) (off2 + c₂) stop1
else true
termination_by stop1.1 - off1.1
decreasing_by
have := Nat.sub_lt_sub_left _h (Nat.add_lt_add_left c₁.utf8Size_pos off1.1)
decreasing_tactic
```
Correct:
```lean
theorem div_add_mod (m n : Nat) : n * (m / n) + m % n = m := by
rw [div_eq, mod_eq]
have h : Decidable (0 < n n m) := inferInstance
cases h with
| isFalse h => simp [h]
| isTrue h =>
simp [h]
have ih := div_add_mod (m - n) n
rw [Nat.left_distrib, Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, ih, Nat.add_comm, Nat.sub_add_cancel h.2]
decreasing_by apply div_rec_lemma; assumption
```
### Deriving
The `deriving` clause should be unindented.
Correct:
```lean
structure Iterator where
array : ByteArray
idx : Nat
deriving Inhabited
```
## Notation and Unicode
We generally prefer to use notation as available. We usually prefer the Unicode versions of notations over non-Unicode alternatives.
There are some rules and exceptions regarding specific notations which are listed below:
* Sigma types: use `(a : α) × β a` instead of `Σ a, β a` or `Sigma β`.
* Function arrows: use `fun a => f x` instead of `fun x ↦ f x` or `λ x => f x` or any other variant.
## Language constructs
### Pattern matching, induction etc.
Match arms are indented at the indentation level that the match statement would have if it was on its own line. If the match is implicit, then the arms should be indented as if the match was explicitly given. The content of match arms is indented two spaces, so that it appears on the same level as the match pattern.
Correct:
```lean
def alter [BEq α] {β : Type v} (a : α) (f : Option β Option β) :
AssocList α (fun _ => β) AssocList α (fun _ => β)
| nil => match f none with
| none => nil
| some b => AssocList.cons a b nil
| cons k v l =>
if k == a then
match f v with
| none => l
| some b => cons a b l
else
cons k v (alter a f l)
```
Correct:
```lean
theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a xs) :
as bs, xs = as ++ a :: bs a as := by
induction xs with
| nil => cases h
| cons x xs ih =>
simp at h
cases h with
| inl h => exact [], xs, by simp_all
| inr h =>
by_cases h' : a = x
· subst h'
exact [], xs, by simp
· obtain as, bs, rfl, h := ih h
exact x :: as, bs, rfl, by simp_all
```
Aligning match arms is allowed, but not required.
Correct:
```lean
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
match h₁?, h₂? with
| none, none => return none
| none, some h => return h
| some h, none => return h
| some h₁, some h₂ => mkEqTrans h₁ h₂
```
Correct:
```lean
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
match h₁?, h₂? with
| none, none => return none
| none, some h => return h
| some h, none => return h
| some h₁, some h₂ => mkEqTrans h₁ h₂
```
Correct:
```lean
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
match h₁?, h₂? with
| none, none => return none
| none, some h => return h
| some h, none => return h
| some h₁, some h₂ => mkEqTrans h₁ h₂
```
### Structures
Note to external contributors: this is a section where the Lean style and the mathlib style are different.
When using structure instance syntax over multiple lines, the opening brace should go on the preceding line, while the closing brace should go on its own line. The rest of the syntax should be indented by one level. During structure updates, the `with` clause goes on the same line as the opening brace. Aligning at the assignment symbol is allowed but not required.
Correct:
```lean
def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (reportExts := true) :
IO AddConstAsyncResult := do
let sigPromise IO.Promise.new
let infoPromise IO.Promise.new
let extensionsPromise IO.Promise.new
let checkedEnvPromise IO.Promise.new
let asyncConst := {
constInfo := {
name := constName
kind
sig := sigPromise.result
constInfo := infoPromise.result
}
exts? := guard reportExts *> some extensionsPromise.result
}
return {
constName, kind
mainEnv := { env with
asyncConsts := env.asyncConsts.add asyncConst
checked := checkedEnvPromise.result }
asyncEnv := { env with
asyncCtx? := some { declPrefix := privateToUserName constName.eraseMacroScopes }
}
sigPromise, infoPromise, extensionsPromise, checkedEnvPromise
}
```
Correct:
```lean
instance [Inhabited α] : Inhabited (Descr α β σ) where
default := {
name := default
mkInitial := default
ofOLeanEntry := default
toOLeanEntry := default
addEntry := fun s _ => s
}
```
### Declaring structures
When defining structure types, do not parenthesize structure fields.
When declaring a structure type with a custom constructor name, put the custom name on its own line, indented like the
structure fields, and add a documentation comment.
Correct:
```lean
/--
A bitvector of the specified width.
This is represented as the underlying `Nat` number in both the runtime
and the kernel, inheriting all the special support for `Nat`.
-/
structure BitVec (w : Nat) where
/--
Constructs a `BitVec w` from a number less than `2^w`.
O(1), because we use `Fin` as the internal representation of a bitvector.
-/
ofFin ::
/--
Interprets a bitvector as a number less than `2^w`.
O(1), because we use `Fin` as the internal representation of a bitvector.
-/
toFin : Fin (2 ^ w)
```
## Tactic proofs
Tactic proofs are the most common thing to break during any kind of upgrade, so it is important to write them in a way that minimizes the likelihood of proofs breaking and that makes it easy to debug breakages if they do occur.
If there are multiple goals, either use a tactic combinator (like `all_goals`) to operate on all of them or a clearly specified subset, or use focus dots to work on goals one at a time. Using structured proofs (e.g., `induction … with`) is encouraged but not mandatory.
Squeeze non-terminal `simp`s (i.e., calls to `simp` which do not close the goal). Squeezing terminal `simp`s is generally discouraged, although there are exceptions (for example if squeezing yields a noticeable performance improvement).
Do not over-golf proofs in ways that are likely to lead to hard-to-debug breakage. Examples of things to avoid include complex multi-goal manipulation using lots of tactic combinators, complex uses of the substitution operator (`▸`) and clever point-free expressions (possibly involving anonymous function notation for multiple arguments).
Do not under-golf proofs: for routine tasks, use the most powerful tactics available.
Do not use `erw`. Avoid using `rfl` after `simp` or `rw`, as this usually indicates a missing lemma that should be used instead of `rfl`.
Use `(d)simp` or `rw` instead of `delta` or `unfold`. Use `refine` instead of `refine`. Use `haveI` and `letI` only if they are actually required.
Prefer highly automated tactics (like `grind` and `omega`) over low-level proofs, unless the automated tactic requires unacceptable additional imports or has bad performance. If you decide against using a highly automated tactic, leave a comment explaining the decision.
## `do` notation
The `do` keyword goes on the same line as the corresponding `:=` (or `=>`, or similar). `Id.run do` should be treated as if it was a bare `do`.
Use early `return` statements to reduce nesting depth and make the non-exceptional control flow of a function easier to see.
Alternatives for `let` matches may be placed in the same line or in the next line, indented by two spaces. If the term that is
being matched on is itself more than one line and there is an alternative present, consider breaking immediately after `←` and indent
as far as necessary to ensure readability.
Correct:
```lean
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
let some decl findFunDecl? fvarId | throwError "unknown local function {fvarId.name}"
return decl
```
Correct:
```lean
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
let some decl
findFunDecl? fvarId
| throwError "unknown local function {fvarId.name}"
return decl
```
Correct:
```lean
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
let some decl findFunDecl?
fvarId
| throwError "unknown local function {fvarId.name}"
return decl
```
Correct:
```lean
def tagUntaggedGoals (parentTag : Name) (newSuffix : Name) (newGoals : List MVarId) : TacticM Unit := do
let mctx getMCtx
let mut numAnonymous := 0
for g in newGoals do
if mctx.isAnonymousMVar g then
numAnonymous := numAnonymous + 1
modifyMCtx fun mctx => Id.run do
let mut mctx := mctx
let mut idx := 1
for g in newGoals do
if mctx.isAnonymousMVar g then
if numAnonymous == 1 then
mctx := mctx.setMVarUserName g parentTag
else
mctx := mctx.setMVarUserName g (parentTag ++ newSuffix.appendIndexAfter idx)
idx := idx + 1
pure mctx
```

98
doc/std/vision.md Normal file
View File

@@ -0,0 +1,98 @@
# The Lean 4 standard library
Maintainer team (in alphabetical order): Henrik Böving, Markus Himmel
(community contact & external contribution coordinator), Kim Morrison, Paul
Reichert, Sofia Rodrigues.
The Lean 4 standard library is a core part of the Lean distribution, providing
essential building blocks for functional programming, verified software
development, and software verification. Unlike the standard libraries of most
other languages, many of its components are formally verified and can be used
as part of verified applications.
The standard library is a public API that contains the components listed in the
standard library outline below. Not all public APIs in the Lean distribution
are part of the standard library, and the standard library does not correspond
to a certain directory within the Lean source repository (like `Std`). For
example, the metaprogramming framework is not part of the standard library, but
basic types like `True` and `Nat` are.
The standard library is under active development. Our guiding principles are:
* Provide comprehensive, verified building blocks for real-world software.
* Build a public API of the highest quality with excellent internal consistency.
* Carefully optimize components that may be used in performance-critical software.
* Ensure smooth adoption and maintenance for users.
* Offer excellent documentation, example projects, and guides.
* Provide a reliable and extensible basis that libraries for software
development, software verification and mathematics can build on.
The standard library is principally developed by the Lean FRO. Community
contributions are welcome. If you would like to contribute, please refer to the
call for contributions below.
### Standard library outline
1. Core types and operations
1. Basic types
2. Numeric types, including floating point numbers
3. Containers
4. Strings and formatting
2. Language constructs
1. Ranges and iterators
2. Comparison, ordering, hashing and related type classes
3. Basic monad infrastructure
3. Libraries
1. Random numbers
2. Dates and times
4. Operating system abstractions
1. Concurrency and parallelism primitives
2. Asynchronous I/O
3. FFI helpers
4. Environment, file system, processes
5. Locales
The material covered in the first three sections (core types and operations,
language constructs and libraries) will be verified, with the exception of
floating point numbers and the parts of the libraries that interface with the
operating system (e.g., sources of operating system randomness or time zone
database access).
### Call for contributions
Thank you for taking interest in contributing to the Lean standard library\!
There are two main ways for community members to contribute to the Lean
standard library: by contributing experience reports or by contributing code
and lemmas.
**If you are using Lean for software verification or verified software
development:** hearing about your experiences using Lean and its standard
library for software verification is extremely valuable to us. We are committed
to building a standard library suitable for real-world applications and your
input will directly influence the continued evolution of the Lean standard
library. Please reach out to the standard library maintainer team via Zulip
(either in a public thread in the \#lean4 channel or via direct message). Even
just a link to your code helps. Thanks\!
**If you have code that you believe could enhance the Lean 4 standard
library:** we encourage you to initiate a discussion in the \#lean4 channel on
Zulip. This is the most effective way to receive preliminary feedback on your
contribution. The Lean standard library has a very precise scope and it has
very high quality standards, so at the moment we are mostly interested in
contributions that expand upon existing material rather than introducing novel
concepts.
**If you would like to contribute code to the standard library but dont know
what to work on:** we are always excited to meet motivated community members
who would like to contribute, and there is always impactful work that is
suitable for new contributors. Please reach out to Markus Himmel on Zulip to
discuss possible contributions.
As laid out in the [project-wide External Contribution
Guidelines](../../CONTRIBUTING.md),
PRs are much more likely to be merged if they are preceded by an RFC or if you
discussed your planned contribution with a member of the standard library
maintainer team. When in doubt, introducing yourself is always a good idea.
All code in the standard library is expected to strictly adhere to the
[standard library coding conventions](./style.md).

28
flake.lock generated
View File

@@ -36,17 +36,17 @@
},
"nixpkgs-cadical": {
"locked": {
"lastModified": 1722221733,
"narHash": "sha256-sga9SrrPb+pQJxG1ttJfMPheZvDOxApFfwXCFO0H9xw=",
"lastModified": 1740791350,
"narHash": "sha256-igS2Z4tVw5W/x3lCZeeadt0vcU9fxtetZ/RyrqsCRQ0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "12bf09802d77264e441f48e25459c10c93eada2e",
"rev": "199169a2135e6b864a888e89a2ace345703c025d",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "12bf09802d77264e441f48e25459c10c93eada2e",
"rev": "199169a2135e6b864a888e89a2ace345703c025d",
"type": "github"
}
},
@@ -67,12 +67,30 @@
"type": "github"
}
},
"nixpkgs-older": {
"flake": false,
"locked": {
"lastModified": 1523316493,
"narHash": "sha256-5qJS+i5ECICPAKA6FhPLIWkhPKDnOZsZbh2PHYF1Kbs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0b307aa73804bbd7a7172899e59ae0b8c347a62d",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0b307aa73804bbd7a7172899e59ae0b8c347a62d",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"nixpkgs-cadical": "nixpkgs-cadical",
"nixpkgs-old": "nixpkgs-old"
"nixpkgs-old": "nixpkgs-old",
"nixpkgs-older": "nixpkgs-older"
}
},
"systems": {

View File

@@ -5,17 +5,20 @@
# old nixpkgs used for portable release with older glibc (2.27)
inputs.nixpkgs-old.url = "github:NixOS/nixpkgs/nixos-19.03";
inputs.nixpkgs-old.flake = false;
# for cadical 1.9.5; sync with CMakeLists.txt
inputs.nixpkgs-cadical.url = "github:NixOS/nixpkgs/12bf09802d77264e441f48e25459c10c93eada2e";
# old nixpkgs used for portable release with older glibc (2.26)
inputs.nixpkgs-older.url = "github:NixOS/nixpkgs/0b307aa73804bbd7a7172899e59ae0b8c347a62d";
inputs.nixpkgs-older.flake = false;
# for cadical 2.1.2; sync with CMakeLists.txt by taking commit from https://www.nixhub.io/packages/cadical
inputs.nixpkgs-cadical.url = "github:NixOS/nixpkgs/199169a2135e6b864a888e89a2ace345703c025d";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, nixpkgs, nixpkgs-old, flake-utils, ... }@inputs: flake-utils.lib.eachDefaultSystem (system:
outputs = inputs: inputs.flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
pkgs = import inputs.nixpkgs { inherit system; };
# An old nixpkgs for creating releases with an old glibc
pkgsDist-old = import nixpkgs-old { inherit system; };
pkgsDist-old = import inputs.nixpkgs-older { inherit system; };
# An old nixpkgs for creating releases with an old glibc
pkgsDist-old-aarch = import nixpkgs-old { localSystem.config = "aarch64-unknown-linux-gnu"; };
pkgsDist-old-aarch = import inputs.nixpkgs-old { localSystem.config = "aarch64-unknown-linux-gnu"; };
pkgsCadical = import inputs.nixpkgs-cadical { inherit system; };
cadical = if pkgs.stdenv.isLinux then
# use statically-linked cadical on Linux to avoid glibc versioning troubles
@@ -28,7 +31,7 @@
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
} ({
buildInputs = with pkgs; [
cmake gmp libuv ccache cadical
cmake gmp libuv ccache cadical pkg-config
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
gdb
tree # for CI
@@ -60,6 +63,7 @@
GLIBC_DEV = pkgsDist.glibc.dev;
GCC_LIB = pkgsDist.gcc.cc.lib;
ZLIB = pkgsDist.zlib;
# for CI coredumps
GDB = pkgsDist.gdb;
});
in {

View File

@@ -1,12 +1,12 @@
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
stdenv, lib, cmake, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
stdenv, lib, cmake, pkg-config, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
... } @ args:
with builtins;
lib.warn "The Nix-based build is deprecated" rec {
inherit stdenv;
sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs);
buildCMake = args: stdenv.mkDerivation ({
nativeBuildInputs = [ cmake ];
nativeBuildInputs = [ cmake pkg-config ];
buildInputs = [ gmp libuv llvmPackages.llvm ];
# https://github.com/NixOS/nixpkgs/issues/60919
hardeningDisable = [ "all" ];

292
releases/v4.0.0-m4.md Normal file
View File

@@ -0,0 +1,292 @@
v4.0.0-m4 (23 March 2022)
---------
* `simp` now takes user-defined simp-attributes. You can define a new `simp` attribute by creating a file (e.g., `MySimp.lean`) containing
```lean
import Lean
open Lean.Meta
initialize my_ext : SimpExtension ← registerSimpAttr `my_simp "my own simp attribute"
```
If you don't need to access `my_ext`, you can also use the macro
```lean
import Lean
register_simp_attr my_simp "my own simp attribute"
```
Recall that the new `simp` attribute is not active in the Lean file where it was defined.
Here is a small example using the new feature.
```lean
import MySimp
def f (x : Nat) := x + 2
def g (x : Nat) := x + 1
@[my_simp] theorem f_eq : f x = x + 2 := rfl
@[my_simp] theorem g_eq : g x = x + 1 := rfl
example : f x + g x = 2*x + 3 := by
simp_arith [my_simp]
```
* Extend `match` syntax: multiple left-hand-sides in a single alternative. Example:
```lean
def fib : Nat → Nat
| 0 | 1 => 1
| n+2 => fib n + fib (n+1)
```
This feature was discussed at [issue 371](https://github.com/leanprover/lean4/issues/371). It was implemented as a macro expansion. Thus, the following is accepted.
```lean
inductive StrOrNum where
| S (s : String)
| I (i : Int)
def StrOrNum.asString (x : StrOrNum) :=
match x with
| I a | S a => toString a
```
* Improve `#eval` command. Now, when it fails to synthesize a `Lean.MetaEval` instance for the result type, it reduces the type and tries again. The following example now works without additional annotations
```lean
def Foo := List Nat
def test (x : Nat) : Foo :=
[x, x+1, x+2]
#eval test 4
```
* `rw` tactic can now apply auto-generated equation theorems for a given definition. Example:
```lean
example (a : Nat) (h : n = 1) : [a].length = n := by
rw [List.length]
trace_state -- .. |- [].length + 1 = n
rw [List.length]
trace_state -- .. |- 0 + 1 = n
rw [h]
```
* [Fuzzy matching for auto completion](https://github.com/leanprover/lean4/pull/1023)
* Extend dot-notation `x.field` for arrow types. If type of `x` is an arrow, we look up for `Function.field`.
For example, given `f : Nat → Nat` and `g : Nat → Nat`, `f.comp g` is now notation for `Function.comp f g`.
* The new `.<identifier>` notation is now also accepted where a function type is expected.
```lean
example (xs : List Nat) : List Nat := .map .succ xs
example (xs : List α) : Std.RBTree α ord := xs.foldl .insert ∅
```
* [Add code folding support to the language server](https://github.com/leanprover/lean4/pull/1014).
* Support notation `let <pattern> := <expr> | <else-case>` in `do` blocks.
* Remove support for "auto" `pure`. In the [Zulip thread](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/for.2C.20unexpected.20need.20for.20type.20ascription/near/269083574), the consensus seemed to be that "auto" `pure` is more confusing than it's worth.
* Remove restriction in `congr` theorems that all function arguments on the left-hand-side must be free variables. For example, the following theorem is now a valid `congr` theorem.
```lean
@[congr]
theorem dep_congr [DecidableEq ι] {p : ι → Set α} [∀ i, Inhabited (p i)] :
∀ {i j} (h : i = j) (x : p i) (y : α) (hx : x = y), Pi.single (f := (p ·)) i x = Pi.single (f := (p ·)) j ⟨y, hx ▸ h ▸ x.2⟩ :=
```
* [Partially applied congruence theorems.](https://github.com/leanprover/lean4/issues/988)
* Improve elaboration postponement heuristic when expected type is a metavariable. Lean now reduces the expected type before performing the test.
* [Remove deprecated leanpkg](https://github.com/leanprover/lean4/pull/985) in favor of [Lake](https://github.com/leanprover/lake) now bundled with Lean.
* Various improvements to go-to-definition & find-all-references accuracy.
* Auto generated congruence lemmas with support for casts on proofs and `Decidable` instances (see [wishlist](https://github.com/leanprover/lean4/issues/988)).
* Rename option `autoBoundImplicitLocal` => `autoImplicit`.
* [Relax auto-implicit restrictions](https://github.com/leanprover/lean4/pull/1011). The command `set_option relaxedAutoImplicit false` disables the relaxations.
* `contradiction` tactic now closes the goal if there is a `False.elim` application in the target.
* Renamed tatic `byCases` => `by_cases` (motivation: enforcing naming convention).
* Local instances occurring in patterns are now considered by the type class resolution procedure. Example:
```lean
def concat : List ((α : Type) × ToString α × α) → String
| [] => ""
| ⟨_, _, a⟩ :: as => toString a ++ concat as
```
* Notation for providing the motive for `match` expressions has changed.
before:
```lean
match x, rfl : (y : Nat) → x = y → Nat with
| 0, h => ...
| x+1, h => ...
```
now:
```lean
match (motive := (y : Nat) → x = y → Nat) x, rfl with
| 0, h => ...
| x+1, h => ...
```
With this change, the notation for giving names to equality proofs in `match`-expressions is not whitespace sensitive anymore. That is,
we can now write
```lean
match h : sort.swap a b with
| (r₁, r₂) => ... -- `h : sort.swap a b = (r₁, r₂)`
```
* `(generalizing := true)` is the default behavior for `match` expressions even if the expected type is not a proposition. In the following example, we used to have to include `(generalizing := true)` manually.
```lean
inductive Fam : Type → Type 1 where
| any : Fam α
| nat : Nat → Fam Nat
example (a : α) (x : Fam α) : α :=
match x with
| Fam.any => a
| Fam.nat n => n
```
* We now use `PSum` (instead of `Sum`) when compiling mutually recursive definitions using well-founded recursion.
* Better support for parametric well-founded relations. See [issue #1017](https://github.com/leanprover/lean4/issues/1017). This change affects the low-level `termination_by'` hint because the fixed prefix of the function parameters in not "packed" anymore when constructing the well-founded relation type. For example, in the following definition, `as` is part of the fixed prefix, and is not packed anymore. In previous versions, the `termination_by'` term would be written as `measure fun ⟨as, i, _⟩ => as.size - i`
```lean
def sum (as : Array Nat) (i : Nat) (s : Nat) : Nat :=
if h : i < as.size then
sum as (i+1) (s + as.get ⟨i, h⟩)
else
s
termination_by' measure fun ⟨i, _⟩ => as.size - i
```
* Add `while <cond> do <do-block>`, `repeat <do-block>`, and `repeat <do-block> until <cond>` macros for `do`-block. These macros are based on `partial` definitions, and consequently are useful only for writing programs we don't want to prove anything about.
* Add `arith` option to `Simp.Config`, the macro `simp_arith` expands to `simp (config := { arith := true })`. Only `Nat` and linear arithmetic is currently supported. Example:
```lean
example : 0 < 1 + x ∧ x + y + 2 ≥ y + 1 := by
simp_arith
```
* Add `fail <string>?` tactic that always fail.
* Add support for acyclicity at dependent elimination. See [issue #1022](https://github.com/leanprover/lean4/issues/1022).
* Add `trace <string>` tactic for debugging purposes.
* Add nontrivial `SizeOf` instance for types `Unit → α`, and add support for them in the auto-generated `SizeOf` instances for user-defined inductive types. For example, given the inductive datatype
```lean
inductive LazyList (α : Type u) where
| nil : LazyList α
| cons (hd : α) (tl : LazyList α) : LazyList α
| delayed (t : Thunk (LazyList α)) : LazyList α
```
we now have `sizeOf (LazyList.delayed t) = 1 + sizeOf t` instead of `sizeOf (LazyList.delayed t) = 2`.
* Add support for guessing (very) simple well-founded relations when proving termination. For example, the following function does not require a `termination_by` annotation anymore.
```lean
def Array.insertAtAux (i : Nat) (as : Array α) (j : Nat) : Array α :=
if h : i < j then
let as := as.swap! (j-1) j;
insertAtAux i as (j-1)
else
as
```
* Add support for `for h : x in xs do ...` notation where `h : x ∈ xs`. This is mainly useful for showing termination.
* Auto implicit behavior changed for inductive families. An auto implicit argument occurring in inductive family index is also treated as an index (IF it is not fixed, see next item). For example
```lean
inductive HasType : Index n → Vector Ty n → Ty → Type where
```
is now interpreted as
```lean
inductive HasType : {n : Nat} → Index n → Vector Ty n → Ty → Type where
```
* To make the previous feature more convenient to use, we promote a fixed prefix of inductive family indices to parameters. For example, the following declaration is now accepted by Lean
```lean
inductive Lst : Type u → Type u
| nil : Lst α
| cons : α → Lst α → Lst α
```
and `α` in `Lst α` is a parameter. The actual number of parameters can be inspected using the command `#print Lst`. This feature also makes sure we still accept the declaration
```lean
inductive Sublist : List α → List α → Prop
| slnil : Sublist [] []
| cons l₁ l₂ a : Sublist l₁ l₂ → Sublist l₁ (a :: l₂)
| cons2 l₁ l₂ a : Sublist l₁ l₂ → Sublist (a :: l₁) (a :: l₂)
```
* Added auto implicit "chaining". Unassigned metavariables occurring in the auto implicit types now become new auto implicit locals. Consider the following example:
```lean
inductive HasType : Fin n → Vector Ty n → Ty → Type where
| stop : HasType 0 (ty :: ctx) ty
| pop : HasType k ctx ty → HasType k.succ (u :: ctx) ty
```
`ctx` is an auto implicit local in the two constructors, and it has type `ctx : Vector Ty ?m`. Without auto implicit "chaining", the metavariable `?m` will remain unassigned. The new feature creates yet another implicit local `n : Nat` and assigns `n` to `?m`. So, the declaration above is shorthand for
```lean
inductive HasType : {n : Nat} → Fin n → Vector Ty n → Ty → Type where
| stop : {ty : Ty} → {n : Nat} → {ctx : Vector Ty n} → HasType 0 (ty :: ctx) ty
| pop : {n : Nat} → {k : Fin n} → {ctx : Vector Ty n} → {ty : Ty} → HasType k ctx ty → HasType k.succ (u :: ctx) ty
```
* Eliminate auxiliary type annotations (e.g, `autoParam` and `optParam`) from recursor minor premises and projection declarations. Consider the following example
```lean
structure A :=
x : Nat
h : x = 1 := by trivial
example (a : A) : a.x = 1 := by
have aux := a.h
-- `aux` has now type `a.x = 1` instead of `autoParam (a.x = 1) auto✝`
exact aux
example (a : A) : a.x = 1 := by
cases a with
| mk x h =>
-- `h` has now type `x = 1` instead of `autoParam (x = 1) auto✝`
assumption
```
* We now accept overloaded notation in patterns, but we require the set of pattern variables in each alternative to be the same. Example:
```lean
inductive Vector (α : Type u) : Nat → Type u
| nil : Vector α 0
| cons : α → Vector α n → Vector α (n+1)
infix:67 " :: " => Vector.cons -- Overloading the `::` notation
def head1 (x : List α) (h : x ≠ []) : α :=
match x with
| a :: as => a -- `::` is `List.cons` here
def head2 (x : Vector α (n+1)) : α :=
match x with
| a :: as => a -- `::` is `Vector.cons` here
```
* New notation `.<identifier>` based on Swift. The namespace is inferred from the expected type. See [issue #944](https://github.com/leanprover/lean4/issues/944). Examples:
```lean
def f (x : Nat) : Except String Nat :=
if x > 0 then
.ok x
else
.error "x is zero"
namespace Lean.Elab
open Lsp
def identOf : Info → Option (RefIdent × Bool)
| .ofTermInfo ti => match ti.expr with
| .const n .. => some (.const n, ti.isBinder)
| .fvar id .. => some (.fvar id, ti.isBinder)
| _ => none
| .ofFieldInfo fi => some (.const fi.projName, false)
| _ => none
def isImplicit (bi : BinderInfo) : Bool :=
bi matches .implicit
end Lean.Elab
```

715
releases/v4.0.0-m5.md Normal file
View File

@@ -0,0 +1,715 @@
v4.0.0-m5 (07 August 2022)
---------
* Update Lake to v4.0.0. See the [v4.0.0 release notes](https://github.com/leanprover/lake/releases/tag/v4.0.0) for detailed changes.
* Mutual declarations in different namespaces are now supported. Example:
```lean
mutual
def Foo.boo (x : Nat) :=
match x with
| 0 => 1
| x + 1 => 2*Boo.bla x
def Boo.bla (x : Nat) :=
match x with
| 0 => 2
| x+1 => 3*Foo.boo x
end
```
A `namespace` is automatically created for the common prefix. Example:
```lean
mutual
def Tst.Foo.boo (x : Nat) := ...
def Tst.Boo.bla (x : Nat) := ...
end
```
expands to
```lean
namespace Tst
mutual
def Foo.boo (x : Nat) := ...
def Boo.bla (x : Nat) := ...
end
end Tst
```
* Allow users to install their own `deriving` handlers for existing type classes.
See example at [Simple.lean](https://github.com/leanprover/lean4/blob/master/tests/pkg/deriving/UserDeriving/Simple.lean).
* Add tactic `congr (num)?`. See doc string for additional details.
* [Missing doc linter](https://github.com/leanprover/lean4/pull/1390)
* `match`-syntax notation now checks for unused alternatives. See issue [#1371](https://github.com/leanprover/lean4/issues/1371).
* Auto-completion for structure instance fields. Example:
```lean
example : Nat × Nat := {
f -- HERE
}
```
`fst` now appears in the list of auto-completion suggestions.
* Auto-completion for dotted identifier notation. Example:
```lean
example : Nat :=
.su -- HERE
```
`succ` now appears in the list of auto-completion suggestions.
* `nat_lit` is not needed anymore when declaring `OfNat` instances. See issues [#1389](https://github.com/leanprover/lean4/issues/1389) and [#875](https://github.com/leanprover/lean4/issues/875). Example:
```lean
inductive Bit where
| zero
| one
instance inst0 : OfNat Bit 0 where
ofNat := Bit.zero
instance : OfNat Bit 1 where
ofNat := Bit.one
example : Bit := 0
example : Bit := 1
```
* Add `[elabAsElim]` attribute (it is called `elab_as_eliminator` in Lean 3). Motivation: simplify the Mathlib port to Lean 4.
* `Trans` type class now accepts relations in `Type u`. See this [Zulip issue](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Calc.20mode/near/291214574).
* Accept unescaped keywords as inductive constructor names. Escaping can often be avoided at use sites via dot notation.
```lean
inductive MyExpr
| let : ...
def f : MyExpr → MyExpr
| .let ... => .let ...
```
* Throw an error message at parametric local instances such as `[Nat -> Decidable p]`. The type class resolution procedure
cannot use this kind of local instance because the parameter does not have a forward dependency.
This check can be disabled using `set_option checkBinderAnnotations false`.
* Add option `pp.showLetValues`. When set to `false`, the info view hides the value of `let`-variables in a goal.
By default, it is `true` when visualizing tactic goals, and `false` otherwise.
See [issue #1345](https://github.com/leanprover/lean4/issues/1345) for additional details.
* Add option `warningAsError`. When set to true, warning messages are treated as errors.
* Support dotted notation and named arguments in patterns. Example:
```lean
def getForallBinderType (e : Expr) : Expr :=
match e with
| .forallE (binderType := type) .. => type
| _ => panic! "forall expected"
```
* "jump-to-definition" now works for function names embedded in the following attributes
`@[implementedBy funName]`, `@[tactic parserName]`, `@[termElab parserName]`, `@[commandElab parserName]`,
`@[builtinTactic parserName]`, `@[builtinTermElab parserName]`, and `@[builtinCommandElab parserName]`.
See [issue #1350](https://github.com/leanprover/lean4/issues/1350).
* Improve `MVarId` methods discoverability. See [issue #1346](https://github.com/leanprover/lean4/issues/1346).
We still have to add similar methods for `FVarId`, `LVarId`, `Expr`, and other objects.
Many existing methods have been marked as deprecated.
* Add attribute `[deprecated]` for marking deprecated declarations. Examples:
```lean
def g (x : Nat) := x + 1
-- Whenever `f` is used, a warning message is generated suggesting to use `g` instead.
@[deprecated g]
def f (x : Nat) := x + 1
#check f 0 -- warning: `f` has been deprecated, use `g` instead
-- Whenever `h` is used, a warning message is generated.
@[deprecated]
def h (x : Nat) := x + 1
#check h 0 -- warning: `h` has been deprecated
```
* Add type `LevelMVarId` (and abbreviation `LMVarId`) for universe level metavariable ids.
Motivation: prevent meta-programmers from mixing up universe and expression metavariable ids.
* Improve `calc` term and tactic. See [issue #1342](https://github.com/leanprover/lean4/issues/1342).
* [Relaxed antiquotation parsing](https://github.com/leanprover/lean4/pull/1272) further reduces the need for explicit `$x:p` antiquotation kind annotations.
* Add support for computed fields in inductives. Example:
```lean
inductive Exp
| var (i : Nat)
| app (a b : Exp)
with
@[computedField] hash : Exp → Nat
| .var i => i
| .app a b => a.hash * b.hash + 1
```
The result of the `Exp.hash` function is then stored as an extra "computed" field in the `.var` and `.app` constructors;
`Exp.hash` accesses this field and thus runs in constant time (even on dag-like values).
* Update `a[i]` notation. It is now based on the typeclass
```lean
class GetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w)) (dom : outParam (cont → idx → Prop)) where
getElem (xs : cont) (i : idx) (h : dom xs i) : Elem
```
The notation `a[i]` is now defined as follows
```lean
macro:max x:term noWs "[" i:term "]" : term => `(getElem $x $i (by get_elem_tactic))
```
The proof that `i` is a valid index is synthesized using the tactic `get_elem_tactic`.
For example, the type `Array α` has the following instances
```lean
instance : GetElem (Array α) Nat α fun xs i => LT.lt i xs.size where ...
instance : GetElem (Array α) USize α fun xs i => LT.lt i.toNat xs.size where ...
```
You can use the notation `a[i]'h` to provide the proof manually.
Two other notations were introduced: `a[i]!` and `a[i]?`, For `a[i]!`, a panic error message is produced at
runtime if `i` is not a valid index. `a[i]?` has type `Option α`, and `a[i]?` evaluates to `none` if the
index `i` is not valid.
The three new notations are defined as follows:
```lean
@[inline] def getElem' [GetElem cont idx elem dom] (xs : cont) (i : idx) (h : dom xs i) : elem :=
getElem xs i h
@[inline] def getElem! [GetElem cont idx elem dom] [Inhabited elem] (xs : cont) (i : idx) [Decidable (dom xs i)] : elem :=
if h : _ then getElem xs i h else panic! "index out of bounds"
@[inline] def getElem? [GetElem cont idx elem dom] (xs : cont) (i : idx) [Decidable (dom xs i)] : Option elem :=
if h : _ then some (getElem xs i h) else none
macro:max x:term noWs "[" i:term "]" noWs "?" : term => `(getElem? $x $i)
macro:max x:term noWs "[" i:term "]" noWs "!" : term => `(getElem! $x $i)
macro x:term noWs "[" i:term "]'" h:term:max : term => `(getElem' $x $i $h)
```
See discussion on [Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/String.2EgetOp/near/287855425).
Examples:
```lean
example (a : Array Int) (i : Nat) : Int :=
a[i] -- Error: failed to prove index is valid ...
example (a : Array Int) (i : Nat) (h : i < a.size) : Int :=
a[i] -- Ok
example (a : Array Int) (i : Nat) : Int :=
a[i]! -- Ok
example (a : Array Int) (i : Nat) : Option Int :=
a[i]? -- Ok
example (a : Array Int) (h : a.size = 2) : Int :=
a[0]'(by rw [h]; decide) -- Ok
example (a : Array Int) (h : a.size = 2) : Int :=
have : 0 < a.size := by rw [h]; decide
have : 1 < a.size := by rw [h]; decide
a[0] + a[1] -- Ok
example (a : Array Int) (i : USize) (h : i.toNat < a.size) : Int :=
a[i] -- Ok
```
The `get_elem_tactic` is defined as
```lean
macro "get_elem_tactic" : tactic =>
`(first
| get_elem_tactic_trivial
| fail "failed to prove index is valid, ..."
)
```
The `get_elem_tactic_trivial` auxiliary tactic can be extended using `macro_rules`. By default, it tries `trivial`, `simp_arith`, and a special case for `Fin`. In the future, it will also try `linarith`.
You can extend `get_elem_tactic_trivial` using `my_tactic` as follows
```lean
macro_rules
| `(tactic| get_elem_tactic_trivial) => `(tactic| my_tactic)
```
Note that `Idx`'s type in `GetElem` does not depend on `Cont`. So, you cannot write the instance `instance : GetElem (Array α) (Fin ??) α fun xs i => ...`, but the Lean library comes equipped with the following auxiliary instance:
```lean
instance [GetElem cont Nat elem dom] : GetElem cont (Fin n) elem fun xs i => dom xs i where
getElem xs i h := getElem xs i.1 h
```
and helper tactic
```lean
macro_rules
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Fin.val_lt_of_le; get_elem_tactic_trivial; done)
```
Example:
```lean
example (a : Array Nat) (i : Fin a.size) :=
a[i] -- Ok
example (a : Array Nat) (h : n ≤ a.size) (i : Fin n) :=
a[i] -- Ok
```
* Better support for qualified names in recursive declarations. The following is now supported:
```lean
namespace Nat
def fact : Nat → Nat
| 0 => 1
| n+1 => (n+1) * Nat.fact n
end Nat
```
* Add support for `CommandElabM` monad at `#eval`. Example:
```lean
import Lean
open Lean Elab Command
#eval do
let id := mkIdent `foo
elabCommand (← `(def $id := 10))
#eval foo -- 10
```
* Try to elaborate `do` notation even if the expected type is not available. We still delay elaboration when the expected type
is not available. This change is particularly useful when writing examples such as
```lean
#eval do
IO.println "hello"
IO.println "world"
```
That is, we don't have to use the idiom `#eval show IO _ from do ...` anymore.
Note that auto monadic lifting is less effective when the expected type is not available.
Monadic polymorphic functions (e.g., `ST.Ref.get`) also require the expected type.
* On Linux, panics now print a backtrace by default, which can be disabled by setting the environment variable `LEAN_BACKTRACE` to `0`.
Other platforms are TBD.
* The `group(·)` `syntax` combinator is now introduced automatically where necessary, such as when using multiple parsers inside `(...)+`.
* Add ["Typed Macros"](https://github.com/leanprover/lean4/pull/1251): syntax trees produced and accepted by syntax antiquotations now remember their syntax kinds, preventing accidental production of ill-formed syntax trees and reducing the need for explicit `:kind` antiquotation annotations. See PR for details.
* Aliases of protected definitions are protected too. Example:
```lean
protected def Nat.double (x : Nat) := 2*x
namespace Ex
export Nat (double) -- Add alias Ex.double for Nat.double
end Ex
open Ex
#check Ex.double -- Ok
#check double -- Error, `Ex.double` is alias for `Nat.double` which is protected
```
* Use `IO.getRandomBytes` to initialize random seed for `IO.rand`. See discussion at [this PR](https://github.com/leanprover/lean4-samples/pull/2).
* Improve dot notation and aliases interaction. See discussion on [Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Namespace-based.20overloading.20does.20not.20find.20exports/near/282946185) for additional details.
Example:
```lean
def Set (α : Type) := α → Prop
def Set.union (s₁ s₂ : Set α) : Set α := fun a => s₁ a s₂ a
def FinSet (n : Nat) := Fin n → Prop
namespace FinSet
export Set (union) -- FinSet.union is now an alias for `Set.union`
end FinSet
example (x y : FinSet 10) : FinSet 10 :=
x.union y -- Works
```
* `ext` and `enter` conv tactics can now go inside let-declarations. Example:
```lean
example (g : Nat → Nat) (y : Nat) (h : let x := y + 1; g (0+x) = x) : g (y + 1) = y + 1 := by
conv at h => enter [x, 1, 1]; rw [Nat.zero_add]
/-
g : Nat → Nat
y : Nat
h : let x := y + 1;
g x = x
⊢ g (y + 1) = y + 1
-/
exact h
```
* Add `zeta` conv tactic to expand let-declarations. Example:
```lean
example (h : let x := y + 1; 0 + x = y) : False := by
conv at h => zeta; rw [Nat.zero_add]
/-
y : Nat
h : y + 1 = y
⊢ False
-/
simp_arith at h
```
* Improve namespace resolution. See issue [#1224](https://github.com/leanprover/lean4/issues/1224). Example:
```lean
import Lean
open Lean Parser Elab
open Tactic -- now opens both `Lean.Parser.Tactic` and `Lean.Elab.Tactic`
```
* Rename `constant` command to `opaque`. See discussion at [Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/What.20is.20.60opaque.60.3F/near/284926171).
* Extend `induction` and `cases` syntax: multiple left-hand-sides in a single alternative. This extension is very similar to the one implemented for `match` expressions. Examples:
```lean
inductive Foo where
| mk1 (x : Nat) | mk2 (x : Nat) | mk3
def f (v : Foo) :=
match v with
| .mk1 x => x + 1
| .mk2 x => 2*x + 1
| .mk3 => 1
theorem f_gt_zero : f v > 0 := by
cases v with
| mk1 x | mk2 x => simp_arith! -- New feature used here!
| mk3 => decide
```
* [`let/if` indentation in `do` blocks in now supported.](https://github.com/leanprover/lean4/issues/1120)
* Add unnamed antiquotation `$_` for use in syntax quotation patterns.
* [Add unused variables linter](https://github.com/leanprover/lean4/pull/1159). Feedback welcome!
* Lean now generates an error if the body of a declaration body contains a universe parameter that does not occur in the declaration type, nor is an explicit parameter.
Examples:
```lean
/-
The following declaration now produces an error because `PUnit` is universe polymorphic,
but the universe parameter does not occur in the function type `Nat → Nat`
-/
def f (n : Nat) : Nat :=
let aux (_ : PUnit) : Nat := n + 1
aux ⟨⟩
/-
The following declaration is accepted because the universe parameter was explicitly provided in the
function signature.
-/
def g.{u} (n : Nat) : Nat :=
let aux (_ : PUnit.{u}) : Nat := n + 1
aux ⟨⟩
```
* Add `subst_vars` tactic.
* [Fix `autoParam` in structure fields lost in multiple inheritance.](https://github.com/leanprover/lean4/issues/1158).
* Add `[eliminator]` attribute. It allows users to specify default recursor/eliminators for the `induction` and `cases` tactics.
It is an alternative for the `using` notation. Example:
```lean
@[eliminator] protected def recDiag {motive : Nat → Nat → Sort u}
(zero_zero : motive 0 0)
(succ_zero : (x : Nat) → motive x 0 → motive (x + 1) 0)
(zero_succ : (y : Nat) → motive 0 y → motive 0 (y + 1))
(succ_succ : (x y : Nat) → motive x y → motive (x + 1) (y + 1))
(x y : Nat) : motive x y :=
let rec go : (x y : Nat) → motive x y
| 0, 0 => zero_zero
| x+1, 0 => succ_zero x (go x 0)
| 0, y+1 => zero_succ y (go 0 y)
| x+1, y+1 => succ_succ x y (go x y)
go x y
termination_by go x y => (x, y)
def f (x y : Nat) :=
match x, y with
| 0, 0 => 1
| x+1, 0 => f x 0
| 0, y+1 => f 0 y
| x+1, y+1 => f x y
termination_by f x y => (x, y)
example (x y : Nat) : f x y > 0 := by
induction x, y <;> simp [f, *]
```
* Add support for `casesOn` applications to structural and well-founded recursion modules.
This feature is useful when writing definitions using tactics. Example:
```lean
inductive Foo where
| a | b | c
| pair: Foo × Foo → Foo
def Foo.deq (a b : Foo) : Decidable (a = b) := by
cases a <;> cases b
any_goals apply isFalse Foo.noConfusion
any_goals apply isTrue rfl
case pair a b =>
let (a₁, a₂) := a
let (b₁, b₂) := b
exact match deq a₁ b₁, deq a₂ b₂ with
| isTrue h₁, isTrue h₂ => isTrue (by rw [h₁,h₂])
| isFalse h₁, _ => isFalse (fun h => by cases h; cases (h₁ rfl))
| _, isFalse h₂ => isFalse (fun h => by cases h; cases (h₂ rfl))
```
* `Option` is again a monad. The auxiliary type `OptionM` has been removed. See [Zulip thread](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Do.20we.20still.20need.20OptionM.3F/near/279761084).
* Improve `split` tactic. It used to fail on `match` expressions of the form `match h : e with ...` where `e` is not a free variable.
The failure used to occur during generalization.
* New encoding for `match`-expressions that use the `h :` notation for discriminants. The information is not lost during delaboration,
and it is the foundation for a better `split` tactic. at delaboration time. Example:
```lean
#print Nat.decEq
/-
protected def Nat.decEq : (n m : Nat) → Decidable (n = m) :=
fun n m =>
match h : Nat.beq n m with
| true => isTrue (_ : n = m)
| false => isFalse (_ : ¬n = m)
-/
```
* `exists` tactic is now takes a comma separated list of terms.
* Add `dsimp` and `dsimp!` tactics. They guarantee the result term is definitionally equal, and only apply
`rfl`-theorems.
* Fix binder information for `match` patterns that use definitions tagged with `[matchPattern]` (e.g., `Nat.add`).
We now have proper binder information for the variable `y` in the following example.
```lean
def f (x : Nat) : Nat :=
match x with
| 0 => 1
| y + 1 => y
```
* (Fix) the default value for structure fields may now depend on the structure parameters. Example:
```lean
structure Something (i: Nat) where
n1: Nat := 1
n2: Nat := 1 + i
def s : Something 10 := {}
example : s.n2 = 11 := rfl
```
* Apply `rfl` theorems at the `dsimp` auxiliary method used by `simp`. `dsimp` can be used anywhere in an expression
because it preserves definitional equality.
* Refine auto bound implicit feature. It does not consider anymore unbound variables that have the same
name of a declaration being defined. Example:
```lean
def f : f → Bool := -- Error at second `f`
fun _ => true
inductive Foo : List Foo → Type -- Error at second `Foo`
| x : Foo []
```
Before this refinement, the declarations above would be accepted and the
second `f` and `Foo` would be treated as auto implicit variables. That is,
`f : {f : Sort u} → f → Bool`, and
`Foo : {Foo : Type u} → List Foo → Type`.
* Fix syntax highlighting for recursive declarations. Example
```lean
inductive List (α : Type u) where
| nil : List α -- `List` is not highlighted as a variable anymore
| cons (head : α) (tail : List α) : List α
def List.map (f : α → β) : List α → List β
| [] => []
| a::as => f a :: map f as -- `map` is not highlighted as a variable anymore
```
* Add `autoUnfold` option to `Lean.Meta.Simp.Config`, and the following macros
- `simp!` for `simp (config := { autoUnfold := true })`
- `simp_arith!` for `simp (config := { autoUnfold := true, arith := true })`
- `simp_all!` for `simp_all (config := { autoUnfold := true })`
- `simp_all_arith!` for `simp_all (config := { autoUnfold := true, arith := true })`
When the `autoUnfold` is set to true, `simp` tries to unfold the following kinds of definition
- Recursive definitions defined by structural recursion.
- Non-recursive definitions where the body is a `match`-expression. This
kind of definition is only unfolded if the `match` can be reduced.
Example:
```lean
def append (as bs : List α) : List α :=
match as with
| [] => bs
| a :: as => a :: append as bs
theorem append_nil (as : List α) : append as [] = as := by
induction as <;> simp_all!
theorem append_assoc (as bs cs : List α) : append (append as bs) cs = append as (append bs cs) := by
induction as <;> simp_all!
```
* Add `save` tactic for creating checkpoints more conveniently. Example:
```lean
example : <some-proposition> := by
tac_1
tac_2
save
tac_3
...
```
is equivalent to
```lean
example : <some-proposition> := by
checkpoint
tac_1
tac_2
tac_3
...
```
* Remove support for `{}` annotation from inductive datatype constructors. This annotation was barely used, and we can control the binder information for parameter bindings using the new inductive family indices to parameter promotion. Example: the following declaration using `{}`
```lean
inductive LE' (n : Nat) : Nat → Prop where
| refl {} : LE' n n -- Want `n` to be explicit
| succ : LE' n m → LE' n (m+1)
```
can now be written as
```lean
inductive LE' : Nat → Nat → Prop where
| refl (n : Nat) : LE' n n
| succ : LE' n m → LE' n (m+1)
```
In both cases, the inductive family has one parameter and one index.
Recall that the actual number of parameters can be retrieved using the command `#print`.
* Remove support for `{}` annotation in the `structure` command.
* Several improvements to LSP server. Examples: "jump to definition" in mutually recursive sections, fixed incorrect hover information in "match"-expression patterns, "jump to definition" for pattern variables, fixed auto-completion in function headers, etc.
* In `macro ... xs:p* ...` and similar macro bindings of combinators, `xs` now has the correct type `Array Syntax`
* Identifiers in syntax patterns now ignore macro scopes during matching.
* Improve binder names for constructor auto implicit parameters. Example, given the inductive datatype
```lean
inductive Member : α → List α → Type u
| head : Member a (a::as)
| tail : Member a bs → Member a (b::bs)
```
before:
```lean
#check @Member.head
-- @Member.head : {x : Type u_1} → {a : x} → {as : List x} → Member a (a :: as)
```
now:
```lean
#check @Member.head
-- @Member.head : {α : Type u_1} → {a : α} → {as : List α} → Member a (a :: as)
```
* Improve error message when constructor parameter universe level is too big.
* Add support for `for h : i in [start:stop] do .. ` where `h : i ∈ [start:stop]`. This feature is useful for proving
termination of functions such as:
```lean
inductive Expr where
| app (f : String) (args : Array Expr)
def Expr.size (e : Expr) : Nat := Id.run do
match e with
| app f args =>
let mut sz := 1
for h : i in [: args.size] do
-- h.upper : i < args.size
sz := sz + size (args.get ⟨i, h.upper⟩)
return sz
```
* Add tactic `case'`. It is similar to `case`, but does not admit the goal on failure.
For example, the new tactic is useful when writing tactic scripts where we need to use `case'`
at `first | ... | ...`, and we want to take the next alternative when `case'` fails.
* Add tactic macro
```lean
macro "stop" s:tacticSeq : tactic => `(repeat sorry)
```
See discussion on [Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Partial.20evaluation.20of.20a.20file).
* When displaying goals, we do not display inaccessible proposition names
if they do not have forward dependencies. We still display their types.
For example, the goal
```lean
case node.inl.node
β : Type u_1
b : BinTree β
k : Nat
v : β
left : Tree β
key : Nat
value : β
right : Tree β
ihl : BST left → Tree.find? (Tree.insert left k v) k = some v
ihr : BST right → Tree.find? (Tree.insert right k v) k = some v
h✝ : k < key
a✝³ : BST left
a✝² : ForallTree (fun k v => k < key) left
a✝¹ : BST right
a✝ : ForallTree (fun k v => key < k) right
⊢ BST left
```
is now displayed as
```lean
case node.inl.node
β : Type u_1
b : BinTree β
k : Nat
v : β
left : Tree β
key : Nat
value : β
right : Tree β
ihl : BST left → Tree.find? (Tree.insert left k v) k = some v
ihr : BST right → Tree.find? (Tree.insert right k v) k = some v
: k < key
: BST left
: ForallTree (fun k v => k < key) left
: BST right
: ForallTree (fun k v => key < k) right
⊢ BST left
```
* The hypothesis name is now optional in the `by_cases` tactic.
* [Fix inconsistency between `syntax` and kind names](https://github.com/leanprover/lean4/issues/1090).
The node kinds `numLit`, `charLit`, `nameLit`, `strLit`, and `scientificLit` are now called
`num`, `char`, `name`, `str`, and `scientific` respectively. Example: we now write
```lean
macro_rules | `($n:num) => `("hello")
```
instead of
```lean
macro_rules | `($n:numLit) => `("hello")
```
* (Experimental) New `checkpoint <tactic-seq>` tactic for big interactive proofs.
* Rename tactic `nativeDecide` => `native_decide`.
* Antiquotations are now accepted in any syntax. The `incQuotDepth` `syntax` parser is therefore obsolete and has been removed.
* Renamed tactic `nativeDecide` => `native_decide`.
* "Cleanup" local context before elaborating a `match` alternative right-hand-side. Examples:
```lean
example (x : Nat) : Nat :=
match g x with
| (a, b) => _ -- Local context does not contain the auxiliary `_discr := g x` anymore
example (x : Nat × Nat) (h : x.1 > 0) : f x > 0 := by
match x with
| (a, b) => _ -- Local context does not contain the `h✝ : x.fst > 0` anymore
```
* Improve `let`-pattern (and `have`-pattern) macro expansion. In the following example,
```lean
example (x : Nat × Nat) : f x > 0 := by
let (a, b) := x
done
```
The resulting goal is now `... |- f (a, b) > 0` instead of `... |- f x > 0`.
* Add cross-compiled [aarch64 Linux](https://github.com/leanprover/lean4/pull/1066) and [aarch64 macOS](https://github.com/leanprover/lean4/pull/1076) releases.
* [Add tutorial-like examples to our documentation](https://github.com/leanprover/lean4/tree/master/doc/examples), rendered using LeanInk+Alectryon.

120
releases/v4.0.0.md Normal file
View File

@@ -0,0 +1,120 @@
v4.0.0
---------
* [`Lean.Meta.getConst?` has been renamed](https://github.com/leanprover/lean4/pull/2454).
We have renamed `getConst?` to `getUnfoldableConst?` (and `getConstNoEx?` to `getUnfoldableConstNoEx?`).
These were not intended to be part of the public API, but downstream projects had been using them
(sometimes expecting different behaviour) incorrectly instead of `Lean.getConstInfo`.
* [`dsimp` / `simp` / `simp_all` now fail by default if they make no progress](https://github.com/leanprover/lean4/pull/2336).
This can be overridden with the `(config := { failIfUnchanged := false })` option.
This change was made to ease manual use of `simp` (with complicated goals it can be hard to tell if it was effective)
and to allow easier flow control in tactics internally using `simp`.
See the [summary discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/simp.20fails.20if.20no.20progress/near/380153295)
on zulip for more details.
* [`simp_all` now preserves order of hypotheses](https://github.com/leanprover/lean4/pull/2334).
In order to support the `failIfUnchanged` configuration option for `dsimp` / `simp` / `simp_all`
the way `simp_all` replaces hypotheses has changed.
In particular it is now more likely to preserve the order of hypotheses.
See [`simp_all` reorders hypotheses unnecessarily](https://github.com/leanprover/lean4/pull/2334).
(Previously all non-dependent propositional hypotheses were reverted and reintroduced.
Now only such hypotheses which were changed, or which come after a changed hypothesis,
are reverted and reintroduced.
This has the effect of preserving the ordering amongst the non-dependent propositional hypotheses,
but now any dependent or non-propositional hypotheses retain their position amongst the unchanged
non-dependent propositional hypotheses.)
This may affect proofs that use `rename_i`, `case ... =>`, or `next ... =>`.
* [New `have this` implementation](https://github.com/leanprover/lean4/pull/2247).
`this` is now a regular identifier again that is implicitly introduced by anonymous `have :=` for the remainder of the tactic block. It used to be a keyword that was visible in all scopes and led to unexpected behavior when explicitly used as a binder name.
* [Show typeclass and tactic names in profile output](https://github.com/leanprover/lean4/pull/2170).
* [Make `calc` require the sequence of relation/proof-s to have the same indentation](https://github.com/leanprover/lean4/pull/1844),
and [add `calc` alternative syntax allowing underscores `_` in the first relation](https://github.com/leanprover/lean4/pull/1844).
The flexible indentation in `calc` was often used to align the relation symbols:
```lean
example (x y : Nat) : (x + y) * (x + y) = x * x + y * x + x * y + y * y :=
calc
(x + y) * (x + y) = (x + y) * x + (x + y) * y := by rw [Nat.mul_add]
-- improper indentation
_ = x * x + y * x + (x + y) * y := by rw [Nat.add_mul]
_ = x * x + y * x + (x * y + y * y) := by rw [Nat.add_mul]
_ = x * x + y * x + x * y + y * y := by rw [←Nat.add_assoc]
```
This is no longer legal. The new syntax puts the first term right after the `calc` and each step has the same indentation:
```lean
example (x y : Nat) : (x + y) * (x + y) = x * x + y * x + x * y + y * y :=
calc (x + y) * (x + y)
_ = (x + y) * x + (x + y) * y := by rw [Nat.mul_add]
_ = x * x + y * x + (x + y) * y := by rw [Nat.add_mul]
_ = x * x + y * x + (x * y + y * y) := by rw [Nat.add_mul]
_ = x * x + y * x + x * y + y * y := by rw [←Nat.add_assoc]
```
* Update Lake to latest prerelease.
* [Make go-to-definition on a typeclass projection application go to the instance(s)](https://github.com/leanprover/lean4/pull/1767).
* [Include timings in trace messages when `profiler` is true](https://github.com/leanprover/lean4/pull/1995).
* [Pretty-print signatures in hover and `#check <ident>`](https://github.com/leanprover/lean4/pull/1943).
* [Introduce parser memoization to avoid exponential behavior](https://github.com/leanprover/lean4/pull/1799).
* [feat: allow `doSeq` in `let x <- e | seq`](https://github.com/leanprover/lean4/pull/1809).
* [Add hover/go-to-def/refs for options](https://github.com/leanprover/lean4/pull/1783).
* [Add empty type ascription syntax `(e :)`](https://github.com/leanprover/lean4/pull/1797).
* [Make tokens in `<|>` relevant to syntax match](https://github.com/leanprover/lean4/pull/1744).
* [Add `linter.deprecated` option to silence deprecation warnings](https://github.com/leanprover/lean4/pull/1768).
* [Improve fuzzy-matching heuristics](https://github.com/leanprover/lean4/pull/1710).
* [Implementation-detail hypotheses](https://github.com/leanprover/lean4/pull/1692).
* [Hover information for `cases`/`induction` case names](https://github.com/leanprover/lean4/pull/1660).
* [Prefer longer parse even if unsuccessful](https://github.com/leanprover/lean4/pull/1658).
* [Show declaration module in hover](https://github.com/leanprover/lean4/pull/1638).
* [New `conv` mode structuring tactics](https://github.com/leanprover/lean4/pull/1636).
* `simp` can track information and can print an equivalent `simp only`. [PR #1626](https://github.com/leanprover/lean4/pull/1626).
* Enforce uniform indentation in tactic blocks / do blocks. See issue [#1606](https://github.com/leanprover/lean4/issues/1606).
* Moved `AssocList`, `HashMap`, `HashSet`, `RBMap`, `RBSet`, `PersistentArray`, `PersistentHashMap`, `PersistentHashSet` to the Lean package. The [standard library](https://github.com/leanprover/std4) contains versions that will evolve independently to simplify bootstrapping process.
* Standard library moved to the [std4 GitHub repository](https://github.com/leanprover/std4).
* `InteractiveGoals` now has information that a client infoview can use to show what parts of the goal have changed after applying a tactic. [PR #1610](https://github.com/leanprover/lean4/pull/1610).
* Add `[inheritDoc]` attribute. [PR #1480](https://github.com/leanprover/lean4/pull/1480).
* Expose that `panic = default`. [PR #1614](https://github.com/leanprover/lean4/pull/1614).
* New [code generator](https://github.com/leanprover/lean4/tree/master/src/Lean/Compiler/LCNF) project has started.
* Remove description argument from `register_simp_attr`. [PR #1566](https://github.com/leanprover/lean4/pull/1566).
* [Additional concurrency primitives](https://github.com/leanprover/lean4/pull/1555).
* [Collapsible traces with messages](https://github.com/leanprover/lean4/pull/1448).
* [Hygienic resolution of namespaces](https://github.com/leanprover/lean4/pull/1442).
* [New `Float` functions](https://github.com/leanprover/lean4/pull/1460).
* Many new doc strings have been added to declarations at `Init`.

21
releases/v4.1.0.md Normal file
View File

@@ -0,0 +1,21 @@
v4.1.0
---------
* The error positioning on missing tokens has been [improved](https://github.com/leanprover/lean4/pull/2393). In particular, this should make it easier to spot errors in incomplete tactic proofs.
* After elaborating a configuration file, Lake will now cache the configuration to a `lakefile.olean`. Subsequent runs of Lake will import this OLean instead of elaborating the configuration file. This provides a significant performance improvement (benchmarks indicate that using the OLean cuts Lake's startup time in half), but there are some important details to keep in mind:
+ Lake will regenerate this OLean after each modification to the `lakefile.lean` or `lean-toolchain`. You can also force a reconfigure by passing the new `--reconfigure` / `-R` option to `lake`.
+ Lake configuration options (i.e., `-K`) will be fixed at the moment of elaboration. Setting these options when `lake` is using the cached configuration will have no effect. To change options, run `lake` with `-R` / `--reconfigure`.
+ **The `lakefile.olean` is a local configuration and should not be committed to Git. Therefore, existing Lake packages need to add it to their `.gitignore`.**
* The signature of `Lake.buildO` has changed, `args` has been split into `weakArgs` and `traceArgs`. `traceArgs` are included in the input trace and `weakArgs` are not. See Lake's [FFI example](src/lake/examples/ffi/lib/lakefile.lean) for a demonstration of how to adapt to this change.
* The signatures of `Lean.importModules`, `Lean.Elab.headerToImports`, and `Lean.Elab.parseImports`
have [changed](https://github.com/leanprover/lean4/pull/2480) from taking `List Import` to `Array Import`.
* There is now [an `occs` field](https://github.com/leanprover/lean4/pull/2470)
in the configuration object for the `rewrite` tactic,
allowing control of which occurrences of a pattern should be rewritten.
This was previously a separate argument for `Lean.MVarId.rewrite`,
and this has been removed in favour of an additional field of `Rewrite.Config`.
It was not previously accessible from user tactics.

281
releases/v4.10.0.md Normal file
View File

@@ -0,0 +1,281 @@
v4.10.0
----------
### Language features, tactics, and metaprograms
* `split` tactic:
* [#4401](https://github.com/leanprover/lean4/pull/4401) improves the strategy `split` uses to generalize discriminants of matches and adds `trace.split.failure` trace class for diagnosing issues.
* `rw` tactic:
* [#4385](https://github.com/leanprover/lean4/pull/4385) prevents the tactic from claiming pre-existing goals are new subgoals.
* [dac1da](https://github.com/leanprover/lean4/commit/dac1dacc5b39911827af68247d575569d9c399b5) adds configuration for ordering new goals, like for `apply`.
* `simp` tactic:
* [#4430](https://github.com/leanprover/lean4/pull/4430) adds `dsimproc`s for `if` expressions (`ite` and `dite`).
* [#4434](https://github.com/leanprover/lean4/pull/4434) improves heuristics for unfolding. Equational lemmas now have priorities where more-specific equationals lemmas are tried first before a possible catch-all.
* [#4481](https://github.com/leanprover/lean4/pull/4481) fixes an issue where function-valued `OfNat` numeric literals would become denormalized.
* [#4467](https://github.com/leanprover/lean4/pull/4467) fixes an issue where dsimp theorems might not apply to literals.
* [#4484](https://github.com/leanprover/lean4/pull/4484) fixes the source position for the warning for deprecated simp arguments.
* [#4258](https://github.com/leanprover/lean4/pull/4258) adds docstrings for `dsimp` configuration.
* [#4567](https://github.com/leanprover/lean4/pull/4567) improves the accuracy of used simp lemmas reported by `simp?`.
* [fb9727](https://github.com/leanprover/lean4/commit/fb97275dcbb683efe6da87ed10a3f0cd064b88fd) adds (but does not implement) the simp configuration option `implicitDefEqProofs`, which will enable including `rfl`-theorems in proof terms.
* `omega` tactic:
* [#4360](https://github.com/leanprover/lean4/pull/4360) makes the tactic generate error messages lazily, improving its performance when used in tactic combinators.
* `bv_omega` tactic:
* [#4579](https://github.com/leanprover/lean4/pull/4579) works around changes to the definition of `Fin.sub` in this release.
* [#4490](https://github.com/leanprover/lean4/pull/4490) sets up groundwork for a tactic index in generated documentation, as there was in Lean 3. See PR description for details.
* **Commands**
* [#4370](https://github.com/leanprover/lean4/pull/4370) makes the `variable` command fully elaborate binders during validation, fixing an issue where some errors would be reported only at the next declaration.
* [#4408](https://github.com/leanprover/lean4/pull/4408) fixes a discrepancy in universe parameter order between `theorem` and `def` declarations.
* [#4493](https://github.com/leanprover/lean4/pull/4493) and
[#4482](https://github.com/leanprover/lean4/pull/4482) fix a discrepancy in the elaborators for `theorem`, `def`, and `example`,
making `Prop`-valued `example`s and other definition commands elaborate like `theorem`s.
* [8f023b](https://github.com/leanprover/lean4/commit/8f023b85c554186ae562774b8122322d856c674e), [3c4d6b](https://github.com/leanprover/lean4/commit/3c4d6ba8648eb04d90371eb3fdbd114d16949501) and [0783d0](https://github.com/leanprover/lean4/commit/0783d0fcbe31b626fbd3ed2f29d838e717f09101) change the `#reduce` command to be able to control what gets reduced.
For example, `#reduce (proofs := true) (types := false) e` reduces both proofs and types in the expression `e`.
By default, neither proofs or types are reduced.
* [#4489](https://github.com/leanprover/lean4/pull/4489) fixes an elaboration bug in `#check_tactic`.
* [#4505](https://github.com/leanprover/lean4/pull/4505) adds support for `open _root_.<namespace>`.
* **Options**
* [#4576](https://github.com/leanprover/lean4/pull/4576) adds the `debug.byAsSorry` option. Setting `set_option debug.byAsSorry true` causes all `by ...` terms to elaborate as `sorry`.
* [7b56eb](https://github.com/leanprover/lean4/commit/7b56eb20a03250472f4b145118ae885274d1f8f7) and [d8e719](https://github.com/leanprover/lean4/commit/d8e719f9ab7d049e423473dfc7a32867d32c856f) add the `debug.skipKernelTC` option. Setting `set_option debug.skipKernelTC true` turns off kernel typechecking. This is meant for temporarily working around kernel performance issues, and it compromises soundness since buggy tactics may produce invalid proofs, which will not be caught if this option is set to true.
* [#4301](https://github.com/leanprover/lean4/pull/4301)
adds a linter to flag situations where a local variable's name is one of
the argumentless constructors of its type. This can arise when a user either
doesn't open a namespace or doesn't add a dot or leading qualifier, as
in the following:
```lean
inductive Tree (α : Type) where
| leaf
| branch (left : Tree α) (val : α) (right : Tree α)
def depth : Tree α → Nat
| leaf => 0
```
With this linter, the `leaf` pattern is highlighted as a local
variable whose name overlaps with the constructor `Tree.leaf`.
The linter can be disabled with `set_option linter.constructorNameAsVariable false`.
Additionally, the error message that occurs when a name in a pattern that takes arguments isn't valid now suggests similar names that would be valid. This means that the following definition:
```lean
def length (list : List α) : Nat :=
match list with
| nil => 0
| cons x xs => length xs + 1
```
now results in the following warning:
```
warning: Local variable 'nil' resembles constructor 'List.nil' - write '.nil' (with a dot) or 'List.nil' to use the constructor.
note: this linter can be disabled with `set_option linter.constructorNameAsVariable false`
```
and error:
```
invalid pattern, constructor or constant marked with '[match_pattern]' expected
Suggestion: 'List.cons' is similar
```
* **Metaprogramming**
* [#4454](https://github.com/leanprover/lean4/pull/4454) adds public `Name.isInternalDetail` function for filtering declarations using naming conventions for internal names.
* **Other fixes or improvements**
* [#4416](https://github.com/leanprover/lean4/pull/4416) sorts the output of `#print axioms` for determinism.
* [#4528](https://github.com/leanprover/lean4/pull/4528) fixes error message range for the cdot focusing tactic.
### Language server, widgets, and IDE extensions
* [#4443](https://github.com/leanprover/lean4/pull/4443) makes the watchdog be more resilient against badly behaving clients.
### Pretty printing
* [#4433](https://github.com/leanprover/lean4/pull/4433) restores fallback pretty printers when context is not available, and documents `addMessageContext`.
* [#4556](https://github.com/leanprover/lean4/pull/4556) introduces `pp.maxSteps` option and sets the default value of `pp.deepTerms` to `false`. Together, these keep excessively large or deep terms from overwhelming the Infoview.
### Library
* [#4560](https://github.com/leanprover/lean4/pull/4560) splits `GetElem` class into `GetElem` and `GetElem?`.
This enables removing `Decidable` instance arguments from `GetElem.getElem?` and `GetElem.getElem!`, improving their rewritability.
See the docstrings for these classes for more information.
* `Array`
* [#4389](https://github.com/leanprover/lean4/pull/4389) makes `Array.toArrayAux_eq` be a `simp` lemma.
* [#4399](https://github.com/leanprover/lean4/pull/4399) improves robustness of the proof for `Array.reverse_data`.
* `List`
* [#4469](https://github.com/leanprover/lean4/pull/4469) and [#4475](https://github.com/leanprover/lean4/pull/4475) improve the organization of the `List` API.
* [#4470](https://github.com/leanprover/lean4/pull/4470) improves the `List.set` and `List.concat` API.
* [#4472](https://github.com/leanprover/lean4/pull/4472) upstreams lemmas about `List.filter` from Batteries.
* [#4473](https://github.com/leanprover/lean4/pull/4473) adjusts `@[simp]` attributes.
* [#4488](https://github.com/leanprover/lean4/pull/4488) makes `List.getElem?_eq_getElem` be a simp lemma.
* [#4487](https://github.com/leanprover/lean4/pull/4487) adds missing `List.replicate` API.
* [#4521](https://github.com/leanprover/lean4/pull/4521) adds lemmas about `List.map`.
* [#4500](https://github.com/leanprover/lean4/pull/4500) changes `List.length_cons` to use `as.length + 1` instead of `as.length.succ`.
* [#4524](https://github.com/leanprover/lean4/pull/4524) fixes the statement of `List.filter_congr`.
* [#4525](https://github.com/leanprover/lean4/pull/4525) changes binder explicitness in `List.bind_map`.
* [#4550](https://github.com/leanprover/lean4/pull/4550) adds `maximum?_eq_some_iff'` and `minimum?_eq_some_iff?`.
* [#4400](https://github.com/leanprover/lean4/pull/4400) switches the normal forms for indexing `List` and `Array` to `xs[n]` and `xs[n]?`.
* `HashMap`
* [#4372](https://github.com/leanprover/lean4/pull/4372) fixes linearity in `HashMap.insert` and `HashMap.erase`, leading to a 40% speedup in a replace-heavy workload.
* `Option`
* [#4403](https://github.com/leanprover/lean4/pull/4403) generalizes type of `Option.forM` from `Unit` to `PUnit`.
* [#4504](https://github.com/leanprover/lean4/pull/4504) remove simp attribute from `Option.elim` and instead adds it to individual reduction lemmas, making unfolding less aggressive.
* `Nat`
* [#4242](https://github.com/leanprover/lean4/pull/4242) adds missing theorems for `n + 1` and `n - 1` normal forms.
* [#4486](https://github.com/leanprover/lean4/pull/4486) makes `Nat.min_assoc` be a simp lemma.
* [#4522](https://github.com/leanprover/lean4/pull/4522) moves `@[simp]` from `Nat.pred_le` to `Nat.sub_one_le`.
* [#4532](https://github.com/leanprover/lean4/pull/4532) changes various `Nat.succ n` to `n + 1`.
* `Int`
* [#3850](https://github.com/leanprover/lean4/pull/3850) adds complete div/mod simprocs for `Int`.
* `String`/`Char`
* [#4357](https://github.com/leanprover/lean4/pull/4357) make the byte size interface be `Nat`-valued with functions `Char.utf8Size` and `String.utf8ByteSize`.
* [#4438](https://github.com/leanprover/lean4/pull/4438) upstreams `Char.ext` from Batteries and adds some `Char` documentation to the manual.
* `Fin`
* [#4421](https://github.com/leanprover/lean4/pull/4421) adjusts `Fin.sub` to be more performant in definitional equality checks.
* `Prod`
* [#4526](https://github.com/leanprover/lean4/pull/4526) adds missing `Prod.map` lemmas.
* [#4533](https://github.com/leanprover/lean4/pull/4533) fixes binder explicitness in lemmas.
* `BitVec`
* [#4428](https://github.com/leanprover/lean4/pull/4428) adds missing `simproc` for `BitVec` equality.
* [#4417](https://github.com/leanprover/lean4/pull/4417) adds `BitVec.twoPow` and lemmas, toward bitblasting multiplication for LeanSAT.
* `Std` library
* [#4499](https://github.com/leanprover/lean4/pull/4499) introduces `Std`, a library situated between `Init` and `Lean`, providing functionality not in the prelude both to Lean's implementation and to external users.
* **Other fixes or improvements**
* [#3056](https://github.com/leanprover/lean4/pull/3056) standardizes on using `(· == a)` over `(a == ·)`.
* [#4502](https://github.com/leanprover/lean4/pull/4502) fixes errors reported by running the library through the the Batteries linters.
### Lean internals
* [#4391](https://github.com/leanprover/lean4/pull/4391) makes `getBitVecValue?` recognize `BitVec.ofNatLt`.
* [#4410](https://github.com/leanprover/lean4/pull/4410) adjusts `instantiateMVars` algorithm to zeta reduce `let` expressions while beta reducing instantiated metavariables.
* [#4420](https://github.com/leanprover/lean4/pull/4420) fixes occurs check for metavariable assignments to also take metavariable types into account.
* [#4425](https://github.com/leanprover/lean4/pull/4425) fixes `forEachModuleInDir` to iterate over each Lean file exactly once.
* [#3886](https://github.com/leanprover/lean4/pull/3886) adds support to build Lean core oleans using Lake.
* **Defeq and WHNF algorithms**
* [#4387](https://github.com/leanprover/lean4/pull/4387) improves performance of `isDefEq` by eta reducing lambda-abstracted terms during metavariable assignments, since these are beta reduced during metavariable instantiation anyway.
* [#4388](https://github.com/leanprover/lean4/pull/4388) removes redundant code in `isDefEqQuickOther`.
* **Typeclass inference**
* [#4530](https://github.com/leanprover/lean4/pull/4530) fixes handling of metavariables when caching results at `synthInstance?`.
* **Elaboration**
* [#4426](https://github.com/leanprover/lean4/pull/4426) makes feature where the "don't know how to synthesize implicit argument" error reports the name of the argument more reliable.
* [#4497](https://github.com/leanprover/lean4/pull/4497) fixes a name resolution bug for generalized field notation (dot notation).
* [#4536](https://github.com/leanprover/lean4/pull/4536) blocks the implicit lambda feature for `(e :)` notation.
* [#4562](https://github.com/leanprover/lean4/pull/4562) makes it be an error for there to be two functions with the same name in a `where`/`let rec` block.
* Recursion principles
* [#4549](https://github.com/leanprover/lean4/pull/4549) refactors `findRecArg`, extracting `withRecArgInfo`.
Errors are now reported in parameter order rather than the order they are tried (non-indices are tried first).
For every argument, it will say why it wasn't tried, even if the reason is obvious (e.g. a fixed prefix or is `Prop`-typed, etc.).
* Porting core C++ to Lean
* [#4474](https://github.com/leanprover/lean4/pull/4474) takes a step to refactor `constructions` toward a future port to Lean.
* [#4498](https://github.com/leanprover/lean4/pull/4498) ports `mk_definition_inferring_unsafe` to Lean.
* [#4516](https://github.com/leanprover/lean4/pull/4516) ports `recOn` construction to Lean.
* [#4517](https://github.com/leanprover/lean4/pull/4517), [#4653](https://github.com/leanprover/lean4/pull/4653), and [#4651](https://github.com/leanprover/lean4/pull/4651) port `below` and `brecOn` construction to Lean.
* Documentation
* [#4501](https://github.com/leanprover/lean4/pull/4501) adds a more-detailed docstring for `PersistentEnvExtension`.
* **Other fixes or improvements**
* [#4382](https://github.com/leanprover/lean4/pull/4382) removes `@[inline]` attribute from `NameMap.find?`, which caused respecialization at each call site.
* [5f9ded](https://github.com/leanprover/lean4/commit/5f9dedfe5ee9972acdebd669f228f487844a6156) improves output of `trace.Elab.snapshotTree`.
* [#4424](https://github.com/leanprover/lean4/pull/4424) removes "you might need to open '{dir}' in your editor" message that is now handled by Lake and the VS Code extension.
* [#4451](https://github.com/leanprover/lean4/pull/4451) improves the performance of `CollectMVars` and `FindMVar`.
* [#4479](https://github.com/leanprover/lean4/pull/4479) adds missing `DecidableEq` and `Repr` instances for intermediate structures used by the `BitVec` and `Fin` simprocs.
* [#4492](https://github.com/leanprover/lean4/pull/4492) adds tests for a previous `isDefEq` issue.
* [9096d6](https://github.com/leanprover/lean4/commit/9096d6fc7180fe533c504f662bcb61550e4a2492) removes `PersistentHashMap.size`.
* [#4508](https://github.com/leanprover/lean4/pull/4508) fixes `@[implemented_by]` for functions defined by well-founded recursion.
* [#4509](https://github.com/leanprover/lean4/pull/4509) adds additional tests for `apply?` tactic.
* [d6eab3](https://github.com/leanprover/lean4/commit/d6eab393f4df9d473b5736d636b178eb26d197e6) fixes a benchmark.
* [#4563](https://github.com/leanprover/lean4/pull/4563) adds a workaround for a bug in `IndPredBelow.mkBelowMatcher`.
* **Cleanup:** [#4380](https://github.com/leanprover/lean4/pull/4380), [#4431](https://github.com/leanprover/lean4/pull/4431), [#4494](https://github.com/leanprover/lean4/pull/4494), [e8f768](https://github.com/leanprover/lean4/commit/e8f768f9fd8cefc758533bc76e3a12b398ed4a39), [de2690](https://github.com/leanprover/lean4/commit/de269060d17a581ed87f40378dbec74032633b27), [d3a756](https://github.com/leanprover/lean4/commit/d3a7569c97123d022828106468d54e9224ed8207), [#4404](https://github.com/leanprover/lean4/pull/4404), [#4537](https://github.com/leanprover/lean4/pull/4537).
### Compiler, runtime, and FFI
* [d85d3d](https://github.com/leanprover/lean4/commit/d85d3d5f3a09ff95b2ee47c6f89ef50b7e339126) fixes criterion for tail-calls in ownership calculation.
* [#3963](https://github.com/leanprover/lean4/pull/3963) adds validation of UTF-8 at the C++-to-Lean boundary in the runtime.
* [#4512](https://github.com/leanprover/lean4/pull/4512) fixes missing unboxing in interpreter when loading initialized value.
* [#4477](https://github.com/leanprover/lean4/pull/4477) exposes the compiler flags for the bundled C compiler (clang).
### Lake
* [#4384](https://github.com/leanprover/lean4/pull/4384) deprecates `inputFile` and replaces it with `inputBinFile` and `inputTextFile`. Unlike `inputBinFile` (and `inputFile`), `inputTextFile` normalizes line endings, which helps ensure text file traces are platform-independent.
* [#4371](https://github.com/leanprover/lean4/pull/4371) simplifies dependency resolution code.
* [#4439](https://github.com/leanprover/lean4/pull/4439) touches up the Lake configuration DSL and makes other improvements:
string literals can now be used instead of identifiers for names,
avoids using French quotes in `lake new` and `lake init` templates,
changes the `exe` template to use `Main` for the main module,
improves the `math` template error if `lean-toolchain` fails to download,
and downgrades unknown configuration fields from an error to a warning to improve cross-version compatibility.
* [#4496](https://github.com/leanprover/lean4/pull/4496) tweaks `require` syntax and updates docs. Now `require` in TOML for a package name such as `doc-gen4` does not need French quotes.
* [#4485](https://github.com/leanprover/lean4/pull/4485) fixes a bug where package versions in indirect dependencies would take precedence over direct dependencies.
* [#4478](https://github.com/leanprover/lean4/pull/4478) fixes a bug where Lake incorrectly included the module dynamic library in a platform-independent trace.
* [#4529](https://github.com/leanprover/lean4/pull/4529) fixes some issues with bad import errors.
A bad import in an executable no longer prevents the executable's root
module from being built. This also fixes a problem where the location
of a transitive bad import would not been shown.
The root module of the executable now respects `nativeFacets`.
* [#4564](https://github.com/leanprover/lean4/pull/4564) fixes a bug where non-identifier script names could not be entered on the CLI without French quotes.
* [#4566](https://github.com/leanprover/lean4/pull/4566) addresses a few issues with precompiled libraries.
* Fixes a bug where Lake would always precompile the package of a module.
* If a module is precompiled, it now precompiles its imports. Previously, it would only do this if imported.
* [#4495](https://github.com/leanprover/lean4/pull/4495), [#4692](https://github.com/leanprover/lean4/pull/4692), [#4849](https://github.com/leanprover/lean4/pull/4849)
add a new type of `require` that fetches package metadata from a
registry API endpoint (e.g. Reservoir) and then clones a Git package
using the information provided. To require such a dependency, the new
syntax is:
```lean
require <scope> / <pkg-name> [@ git <rev>]
-- Examples:
require "leanprover" / "doc-gen4"
require "leanprover-community" / "proofwidgets" @ git "v0.0.39"
```
Or in TOML:
```toml
[[require]]
name = "<pkg-name>"
scope = "<scope>"
rev = "<rev>"
```
Unlike with Git dependencies, Lake can make use of the richer
information provided by the registry to determine the default branch of
the package. This means for repositories of packages like `doc-gen4`
which have a default branch that is not `master`, Lake will now use said
default branch (e.g., in `doc-gen4`'s case, `main`).
Lake also supports configuring the registry endpoint via an environment
variable: `RESERVIOR_API_URL`. Thus, any server providing a similar
interface to Reservoir can be used as the registry. Further
configuration options paralleling those of Cargo's [Alternative Registries](https://doc.rust-lang.org/cargo/reference/registries.html)
and [Source Replacement](https://doc.rust-lang.org/cargo/reference/source-replacement.html)
will come in the future.
### DevOps/CI
* [#4427](https://github.com/leanprover/lean4/pull/4427) uses Namespace runners for CI for `leanprover/lean4`.
* [#4440](https://github.com/leanprover/lean4/pull/4440) fixes speedcenter tests in CI.
* [#4441](https://github.com/leanprover/lean4/pull/4441) fixes that workflow change would break CI for unrebased PRs.
* [#4442](https://github.com/leanprover/lean4/pull/4442) fixes Wasm release-ci.
* [6d265b](https://github.com/leanprover/lean4/commit/6d265b42b117eef78089f479790587a399da7690) fixes for `github.event.pull_request.merge_commit_sha` sometimes not being available.
* [16cad2](https://github.com/leanprover/lean4/commit/16cad2b45c6a77efe4dce850dcdbaafaa7c91fc3) adds optimization for CI to not fetch complete history.
* [#4544](https://github.com/leanprover/lean4/pull/4544) causes releases to be marked as prerelease on GitHub.
* [#4446](https://github.com/leanprover/lean4/pull/4446) switches Lake to using `src/lake/lakefile.toml` to avoid needing to load a version of Lake to build Lake.
* Nix
* [5eb5fa](https://github.com/leanprover/lean4/commit/5eb5fa49cf9862e99a5bccff8d4ca1a062f81900) fixes `update-stage0-commit` for Nix.
* [#4476](https://github.com/leanprover/lean4/pull/4476) adds gdb to Nix shell.
* [e665a0](https://github.com/leanprover/lean4/commit/e665a0d716dc42ba79b339b95e01eb99fe932cb3) fixes `update-stage0` for Nix.
* [4808eb](https://github.com/leanprover/lean4/commit/4808eb7c4bfb98f212b865f06a97d46c44978a61) fixes `cacheRoots` for Nix.
* [#3811](https://github.com/leanprover/lean4/pull/3811) adds platform-dependent flag to lib target.
* [#4587](https://github.com/leanprover/lean4/pull/4587) adds linking of `-lStd` back into nix build flags on darwin.
### Breaking changes
* `Char.csize` is replaced by `Char.utf8Size` ([#4357](https://github.com/leanprover/lean4/pull/4357)).
* Library lemmas now are in terms of `(· == a)` over `(a == ·)` ([#3056](https://github.com/leanprover/lean4/pull/3056)).
* Now the normal forms for indexing into `List` and `Array` is `xs[n]` and `xs[n]?` rather than using functions like `List.get` ([#4400](https://github.com/leanprover/lean4/pull/4400)).
* Sometimes terms created via a sequence of unifications will be more eta reduced than before and proofs will require adaptation ([#4387](https://github.com/leanprover/lean4/pull/4387)).
* The `GetElem` class has been split into two; see the docstrings for `GetElem` and `GetElem?` for more information ([#4560](https://github.com/leanprover/lean4/pull/4560)).

337
releases/v4.11.0.md Normal file
View File

@@ -0,0 +1,337 @@
v4.11.0
----------
### Language features, tactics, and metaprograms
* The variable inclusion mechanism has been changed. Like before, when a definition mentions a variable, Lean will add it as an argument of the definition, but now in theorem bodies, variables are not included based on usage in order to ensure that changes to the proof cannot change the statement of the overall theorem. Instead, variables are only available to the proof if they have been mentioned in the theorem header or in an **`include` command** or are instance implicit and depend only on such variables. The **`omit` command** can be used to omit included variables.
See breaking changes below.
PRs: [#4883](https://github.com/leanprover/lean4/pull/4883), [#4814](https://github.com/leanprover/lean4/pull/4814), [#5000](https://github.com/leanprover/lean4/pull/5000), [#5036](https://github.com/leanprover/lean4/pull/5036), [#5138](https://github.com/leanprover/lean4/pull/5138), [0edf1b](https://github.com/leanprover/lean4/commit/0edf1bac392f7e2fe0266b28b51c498306363a84).
* **Recursive definitions**
* Structural recursion can now be explicitly requested using
```
termination_by structural x
```
in analogy to the existing `termination_by x` syntax that causes well-founded recursion to be used.
[#4542](https://github.com/leanprover/lean4/pull/4542)
* [#4672](https://github.com/leanprover/lean4/pull/4672) fixes a bug that could lead to ill-typed terms.
* The `termination_by?` syntax no longer forces the use of well-founded recursion, and when structural
recursion is inferred, it will print the result using the `termination_by structural` syntax.
* **Mutual structural recursion** is now supported. This feature supports both mutual recursion over a non-mutual
data type, as well as recursion over mutual or nested data types:
```lean
mutual
def Even : Nat → Prop
| 0 => True
| n+1 => Odd n
def Odd : Nat → Prop
| 0 => False
| n+1 => Even n
end
mutual
inductive A
| other : B → A
| empty
inductive B
| other : A → B
| empty
end
mutual
def A.size : A → Nat
| .other b => b.size + 1
| .empty => 0
def B.size : B → Nat
| .other a => a.size + 1
| .empty => 0
end
inductive Tree where | node : List Tree → Tree
mutual
def Tree.size : Tree → Nat
| node ts => Tree.list_size ts
def Tree.list_size : List Tree → Nat
| [] => 0
| t::ts => Tree.size t + Tree.list_size ts
end
```
Functional induction principles are generated for these functions as well (`A.size.induct`, `A.size.mutual_induct`).
Nested structural recursion is still not supported.
PRs: [#4639](https://github.com/leanprover/lean4/pull/4639), [#4715](https://github.com/leanprover/lean4/pull/4715), [#4642](https://github.com/leanprover/lean4/pull/4642), [#4656](https://github.com/leanprover/lean4/pull/4656), [#4684](https://github.com/leanprover/lean4/pull/4684), [#4715](https://github.com/leanprover/lean4/pull/4715), [#4728](https://github.com/leanprover/lean4/pull/4728), [#4575](https://github.com/leanprover/lean4/pull/4575), [#4731](https://github.com/leanprover/lean4/pull/4731), [#4658](https://github.com/leanprover/lean4/pull/4658), [#4734](https://github.com/leanprover/lean4/pull/4734), [#4738](https://github.com/leanprover/lean4/pull/4738), [#4718](https://github.com/leanprover/lean4/pull/4718), [#4733](https://github.com/leanprover/lean4/pull/4733), [#4787](https://github.com/leanprover/lean4/pull/4787), [#4788](https://github.com/leanprover/lean4/pull/4788), [#4789](https://github.com/leanprover/lean4/pull/4789), [#4807](https://github.com/leanprover/lean4/pull/4807), [#4772](https://github.com/leanprover/lean4/pull/4772)
* [#4809](https://github.com/leanprover/lean4/pull/4809) makes unnecessary `termination_by` clauses cause warnings, not errors.
* [#4831](https://github.com/leanprover/lean4/pull/4831) improves handling of nested structural recursion through non-recursive types.
* [#4839](https://github.com/leanprover/lean4/pull/4839) improves support for structural recursive over inductive predicates when there are reflexive arguments.
* `simp` tactic
* [#4784](https://github.com/leanprover/lean4/pull/4784) sets configuration `Simp.Config.implicitDefEqProofs` to `true` by default.
* `omega` tactic
* [#4612](https://github.com/leanprover/lean4/pull/4612) normalizes the order that constraints appear in error messages.
* [#4695](https://github.com/leanprover/lean4/pull/4695) prevents pushing casts into multiplications unless it produces a non-trivial linear combination.
* [#4989](https://github.com/leanprover/lean4/pull/4989) fixes a regression.
* `decide` tactic
* [#4711](https://github.com/leanprover/lean4/pull/4711) switches from using default transparency to *at least* default transparency when reducing the `Decidable` instance.
* [#4674](https://github.com/leanprover/lean4/pull/4674) adds detailed feedback on `decide` tactic failure. It tells you which `Decidable` instances it unfolded, if it get stuck on `Eq.rec` it gives a hint about avoiding tactics when defining `Decidable` instances, and if it gets stuck on `Classical.choice` it gives hints about classical instances being in scope. During this process, it processes `Decidable.rec`s and matches to pin blame on a non-reducing instance.
* `@[ext]` attribute
* [#4543](https://github.com/leanprover/lean4/pull/4543) and [#4762](https://github.com/leanprover/lean4/pull/4762) make `@[ext]` realize `ext_iff` theorems from user `ext` theorems. Fixes the attribute so that `@[local ext]` and `@[scoped ext]` are usable. The `@[ext (iff := false)]` option can be used to turn off `ext_iff` realization.
* [#4694](https://github.com/leanprover/lean4/pull/4694) makes "go to definition" work for the generated lemmas. Also adjusts the core library to make use of `ext_iff` generation.
* [#4710](https://github.com/leanprover/lean4/pull/4710) makes `ext_iff` theorem preserve inst implicit binder types, rather than making all binder types implicit.
* `#eval` command
* [#4810](https://github.com/leanprover/lean4/pull/4810) introduces a safer `#eval` command that prevents evaluation of terms that contain `sorry`. The motivation is that failing tactics, in conjunction with operations such as array accesses, can lead to the Lean process crashing. Users can use the new `#eval!` command to use the previous unsafe behavior. ([#4829](https://github.com/leanprover/lean4/pull/4829) adjusts a test.)
* [#4447](https://github.com/leanprover/lean4/pull/4447) adds `#discr_tree_key` and `#discr_tree_simp_key` commands, for helping debug discrimination tree failures. The `#discr_tree_key t` command prints the discrimination tree keys for a term `t` (or, if it is a single identifier, the type of that constant). It uses the default configuration for generating keys. The `#discr_tree_simp_key` command is similar to `#discr_tree_key`, but treats the underlying type as one of a simp lemma, that is it transforms it into an equality and produces the key of the left-hand side.
For example,
```
#discr_tree_key (∀ {a n : Nat}, bar a (OfNat.ofNat n))
-- bar _ (@OfNat.ofNat Nat _ _)
#discr_tree_simp_key Nat.add_assoc
-- @HAdd.hAdd Nat Nat Nat _ (@HAdd.hAdd Nat Nat Nat _ _ _) _
```
* [#4741](https://github.com/leanprover/lean4/pull/4741) changes option parsing to allow user-defined options from the command line. Initial options are now re-parsed and validated after importing. Command line option assignments prefixed with `weak.` are silently discarded if the option name without the prefix does not exist.
* **Deriving handlers**
* [7253ef](https://github.com/leanprover/lean4/commit/7253ef8751f76bcbe0e6f46dcfa8069699a2bac7) and [a04f3c](https://github.com/leanprover/lean4/commit/a04f3cab5a9fe2870825af6544ca13c5bb766706) improve the construction of the `BEq` deriving handler.
* [86af04](https://github.com/leanprover/lean4/commit/86af04cc08c0dbbe0e735ea13d16edea3465f850) makes `BEq` deriving handler work when there are dependently typed fields.
* [#4826](https://github.com/leanprover/lean4/pull/4826) refactors the `DecidableEq` deriving handle to use `termination_by structural`.
* **Metaprogramming**
* [#4593](https://github.com/leanprover/lean4/pull/4593) adds `unresolveNameGlobalAvoidingLocals`.
* [#4618](https://github.com/leanprover/lean4/pull/4618) deletes deprecated functions from 2022.
* [#4642](https://github.com/leanprover/lean4/pull/4642) adds `Meta.lambdaBoundedTelescope`.
* [#4731](https://github.com/leanprover/lean4/pull/4731) adds `Meta.withErasedFVars`, to enter a context with some fvars erased from the local context.
* [#4777](https://github.com/leanprover/lean4/pull/4777) adds assignment validation at `closeMainGoal`, preventing users from circumventing the occurs check for tactics such as `exact`.
* [#4807](https://github.com/leanprover/lean4/pull/4807) introduces `Lean.Meta.PProdN` module for packing and projecting nested `PProd`s.
* [#5170](https://github.com/leanprover/lean4/pull/5170) fixes `Syntax.unsetTrailing`. A consequence of this is that "go to definition" now works on the last module name in an `import` block (issue [#4958](https://github.com/leanprover/lean4/issues/4958)).
### Language server, widgets, and IDE extensions
* [#4727](https://github.com/leanprover/lean4/pull/4727) makes it so that responses to info view requests come as soon as the relevant tactic has finished execution.
* [#4580](https://github.com/leanprover/lean4/pull/4580) makes it so that whitespace changes do not invalidate imports, and so starting to type the first declaration after imports should no longer cause them to reload.
* [#4780](https://github.com/leanprover/lean4/pull/4780) fixes an issue where hovering over unimported builtin names could result in a panic.
### Pretty printing
* [#4558](https://github.com/leanprover/lean4/pull/4558) fixes the `pp.instantiateMVars` setting and changes the default value to `true`.
* [#4631](https://github.com/leanprover/lean4/pull/4631) makes sure syntax nodes always run their formatters. Fixes an issue where if `ppSpace` appears in a `macro` or `elab` command then it does not format with a space.
* [#4665](https://github.com/leanprover/lean4/pull/4665) fixes a bug where pretty printed signatures (for example in `#check`) were overly hoverable due to `pp.tagAppFns` being set.
* [#4724](https://github.com/leanprover/lean4/pull/4724) makes `match` pretty printer be sensitive to `pp.explicit`, which makes hovering over a `match` in the Infoview show the underlying term.
* [#4764](https://github.com/leanprover/lean4/pull/4764) documents why anonymous constructor notation isn't pretty printed with flattening.
* [#4786](https://github.com/leanprover/lean4/pull/4786) adjusts the parenthesizer so that only the parentheses are hoverable, implemented by having the parentheses "steal" the term info from the parenthesized expression.
* [#4854](https://github.com/leanprover/lean4/pull/4854) allows arbitrarily long sequences of optional arguments to be omitted from the end of applications, versus the previous conservative behavior of omitting up to one optional argument.
### Library
* `Nat`
* [#4597](https://github.com/leanprover/lean4/pull/4597) adds bitwise lemmas `Nat.and_le_(left|right)`.
* [#4874](https://github.com/leanprover/lean4/pull/4874) adds simprocs for simplifying bit expressions.
* `Int`
* [#4903](https://github.com/leanprover/lean4/pull/4903) fixes performance of `HPow Int Nat Int` synthesis by rewriting it as a `NatPow Int` instance.
* `UInt*` and `Fin`
* [#4605](https://github.com/leanprover/lean4/pull/4605) adds lemmas.
* [#4629](https://github.com/leanprover/lean4/pull/4629) adds `*.and_toNat`.
* `Option`
* [#4599](https://github.com/leanprover/lean4/pull/4599) adds `get` lemmas.
* [#4600](https://github.com/leanprover/lean4/pull/4600) adds `Option.or`, a version of `Option.orElse` that is strict in the second argument.
* `GetElem`
* [#4603](https://github.com/leanprover/lean4/pull/4603) adds `getElem_congr` to help with rewriting indices.
* `List` and `Array`
* Upstreamed from Batteries: [#4586](https://github.com/leanprover/lean4/pull/4586) upstreams `List.attach` and `Array.attach`, [#4697](https://github.com/leanprover/lean4/pull/4697) upstreams `List.Subset` and `List.Sublist` and API, [#4706](https://github.com/leanprover/lean4/pull/4706) upstreams basic material on `List.Pairwise` and `List.Nodup`, [#4720](https://github.com/leanprover/lean4/pull/4720) upstreams more `List.erase` API, [#4836](https://github.com/leanprover/lean4/pull/4836) and [#4837](https://github.com/leanprover/lean4/pull/4837) upstream `List.IsPrefix`/`List.IsSuffix`/`List.IsInfix` and add `Decidable` instances, [#4855](https://github.com/leanprover/lean4/pull/4855) upstreams `List.tail`, `List.findIdx`, `List.indexOf`, `List.countP`, `List.count`, and `List.range'`, [#4856](https://github.com/leanprover/lean4/pull/4856) upstreams more List lemmas, [#4866](https://github.com/leanprover/lean4/pull/4866) upstreams `List.pairwise_iff_getElem`, [#4865](https://github.com/leanprover/lean4/pull/4865) upstreams `List.eraseIdx` lemmas.
* [#4687](https://github.com/leanprover/lean4/pull/4687) adjusts `List.replicate` simp lemmas and simprocs.
* [#4704](https://github.com/leanprover/lean4/pull/4704) adds characterizations of `List.Sublist`.
* [#4707](https://github.com/leanprover/lean4/pull/4707) adds simp normal form tests for `List.Pairwise` and `List.Nodup`.
* [#4708](https://github.com/leanprover/lean4/pull/4708) and [#4815](https://github.com/leanprover/lean4/pull/4815) reorganize lemmas on list getters.
* [#4765](https://github.com/leanprover/lean4/pull/4765) adds simprocs for literal array accesses such as `#[1,2,3,4,5][2]`.
* [#4790](https://github.com/leanprover/lean4/pull/4790) removes typeclass assumptions for `List.Nodup.eraseP`.
* [#4801](https://github.com/leanprover/lean4/pull/4801) adds efficient `usize` functions for array types.
* [#4820](https://github.com/leanprover/lean4/pull/4820) changes `List.filterMapM` to run left-to-right.
* [#4835](https://github.com/leanprover/lean4/pull/4835) fills in and cleans up gaps in List API.
* [#4843](https://github.com/leanprover/lean4/pull/4843), [#4868](https://github.com/leanprover/lean4/pull/4868), and [#4877](https://github.com/leanprover/lean4/pull/4877) correct `List.Subset` lemmas.
* [#4863](https://github.com/leanprover/lean4/pull/4863) splits `Init.Data.List.Lemmas` into function-specific files.
* [#4875](https://github.com/leanprover/lean4/pull/4875) fixes statement of `List.take_takeWhile`.
* Lemmas: [#4602](https://github.com/leanprover/lean4/pull/4602), [#4627](https://github.com/leanprover/lean4/pull/4627), [#4678](https://github.com/leanprover/lean4/pull/4678) for `List.head` and `list.getLast`, [#4723](https://github.com/leanprover/lean4/pull/4723) for `List.erase`, [#4742](https://github.com/leanprover/lean4/pull/4742)
* `ByteArray`
* [#4582](https://github.com/leanprover/lean4/pull/4582) eliminates `partial` from `ByteArray.toList` and `ByteArray.findIdx?`.
* `BitVec`
* [#4568](https://github.com/leanprover/lean4/pull/4568) adds recurrence theorems for bitblasting multiplication.
* [#4571](https://github.com/leanprover/lean4/pull/4571) adds `shiftLeftRec` lemmas.
* [#4872](https://github.com/leanprover/lean4/pull/4872) adds `ushiftRightRec` and lemmas.
* [#4873](https://github.com/leanprover/lean4/pull/4873) adds `getLsb_replicate`.
* `Std.HashMap` added:
* [#4583](https://github.com/leanprover/lean4/pull/4583) **adds `Std.HashMap`** as a verified replacement for `Lean.HashMap`. See the PR for naming differences, but [#4725](https://github.com/leanprover/lean4/pull/4725) renames `HashMap.remove` to `HashMap.erase`.
* [#4682](https://github.com/leanprover/lean4/pull/4682) adds `Inhabited` instances.
* [#4732](https://github.com/leanprover/lean4/pull/4732) improves `BEq` argument order in hash map lemmas.
* [#4759](https://github.com/leanprover/lean4/pull/4759) makes lemmas resolve instances via unification.
* [#4771](https://github.com/leanprover/lean4/pull/4771) documents that hash maps should be used linearly to avoid expensive copies.
* [#4791](https://github.com/leanprover/lean4/pull/4791) removes `bif` from hash map lemmas, which is inconvenient to work with in practice.
* [#4803](https://github.com/leanprover/lean4/pull/4803) adds more lemmas.
* `SMap`
* [#4690](https://github.com/leanprover/lean4/pull/4690) upstreams `SMap.foldM`.
* `BEq`
* [#4607](https://github.com/leanprover/lean4/pull/4607) adds `PartialEquivBEq`, `ReflBEq`, `EquivBEq`, and `LawfulHashable` classes.
* `IO`
* [#4660](https://github.com/leanprover/lean4/pull/4660) adds `IO.Process.Child.tryWait`.
* [#4747](https://github.com/leanprover/lean4/pull/4747), [#4730](https://github.com/leanprover/lean4/pull/4730), and [#4756](https://github.com/leanprover/lean4/pull/4756) add `×'` syntax for `PProd`. Adds a delaborator for `PProd` and `MProd` values to pretty print as flattened angle bracket tuples.
* **Other fixes or improvements**
* [#4604](https://github.com/leanprover/lean4/pull/4604) adds lemmas for cond.
* [#4619](https://github.com/leanprover/lean4/pull/4619) changes some definitions into theorems.
* [#4616](https://github.com/leanprover/lean4/pull/4616) fixes some names with duplicated namespaces.
* [#4620](https://github.com/leanprover/lean4/pull/4620) fixes simp lemmas flagged by the simpNF linter.
* [#4666](https://github.com/leanprover/lean4/pull/4666) makes the `Antisymm` class be a `Prop`.
* [#4621](https://github.com/leanprover/lean4/pull/4621) cleans up unused arguments flagged by linter.
* [#4680](https://github.com/leanprover/lean4/pull/4680) adds imports for orphaned `Init` modules.
* [#4679](https://github.com/leanprover/lean4/pull/4679) adds imports for orphaned `Std.Data` modules.
* [#4688](https://github.com/leanprover/lean4/pull/4688) adds forward and backward directions of `not_exists`.
* [#4689](https://github.com/leanprover/lean4/pull/4689) upstreams `eq_iff_true_of_subsingleton`.
* [#4709](https://github.com/leanprover/lean4/pull/4709) fixes precedence handling for `Repr` instances for negative numbers for `Int` and `Float`.
* [#4760](https://github.com/leanprover/lean4/pull/4760) renames `TC` ("transitive closure") to `Relation.TransGen`.
* [#4842](https://github.com/leanprover/lean4/pull/4842) fixes `List` deprecations.
* [#4852](https://github.com/leanprover/lean4/pull/4852) upstreams some Mathlib attributes applied to lemmas.
* [93ac63](https://github.com/leanprover/lean4/commit/93ac635a89daa5a8e8ef33ec96b0bcbb5d7ec1ea) improves proof.
* [#4862](https://github.com/leanprover/lean4/pull/4862) and [#4878](https://github.com/leanprover/lean4/pull/4878) generalize the universe for `PSigma.exists` and rename it to `Exists.of_psigma_prop`.
* Typos: [#4737](https://github.com/leanprover/lean4/pull/4737), [7d2155](https://github.com/leanprover/lean4/commit/7d2155943c67c743409420b4546d47fadf73af1c)
* Docs: [#4782](https://github.com/leanprover/lean4/pull/4782), [#4869](https://github.com/leanprover/lean4/pull/4869), [#4648](https://github.com/leanprover/lean4/pull/4648)
### Lean internals
* **Elaboration**
* [#4596](https://github.com/leanprover/lean4/pull/4596) enforces `isDefEqStuckEx` at `unstuckMVar` procedure, causing isDefEq to throw a stuck defeq exception if the metavariable was created in a previous level. This results in some better error messages, and it helps `rw` succeed in synthesizing instances (see issue [#2736](https://github.com/leanprover/lean4/issues/2736)).
* [#4713](https://github.com/leanprover/lean4/pull/4713) fixes deprecation warnings when there are overloaded symbols.
* `elab_as_elim` algorithm:
* [#4722](https://github.com/leanprover/lean4/pull/4722) adds check that inferred motive is type-correct.
* [#4800](https://github.com/leanprover/lean4/pull/4800) elaborates arguments for parameters appearing in the types of targets.
* [#4817](https://github.com/leanprover/lean4/pull/4817) makes the algorithm correctly handle eliminators with explicit motive arguments.
* [#4792](https://github.com/leanprover/lean4/pull/4792) adds term elaborator for `Lean.Parser.Term.namedPattern` (e.g. `n@(n' + 1)`) to report errors when used in non-pattern-matching contexts.
* [#4818](https://github.com/leanprover/lean4/pull/4818) makes anonymous dot notation work when the expected type is a pi-type-valued type synonym.
* **Typeclass inference**
* [#4646](https://github.com/leanprover/lean4/pull/4646) improves `synthAppInstances`, the function responsible for synthesizing instances for the `rw` and `apply` tactics. Adds a synthesis loop to handle functions whose instances need to be synthesized in a complex order.
* **Inductive types**
* [#4684](https://github.com/leanprover/lean4/pull/4684) (backported as [98ee78](https://github.com/leanprover/lean4/commit/98ee789990f91ff5935627787b537911ef8773c4)) refactors `InductiveVal` to have a `numNested : Nat` field instead of `isNested : Bool`. This modifies the kernel.
* **Definitions**
* [#4776](https://github.com/leanprover/lean4/pull/4776) improves performance of `Replacement.apply`.
* [#4712](https://github.com/leanprover/lean4/pull/4712) fixes `.eq_def` theorem generation with messy universes.
* [#4841](https://github.com/leanprover/lean4/pull/4841) improves success of finding `T.below x` hypothesis when transforming `match` statements for `IndPredBelow`.
* **Diagnostics and profiling**
* [#4611](https://github.com/leanprover/lean4/pull/4611) makes kernel diagnostics appear when `diagnostics` is enabled even if it is the only section.
* [#4753](https://github.com/leanprover/lean4/pull/4753) adds missing `profileitM` functions.
* [#4754](https://github.com/leanprover/lean4/pull/4754) adds `Lean.Expr.numObjs` to compute the number of allocated sub-expressions in a given expression, primarily for diagnosing performance issues.
* [#4769](https://github.com/leanprover/lean4/pull/4769) adds missing `withTraceNode`s to improve `trace.profiler` output.
* [#4781](https://github.com/leanprover/lean4/pull/4781) and [#4882](https://github.com/leanprover/lean4/pull/4882) make the "use `set_option diagnostics true`" message be conditional on current setting of `diagnostics`.
* **Performance**
* [#4767](https://github.com/leanprover/lean4/pull/4767), [#4775](https://github.com/leanprover/lean4/pull/4775), and [#4887](https://github.com/leanprover/lean4/pull/4887) add `ShareCommon.shareCommon'` for sharing common terms. In an example with 16 million subterms, it is 20 times faster than the old `shareCommon` procedure.
* [#4779](https://github.com/leanprover/lean4/pull/4779) ensures `Expr.replaceExpr` preserves DAG structure in `Expr`s.
* [#4783](https://github.com/leanprover/lean4/pull/4783) documents performance issue in `Expr.replaceExpr`.
* [#4794](https://github.com/leanprover/lean4/pull/4794), [#4797](https://github.com/leanprover/lean4/pull/4797), [#4798](https://github.com/leanprover/lean4/pull/4798) make `for_each` use precise cache.
* [#4795](https://github.com/leanprover/lean4/pull/4795) makes `Expr.find?` and `Expr.findExt?` use the kernel implementations.
* [#4799](https://github.com/leanprover/lean4/pull/4799) makes `Expr.replace` use the kernel implementation.
* [#4871](https://github.com/leanprover/lean4/pull/4871) makes `Expr.foldConsts` use a precise cache.
* [#4890](https://github.com/leanprover/lean4/pull/4890) makes `expr_eq_fn` use a precise cache.
* **Utilities**
* [#4453](https://github.com/leanprover/lean4/pull/4453) upstreams `ToExpr FilePath` and `compile_time_search_path%`.
* **Module system**
* [#4652](https://github.com/leanprover/lean4/pull/4652) fixes handling of `const2ModIdx` in `finalizeImport`, making it prefer the original module for a declaration when a declaration is re-declared.
* **Kernel**
* [#4637](https://github.com/leanprover/lean4/pull/4637) adds a check to prevent large `Nat` exponentiations from evaluating. Elaborator reduction is controlled by the option `exponentiation.threshold`.
* [#4683](https://github.com/leanprover/lean4/pull/4683) updates comments in `kernel/declaration.h`, making sure they reflect the current Lean 4 types.
* [#4796](https://github.com/leanprover/lean4/pull/4796) improves performance by using `replace` with a precise cache.
* [#4700](https://github.com/leanprover/lean4/pull/4700) improves performance by fixing the implementation of move constructors and move assignment operators. Expression copying was taking 10% of total runtime in some workloads. See issue [#4698](https://github.com/leanprover/lean4/issues/4698).
* [#4702](https://github.com/leanprover/lean4/pull/4702) improves performance in `replace_rec_fn::apply` by avoiding expression copies. These copies represented about 13% of time spent in `save_result` in some workloads. See the same issue.
* **Other fixes or improvements**
* [#4590](https://github.com/leanprover/lean4/pull/4590) fixes a typo in some constants and `trace.profiler.useHeartbeats`.
* [#4617](https://github.com/leanprover/lean4/pull/4617) add 'since' dates to `deprecated` attributes.
* [#4625](https://github.com/leanprover/lean4/pull/4625) improves the robustness of the constructor-as-variable test.
* [#4740](https://github.com/leanprover/lean4/pull/4740) extends test with nice example reported on Zulip.
* [#4766](https://github.com/leanprover/lean4/pull/4766) moves `Syntax.hasIdent` to be available earlier and shakes dependencies.
* [#4881](https://github.com/leanprover/lean4/pull/4881) splits out `Lean.Language.Lean.Types`.
* [#4893](https://github.com/leanprover/lean4/pull/4893) adds `LEAN_EXPORT` for `sharecommon` functions.
* Typos: [#4635](https://github.com/leanprover/lean4/pull/4635), [#4719](https://github.com/leanprover/lean4/pull/4719), [af40e6](https://github.com/leanprover/lean4/commit/af40e618111581c82fc44de922368a02208b499f)
* Docs: [#4748](https://github.com/leanprover/lean4/pull/4748) (`Command.Scope`)
### Compiler, runtime, and FFI
* [#4661](https://github.com/leanprover/lean4/pull/4661) moves `Std` from `libleanshared` to much smaller `libInit_shared`. This fixes the Windows build.
* [#4668](https://github.com/leanprover/lean4/pull/4668) fixes initialization, explicitly initializing `Std` in `lean_initialize`.
* [#4746](https://github.com/leanprover/lean4/pull/4746) adjusts `shouldExport` to exclude more symbols to get below Windows symbol limit. Some exceptions are added by [#4884](https://github.com/leanprover/lean4/pull/4884) and [#4956](https://github.com/leanprover/lean4/pull/4956) to support Verso.
* [#4778](https://github.com/leanprover/lean4/pull/4778) adds `lean_is_exclusive_obj` (`Lean.isExclusiveUnsafe`) and `lean_set_external_data`.
* [#4515](https://github.com/leanprover/lean4/pull/4515) fixes calling programs with spaces on Windows.
### Lake
* [#4735](https://github.com/leanprover/lean4/pull/4735) improves a number of elements related to Git checkouts, cloud releases,
and related error handling.
* On error, Lake now prints all top-level logs. Top-level logs are those produced by Lake outside of the job monitor (e.g., when cloning dependencies).
* When fetching a remote for a dependency, Lake now forcibly fetches tags. This prevents potential errors caused by a repository recreating tags already fetched.
* Git error handling is now more informative.
* The builtin package facets `release`, `optRelease`, `extraDep` are now captions in the same manner as other facets.
* `afterReleaseSync` and `afterReleaseAsync` now fetch `optRelease` rather than `release`.
* Added support for optional jobs, whose failure does not cause the whole build to failure. Now `optRelease` is such a job.
* [#4608](https://github.com/leanprover/lean4/pull/4608) adds draft CI workflow when creating new projects.
* [#4847](https://github.com/leanprover/lean4/pull/4847) adds CLI options to control log levels. The `--log-level=<lv>` controls the minimum log level Lake should output. For instance, `--log-level=error` will only print errors (not warnings or info). Also, adds an analogous `--fail-level` option to control the minimum log level for build failures. The existing `--iofail` and `--wfail` options are respectively equivalent to `--fail-level=info` and `--fail-level=warning`.
* Docs: [#4853](https://github.com/leanprover/lean4/pull/4853)
### DevOps/CI
* **Workflows**
* [#4531](https://github.com/leanprover/lean4/pull/4531) makes release trigger an update of `release.lean-lang.org`.
* [#4598](https://github.com/leanprover/lean4/pull/4598) adjusts `pr-release` to the new `lakefile.lean` syntax.
* [#4632](https://github.com/leanprover/lean4/pull/4632) makes `pr-release` use the correct tag name.
* [#4638](https://github.com/leanprover/lean4/pull/4638) adds ability to manually trigger nightly release.
* [#4640](https://github.com/leanprover/lean4/pull/4640) adds more debugging output for `restart-on-label` CI.
* [#4663](https://github.com/leanprover/lean4/pull/4663) bumps up waiting for 10s to 30s for `restart-on-label`.
* [#4664](https://github.com/leanprover/lean4/pull/4664) bumps versions for `actions/checkout` and `actions/upload-artifacts`.
* [582d6e](https://github.com/leanprover/lean4/commit/582d6e7f7168e0dc0819099edaace27d913b893e) bumps version for `actions/download-artifact`.
* [6d9718](https://github.com/leanprover/lean4/commit/6d971827e253a4dc08cda3cf6524d7f37819eb47) adds back dropped `check-stage3`.
* [0768ad](https://github.com/leanprover/lean4/commit/0768ad4eb9020af0777587a25a692d181e857c14) adds Jira sync (for FRO).
* [#4830](https://github.com/leanprover/lean4/pull/4830) adds support to report CI errors on FRO Zulip.
* [#4838](https://github.com/leanprover/lean4/pull/4838) adds trigger for `nightly_bump_toolchain` on mathlib4 upon nightly release.
* [abf420](https://github.com/leanprover/lean4/commit/abf4206e9c0fcadf17b6f7933434fd1580175015) fixes msys2.
* [#4895](https://github.com/leanprover/lean4/pull/4895) deprecates Nix-based builds and removes interactive components. Users who prefer the flake build should maintain it externally.
* [#4693](https://github.com/leanprover/lean4/pull/4693), [#4458](https://github.com/leanprover/lean4/pull/4458), and [#4876](https://github.com/leanprover/lean4/pull/4876) update the **release checklist**.
* [#4669](https://github.com/leanprover/lean4/pull/4669) fixes the "max dynamic symbols" metric per static library.
* [#4691](https://github.com/leanprover/lean4/pull/4691) improves compatibility of `tests/list_simp` for retesting simp normal forms with Mathlib.
* [#4806](https://github.com/leanprover/lean4/pull/4806) updates the quickstart guide.
* [c02aa9](https://github.com/leanprover/lean4/commit/c02aa98c6a08c3a9b05f68039c071085a4ef70d7) documents the **triage team** in the contribution guide.
### Breaking changes
* For `@[ext]`-generated `ext` and `ext_iff` lemmas, the `x` and `y` term arguments are now implicit. Furthermore these two lemmas are now protected ([#4543](https://github.com/leanprover/lean4/pull/4543)).
* Now `trace.profiler.useHearbeats` is `trace.profiler.useHeartbeats` ([#4590](https://github.com/leanprover/lean4/pull/4590)).
* A bugfix in the structural recursion code may in some cases break existing code, when a parameter of the type of the recursive argument is bound behind indices of that type. This can usually be fixed by reordering the parameters of the function ([#4672](https://github.com/leanprover/lean4/pull/4672)).
* Now `List.filterMapM` sequences monadic actions left-to-right ([#4820](https://github.com/leanprover/lean4/pull/4820)).
* The effect of the `variable` command on proofs of `theorem`s has been changed. Whether such section variables are accessible in the proof now depends only on the theorem signature and other top-level commands, not on the proof itself. This change ensures that
* the statement of a theorem is independent of its proof. In other words, changes in the proof cannot change the theorem statement.
* tactics such as `induction` cannot accidentally include a section variable.
* the proof can be elaborated in parallel to subsequent declarations in a future version of Lean.
The effect of `variable`s on the theorem header as well as on other kinds of declarations is unchanged.
Specifically, section variables are included if they
* are directly referenced by the theorem header,
* are included via the new `include` command in the current section and not subsequently mentioned in an `omit` statement,
* are directly referenced by any variable included by these rules, OR
* are instance-implicit variables that reference only variables included by these rules.
For porting, a new option `deprecated.oldSectionVars` is included to locally switch back to the old behavior.

312
releases/v4.12.0.md Normal file
View File

@@ -0,0 +1,312 @@
v4.12.0
----------
### Language features, tactics, and metaprograms
* `bv_decide` tactic. This release introduces a new tactic for proving goals involving `BitVec` and `Bool`. It reduces the goal to a SAT instance that is refuted by an external solver, and the resulting LRAT proof is checked in Lean. This is used to synthesize a proof of the goal by reflection. As this process uses verified algorithms, proofs generated by this tactic use `Lean.ofReduceBool`, so this tactic includes the Lean compiler as part of the trusted code base. The external solver CaDiCaL is included with Lean and does not need to be installed separately to make use of `bv_decide`.
For example, we can use `bv_decide` to verify that a bit twiddling formula leaves at most one bit set:
```lean
def popcount (x : BitVec 64) : BitVec 64 :=
let rec go (x pop : BitVec 64) : Nat → BitVec 64
| 0 => pop
| n + 1 => go (x >>> 2) (pop + (x &&& 1)) n
go x 0 64
example (x : BitVec 64) : popcount ((x &&& (x - 1)) ^^^ x) ≤ 1 := by
simp only [popcount, popcount.go]
bv_decide
```
When the external solver fails to refute the SAT instance generated by `bv_decide`, it can report a counterexample:
```lean
/--
error: The prover found a counterexample, consider the following assignment:
x = 0xffffffffffffffff#64
-/
#guard_msgs in
example (x : BitVec 64) : x < x + 1 := by
bv_decide
```
See `Lean.Elab.Tactic.BVDecide` for a more detailed overview, and look in `tests/lean/run/bv_*` for examples.
[#5013](https://github.com/leanprover/lean4/pull/5013), [#5074](https://github.com/leanprover/lean4/pull/5074), [#5100](https://github.com/leanprover/lean4/pull/5100), [#5113](https://github.com/leanprover/lean4/pull/5113), [#5137](https://github.com/leanprover/lean4/pull/5137), [#5203](https://github.com/leanprover/lean4/pull/5203), [#5212](https://github.com/leanprover/lean4/pull/5212), [#5220](https://github.com/leanprover/lean4/pull/5220).
* `simp` tactic
* [#4988](https://github.com/leanprover/lean4/pull/4988) fixes a panic in the `reducePow` simproc.
* [#5071](https://github.com/leanprover/lean4/pull/5071) exposes the `index` option to the `dsimp` tactic, introduced to `simp` in [#4202](https://github.com/leanprover/lean4/pull/4202).
* [#5159](https://github.com/leanprover/lean4/pull/5159) fixes a panic at `Fin.isValue` simproc.
* [#5167](https://github.com/leanprover/lean4/pull/5167) and [#5175](https://github.com/leanprover/lean4/pull/5175) rename the `simpCtorEq` simproc to `reduceCtorEq` and makes it optional. (See breaking changes.)
* [#5187](https://github.com/leanprover/lean4/pull/5187) ensures `reduceCtorEq` is enabled in the `norm_cast` tactic.
* [#5073](https://github.com/leanprover/lean4/pull/5073) modifies the simp debug trace messages to tag with "dpre" and "dpost" instead of "pre" and "post" when in definitional rewrite mode. [#5054](https://github.com/leanprover/lean4/pull/5054) explains the `reduce` steps for `trace.Debug.Meta.Tactic.simp` trace messages.
* `ext` tactic
* [#4996](https://github.com/leanprover/lean4/pull/4996) reduces default maximum iteration depth from 1000000 to 100.
* `induction` tactic
* [#5117](https://github.com/leanprover/lean4/pull/5117) fixes a bug where `let` bindings in minor premises wouldn't be counted correctly.
* `omega` tactic
* [#5157](https://github.com/leanprover/lean4/pull/5157) fixes a panic.
* `conv` tactic
* [#5149](https://github.com/leanprover/lean4/pull/5149) improves `arg n` to handle subsingleton instance arguments.
* [#5044](https://github.com/leanprover/lean4/pull/5044) upstreams the `#time` command.
* [#5079](https://github.com/leanprover/lean4/pull/5079) makes `#check` and `#reduce` typecheck the elaborated terms.
* **Incrementality**
* [#4974](https://github.com/leanprover/lean4/pull/4974) fixes regression where we would not interrupt elaboration of previous document versions.
* [#5004](https://github.com/leanprover/lean4/pull/5004) fixes a performance regression.
* [#5001](https://github.com/leanprover/lean4/pull/5001) disables incremental body elaboration in presence of `where` clauses in declarations.
* [#5018](https://github.com/leanprover/lean4/pull/5018) enables infotrees on the command line for ilean generation.
* [#5040](https://github.com/leanprover/lean4/pull/5040) and [#5056](https://github.com/leanprover/lean4/pull/5056) improve performance of info trees.
* [#5090](https://github.com/leanprover/lean4/pull/5090) disables incrementality in the `case .. | ..` tactic.
* [#5312](https://github.com/leanprover/lean4/pull/5312) fixes a bug where changing whitespace after the module header could break subsequent commands.
* **Definitions**
* [#5016](https://github.com/leanprover/lean4/pull/5016) and [#5066](https://github.com/leanprover/lean4/pull/5066) add `clean_wf` tactic to clean up tactic state in `decreasing_by`. This can be disabled with `set_option debug.rawDecreasingByGoal false`.
* [#5055](https://github.com/leanprover/lean4/pull/5055) unifies equational theorems between structural and well-founded recursion.
* [#5041](https://github.com/leanprover/lean4/pull/5041) allows mutually recursive functions to use different parameter names among the “fixed parameter prefix”
* [#4154](https://github.com/leanprover/lean4/pull/4154) and [#5109](https://github.com/leanprover/lean4/pull/5109) add fine-grained equational lemmas for non-recursive functions. See breaking changes.
* [#5129](https://github.com/leanprover/lean4/pull/5129) unifies equation lemmas for recursive and non-recursive definitions. The `backward.eqns.deepRecursiveSplit` option can be set to `false` to get the old behavior. See breaking changes.
* [#5141](https://github.com/leanprover/lean4/pull/5141) adds `f.eq_unfold` lemmas. Now Lean produces the following zoo of rewrite rules:
```
Option.map.eq_1 : Option.map f none = none
Option.map.eq_2 : Option.map f (some x) = some (f x)
Option.map.eq_def : Option.map f p = match o with | none => none | (some x) => some (f x)
Option.map.eq_unfold : Option.map = fun f p => match o with | none => none | (some x) => some (f x)
```
The `f.eq_unfold` variant is especially useful to rewrite with `rw` under binders.
* [#5136](https://github.com/leanprover/lean4/pull/5136) fixes bugs in recursion over predicates.
* **Variable inclusion**
* [#5206](https://github.com/leanprover/lean4/pull/5206) documents that `include` currently only applies to theorems.
* **Elaboration**
* [#4926](https://github.com/leanprover/lean4/pull/4926) fixes a bug where autoparam errors were associated to an incorrect source position.
* [#4833](https://github.com/leanprover/lean4/pull/4833) fixes an issue where cdot anonymous functions (e.g. `(· + ·)`) would not handle ambiguous notation correctly. Numbers the parameters, making this example expand as `fun x1 x2 => x1 + x2` rather than `fun x x_1 => x + x_1`.
* [#5037](https://github.com/leanprover/lean4/pull/5037) improves strength of the tactic that proves array indexing is in bounds.
* [#5119](https://github.com/leanprover/lean4/pull/5119) fixes a bug in the tactic that proves indexing is in bounds where it could loop in the presence of mvars.
* [#5072](https://github.com/leanprover/lean4/pull/5072) makes the structure type clickable in "not a field of structure" errors for structure instance notation.
* [#4717](https://github.com/leanprover/lean4/pull/4717) fixes a bug where mutual `inductive` commands could create terms that the kernel rejects.
* [#5142](https://github.com/leanprover/lean4/pull/5142) fixes a bug where `variable` could fail when mixing binder updates and declarations.
* **Other fixes or improvements**
* [#5118](https://github.com/leanprover/lean4/pull/5118) changes the definition of the `syntheticHole` parser so that hovering over `_` in `?_` gives the docstring for synthetic holes.
* [#5173](https://github.com/leanprover/lean4/pull/5173) uses the emoji variant selector for ✅️,❌️,💥️ in messages, improving fonts selection.
* [#5183](https://github.com/leanprover/lean4/pull/5183) fixes a bug in `rename_i` where implementation detail hypotheses could be renamed.
### Language server, widgets, and IDE extensions
* [#4821](https://github.com/leanprover/lean4/pull/4821) resolves two language server bugs that especially affect Windows users. (1) Editing the header could result in the watchdog not correctly restarting the file worker, which would lead to the file seemingly being processed forever. (2) On an especially slow Windows machine, we found that starting the language server would sometimes not succeed at all. This PR also resolves an issue where we would not correctly emit messages that we received while the file worker is being restarted to the corresponding file worker after the restart.
* [#5006](https://github.com/leanprover/lean4/pull/5006) updates the user widget manual.
* [#5193](https://github.com/leanprover/lean4/pull/5193) updates the quickstart guide with the new display name for the Lean 4 extension ("Lean 4").
* [#5185](https://github.com/leanprover/lean4/pull/5185) fixes a bug where over time "import out of date" messages would accumulate.
* [#4900](https://github.com/leanprover/lean4/pull/4900) improves ilean loading performance by about a factor of two. Optimizes the JSON parser and the conversion from JSON to Lean data structures; see PR description for details.
* **Other fixes or improvements**
* [#5031](https://github.com/leanprover/lean4/pull/5031) localizes an instance in `Lsp.Diagnostics`.
### Pretty printing
* [#4976](https://github.com/leanprover/lean4/pull/4976) introduces `@[app_delab]`, a macro for creating delaborators for particular constants. The `@[app_delab ident]` syntax resolves `ident` to its constant name `name` and then expands to `@[delab app.name]`.
* [#4982](https://github.com/leanprover/lean4/pull/4982) fixes a bug where the pretty printer assumed structure projections were type correct (such terms can appear in type mismatch errors). Improves hoverability of `#print` output for structures.
* [#5218](https://github.com/leanprover/lean4/pull/5218) and [#5239](https://github.com/leanprover/lean4/pull/5239) add `pp.exprSizes` debugging option. When true, each pretty printed expression is prefixed with `[size a/b/c]`, where `a` is the size without sharing, `b` is the actual size, and `c` is the size with the maximum possible sharing.
### Library
* [#5020](https://github.com/leanprover/lean4/pull/5020) swaps the parameters to `Membership.mem`. A purpose of this change is to make set-like `CoeSort` coercions to refer to the eta-expanded function `fun x => Membership.mem s x`, which can reduce in many computations. Another is that having the `s` argument first leads to better discrimination tree keys. (See breaking changes.)
* `Array`
* [#4970](https://github.com/leanprover/lean4/pull/4970) adds `@[ext]` attribute to `Array.ext`.
* [#4957](https://github.com/leanprover/lean4/pull/4957) deprecates `Array.get_modify`.
* `List`
* [#4995](https://github.com/leanprover/lean4/pull/4995) upstreams `List.findIdx` lemmas.
* [#5029](https://github.com/leanprover/lean4/pull/5029), [#5048](https://github.com/leanprover/lean4/pull/5048) and [#5132](https://github.com/leanprover/lean4/pull/5132) add `List.Sublist` lemmas, some upstreamed. [#5077](https://github.com/leanprover/lean4/pull/5077) fixes implicitness in refl/rfl lemma binders. add `List.Sublist` theorems.
* [#5047](https://github.com/leanprover/lean4/pull/5047) upstreams `List.Pairwise` lemmas.
* [#5053](https://github.com/leanprover/lean4/pull/5053), [#5124](https://github.com/leanprover/lean4/pull/5124), and [#5161](https://github.com/leanprover/lean4/pull/5161) add `List.find?/findSome?/findIdx?` theorems.
* [#5039](https://github.com/leanprover/lean4/pull/5039) adds `List.foldlRecOn` and `List.foldrRecOn` recursion principles to prove things about `List.foldl` and `List.foldr`.
* [#5069](https://github.com/leanprover/lean4/pull/5069) upstreams `List.Perm`.
* [#5092](https://github.com/leanprover/lean4/pull/5092) and [#5107](https://github.com/leanprover/lean4/pull/5107) add `List.mergeSort` and a fast `@[csimp]` implementation.
* [#5103](https://github.com/leanprover/lean4/pull/5103) makes the simp lemmas for `List.subset` more aggressive.
* [#5106](https://github.com/leanprover/lean4/pull/5106) changes the statement of `List.getLast?_cons`.
* [#5123](https://github.com/leanprover/lean4/pull/5123) and [#5158](https://github.com/leanprover/lean4/pull/5158) add `List.range` and `List.iota` lemmas.
* [#5130](https://github.com/leanprover/lean4/pull/5130) adds `List.join` lemmas.
* [#5131](https://github.com/leanprover/lean4/pull/5131) adds `List.append` lemmas.
* [#5152](https://github.com/leanprover/lean4/pull/5152) adds `List.erase(|P|Idx)` lemmas.
* [#5127](https://github.com/leanprover/lean4/pull/5127) makes miscellaneous lemma updates.
* [#5153](https://github.com/leanprover/lean4/pull/5153) and [#5160](https://github.com/leanprover/lean4/pull/5160) add lemmas about `List.attach` and `List.pmap`.
* [#5164](https://github.com/leanprover/lean4/pull/5164), [#5177](https://github.com/leanprover/lean4/pull/5177), and [#5215](https://github.com/leanprover/lean4/pull/5215) add `List.find?` and `List.range'/range/iota` lemmas.
* [#5196](https://github.com/leanprover/lean4/pull/5196) adds `List.Pairwise_erase` and related lemmas.
* [#5151](https://github.com/leanprover/lean4/pull/5151) and [#5163](https://github.com/leanprover/lean4/pull/5163) improve confluence of `List` simp lemmas. [#5105](https://github.com/leanprover/lean4/pull/5105) and [#5102](https://github.com/leanprover/lean4/pull/5102) adjust `List` simp lemmas.
* [#5178](https://github.com/leanprover/lean4/pull/5178) removes `List.getLast_eq_iff_getLast_eq_some` as a simp lemma.
* [#5210](https://github.com/leanprover/lean4/pull/5210) reverses the meaning of `List.getElem_drop` and `List.getElem_drop'`.
* [#5214](https://github.com/leanprover/lean4/pull/5214) moves `@[csimp]` lemmas earlier where possible.
* `Nat` and `Int`
* [#5104](https://github.com/leanprover/lean4/pull/5104) adds `Nat.add_left_eq_self` and relatives.
* [#5146](https://github.com/leanprover/lean4/pull/5146) adds missing `Nat.and_xor_distrib_(left|right)`.
* [#5148](https://github.com/leanprover/lean4/pull/5148) and [#5190](https://github.com/leanprover/lean4/pull/5190) improve `Nat` and `Int` simp lemma confluence.
* [#5165](https://github.com/leanprover/lean4/pull/5165) adjusts `Int` simp lemmas.
* [#5166](https://github.com/leanprover/lean4/pull/5166) adds `Int` lemmas relating `neg` and `emod`/`mod`.
* [#5208](https://github.com/leanprover/lean4/pull/5208) reverses the direction of the `Int.toNat_sub` simp lemma.
* [#5209](https://github.com/leanprover/lean4/pull/5209) adds `Nat.bitwise` lemmas.
* [#5230](https://github.com/leanprover/lean4/pull/5230) corrects the docstrings for integer division and modulus.
* `Option`
* [#5128](https://github.com/leanprover/lean4/pull/5128) and [#5154](https://github.com/leanprover/lean4/pull/5154) add `Option` lemmas.
* `BitVec`
* [#4889](https://github.com/leanprover/lean4/pull/4889) adds `sshiftRight` bitblasting.
* [#4981](https://github.com/leanprover/lean4/pull/4981) adds `Std.Associative` and `Std.Commutative` instances for `BitVec.[and|or|xor]`.
* [#4913](https://github.com/leanprover/lean4/pull/4913) enables `missingDocs` error for `BitVec` modules.
* [#4930](https://github.com/leanprover/lean4/pull/4930) makes parameter names for `BitVec` more consistent.
* [#5098](https://github.com/leanprover/lean4/pull/5098) adds `BitVec.intMin`. Introduces `boolToPropSimps` simp set for converting from boolean to propositional expressions.
* [#5200](https://github.com/leanprover/lean4/pull/5200) and [#5217](https://github.com/leanprover/lean4/pull/5217) rename `BitVec.getLsb` to `BitVec.getLsbD`, etc., to bring naming in line with `List`/`Array`/etc.
* **Theorems:** [#4977](https://github.com/leanprover/lean4/pull/4977), [#4951](https://github.com/leanprover/lean4/pull/4951), [#4667](https://github.com/leanprover/lean4/pull/4667), [#5007](https://github.com/leanprover/lean4/pull/5007), [#4997](https://github.com/leanprover/lean4/pull/4997), [#5083](https://github.com/leanprover/lean4/pull/5083), [#5081](https://github.com/leanprover/lean4/pull/5081), [#4392](https://github.com/leanprover/lean4/pull/4392)
* `UInt`
* [#4514](https://github.com/leanprover/lean4/pull/4514) fixes naming convention for `UInt` lemmas.
* `Std.HashMap` and `Std.HashSet`
* [#4943](https://github.com/leanprover/lean4/pull/4943) deprecates variants of hash map query methods. (See breaking changes.)
* [#4917](https://github.com/leanprover/lean4/pull/4917) switches the library and Lean to `Std.HashMap` and `Std.HashSet` almost everywhere.
* [#4954](https://github.com/leanprover/lean4/pull/4954) deprecates `Lean.HashMap` and `Lean.HashSet`.
* [#5023](https://github.com/leanprover/lean4/pull/5023) cleans up lemma parameters.
* `Std.Sat` (for `bv_decide`)
* [#4933](https://github.com/leanprover/lean4/pull/4933) adds definitions of SAT and CNF.
* [#4953](https://github.com/leanprover/lean4/pull/4953) defines "and-inverter graphs" (AIGs) as described in section 3 of [Davis-Swords 2013](https://arxiv.org/pdf/1304.7861.pdf).
* **Parsec**
* [#4774](https://github.com/leanprover/lean4/pull/4774) generalizes the `Parsec` library, allowing parsing of iterable data beyond `String` such as `ByteArray`. (See breaking changes.)
* [#5115](https://github.com/leanprover/lean4/pull/5115) moves `Lean.Data.Parsec` to `Std.Internal.Parsec` for bootstrappng reasons.
* `Thunk`
* [#4969](https://github.com/leanprover/lean4/pull/4969) upstreams `Thunk.ext`.
* **IO**
* [#4973](https://github.com/leanprover/lean4/pull/4973) modifies `IO.FS.lines` to handle `\r\n` on all operating systems instead of just on Windows.
* [#5125](https://github.com/leanprover/lean4/pull/5125) adds `createTempFile` and `withTempFile` for creating temporary files that can only be read and written by the current user.
* **Other fixes or improvements**
* [#4945](https://github.com/leanprover/lean4/pull/4945) adds `Array`, `Bool` and `Prod` utilities from LeanSAT.
* [#4960](https://github.com/leanprover/lean4/pull/4960) adds `Relation.TransGen.trans`.
* [#5012](https://github.com/leanprover/lean4/pull/5012) states `WellFoundedRelation Nat` using `<`, not `Nat.lt`.
* [#5011](https://github.com/leanprover/lean4/pull/5011) uses `` instead of `Not (Eq ...)` in `Fin.ne_of_val_ne`.
* [#5197](https://github.com/leanprover/lean4/pull/5197) upstreams `Fin.le_antisymm`.
* [#5042](https://github.com/leanprover/lean4/pull/5042) reduces usage of `refine'`.
* [#5101](https://github.com/leanprover/lean4/pull/5101) adds about `if-then-else` and `Option`.
* [#5112](https://github.com/leanprover/lean4/pull/5112) adds basic instances for `ULift` and `PLift`.
* [#5133](https://github.com/leanprover/lean4/pull/5133) and [#5168](https://github.com/leanprover/lean4/pull/5168) make fixes from running the simpNF linter over Lean.
* [#5156](https://github.com/leanprover/lean4/pull/5156) removes a bad simp lemma in `omega` theory.
* [#5155](https://github.com/leanprover/lean4/pull/5155) improves confluence of `Bool` simp lemmas.
* [#5162](https://github.com/leanprover/lean4/pull/5162) improves confluence of `Function.comp` simp lemmas.
* [#5191](https://github.com/leanprover/lean4/pull/5191) improves confluence of `if-then-else` simp lemmas.
* [#5147](https://github.com/leanprover/lean4/pull/5147) adds `@[elab_as_elim]` to `Quot.rec`, `Nat.strongInductionOn` and `Nat.casesStrongInductionOn`, and also renames the latter two to `Nat.strongRecOn` and `Nat.casesStrongRecOn` (deprecated in [#5179](https://github.com/leanprover/lean4/pull/5179)).
* [#5180](https://github.com/leanprover/lean4/pull/5180) disables some simp lemmas with bad discrimination tree keys.
* [#5189](https://github.com/leanprover/lean4/pull/5189) cleans up internal simp lemmas that had leaked.
* [#5198](https://github.com/leanprover/lean4/pull/5198) cleans up `allowUnsafeReducibility`.
* [#5229](https://github.com/leanprover/lean4/pull/5229) removes unused lemmas from some `simp` tactics.
* [#5199](https://github.com/leanprover/lean4/pull/5199) removes >6 month deprecations.
### Lean internals
* **Performance**
* Some core algorithms have been rewritten in C++ for performance.
* [#4910](https://github.com/leanprover/lean4/pull/4910) and [#4912](https://github.com/leanprover/lean4/pull/4912) reimplement `instantiateLevelMVars`.
* [#4915](https://github.com/leanprover/lean4/pull/4915), [#4922](https://github.com/leanprover/lean4/pull/4922), and [#4931](https://github.com/leanprover/lean4/pull/4931) reimplement `instantiateExprMVars`, 30% faster on a benchmark.
* [#4934](https://github.com/leanprover/lean4/pull/4934) has optimizations for the kernel's `Expr` equality test.
* [#4990](https://github.com/leanprover/lean4/pull/4990) fixes bug in hashing for the kernel's `Expr` equality test.
* [#4935](https://github.com/leanprover/lean4/pull/4935) and [#4936](https://github.com/leanprover/lean4/pull/4936) skip some `PreDefinition` transformations if they are not needed.
* [#5225](https://github.com/leanprover/lean4/pull/5225) adds caching for visited exprs at `CheckAssignmentQuick` in `ExprDefEq`.
* [#5226](https://github.com/leanprover/lean4/pull/5226) maximizes term sharing at `instantiateMVarDeclMVars`, used by `runTactic`.
* **Diagnostics and profiling**
* [#4923](https://github.com/leanprover/lean4/pull/4923) adds profiling for `instantiateMVars` in `Lean.Elab.MutualDef`, which can be a bottleneck there.
* [#4924](https://github.com/leanprover/lean4/pull/4924) adds diagnostics for large theorems, controlled by the `diagnostics.threshold.proofSize` option.
* [#4897](https://github.com/leanprover/lean4/pull/4897) improves display of diagnostic results.
* **Other fixes or improvements**
* [#4921](https://github.com/leanprover/lean4/pull/4921) cleans up `Expr.betaRev`.
* [#4940](https://github.com/leanprover/lean4/pull/4940) fixes tests by not writing directly to stdout, which is unreliable now that elaboration and reporting are executed in separate threads.
* [#4955](https://github.com/leanprover/lean4/pull/4955) documents that `stderrAsMessages` is now the default on the command line as well.
* [#4647](https://github.com/leanprover/lean4/pull/4647) adjusts documentation for building on macOS.
* [#4987](https://github.com/leanprover/lean4/pull/4987) makes regular mvar assignments take precedence over delayed ones in `instantiateMVars`. Normally delayed assignment metavariables are never directly assigned, but on errors Lean assigns `sorry` to unassigned metavariables.
* [#4967](https://github.com/leanprover/lean4/pull/4967) adds linter name to errors when a linter crashes.
* [#5043](https://github.com/leanprover/lean4/pull/5043) cleans up command line snapshots logic.
* [#5067](https://github.com/leanprover/lean4/pull/5067) minimizes some imports.
* [#5068](https://github.com/leanprover/lean4/pull/5068) generalizes the monad for `addMatcherInfo`.
* [f71a1f](https://github.com/leanprover/lean4/commit/f71a1fb4ae958fccb3ad4d48786a8f47ced05c15) adds missing test for [#5126](https://github.com/leanprover/lean4/issues/5126).
* [#5201](https://github.com/leanprover/lean4/pull/5201) restores a test.
* [#3698](https://github.com/leanprover/lean4/pull/3698) fixes a bug where label attributes did not pass on the attribute kind.
* Typos: [#5080](https://github.com/leanprover/lean4/pull/5080), [#5150](https://github.com/leanprover/lean4/pull/5150), [#5202](https://github.com/leanprover/lean4/pull/5202)
### Compiler, runtime, and FFI
* [#3106](https://github.com/leanprover/lean4/pull/3106) moves frontend to new snapshot architecture. Note that `Frontend.processCommand` and `FrontendM` are no longer used by Lean core, but they will be preserved.
* [#4919](https://github.com/leanprover/lean4/pull/4919) adds missing include in runtime for `AUTO_THREAD_FINALIZATION` feature on Windows.
* [#4941](https://github.com/leanprover/lean4/pull/4941) adds more `LEAN_EXPORT`s for Windows.
* [#4911](https://github.com/leanprover/lean4/pull/4911) improves formatting of CLI help text for the frontend.
* [#4950](https://github.com/leanprover/lean4/pull/4950) improves file reading and writing.
* `readBinFile` and `readFile` now only require two system calls (`stat` + `read`) instead of one `read` per 1024 byte chunk.
* `Handle.getLine` and `Handle.putStr` no longer get tripped up by NUL characters.
* [#4971](https://github.com/leanprover/lean4/pull/4971) handles the SIGBUS signal when detecting stack overflows.
* [#5062](https://github.com/leanprover/lean4/pull/5062) avoids overwriting existing signal handlers, like in [rust-lang/rust#69685](https://github.com/rust-lang/rust/pull/69685).
* [#4860](https://github.com/leanprover/lean4/pull/4860) improves workarounds for building on Windows. Splits `libleanshared` on Windows to avoid symbol limit, removes the `LEAN_EXPORT` denylist workaround, adds missing `LEAN_EXPORT`s.
* [#4952](https://github.com/leanprover/lean4/pull/4952) output panics into Lean's redirected stderr, ensuring panics ARE visible as regular messages in the language server and properly ordered in relation to other messages on the command line.
* [#4963](https://github.com/leanprover/lean4/pull/4963) links LibUV.
### Lake
* [#5030](https://github.com/leanprover/lean4/pull/5030) removes dead code.
* [#4770](https://github.com/leanprover/lean4/pull/4770) adds additional fields to the package configuration which will be used by Reservoir. See the PR description for details.
### DevOps/CI
* [#4914](https://github.com/leanprover/lean4/pull/4914) and [#4937](https://github.com/leanprover/lean4/pull/4937) improve the release checklist.
* [#4925](https://github.com/leanprover/lean4/pull/4925) ignores stale leanpkg tests.
* [#5003](https://github.com/leanprover/lean4/pull/5003) upgrades `actions/cache` in CI.
* [#5010](https://github.com/leanprover/lean4/pull/5010) sets `save-always` in cache actions in CI.
* [#5008](https://github.com/leanprover/lean4/pull/5008) adds more libuv search patterns for the speedcenter.
* [#5009](https://github.com/leanprover/lean4/pull/5009) reduce number of runs in the speedcenter for "fast" benchmarks from 10 to 3.
* [#5014](https://github.com/leanprover/lean4/pull/5014) adjusts lakefile editing to use new `git` syntax in `pr-release` workflow.
* [#5025](https://github.com/leanprover/lean4/pull/5025) has `pr-release` workflow pass `--retry` to `curl`.
* [#5022](https://github.com/leanprover/lean4/pull/5022) builds MacOS Aarch64 release for PRs by default.
* [#5045](https://github.com/leanprover/lean4/pull/5045) adds libuv to the required packages heading in macos docs.
* [#5034](https://github.com/leanprover/lean4/pull/5034) fixes the install name of `libleanshared_1` on macOS.
* [#5051](https://github.com/leanprover/lean4/pull/5051) fixes Windows stage 0.
* [#5052](https://github.com/leanprover/lean4/pull/5052) fixes 32bit stage 0 builds in CI.
* [#5057](https://github.com/leanprover/lean4/pull/5057) avoids rebuilding `leanmanifest` in each build.
* [#5099](https://github.com/leanprover/lean4/pull/5099) makes `restart-on-label` workflow also filter by commit SHA.
* [#4325](https://github.com/leanprover/lean4/pull/4325) adds CaDiCaL.
### Breaking changes
* [LibUV](https://libuv.org/) is now required to build Lean. This change only affects developers who compile Lean themselves instead of obtaining toolchains via `elan`. We have updated the official build instructions with information on how to obtain LibUV on our supported platforms. ([#4963](https://github.com/leanprover/lean4/pull/4963))
* Recursive definitions with a `decreasing_by` clause that begins with `simp_wf` may break. Try removing `simp_wf` or replacing it with `simp`. ([#5016](https://github.com/leanprover/lean4/pull/5016))
* The behavior of `rw [f]` where `f` is a non-recursive function defined by pattern matching changed.
For example, preciously, `rw [Option.map]` would rewrite `Option.map f o` to `match o with … `. Now this rewrite fails because it will use the equational lemmas, and these require constructors just like for `List.map`.
Remedies:
* Split on `o` before rewriting.
* Use `rw [Option.map.eq_def]`, which rewrites any (saturated) application of `Option.map`.
* Use `set_option backward.eqns.nonrecursive false` when *defining* the function in question.
([#4154](https://github.com/leanprover/lean4/pull/4154))
* The unified handling of equation lemmas for recursive and non-recursive functions can break existing code, as there now can be extra equational lemmas:
* Explicit uses of `f.eq_2` might have to be adjusted if the numbering changed.
* Uses of `rw [f]` or `simp [f]` may no longer apply if they previously matched (and introduced a `match` statement), when the equational lemmas got more fine-grained.
In this case either case analysis on the parameters before rewriting helps, or setting the option `backward.eqns.deepRecursiveSplit false` while *defining* the function.
([#5129](https://github.com/leanprover/lean4/pull/5129), [#5207](https://github.com/leanprover/lean4/pull/5207))
* The `reduceCtorEq` simproc is now optional, and it might need to be included in lists of simp lemmas, like `simp only [reduceCtorEq]`. This simproc is responsible for reducing equalities of constructors. ([#5167](https://github.com/leanprover/lean4/pull/5167))
* `Nat.strongInductionOn` is now `Nat.strongRecOn` and `Nat.caseStrongInductionOn` to `Nat.caseStrongRecOn`. ([#5147](https://github.com/leanprover/lean4/pull/5147))
* The parameters to `Membership.mem` have been swapped, which affects all `Membership` instances. ([#5020](https://github.com/leanprover/lean4/pull/5020))
* The meanings of `List.getElem_drop` and `List.getElem_drop'` have been reversed and the first is now a simp lemma. ([#5210](https://github.com/leanprover/lean4/pull/5210))
* The `Parsec` library has moved from `Lean.Data.Parsec` to `Std.Internal.Parsec`. The `Parsec` type is now more general with a parameter for an iterable. Users parsing strings can migrate to `Parser` in the `Std.Internal.Parsec.String` namespace, which also includes string-focused parsing combinators. ([#4774](https://github.com/leanprover/lean4/pull/4774))
* The `Lean` module has switched from `Lean.HashMap` and `Lean.HashSet` to `Std.HashMap` and `Std.HashSet` ([#4943](https://github.com/leanprover/lean4/pull/4943)). `Lean.HashMap` and `Lean.HashSet` are now deprecated ([#4954](https://github.com/leanprover/lean4/pull/4954)) and will be removed in a future release. Users of `Lean` APIs that interact with hash maps, for example `Lean.Environment.const2ModIdx`, might encounter minor breakage due to the following changes from `Lean.HashMap` to `Std.HashMap`:
* query functions use the term `get` instead of `find`, ([#4943](https://github.com/leanprover/lean4/pull/4943))
* the notation `map[key]` no longer returns an optional value but instead expects a proof that the key is present in the map. The previous behavior is available via the `map[key]?` notation.

312
releases/v4.13.0.md Normal file
View File

@@ -0,0 +1,312 @@
v4.13.0
----------
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.12.0...v4.13.0
### Language features, tactics, and metaprograms
* `structure` command
* [#5511](https://github.com/leanprover/lean4/pull/5511) allows structure parents to be type synonyms.
* [#5531](https://github.com/leanprover/lean4/pull/5531) allows default values for structure fields to be noncomputable.
* `rfl` and `apply_rfl` tactics
* [#3714](https://github.com/leanprover/lean4/pull/3714), [#3718](https://github.com/leanprover/lean4/pull/3718) improve the `rfl` tactic and give better error messages.
* [#3772](https://github.com/leanprover/lean4/pull/3772) makes `rfl` no longer use kernel defeq for ground terms.
* [#5329](https://github.com/leanprover/lean4/pull/5329) tags `Iff.refl` with `@[refl]` (@Parcly-Taxel)
* [#5359](https://github.com/leanprover/lean4/pull/5359) ensures that the `rfl` tactic tries `Iff.rfl` (@Parcly-Taxel)
* `unfold` tactic
* [#4834](https://github.com/leanprover/lean4/pull/4834) let `unfold` do zeta-delta reduction of local definitions, incorporating functionality of the Mathlib `unfold_let` tactic.
* `omega` tactic
* [#5382](https://github.com/leanprover/lean4/pull/5382) fixes spurious error in [#5315](https://github.com/leanprover/lean4/issues/5315)
* [#5523](https://github.com/leanprover/lean4/pull/5523) supports `Int.toNat`
* `simp` tactic
* [#5479](https://github.com/leanprover/lean4/pull/5479) lets `simp` apply rules with higher-order patterns.
* `induction` tactic
* [#5494](https://github.com/leanprover/lean4/pull/5494) fixes `induction`s "pre-tactic" block to always be indented, avoiding unintended uses of it.
* `ac_nf` tactic
* [#5524](https://github.com/leanprover/lean4/pull/5524) adds `ac_nf`, a counterpart to `ac_rfl`, for normalizing expressions with respect to associativity and commutativity. Tests it with `BitVec` expressions.
* `bv_decide`
* [#5211](https://github.com/leanprover/lean4/pull/5211) makes `extractLsb'` the primitive `bv_decide` understands, rather than `extractLsb` (@alexkeizer)
* [#5365](https://github.com/leanprover/lean4/pull/5365) adds `bv_decide` diagnoses.
* [#5375](https://github.com/leanprover/lean4/pull/5375) adds `bv_decide` normalization rules for `ofBool (a.getLsbD i)` and `ofBool a[i]` (@alexkeizer)
* [#5423](https://github.com/leanprover/lean4/pull/5423) enhances the rewriting rules of `bv_decide`
* [#5433](https://github.com/leanprover/lean4/pull/5433) presents the `bv_decide` counterexample at the API
* [#5484](https://github.com/leanprover/lean4/pull/5484) handles `BitVec.ofNat` with `Nat` fvars in `bv_decide`
* [#5506](https://github.com/leanprover/lean4/pull/5506), [#5507](https://github.com/leanprover/lean4/pull/5507) add `bv_normalize` rules.
* [#5568](https://github.com/leanprover/lean4/pull/5568) generalize the `bv_normalize` pipeline to support more general preprocessing passes
* [#5573](https://github.com/leanprover/lean4/pull/5573) gets `bv_normalize` up-to-date with the current `BitVec` rewrites
* Cleanups: [#5408](https://github.com/leanprover/lean4/pull/5408), [#5493](https://github.com/leanprover/lean4/pull/5493), [#5578](https://github.com/leanprover/lean4/pull/5578)
* Elaboration improvements
* [#5266](https://github.com/leanprover/lean4/pull/5266) preserve order of overapplied arguments in `elab_as_elim` procedure.
* [#5510](https://github.com/leanprover/lean4/pull/5510) generalizes `elab_as_elim` to allow arbitrary motive applications.
* [#5283](https://github.com/leanprover/lean4/pull/5283), [#5512](https://github.com/leanprover/lean4/pull/5512) refine how named arguments suppress explicit arguments. Breaking change: some previously omitted explicit arguments may need explicit `_` arguments now.
* [#5376](https://github.com/leanprover/lean4/pull/5376) modifies projection instance binder info for instances, making parameters that are instance implicit in the type be implicit.
* [#5402](https://github.com/leanprover/lean4/pull/5402) localizes universe metavariable errors to `let` bindings and `fun` binders if possible. Makes "cannot synthesize metavariable" errors take precedence over unsolved universe level errors.
* [#5419](https://github.com/leanprover/lean4/pull/5419) must not reduce `ite` in the discriminant of `match`-expression when reducibility setting is `.reducible`
* [#5474](https://github.com/leanprover/lean4/pull/5474) have autoparams report parameter/field on failure
* [#5530](https://github.com/leanprover/lean4/pull/5530) makes automatic instance names about types with hygienic names be hygienic.
* Deriving handlers
* [#5432](https://github.com/leanprover/lean4/pull/5432) makes `Repr` deriving instance handle explicit type parameters
* Functional induction
* [#5364](https://github.com/leanprover/lean4/pull/5364) adds more equalities in context, more careful cleanup.
* Linters
* [#5335](https://github.com/leanprover/lean4/pull/5335) fixes the unused variables linter complaining about match/tactic combinations
* [#5337](https://github.com/leanprover/lean4/pull/5337) fixes the unused variables linter complaining about some wildcard patterns
* Other fixes
* [#4768](https://github.com/leanprover/lean4/pull/4768) fixes a parse error when `..` appears with a `.` on the next line
* Metaprogramming
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
* [#5401](https://github.com/leanprover/lean4/pull/5401) instance for `Inhabited (TacticM α)` (@alexkeizer)
* [#5412](https://github.com/leanprover/lean4/pull/5412) expose Kernel.check for debugging purposes
* [#5556](https://github.com/leanprover/lean4/pull/5556) improves the "invalid projection" type inference error in `inferType`.
* [#5587](https://github.com/leanprover/lean4/pull/5587) allows `MVarId.assertHypotheses` to set `BinderInfo` and `LocalDeclKind`.
* [#5588](https://github.com/leanprover/lean4/pull/5588) adds `MVarId.tryClearMany'`, a variant of `MVarId.tryClearMany`.
### Language server, widgets, and IDE extensions
* [#5205](https://github.com/leanprover/lean4/pull/5205) decreases the latency of auto-completion in tactic blocks.
* [#5237](https://github.com/leanprover/lean4/pull/5237) fixes symbol occurrence highlighting in VS Code not highlighting occurrences when moving the text cursor into the identifier from the right.
* [#5257](https://github.com/leanprover/lean4/pull/5257) fixes several instances of incorrect auto-completions being reported.
* [#5299](https://github.com/leanprover/lean4/pull/5299) allows auto-completion to report completions for global identifiers when the elaborator fails to provide context-specific auto-completions.
* [#5312](https://github.com/leanprover/lean4/pull/5312) fixes the server breaking when changing whitespace after the module header.
* [#5322](https://github.com/leanprover/lean4/pull/5322) fixes several instances of auto-completion reporting non-existent namespaces.
* [#5428](https://github.com/leanprover/lean4/pull/5428) makes sure to always report some recent file range as progress when waiting for elaboration.
### Pretty printing
* [#4979](https://github.com/leanprover/lean4/pull/4979) make pretty printer escape identifiers that are tokens.
* [#5389](https://github.com/leanprover/lean4/pull/5389) makes formatter use the current token table.
* [#5513](https://github.com/leanprover/lean4/pull/5513) use breakable instead of unbreakable whitespace when formatting tokens.
### Library
* [#5222](https://github.com/leanprover/lean4/pull/5222) reduces allocations in `Json.compress`.
* [#5231](https://github.com/leanprover/lean4/pull/5231) upstreams `Zero` and `NeZero`
* [#5292](https://github.com/leanprover/lean4/pull/5292) refactors `Lean.Elab.Deriving.FromToJson` (@arthur-adjedj)
* [#5415](https://github.com/leanprover/lean4/pull/5415) implements `Repr Empty` (@TomasPuverle)
* [#5421](https://github.com/leanprover/lean4/pull/5421) implements `To/FromJSON Empty` (@TomasPuverle)
* Logic
* [#5263](https://github.com/leanprover/lean4/pull/5263) allows simplifying `dite_not`/`decide_not` with only `Decidable (¬p)`.
* [#5268](https://github.com/leanprover/lean4/pull/5268) fixes binders on `ite_eq_left_iff`
* [#5284](https://github.com/leanprover/lean4/pull/5284) turns off `Inhabited (Sum α β)` instances
* [#5355](https://github.com/leanprover/lean4/pull/5355) adds simp lemmas for `LawfulBEq`
* [#5374](https://github.com/leanprover/lean4/pull/5374) add `Nonempty` instances for products, allowing more `partial` functions to elaborate successfully
* [#5447](https://github.com/leanprover/lean4/pull/5447) updates Pi instance names
* [#5454](https://github.com/leanprover/lean4/pull/5454) makes some instance arguments implicit
* [#5456](https://github.com/leanprover/lean4/pull/5456) adds `heq_comm`
* [#5529](https://github.com/leanprover/lean4/pull/5529) moves `@[simp]` from `exists_prop'` to `exists_prop`
* `Bool`
* [#5228](https://github.com/leanprover/lean4/pull/5228) fills gaps in Bool lemmas
* [#5332](https://github.com/leanprover/lean4/pull/5332) adds notation `^^` for Bool.xor
* [#5351](https://github.com/leanprover/lean4/pull/5351) removes `_root_.and` (and or/not/xor) and instead exports/uses `Bool.and` (etc.).
* `BitVec`
* [#5240](https://github.com/leanprover/lean4/pull/5240) removes BitVec simps with complicated RHS
* [#5247](https://github.com/leanprover/lean4/pull/5247) `BitVec.getElem_zeroExtend`
* [#5248](https://github.com/leanprover/lean4/pull/5248) simp lemmas for BitVec, improving confluence
* [#5249](https://github.com/leanprover/lean4/pull/5249) removes `@[simp]` from some BitVec lemmas
* [#5252](https://github.com/leanprover/lean4/pull/5252) changes `BitVec.intMin/Max` from abbrev to def
* [#5278](https://github.com/leanprover/lean4/pull/5278) adds `BitVec.getElem_truncate` (@tobiasgrosser)
* [#5281](https://github.com/leanprover/lean4/pull/5281) adds udiv/umod bitblasting for `bv_decide` (@bollu)
* [#5297](https://github.com/leanprover/lean4/pull/5297) `BitVec` unsigned order theoretic results
* [#5313](https://github.com/leanprover/lean4/pull/5313) adds more basic BitVec ordering theory for UInt
* [#5314](https://github.com/leanprover/lean4/pull/5314) adds `toNat_sub_of_le` (@bollu)
* [#5357](https://github.com/leanprover/lean4/pull/5357) adds `BitVec.truncate` lemmas
* [#5358](https://github.com/leanprover/lean4/pull/5358) introduces `BitVec.setWidth` to unify zeroExtend and truncate (@tobiasgrosser)
* [#5361](https://github.com/leanprover/lean4/pull/5361) some BitVec GetElem lemmas
* [#5385](https://github.com/leanprover/lean4/pull/5385) adds `BitVec.ofBool_[and|or|xor]_ofBool` theorems (@tobiasgrosser)
* [#5404](https://github.com/leanprover/lean4/pull/5404) more of `BitVec.getElem_*` (@tobiasgrosser)
* [#5410](https://github.com/leanprover/lean4/pull/5410) BitVec analogues of `Nat.{mul_two, two_mul, mul_succ, succ_mul}` (@bollu)
* [#5411](https://github.com/leanprover/lean4/pull/5411) `BitVec.toNat_{add,sub,mul_of_lt}` for BitVector non-overflow reasoning (@bollu)
* [#5413](https://github.com/leanprover/lean4/pull/5413) adds `_self`, `_zero`, and `_allOnes` for `BitVec.[and|or|xor]` (@tobiasgrosser)
* [#5416](https://github.com/leanprover/lean4/pull/5416) adds LawCommIdentity + IdempotentOp for `BitVec.[and|or|xor]` (@tobiasgrosser)
* [#5418](https://github.com/leanprover/lean4/pull/5418) decidable quantifers for BitVec
* [#5450](https://github.com/leanprover/lean4/pull/5450) adds `BitVec.toInt_[intMin|neg|neg_of_ne_intMin]` (@tobiasgrosser)
* [#5459](https://github.com/leanprover/lean4/pull/5459) missing BitVec lemmas
* [#5469](https://github.com/leanprover/lean4/pull/5469) adds `BitVec.[not_not, allOnes_shiftLeft_or_shiftLeft, allOnes_shiftLeft_and_shiftLeft]` (@luisacicolini)
* [#5478](https://github.com/leanprover/lean4/pull/5478) adds `BitVec.(shiftLeft_add_distrib, shiftLeft_ushiftRight)` (@luisacicolini)
* [#5487](https://github.com/leanprover/lean4/pull/5487) adds `sdiv_eq`, `smod_eq` to allow `sdiv`/`smod` bitblasting (@bollu)
* [#5491](https://github.com/leanprover/lean4/pull/5491) adds `BitVec.toNat_[abs|sdiv|smod]` (@tobiasgrosser)
* [#5492](https://github.com/leanprover/lean4/pull/5492) `BitVec.(not_sshiftRight, not_sshiftRight_not, getMsb_not, msb_not)` (@luisacicolini)
* [#5499](https://github.com/leanprover/lean4/pull/5499) `BitVec.Lemmas` - drop non-terminal simps (@tobiasgrosser)
* [#5505](https://github.com/leanprover/lean4/pull/5505) unsimps `BitVec.divRec_succ'`
* [#5508](https://github.com/leanprover/lean4/pull/5508) adds `BitVec.getElem_[add|add_add_bool|mul|rotateLeft|rotateRight…` (@tobiasgrosser)
* [#5554](https://github.com/leanprover/lean4/pull/5554) adds `Bitvec.[add, sub, mul]_eq_xor` and `width_one_cases` (@luisacicolini)
* `List`
* [#5242](https://github.com/leanprover/lean4/pull/5242) improve naming for `List.mergeSort` lemmas
* [#5302](https://github.com/leanprover/lean4/pull/5302) provide `mergeSort` comparator autoParam
* [#5373](https://github.com/leanprover/lean4/pull/5373) fix name of `List.length_mergeSort`
* [#5377](https://github.com/leanprover/lean4/pull/5377) upstream `map_mergeSort`
* [#5378](https://github.com/leanprover/lean4/pull/5378) modify signature of lemmas about `mergeSort`
* [#5245](https://github.com/leanprover/lean4/pull/5245) avoid importing `List.Basic` without List.Impl
* [#5260](https://github.com/leanprover/lean4/pull/5260) review of List API
* [#5264](https://github.com/leanprover/lean4/pull/5264) review of List API
* [#5269](https://github.com/leanprover/lean4/pull/5269) remove HashMap's duplicated Pairwise and Sublist
* [#5271](https://github.com/leanprover/lean4/pull/5271) remove @[simp] from `List.head_mem` and similar
* [#5273](https://github.com/leanprover/lean4/pull/5273) lemmas about `List.attach`
* [#5275](https://github.com/leanprover/lean4/pull/5275) reverse direction of `List.tail_map`
* [#5277](https://github.com/leanprover/lean4/pull/5277) more `List.attach` lemmas
* [#5285](https://github.com/leanprover/lean4/pull/5285) `List.count` lemmas
* [#5287](https://github.com/leanprover/lean4/pull/5287) use boolean predicates in `List.filter`
* [#5289](https://github.com/leanprover/lean4/pull/5289) `List.mem_ite_nil_left` and analogues
* [#5293](https://github.com/leanprover/lean4/pull/5293) cleanup of `List.findIdx` / `List.take` lemmas
* [#5294](https://github.com/leanprover/lean4/pull/5294) switch primes on `List.getElem_take`
* [#5300](https://github.com/leanprover/lean4/pull/5300) more `List.findIdx` theorems
* [#5310](https://github.com/leanprover/lean4/pull/5310) fix `List.all/any` lemmas
* [#5311](https://github.com/leanprover/lean4/pull/5311) fix `List.countP` lemmas
* [#5316](https://github.com/leanprover/lean4/pull/5316) `List.tail` lemma
* [#5331](https://github.com/leanprover/lean4/pull/5331) fix implicitness of `List.getElem_mem`
* [#5350](https://github.com/leanprover/lean4/pull/5350) `List.replicate` lemmas
* [#5352](https://github.com/leanprover/lean4/pull/5352) `List.attachWith` lemmas
* [#5353](https://github.com/leanprover/lean4/pull/5353) `List.head_mem_head?`
* [#5360](https://github.com/leanprover/lean4/pull/5360) lemmas about `List.tail`
* [#5391](https://github.com/leanprover/lean4/pull/5391) review of `List.erase` / `List.find` lemmas
* [#5392](https://github.com/leanprover/lean4/pull/5392) `List.fold` / `attach` lemmas
* [#5393](https://github.com/leanprover/lean4/pull/5393) `List.fold` relators
* [#5394](https://github.com/leanprover/lean4/pull/5394) lemmas about `List.maximum?`
* [#5403](https://github.com/leanprover/lean4/pull/5403) theorems about `List.toArray`
* [#5405](https://github.com/leanprover/lean4/pull/5405) reverse direction of `List.set_map`
* [#5448](https://github.com/leanprover/lean4/pull/5448) add lemmas about `List.IsPrefix` (@Command-Master)
* [#5460](https://github.com/leanprover/lean4/pull/5460) missing `List.set_replicate_self`
* [#5518](https://github.com/leanprover/lean4/pull/5518) rename `List.maximum?` to `max?`
* [#5519](https://github.com/leanprover/lean4/pull/5519) upstream `List.fold` lemmas
* [#5520](https://github.com/leanprover/lean4/pull/5520) restore `@[simp]` on `List.getElem_mem` etc.
* [#5521](https://github.com/leanprover/lean4/pull/5521) List simp fixes
* [#5550](https://github.com/leanprover/lean4/pull/5550) `List.unattach` and simp lemmas
* [#5594](https://github.com/leanprover/lean4/pull/5594) induction-friendly `List.min?_cons`
* `Array`
* [#5246](https://github.com/leanprover/lean4/pull/5246) cleanup imports of Array.Lemmas
* [#5255](https://github.com/leanprover/lean4/pull/5255) split Init.Data.Array.Lemmas for better bootstrapping
* [#5288](https://github.com/leanprover/lean4/pull/5288) rename `Array.data` to `Array.toList`
* [#5303](https://github.com/leanprover/lean4/pull/5303) cleanup of `List.getElem_append` variants
* [#5304](https://github.com/leanprover/lean4/pull/5304) `Array.not_mem_empty`
* [#5400](https://github.com/leanprover/lean4/pull/5400) reorganization in Array/Basic
* [#5420](https://github.com/leanprover/lean4/pull/5420) make `Array` functions either semireducible or use structural recursion
* [#5422](https://github.com/leanprover/lean4/pull/5422) refactor `DecidableEq (Array α)`
* [#5452](https://github.com/leanprover/lean4/pull/5452) refactor of Array
* [#5458](https://github.com/leanprover/lean4/pull/5458) cleanup of Array docstrings after refactor
* [#5461](https://github.com/leanprover/lean4/pull/5461) restore `@[simp]` on `Array.swapAt!_def`
* [#5465](https://github.com/leanprover/lean4/pull/5465) improve Array GetElem lemmas
* [#5466](https://github.com/leanprover/lean4/pull/5466) `Array.foldX` lemmas
* [#5472](https://github.com/leanprover/lean4/pull/5472) @[simp] lemmas about `List.toArray`
* [#5485](https://github.com/leanprover/lean4/pull/5485) reverse simp direction for `toArray_concat`
* [#5514](https://github.com/leanprover/lean4/pull/5514) `Array.eraseReps`
* [#5515](https://github.com/leanprover/lean4/pull/5515) upstream `Array.qsortOrd`
* [#5516](https://github.com/leanprover/lean4/pull/5516) upstream `Subarray.empty`
* [#5526](https://github.com/leanprover/lean4/pull/5526) fix name of `Array.length_toList`
* [#5527](https://github.com/leanprover/lean4/pull/5527) reduce use of deprecated lemmas in Array
* [#5534](https://github.com/leanprover/lean4/pull/5534) cleanup of Array GetElem lemmas
* [#5536](https://github.com/leanprover/lean4/pull/5536) fix `Array.modify` lemmas
* [#5551](https://github.com/leanprover/lean4/pull/5551) upstream `Array.flatten` lemmas
* [#5552](https://github.com/leanprover/lean4/pull/5552) switch obvious cases of array "bang"`[]!` indexing to rely on hypothesis (@TomasPuverle)
* [#5577](https://github.com/leanprover/lean4/pull/5577) add missing simp to `Array.size_feraseIdx`
* [#5586](https://github.com/leanprover/lean4/pull/5586) `Array/Option.unattach`
* `Option`
* [#5272](https://github.com/leanprover/lean4/pull/5272) remove @[simp] from `Option.pmap/pbind` and add simp lemmas
* [#5307](https://github.com/leanprover/lean4/pull/5307) restoring Option simp confluence
* [#5354](https://github.com/leanprover/lean4/pull/5354) remove @[simp] from `Option.bind_map`
* [#5532](https://github.com/leanprover/lean4/pull/5532) `Option.attach`
* [#5539](https://github.com/leanprover/lean4/pull/5539) fix explicitness of `Option.mem_toList`
* `Nat`
* [#5241](https://github.com/leanprover/lean4/pull/5241) add @[simp] to `Nat.add_eq_zero_iff`
* [#5261](https://github.com/leanprover/lean4/pull/5261) Nat bitwise lemmas
* [#5262](https://github.com/leanprover/lean4/pull/5262) `Nat.testBit_add_one` should not be a global simp lemma
* [#5267](https://github.com/leanprover/lean4/pull/5267) protect some Nat bitwise theorems
* [#5305](https://github.com/leanprover/lean4/pull/5305) rename Nat bitwise lemmas
* [#5306](https://github.com/leanprover/lean4/pull/5306) add `Nat.self_sub_mod` lemma
* [#5503](https://github.com/leanprover/lean4/pull/5503) restore @[simp] to upstreamed `Nat.lt_off_iff`
* `Int`
* [#5301](https://github.com/leanprover/lean4/pull/5301) rename `Int.div/mod` to `Int.tdiv/tmod`
* [#5320](https://github.com/leanprover/lean4/pull/5320) add `ediv_nonneg_of_nonpos_of_nonpos` to DivModLemmas (@sakehl)
* `Fin`
* [#5250](https://github.com/leanprover/lean4/pull/5250) missing lemma about `Fin.ofNat'`
* [#5356](https://github.com/leanprover/lean4/pull/5356) `Fin.ofNat'` uses `NeZero`
* [#5379](https://github.com/leanprover/lean4/pull/5379) remove some @[simp]s from Fin lemmas
* [#5380](https://github.com/leanprover/lean4/pull/5380) missing Fin @[simp] lemmas
* `HashMap`
* [#5244](https://github.com/leanprover/lean4/pull/5244) (`DHashMap`|`HashMap`|`HashSet`).(`getKey?`|`getKey`|`getKey!`|`getKeyD`)
* [#5362](https://github.com/leanprover/lean4/pull/5362) remove the last use of `Lean.(HashSet|HashMap)`
* [#5369](https://github.com/leanprover/lean4/pull/5369) `HashSet.ofArray`
* [#5370](https://github.com/leanprover/lean4/pull/5370) `HashSet.partition`
* [#5581](https://github.com/leanprover/lean4/pull/5581) `Singleton`/`Insert`/`Union` instances for `HashMap`/`Set`
* [#5582](https://github.com/leanprover/lean4/pull/5582) `HashSet.all`/`any`
* [#5590](https://github.com/leanprover/lean4/pull/5590) adding `Insert`/`Singleton`/`Union` instances for `HashMap`/`Set.Raw`
* [#5591](https://github.com/leanprover/lean4/pull/5591) `HashSet.Raw.all/any`
* `Monads`
* [#5463](https://github.com/leanprover/lean4/pull/5463) upstream some monad lemmas
* [#5464](https://github.com/leanprover/lean4/pull/5464) adjust simp attributes on monad lemmas
* [#5522](https://github.com/leanprover/lean4/pull/5522) more monadic simp lemmas
* Simp lemma cleanup
* [#5251](https://github.com/leanprover/lean4/pull/5251) remove redundant simp annotations
* [#5253](https://github.com/leanprover/lean4/pull/5253) remove Int simp lemmas that can't fire
* [#5254](https://github.com/leanprover/lean4/pull/5254) variables appearing on both sides of an iff should be implicit
* [#5381](https://github.com/leanprover/lean4/pull/5381) cleaning up redundant simp lemmas
### Compiler, runtime, and FFI
* [#4685](https://github.com/leanprover/lean4/pull/4685) fixes a typo in the C `run_new_frontend` signature
* [#4729](https://github.com/leanprover/lean4/pull/4729) has IR checker suggest using `noncomputable`
* [#5143](https://github.com/leanprover/lean4/pull/5143) adds a shared library for Lake
* [#5437](https://github.com/leanprover/lean4/pull/5437) removes (syntactically) duplicate imports (@euprunin)
* [#5462](https://github.com/leanprover/lean4/pull/5462) updates `src/lake/lakefile.toml` to the adjusted Lake build process
* [#5541](https://github.com/leanprover/lean4/pull/5541) removes new shared libs before build to better support Windows
* [#5558](https://github.com/leanprover/lean4/pull/5558) make `lean.h` compile with MSVC (@kant2002)
* [#5564](https://github.com/leanprover/lean4/pull/5564) removes non-conforming size-0 arrays (@eric-wieser)
### Lake
* Reservoir build cache. Lake will now attempt to fetch a pre-built copy of the package from Reservoir before building it. This is only enabled for packages in the leanprover or leanprover-community organizations on versions indexed by Reservoir. Users can force Lake to build packages from the source by passing --no-cache on the CLI or by setting the LAKE_NO_CACHE environment variable to true. [#5486](https://github.com/leanprover/lean4/pull/5486), [#5572](https://github.com/leanprover/lean4/pull/5572), [#5583](https://github.com/leanprover/lean4/pull/5583), [#5600](https://github.com/leanprover/lean4/pull/5600), [#5641](https://github.com/leanprover/lean4/pull/5641), [#5642](https://github.com/leanprover/lean4/pull/5642).
* [#5504](https://github.com/leanprover/lean4/pull/5504) lake new and lake init now produce TOML configurations by default.
* [#5878](https://github.com/leanprover/lean4/pull/5878) fixes a serious issue where Lake would delete path dependencies when attempting to cleanup a dependency required with an incorrect name.
* **Breaking changes**
* [#5641](https://github.com/leanprover/lean4/pull/5641) A Lake build of target within a package will no longer build a package's dependencies package-level extra target dependencies. At the technical level, a package's extraDep facet no longer transitively builds its dependencies extraDep facets (which include their extraDepTargets).
### Documentation fixes
* [#3918](https://github.com/leanprover/lean4/pull/3918) `@[builtin_doc]` attribute (@digama0)
* [#4305](https://github.com/leanprover/lean4/pull/4305) explains the borrow syntax (@eric-wieser)
* [#5349](https://github.com/leanprover/lean4/pull/5349) adds documentation for `groupBy.loop` (@vihdzp)
* [#5473](https://github.com/leanprover/lean4/pull/5473) fixes typo in `BitVec.mul` docstring (@llllvvuu)
* [#5476](https://github.com/leanprover/lean4/pull/5476) fixes typos in `Lean.MetavarContext`
* [#5481](https://github.com/leanprover/lean4/pull/5481) removes mention of `Lean.withSeconds` (@alexkeizer)
* [#5497](https://github.com/leanprover/lean4/pull/5497) updates documentation and tests for `toUIntX` functions (@TomasPuverle)
* [#5087](https://github.com/leanprover/lean4/pull/5087) mentions that `inferType` does not ensure type correctness
* Many fixes to spelling across the doc-strings, (@euprunin): [#5425](https://github.com/leanprover/lean4/pull/5425) [#5426](https://github.com/leanprover/lean4/pull/5426) [#5427](https://github.com/leanprover/lean4/pull/5427) [#5430](https://github.com/leanprover/lean4/pull/5430) [#5431](https://github.com/leanprover/lean4/pull/5431) [#5434](https://github.com/leanprover/lean4/pull/5434) [#5435](https://github.com/leanprover/lean4/pull/5435) [#5436](https://github.com/leanprover/lean4/pull/5436) [#5438](https://github.com/leanprover/lean4/pull/5438) [#5439](https://github.com/leanprover/lean4/pull/5439) [#5440](https://github.com/leanprover/lean4/pull/5440) [#5599](https://github.com/leanprover/lean4/pull/5599)
### Changes to CI
* [#5343](https://github.com/leanprover/lean4/pull/5343) allows addition of `release-ci` label via comment (@thorimur)
* [#5344](https://github.com/leanprover/lean4/pull/5344) sets check level correctly during workflow (@thorimur)
* [#5444](https://github.com/leanprover/lean4/pull/5444) Mathlib's `lean-pr-testing-NNNN` branches should use Batteries' `lean-pr-testing-NNNN` branches
* [#5489](https://github.com/leanprover/lean4/pull/5489) commit `lake-manifest.json` when updating `lean-pr-testing` branches
* [#5490](https://github.com/leanprover/lean4/pull/5490) use separate secrets for commenting and branching in `pr-release.yml`

282
releases/v4.14.0.md Normal file
View File

@@ -0,0 +1,282 @@
v4.14.0
----------
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.13.0...v4.14.0
### Language features, tactics, and metaprograms
* `structure` and `inductive` commands
* [#5517](https://github.com/leanprover/lean4/pull/5517) improves universe level inference for the resulting type of an `inductive` or `structure.` Recall that a `Prop`-valued inductive type is a syntactic subsingleton if it has at most one constructor and all the arguments to the constructor are in `Prop`. Such types have large elimination, so they could be defined in `Type` or `Prop` without any trouble. The way inference has changed is that if a type is a syntactic subsingleton with exactly one constructor, and the constructor has at least one parameter/field, then the `inductive`/`structure` command will prefer creating a `Prop` instead of a `Type`. The upshot is that the `: Prop` in `structure S : Prop` is often no longer needed. (With @arthur-adjedj).
* [#5842](https://github.com/leanprover/lean4/pull/5842) and [#5783](https://github.com/leanprover/lean4/pull/5783) implement a feature where the `structure` command can now define recursive inductive types:
```lean
structure Tree where
n : Nat
children : Fin n → Tree
def Tree.size : Tree → Nat
| {n, children} => Id.run do
let mut s := 0
for h : i in [0 : n] do
s := s + (children ⟨i, h.2⟩).size
pure s
```
* [#5814](https://github.com/leanprover/lean4/pull/5814) fixes a bug where Mathlib's `Type*` elaborator could lead to incorrect universe parameters with the `inductive` command.
* [#3152](https://github.com/leanprover/lean4/pull/3152) and [#5844](https://github.com/leanprover/lean4/pull/5844) fix bugs in default value processing for structure instance notation (with @arthur-adjedj).
* [#5399](https://github.com/leanprover/lean4/pull/5399) promotes instance synthesis order calculation failure from a soft error to a hard error.
* [#5542](https://github.com/leanprover/lean4/pull/5542) deprecates `:=` variants of `inductive` and `structure` (see breaking changes).
* **Application elaboration improvements**
* [#5671](https://github.com/leanprover/lean4/pull/5671) makes `@[elab_as_elim]` require at least one discriminant, since otherwise there is no advantage to this alternative elaborator.
* [#5528](https://github.com/leanprover/lean4/pull/5528) enables field notation in explicit mode. The syntax `@x.f` elaborates as `@S.f` with `x` supplied to the appropriate parameter.
* [#5692](https://github.com/leanprover/lean4/pull/5692) modifies the dot notation resolution algorithm so that it can apply `CoeFun` instances. For example, Mathlib has `Multiset.card : Multiset α →+ Nat`, and now with `m : Multiset α`, the notation `m.card` resolves to `⇑Multiset.card m`.
* [#5658](https://github.com/leanprover/lean4/pull/5658) fixes a bug where 'don't know how to synthesize implicit argument' errors might have the incorrect local context when the eta arguments feature is activated.
* [#5933](https://github.com/leanprover/lean4/pull/5933) fixes a bug where `..` ellipses in patterns made use of optparams and autoparams.
* [#5770](https://github.com/leanprover/lean4/pull/5770) makes dot notation for structures resolve using *all* ancestors. Adds a *resolution order* for generalized field notation. This is the order of namespaces visited during resolution when trying to resolve names. The algorithm to compute a resolution order is the commonly used C3 linearization (used for example by Python), which when successful ensures that immediate parents' namespaces are considered before more distant ancestors' namespaces. By default we use a relaxed version of the algorithm that tolerates inconsistencies, but using `set_option structure.strictResolutionOrder true` makes inconsistent parent orderings into warnings.
* **Recursion and induction principles**
* [#5619](https://github.com/leanprover/lean4/pull/5619) fixes functional induction principle generation to avoid over-eta-expanding in the preprocessing step.
* [#5766](https://github.com/leanprover/lean4/pull/5766) fixes structural nested recursion so that it is not confused when a nested type appears first.
* [#5803](https://github.com/leanprover/lean4/pull/5803) fixes a bug in functional induction principle generation when there are `let` bindings.
* [#5904](https://github.com/leanprover/lean4/pull/5904) improves functional induction principle generation to unfold aux definitions more carefully.
* [#5850](https://github.com/leanprover/lean4/pull/5850) refactors code for `Predefinition.Structural`.
* **Error messages**
* [#5276](https://github.com/leanprover/lean4/pull/5276) fixes a bug in "type mismatch" errors that would structurally assign metavariables during the algorithm to expose differences.
* [#5919](https://github.com/leanprover/lean4/pull/5919) makes "type mismatch" errors add type ascriptions to expose differences for numeric literals.
* [#5922](https://github.com/leanprover/lean4/pull/5922) makes "type mismatch" errors expose differences in the bodies of functions and pi types.
* [#5888](https://github.com/leanprover/lean4/pull/5888) improves the error message for invalid induction alternative names in `match` expressions (@josojo).
* [#5719](https://github.com/leanprover/lean4/pull/5719) improves `calc` error messages.
* [#5627](https://github.com/leanprover/lean4/pull/5627) and [#5663](https://github.com/leanprover/lean4/pull/5663) improve the **`#eval` command** and introduce some new features.
* Now results can be pretty printed if there is a `ToExpr` instance, which means **hoverable output**. If `ToExpr` fails, it then tries looking for a `Repr` or `ToString` instance like before. Setting `set_option eval.pp false` disables making use of `ToExpr` instances.
* There is now **auto-derivation** of `Repr` instances, enabled with the `pp.derive.repr` option (default to **true**). For example:
```lean
inductive Baz
| a | b
#eval Baz.a
-- Baz.a
```
It simply does `deriving instance Repr for Baz` when there's no way to represent `Baz`.
* The option `eval.type` controls whether or not to include the type in the output. For now the default is false.
* Now expressions such as `#eval do return 2`, where monad is unknown, work. It tries unifying the monad with `CommandElabM`, `TermElabM`, or `IO`.
* The classes `Lean.Eval` and `Lean.MetaEval` have been removed. These each used to be responsible for adapting monads and printing results. Now the `MonadEval` class is responsible for adapting monads for evaluation (it is similar to `MonadLift`, but instances are allowed to use default data when initializing state), and representing results is handled through a separate process.
* Error messages about failed instance synthesis are now more precise. Once it detects that a `MonadEval` class applies, then the error message will be specific about missing `ToExpr`/`Repr`/`ToString` instances.
* Fixes bugs where evaluating `MetaM` and `CoreM` wouldn't collect log messages.
* Fixes a bug where `let rec` could not be used in `#eval`.
* `partial` definitions
* [#5780](https://github.com/leanprover/lean4/pull/5780) improves the error message when `partial` fails to prove a type is inhabited. Add delta deriving.
* [#5821](https://github.com/leanprover/lean4/pull/5821) gives `partial` inhabitation the ability to create local `Inhabited` instances from parameters.
* **New tactic configuration syntax.** The configuration syntax for all core tactics has been given an upgrade. Rather than `simp (config := { contextual := true, maxSteps := 22})`, one can now write `simp +contextual (maxSteps := 22)`. Tactic authors can migrate by switching from `(config)?` to `optConfig` in tactic syntaxes and potentially deleting `mkOptionalNode` in elaborators. [#5883](https://github.com/leanprover/lean4/pull/5883), [#5898](https://github.com/leanprover/lean4/pull/5898), [#5928](https://github.com/leanprover/lean4/pull/5928), and [#5932](https://github.com/leanprover/lean4/pull/5932). (Tactic authors, see breaking changes.)
* `simp` tactic
* [#5632](https://github.com/leanprover/lean4/pull/5632) fixes the simpproc for `Fin` literals to reduce more consistently.
* [#5648](https://github.com/leanprover/lean4/pull/5648) fixes a bug in `simpa ... using t` where metavariables in `t` were not properly accounted for, and also improves the type mismatch error.
* [#5838](https://github.com/leanprover/lean4/pull/5838) fixes the docstring of `simp!` to actually talk about `simp!`.
* [#5870](https://github.com/leanprover/lean4/pull/5870) adds support for `attribute [simp ←]` (note the reverse direction). This adds the reverse of a theorem as a global simp theorem.
* `decide` tactic
* [#5665](https://github.com/leanprover/lean4/pull/5665) adds `decide!` tactic for using kernel reduction (warning: this is renamed to `decide +kernel` in a future release).
* `bv_decide` tactic
* [#5714](https://github.com/leanprover/lean4/pull/5714) adds inequality regression tests (@alexkeizer).
* [#5608](https://github.com/leanprover/lean4/pull/5608) adds `bv_toNat` tag for `toNat_ofInt` (@bollu).
* [#5618](https://github.com/leanprover/lean4/pull/5618) adds support for `at` in `ac_nf` and uses it in `bv_normalize` (@tobiasgrosser).
* [#5628](https://github.com/leanprover/lean4/pull/5628) adds udiv support.
* [#5635](https://github.com/leanprover/lean4/pull/5635) adds auxiliary bitblasters for negation and subtraction.
* [#5637](https://github.com/leanprover/lean4/pull/5637) adds more `getLsbD` bitblaster theory.
* [#5652](https://github.com/leanprover/lean4/pull/5652) adds umod support.
* [#5653](https://github.com/leanprover/lean4/pull/5653) adds performance benchmark for modulo.
* [#5655](https://github.com/leanprover/lean4/pull/5655) reduces error on `bv_check` to warning.
* [#5670](https://github.com/leanprover/lean4/pull/5670) adds `~~~(-x)` support.
* [#5673](https://github.com/leanprover/lean4/pull/5673) disables `ac_nf` by default.
* [#5675](https://github.com/leanprover/lean4/pull/5675) fixes context tracking in `bv_decide` counter example.
* [#5676](https://github.com/leanprover/lean4/pull/5676) adds an error when the LRAT proof is invalid.
* [#5781](https://github.com/leanprover/lean4/pull/5781) introduces uninterpreted symbols everywhere.
* [#5823](https://github.com/leanprover/lean4/pull/5823) adds `BitVec.sdiv` support.
* [#5852](https://github.com/leanprover/lean4/pull/5852) adds `BitVec.ofBool` support.
* [#5855](https://github.com/leanprover/lean4/pull/5855) adds `if` support.
* [#5869](https://github.com/leanprover/lean4/pull/5869) adds support for all the SMTLIB BitVec divison/remainder operations.
* [#5886](https://github.com/leanprover/lean4/pull/5886) adds embedded constraint substitution.
* [#5918](https://github.com/leanprover/lean4/pull/5918) fixes loose mvars bug in `bv_normalize`.
* Documentation:
* [#5636](https://github.com/leanprover/lean4/pull/5636) adds remarks about multiplication.
* `conv` mode
* [#5861](https://github.com/leanprover/lean4/pull/5861) improves the `congr` conv tactic to handle "over-applied" functions.
* [#5894](https://github.com/leanprover/lean4/pull/5894) improves the `arg` conv tactic so that it can access more arguments and so that it can handle "over-applied" functions (it generates a specialized congruence lemma for the specific argument in question). Makes `arg 1` and `arg 2` apply to pi types in more situations. Adds negative indexing, for example `arg -2` is equivalent to the `lhs` tactic. Makes the `enter [...]` tactic show intermediate states like `rw`.
* **Other tactics**
* [#4846](https://github.com/leanprover/lean4/pull/4846) fixes a bug where `generalize ... at *` would apply to implementation details (@ymherklotz).
* [#5730](https://github.com/leanprover/lean4/pull/5730) upstreams the `classical` tactic combinator.
* [#5815](https://github.com/leanprover/lean4/pull/5815) improves the error message when trying to unfold a local hypothesis that is not a local definition.
* [#5862](https://github.com/leanprover/lean4/pull/5862) and [#5863](https://github.com/leanprover/lean4/pull/5863) change how `apply` and `simp` elaborate, making them not disable error recovery. This improves hovers and completions when the term has elaboration errors.
* `deriving` clauses
* [#5899](https://github.com/leanprover/lean4/pull/5899) adds declaration ranges for delta-derived instances.
* [#5265](https://github.com/leanprover/lean4/pull/5265) removes unused syntax in `deriving` clauses for providing arguments to deriving handlers (see breaking changes).
* [#5065](https://github.com/leanprover/lean4/pull/5065) upstreams and updates `#where`, a command that reports the current scope information.
* **Linters**
* [#5338](https://github.com/leanprover/lean4/pull/5338) makes the unused variables linter ignore variables defined in tactics by default now, avoiding performance bottlenecks.
* [#5644](https://github.com/leanprover/lean4/pull/5644) ensures that linters in general do not run on `#guard_msgs` itself.
* **Metaprogramming interface**
* [#5720](https://github.com/leanprover/lean4/pull/5720) adds `pushGoal`/`pushGoals` and `popGoal` for manipulating the goal state. These are an alternative to `replaceMainGoal` and `getMainGoal`, and with them you don't need to worry about making sure nothing clears assigned metavariables from the goal list between assigning the main goal and using `replaceMainGoal`. Modifies `closeMainGoalUsing`, which is like a `TacticM` version of `liftMetaTactic`. Now the callback is run in a context where the main goal is removed from the goal list, and the callback is free to modify the goal list. Furthermore, the `checkUnassigned` argument has been replaced with `checkNewUnassigned`, which checks whether the value assigned to the goal has any *new* metavariables, relative to the start of execution of the callback. Modifies `withCollectingNewGoalsFrom` to take the `parentTag` argument explicitly rather than indirectly via `getMainTag`. Modifies `elabTermWithHoles` to optionally take `parentTag?`.
* [#5563](https://github.com/leanprover/lean4/pull/5563) fixes `getFunInfo` and `inferType` to use `withAtLeastTransparency` rather than `withTransparency`.
* [#5679](https://github.com/leanprover/lean4/pull/5679) fixes `RecursorVal.getInduct` to return the name of major arguments type. This makes "structure eta" work for nested inductives.
* [#5681](https://github.com/leanprover/lean4/pull/5681) removes unused `mkRecursorInfoForKernelRec`.
* [#5686](https://github.com/leanprover/lean4/pull/5686) makes discrimination trees index the domains of foralls, for better performance of the simplify and type class search.
* [#5760](https://github.com/leanprover/lean4/pull/5760) adds `Lean.Expr.name?` recognizer for `Name` expressions.
* [#5800](https://github.com/leanprover/lean4/pull/5800) modifies `liftCommandElabM` to preserve more state, fixing an issue where using it would drop messages.
* [#5857](https://github.com/leanprover/lean4/pull/5857) makes it possible to use dot notation in `m!` strings, for example `m!"{.ofConstName n}"`.
* [#5841](https://github.com/leanprover/lean4/pull/5841) and [#5853](https://github.com/leanprover/lean4/pull/5853) record the complete list of `structure` parents in the `StructureInfo` environment extension.
* **Other fixes or improvements**
* [#5566](https://github.com/leanprover/lean4/pull/5566) fixes a bug introduced in [#4781](https://github.com/leanprover/lean4/pull/4781) where heartbeat exceptions were no longer being handled properly. Now such exceptions are tagged with `runtime.maxHeartbeats` (@eric-wieser).
* [#5708](https://github.com/leanprover/lean4/pull/5708) modifies the proof objects produced by the proof-by-reflection tactics `ac_nf0` and `simp_arith` so that the kernel is less prone to reducing expensive atoms.
* [#5768](https://github.com/leanprover/lean4/pull/5768) adds a `#version` command that prints Lean's version information.
* [#5822](https://github.com/leanprover/lean4/pull/5822) fixes elaborator algorithms to match kernel algorithms for primitive projections (`Expr.proj`).
* [#5811](https://github.com/leanprover/lean4/pull/5811) improves the docstring for the `rwa` tactic.
### Language server, widgets, and IDE extensions
* [#5224](https://github.com/leanprover/lean4/pull/5224) fixes `WorkspaceClientCapabilities` to make `applyEdit` optional, in accordance with the LSP specification (@pzread).
* [#5340](https://github.com/leanprover/lean4/pull/5340) fixes a server deadlock when shutting down the language server and a desync between client and language server after a file worker crash.
* [#5560](https://github.com/leanprover/lean4/pull/5560) makes `initialize` and `builtin_initialize` participate in the call hierarchy and other requests.
* [#5650](https://github.com/leanprover/lean4/pull/5650) makes references in attributes participate in the call hierarchy and other requests.
* [#5666](https://github.com/leanprover/lean4/pull/5666) add auto-completion in tactic blocks without having to type the first character of the tactic, and adds tactic completion docs to tactic auto-completion items.
* [#5677](https://github.com/leanprover/lean4/pull/5677) fixes several cases where goal states were not displayed in certain text cursor positions.
* [#5707](https://github.com/leanprover/lean4/pull/5707) indicates deprecations in auto-completion items.
* [#5736](https://github.com/leanprover/lean4/pull/5736), [#5752](https://github.com/leanprover/lean4/pull/5752), [#5763](https://github.com/leanprover/lean4/pull/5763), [#5802](https://github.com/leanprover/lean4/pull/5802), and [#5805](https://github.com/leanprover/lean4/pull/5805) fix various performance issues in the language server.
* [#5801](https://github.com/leanprover/lean4/pull/5801) distinguishes theorem auto-completions from non-theorem auto-completions.
### Pretty printing
* [#5640](https://github.com/leanprover/lean4/pull/5640) fixes a bug where goal states in messages might print newlines as spaces.
* [#5643](https://github.com/leanprover/lean4/pull/5643) adds option `pp.mvars.delayed` (default false), which when false causes delayed assignment metavariables to pretty print with what they are assigned to. Now `fun x : Nat => ?a` pretty prints as `fun x : Nat => ?a` rather than `fun x ↦ ?m.7 x`.
* [#5711](https://github.com/leanprover/lean4/pull/5711) adds options `pp.mvars.anonymous` and `pp.mvars.levels`, which when false respectively cause expression metavariables and level metavariables to pretty print as `?_`.
* [#5710](https://github.com/leanprover/lean4/pull/5710) adjusts the `` elaboration warning to mention `pp.maxSteps`.
* [#5759](https://github.com/leanprover/lean4/pull/5759) fixes the app unexpander for `sorryAx`.
* [#5827](https://github.com/leanprover/lean4/pull/5827) improves accuracy of binder names in the signature pretty printer (like in output of `#check`). Also fixes the issue where consecutive hygienic names pretty print without a space separating them, so we now have `(x✝ y✝ : Nat)` rather than `(x✝y✝ : Nat)`.
* [#5830](https://github.com/leanprover/lean4/pull/5830) makes sure all the core delaborators respond to `pp.explicit` when appropriate.
* [#5639](https://github.com/leanprover/lean4/pull/5639) makes sure name literals use escaping when pretty printing.
* [#5854](https://github.com/leanprover/lean4/pull/5854) adds delaborators for `<|>`, `<*>`, `>>`, `<*`, and `*>`.
### Library
* `Array`
* [#5687](https://github.com/leanprover/lean4/pull/5687) deprecates `Array.data`.
* [#5705](https://github.com/leanprover/lean4/pull/5705) uses a better default value for `Array.swapAt!`.
* [#5748](https://github.com/leanprover/lean4/pull/5748) moves `Array.mapIdx` lemmas to a new file.
* [#5749](https://github.com/leanprover/lean4/pull/5749) simplifies signature of `Array.mapIdx`.
* [#5758](https://github.com/leanprover/lean4/pull/5758) upstreams `Array.reduceOption`.
* [#5786](https://github.com/leanprover/lean4/pull/5786) adds simp lemmas for `Array.isEqv` and `BEq`.
* [#5796](https://github.com/leanprover/lean4/pull/5796) renames `Array.shrink` to `Array.take`, and relates it to `List.take`.
* [#5798](https://github.com/leanprover/lean4/pull/5798) upstreams `List.modify`, adds lemmas, relates to `Array.modify`.
* [#5799](https://github.com/leanprover/lean4/pull/5799) relates `Array.forIn` and `List.forIn`.
* [#5833](https://github.com/leanprover/lean4/pull/5833) adds `Array.forIn'`, and relates to `List`.
* [#5848](https://github.com/leanprover/lean4/pull/5848) fixes deprecations in `Init.Data.Array.Basic` to not recommend the deprecated constant.
* [#5895](https://github.com/leanprover/lean4/pull/5895) adds `LawfulBEq (Array α) ↔ LawfulBEq α`.
* [#5896](https://github.com/leanprover/lean4/pull/5896) moves `@[simp]` from `back_eq_back?` to `back_push`.
* [#5897](https://github.com/leanprover/lean4/pull/5897) renames `Array.back` to `back!`.
* `List`
* [#5605](https://github.com/leanprover/lean4/pull/5605) removes `List.redLength`.
* [#5696](https://github.com/leanprover/lean4/pull/5696) upstreams `List.mapIdx` and adds lemmas.
* [#5697](https://github.com/leanprover/lean4/pull/5697) upstreams `List.foldxM_map`.
* [#5701](https://github.com/leanprover/lean4/pull/5701) renames `List.join` to `List.flatten`.
* [#5703](https://github.com/leanprover/lean4/pull/5703) upstreams `List.sum`.
* [#5706](https://github.com/leanprover/lean4/pull/5706) marks `prefix_append_right_inj` as a simp lemma.
* [#5716](https://github.com/leanprover/lean4/pull/5716) fixes `List.drop_drop` addition order.
* [#5731](https://github.com/leanprover/lean4/pull/5731) renames `List.bind` and `Array.concatMap` to `flatMap`.
* [#5732](https://github.com/leanprover/lean4/pull/5732) renames `List.pure` to `List.singleton`.
* [#5742](https://github.com/leanprover/lean4/pull/5742) upstreams `ne_of_mem_of_not_mem`.
* [#5743](https://github.com/leanprover/lean4/pull/5743) upstreams `ne_of_apply_ne`.
* [#5816](https://github.com/leanprover/lean4/pull/5816) adds more `List.modify` lemmas.
* [#5879](https://github.com/leanprover/lean4/pull/5879) renames `List.groupBy` to `splitBy`.
* [#5913](https://github.com/leanprover/lean4/pull/5913) relates `for` loops over `List` with `foldlM`.
* `Nat`
* [#5694](https://github.com/leanprover/lean4/pull/5694) removes `instBEqNat`, which is redundant with `instBEqOfDecidableEq` but not defeq.
* [#5746](https://github.com/leanprover/lean4/pull/5746) deprecates `Nat.sum`.
* [#5785](https://github.com/leanprover/lean4/pull/5785) adds `Nat.forall_lt_succ` and variants.
* Fixed width integers
* [#5323](https://github.com/leanprover/lean4/pull/5323) redefine unsigned fixed width integers in terms of `BitVec`.
* [#5735](https://github.com/leanprover/lean4/pull/5735) adds `UIntX.[val_ofNat, toBitVec_ofNat]`.
* [#5790](https://github.com/leanprover/lean4/pull/5790) defines `Int8`.
* [#5901](https://github.com/leanprover/lean4/pull/5901) removes native code for `UInt8.modn`.
* `BitVec`
* [#5604](https://github.com/leanprover/lean4/pull/5604) completes `BitVec.[getMsbD|getLsbD|msb]` for shifts (@luisacicolini).
* [#5609](https://github.com/leanprover/lean4/pull/5609) adds lemmas for division when denominator is zero (@bollu).
* [#5620](https://github.com/leanprover/lean4/pull/5620) documents Bitblasting (@bollu)
* [#5623](https://github.com/leanprover/lean4/pull/5623) moves `BitVec.udiv/umod/sdiv/smod` after `add/sub/mul/lt` (@tobiasgrosser).
* [#5645](https://github.com/leanprover/lean4/pull/5645) defines `udiv` normal form to be `/`, resp. `umod` and `%` (@bollu).
* [#5646](https://github.com/leanprover/lean4/pull/5646) adds lemmas about arithmetic inequalities (@bollu).
* [#5680](https://github.com/leanprover/lean4/pull/5680) expands relationship with `toFin` (@tobiasgrosser).
* [#5691](https://github.com/leanprover/lean4/pull/5691) adds `BitVec.(getMSbD, msb)_(add, sub)` and `BitVec.getLsbD_sub` (@luisacicolini).
* [#5712](https://github.com/leanprover/lean4/pull/5712) adds `BitVec.[udiv|umod]_[zero|one|self]` (@tobiasgrosser).
* [#5718](https://github.com/leanprover/lean4/pull/5718) adds `BitVec.sdiv_[zero|one|self]` (@tobiasgrosser).
* [#5721](https://github.com/leanprover/lean4/pull/5721) adds `BitVec.(msb, getMsbD, getLsbD)_(neg, abs)` (@luisacicolini).
* [#5772](https://github.com/leanprover/lean4/pull/5772) adds `BitVec.toInt_sub`, simplifies `BitVec.toInt_neg` (@tobiasgrosser).
* [#5778](https://github.com/leanprover/lean4/pull/5778) prove that `intMin` the smallest signed bitvector (@alexkeizer).
* [#5851](https://github.com/leanprover/lean4/pull/5851) adds `(msb, getMsbD)_twoPow` (@luisacicolini).
* [#5858](https://github.com/leanprover/lean4/pull/5858) adds `BitVec.[zero_ushiftRight|zero_sshiftRight|zero_mul]` and cleans up BVDecide (@tobiasgrosser).
* [#5865](https://github.com/leanprover/lean4/pull/5865) adds `BitVec.(msb, getMsbD)_concat` (@luisacicolini).
* [#5881](https://github.com/leanprover/lean4/pull/5881) adds `Hashable (BitVec n)`
* `String`/`Char`
* [#5728](https://github.com/leanprover/lean4/pull/5728) upstreams `String.dropPrefix?`.
* [#5745](https://github.com/leanprover/lean4/pull/5745) changes `String.dropPrefix?` signature.
* [#5747](https://github.com/leanprover/lean4/pull/5747) adds `Hashable Char` instance
* `HashMap`
* [#5880](https://github.com/leanprover/lean4/pull/5880) adds interim implementation of `HashMap.modify`/`alter`
* **Other**
* [#5704](https://github.com/leanprover/lean4/pull/5704) removes `@[simp]` from `Option.isSome_eq_isSome`.
* [#5739](https://github.com/leanprover/lean4/pull/5739) upstreams material on `Prod`.
* [#5740](https://github.com/leanprover/lean4/pull/5740) moves `Antisymm` to `Std.Antisymm`.
* [#5741](https://github.com/leanprover/lean4/pull/5741) upstreams basic material on `Sum`.
* [#5756](https://github.com/leanprover/lean4/pull/5756) adds `Nat.log2_two_pow` (@spinylobster).
* [#5892](https://github.com/leanprover/lean4/pull/5892) removes duplicated `ForIn` instances.
* [#5900](https://github.com/leanprover/lean4/pull/5900) removes `@[simp]` from `Sum.forall` and `Sum.exists`.
* [#5812](https://github.com/leanprover/lean4/pull/5812) removes redundant `Decidable` assumptions (@FR-vdash-bot).
### Compiler, runtime, and FFI
* [#5685](https://github.com/leanprover/lean4/pull/5685) fixes help message flags, removes the `-f` flag and adds the `-g` flag (@James-Oswald).
* [#5930](https://github.com/leanprover/lean4/pull/5930) adds `--short-version` (`-V`) option to display short version (@juhp).
* [#5144](https://github.com/leanprover/lean4/pull/5144) switches all 64-bit platforms over to consistently using GMP for bignum arithmetic.
* [#5753](https://github.com/leanprover/lean4/pull/5753) raises the minimum supported Windows version to Windows 10 1903 (released May 2019).
### Lake
* [#5715](https://github.com/leanprover/lean4/pull/5715) changes `lake new math` to use `autoImplicit false` (@eric-wieser).
* [#5688](https://github.com/leanprover/lean4/pull/5688) makes `Lake` not create core aliases in the `Lake` namespace.
* [#5924](https://github.com/leanprover/lean4/pull/5924) adds a `text` option for `buildFile*` utilities.
* [#5789](https://github.com/leanprover/lean4/pull/5789) makes `lake init` not `git init` when inside git work tree (@haoxins).
* [#5684](https://github.com/leanprover/lean4/pull/5684) has Lake update a package's `lean-toolchain` file on `lake update` if it finds the package's direct dependencies use a newer compatible toolchain. To skip this step, use the `--keep-toolchain` CLI option. (See breaking changes.)
* [#6218](https://github.com/leanprover/lean4/pull/6218) makes Lake no longer automatically fetch GitHub cloud releases if the package build directory is already present (mirroring the behavior of the Reservoir cache). This prevents the cache from clobbering existing prebuilt artifacts. Users can still manually fetch the cache and clobber the build directory by running `lake build <pkg>:release`.
* [#6231](https://github.com/leanprover/lean4/pull/6231) improves the errors Lake produces when it fails to fetch a dependency from Reservoir. If the package is not indexed, it will produce a suggestion about how to require it from GitHub.
### Documentation
* [#5617](https://github.com/leanprover/lean4/pull/5617) fixes MSYS2 build instructions.
* [#5725](https://github.com/leanprover/lean4/pull/5725) points out that `OfScientific` is called with raw literals (@eric-wieser).
* [#5794](https://github.com/leanprover/lean4/pull/5794) adds a stub for application ellipsis notation (@eric-wieser).
### Breaking changes
* The syntax for providing arguments to deriving handlers has been removed, which was not used by any major Lean projects in the ecosystem. As a result, the `applyDerivingHandlers` now takes one fewer argument, `registerDerivingHandlerWithArgs` is now simply `registerDerivingHandler`, `DerivingHandler` no longer includes the unused parameter, and `DerivingHandlerNoArgs` has been deprecated. To migrate code, delete the unused `none` argument and use `registerDerivingHandler` and `DerivingHandler`. ([#5265](https://github.com/leanprover/lean4/pull/5265))
* The minimum supported Windows version has been raised to Windows 10 1903, released May 2019. ([#5753](https://github.com/leanprover/lean4/pull/5753))
* The `--lean` CLI option for `lake` was removed. Use the `LEAN` environment variable instead. ([#5684](https://github.com/leanprover/lean4/pull/5684))
* The `inductive ... :=`, `structure ... :=`, and `class ... :=` syntaxes have been deprecated in favor of the `... where` variants. The old syntax produces a warning, controlled by the `linter.deprecated` option. ([#5542](https://github.com/leanprover/lean4/pull/5542))
* The generated tactic configuration elaborators now land in `TacticM` to make use of the current recovery state. Commands that wish to elaborate configurations should now use `declare_command_config_elab` instead of `declare_config_elab` to get an elaborator landing in `CommandElabM`. Syntaxes should migrate to `optConfig` instead of `(config)?`, but the elaborators are reverse compatible. ([#5883](https://github.com/leanprover/lean4/pull/5883))

645
releases/v4.15.0.md Normal file
View File

@@ -0,0 +1,645 @@
v4.15.0
----------
## Language
- [#4595](https://github.com/leanprover/lean4/pull/4595) implements `Simp.Config.implicitDefEqsProofs`. When `true`
(default: `true`), `simp` will **not** create a proof term for a
rewriting rule associated with an `rfl`-theorem. Rewriting rules are
provided by users by annotating theorems with the attribute `@[simp]`.
If the proof of the theorem is just `rfl` (reflexivity), and
`implicitDefEqProofs := true`, `simp` will **not** create a proof term
which is an application of the annotated theorem.
- [#5429](https://github.com/leanprover/lean4/pull/5429) avoid negative environment lookup
- [#5501](https://github.com/leanprover/lean4/pull/5501) ensure `instantiateMVarsProfiling` adds a trace node
- [#5856](https://github.com/leanprover/lean4/pull/5856) adds a feature to the the mutual def elaborator where the
`instance` command yields theorems instead of definitions when the class
is a `Prop`.
- [#5907](https://github.com/leanprover/lean4/pull/5907) unset trailing for `simpa?` "try this" suggestion
- [#5920](https://github.com/leanprover/lean4/pull/5920) changes the rule for which projections become instances. Before,
all parents along with all indirect ancestors that were represented as
subobject fields would have their projections become instances. Now only
projections for direct parents become instances.
- [#5934](https://github.com/leanprover/lean4/pull/5934) make `all_goals` admit goals on failure
- [#5942](https://github.com/leanprover/lean4/pull/5942) introduce synthetic atoms in bv_decide
- [#5945](https://github.com/leanprover/lean4/pull/5945) adds a new definition `Message.kind` which returns the top-level
tag of a message. This is serialized as the new field `kind` in
`SerialMessaege` so that i can be used by external consumers (e.g.,
Lake) to identify messages via `lean --json`.
- [#5968](https://github.com/leanprover/lean4/pull/5968) `arg` conv tactic misreported number of arguments on error
- [#5979](https://github.com/leanprover/lean4/pull/5979) BitVec.twoPow in bv_decide
- [#5991](https://github.com/leanprover/lean4/pull/5991) simplifies the implementation of `omega`.
- [#5992](https://github.com/leanprover/lean4/pull/5992) fix style in bv_decide normalizer
- [#5999](https://github.com/leanprover/lean4/pull/5999) adds configuration options for
`decide`/`decide!`/`native_decide` and refactors the tactics to be
frontends to the same backend. Adds a `+revert` option that cleans up
the local context and reverts all local variables the goal depends on,
along with indirect propositional hypotheses. Makes `native_decide` fail
at elaboration time on failure without sacrificing performance (the
decision procedure is still evaluated just once). Now `native_decide`
supports universe polymorphism.
- [#6010](https://github.com/leanprover/lean4/pull/6010) changes `bv_decide`'s configuration from lots of `set_option` to
an elaborated config like `simp` or `omega`. The notable exception is
`sat.solver` which is still a `set_option` such that users can configure
a custom SAT solver globally for an entire project or file. Additionally
it introduces the ability to set `maxSteps` for the simp preprocessing
run through the new config.
- [#6012](https://github.com/leanprover/lean4/pull/6012) improves the validation of new syntactic tokens. Previously, the
validation code had inconsistencies: some atoms would be accepted only
if they had a leading space as a pretty printer hint. Additionally,
atoms with internal whitespace are no longer allowed.
- [#6016](https://github.com/leanprover/lean4/pull/6016) removes the `decide!` tactic in favor of `decide +kernel`
(breaking change).
- [#6019](https://github.com/leanprover/lean4/pull/6019) removes @[specilize] from `MkBinding.mkBinding`, which is a
function that cannot be specialized (as none of its arguments are
functions). As a result, the specializable function `Nat.foldRevM.loop`
doesn't get specialized, which leads to worse performing code.
- [#6022](https://github.com/leanprover/lean4/pull/6022) makes the `change` tactic and conv tactic use the same
elaboration strategy. It works uniformly for both the target and local
hypotheses. Now `change` can assign metavariables, for example:
```lean
example (x y z : Nat) : x + y = z := by
change ?a = _
let w := ?a
-- now `w : Nat := x + y`
```
- [#6024](https://github.com/leanprover/lean4/pull/6024) fixes a bug where the monad lift coercion elaborator would
partially unify expressions even if they were not monads. This could be
taken advantage of to propagate information that could help elaboration
make progress, for example the first `change` worked because the monad
lift coercion elaborator was unifying `@Eq _ _` with `@Eq (Nat × Nat)
p`:
```lean
example (p : Nat × Nat) : p = p := by
change _ = _, _ -- used to work (yielding `p = (p.fst, p.snd)`), now it doesn't
change _, _ = _ -- never worked
```
As such, this is a breaking change; you may need to adjust expressions
to include additional implicit arguments.
- [#6029](https://github.com/leanprover/lean4/pull/6029) adds a normalization rule to `bv_normalize` (which is used by
`bv_decide`) that converts `x / 2^k` into `x >>> k` under suitable
conditions. This allows us to simplify the expensive division circuits
that are used for bitblasting into much cheaper shifting circuits.
Concretely, it allows for the following canonicalization:
- [#6030](https://github.com/leanprover/lean4/pull/6030) fixes `simp only [· ∈ ·]` after #5020.
- [#6035](https://github.com/leanprover/lean4/pull/6035) introduces the and flattening pre processing pass from Bitwuzla
to `bv_decide`. It splits hypotheses of the form `(a && b) = true` into
`a = true` and `b = true` which has synergy potential with the already
existing embedded constraint substitution pass.
- [#6037](https://github.com/leanprover/lean4/pull/6037) fixes `bv_decide`'s embedded constraint substitution to generate
correct counter examples in the corner case where duplicate theorems are
in the local context.
- [#6045](https://github.com/leanprover/lean4/pull/6045) add `LEAN_ALWAYS_INLINE` to some functions
- [#6048](https://github.com/leanprover/lean4/pull/6048) fixes `simp?` suggesting output with invalid indentation
- [#6051](https://github.com/leanprover/lean4/pull/6051) mark `Meta.Context.config` as private
- [#6053](https://github.com/leanprover/lean4/pull/6053) fixes the caching infrastructure for `whnf` and `isDefEq`,
ensuring the cache accounts for all relevant configuration flags. It
also cleans up the `WHNF.lean` module and improves the configuration of
`whnf`.
- [#6061](https://github.com/leanprover/lean4/pull/6061) adds a simp_arith benchmark.
- [#6062](https://github.com/leanprover/lean4/pull/6062) optimize Nat.Linear.Expr.toPoly
- [#6064](https://github.com/leanprover/lean4/pull/6064) optimize Nat.Linear.Poly.norm
- [#6068](https://github.com/leanprover/lean4/pull/6068) improves the asymptotic performance of `simp_arith` when there are many variables to consider.
- [#6077](https://github.com/leanprover/lean4/pull/6077) adds options to `bv_decide`'s configuration structure such that
all non mandatory preprocessing passes can be disabled.
- [#6082](https://github.com/leanprover/lean4/pull/6082) changes how the canonicalizer handles `forall` and `lambda`,
replacing bvars with temporary fvars. Fixes a bug reported by @hrmacbeth
on
[zulip](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Quantifiers.20in.20CanonM/near/482483448).
- [#6093](https://github.com/leanprover/lean4/pull/6093) use mkFreshUserName in ArgsPacker
- [#6096](https://github.com/leanprover/lean4/pull/6096) improves the `#print` command for structures to show all fields
and which parents the fields were inherited from, hiding internal
details such as which parents are represented as subobjects. This
information is still present in the constructor if needed. The pretty
printer for private constants is also improved, and it now handles
private names from the current module like any other name; private names
from other modules are made hygienic.
- [#6098](https://github.com/leanprover/lean4/pull/6098) modifies `Lean.MVarId.replaceTargetDefEq` and
`Lean.MVarId.replaceLocalDeclDefEq` to use `Expr.equal` instead of
`Expr.eqv` when determining whether the expression has changed. This is
justified on the grounds that binder names and binder infos are
user-visible and affect elaboration.
- [#6105](https://github.com/leanprover/lean4/pull/6105) fixes a stack overflow caused by a cyclic assignment in the
metavariable context. The cycle is unintentionally introduced by the
structure instance elaborator.
- [#6108](https://github.com/leanprover/lean4/pull/6108) turn off pp.mvars in apply? results
- [#6109](https://github.com/leanprover/lean4/pull/6109) fixes an issue in the `injection` tactic. This tactic may
execute multiple sub-tactics. If any of them fail, we must backtrack the
partial assignment. This issue was causing the error: "`mvarId` is
already assigned" in issue #6066. The issue is not yet resolved, as the
equation generator for the match expressions is failing in the example
provided in this issue.
- [#6112](https://github.com/leanprover/lean4/pull/6112) makes stricter requirements for the `@[deprecated]` attribute,
requiring either a replacement identifier as `@[deprecated bar]` or
suggestion text `@[deprecated "Past its use by date"]`, and also
requires a `since := "..."` field.
- [#6114](https://github.com/leanprover/lean4/pull/6114) liberalizes atom rules by allowing `''` to be a prefix of an
atom, after #6012 only added an exception for `''` alone, and also adds
some unit tests for atom validation.
- [#6116](https://github.com/leanprover/lean4/pull/6116) fixes a bug where structural recursion did not work when indices
of the recursive argument appeared as function parameters in a different
order than in the argument's type's definition.
- [#6125](https://github.com/leanprover/lean4/pull/6125) adds support for `structure` in `mutual` blocks, allowing
inductive types defined by `inductive` and `structure` to be mutually
recursive. The limitations are (1) that the parents in the `extends`
clause must be defined before the `mutual` block and (2) mutually
recursive classes are not allowed (a limitation shared by `class
inductive`). There are also improvements to universe level inference for
inductive types and structures. Breaking change: structure parents now
elaborate with the structure in scope (fix: use qualified names or
rename the structure to avoid shadowing), and structure parents no
longer elaborate with autoimplicits enabled.
- [#6128](https://github.com/leanprover/lean4/pull/6128) does the same fix as #6104, but such that it doesn't break the
test/the file in `Plausible`. This is done by not creating unused let
binders in metavariable types that are made by `elimMVar`. (This is also
a positive thing for users looking at metavariable types, for example in
error messages)
- [#6129](https://github.com/leanprover/lean4/pull/6129) fixes a bug at `isDefEq` when `zetaDelta := false`. See new test
for a small example that exposes the issue.
- [#6131](https://github.com/leanprover/lean4/pull/6131) fixes a bug at the definitional equality test (`isDefEq`). At
unification constraints of the form `c.{u} =?= c.{v}`, it was not trying
to unfold `c`. This bug did not affect the kernel.
- [#6141](https://github.com/leanprover/lean4/pull/6141) make use of recursive structures in snapshot types
- [#6145](https://github.com/leanprover/lean4/pull/6145) fixes the `revert` tactic so that it creates a `syntheticOpaque`
metavariable as the new goal, instead of a `natural` metavariable
- [#6146](https://github.com/leanprover/lean4/pull/6146) fixes a non-termination bug that occurred when generating the
match-expression splitter theorem. The bug was triggered when the proof
automation for the splitter theorem repeatedly applied `injection` to
the same local declaration, as it could not be removed due to forward
dependencies. See issue #6065 for an example that reproduces this issue.
- [#6165](https://github.com/leanprover/lean4/pull/6165) modifies structure instance notation and `where` notation to use
the same notation for fields. Structure instance notation now admits
binders, type ascriptions, and equations, and `where` notation admits
full structure lvals. Examples of these for structure instance notation:
```lean
structure PosFun where
f : Nat Nat
pos : n, 0 < f n
```
- [#6168](https://github.com/leanprover/lean4/pull/6168) extends the "motive is not type correct" error message for the
rewrite tactic to explain what it means. It also pretty prints the
type-incorrect motive and reports the type error.
- [#6170](https://github.com/leanprover/lean4/pull/6170) adds core metaprogramming functions for forking off background
tasks from elaboration such that their results are visible to reporting
and the language server
- [#6175](https://github.com/leanprover/lean4/pull/6175) fixes a bug with the `structure`/`class` command where if there
are parents that are not represented as subobjects but which used other
parents as instances, then there would be a kernel error. Closes #2611.
- [#6180](https://github.com/leanprover/lean4/pull/6180) fixes a non-termination bug that occurred when generating the
match-expression equation theorems. The bug was triggered when the proof
automation for the equation theorem repeatedly applied `injection(` to
the same local declaration, as it could not be removed due to forward
dependencies. See issue #6067 for an example that reproduces this issue.
- [#6189](https://github.com/leanprover/lean4/pull/6189) changes how generalized field notation ("dot notation") resolves
the function. The new resolution rule is that if `x : S`, then `x.f`
resolves the name `S.f` relative to the root namespace (hence it now
affected by `export` and `open`). Breaking change: aliases now resolve
differently. Before, if `x : S`, and if `S.f` is an alias for `S'.f`,
then `x.f` would use `S'.f` and look for an argument of type `S'`. Now,
it looks for an argument of type `S`, which is more generally useful
behavior. Code making use of the old behavior should consider defining
`S` or `S'` in terms of the other, since dot notation can unfold
definitions during resolution.
- [#6206](https://github.com/leanprover/lean4/pull/6206) makes it possible to write `rw (occs := [1,2]) ...` instead of
`rw (occs := .pos [1,2]) ...` by adding a coercion from `List.Nat` to
`Lean.Meta.Occurrences`.
- [#6220](https://github.com/leanprover/lean4/pull/6220) adds proper support for `let_fun` in `simp`.
- [#6236](https://github.com/leanprover/lean4/pull/6236) fixes an issue where edits to a command containing a nested
docstring fail to reparse the entire command.
## Library
- [#4904](https://github.com/leanprover/lean4/pull/4904) introduces date and time functionality to the Lean 4 Std.
- [#5616](https://github.com/leanprover/lean4/pull/5616) is a follow-up to https://github.com/leanprover/lean4/pull/5609,
where we add lemmas characterizing `smtUDiv` and `smtSDiv`'s behavior
when the denominator is zero.
- [#5866](https://github.com/leanprover/lean4/pull/5866) verifies the `keys` function on `Std.HashMap`.
- [#5885](https://github.com/leanprover/lean4/pull/5885) add Int16/Int32/Int64
- [#5926](https://github.com/leanprover/lean4/pull/5926) add `Option.or_some'`
- [#5927](https://github.com/leanprover/lean4/pull/5927) `List.pmap_eq_self`
- [#5937](https://github.com/leanprover/lean4/pull/5937) upstream lemmas about Fin.foldX
- [#5938](https://github.com/leanprover/lean4/pull/5938) upstream List.ofFn and relate to Array.ofFn
- [#5941](https://github.com/leanprover/lean4/pull/5941) List.mapFinIdx, lemmas, relate to Array version
- [#5949](https://github.com/leanprover/lean4/pull/5949) consolidate `decide_True` and `decide_true_eq_true`
- [#5950](https://github.com/leanprover/lean4/pull/5950) relate Array.takeWhile with List.takeWhile
- [#5951](https://github.com/leanprover/lean4/pull/5951) remove @[simp] from BitVec.ofFin_sub and sub_ofFin
- [#5952](https://github.com/leanprover/lean4/pull/5952) relate Array.eraseIdx with List.eraseIdx
- [#5961](https://github.com/leanprover/lean4/pull/5961) define ISize and basic operations on it
- [#5969](https://github.com/leanprover/lean4/pull/5969) upstream List.insertIdx from Batteries, lemmas from Mathlib, and revise lemmas
- [#5970](https://github.com/leanprover/lean4/pull/5970) deprecate Array.split in favour of identical Array.partition
- [#5971](https://github.com/leanprover/lean4/pull/5971) relate Array.isPrefixOf with List.isPrefixOf
- [#5972](https://github.com/leanprover/lean4/pull/5972) relate Array.zipWith/zip/unzip with List versions
- [#5974](https://github.com/leanprover/lean4/pull/5974) add another List.find?_eq_some lemma
- [#5981](https://github.com/leanprover/lean4/pull/5981) names the default SizeOf instance `instSizeOfDefault`
- [#5982](https://github.com/leanprover/lean4/pull/5982) minor lemmas about List.ofFn
- [#5984](https://github.com/leanprover/lean4/pull/5984) adds lemmas for `List` for the interactions between {`foldl`,
`foldr`, `foldlM`, `foldlrM`} and {`filter`, `filterMap`}.
- [#5985](https://github.com/leanprover/lean4/pull/5985) relates the operations `findSomeM?`, `findM?`, `findSome?`, and
`find?` on `Array` with the corresponding operations on `List`, and also
provides simp lemmas for the `Array` operations `findSomeRevM?`,
`findRevM?`, `findSomeRev?`, `findRev?` (in terms of `reverse` and the
usual forward find operations).
- [#5987](https://github.com/leanprover/lean4/pull/5987) BitVec.getMsbD in bv_decide
- [#5988](https://github.com/leanprover/lean4/pull/5988) changes the signature of `Array.set` to take a `Nat`, and a
tactic-provided bound, rather than a `Fin`.
- [#5995](https://github.com/leanprover/lean4/pull/5995) BitVec.sshiftRight' in bv_decide
- [#6007](https://github.com/leanprover/lean4/pull/6007) List.modifyTailIdx naming fix
- [#6008](https://github.com/leanprover/lean4/pull/6008) missing @[ext] attribute on monad transformer ext lemmas
- [#6023](https://github.com/leanprover/lean4/pull/6023) variants of List.forIn_eq_foldlM
- [#6025](https://github.com/leanprover/lean4/pull/6025) deprecate duplicated Fin.size_pos
- [#6032](https://github.com/leanprover/lean4/pull/6032) changes the signature of `Array.get` to take a Nat and a proof,
rather than a `Fin`, for consistency with the rest of the (planned)
Array API. Note that because of bootstrapping issues we can't provide
`get_elem_tactic` as an autoparameter for the proof. As users will
mostly use the `xs[i]` notation provided by `GetElem`, this hopefully
isn't a problem.
- [#6041](https://github.com/leanprover/lean4/pull/6041) modifies the order of arguments for higher-order `Array`
functions, preferring to put the `Array` last (besides positional
arguments with defaults). This is more consistent with the `List` API,
and is more flexible, as dot notation allows two different partially
applied versions.
- [#6049](https://github.com/leanprover/lean4/pull/6049) adds a primitive for accessing the current thread ID
- [#6052](https://github.com/leanprover/lean4/pull/6052) adds `Array.pmap`, as well as a `@[csimp]` lemma in terms of the
no-copy `Array.attachWith`.
- [#6055](https://github.com/leanprover/lean4/pull/6055) adds lemmas about for loops over `Array`, following the existing
lemmas for `List`.
- [#6056](https://github.com/leanprover/lean4/pull/6056) upstream some NameMap functions
- [#6060](https://github.com/leanprover/lean4/pull/6060) implements conversion functions from `Bool` to all `UIntX` and
`IntX` types.
- [#6070](https://github.com/leanprover/lean4/pull/6070) adds the Lean.RArray data structure.
- [#6074](https://github.com/leanprover/lean4/pull/6074) allow `Sort u` in `Squash`
- [#6094](https://github.com/leanprover/lean4/pull/6094) adds raw transmutation of floating-point numbers to and from
`UInt64`. Floats and UInts share the same endianness across all
supported platforms. The IEEE 754 standard precisely specifies the bit
layout of floats. Note that `Float.toBits` is distinct from
`Float.toUInt64`, which attempts to preserve the numeric value rather
than the bitwise value.
- [#6095](https://github.com/leanprover/lean4/pull/6095) generalize `List.get_mem`
- [#6097](https://github.com/leanprover/lean4/pull/6097) naming convention and `NaN` normalization
- [#6102](https://github.com/leanprover/lean4/pull/6102) moves `IO.rand` and `IO.setRandSeed` to be in the `BaseIO`
monad.
- [#6106](https://github.com/leanprover/lean4/pull/6106) fix naming of left/right injectivity lemmas
- [#6111](https://github.com/leanprover/lean4/pull/6111) fills in the API for `Array.findSome?` and `Array.find?`,
transferring proofs from the corresponding List statements.
- [#6120](https://github.com/leanprover/lean4/pull/6120) adds theorems `BitVec.(getMsbD, msb)_(rotateLeft, rotateRight)`.
- [#6126](https://github.com/leanprover/lean4/pull/6126) adds lemmas for extracting a given bit of a `BitVec` obtained
via `sub`/`neg`/`sshiftRight'`/`abs`.
- [#6130](https://github.com/leanprover/lean4/pull/6130) adds `Lean.loadPlugin` which exposes functionality similar to
the `lean` executable's `--plugin` option to Lean code.
- [#6132](https://github.com/leanprover/lean4/pull/6132) duplicates the verification API for
`List.attach`/`attachWith`/`pmap` over to `Array`.
- [#6133](https://github.com/leanprover/lean4/pull/6133) replaces `Array.feraseIdx` and `Array.insertAt` with
`Array.eraseIdx` and `Array.insertIdx`, both of which take a `Nat`
argument and a tactic-provided proof that it is in bounds. We also have
`eraseIdxIfInBounds` and `insertIdxIfInBounds` which are noops if the
index is out of bounds. We also provide a `Fin` valued version of
`Array.findIdx?`. Together, these quite ergonomically improve the array
indexing safety at a number of places in the compiler/elaborator.
- [#6136](https://github.com/leanprover/lean4/pull/6136) fixes the run-time evaluation of `(default : Float)`.
- [#6139](https://github.com/leanprover/lean4/pull/6139) modifies the signature of the functions `Nat.fold`,
`Nat.foldRev`, `Nat.any`, `Nat.all`, so that the function is passed the
upper bound. This allows us to change runtime array bounds checks to
compile time checks in many places.
- [#6148](https://github.com/leanprover/lean4/pull/6148) adds a primitive for creating temporary directories, akin to the
existing functionality for creating temporary files.
- [#6149](https://github.com/leanprover/lean4/pull/6149) completes the elementwise accessors for `ofNatLt`, `allOnes`,
and `not` by adding their implementations of `getMsbD`.
- [#6151](https://github.com/leanprover/lean4/pull/6151) completes the `toInt` interface for `BitVec` bitwise operations.
- [#6154](https://github.com/leanprover/lean4/pull/6154) implements `BitVec.toInt_abs`.
- [#6155](https://github.com/leanprover/lean4/pull/6155) adds `toNat` theorems for `BitVec.signExtend.`
- [#6157](https://github.com/leanprover/lean4/pull/6157) adds toInt theorems for BitVec.signExtend.
- [#6160](https://github.com/leanprover/lean4/pull/6160) adds theorem `mod_eq_sub`, makes theorem
`sub_mul_eq_mod_of_lt_of_le` not private anymore and moves its location
within the `rotate*` section to use it in other proofs.
- [#6184](https://github.com/leanprover/lean4/pull/6184) uses `Array.findFinIdx?` in preference to `Array.findIdx?` where
it allows converting a runtime bounds check to a compile time bounds
check.
- [#6188](https://github.com/leanprover/lean4/pull/6188) completes the `toNat` theorems for the bitwise operations
(`and`, `or`, `xor`, `shiftLeft`, `shiftRight`) of the UInt types and
adds `toBitVec` theorems as well. It also renames `and_toNat` to
`toNat_and` to fit with the current naming convention.
- [#6190](https://github.com/leanprover/lean4/pull/6190) adds the builtin simproc `USize.reduceToNat` which reduces the
`USize.toNat` operation on literals less than `UInt32.size` (i.e.,
`4294967296`).
- [#6191](https://github.com/leanprover/lean4/pull/6191) adds `Array.zipWithAll`, and the basic lemmas relating it to
`List.zipWithAll`.
- [#6192](https://github.com/leanprover/lean4/pull/6192) adds deprecations for `Lean.HashMap` functions which did not
receive deprecation attributes initially.
- [#6193](https://github.com/leanprover/lean4/pull/6193) completes the TODO in `Init.Data.Array.BinSearch`, removing the
`partial` keyword and converting runtime bounds checks to compile time
bounds checks.
- [#6194](https://github.com/leanprover/lean4/pull/6194) changes the signature of `Array.swap`, so it takes `Nat`
arguments with tactic provided bounds checking. It also renames
`Array.swap!` to `Array.swapIfInBounds`.
- [#6195](https://github.com/leanprover/lean4/pull/6195) renames `Array.setD` to `Array.setIfInBounds`.
- [#6197](https://github.com/leanprover/lean4/pull/6197) upstreams the definition of `Vector` from Batteries, along with
the basic functions.
- [#6200](https://github.com/leanprover/lean4/pull/6200) upstreams `Nat.lt_pow_self` and `Nat.lt_two_pow` from Mathlib
and uses them to prove the simp theorem `Nat.mod_two_pow`.
- [#6202](https://github.com/leanprover/lean4/pull/6202) makes `USize.toUInt64` a regular non-opaque definition.
- [#6203](https://github.com/leanprover/lean4/pull/6203) adds the theorems `le_usize_size` and `usize_size_le`, which
make proving inequalities about `USize.size` easier.
- [#6205](https://github.com/leanprover/lean4/pull/6205) upstreams some UInt theorems from Batteries and adds more
`toNat`-related theorems. It also adds the missing `UInt8` and `UInt16`
to/from `USize` conversions so that the the interface is uniform across
the UInt types.
- [#6207](https://github.com/leanprover/lean4/pull/6207) ensures the `Fin.foldl` and `Fin.foldr` are semireducible.
Without this the defeq `example (f : Fin 3 → ) : List.ofFn f = [f 0, f
1, f 2] := rfl` was failing.
- [#6208](https://github.com/leanprover/lean4/pull/6208) fix Vector.indexOf?
- [#6217](https://github.com/leanprover/lean4/pull/6217) adds `simp` lemmas about `List`'s `==` operation.
- [#6221](https://github.com/leanprover/lean4/pull/6221) fixes:
- Problems in other linux distributions that the default `tzdata`
directory is not the same as previously defined by ensuring it with a
fallback behavior when directory is missing.
- Trim unnecessary characters from local time identifier.
- [#6222](https://github.com/leanprover/lean4/pull/6222) changes the definition of `HashSet.insertMany` and
`HashSet.Raw.insertMany` so that it is equivalent to repeatedly calling
`HashSet.insert`/`HashSet.Raw.insert`. It also clarifies the docstrings
of all the `insert` and `insertMany` functions.
- [#6230](https://github.com/leanprover/lean4/pull/6230) copies some lemmas about `List.foldX` to `Array`.
- [#6233](https://github.com/leanprover/lean4/pull/6233) upstreams lemmas about `Vector` from Batteries.
- [#6234](https://github.com/leanprover/lean4/pull/6234) upstreams the definition and basic lemmas about `List.finRange`
from Batteries.
- [#6235](https://github.com/leanprover/lean4/pull/6235) relates that operations `Nat.fold`/`foldRev`/`any`/`all` to the
corresponding List operations over `List.finRange`.
- [#6241](https://github.com/leanprover/lean4/pull/6241) refactors `Array.qsort` to remove runtime array bounds checks,
and avoids the use of `partial`. We use the `Vector` API, along with
auto_params, to avoid having to write any proofs. The new code
benchmarks indistinguishably from the old.
- [#6242](https://github.com/leanprover/lean4/pull/6242) deprecates `Fin.ofNat` in favour of `Fin.ofNat'` (which takes an
`[NeZero]` instance, rather than returning an element of `Fin (n+1)`).
- [#6247](https://github.com/leanprover/lean4/pull/6247) adds the theorems `numBits_pos`, `le_numBits`, `numBits_le` ,
which make proving inequalities about `System.Platform.numBits` easier.
## Compiler
- [#5840](https://github.com/leanprover/lean4/pull/5840) changes `lean_sharecommon_{eq,hash}` to only consider the
salient bytes of an object, and not any bytes of any
unspecified/uninitialized unused capacity.
- [#6087](https://github.com/leanprover/lean4/pull/6087) fixes a bug in the constant folding for the `Nat.ble` and
`Nat.blt` function in the old code generator, leading to a
miscompilation.
- [#6143](https://github.com/leanprover/lean4/pull/6143) should make lean better-behaved around sanitizers, per
https://github.com/google/sanitizers/issues/1688.
As far as I can tell,
https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn#algorithm
replaces local variables with heap allocations, and so taking the
address of a local is not effective at producing a monotonic measure of
stack usage.
- [#6209](https://github.com/leanprover/lean4/pull/6209) documents under which conditions `Runtime.markPersistent` is
unsafe and adjusts the elaborator accordingly
- [#6257](https://github.com/leanprover/lean4/pull/6257) harden `markPersistent` uses
## Pretty Printing
- [#2934](https://github.com/leanprover/lean4/pull/2934) adds the option `pp.parens` (default: false) that causes the
pretty printer to eagerly insert parentheses, which can be useful for
teaching and for understanding the structure of expressions. For
example, it causes `p → q → r` to pretty print as `p → (q → r)`.
- [#6014](https://github.com/leanprover/lean4/pull/6014) prevents `Nat.succ ?_` from pretty printing as `?_.succ`, which
should make `apply?` be more usable.
- [#6085](https://github.com/leanprover/lean4/pull/6085) improves the term info for coercions marked with
`CoeFnType.coeFun` (such as `DFunLike.coe` in Mathlib), making "go to
definition" on the function name work. Hovering over such a coerced
function will show the coercee rather than the coercion expression. The
coercion expression can still be seen by hovering over the whitespace in
the function application.
- [#6096](https://github.com/leanprover/lean4/pull/6096) improves the `#print` command for structures to show all fields
and which parents the fields were inherited from, hiding internal
details such as which parents are represented as subobjects. This
information is still present in the constructor if needed. The pretty
printer for private constants is also improved, and it now handles
private names from the current module like any other name; private names
from other modules are made hygienic.
- [#6119](https://github.com/leanprover/lean4/pull/6119) adds a new delab option `pp.coercions.types` which, when
enabled, will display all coercions with an explicit type ascription.
- [#6161](https://github.com/leanprover/lean4/pull/6161) ensures whitespace is printed before `+opt` and `-opt`
configuration options when pretty printing, improving the experience of
tactics such as `simp?`.
- [#6181](https://github.com/leanprover/lean4/pull/6181) fixes a bug where the signature pretty printer would ignore the
current setting of `pp.raw`. This fixes an issue where `#check ident`
would not heed `pp.raw`. Closes #6090.
- [#6213](https://github.com/leanprover/lean4/pull/6213) exposes the difference in "synthesized type class instance is
not definitionally equal" errors.
## Documentation
- [#6009](https://github.com/leanprover/lean4/pull/6009) fixes a typo in the docstring for prec and makes the text
slightly more precise.
- [#6040](https://github.com/leanprover/lean4/pull/6040) join → flatten in docstring
- [#6110](https://github.com/leanprover/lean4/pull/6110) does some mild refactoring of the `Lean.Elab.StructInst` module
while adding documentation.
- [#6144](https://github.com/leanprover/lean4/pull/6144) converts 3 doc-string to module docs since it seems that this is
what they were intended to be!
- [#6150](https://github.com/leanprover/lean4/pull/6150) refine kernel code comments
- [#6158](https://github.com/leanprover/lean4/pull/6158) adjust file reference in Data.Sum
- [#6239](https://github.com/leanprover/lean4/pull/6239) explains the order in which `Expr.abstract` introduces de Bruijn
indices.
## Server
- [#5835](https://github.com/leanprover/lean4/pull/5835) adds auto-completion for the fields of structure instance notation. Specifically, querying the completions via `Ctrl+Space` in the whitespace of a structure instance notation will now bring up the full list of fields. Whitespace structure completion can be enabled for custom syntax by wrapping the parser for the list of fields in a `structInstFields` parser.
- [#5837](https://github.com/leanprover/lean4/pull/5837) fixes an old auto-completion bug where `x.` would issue
nonsensical completions when `x.` could not be elaborated as a dot
completion.
- [#5996](https://github.com/leanprover/lean4/pull/5996) avoid max heartbeat error in completion
- [#6031](https://github.com/leanprover/lean4/pull/6031) fixes a regression with go-to-definition and document highlight
misbehaving on tactic blocks.
- [#6246](https://github.com/leanprover/lean4/pull/6246) fixes a performance issue where the Lean language server would
walk the full project file tree every time a file was saved, blocking
the processing of all other requests and notifications and significantly
increasing overall language server latency after saving.
## Lake
- [#5684](https://github.com/leanprover/lean4/pull/5684) update toolchain on `lake update`
- [#6026](https://github.com/leanprover/lean4/pull/6026) adds a newline at end of each Lean file generated by `lake new`
templates.
- [#6218](https://github.com/leanprover/lean4/pull/6218) makes Lake no longer automatically fetch GitHub cloud releases
if the package build directory is already present (mirroring the
behavior of the Reservoir cache). This prevents the cache from
clobbering existing prebuilt artifacts. Users can still manually fetch
the cache and clobber the build directory by running `lake build
<pkg>:release`.
- [#6225](https://github.com/leanprover/lean4/pull/6225) makes `lake build` also eagerly print package materialization
log lines. Previously, only a `lake update` performed eager logging.
- [#6231](https://github.com/leanprover/lean4/pull/6231) improves the errors Lake produces when it fails to fetch a
dependency from Reservoir. If the package is not indexed, it will
produce a suggestion about how to require it from GitHub.
## Other
- [#6137](https://github.com/leanprover/lean4/pull/6137) adds support for displaying multiple threads in the trace
profiler output.
- [#6138](https://github.com/leanprover/lean4/pull/6138) fixes `trace.profiler.pp` not using the term pretty printer.
- [#6259](https://github.com/leanprover/lean4/pull/6259) ensures that nesting trace nodes are annotated with timing
information iff `trace.profiler` is active.

565
releases/v4.16.0.md Normal file
View File

@@ -0,0 +1,565 @@
v4.16.0
----------
## Highlights
### Unique `sorry`s
[#5757](https://github.com/leanprover/lean4/pull/5757) makes it harder to create "fake" theorems about definitions that
are stubbed-out with `sorry` by ensuring that each `sorry` is not
definitionally equal to any other. For example, this now fails:
```lean
example : (sorry : Nat) = sorry := rfl -- fails
```
However, this still succeeds, since the `sorry` is a single
indeterminate `Nat`:
```lean
def f (n : Nat) : Nat := sorry
example : f 0 = f 1 := rfl -- succeeds
```
One can be more careful by putting parameters to the right of the colon:
```lean
def f : (n : Nat) Nat := sorry
example : f 0 = f 1 := rfl -- fails
```
Most sources of synthetic sorries (recall: a sorry that originates from
the elaborator) are now unique, except for elaboration errors, since
making these unique tends to cause a confusing cascade of errors. In
general, however, such sorries are labeled. This enables "go to
definition" on `sorry` in the Infoview, which brings you to its origin.
The option `set_option pp.sorrySource true` causes the pretty printer to
show source position information on sorries.
### Separators in numeric literals
[#6204](https://github.com/leanprover/lean4/pull/6204) lets `_` be used in numeric literals as a separator. For
example, `1_000_000`, `0xff_ff` or `0b_10_11_01_00`. New lexical syntax:
```text
numeral10 : [0-9]+ ("_"+ [0-9]+)*
numeral2 : "0" [bB] ("_"* [0-1]+)+
numeral8 : "0" [oO] ("_"* [0-7]+)+
numeral16 : "0" [xX] ("_"* hex_char+)+
float : numeral10 "." numeral10? [eE[+-]numeral10]
```
### Additional new featues
* [#6300](https://github.com/leanprover/lean4/pull/6300) adds the `debug.proofAsSorry` option. When enabled, the proofs
of theorems are ignored and replaced with `sorry`.
* [#6362](https://github.com/leanprover/lean4/pull/6362) adds the `--error=kind` option (shorthand: `-Ekind`) to the
`lean` CLI. When set, messages of `kind` (e.g.,
`linter.unusedVariables`) will be reported as errors. This setting does
nothing in interactive contexts (e.g., the server).
* [#6366](https://github.com/leanprover/lean4/pull/6366) adds support for `Float32` and fixes a bug in the runtime.
### Library updates
The Lean 4 library saw many changes that improve arithmetic reasoning, enhance data structure APIs,
and refine library organization. Key changes include better support for bitwise operations, shifts,
and conversions, expanded lemmas for `Array`, `Vector`, and `List`, and improved ordering definitions.
Some modules have been reorganized for clarity, and internal refinements ensure greater consistency and correctness.
### Breaking changes
[#6330](https://github.com/leanprover/lean4/pull/6330) removes unnecessary parameters from the functional induction
principles. This is a breaking change; broken code can typically be adjusted
simply by passing fewer parameters.
_This highlights section was contributed by Violetta Sim._
For this release, 201 changes landed. In addition to the 74 feature additions and 44 fixes listed below there were 7 refactoring changes, 5 documentation improvements and 62 chores.
## Language
* [#3696](https://github.com/leanprover/lean4/pull/3696) makes all message constructors handle pretty printer errors.
* [#4460](https://github.com/leanprover/lean4/pull/4460) runs all linters for a single command (together) on a separate
thread from further elaboration, making a first step towards
parallelizing the elaborator.
* [#5757](https://github.com/leanprover/lean4/pull/5757), see the highlights section above for details.
* [#6123](https://github.com/leanprover/lean4/pull/6123) ensures that the configuration in `Simp.Config` is used when
reducing terms and checking definitional equality in `simp`.
* [#6204](https://github.com/leanprover/lean4/pull/6204), see the highlights section above for details.
* [#6270](https://github.com/leanprover/lean4/pull/6270) fixes a bug that could cause the `injectivity` tactic to fail in
reducible mode, which could cause unfolding lemma generation to fail
(used by tactics such as `unfold`). In particular,
`Lean.Meta.isConstructorApp'?` was not aware that `n + 1` is equivalent
to `Nat.succ n`.
* [#6273](https://github.com/leanprover/lean4/pull/6273) modifies the "foo has been deprecated: use betterFoo instead"
warning so that foo and betterFoo are hoverable.
* [#6278](https://github.com/leanprover/lean4/pull/6278) enables simp configuration options to be passed to `norm_cast`.
* [#6286](https://github.com/leanprover/lean4/pull/6286) ensure `bv_decide` uses definitional equality in its reflection
procedure as much as possible. Previously it would build up explicit
congruence proofs for the kernel to check. This reduces the size of
proof terms passed to kernel speeds up checking of large reflection
proofs.
* [#6288](https://github.com/leanprover/lean4/pull/6288) uses Lean.RArray in bv_decide's reflection proofs. Giving
speedups on problems with lots of variables.
* [#6295](https://github.com/leanprover/lean4/pull/6295) sets up simprocs for all the remaining operations defined in
`Init.Data.Fin.Basic`
* [#6300](https://github.com/leanprover/lean4/pull/6300), see the highlights section above for details.
* [#6330](https://github.com/leanprover/lean4/pull/6330), see the highlights section above for details.
* [#6362](https://github.com/leanprover/lean4/pull/6362), see the highlights section above for details.
* [#6366](https://github.com/leanprover/lean4/pull/6366), see the highlights section above for details.
* [#6375](https://github.com/leanprover/lean4/pull/6375) fixes a bug in the simplifier. It was producing terms with loose
bound variables when eliminating unused `let_fun` expressions.
* [#6378](https://github.com/leanprover/lean4/pull/6378) adds an explanation to the error message when `cases` and
`induction` are applied to a term whose type is not an inductive type.
For `Prop`, these tactics now suggest the `by_cases` tactic. Example:
```
tactic 'cases' failed, major premise type is not an inductive type
Prop
```
* [#6381](https://github.com/leanprover/lean4/pull/6381) fixes a bug in `withTrackingZetaDelta` and
`withTrackingZetaDeltaSet`. The `MetaM` caches need to be reset. See new
test.
* [#6385](https://github.com/leanprover/lean4/pull/6385) fixes a bug in `simp_all?` that caused some local declarations
to be omitted from the `Try this:` suggestions.
* [#6386](https://github.com/leanprover/lean4/pull/6386) ensures that `revertAll` clears auxiliary declarations when
invoked directly by users.
* [#6387](https://github.com/leanprover/lean4/pull/6387) fixes a type error in the proof generated by the `contradiction`
tactic.
* [#6397](https://github.com/leanprover/lean4/pull/6397) ensures that `simp` and `dsimp` do not unfold definitions that
are not intended to be unfolded by the user. See issue #5755 for an
example affected by this issue.
* [#6398](https://github.com/leanprover/lean4/pull/6398) ensures `Meta.check` check projections.
* [#6412](https://github.com/leanprover/lean4/pull/6412) adds reserved names for congruence theorems used in the
simplifier and `grind` tactics. The idea is prevent the same congruence
theorems to be generated over and over again.
* [#6413](https://github.com/leanprover/lean4/pull/6413) introduces the following features to the WIP `grind` tactic:
- `Expr` internalization.
- Congruence theorem cache.
- Procedure for adding new facts
- New tracing options
- New preprocessing steps: fold projections and eliminate dangling
`Expr.mdata`
* [#6414](https://github.com/leanprover/lean4/pull/6414) fixes a bug in `Lean.Meta.Closure` that would introduce
under-applied delayed assignment metavariables, which would keep them
from ever getting instantiated. This bug affected `match` elaboration
when the expected type contained postponed elaboration problems, for
example tactic blocks.
* [#6419](https://github.com/leanprover/lean4/pull/6419) fixes multiple bugs in the WIP `grind` tactic. It also adds
support for printing the `grind` internal state.
* [#6428](https://github.com/leanprover/lean4/pull/6428) adds a new preprocessing step to the `grind` tactic:
universe-level normalization. The goal is to avoid missing equalities in
the congruence closure module.
* [#6430](https://github.com/leanprover/lean4/pull/6430) adds the predicate `Expr.fvarsSet a b`, which returns `true` if
and only if the free variables in `a` are a subset of the free variables
in `b`.
* [#6433](https://github.com/leanprover/lean4/pull/6433) adds a custom type and instance canonicalizer for the (WIP)
`grind` tactic. The `grind` tactic uses congruence closure but
disregards types, type formers, instances, and proofs. Proofs are
ignored due to proof irrelevance. Types, type formers, and instances are
considered supporting elements and are not factored into congruence
detection. Instead, `grind` only checks whether elements are
structurally equal, which, in the context of the `grind` tactic, is
equivalent to pointer equality. See new tests for examples where the
canonicalizer is important.
* [#6435](https://github.com/leanprover/lean4/pull/6435) implements the congruence table for the (WIP) `grind` tactic. It
also fixes several bugs, and adds a new preprocessing step.
* [#6437](https://github.com/leanprover/lean4/pull/6437) adds support for detecting congruent terms in the (WIP) `grind`
tactic. It also introduces the `grind.debug` option, which, when set to
`true`, checks many invariants after each equivalence class is merged.
This option is intended solely for debugging purposes.
* [#6438](https://github.com/leanprover/lean4/pull/6438) ensures `norm_cast` doesn't fail to act in the presence of
`no_index` annotations
* [#6441](https://github.com/leanprover/lean4/pull/6441) adds basic truth value propagation rules to the (WIP) `grind`
tactic.
* [#6442](https://github.com/leanprover/lean4/pull/6442) fixes the `checkParents` sanity check in `grind`.
* [#6443](https://github.com/leanprover/lean4/pull/6443) adds support for propagating the truth value of equalities in
the (WIP) `grind` tactic.
* [#6447](https://github.com/leanprover/lean4/pull/6447) refactors `grind` and adds support for invoking the simplifier
using the `GrindM` monad.
* [#6448](https://github.com/leanprover/lean4/pull/6448) declares the command `builtin_grind_propagator` for registering
equation propagator for `grind`. It also declares the auxiliary the
attribute.
* [#6449](https://github.com/leanprover/lean4/pull/6449) completes the implementation of the command
`builtin_grind_propagator`.
* [#6452](https://github.com/leanprover/lean4/pull/6452) adds support for generating (small) proofs for any two
expressions that belong to the same equivalence class in the `grind`
tactic state.
* [#6453](https://github.com/leanprover/lean4/pull/6453) improves bv_decide's performance in the presence of large
literals.
* [#6455](https://github.com/leanprover/lean4/pull/6455) fixes a bug in the equality proof generator in the (WIP) `grind`
tactic.
* [#6456](https://github.com/leanprover/lean4/pull/6456) fixes another bug in the equality proof generator in the (WIP)
`grind` tactic.
* [#6457](https://github.com/leanprover/lean4/pull/6457) adds support for generating congruence proofs for congruences
detected by the `grind` tactic.
* [#6458](https://github.com/leanprover/lean4/pull/6458) adds support for compact congruence proofs in the (WIP) `grind`
tactic. The `mkCongrProof` function now verifies whether the congruence
proof can be constructed using only `congr`, `congrFun`, and `congrArg`,
avoiding the need to generate the more complex `hcongr` auxiliary
theorems.
* [#6459](https://github.com/leanprover/lean4/pull/6459) adds the (WIP) `grind` tactic. It currently generates a warning
message to make it clear that the tactic is not ready for production.
* [#6461](https://github.com/leanprover/lean4/pull/6461) adds a new propagation rule for negation to the (WIP) `grind`
tactic.
* [#6463](https://github.com/leanprover/lean4/pull/6463) adds support for constructors to the (WIP) `grind` tactic. When
merging equivalence classes, `grind` checks for equalities between
constructors. If they are distinct, it closes the goal; if they are the
same, it applies injectivity.
* [#6464](https://github.com/leanprover/lean4/pull/6464) completes support for literal values in the (WIP) `grind`
tactic. `grind` now closes the goal whenever it merges two equivalence
classes with distinct literal values.
* [#6465](https://github.com/leanprover/lean4/pull/6465) adds support for projection functions to the (WIP) `grind`
tactic.
* [#6466](https://github.com/leanprover/lean4/pull/6466) completes the implementation of `addCongrTable` in the (WIP)
`grind` tactic. It also adds a new test to demonstrate why the extra
check is needed. It also updates the field `cgRoot` (congruence root).
* [#6468](https://github.com/leanprover/lean4/pull/6468) fixes issue #6467
* [#6469](https://github.com/leanprover/lean4/pull/6469) adds support code for implementing e-match in the (WIP) `grind`
tactic.
* [#6470](https://github.com/leanprover/lean4/pull/6470) introduces a command for specifying patterns used in the
heuristic instantiation of global theorems in the `grind` tactic. Note
that this PR only adds the parser.
* [#6472](https://github.com/leanprover/lean4/pull/6472) implements the command `grind_pattern`. The new command allows
users to associate patterns with theorems. These patterns are used for
performing heuristic instantiation with e-matching. In the future, we
will add the attributes `@[grind_eq]`, `@[grind_fwd]`, and
`@[grind_bwd]` to compute the patterns automatically for theorems.
* [#6473](https://github.com/leanprover/lean4/pull/6473) adds a deriving handler for the `ToExpr` class. It can handle
mutual and nested inductive types, however it falls back to creating
`partial` instances in such cases. This is upstreamed from the Mathlib
deriving handler written by @kmill, but has fixes to handle autoimplicit
universe level variables.
* [#6474](https://github.com/leanprover/lean4/pull/6474) adds pattern validation to the `grind_pattern` command. The new
`checkCoverage` function will also be used to implement the attributes
`@[grind_eq]`, `@[grind_fwd]`, and `@[grind_bwd]`.
* [#6475](https://github.com/leanprover/lean4/pull/6475) adds support for activating relevant theorems for the (WIP)
`grind` tactic. We say a theorem is relevant to a `grind` goal if the
symbols occurring in its patterns also occur in the goal.
* [#6478](https://github.com/leanprover/lean4/pull/6478) internalize nested ground patterns when activating ematch
theorems in the (WIP) `grind` tactic.
* [#6481](https://github.com/leanprover/lean4/pull/6481) implements E-matching for the (WIP) `grind` tactic. We still
need to finalize and internalize the new instances.
* [#6484](https://github.com/leanprover/lean4/pull/6484) addresses a few error messages where diffs weren't being
exposed.
* [#6485](https://github.com/leanprover/lean4/pull/6485) implements `Grind.EMatch.instantiateTheorem` in the (WIP)
`grind` tactic.
* [#6487](https://github.com/leanprover/lean4/pull/6487) adds source position information for `structure` parent
projections, supporting "go to definition". Closes #3063.
* [#6488](https://github.com/leanprover/lean4/pull/6488) fixes and refactors the E-matching module for the (WIP) `grind`
tactic.
* [#6490](https://github.com/leanprover/lean4/pull/6490) adds basic configuration options for the `grind` tactic.
* [#6492](https://github.com/leanprover/lean4/pull/6492) fixes a bug in the theorem instantiation procedure in the (WIP)
`grind` tactic.
* [#6497](https://github.com/leanprover/lean4/pull/6497) fixes another theorem instantiation bug in the `grind` tactic.
It also moves new instances to be processed to `Goal`.
* [#6498](https://github.com/leanprover/lean4/pull/6498) adds support in the `grind` tactic for propagating dependent
forall terms `forall (h : p), q[h]` where `p` is a proposition.
* [#6499](https://github.com/leanprover/lean4/pull/6499) fixes the proof canonicalizer for `grind`.
* [#6500](https://github.com/leanprover/lean4/pull/6500) fixes a bug in the `markNestedProofs` used in `grind`. See new
test.
* [#6502](https://github.com/leanprover/lean4/pull/6502) fixes a bug in the proof assembly procedure utilized by the
`grind` tactic.
* [#6503](https://github.com/leanprover/lean4/pull/6503) adds a simple strategy to the (WIP) `grind` tactic. It just
keeps internalizing new theorem instances found by E-matching.
* [#6506](https://github.com/leanprover/lean4/pull/6506) adds the `monotonicity` tactic, intended to be used inside the
`partial_fixpoint` feature.
* [#6508](https://github.com/leanprover/lean4/pull/6508) fixes a bug in the sanity checkers for the `grind` tactic. See
the new test for an example of a case where it was panicking.
* [#6509](https://github.com/leanprover/lean4/pull/6509) fixes a bug in the congruence closure data structure used in the
`grind` tactic. The new test includes an example that previously caused
a panic. A similar panic was also occurring in the test
`grind_nested_proofs.lean`.
* [#6510](https://github.com/leanprover/lean4/pull/6510) adds a custom congruence rule for equality in `grind`. The new
rule takes into account that `Eq` is a symmetric relation. In the
future, we will add support for arbitrary symmetric relations. The
current rule is important for propagating disequalities effectively in
`grind`.
* [#6512](https://github.com/leanprover/lean4/pull/6512) introduces support for user-defined fallback code in the `grind`
tactic. The fallback code can be utilized to inspect the state of
failing `grind` subgoals and/or invoke user-defined automation. Users
can now write `grind on_failure <code>`, where `<code>` should have the
type `GoalM Unit`. See the modified tests in this PR for examples.
* [#6513](https://github.com/leanprover/lean4/pull/6513) adds support for (dependent) if-then-else terms (i.e., `ite` and
`dite` applications) in the `grind` tactic.
* [#6514](https://github.com/leanprover/lean4/pull/6514) enhances the assertion of new facts in `grind` by avoiding the
creation of unnecessary metavariables.
## Library
* [#6182](https://github.com/leanprover/lean4/pull/6182) adds `BitVec.[toInt|toFin]_concat` and moves a couple of
theorems into the concat section, as `BitVec.msb_concat` is needed for
the `toInt_concat` proof.
* [#6188](https://github.com/leanprover/lean4/pull/6188) completes the `toNat` theorems for the bitwise operations
(`and`, `or`, `xor`, `shiftLeft`, `shiftRight`) of the UInt types and
adds `toBitVec` theorems as well. It also renames `and_toNat` to
`toNat_and` to fit with the current naming convention.
* [#6238](https://github.com/leanprover/lean4/pull/6238) adds theorems characterizing the value of the unsigned shift
right of a bitvector in terms of its 2s complement interpretation as an
integer.
Unsigned shift right by at least one bit makes the value of the
bitvector less than or equal to `2^(w-1)`,
makes the interpretation of the bitvector `Int` and `Nat` agree.
In the case when `n = 0`, then the shift right value equals the integer
interpretation.
* [#6244](https://github.com/leanprover/lean4/pull/6244) changes the implementation of `HashMap.toList`, so the ordering
agrees with `HashMap.toArray`.
* [#6272](https://github.com/leanprover/lean4/pull/6272) introduces the basic theory of permutations of `Array`s and
proves `Array.swap_perm`.
* [#6282](https://github.com/leanprover/lean4/pull/6282) moves `IO.Channel` and `IO.Mutex` from `Init` to `Std.Sync` and
renames them to `Std.Channel` and `Std.Mutex`.
* [#6294](https://github.com/leanprover/lean4/pull/6294) upstreams `List.length_flatMap`, `countP_flatMap` and
`count_flatMap` from Mathlib. These were not possible to state before we
upstreamed `List.sum`.
* [#6315](https://github.com/leanprover/lean4/pull/6315) adds `protected` to `Fin.cast` and `BitVec.cast`, to avoid
confusion with `_root_.cast`. These should mostly be used via
dot-notation in any case.
* [#6316](https://github.com/leanprover/lean4/pull/6316) adds lemmas simplifying `for` loops over `Option` into
`Option.pelim`, giving parity with lemmas simplifying `for` loops of
`List` into `List.fold`.
* [#6317](https://github.com/leanprover/lean4/pull/6317) completes the basic API for BitVec.ofBool.
* [#6318](https://github.com/leanprover/lean4/pull/6318) generalizes the universe level for `Array.find?`, by giving it a
separate implementation from `Array.findM?`.
* [#6324](https://github.com/leanprover/lean4/pull/6324) adds `GetElem` lemmas for the basic `Vector` operations.
* [#6333](https://github.com/leanprover/lean4/pull/6333) generalizes the panic functions to a type of `Sort u` rather
than `Type u`. This better supports universe polymorphic types and
avoids confusing errors.
* [#6334](https://github.com/leanprover/lean4/pull/6334) adds `Nat` theorems for distributing `>>>` over bitwise
operations, paralleling those of `BitVec`.
* [#6338](https://github.com/leanprover/lean4/pull/6338) adds `BitVec.[toFin|getMsbD]_setWidth` and
`[getMsb|msb]_signExtend` as well as `ofInt_toInt`.
* [#6341](https://github.com/leanprover/lean4/pull/6341) generalizes `DecidableRel` to allow a heterogeneous relation.
* [#6353](https://github.com/leanprover/lean4/pull/6353) reproduces the API around `List.any/all` for `Array.any/all`.
* [#6364](https://github.com/leanprover/lean4/pull/6364) makes fixes suggested by the Batteries environment linters,
particularly `simpNF`, and `unusedHavesSuffices`.
* [#6365](https://github.com/leanprover/lean4/pull/6365) expands the `Array.set` and `Array.setIfInBounds` lemmas to
match existing lemmas for `List.set`.
* [#6367](https://github.com/leanprover/lean4/pull/6367) brings Vector lemmas about membership and indexing to parity
with List and Array.
* [#6369](https://github.com/leanprover/lean4/pull/6369) adds lemmas about `Vector.set`, `anyM`, `any`, `allM`, and
`all`.
* [#6376](https://github.com/leanprover/lean4/pull/6376) adds theorems about `==` on `Vector`, reproducing those already
on `List` and `Array`.
* [#6379](https://github.com/leanprover/lean4/pull/6379) replaces the inductive predicate `List.lt` with an upstreamed version of `List.Lex` from Mathlib.
(Previously `Lex.lt` was defined in terms of `<`; now it is generalized to take an arbitrary relation.)
This subtly changes the notion of ordering on `List α`.
`List.lt` was a weaker relation: in particular if `l₁ < l₂`, then `a :: l₁ < b :: l₂` may hold according to `List.lt` even if `a` and `b` are merely incomparable (either neither `a < b` nor `b < a`), whereas according to `List.Lex` this would require `a = b`.
When `<` is total, in the sense that `¬ · < ·` is antisymmetric, then the two relations coincide.
Mathlib was already overriding the order instances for `List α`, so this change should not be noticed by anyone already using Mathlib.
We simultaneously add the boolean valued `List.lex` function, parameterised by a `BEq` typeclass and an arbitrary `lt` function. This will support the flexibility previously provided for `List.lt`, via a `==` function which is weaker than strict equality.
* [#6390](https://github.com/leanprover/lean4/pull/6390) redefines `Range.forIn'` and `Range.forM`, in preparation for
writing lemmas about them.
* [#6391](https://github.com/leanprover/lean4/pull/6391) requires that the step size in `Std.Range` is positive, to avoid
ill-specified behaviour.
* [#6396](https://github.com/leanprover/lean4/pull/6396) adds lemmas reducing for loops over `Std.Range` to for loops
over `List.range'`.
* [#6399](https://github.com/leanprover/lean4/pull/6399) adds basic lemmas about lexicographic order on Array and Vector,
achieving parity with List.
* [#6423](https://github.com/leanprover/lean4/pull/6423) adds missing lemmas about lexicographic order on
List/Array/Vector.
* [#6477](https://github.com/leanprover/lean4/pull/6477) adds the necessary domain theory that backs the
`partial_fixpoint` feature.
## Compiler
* [#6311](https://github.com/leanprover/lean4/pull/6311) adds support for `HEq` to the new code generator.
* [#6348](https://github.com/leanprover/lean4/pull/6348) adds support for `Float32` to the Lean runtime.
* [#6350](https://github.com/leanprover/lean4/pull/6350) adds missing features and fixes bugs in the `Float32` support
* [#6383](https://github.com/leanprover/lean4/pull/6383) ensures the new code generator produces code for `opaque`
definitions that are not tagged as `@[extern]`.
Remark: This is the behavior of the old code generator.
* [#6405](https://github.com/leanprover/lean4/pull/6405) adds support for erasure of `Decidable.decide` to the new code
generator. It also adds a new `Probe.runOnDeclsNamed` function, which is
helpful for writing targeted single-file tests of compiler internals.
* [#6415](https://github.com/leanprover/lean4/pull/6415) fixes a bug in the `sharecommon` module, which was returning
incorrect results for objects that had already been processed by
`sharecommon`. See the new test for an example that triggered the bug.
* [#6429](https://github.com/leanprover/lean4/pull/6429) adds support for extern LCNF decls, which is required for parity
with the existing code generator.
* [#6535](https://github.com/leanprover/lean4/pull/6535) avoids a linker warning on Windows.
* [#6547](https://github.com/leanprover/lean4/pull/6547) should prevent Lake from accidentally picking up other linkers
installed on the machine.
* [#6574](https://github.com/leanprover/lean4/pull/6574) actually prevents Lake from accidentally picking up other
toolchains installed on the machine.
## Pretty Printing
* [#5689](https://github.com/leanprover/lean4/pull/5689) adjusts the way the pretty printer unresolves names. It used to
make use of all `export`s when pretty printing, but now it only uses
`export`s that put names into parent namespaces (heuristic: these are
"API exports" that are intended by the library author), rather than
"horizontal exports" that put the names into an unrelated namespace,
which the dot notation feature in #6189 now incentivizes.
* [#5757](https://github.com/leanprover/lean4/pull/5757), aside from introducing labeled sorries, fixes the bug that the metadata attached to the pretty-printed representation of arguments with a borrow annotation (for example, the second argument of `String.append`), is inconsistent with the metadata attached to the regular arguments.
## Documentation
* [#6450](https://github.com/leanprover/lean4/pull/6450) adds a docstring to the `@[app_delab]` attribute.
## Server
* [#6279](https://github.com/leanprover/lean4/pull/6279) fixes a bug in structure instance field completion that caused
it to not function correctly for bracketed structure instances written
in Mathlib style.
* [#6408](https://github.com/leanprover/lean4/pull/6408) fixes a regression where goals that don't exist were being
displayed. The regression was triggered by #5835 and originally caused
by #4926.
## Lake
* [#6176](https://github.com/leanprover/lean4/pull/6176) changes Lake's build process to no longer use `leanc` for
compiling C files or linking shared libraries and executables. Instead,
it directly invokes the bundled compiler (or the native compiler if
none) using the necessary flags.
* [#6289](https://github.com/leanprover/lean4/pull/6289) adapts Lake modules to use `prelude` and includes them in the
`check-prelude` CI.
* [#6291](https://github.com/leanprover/lean4/pull/6291) ensures the the log error position is properly preserved when
prepending stray log entries to the job log. It also adds comparison
support for `Log.Pos`.
* [#6388](https://github.com/leanprover/lean4/pull/6388) merges `BuildJob` and `Job`, deprecating the former. `Job` now
contains a trace as part of its state which can be interacted with
monadically. also simplifies the implementation of `OpaqueJob`.
* [#6411](https://github.com/leanprover/lean4/pull/6411) adds the ability to override package entries in a Lake manifest
via a separate JSON file. This file can be specified on the command line
with `--packages` or applied persistently by placing it at
`.lake/package-overrides.json`.
* [#6422](https://github.com/leanprover/lean4/pull/6422) fixes a bug in #6388 where the `Package.afterBuildCahe*`
functions would produce different traces depending on whether the cache
was fetched.
* [#6627](https://github.com/leanprover/lean4/pull/6627) aims to fix the trace issues reported by Mathlib that are
breaking `lake exe cache` in downstream projects.
* [#6631](https://github.com/leanprover/lean4/pull/6631) sets `MACOSX_DEPLOYMENT_TARGET` for shared libraries (it was
previously only set for executables).
## Other
* [#6285](https://github.com/leanprover/lean4/pull/6285) upstreams the `ToLevel` typeclass from mathlib and uses it to
fix the existing `ToExpr` instances so that they are truly universe
polymorphic (previously it generated malformed expressions when the
universe level was nonzero). We improve on the mathlib definition of
`ToLevel` to ensure the class always lives in `Type`, irrespective of
the universe parameter.
* [#6363](https://github.com/leanprover/lean4/pull/6363) fixes errors at load time in the comparison mode of the Firefox
profiler.

1110
releases/v4.17.0.md Normal file

File diff suppressed because it is too large Load Diff

16
releases/v4.2.0.md Normal file
View File

@@ -0,0 +1,16 @@
v4.2.0
---------
* [isDefEq cache for terms not containing metavariables.](https://github.com/leanprover/lean4/pull/2644).
* Make [`Environment.mk`](https://github.com/leanprover/lean4/pull/2604) and [`Environment.add`](https://github.com/leanprover/lean4/pull/2642) private, and add [`replay`](https://github.com/leanprover/lean4/pull/2617) as a safer alternative.
* `IO.Process.output` no longer inherits the standard input of the caller.
* [Do not inhibit caching](https://github.com/leanprover/lean4/pull/2612) of default-level `match` reduction.
* [List the valid case tags](https://github.com/leanprover/lean4/pull/2629) when the user writes an invalid one.
* The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types.
* [Show path of failed import in Lake](https://github.com/leanprover/lean4/pull/2616).
* [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598).
* **Lake:** Add `postUpdate?` package configuration option. Used by a package to specify some code which should be run after a successful `lake update` of the package or one of its downstream dependencies. ([lake#185](https://github.com/leanprover/lake/issues/185))
* Improvements to Lake startup time ([#2572](https://github.com/leanprover/lean4/pull/2572), [#2573](https://github.com/leanprover/lean4/pull/2573))
* `refine e` now replaces the main goal with metavariables which were created during elaboration of `e` and no longer captures pre-existing metavariables that occur in `e` ([#2502](https://github.com/leanprover/lean4/pull/2502)).
* This is accomplished via changes to `withCollectingNewGoalsFrom`, which also affects `elabTermWithHoles`, `refine'`, `calc` (tactic), and `specialize`. Likewise, all of these now only include newly-created metavariables in their output.
* Previously, both newly-created and pre-existing metavariables occurring in `e` were returned inconsistently in different edge cases, causing duplicated goals in the infoview (issue [#2495](https://github.com/leanprover/lean4/issues/2495)), erroneously closed goals (issue [#2434](https://github.com/leanprover/lean4/issues/2434)), and unintuitive behavior due to `refine e` capturing previously-created goals appearing unexpectedly in `e` (no issue; see PR).

37
releases/v4.3.0.md Normal file
View File

@@ -0,0 +1,37 @@
v4.3.0
---------
* `simp [f]` does not unfold partial applications of `f` anymore. See issue [#2042](https://github.com/leanprover/lean4/issues/2042).
To fix proofs affected by this change, use `unfold f` or `simp (config := { unfoldPartialApp := true }) [f]`.
* By default, `simp` will no longer try to use Decidable instances to rewrite terms. In particular, not all decidable goals will be closed by `simp`, and the `decide` tactic may be useful in such cases. The `decide` simp configuration option can be used to locally restore the old `simp` behavior, as in `simp (config := {decide := true})`; this includes using Decidable instances to verify side goals such as numeric inequalities.
* Many bug fixes:
* [Add left/right actions to term tree coercion elaborator and make `^`` a right action](https://github.com/leanprover/lean4/pull/2778)
* [Fix for #2775, don't catch max recursion depth errors](https://github.com/leanprover/lean4/pull/2790)
* [Reduction of `Decidable` instances very slow when using `cases` tactic](https://github.com/leanprover/lean4/issues/2552)
* [`simp` not rewriting in binder](https://github.com/leanprover/lean4/issues/1926)
* [`simp` unfolding `let` even with `zeta := false` option](https://github.com/leanprover/lean4/issues/2669)
* [`simp` (with beta/zeta disabled) and discrimination trees](https://github.com/leanprover/lean4/issues/2281)
* [unknown free variable introduced by `rw ... at h`](https://github.com/leanprover/lean4/issues/2711)
* [`dsimp` doesn't use `rfl` theorems which consist of an unapplied constant](https://github.com/leanprover/lean4/issues/2685)
* [`dsimp` does not close reflexive equality goals if they are wrapped in metadata](https://github.com/leanprover/lean4/issues/2514)
* [`rw [h]` uses `h` from the environment in preference to `h` from the local context](https://github.com/leanprover/lean4/issues/2729)
* [missing `withAssignableSyntheticOpaque` for `assumption` tactic](https://github.com/leanprover/lean4/issues/2361)
* [ignoring default value for field warning](https://github.com/leanprover/lean4/issues/2178)
* [Cancel outstanding tasks on document edit in the language server](https://github.com/leanprover/lean4/pull/2648).
* [Remove unnecessary `%` operations in `Fin.mod` and `Fin.div`](https://github.com/leanprover/lean4/pull/2688)
* [Avoid `DecidableEq` in `Array.mem`](https://github.com/leanprover/lean4/pull/2774)
* [Ensure `USize.size` unifies with `?m + 1`](https://github.com/leanprover/lean4/issues/1926)
* [Improve compatibility with emacs eglot client](https://github.com/leanprover/lean4/pull/2721)
**Lake:**
* [Sensible defaults for `lake new MyProject math`](https://github.com/leanprover/lean4/pull/2770)
* Changed `postUpdate?` configuration option to a `post_update` declaration. See the `post_update` syntax docstring for more information on the new syntax.
* [A manifest is automatically created on workspace load if one does not exists.](https://github.com/leanprover/lean4/pull/2680).
* The `:=` syntax for configuration declarations (i.e., `package`, `lean_lib`, and `lean_exe`) has been deprecated. For example, `package foo := {...}` is deprecated.
* [support for overriding package URLs via `LAKE_PKG_URL_MAP`](https://github.com/leanprover/lean4/pull/2709)
* Moved the default build directory (e.g., `build`), default packages directory (e.g., `lake-packages`), and the compiled configuration (e.g., `lakefile.olean`) into a new dedicated directory for Lake outputs, `.lake`. The cloud release build archives are also stored here, fixing [#2713](https://github.com/leanprover/lean4/issues/2713).
* Update manifest format to version 7 (see [lean4#2801](https://github.com/leanprover/lean4/pull/2801) for details on the changes).
* Deprecate the `manifestFile` field of a package configuration.
* There is now a more rigorous check on `lakefile.olean` compatibility (see [#2842](https://github.com/leanprover/lean4/pull/2842) for more details).

45
releases/v4.4.0.md Normal file
View File

@@ -0,0 +1,45 @@
v4.4.0
---------
* Lake and the language server now support per-package server options using the `moreServerOptions` config field, as well as options that apply to both the language server and `lean` using the `leanOptions` config field. Setting either of these fields instead of `moreServerArgs` ensures that viewing files from a dependency uses the options for that dependency. Additionally, `moreServerArgs` is being deprecated in favor of the `moreGlobalServerArgs` field. See PR [#2858](https://github.com/leanprover/lean4/pull/2858).
A Lakefile with the following deprecated package declaration:
```lean
def moreServerArgs := #[
"-Dpp.unicode.fun=true"
]
def moreLeanArgs := moreServerArgs
package SomePackage where
moreServerArgs := moreServerArgs
moreLeanArgs := moreLeanArgs
```
... can be updated to the following package declaration to use per-package options:
```lean
package SomePackage where
leanOptions := #[⟨`pp.unicode.fun, true⟩]
```
* [Rename request handler](https://github.com/leanprover/lean4/pull/2462).
* [Import auto-completion](https://github.com/leanprover/lean4/pull/2904).
* [`pp.beta`` to apply beta reduction when pretty printing](https://github.com/leanprover/lean4/pull/2864).
* [Embed and check githash in .olean](https://github.com/leanprover/lean4/pull/2766).
* [Guess lexicographic order for well-founded recursion](https://github.com/leanprover/lean4/pull/2874).
* [Allow trailing comma in tuples, lists, and tactics](https://github.com/leanprover/lean4/pull/2643).
Bug fixes for [#2628](https://github.com/leanprover/lean4/issues/2628), [#2883](https://github.com/leanprover/lean4/issues/2883),
[#2810](https://github.com/leanprover/lean4/issues/2810), [#2925](https://github.com/leanprover/lean4/issues/2925), and [#2914](https://github.com/leanprover/lean4/issues/2914).
**Lake:**
* `lake init .` and a bare `lake init` and will now use the current directory as the package name. [#2890](https://github.com/leanprover/lean4/pull/2890)
* `lake new` and `lake init` will now produce errors on invalid package names such as `..`, `foo/bar`, `Init`, `Lean`, `Lake`, and `Main`. See issue [#2637](https://github.com/leanprover/lean4/issues/2637) and PR [#2890](https://github.com/leanprover/lean4/pull/2890).
* `lean_lib` no longer converts its name to upper camel case (e.g., `lean_lib bar` will include modules named `bar.*` rather than `Bar.*`). See issue [#2567](https://github.com/leanprover/lean4/issues/2567) and PR [#2889](https://github.com/leanprover/lean4/pull/2889).
* Lean and Lake now properly support non-identifier library names (e.g., `lake new 123-hello` and `import «123Hello»` now work correctly). See issue [#2865](https://github.com/leanprover/lean4/issues/2865) and PR [#2889](https://github.com/leanprover/lean4/pull/2888).
* Lake now filters the environment extensions loaded from a compiled configuration (`lakefile.olean`) to include only those relevant to Lake's workspace loading process. This resolves segmentation faults caused by environment extension type mismatches (e.g., when defining custom elaborators via `elab` in configurations). See issue [#2632](https://github.com/leanprover/lean4/issues/2632) and PR [#2896](https://github.com/leanprover/lean4/pull/2896).
* Cloud releases will now properly be re-unpacked if the build directory is removed. See PR [#2928](https://github.com/leanprover/lean4/pull/2928).
* Lake's `math` template has been simplified. See PR [#2930](https://github.com/leanprover/lean4/pull/2930).
* `lake exe <target>` now parses `target` like a build target (as the help text states it should) rather than as a basic name. For example, `lake exe @mathlib/runLinter` should now work. See PR [#2932](https://github.com/leanprover/lean4/pull/2932).
* `lake new foo.bar [std]` now generates executables named `foo-bar` and `lake new foo.bar exe` properly creates `foo/bar.lean`. See PR [#2932](https://github.com/leanprover/lean4/pull/2932).
* Later packages and libraries in the dependency tree are now preferred over earlier ones. That is, the later ones "shadow" the earlier ones. Such an ordering is more consistent with how declarations generally work in programming languages. This will break any package that relied on the previous ordering. See issue [#2548](https://github.com/leanprover/lean4/issues/2548) and PR [#2937](https://github.com/leanprover/lean4/pull/2937).
* Executable roots are no longer mistakenly treated as importable. They will no longer be picked up by `findModule?`. See PR [#2937](https://github.com/leanprover/lean4/pull/2937).

77
releases/v4.5.0.md Normal file
View File

@@ -0,0 +1,77 @@
v4.5.0
---------
* Modify the lexical syntax of string literals to have string gaps, which are escape sequences of the form `"\" newline whitespace*`.
These have the interpretation of an empty string and allow a string to flow across multiple lines without introducing additional whitespace.
The following is equivalent to `"this is a string"`.
```lean
"this is \
a string"
```
[PR #2821](https://github.com/leanprover/lean4/pull/2821) and [RFC #2838](https://github.com/leanprover/lean4/issues/2838).
* Add raw string literal syntax. For example, `r"\n"` is equivalent to `"\\n"`, with no escape processing.
To include double quote characters in a raw string one can add sufficiently many `#` characters before and after
the bounding `"`s, as in `r#"the "the" is in quotes"#` for `"the \"the\" is in quotes"`.
[PR #2929](https://github.com/leanprover/lean4/pull/2929) and [issue #1422](https://github.com/leanprover/lean4/issues/1422).
* The low-level `termination_by'` clause is no longer supported.
Migration guide: Use `termination_by` instead, e.g.:
```diff
-termination_by' measure (fun ⟨i, _⟩ => as.size - i)
+termination_by i _ => as.size - i
```
If the well-founded relation you want to use is not the one that the
`WellFoundedRelation` type class would infer for your termination argument,
you can use `WellFounded.wrap` from the std library to explicitly give one:
```diff
-termination_by' ⟨r, hwf⟩
+termination_by x => hwf.wrap x
```
* Support snippet edits in LSP `TextEdit`s. See `Lean.Lsp.SnippetString` for more details.
* Deprecations and changes in the widget API.
- `Widget.UserWidgetDefinition` is deprecated in favour of `Widget.Module`. The annotation `@[widget]` is deprecated in favour of `@[widget_module]`. To migrate a definition of type `UserWidgetDefinition`, remove the `name` field and replace the type with `Widget.Module`. Removing the `name` results in a title bar no longer being drawn above your panel widget. To add it back, draw it as part of the component using `<details open=true><summary class='mv2 pointer'>{name}</summary>{rest_of_widget}</details>`. See an example migration [here](https://github.com/leanprover/std4/pull/475/files#diff-857376079661a0c28a53b7ff84701afabbdf529836a6944d106c5294f0e68109R43-R83).
- The new command `show_panel_widgets` allows displaying always-on and locally-on panel widgets.
- `RpcEncodable` widget props can now be stored in the infotree.
- See [RFC 2963](https://github.com/leanprover/lean4/issues/2963) for more details and motivation.
* If no usable lexicographic order can be found automatically for a termination proof, explain why.
See [feat: GuessLex: if no measure is found, explain why](https://github.com/leanprover/lean4/pull/2960).
* Option to print [inferred termination argument](https://github.com/leanprover/lean4/pull/3012).
With `set_option showInferredTerminationBy true` you will get messages like
```
Inferred termination argument:
termination_by
ackermann n m => (sizeOf n, sizeOf m)
```
for automatically generated `termination_by` clauses.
* More detailed error messages for [invalid mutual blocks](https://github.com/leanprover/lean4/pull/2949).
* [Multiple](https://github.com/leanprover/lean4/pull/2923) [improvements](https://github.com/leanprover/lean4/pull/2969) to the output of `simp?` and `simp_all?`.
* Tactics with `withLocation *` [no longer fail](https://github.com/leanprover/lean4/pull/2917) if they close the main goal.
* Implementation of a `test_extern` command for writing tests for `@[extern]` and `@[implemented_by]` functions.
Usage is
```
import Lean.Util.TestExtern
test_extern Nat.add 17 37
```
The head symbol must be the constant with the `@[extern]` or `@[implemented_by]` attribute. The return type must have a `DecidableEq` instance.
Bug fixes for
[#2853](https://github.com/leanprover/lean4/issues/2853), [#2953](https://github.com/leanprover/lean4/issues/2953), [#2966](https://github.com/leanprover/lean4/issues/2966),
[#2971](https://github.com/leanprover/lean4/issues/2971), [#2990](https://github.com/leanprover/lean4/issues/2990), [#3094](https://github.com/leanprover/lean4/issues/3094).
Bug fix for [eager evaluation of default value](https://github.com/leanprover/lean4/pull/3043) in `Option.getD`.
Avoid [panic in `leanPosToLspPos`](https://github.com/leanprover/lean4/pull/3071) when file source is unavailable.
Improve [short-circuiting behavior](https://github.com/leanprover/lean4/pull/2972) for `List.all` and `List.any`.
Several Lake bug fixes: [#3036](https://github.com/leanprover/lean4/issues/3036), [#3064](https://github.com/leanprover/lean4/issues/3064), [#3069](https://github.com/leanprover/lean4/issues/3069).

230
releases/v4.6.0.md Normal file
View File

@@ -0,0 +1,230 @@
v4.6.0
---------
* Add custom simplification procedures (aka `simproc`s) to `simp`. Simprocs can be triggered by the simplifier on a specified term-pattern. Here is an small example:
```lean
import Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat
def foo (x : Nat) : Nat :=
x + 10
/--
The `simproc` `reduceFoo` is invoked on terms that match the pattern `foo _`.
-/
simproc reduceFoo (foo _) :=
/- A term of type `Expr → SimpM Step -/
fun e => do
/-
The `Step` type has three constructors: `.done`, `.visit`, `.continue`.
* The constructor `.done` instructs `simp` that the result does
not need to be simplified further.
* The constructor `.visit` instructs `simp` to visit the resulting expression.
* The constructor `.continue` instructs `simp` to try other simplification procedures.
All three constructors take a `Result`. The `.continue` constructor may also take `none`.
`Result` has two fields `expr` (the new expression), and `proof?` (an optional proof).
If the new expression is definitionally equal to the input one, then `proof?` can be omitted or set to `none`.
-/
/- `simp` uses matching modulo reducibility. So, we ensure the term is a `foo`-application. -/
unless e.isAppOfArity ``foo 1 do
return .continue
/- `Nat.fromExpr?` tries to convert an expression into a `Nat` value -/
let some n ← Nat.fromExpr? e.appArg!
| return .continue
return .done { expr := Lean.mkNatLit (n+10) }
```
We disable simprocs support by using the command `set_option simprocs false`. This command is particularly useful when porting files to v4.6.0.
Simprocs can be scoped, manually added to `simp` commands, and suppressed using `-`. They are also supported by `simp?`. `simp only` does not execute any `simproc`. Here are some examples for the `simproc` defined above.
```lean
example : x + foo 2 = 12 + x := by
set_option simprocs false in
/- This `simp` command does not make progress since `simproc`s are disabled. -/
fail_if_success simp
simp_arith
example : x + foo 2 = 12 + x := by
/- `simp only` must not use the default simproc set. -/
fail_if_success simp only
simp_arith
example : x + foo 2 = 12 + x := by
/-
`simp only` does not use the default simproc set,
but we can provide simprocs as arguments. -/
simp only [reduceFoo]
simp_arith
example : x + foo 2 = 12 + x := by
/- We can use `-` to disable `simproc`s. -/
fail_if_success simp [-reduceFoo]
simp_arith
```
The command `register_simp_attr <id>` now creates a `simp` **and** a `simproc` set with the name `<id>`. The following command instructs Lean to insert the `reduceFoo` simplification procedure into the set `my_simp`. If no set is specified, Lean uses the default `simp` set.
```lean
simproc [my_simp] reduceFoo (foo _) := ...
```
* The syntax of the `termination_by` and `decreasing_by` termination hints is overhauled:
* They are now placed directly after the function they apply to, instead of
after the whole `mutual` block.
* Therefore, the function name no longer has to be mentioned in the hint.
* If the function has a `where` clause, the `termination_by` and
`decreasing_by` for that function come before the `where`. The
functions in the `where` clause can have their own termination hints, each
following the corresponding definition.
* The `termination_by` clause can only bind “extra parameters”, that are not
already bound by the function header, but are bound in a lambda (`:= fun x
y z =>`) or in patterns (`| x, n + 1 => …`). These extra parameters used to
be understood as a suffix of the function parameters; now it is a prefix.
Migration guide: In simple cases just remove the function name, and any
variables already bound at the header.
```diff
def foo : Nat → Nat → Nat := …
-termination_by foo a b => a - b
+termination_by a b => a - b
```
or
```diff
def foo : Nat → Nat → Nat := …
-termination_by _ a b => a - b
+termination_by a b => a - b
```
If the parameters are bound in the function header (before the `:`), remove them as well:
```diff
def foo (a b : Nat) : Nat := …
-termination_by foo a b => a - b
+termination_by a - b
```
Else, if there are multiple extra parameters, make sure to refer to the right
ones; the bound variables are interpreted from left to right, no longer from
right to left:
```diff
def foo : Nat → Nat → Nat → Nat
| a, b, c => …
-termination_by foo b c => b
+termination_by a b => b
```
In the case of a `mutual` block, place the termination arguments (without the
function name) next to the function definition:
```diff
-mutual
-def foo : Nat → Nat → Nat := …
-def bar : Nat → Nat := …
-end
-termination_by
- foo a b => a - b
- bar a => a
+mutual
+def foo : Nat → Nat → Nat := …
+termination_by a b => a - b
+def bar : Nat → Nat := …
+termination_by a => a
+end
```
Similarly, if you have (mutual) recursion through `where` or `let rec`, the
termination hints are now placed directly after the function they apply to:
```diff
-def foo (a b : Nat) : Nat := …
- where bar (x : Nat) : Nat := …
-termination_by
- foo a b => a - b
- bar x => x
+def foo (a b : Nat) : Nat := …
+termination_by a - b
+ where
+ bar (x : Nat) : Nat := …
+ termination_by x
-def foo (a b : Nat) : Nat :=
- let rec bar (x : Nat) : Nat := …
- …
-termination_by
- foo a b => a - b
- bar x => x
+def foo (a b : Nat) : Nat :=
+ let rec bar (x : Nat) : Nat := …
+ termination_by x
+ …
+termination_by a - b
```
In cases where a single `decreasing_by` clause applied to multiple mutually
recursive functions before, the tactic now has to be duplicated.
* The semantics of `decreasing_by` changed; the tactic is applied to all
termination proof goals together, not individually.
This helps when writing termination proofs interactively, as one can focus
each subgoal individually, for example using `·`. Previously, the given
tactic script had to work for _all_ goals, and one had to resort to tactic
combinators like `first`:
```diff
def foo (n : Nat) := … foo e1 … foo e2 …
-decreasing_by
-simp_wf
-first | apply something_about_e1; …
- | apply something_about_e2; …
+decreasing_by
+all_goals simp_wf
+· apply something_about_e1; …
+· apply something_about_e2; …
```
To obtain the old behaviour of applying a tactic to each goal individually,
use `all_goals`:
```diff
def foo (n : Nat) := …
-decreasing_by some_tactic
+decreasing_by all_goals some_tactic
```
In the case of mutual recursion each `decreasing_by` now applies to just its
function. If some functions in a recursive group do not have their own
`decreasing_by`, the default `decreasing_tactic` is used. If the same tactic
ought to be applied to multiple functions, the `decreasing_by` clause has to
be repeated at each of these functions.
* Modify `InfoTree.context` to facilitate augmenting it with partial contexts while elaborating a command. This breaks backwards compatibility with all downstream projects that traverse the `InfoTree` manually instead of going through the functions in `InfoUtils.lean`, as well as those manually creating and saving `InfoTree`s. See [PR #3159](https://github.com/leanprover/lean4/pull/3159) for how to migrate your code.
* Add language server support for [call hierarchy requests](https://www.youtube.com/watch?v=r5LA7ivUb2c) ([PR #3082](https://github.com/leanprover/lean4/pull/3082)). The change to the .ilean format in this PR means that projects must be fully rebuilt once in order to generate .ilean files with the new format before features like "find references" work correctly again.
* Structure instances with multiple sources (for example `{a, b, c with x := 0}`) now have their fields filled from these sources
in strict left-to-right order. Furthermore, the structure instance elaborator now aggressively use sources to fill in subobject
fields, which prevents unnecessary eta expansion of the sources,
and hence greatly reduces the reliance on costly structure eta reduction. This has a large impact on mathlib,
reducing total CPU instructions by 3% and enabling impactful refactors like leanprover-community/mathlib4#8386
which reduces the build time by almost 20%.
See [PR #2478](https://github.com/leanprover/lean4/pull/2478) and [RFC #2451](https://github.com/leanprover/lean4/issues/2451).
* Add pretty printer settings to omit deeply nested terms (`pp.deepTerms false` and `pp.deepTerms.threshold`) ([PR #3201](https://github.com/leanprover/lean4/pull/3201))
* Add pretty printer options `pp.numeralTypes` and `pp.natLit`.
When `pp.numeralTypes` is true, then natural number literals, integer literals, and rational number literals
are pretty printed with type ascriptions, such as `(2 : Rat)`, `(-2 : Rat)`, and `(-2 / 3 : Rat)`.
When `pp.natLit` is true, then raw natural number literals are pretty printed as `nat_lit 2`.
[PR #2933](https://github.com/leanprover/lean4/pull/2933) and [RFC #3021](https://github.com/leanprover/lean4/issues/3021).
Lake updates:
* improved platform information & control [#3226](https://github.com/leanprover/lean4/pull/3226)
* `lake update` from unsupported manifest versions [#3149](https://github.com/leanprover/lean4/pull/3149)
Other improvements:
* make `intro` be aware of `let_fun` [#3115](https://github.com/leanprover/lean4/pull/3115)
* produce simpler proof terms in `rw` [#3121](https://github.com/leanprover/lean4/pull/3121)
* fuse nested `mkCongrArg` calls in proofs generated by `simp` [#3203](https://github.com/leanprover/lean4/pull/3203)
* `induction using` followed by a general term [#3188](https://github.com/leanprover/lean4/pull/3188)
* allow generalization in `let` [#3060](https://github.com/leanprover/lean4/pull/3060), fixing [#3065](https://github.com/leanprover/lean4/issues/3065)
* reducing out-of-bounds `swap!` should return `a`, not `default`` [#3197](https://github.com/leanprover/lean4/pull/3197), fixing [#3196](https://github.com/leanprover/lean4/issues/3196)
* derive `BEq` on structure with `Prop`-fields [#3191](https://github.com/leanprover/lean4/pull/3191), fixing [#3140](https://github.com/leanprover/lean4/issues/3140)
* refine through more `casesOnApp`/`matcherApp` [#3176](https://github.com/leanprover/lean4/pull/3176), fixing [#3175](https://github.com/leanprover/lean4/pull/3175)
* do not strip dotted components from lean module names [#2994](https://github.com/leanprover/lean4/pull/2994), fixing [#2999](https://github.com/leanprover/lean4/issues/2999)
* fix `deriving` only deriving the first declaration for some handlers [#3058](https://github.com/leanprover/lean4/pull/3058), fixing [#3057](https://github.com/leanprover/lean4/issues/3057)
* do not instantiate metavariables in kabstract/rw for disallowed occurrences [#2539](https://github.com/leanprover/lean4/pull/2539), fixing [#2538](https://github.com/leanprover/lean4/issues/2538)
* hover info for `cases h : ...` [#3084](https://github.com/leanprover/lean4/pull/3084)

4
releases/v4.6.1.md Normal file
View File

@@ -0,0 +1,4 @@
v4.6.1
---------
* Backport of [#3552](https://github.com/leanprover/lean4/pull/3552) fixing a performance regression
in server startup.

186
releases/v4.7.0.md Normal file
View File

@@ -0,0 +1,186 @@
v4.7.0
---------
* `simp` and `rw` now use instance arguments found by unification,
rather than always resynthesizing. For backwards compatibility, the original behaviour is
available via `set_option tactic.skipAssignedInstances false`.
[#3507](https://github.com/leanprover/lean4/pull/3507) and
[#3509](https://github.com/leanprover/lean4/pull/3509).
* When the `pp.proofs` is false, now omitted proofs use `⋯` rather than `_`,
which gives a more helpful error message when copied from the Infoview.
The `pp.proofs.threshold` option lets small proofs always be pretty printed.
[#3241](https://github.com/leanprover/lean4/pull/3241).
* `pp.proofs.withType` is now set to false by default to reduce noise in the info view.
* The pretty printer for applications now handles the case of over-application itself when applying app unexpanders.
In particular, the ``| `($_ $a $b $xs*) => `(($a + $b) $xs*)`` case of an `app_unexpander` is no longer necessary.
[#3495](https://github.com/leanprover/lean4/pull/3495).
* New `simp` (and `dsimp`) configuration option: `zetaDelta`. It is `false` by default.
The `zeta` option is still `true` by default, but their meaning has changed.
- When `zeta := true`, `simp` and `dsimp` reduce terms of the form
`let x := val; e[x]` into `e[val]`.
- When `zetaDelta := true`, `simp` and `dsimp` will expand let-variables in
the context. For example, suppose the context contains `x := val`. Then,
any occurrence of `x` is replaced with `val`.
See [issue #2682](https://github.com/leanprover/lean4/pull/2682) for additional details. Here are some examples:
```
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
simp
/-
New goal:
h : z = 9; x := 5 |- x + 4 = z
-/
rw [h]
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
-- Using both `zeta` and `zetaDelta`.
simp (config := { zetaDelta := true })
/-
New goal:
h : z = 9; x := 5 |- 9 = z
-/
rw [h]
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
simp [x] -- asks `simp` to unfold `x`
/-
New goal:
h : z = 9; x := 5 |- 9 = z
-/
rw [h]
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
simp (config := { zetaDelta := true, zeta := false })
/-
New goal:
h : z = 9; x := 5 |- let y := 4; 5 + y = z
-/
rw [h]
```
* When adding new local theorems to `simp`, the system assumes that the function application arguments
have been annotated with `no_index`. This modification, which addresses [issue #2670](https://github.com/leanprover/lean4/issues/2670),
restores the Lean 3 behavior that users expect. With this modification, the following examples are now operational:
```
example {α β : Type} {f : α × β → β → β} (h : ∀ p : α × β, f p p.2 = p.2)
(a : α) (b : β) : f (a, b) b = b := by
simp [h]
example {α β : Type} {f : α × β → β → β}
(a : α) (b : β) (h : f (a,b) (a,b).2 = (a,b).2) : f (a, b) b = b := by
simp [h]
```
In both cases, `h` is applicable because `simp` does not index f-arguments anymore when adding `h` to the `simp`-set.
It's important to note, however, that global theorems continue to be indexed in the usual manner.
* Improved the error messages produced by the `decide` tactic. [#3422](https://github.com/leanprover/lean4/pull/3422)
* Improved auto-completion performance. [#3460](https://github.com/leanprover/lean4/pull/3460)
* Improved initial language server startup performance. [#3552](https://github.com/leanprover/lean4/pull/3552)
* Changed call hierarchy to sort entries and strip private header from names displayed in the call hierarchy. [#3482](https://github.com/leanprover/lean4/pull/3482)
* There is now a low-level error recovery combinator in the parsing framework, primarily intended for DSLs. [#3413](https://github.com/leanprover/lean4/pull/3413)
* You can now write `termination_by?` after a declaration to see the automatically inferred
termination argument, and turn it into a `termination_by …` clause using the “Try this” widget or a code action. [#3514](https://github.com/leanprover/lean4/pull/3514)
* A large fraction of `Std` has been moved into the Lean repository.
This was motivated by:
1. Making universally useful tactics such as `ext`, `by_cases`, `change at`,
`norm_cast`, `rcases`, `simpa`, `simp?`, `omega`, and `exact?`
available to all users of Lean, without imports.
2. Minimizing the syntactic changes between plain Lean and Lean with `import Std`.
3. Simplifying the development process for the basic data types
`Nat`, `Int`, `Fin` (and variants such as `UInt64`), `List`, `Array`,
and `BitVec` as we begin making the APIs and simp normal forms for these types
more complete and consistent.
4. Laying the groundwork for the Std roadmap, as a library focused on
essential datatypes not provided by the core language (e.g. `RBMap`)
and utilities such as basic IO.
While we have achieved most of our initial aims in `v4.7.0-rc1`,
some upstreaming will continue over the coming months.
* The `/` and `%` notations in `Int` now use `Int.ediv` and `Int.emod`
(i.e. the rounding conventions have changed).
Previously `Std` overrode these notations, so this is no change for users of `Std`.
There is now kernel support for these functions.
[#3376](https://github.com/leanprover/lean4/pull/3376).
* `omega`, our integer linear arithmetic tactic, is now available in the core language.
* It is supplemented by a preprocessing tactic `bv_omega` which can solve goals about `BitVec`
which naturally translate into linear arithmetic problems.
[#3435](https://github.com/leanprover/lean4/pull/3435).
* `omega` now has support for `Fin` [#3427](https://github.com/leanprover/lean4/pull/3427),
the `<<<` operator [#3433](https://github.com/leanprover/lean4/pull/3433).
* During the port `omega` was modified to no longer identify atoms up to definitional equality
(so in particular it can no longer prove `id x ≤ x`). [#3525](https://github.com/leanprover/lean4/pull/3525).
This may cause some regressions.
We plan to provide a general purpose preprocessing tactic later, or an `omega!` mode.
* `omega` is now invoked in Lean's automation for termination proofs
[#3503](https://github.com/leanprover/lean4/pull/3503) as well as in
array indexing proofs [#3515](https://github.com/leanprover/lean4/pull/3515).
This automation will be substantially revised in the medium term,
and while `omega` does help automate some proofs, we plan to make this much more robust.
* The library search tactics `exact?` and `apply?` that were originally in
Mathlib are now available in Lean itself. These use the implementation using
lazy discrimination trees from `Std`, and thus do not require a disk cache but
have a slightly longer startup time. The order used for selection lemmas has
changed as well to favor goals purely based on how many terms in the head
pattern match the current goal.
* The `solve_by_elim` tactic has been ported from `Std` to Lean so that library
search can use it.
* New `#check_tactic` and `#check_simp` commands have been added. These are
useful for checking tactics (particularly `simp`) behave as expected in test
suites.
* Previously, app unexpanders would only be applied to entire applications. However, some notations produce
functions, and these functions can be given additional arguments. The solution so far has been to write app unexpanders so that they can take an arbitrary number of additional arguments. However this leads to misleading hover information in the Infoview. For example, while `HAdd.hAdd f g 1` pretty prints as `(f + g) 1`, hovering over `f + g` shows `f`. There is no way to fix the situation from within an app unexpander; the expression position for `HAdd.hAdd f g` is absent, and app unexpanders cannot register TermInfo.
This commit changes the app delaborator to try running app unexpanders on every prefix of an application, from longest to shortest prefix. For efficiency, it is careful to only try this when app delaborators do in fact exist for the head constant, and it also ensures arguments are only delaborated once. Then, in `(f + g) 1`, the `f + g` gets TermInfo registered for that subexpression, making it properly hoverable.
[#3375](https://github.com/leanprover/lean4/pull/3375)
Breaking changes:
* `Lean.withTraceNode` and variants got a stronger `MonadAlwaysExcept` assumption to
fix trace trees not being built on elaboration runtime exceptions. Instances for most elaboration
monads built on `EIO Exception` should be synthesized automatically.
* The `match ... with.` and `fun.` notations previously in Std have been replaced by
`nomatch ...` and `nofun`. [#3279](https://github.com/leanprover/lean4/pull/3279) and [#3286](https://github.com/leanprover/lean4/pull/3286)
Other improvements:
* several bug fixes for `simp`:
* we should not crash when `simp` loops [#3269](https://github.com/leanprover/lean4/pull/3269)
* `simp` gets stuck on `autoParam` [#3315](https://github.com/leanprover/lean4/pull/3315)
* `simp` fails when custom discharger makes no progress [#3317](https://github.com/leanprover/lean4/pull/3317)
* `simp` fails to discharge `autoParam` premises even when it can reduce them to `True` [#3314](https://github.com/leanprover/lean4/pull/3314)
* `simp?` suggests generated equations lemma names, fixes [#3547](https://github.com/leanprover/lean4/pull/3547) [#3573](https://github.com/leanprover/lean4/pull/3573)
* fixes for `match` expressions:
* fix regression with builtin literals [#3521](https://github.com/leanprover/lean4/pull/3521)
* accept `match` when patterns cover all cases of a `BitVec` finite type [#3538](https://github.com/leanprover/lean4/pull/3538)
* fix matching `Int` literals [#3504](https://github.com/leanprover/lean4/pull/3504)
* patterns containing int values and constructors [#3496](https://github.com/leanprover/lean4/pull/3496)
* improve `termination_by` error messages [#3255](https://github.com/leanprover/lean4/pull/3255)
* fix `rename_i` in macros, fixes [#3553](https://github.com/leanprover/lean4/pull/3553) [#3581](https://github.com/leanprover/lean4/pull/3581)
* fix excessive resource usage in `generalize`, fixes [#3524](https://github.com/leanprover/lean4/pull/3524) [#3575](https://github.com/leanprover/lean4/pull/3575)
* an equation lemma with autoParam arguments fails to rewrite, fixing [#2243](https://github.com/leanprover/lean4/pull/2243) [#3316](https://github.com/leanprover/lean4/pull/3316)
* `add_decl_doc` should check that declarations are local [#3311](https://github.com/leanprover/lean4/pull/3311)
* instantiate the types of inductives with the right parameters, closing [#3242](https://github.com/leanprover/lean4/pull/3242) [#3246](https://github.com/leanprover/lean4/pull/3246)
* New simprocs for many basic types. [#3407](https://github.com/leanprover/lean4/pull/3407)
Lake fixes:
* Warn on fetch cloud release failure [#3401](https://github.com/leanprover/lean4/pull/3401)
* Cloud release trace & `lake build :release` errors [#3248](https://github.com/leanprover/lean4/pull/3248)

494
releases/v4.8.0.md Normal file
View File

@@ -0,0 +1,494 @@
v4.8.0
---------
### Language features, tactics, and metaprograms
* **Functional induction principles.**
[#3432](https://github.com/leanprover/lean4/pull/3432), [#3620](https://github.com/leanprover/lean4/pull/3620),
[#3754](https://github.com/leanprover/lean4/pull/3754), [#3762](https://github.com/leanprover/lean4/pull/3762),
[#3738](https://github.com/leanprover/lean4/pull/3738), [#3776](https://github.com/leanprover/lean4/pull/3776),
[#3898](https://github.com/leanprover/lean4/pull/3898).
Derived from the definition of a (possibly mutually) recursive function,
a **functional induction principle** is created that is tailored to proofs about that function.
For example from:
```
def ackermann : Nat → Nat → Nat
| 0, m => m + 1
| n+1, 0 => ackermann n 1
| n+1, m+1 => ackermann n (ackermann (n + 1) m)
```
we get
```
ackermann.induct (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (n : Nat), motive n 1 → motive (Nat.succ n) 0)
(case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive (Nat.succ n) (Nat.succ m))
(x x : Nat) : motive x x
```
It can be used in the `induction` tactic using the `using` syntax:
```
induction n, m using ackermann.induct
```
* The termination checker now recognizes more recursion patterns without an
explicit `termination_by`. In particular the idiom of counting up to an upper
bound, as in
```
def Array.sum (arr : Array Nat) (i acc : Nat) : Nat :=
if _ : i < arr.size then
Array.sum arr (i+1) (acc + arr[i])
else
acc
```
is recognized without having to say `termination_by arr.size - i`.
* [#3630](https://github.com/leanprover/lean4/pull/3630) makes `termination_by?` not use `sizeOf` when not needed
* [#3652](https://github.com/leanprover/lean4/pull/3652) improves the `termination_by` syntax.
* [#3658](https://github.com/leanprover/lean4/pull/3658) changes how termination arguments are elaborated.
* [#3665](https://github.com/leanprover/lean4/pull/3665) refactors GuessLex to allow inferring more complex termination arguments
* [#3666](https://github.com/leanprover/lean4/pull/3666) infers termination arguments such as `xs.size - i`
* [#3629](https://github.com/leanprover/lean4/pull/3629),
[#3655](https://github.com/leanprover/lean4/pull/3655),
[#3747](https://github.com/leanprover/lean4/pull/3747):
Adds `@[induction_eliminator]` and `@[cases_eliminator]` attributes to be able to define custom eliminators
for the `induction` and `cases` tactics, replacing the `@[eliminator]` attribute.
Gives custom eliminators for `Nat` so that `induction` and `cases` put goal states into terms of `0` and `n + 1`
rather than `Nat.zero` and `Nat.succ n`.
Added option `tactic.customEliminators` to control whether to use custom eliminators.
Added a hack for `rcases`/`rintro`/`obtain` to use the custom eliminator for `Nat`.
* **Shorter instances names.** There is a new algorithm for generating names for anonymous instances.
Across Std and Mathlib, the median ratio between lengths of new names and of old names is about 72%.
With the old algorithm, the longest name was 1660 characters, and now the longest name is 202 characters.
The new algorithm's 95th percentile name length is 67 characters, versus 278 for the old algorithm.
While the new algorithm produces names that are 1.2% less unique,
it avoids cross-project collisions by adding a module-based suffix
when it does not refer to declarations from the same "project" (modules that share the same root).
[#3089](https://github.com/leanprover/lean4/pull/3089)
and [#3934](https://github.com/leanprover/lean4/pull/3934).
* [8d2adf](https://github.com/leanprover/lean4/commit/8d2adf521d2b7636347a5b01bfe473bf0fcfaf31)
Importing two different files containing proofs of the same theorem is no longer considered an error.
This feature is particularly useful for theorems that are automatically generated on demand (e.g., equational theorems).
* [84b091](https://github.com/leanprover/lean4/commit/84b0919a116e9be12f933e764474f45d964ce85c)
Lean now generates an error if the type of a theorem is **not** a proposition.
* **Definition transparency.** [47a343](https://github.com/leanprover/lean4/commit/47a34316fc03ce936fddd2d3dce44784c5bcdfa9). `@[reducible]`, `@[semireducible]`, and `@[irreducible]` are now scoped and able to be set for imported declarations.
* `simp`/`dsimp`
* [#3607](https://github.com/leanprover/lean4/pull/3607) enables kernel projection reduction in `dsimp`
* [b24fbf](https://github.com/leanprover/lean4/commit/b24fbf44f3aaa112f5d799ef2a341772d1eb222d)
and [acdb00](https://github.com/leanprover/lean4/commit/acdb0054d5a0efa724cff596ac26852fad5724c4):
`dsimproc` command
to define defeq-preserving simplification procedures.
* [#3624](https://github.com/leanprover/lean4/pull/3624) makes `dsimp` normalize raw nat literals as `OfNat.ofNat` applications.
* [#3628](https://github.com/leanprover/lean4/pull/3628) makes `simp` correctly handle `OfScientific.ofScientific` literals.
* [#3654](https://github.com/leanprover/lean4/pull/3654) makes `dsimp?` report used simprocs.
* [dee074](https://github.com/leanprover/lean4/commit/dee074dcde03a37b7895a4901df2e4fa490c73c7) fixes equation theorem
handling in `simp` for non-recursive definitions.
* [#3819](https://github.com/leanprover/lean4/pull/3819) improved performance when simp encounters a loop.
* [#3821](https://github.com/leanprover/lean4/pull/3821) fixes discharger/cache interaction.
* [#3824](https://github.com/leanprover/lean4/pull/3824) keeps `simp` from breaking `Char` literals.
* [#3838](https://github.com/leanprover/lean4/pull/3838) allows `Nat` instances matching to be more lenient.
* [#3870](https://github.com/leanprover/lean4/pull/3870) documentation for `simp` configuration options.
* [#3972](https://github.com/leanprover/lean4/pull/3972) fixes simp caching.
* [#4044](https://github.com/leanprover/lean4/pull/4044) improves cache behavior for "well-behaved" dischargers.
* `omega`
* [#3639](https://github.com/leanprover/lean4/pull/3639), [#3766](https://github.com/leanprover/lean4/pull/3766),
[#3853](https://github.com/leanprover/lean4/pull/3853), [#3875](https://github.com/leanprover/lean4/pull/3875):
introduces a term canonicalizer.
* [#3736](https://github.com/leanprover/lean4/pull/3736) improves handling of positivity for the modulo operator for `Int`.
* [#3828](https://github.com/leanprover/lean4/pull/3828) makes it work as a `simp` discharger.
* [#3847](https://github.com/leanprover/lean4/pull/3847) adds helpful error messages.
* `rfl`
* [#3671](https://github.com/leanprover/lean4/pull/3671), [#3708](https://github.com/leanprover/lean4/pull/3708): upstreams the `@[refl]` attribute and the `rfl` tactic.
* [#3751](https://github.com/leanprover/lean4/pull/3751) makes `apply_rfl` not operate on `Eq` itself.
* [#4067](https://github.com/leanprover/lean4/pull/4067) improves error message when there are no goals.
* [#3719](https://github.com/leanprover/lean4/pull/3719) upstreams the `rw?` tactic, with fixes and improvements in
[#3783](https://github.com/leanprover/lean4/pull/3783), [#3794](https://github.com/leanprover/lean4/pull/3794),
[#3911](https://github.com/leanprover/lean4/pull/3911).
* `conv`
* [#3659](https://github.com/leanprover/lean4/pull/3659) adds a `conv` version of the `calc` tactic.
* [#3763](https://github.com/leanprover/lean4/pull/3763) makes `conv` clean up using `try with_reducible rfl` instead of `try rfl`.
* `#guard_msgs`
* [#3617](https://github.com/leanprover/lean4/pull/3617) introduces whitespace protection using the `` character.
* [#3883](https://github.com/leanprover/lean4/pull/3883):
The `#guard_msgs` command now has options to change whitespace normalization and sensitivity to message ordering.
For example, `#guard_msgs (whitespace := lax) in cmd` collapses whitespace before checking messages,
and `#guard_msgs (ordering := sorted) in cmd` sorts the messages in lexicographic order before checking.
* [#3931](https://github.com/leanprover/lean4/pull/3931) adds an unused variables ignore function for `#guard_msgs`.
* [#3912](https://github.com/leanprover/lean4/pull/3912) adds a diff between the expected and actual outputs. This feature is currently
disabled by default, but can be enabled with `set_option guard_msgs.diff true`.
Depending on user feedback, this option may default to `true` in a future version of Lean.
* `do` **notation**
* [#3820](https://github.com/leanprover/lean4/pull/3820) makes it an error to lift `(<- ...)` out of a pure `if ... then ... else ...`
* **Lazy discrimination trees**
* [#3610](https://github.com/leanprover/lean4/pull/3610) fixes a name collision for `LazyDiscrTree` that could lead to cache poisoning.
* [#3677](https://github.com/leanprover/lean4/pull/3677) simplifies and fixes `LazyDiscrTree` handling for `exact?`/`apply?`.
* [#3685](https://github.com/leanprover/lean4/pull/3685) moves general `exact?`/`apply?` functionality into `LazyDiscrTree`.
* [#3769](https://github.com/leanprover/lean4/pull/3769) has lemma selection improvements for `rw?` and `LazyDiscrTree`.
* [#3818](https://github.com/leanprover/lean4/pull/3818) improves ordering of matches.
* [#3590](https://github.com/leanprover/lean4/pull/3590) adds `inductive.autoPromoteIndices` option to be able to disable auto promotion of indices in the `inductive` command.
* **Miscellaneous bug fixes and improvements**
* [#3606](https://github.com/leanprover/lean4/pull/3606) preserves `cache` and `dischargeDepth` fields in `Lean.Meta.Simp.Result.mkEqSymm`.
* [#3633](https://github.com/leanprover/lean4/pull/3633) makes `elabTermEnsuringType` respect `errToSorry`, improving error recovery of the `have` tactic.
* [#3647](https://github.com/leanprover/lean4/pull/3647) enables `noncomputable unsafe` definitions, for deferring implementations until later.
* [#3672](https://github.com/leanprover/lean4/pull/3672) adjust namespaces of tactics.
* [#3725](https://github.com/leanprover/lean4/pull/3725) fixes `Ord` derive handler for indexed inductive types with unused alternatives.
* [#3893](https://github.com/leanprover/lean4/pull/3893) improves performance of derived `Ord` instances.
* [#3771](https://github.com/leanprover/lean4/pull/3771) changes error reporting for failing tactic macros. Improves `rfl` error message.
* [#3745](https://github.com/leanprover/lean4/pull/3745) fixes elaboration of generalized field notation if the object of the notation is an optional parameter.
* [#3799](https://github.com/leanprover/lean4/pull/3799) makes commands such as `universe`, `variable`, `namespace`, etc. require that their argument appear in a later column.
Commands that can optionally parse an `ident` or parse any number of `ident`s generally should require
that the `ident` use `colGt`. This keeps typos in commands from being interpreted as identifiers.
* [#3815](https://github.com/leanprover/lean4/pull/3815) lets the `split` tactic be used for writing code.
* [#3822](https://github.com/leanprover/lean4/pull/3822) adds missing info in `induction` tactic for `with` clauses of the form `| cstr a b c => ?_`.
* [#3806](https://github.com/leanprover/lean4/pull/3806) fixes `withSetOptionIn` combinator.
* [#3844](https://github.com/leanprover/lean4/pull/3844) removes unused `trace.Elab.syntax` option.
* [#3896](https://github.com/leanprover/lean4/pull/3896) improves hover and go-to-def for `attribute` command.
* [#3989](https://github.com/leanprover/lean4/pull/3989) makes linter options more discoverable.
* [#3916](https://github.com/leanprover/lean4/pull/3916) fixes go-to-def for syntax defined with `@[builtin_term_parser]`.
* [#3962](https://github.com/leanprover/lean4/pull/3962) fixes how `solveByElim` handles `symm` lemmas, making `exact?`/`apply?` usable again.
* [#3968](https://github.com/leanprover/lean4/pull/3968) improves the `@[deprecated]` attribute, adding `(since := "<date>")` field.
* [#3768](https://github.com/leanprover/lean4/pull/3768) makes `#print` command show structure fields.
* [#3974](https://github.com/leanprover/lean4/pull/3974) makes `exact?%` behave like `by exact?` rather than `by apply?`.
* [#3994](https://github.com/leanprover/lean4/pull/3994) makes elaboration of `he ▸ h` notation more predictable.
* [#3991](https://github.com/leanprover/lean4/pull/3991) adjusts transparency for `decreasing_trivial` macros.
* [#4092](https://github.com/leanprover/lean4/pull/4092) improves performance of `binop%` and `binrel%` expression tree elaborators.
* **Docs:** [#3748](https://github.com/leanprover/lean4/pull/3748), [#3796](https://github.com/leanprover/lean4/pull/3796),
[#3800](https://github.com/leanprover/lean4/pull/3800), [#3874](https://github.com/leanprover/lean4/pull/3874),
[#3863](https://github.com/leanprover/lean4/pull/3863), [#3862](https://github.com/leanprover/lean4/pull/3862),
[#3891](https://github.com/leanprover/lean4/pull/3891), [#3873](https://github.com/leanprover/lean4/pull/3873),
[#3908](https://github.com/leanprover/lean4/pull/3908), [#3872](https://github.com/leanprover/lean4/pull/3872).
### Language server and IDE extensions
* [#3602](https://github.com/leanprover/lean4/pull/3602) enables `import` auto-completions.
* [#3608](https://github.com/leanprover/lean4/pull/3608) fixes issue [leanprover/vscode-lean4#392](https://github.com/leanprover/vscode-lean4/issues/392).
Diagnostic ranges had an off-by-one error that would misplace goal states for example.
* [#3014](https://github.com/leanprover/lean4/pull/3014) introduces snapshot trees, foundational work for incremental tactics and parallelism.
[#3849](https://github.com/leanprover/lean4/pull/3849) adds basic incrementality API.
* [#3271](https://github.com/leanprover/lean4/pull/3271) adds support for server-to-client requests.
* [#3656](https://github.com/leanprover/lean4/pull/3656) fixes jump to definition when there are conflicting names from different files.
Fixes issue [#1170](https://github.com/leanprover/lean4/issues/1170).
* [#3691](https://github.com/leanprover/lean4/pull/3691), [#3925](https://github.com/leanprover/lean4/pull/3925),
[#3932](https://github.com/leanprover/lean4/pull/3932) keep semantic tokens synchronized (used for semantic highlighting), with performance improvements.
* [#3247](https://github.com/leanprover/lean4/pull/3247) and [#3730](https://github.com/leanprover/lean4/pull/3730)
add diagnostics to run "Restart File" when a file dependency is saved.
* [#3722](https://github.com/leanprover/lean4/pull/3722) uses the correct module names when displaying references.
* [#3728](https://github.com/leanprover/lean4/pull/3728) makes errors in header reliably appear and makes the "Import out of date" warning be at "hint" severity.
[#3739](https://github.com/leanprover/lean4/pull/3739) simplifies the text of this warning.
* [#3778](https://github.com/leanprover/lean4/pull/3778) fixes [#3462](https://github.com/leanprover/lean4/issues/3462),
where info nodes from before the cursor would be used for computing completions.
* [#3985](https://github.com/leanprover/lean4/pull/3985) makes trace timings appear in Infoview.
### Pretty printing
* [#3797](https://github.com/leanprover/lean4/pull/3797) fixes the hovers over binders so that they show their types.
* [#3640](https://github.com/leanprover/lean4/pull/3640) and [#3735](https://github.com/leanprover/lean4/pull/3735): Adds attribute `@[pp_using_anonymous_constructor]` to make structures pretty print as `⟨x, y, z⟩`
rather than as `{a := x, b := y, c := z}`.
This attribute is applied to `Sigma`, `PSigma`, `PProd`, `Subtype`, `And`, and `Fin`.
* [#3749](https://github.com/leanprover/lean4/pull/3749)
Now structure instances pretty print with parent structures' fields inlined.
That is, if `B` extends `A`, then `{ toA := { x := 1 }, y := 2 }` now pretty prints as `{ x := 1, y := 2 }`.
Setting option `pp.structureInstances.flatten` to false turns this off.
* [#3737](https://github.com/leanprover/lean4/pull/3737), [#3744](https://github.com/leanprover/lean4/pull/3744)
and [#3750](https://github.com/leanprover/lean4/pull/3750):
Option `pp.structureProjections` is renamed to `pp.fieldNotation`, and there is now a suboption `pp.fieldNotation.generalized`
to enable pretty printing function applications using generalized field notation (defaults to true).
Field notation can be disabled on a function-by-function basis using the `@[pp_nodot]` attribute.
The notation is not used for theorems.
* [#4071](https://github.com/leanprover/lean4/pull/4071) fixes interaction between app unexpanders and `pp.fieldNotation.generalized`
* [#3625](https://github.com/leanprover/lean4/pull/3625) makes `delabConstWithSignature` (used by `#check`) have the ability to put arguments "after the colon"
to avoid printing inaccessible names.
* [#3798](https://github.com/leanprover/lean4/pull/3798),
[#3978](https://github.com/leanprover/lean4/pull/3978),
[#3798](https://github.com/leanprover/lean4/pull/3980):
Adds options `pp.mvars` (default: true) and `pp.mvars.withType` (default: false).
When `pp.mvars` is false, expression metavariables pretty print as `?_` and universe metavariables pretty print as `_`.
When `pp.mvars.withType` is true, expression metavariables pretty print with a type ascription.
These can be set when using `#guard_msgs` to make tests not depend on the particular names of metavariables.
* [#3917](https://github.com/leanprover/lean4/pull/3917) makes binders hoverable and gives them docstrings.
* [#4034](https://github.com/leanprover/lean4/pull/4034) makes hovers for RHS terms in `match` expressions in the Infoview reliably show the correct term.
### Library
* `Bool`/`Prop`
* [#3508](https://github.com/leanprover/lean4/pull/3508) improves `simp` confluence for `Bool` and `Prop` terms.
* Theorems: [#3604](https://github.com/leanprover/lean4/pull/3604)
* `Nat`
* [#3579](https://github.com/leanprover/lean4/pull/3579) makes `Nat.succ_eq_add_one` be a simp lemma, now that `induction`/`cases` uses `n + 1` instead of `Nat.succ n`.
* [#3808](https://github.com/leanprover/lean4/pull/3808) replaces `Nat.succ` simp rules with simprocs.
* [#3876](https://github.com/leanprover/lean4/pull/3876) adds faster `Nat.repr` implementation in C.
* `Int`
* Theorems: [#3890](https://github.com/leanprover/lean4/pull/3890)
* `UInt`s
* [#3960](https://github.com/leanprover/lean4/pull/3960) improves performance of upcasting.
* `Array` and `Subarray`
* [#3676](https://github.com/leanprover/lean4/pull/3676) removes `Array.eraseIdxAux`, `Array.eraseIdxSzAux`, and `Array.eraseIdx'`.
* [#3648](https://github.com/leanprover/lean4/pull/3648) simplifies `Array.findIdx?`.
* [#3851](https://github.com/leanprover/lean4/pull/3851) renames fields of `Subarray`.
* `List`
* [#3785](https://github.com/leanprover/lean4/pull/3785) upstreams tail-recursive List operations and `@[csimp]` lemmas.
* `BitVec`
* Theorems: [#3593](https://github.com/leanprover/lean4/pull/3593),
[#3593](https://github.com/leanprover/lean4/pull/3593), [#3597](https://github.com/leanprover/lean4/pull/3597),
[#3598](https://github.com/leanprover/lean4/pull/3598), [#3721](https://github.com/leanprover/lean4/pull/3721),
[#3729](https://github.com/leanprover/lean4/pull/3729), [#3880](https://github.com/leanprover/lean4/pull/3880),
[#4039](https://github.com/leanprover/lean4/pull/4039).
* [#3884](https://github.com/leanprover/lean4/pull/3884) protects `Std.BitVec`.
* `String`
* [#3832](https://github.com/leanprover/lean4/pull/3832) fixes `String.splitOn`.
* [#3959](https://github.com/leanprover/lean4/pull/3959) adds `String.Pos.isValid`.
* [#3959](https://github.com/leanprover/lean4/pull/3959) UTF-8 string validation.
* [#3961](https://github.com/leanprover/lean4/pull/3961) adds a model implementation for UTF-8 encoding and decoding.
* `IO`
* [#4097](https://github.com/leanprover/lean4/pull/4097) adds `IO.getTaskState` which returns whether a task is finished, actively running, or waiting on other Tasks to finish.
* **Refactors**
* [#3605](https://github.com/leanprover/lean4/pull/3605) reduces imports for `Init.Data.Nat` and `Init.Data.Int`.
* [#3613](https://github.com/leanprover/lean4/pull/3613) reduces imports for `Init.Omega.Int`.
* [#3634](https://github.com/leanprover/lean4/pull/3634) upstreams `Std.Data.Nat`
and [#3635](https://github.com/leanprover/lean4/pull/3635) upstreams `Std.Data.Int`.
* [#3790](https://github.com/leanprover/lean4/pull/3790) reduces more imports for `omega`.
* [#3694](https://github.com/leanprover/lean4/pull/3694) extends `GetElem` interface with `getElem!` and `getElem?` to simplify containers like `RBMap`.
* [#3865](https://github.com/leanprover/lean4/pull/3865) renames `Option.toMonad` (see breaking changes below).
* [#3882](https://github.com/leanprover/lean4/pull/3882) unifies `lexOrd` with `compareLex`.
* **Other fixes or improvements**
* [#3765](https://github.com/leanprover/lean4/pull/3765) makes `Quotient.sound` be a `theorem`.
* [#3645](https://github.com/leanprover/lean4/pull/3645) fixes `System.FilePath.parent` in the case of absolute paths.
* [#3660](https://github.com/leanprover/lean4/pull/3660) `ByteArray.toUInt64LE!` and `ByteArray.toUInt64BE!` were swapped.
* [#3881](https://github.com/leanprover/lean4/pull/3881), [#3887](https://github.com/leanprover/lean4/pull/3887) fix linearity issues in `HashMap.insertIfNew`, `HashSet.erase`, and `HashMap.erase`.
The `HashMap.insertIfNew` fix improves `import` performance.
* [#3830](https://github.com/leanprover/lean4/pull/3830) ensures linearity in `Parsec.many*Core`.
* [#3930](https://github.com/leanprover/lean4/pull/3930) adds `FS.Stream.isTty` field.
* [#3866](https://github.com/leanprover/lean4/pull/3866) deprecates `Option.toBool` in favor of `Option.isSome`.
* [#3975](https://github.com/leanprover/lean4/pull/3975) upstreams `Data.List.Init` and `Data.Array.Init` material from Std.
* [#3942](https://github.com/leanprover/lean4/pull/3942) adds instances that make `ac_rfl` work without Mathlib.
* [#4010](https://github.com/leanprover/lean4/pull/4010) changes `Fin.induction` to use structural induction.
* [02753f](https://github.com/leanprover/lean4/commit/02753f6e4c510c385efcbf71fa9a6bec50fce9ab)
fixes bug in `reduceLeDiff` simproc.
* [#4097](https://github.com/leanprover/lean4/pull/4097)
adds `IO.TaskState` and `IO.getTaskState` to get the task from the Lean runtime's task manager.
* **Docs:** [#3615](https://github.com/leanprover/lean4/pull/3615), [#3664](https://github.com/leanprover/lean4/pull/3664),
[#3707](https://github.com/leanprover/lean4/pull/3707), [#3734](https://github.com/leanprover/lean4/pull/3734),
[#3868](https://github.com/leanprover/lean4/pull/3868), [#3861](https://github.com/leanprover/lean4/pull/3861),
[#3869](https://github.com/leanprover/lean4/pull/3869), [#3858](https://github.com/leanprover/lean4/pull/3858),
[#3856](https://github.com/leanprover/lean4/pull/3856), [#3857](https://github.com/leanprover/lean4/pull/3857),
[#3867](https://github.com/leanprover/lean4/pull/3867), [#3864](https://github.com/leanprover/lean4/pull/3864),
[#3860](https://github.com/leanprover/lean4/pull/3860), [#3859](https://github.com/leanprover/lean4/pull/3859),
[#3871](https://github.com/leanprover/lean4/pull/3871), [#3919](https://github.com/leanprover/lean4/pull/3919).
### Lean internals
* **Defeq and WHNF algorithms**
* [#3616](https://github.com/leanprover/lean4/pull/3616) gives better support for reducing `Nat.rec` expressions.
* [#3774](https://github.com/leanprover/lean4/pull/3774) add tracing for "non-easy" WHNF cases.
* [#3807](https://github.com/leanprover/lean4/pull/3807) fixes an `isDefEq` performance issue, now trying structure eta *after* lazy delta reduction.
* [#3816](https://github.com/leanprover/lean4/pull/3816) fixes `.yesWithDeltaI` behavior to prevent increasing transparency level when reducing projections.
* [#3837](https://github.com/leanprover/lean4/pull/3837) improves heuristic at `isDefEq`.
* [#3965](https://github.com/leanprover/lean4/pull/3965) improves `isDefEq` for constraints of the form `t.i =?= s.i`.
* [#3977](https://github.com/leanprover/lean4/pull/3977) improves `isDefEqProj`.
* [#3981](https://github.com/leanprover/lean4/pull/3981) adds universe constraint approximations to be able to solve `u =?= max u ?v` using `?v = u`.
These approximations are only applied when universe constraints cannot be postponed anymore.
* [#4004](https://github.com/leanprover/lean4/pull/4004) improves `isDefEqProj` during typeclass resolution.
* [#4012](https://github.com/leanprover/lean4/pull/4012) adds `backward.isDefEq.lazyProjDelta` and `backward.isDefEq.lazyWhnfCore` backwards compatibility flags.
* **Kernel**
* [#3966](https://github.com/leanprover/lean4/pull/3966) removes dead code.
* [#4035](https://github.com/leanprover/lean4/pull/4035) fixes mismatch for `TheoremVal` between Lean and C++.
* **Discrimination trees**
* [423fed](https://github.com/leanprover/lean4/commit/423fed79a9de75705f34b3e8648db7e076c688d7)
and [3218b2](https://github.com/leanprover/lean4/commit/3218b25974d33e92807af3ce42198911c256ff1d):
simplify handling of dependent/non-dependent pi types.
* **Typeclass instance synthesis**
* [#3638](https://github.com/leanprover/lean4/pull/3638) eta-reduces synthesized instances
* [ce350f](https://github.com/leanprover/lean4/commit/ce350f348161e63fccde6c4a5fe1fd2070e7ce0f) fixes a linearity issue
* [917a31](https://github.com/leanprover/lean4/commit/917a31f694f0db44d6907cc2b1485459afe74d49)
improves performance by considering at most one answer for subgoals not containing metavariables.
[#4008](https://github.com/leanprover/lean4/pull/4008) adds `backward.synthInstance.canonInstances` backward compatibility flag.
* **Definition processing**
* [#3661](https://github.com/leanprover/lean4/pull/3661), [#3767](https://github.com/leanprover/lean4/pull/3767) changes automatically generated equational theorems to be named
using suffix `.eq_<idx>` instead of `._eq_<idx>`, and `.eq_def` instead of `._unfold`. (See breaking changes below.)
[#3675](https://github.com/leanprover/lean4/pull/3675) adds a mechanism to reserve names.
[#3803](https://github.com/leanprover/lean4/pull/3803) fixes reserved name resolution inside namespaces and fixes handling of `match`er declarations and equation lemmas.
* [#3662](https://github.com/leanprover/lean4/pull/3662) causes auxiliary definitions nested inside theorems to become `def`s if they are not proofs.
* [#4006](https://github.com/leanprover/lean4/pull/4006) makes proposition fields of `structure`s be theorems.
* [#4018](https://github.com/leanprover/lean4/pull/4018) makes it an error for a theorem to be `extern`.
* [#4047](https://github.com/leanprover/lean4/pull/4047) improves performance making equations for well-founded recursive definitions.
* **Refactors**
* [#3614](https://github.com/leanprover/lean4/pull/3614) avoids unfolding in `Lean.Meta.evalNat`.
* [#3621](https://github.com/leanprover/lean4/pull/3621) centralizes functionality for `Fix`/`GuessLex`/`FunInd` in the `ArgsPacker` module.
* [#3186](https://github.com/leanprover/lean4/pull/3186) rewrites the UnusedVariable linter to be more performant.
* [#3589](https://github.com/leanprover/lean4/pull/3589) removes coercion from `String` to `Name` (see breaking changes below).
* [#3237](https://github.com/leanprover/lean4/pull/3237) removes the `lines` field from `FileMap`.
* [#3951](https://github.com/leanprover/lean4/pull/3951) makes msg parameter to `throwTacticEx` optional.
* **Diagnostics**
* [#4016](https://github.com/leanprover/lean4/pull/4016), [#4019](https://github.com/leanprover/lean4/pull/4019),
[#4020](https://github.com/leanprover/lean4/pull/4020), [#4030](https://github.com/leanprover/lean4/pull/4030),
[#4031](https://github.com/leanprover/lean4/pull/4031),
[c3714b](https://github.com/leanprover/lean4/commit/c3714bdc6d46845c0428735b283c5b48b23cbcf7),
[#4049](https://github.com/leanprover/lean4/pull/4049) adds `set_option diagnostics true` for diagnostic counters.
Tracks number of unfolded declarations, instances, reducible declarations, used instances, recursor reductions,
`isDefEq` heuristic applications, among others.
This option is suggested in exceptional situations, such as at deterministic timeout and maximum recursion depth.
* [283587](https://github.com/leanprover/lean4/commit/283587987ab2eb3b56fbc3a19d5f33ab9e04a2ef)
adds diagnostic information for `simp`.
* [#4043](https://github.com/leanprover/lean4/pull/4043) adds diagnostic information for congruence theorems.
* [#4048](https://github.com/leanprover/lean4/pull/4048) display diagnostic information
for `set_option diagnostics true in <tactic>` and `set_option diagnostics true in <term>`.
* **Other features**
* [#3800](https://github.com/leanprover/lean4/pull/3800) adds environment extension to record which definitions use structural or well-founded recursion.
* [#3801](https://github.com/leanprover/lean4/pull/3801) `trace.profiler` can now export to Firefox Profiler.
* [#3918](https://github.com/leanprover/lean4/pull/3918), [#3953](https://github.com/leanprover/lean4/pull/3953) adds `@[builtin_doc]` attribute to make docs and location of a declaration available as a builtin.
* [#3939](https://github.com/leanprover/lean4/pull/3939) adds the `lean --json` CLI option to print messages as JSON.
* [#3075](https://github.com/leanprover/lean4/pull/3075) improves `test_extern` command.
* [#3970](https://github.com/leanprover/lean4/pull/3970) gives monadic generalization of `FindExpr`.
* **Docs:** [#3743](https://github.com/leanprover/lean4/pull/3743), [#3921](https://github.com/leanprover/lean4/pull/3921),
[#3954](https://github.com/leanprover/lean4/pull/3954).
* **Other fixes:** [#3622](https://github.com/leanprover/lean4/pull/3622),
[#3726](https://github.com/leanprover/lean4/pull/3726), [#3823](https://github.com/leanprover/lean4/pull/3823),
[#3897](https://github.com/leanprover/lean4/pull/3897), [#3964](https://github.com/leanprover/lean4/pull/3964),
[#3946](https://github.com/leanprover/lean4/pull/3946), [#4007](https://github.com/leanprover/lean4/pull/4007),
[#4026](https://github.com/leanprover/lean4/pull/4026).
### Compiler, runtime, and FFI
* [#3632](https://github.com/leanprover/lean4/pull/3632) makes it possible to allocate and free thread-local runtime resources for threads not started by Lean itself.
* [#3627](https://github.com/leanprover/lean4/pull/3627) improves error message about compacting closures.
* [#3692](https://github.com/leanprover/lean4/pull/3692) fixes deadlock in `IO.Promise.resolve`.
* [#3753](https://github.com/leanprover/lean4/pull/3753) catches error code from `MoveFileEx` on Windows.
* [#4028](https://github.com/leanprover/lean4/pull/4028) fixes a double `reset` bug in `ResetReuse` transformation.
* [6e731b](https://github.com/leanprover/lean4/commit/6e731b4370000a8e7a5cfb675a7f3d7635d21f58)
removes `interpreter` copy constructor to avoid potential memory safety issues.
### Lake
* **TOML Lake configurations**. [#3298](https://github.com/leanprover/lean4/pull/3298), [#4104](https://github.com/leanprover/lean4/pull/4104).
Lake packages can now use TOML as a alternative configuration file format instead of Lean. If the default `lakefile.lean` is missing, Lake will also look for a `lakefile.toml`. The TOML version of the configuration supports a restricted set of the Lake configuration options, only including those which can easily mapped to a TOML data structure. The TOML syntax itself fully compiles with the TOML v1.0.0 specification.
As part of the introduction of this new feature, we have been helping maintainers of some major packages within the ecosystem switch to this format. For example, the following is Aesop's new `lakefile.toml`:
**[leanprover-community/aesop/lakefile.toml](https://raw.githubusercontent.com/leanprover-community/aesop/de11e0ecf372976e6d627c210573146153090d2d/lakefile.toml)**
```toml
name = "aesop"
defaultTargets = ["Aesop"]
testRunner = "test"
precompileModules = false
[[require]]
name = "batteries"
git = "https://github.com/leanprover-community/batteries"
rev = "main"
[[lean_lib]]
name = "Aesop"
[[lean_lib]]
name = "AesopTest"
globs = ["AesopTest.+"]
leanOptions = {linter.unusedVariables = false}
[[lean_exe]]
name = "test"
srcDir = "scripts"
```
To assist users who wish to transition their packages between configuration file formats, there is also a new `lake translate-config` command for migrating to/from TOML.
Running `lake translate-config toml` will produce a `lakefile.toml` version of a package's `lakefile.lean`. Any configuration options unsupported by the TOML format will be discarded during translation, but the original `lakefile.lean` will remain so that you can verify the translation looks good before deleting it.
* **Build progress overhaul.** [#3835](https://github.com/leanprover/lean4/pull/3835), [#4115](https://github.com/leanprover/lean4/pull/4115), [#4127](https://github.com/leanprover/lean4/pull/4127), [#4220](https://github.com/leanprover/lean4/pull/4220), [#4232](https://github.com/leanprover/lean4/pull/4232), [#4236](https://github.com/leanprover/lean4/pull/4236).
Builds are now managed by a top-level Lake build monitor, this makes the output of Lake builds more standardized and enables producing prettier and more configurable progress reports.
As part of this change, job isolation has improved. Stray I/O and other build related errors in custom targets are now properly isolated and caught as part of their job. Import errors no longer cause Lake to abort the entire build and are instead localized to the build jobs of the modules in question.
Lake also now uses ANSI escape sequences to add color and produce progress lines that update in-place; this can be toggled on and off using `--ansi` / `--no-ansi`.
`--wfail` and `--iofail` options have been added that causes a build to fail if any of the jobs log a warning (`--wfail`) or produce any output or log information messages (`--iofail`). Unlike some other build systems, these options do **NOT** convert these logs into errors, and Lake does not abort jobs on such a log (i.e., dependent jobs will still continue unimpeded).
* `lake test`. [#3779](https://github.com/leanprover/lean4/pull/3779).
Lake now has a built-in `test` command which will run a script or executable labelled `@[test_runner]` (in Lean) or defined as the `testRunner` (in TOML) in the root package.
Lake also provides a `lake check-test` command which will exit with code `0` if the package has a properly configured test runner or error with `1` otherwise.
* `lake lean`. [#3793](https://github.com/leanprover/lean4/pull/3793).
The new command `lake lean <file> [-- <args...>]` functions like `lake env lean <file> <args...>`, except that it builds the imports of `file` before running `lean`. This makes it very useful for running test or example code that imports modules that are not guaranteed to have been built beforehand.
* **Miscellaneous bug fixes and improvements**
* [#3609](https://github.com/leanprover/lean4/pull/3609) `LEAN_GITHASH` environment variable to override the detected Git hash for Lean when computing traces, useful for testing custom builds of Lean.
* [#3795](https://github.com/leanprover/lean4/pull/3795) improves relative package directory path normalization in the pre-rename check.
* [#3957](https://github.com/leanprover/lean4/pull/3957) fixes handling of packages that appear multiple times in a dependency tree.
* [#3999](https://github.com/leanprover/lean4/pull/3999) makes it an error for there to be a mismatch between a package name and what it is required as. Also adds a special message for the `std`-to-`batteries` rename.
* [#4033](https://github.com/leanprover/lean4/pull/4033) fixes quiet mode.
* **Docs:** [#3704](https://github.com/leanprover/lean4/pull/3704).
### DevOps
* [#3536](https://github.com/leanprover/lean4/pull/3536) and [#3833](https://github.com/leanprover/lean4/pull/3833)
add a checklist for the release process.
* [#3600](https://github.com/leanprover/lean4/pull/3600) runs nix-ci more uniformly.
* [#3612](https://github.com/leanprover/lean4/pull/3612) avoids argument limits when building on Windows.
* [#3682](https://github.com/leanprover/lean4/pull/3682) builds Lean's `.o` files in parallel to rest of core.
* [#3601](https://github.com/leanprover/lean4/pull/3601)
changes the way Lean is built on Windows (see breaking changes below).
As a result, Lake now dynamically links executables with `supportInterpreter := true` on Windows
to `libleanshared.dll` and `libInit_shared.dll`. Therefore, such executables will not run
unless those shared libraries are co-located with the executables or part of `PATH`.
Running the executable via `lake exe` will ensure these libraries are part of `PATH`.
In a related change, the signature of the `nativeFacets` Lake configuration options has changed
from a static `Array` to a function `(shouldExport : Bool) → Array`.
See its docstring or Lake's [README](src/lake/README.md) for further details on the changed option.
* [#3690](https://github.com/leanprover/lean4/pull/3690) marks "Build matrix complete" as canceled if the build is canceled.
* [#3700](https://github.com/leanprover/lean4/pull/3700), [#3702](https://github.com/leanprover/lean4/pull/3702),
[#3701](https://github.com/leanprover/lean4/pull/3701), [#3834](https://github.com/leanprover/lean4/pull/3834),
[#3923](https://github.com/leanprover/lean4/pull/3923): fixes and improvements for std and mathlib CI.
* [#3712](https://github.com/leanprover/lean4/pull/3712) fixes `nix build .` on macOS.
* [#3717](https://github.com/leanprover/lean4/pull/3717) replaces `shell.nix` in devShell with `flake.nix`.
* [#3715](https://github.com/leanprover/lean4/pull/3715) and [#3790](https://github.com/leanprover/lean4/pull/3790) add test result summaries.
* [#3971](https://github.com/leanprover/lean4/pull/3971) prevents stage0 changes via the merge queue.
* [#3979](https://github.com/leanprover/lean4/pull/3979) adds handling for `changes-stage0` label.
* [#3952](https://github.com/leanprover/lean4/pull/3952) adds a script to summarize GitHub issues.
* [18a699](https://github.com/leanprover/lean4/commit/18a69914da53dbe37c91bc2b9ce65e1dc01752b6)
fixes asan linking
### Breaking changes
* Due to the major Lake build refactor, code using the affected parts of the Lake API or relying on the previous output format of Lake builds is likely to have been broken. We have tried to minimize the breakages and, where possible, old definitions have been marked `@[deprecated]` with a reference to the new alternative.
* Executables configured with `supportInterpreter := true` on Windows should now be run via `lake exe` to function properly.
* Automatically generated equational theorems are now named using suffix `.eq_<idx>` instead of `._eq_<idx>`, and `.eq_def` instead of `._unfold`. Example:
```
def fact : Nat → Nat
| 0 => 1
| n+1 => (n+1) * fact n
theorem ex : fact 0 = 1 := by unfold fact; decide
#check fact.eq_1
-- fact.eq_1 : fact 0 = 1
#check fact.eq_2
-- fact.eq_2 (n : Nat) : fact (Nat.succ n) = (n + 1) * fact n
#check fact.eq_def
/-
fact.eq_def :
∀ (x : Nat),
fact x =
match x with
| 0 => 1
| Nat.succ n => (n + 1) * fact n
-/
```
* The coercion from `String` to `Name` was removed. Previously, it was `Name.mkSimple`, which does not separate strings at dots, but experience showed that this is not always the desired coercion. For the previous behavior, manually insert a call to `Name.mkSimple`.
* The `Subarray` fields `as`, `h₁` and `h₂` have been renamed to `array`, `start_le_stop`, and `stop_le_array_size`, respectively. This more closely follows standard Lean conventions. Deprecated aliases for the field projections were added; these will be removed in a future release.
* The change to the instance name algorithm (described above) can break projects that made use of the auto-generated names.
* `Option.toMonad` has been renamed to `Option.getM` and the unneeded `[Monad m]` instance argument has been removed.

321
releases/v4.9.0.md Normal file
View File

@@ -0,0 +1,321 @@
v4.9.0
----------
### Language features, tactics, and metaprograms
* **Definition transparency**
* [#4053](https://github.com/leanprover/lean4/pull/4053) adds the `seal` and `unseal` commands, which make definitions locally be irreducible or semireducible.
* [#4061](https://github.com/leanprover/lean4/pull/4061) marks functions defined by well-founded recursion with `@[irreducible]` by default,
which should prevent the expensive and often unfruitful unfolding of such definitions (see breaking changes below).
* **Incrementality**
* [#3940](https://github.com/leanprover/lean4/pull/3940) extends incremental elaboration into various steps inside of declarations:
definition headers, bodies, and tactics.
![Recording 2024-05-10](https://github.com/leanprover/lean4/assets/109126/c9d67b6f-c131-4bc3-a0de-7d63eaf1bfc9).
* [250994](https://github.com/leanprover/lean4/commit/250994166ce036ab8644e459129f51ea79c1c2d2)
and [67338b](https://github.com/leanprover/lean4/commit/67338bac2333fa39a8656e8f90574784e4c23d3d)
add `@[incremental]` attribute to mark an elaborator as supporting incremental elaboration.
* [#4259](https://github.com/leanprover/lean4/pull/4259) improves resilience by ensuring incremental commands and tactics are reached only in supported ways.
* [#4268](https://github.com/leanprover/lean4/pull/4268) adds special handling for `:= by` so that stray tokens in tactic blocks do not inhibit incrementality.
* [#4308](https://github.com/leanprover/lean4/pull/4308) adds incremental `have` tactic.
* [#4340](https://github.com/leanprover/lean4/pull/4340) fixes incorrect info tree reuse.
* [#4364](https://github.com/leanprover/lean4/pull/4364) adds incrementality for careful command macros such as `set_option in theorem`, `theorem foo.bar`, and `lemma`.
* [#4395](https://github.com/leanprover/lean4/pull/4395) adds conservative fix for whitespace handling to avoid incremental reuse leading to goals in front of the text cursor being shown.
* [#4407](https://github.com/leanprover/lean4/pull/4407) fixes non-incremental commands in macros blocking further incremental reporting.
* [#4436](https://github.com/leanprover/lean4/pull/4436) fixes incremental reporting when there are nested tactics in terms.
* [#4459](https://github.com/leanprover/lean4/pull/4459) adds incrementality support for `next` and `if` tactics.
* [#4554](https://github.com/leanprover/lean4/pull/4554) disables incrementality for tactics in terms in tactics.
* **Functional induction**
* [#4135](https://github.com/leanprover/lean4/pull/4135) ensures that the names used for functional induction are reserved.
* [#4327](https://github.com/leanprover/lean4/pull/4327) adds support for structural recursion on reflexive types.
For example,
```lean4
inductive Many (α : Type u) where
| none : Many α
| more : α → (Unit → Many α) → Many α
def Many.map {α β : Type u} (f : α → β) : Many α → Many β
| .none => .none
| .more x xs => .more (f x) (fun _ => (xs ()).map f)
#check Many.map.induct
/-
Many.map.induct {α β : Type u} (f : α → β) (motive : Many α → Prop)
(case1 : motive Many.none)
(case2 : ∀ (x : α) (xs : Unit → Many α), motive (xs ()) → motive (Many.more x xs)) :
∀ (a : Many α), motive a
-/
```
* [#3903](https://github.com/leanprover/lean4/pull/3903) makes the Lean frontend normalize all line endings to LF before processing.
This lets Lean be insensitive to CRLF vs LF line endings, improving the cross-platform experience and making Lake hashes be faithful to what Lean processes.
* [#4130](https://github.com/leanprover/lean4/pull/4130) makes the tactic framework be able to recover from runtime errors (for example, deterministic timeouts or maximum recursion depth errors).
* `split` tactic
* [#4211](https://github.com/leanprover/lean4/pull/4211) fixes `split at h` when `h` has forward dependencies.
* [#4349](https://github.com/leanprover/lean4/pull/4349) allows `split` for `if`-expressions to work on non-propositional goals.
* `apply` tactic
* [#3929](https://github.com/leanprover/lean4/pull/3929) makes error message for `apply` show implicit arguments in unification errors as needed.
Modifies `MessageData` type (see breaking changes below).
* `cases` tactic
* [#4224](https://github.com/leanprover/lean4/pull/4224) adds support for unification of offsets such as `x + 20000 = 20001` in `cases` tactic.
* `omega` tactic
* [#4073](https://github.com/leanprover/lean4/pull/4073) lets `omega` fall back to using classical `Decidable` instances when setting up contradiction proofs.
* [#4141](https://github.com/leanprover/lean4/pull/4141) and [#4184](https://github.com/leanprover/lean4/pull/4184) fix bugs.
* [#4264](https://github.com/leanprover/lean4/pull/4264) improves `omega` error message if no facts found in local context.
* [#4358](https://github.com/leanprover/lean4/pull/4358) improves expression matching in `omega` by using `match_expr`.
* `simp` tactic
* [#4176](https://github.com/leanprover/lean4/pull/4176) makes names of erased lemmas clickable.
* [#4208](https://github.com/leanprover/lean4/pull/4208) adds a pretty printer for discrimination tree keys.
* [#4202](https://github.com/leanprover/lean4/pull/4202) adds `Simp.Config.index` configuration option,
which controls whether to use the full discrimination tree when selecting candidate simp lemmas.
When `index := false`, only the head function is taken into account, like in Lean 3.
This feature can help users diagnose tricky simp failures or issues in code from libraries
developed using Lean 3 and then ported to Lean 4.
In the following example, it will report that `foo` is a problematic theorem.
```lean
opaque f : Nat → Nat → Nat
@[simp] theorem foo : f x (x, y).2 = y := by sorry
example : f a b ≤ b := by
set_option diagnostics true in
simp (config := { index := false })
/-
[simp] theorems with bad keys
foo, key: f _ (@Prod.mk _ _).2
-/
```
With the information above, users can annotate theorems such as `foo` using `no_index` for problematic subterms. Example:
```lean
opaque f : Nat → Nat → Nat
@[simp] theorem foo : f x (no_index (x, y).2) = y := by sorry
example : f a b ≤ b := by
simp -- `foo` is still applied with `index := true`
```
* [#4274](https://github.com/leanprover/lean4/pull/4274) prevents internal `match` equational theorems from appearing in simp trace.
* [#4177](https://github.com/leanprover/lean4/pull/4177) and [#4359](https://github.com/leanprover/lean4/pull/4359) make `simp` continue even if a simp lemma does not elaborate, if the tactic state is in recovery mode.
* [#4341](https://github.com/leanprover/lean4/pull/4341) fixes panic when applying `@[simp]` to malformed theorem syntax.
* [#4345](https://github.com/leanprover/lean4/pull/4345) fixes `simp` so that it does not use the forward version of a user-specified backward theorem.
* [#4352](https://github.com/leanprover/lean4/pull/4352) adds missing `dsimp` simplifications for fixed parameters of generated congruence theorems.
* [#4362](https://github.com/leanprover/lean4/pull/4362) improves trace messages for `simp` so that constants are hoverable.
* **Elaboration**
* [#4046](https://github.com/leanprover/lean4/pull/4046) makes subst notation (`he ▸ h`) try rewriting in both directions even when there is no expected type available.
* [#3328](https://github.com/leanprover/lean4/pull/3328) adds support for identifiers in autoparams (for example, `rfl` in `(h : x = y := by exact rfl)`).
* [#4096](https://github.com/leanprover/lean4/pull/4096) changes how the type in `let` and `have` is elaborated, requiring that any tactics in the type be evaluated before proceeding, improving performance.
* [#4215](https://github.com/leanprover/lean4/pull/4215) ensures the expression tree elaborator commits to the computed "max type" for the entire arithmetic expression.
* [#4267](https://github.com/leanprover/lean4/pull/4267) cases signature elaboration errors to show even if there are parse errors in the body.
* [#4368](https://github.com/leanprover/lean4/pull/4368) improves error messages when numeric literals fail to synthesize an `OfNat` instance,
including special messages warning when the expected type of the numeral can be a proposition.
* [#4643](https://github.com/leanprover/lean4/pull/4643) fixes issue leading to nested error messages and info trees vanishing, where snapshot subtrees were not restored on reuse.
* [#4657](https://github.com/leanprover/lean4/pull/4657) calculates error suppression per snapshot, letting elaboration errors appear even when there are later parse errors ([RFC #3556](https://github.com/leanprover/lean4/issues/3556)).
* **Metaprogramming**
* [#4167](https://github.com/leanprover/lean4/pull/4167) adds `Lean.MVarId.revertAll` to revert all free variables.
* [#4169](https://github.com/leanprover/lean4/pull/4169) adds `Lean.MVarId.ensureNoMVar` to ensure the goal's target contains no expression metavariables.
* [#4180](https://github.com/leanprover/lean4/pull/4180) adds `cleanupAnnotations` parameter to `forallTelescope` methods.
* [#4307](https://github.com/leanprover/lean4/pull/4307) adds support for parser aliases in syntax quotations.
* Work toward implementing `grind` tactic
* [0a515e](https://github.com/leanprover/lean4/commit/0a515e2ec939519dafb4b99daa81d6bf3c411404)
and [#4164](https://github.com/leanprover/lean4/pull/4164)
add `grind_norm` and `grind_norm_proc` attributes and `@[grind_norm]` theorems.
* [#4170](https://github.com/leanprover/lean4/pull/4170), [#4221](https://github.com/leanprover/lean4/pull/4221),
and [#4249](https://github.com/leanprover/lean4/pull/4249) create `grind` preprocessor and core module.
* [#4235](https://github.com/leanprover/lean4/pull/4235) and [d6709e](https://github.com/leanprover/lean4/commit/d6709eb1576c5d40fc80462637dc041f970e4d9f)
add special `cases` tactic to `grind` along with `@[grind_cases]` attribute to mark types that this `cases` tactic should automatically apply to.
* [#4243](https://github.com/leanprover/lean4/pull/4243) adds special `injection?` tactic to `grind`.
* **Other fixes or improvements**
* [#4065](https://github.com/leanprover/lean4/pull/4065) fixes a bug in the `Nat.reduceLeDiff` simproc.
* [#3969](https://github.com/leanprover/lean4/pull/3969) makes deprecation warnings activate even for generalized field notation ("dot notation").
* [#4132](https://github.com/leanprover/lean4/pull/4132) fixes the `sorry` term so that it does not activate the implicit lambda feature
* [9803c5](https://github.com/leanprover/lean4/commit/9803c5dd63dc993628287d5f998525e74af03839)
and [47c8e3](https://github.com/leanprover/lean4/commit/47c8e340d65b01f4d9f011686e3dda0d4bb30a20)
move `cdot` and `calc` parsers to `Lean` namespace.
* [#4252](https://github.com/leanprover/lean4/pull/4252) fixes the `case` tactic so that it is usable in macros by having it erase macro scopes from the tag.
* [26b671](https://github.com/leanprover/lean4/commit/26b67184222e75529e1b166db050aaebee323d2d)
and [cc33c3](https://github.com/leanprover/lean4/commit/cc33c39cb022d8a3166b1e89677c78835ead1fc7)
extract `haveId` syntax.
* [#4335](https://github.com/leanprover/lean4/pull/4335) fixes bugs in partial `calc` tactic when there is mdata or metavariables.
* [#4329](https://github.com/leanprover/lean4/pull/4329) makes `termination_by?` report unused each unused parameter as `_`.
* **Docs:** [#4238](https://github.com/leanprover/lean4/pull/4238), [#4294](https://github.com/leanprover/lean4/pull/4294),
[#4338](https://github.com/leanprover/lean4/pull/4338).
### Language server, widgets, and IDE extensions
* [#4066](https://github.com/leanprover/lean4/pull/4066) fixes features like "Find References" when browsing core Lean sources.
* [#4254](https://github.com/leanprover/lean4/pull/4254) allows embedding user widgets in structured messages.
Companion PR is [vscode-lean4#449](https://github.com/leanprover/vscode-lean4/pull/449).
* [#4445](https://github.com/leanprover/lean4/pull/4445) makes watchdog more resilient against badly behaving clients.
### Library
* [#4059](https://github.com/leanprover/lean4/pull/4059) upstreams many `List` and `Array` operations and theorems from Batteries.
* [#4055](https://github.com/leanprover/lean4/pull/4055) removes the unused `Inhabited` instance for `Subtype`.
* [#3967](https://github.com/leanprover/lean4/pull/3967) adds dates in existing `@[deprecated]` attributes.
* [#4231](https://github.com/leanprover/lean4/pull/4231) adds boilerplate `Char`, `UInt`, and `Fin` theorems.
* [#4205](https://github.com/leanprover/lean4/pull/4205) fixes the `MonadStore` type classes to use `semiOutParam`.
* [#4350](https://github.com/leanprover/lean4/pull/4350) renames `IsLawfulSingleton` to `LawfulSingleton`.
* `Nat`
* [#4094](https://github.com/leanprover/lean4/pull/4094) swaps `Nat.zero_or` and `Nat.or_zero`.
* [#4098](https://github.com/leanprover/lean4/pull/4098) and [#4145](https://github.com/leanprover/lean4/pull/4145)
change the definition of `Nat.mod` so that `n % (m + n)` reduces when `n` is literal without relying on well-founded recursion,
which becomes irreducible by default in [#4061](https://github.com/leanprover/lean4/pull/4061).
* [#4188](https://github.com/leanprover/lean4/pull/4188) redefines `Nat.testBit` to be more performant.
* Theorems: [#4199](https://github.com/leanprover/lean4/pull/4199).
* `Array`
* [#4074](https://github.com/leanprover/lean4/pull/4074) improves the functional induction principle `Array.feraseIdx.induct`.
* `List`
* [#4172](https://github.com/leanprover/lean4/pull/4172) removes `@[simp]` from `List.length_pos`.
* `Option`
* [#4037](https://github.com/leanprover/lean4/pull/4037) adds theorems to simplify `Option`-valued dependent if-then-else.
* [#4314](https://github.com/leanprover/lean4/pull/4314) removes `@[simp]` from `Option.bind_eq_some`.
* `BitVec`
* Theorems: [#3920](https://github.com/leanprover/lean4/pull/3920), [#4095](https://github.com/leanprover/lean4/pull/4095),
[#4075](https://github.com/leanprover/lean4/pull/4075), [#4148](https://github.com/leanprover/lean4/pull/4148),
[#4165](https://github.com/leanprover/lean4/pull/4165), [#4178](https://github.com/leanprover/lean4/pull/4178),
[#4200](https://github.com/leanprover/lean4/pull/4200), [#4201](https://github.com/leanprover/lean4/pull/4201),
[#4298](https://github.com/leanprover/lean4/pull/4298), [#4299](https://github.com/leanprover/lean4/pull/4299),
[#4257](https://github.com/leanprover/lean4/pull/4257), [#4179](https://github.com/leanprover/lean4/pull/4179),
[#4321](https://github.com/leanprover/lean4/pull/4321), [#4187](https://github.com/leanprover/lean4/pull/4187).
* [#4193](https://github.com/leanprover/lean4/pull/4193) adds simprocs for reducing `x >>> i` and `x <<< i` where `i` is a bitvector literal.
* [#4194](https://github.com/leanprover/lean4/pull/4194) adds simprocs for reducing `(x <<< i) <<< j` and `(x >>> i) >>> j` where `i` and `j` are natural number literals.
* [#4229](https://github.com/leanprover/lean4/pull/4229) redefines `rotateLeft`/`rotateRight` to use modulo reduction of shift offset.
* [0d3051](https://github.com/leanprover/lean4/commit/0d30517dca094a07bcb462252f718e713b93ffba) makes `<num>#<term>` bitvector literal notation global.
* `Char`/`String`
* [#4143](https://github.com/leanprover/lean4/pull/4143) modifies `String.substrEq` to avoid linter warnings in downstream code.
* [#4233](https://github.com/leanprover/lean4/pull/4233) adds simprocs for `Char` and `String` inequalities.
* [#4348](https://github.com/leanprover/lean4/pull/4348) upstreams Mathlib lemmas.
* [#4354](https://github.com/leanprover/lean4/pull/4354) upstreams basic `String` lemmas.
* `HashMap`
* [#4248](https://github.com/leanprover/lean4/pull/4248) fixes implicitness of typeclass arguments in `HashMap.ofList`.
* `IO`
* [#4036](https://github.com/leanprover/lean4/pull/4036) adds `IO.Process.getCurrentDir` and `IO.Process.setCurrentDir` for adjusting the current process's working directory.
* **Cleanup:** [#4077](https://github.com/leanprover/lean4/pull/4077), [#4189](https://github.com/leanprover/lean4/pull/4189),
[#4304](https://github.com/leanprover/lean4/pull/4304).
* **Docs:** [#4001](https://github.com/leanprover/lean4/pull/4001), [#4166](https://github.com/leanprover/lean4/pull/4166),
[#4332](https://github.com/leanprover/lean4/pull/4332).
### Lean internals
* **Defeq and WHNF algorithms**
* [#4029](https://github.com/leanprover/lean4/pull/4029) remove unnecessary `checkpointDefEq`
* [#4206](https://github.com/leanprover/lean4/pull/4206) fixes `isReadOnlyOrSyntheticOpaque` to respect metavariable depth.
* [#4217](https://github.com/leanprover/lean4/pull/4217) fixes missing occurs check for delayed assignments.
* **Definition transparency**
* [#4052](https://github.com/leanprover/lean4/pull/4052) adds validation to application of `@[reducible]`/`@[semireducible]`/`@[irreducible]` attributes (with `local`/`scoped` modifiers as well).
Setting `set_option allowUnsafeReductibility true` turns this validation off.
* **Inductive types**
* [#3591](https://github.com/leanprover/lean4/pull/3591) fixes a bug where indices could be incorrectly promoted to parameters.
* [#3398](https://github.com/leanprover/lean4/pull/3398) fixes a bug in the injectivity theorem generator.
* [#4342](https://github.com/leanprover/lean4/pull/4342) fixes elaboration of mutual inductives with instance parameters.
* **Diagnostics and profiling**
* [#3986](https://github.com/leanprover/lean4/pull/3986) adds option `trace.profiler.useHeartbeats` to switch `trace.profiler.threshold` to being in terms of heartbeats instead of milliseconds.
* [#4082](https://github.com/leanprover/lean4/pull/4082) makes `set_option diagnostics true` report kernel diagnostic information.
* **Typeclass resolution**
* [#4119](https://github.com/leanprover/lean4/pull/4119) fixes multiple issues with TC caching interacting with `synthPendingDepth`, adds `maxSynthPendingDepth` option with default value `1`.
* [#4210](https://github.com/leanprover/lean4/pull/4210) ensures local instance cache does not contain multiple copies of the same instance.
* [#4216](https://github.com/leanprover/lean4/pull/4216) fix handling of metavariables, to avoid needing to set the option `backward.synthInstance.canonInstances` to `false`.
* **Other fixes or improvements**
* [#4080](https://github.com/leanprover/lean4/pull/4080) fixes propagation of state for `Lean.Elab.Command.liftCoreM` and `Lean.Elab.Command.liftTermElabM`.
* [#3944](https://github.com/leanprover/lean4/pull/3944) makes the `Repr` deriving handler be consistent between `structure` and `inductive` for how types and proofs are erased.
* [#4113](https://github.com/leanprover/lean4/pull/4113) propagates `maxHeartbeats` to kernel to control "(kernel) deterministic timeout" error.
* [#4125](https://github.com/leanprover/lean4/pull/4125) reverts [#3970](https://github.com/leanprover/lean4/pull/3970) (monadic generalization of `FindExpr`).
* [#4128](https://github.com/leanprover/lean4/pull/4128) catches stack overflow in auto-bound implicits feature.
* [#4129](https://github.com/leanprover/lean4/pull/4129) adds `tryCatchRuntimeEx` combinator to replace `catchRuntimeEx` reader state.
* [#4155](https://github.com/leanprover/lean4/pull/4155) simplifies the expression canonicalizer.
* [#4151](https://github.com/leanprover/lean4/pull/4151) and [#4369](https://github.com/leanprover/lean4/pull/4369)
add many missing trace classes.
* [#4185](https://github.com/leanprover/lean4/pull/4185) makes congruence theorem generators clean up type annotations of argument types.
* [#4192](https://github.com/leanprover/lean4/pull/4192) fixes restoration of infotrees when auto-bound implicit feature is activated,
fixing a pretty printing error in hovers and strengthening the unused variable linter.
* [dfb496](https://github.com/leanprover/lean4/commit/dfb496a27123c3864571aec72f6278e2dad1cecf) fixes `declareBuiltin` to allow it to be called multiple times per declaration.
* [#4569](https://github.com/leanprover/lean4/pull/4569) fixes an issue introduced in a merge conflict, where the interrupt exception was swallowed by some `tryCatchRuntimeEx` uses.
* [#4584](https://github.com/leanprover/lean4/pull/4584) (backported as [b056a0](https://github.com/leanprover/lean4/commit/b056a0b395bb728512a3f3e83bf9a093059d4301)) adapts kernel interruption to the new cancellation system.
* Cleanup: [#4112](https://github.com/leanprover/lean4/pull/4112), [#4126](https://github.com/leanprover/lean4/pull/4126), [#4091](https://github.com/leanprover/lean4/pull/4091), [#4139](https://github.com/leanprover/lean4/pull/4139), [#4153](https://github.com/leanprover/lean4/pull/4153).
* Tests: [030406](https://github.com/leanprover/lean4/commit/03040618b8f9b35b7b757858483e57340900cdc4), [#4133](https://github.com/leanprover/lean4/pull/4133).
### Compiler, runtime, and FFI
* [#4100](https://github.com/leanprover/lean4/pull/4100) improves reset/reuse algorithm; it now runs a second pass relaxing the constraint that reused memory cells must only be for the exact same constructor.
* [#2903](https://github.com/leanprover/lean4/pull/2903) fixes segfault in old compiler from mishandling `noConfusion` applications.
* [#4311](https://github.com/leanprover/lean4/pull/4311) fixes bug in constant folding.
* [#3915](https://github.com/leanprover/lean4/pull/3915) documents the runtime memory layout for inductive types.
### Lake
* [#4518](https://github.com/leanprover/lean4/pull/4518) makes trace reading more robust. Lake now rebuilds if trace files are invalid or unreadable and is backwards compatible with previous pure numeric traces.
* [#4057](https://github.com/leanprover/lean4/pull/4057) adds support for docstrings on `require` commands.
* [#4088](https://github.com/leanprover/lean4/pull/4088) improves hovers for `family_def` and `library_data` commands.
* [#4147](https://github.com/leanprover/lean4/pull/4147) adds default `README.md` to package templates
* [#4261](https://github.com/leanprover/lean4/pull/4261) extends `lake test` help page, adds help page for `lake check-test`,
adds `lake lint` and tag `@[lint_driver]`, adds support for specifying test and lint drivers from dependencies,
adds `testDriverArgs` and `lintDriverArgs` options, adds support for library test drivers,
makes `lake check-test` and `lake check-lint` only load the package without dependencies.
* [#4270](https://github.com/leanprover/lean4/pull/4270) adds `lake pack` and `lake unpack` for packing and unpacking Lake build artifacts from an archive.
* [#4083](https://github.com/leanprover/lean4/pull/4083)
Switches the manifest format to use `major.minor.patch` semantic
versions. Major version increments indicate breaking changes (e.g., new
required fields and semantic changes to existing fields). Minor version
increments (after `0.x`) indicate backwards-compatible extensions (e.g.,
adding optional fields, removing fields). This change is backwards
compatible. Lake will still successfully read old manifests with numeric
versions. It will treat the numeric version `N` as semantic version
`0.N.0`. Lake will also accept manifest versions with `-` suffixes
(e.g., `x.y.z-foo`) and then ignore the suffix.
* [#4273](https://github.com/leanprover/lean4/pull/4273) adds a lift from `JobM` to `FetchM` for backwards compatibility reasons.
* [#4351](https://github.com/leanprover/lean4/pull/4351) fixes `LogIO`-to-`CliM`-lifting performance issues.
* [#4343](https://github.com/leanprover/lean4/pull/4343) make Lake store the dependency trace for a build in
the cached build long and then verifies that it matches the trace of the current build before replaying the log.
* [#4402](https://github.com/leanprover/lean4/pull/4402) moves the cached log into the trace file (no more `.log.json`).
This means logs are no longer cached on fatal errors and this ensures that an out-of-date log is not associated with an up-to-date trace.
Separately, `.hash` file generation was changed to be more reliable as well.
The `.hash` files are deleted as part of the build and always regenerate with `--rehash`.
* **Other fixes or improvements**
* [#4056](https://github.com/leanprover/lean4/pull/4056) cleans up tests
* [#4244](https://github.com/leanprover/lean4/pull/4244) fixes `noRelease` test when Lean repo is tagged
* [#4346](https://github.com/leanprover/lean4/pull/4346) improves `tests/serve`
* [#4356](https://github.com/leanprover/lean4/pull/4356) adds build log path to the warning for a missing or invalid build log.
### DevOps
* [#3984](https://github.com/leanprover/lean4/pull/3984) adds a script (`script/rebase-stage0.sh`) for `git rebase -i` that automatically updates each stage0.
* [#4108](https://github.com/leanprover/lean4/pull/4108) finishes renamings from transition to Std to Batteries.
* [#4109](https://github.com/leanprover/lean4/pull/4109) adjusts the Github bug template to mention testing using [live.lean-lang.org](https://live.lean-lang.org).
* [#4136](https://github.com/leanprover/lean4/pull/4136) makes CI rerun only when `full-ci` label is added or removed.
* [#4175](https://github.com/leanprover/lean4/pull/4175) and [72b345](https://github.com/leanprover/lean4/commit/72b345c621a9a06d3a5a656da2b793a5eea5f168)
switch to using `#guard_msgs` to run tests as much as possible.
* [#3125](https://github.com/leanprover/lean4/pull/3125) explains the Lean4 `pygments` lexer.
* [#4247](https://github.com/leanprover/lean4/pull/4247) sets up a procedure for preparing release notes.
* [#4032](https://github.com/leanprover/lean4/pull/4032) modernizes build instructions and workflows.
* [#4255](https://github.com/leanprover/lean4/pull/4255) moves some expensive checks from merge queue to releases.
* [#4265](https://github.com/leanprover/lean4/pull/4265) adds aarch64 macOS as native compilation target for CI.
* [f05a82](https://github.com/leanprover/lean4/commit/f05a82799a01569edeb5e2594cd7d56282320f9e) restores macOS aarch64 install suffix in CI
* [#4317](https://github.com/leanprover/lean4/pull/4317) updates build instructions for macOS.
* [#4333](https://github.com/leanprover/lean4/pull/4333) adjusts workflow to update Batteries in manifest when creating `lean-pr-testing-NNNN` Mathlib branches.
* [#4355](https://github.com/leanprover/lean4/pull/4355) simplifies `lean4checker` step of release checklist.
* [#4361](https://github.com/leanprover/lean4/pull/4361) adds installing elan to `pr-release` CI step.
* [#4628](https://github.com/leanprover/lean4/pull/4628) fixes the Windows build, which was missing an exported symbol.
### Breaking changes
While most changes could be considered to be a breaking change, this section makes special note of API changes.
* `Nat.zero_or` and `Nat.or_zero` have been swapped ([#4094](https://github.com/leanprover/lean4/pull/4094)).
* `IsLawfulSingleton` is now `LawfulSingleton` ([#4350](https://github.com/leanprover/lean4/pull/4350)).
* The `BitVec` literal notation is now `<num>#<term>` rather than `<term>#<term>`, and it is global rather than scoped. Use `BitVec.ofNat w x` rather than `x#w` when `x` is a not a numeric literal ([0d3051](https://github.com/leanprover/lean4/commit/0d30517dca094a07bcb462252f718e713b93ffba)).
* `BitVec.rotateLeft` and `BitVec.rotateRight` now take the shift modulo the bitwidth ([#4229](https://github.com/leanprover/lean4/pull/4229)).
* These are no longer simp lemmas:
`List.length_pos` ([#4172](https://github.com/leanprover/lean4/pull/4172)),
`Option.bind_eq_some` ([#4314](https://github.com/leanprover/lean4/pull/4314)).
* Types in `let` and `have` (both the expressions and tactics) may fail to elaborate due to new restrictions on what sorts of elaboration problems may be postponed ([#4096](https://github.com/leanprover/lean4/pull/4096)).
In particular, tactics embedded in the type will no longer make use of the type of `value` in expressions such as `let x : type := value; body`.
* Now functions defined by well-founded recursion are marked with `@[irreducible]` by default ([#4061](https://github.com/leanprover/lean4/pull/4061)).
Existing proofs that hold by definitional equality (e.g. `rfl`) can be
rewritten to explicitly unfold the function definition (using `simp`,
`unfold`, `rw`), or the recursive function can be temporarily made
semireducible (using `unseal f in` before the command), or the function
definition itself can be marked as `@[semireducible]` to get the previous
behavior.
* Due to [#3929](https://github.com/leanprover/lean4/pull/3929):
* The `MessageData.ofPPFormat` constructor has been removed.
Its functionality has been split into two:
- for lazy structured messages, please use `MessageData.lazy`;
- for embedding `Format` or `FormatWithInfos`, use `MessageData.ofFormatWithInfos`.
An example migration can be found in [#3929](https://github.com/leanprover/lean4/pull/3929/files#diff-5910592ab7452a0e1b2616c62d22202d2291a9ebb463145f198685aed6299867L109).
* The `MessageData.ofFormat` constructor has been turned into a function.
If you need to inspect `MessageData`, you can pattern-match on `MessageData.ofFormatWithInfos`.

View File

@@ -1,16 +0,0 @@
We replace the inductive predicate `List.lt` with an upstreamed version of `List.Lex` from Mathlib.
(Previously `Lex.lt` was defined in terms of `<`; now it is generalized to take an arbitrary relation.)
This subtely changes the notion of ordering on `List α`.
`List.lt` was a weaker relation: in particular if `l₁ < l₂`, then
`a :: l₁ < b :: l₂` may hold according to `List.lt` even if `a` and `b` are merely incomparable
(either neither `a < b` nor `b < a`), whereas according to `List.Lex` this would require `a = b`.
When `<` is total, in the sense that `¬ · < ·` is antisymmetric, then the two relations coincide.
Mathlib was already overriding the order instances for `List α`,
so this change should not be noticed by anyone already using Mathlib.
We simultaneously add the boolean valued `List.lex` function, parameterised by a `BEq` typeclass
and an arbitrary `lt` function. This will support the flexibility previously provided for `List.lt`,
via a `==` function which is weaker than strict equality.

View File

@@ -63,8 +63,8 @@ else
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='-nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-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 -Wl,--no-as-needed -fuse-ld=lld'"
echo -n " -DLEANC_INTERNAL_FLAGS='--sysroot ROOT -nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
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 -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

@@ -48,12 +48,11 @@ if [[ -L llvm-host ]]; then
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang"
gcp $GMP/lib/libgmp.a stage1/lib/
gcp $LIBUV/lib/libuv.a stage1/lib/
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/libc -fuse-ld=lld'"
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp -luv'"
else
echo -n " -DCMAKE_C_COMPILER=$PWD/llvm-host/bin/clang -DLEANC_OPTS='--sysroot $PWD/stage1 -resource-dir $PWD/stage1/lib/clang/15.0.1 ${EXTRA_FLAGS:-}'"
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/libc -fuse-ld=lld'"
fi
echo -n " -DLEANC_INTERNAL_FLAGS='-nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
echo -n " -DLEANC_INTERNAL_FLAGS='--sysroot ROOT -nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='--sysroot ROOT -L ROOT/lib -L ROOT/lib/libc -fuse-ld=lld'"
# do not set `LEAN_CC` for tests
echo -n " -DLEAN_TEST_VARS=''"

View File

@@ -25,7 +25,10 @@ cp llvm/lib/clang/*/include/{std*,__std*,limits}.h stage1/include/clang
echo '
// https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode
#define SEM_FAILCRITICALERRORS 0x0001
__declspec(dllimport) __stdcall unsigned int SetErrorMode(unsigned int uMode);' > stage1/include/clang/windows.h
__declspec(dllimport) __stdcall unsigned int SetErrorMode(unsigned int uMode);
// https://docs.microsoft.com/en-us/windows/console/setconsoleoutputcp
#define CP_UTF8 65001
__declspec(dllimport) __stdcall int SetConsoleOutputCP(unsigned int wCodePageID);' > stage1/include/clang/windows.h
# COFF dependencies
cp /clang64/lib/{crtbegin,crtend,crt2,dllcrt2}.o stage1/lib/
# runtime
@@ -43,7 +46,7 @@ echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang.exe -DCMAKE_C_COMPILER_WORKS=
echo -n " -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_CXX_COMPILER=clang++"
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter /clang64/include/'"
echo -n " -DLEANC_INTERNAL_FLAGS='--sysroot ROOT -nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang.exe"
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -static-libgcc -Wl,-Bstatic -lgmp $(pkg-config --static --libs libuv) -lunwind -Wl,-Bdynamic -fuse-ld=lld'"
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='--sysroot ROOT -L ROOT/lib -Wl,-Bstatic -lgmp $(pkg-config --static --libs libuv) -lunwind -Wl,-Bdynamic -fuse-ld=lld'"
# when not using the above flags, link GMP dynamically/as usual. Always link ICU dynamically.
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp $(pkg-config --libs libuv) -lucrtbase'"
# do not set `LEAN_CC` for tests

69
script/push_repo_release_tag.py Executable file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
import sys
import subprocess
import requests
def main():
if len(sys.argv) != 4:
print("Usage: ./push_repo_release_tag.py <repo> <branch> <version_tag>")
sys.exit(1)
repo, branch, version_tag = sys.argv[1], sys.argv[2], sys.argv[3]
if branch not in {"master", "main"}:
print(f"Error: Branch '{branch}' is not 'master' or 'main'.")
sys.exit(1)
# Get the `lean-toolchain` file content
lean_toolchain_url = f"https://raw.githubusercontent.com/{repo}/{branch}/lean-toolchain"
try:
response = requests.get(lean_toolchain_url)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Error fetching 'lean-toolchain' file: {e}")
sys.exit(1)
lean_toolchain_content = response.text.strip()
expected_prefix = "leanprover/lean4:"
if not lean_toolchain_content.startswith(expected_prefix) or lean_toolchain_content != f"{expected_prefix}{version_tag}":
print(f"Error: 'lean-toolchain' content does not match '{expected_prefix}{version_tag}'.")
sys.exit(1)
# Create and push the tag using `gh`
try:
# Check if the tag already exists
list_tags_cmd = ["gh", "api", f"repos/{repo}/git/matching-refs/tags/v4", "--jq", ".[].ref"]
list_tags_output = subprocess.run(list_tags_cmd, capture_output=True, text=True)
if list_tags_output.returncode == 0:
existing_tags = list_tags_output.stdout.strip().splitlines()
if f"refs/tags/{version_tag}" in existing_tags:
print(f"Error: Tag '{version_tag}' already exists.")
print("Existing tags starting with 'v4':")
for tag in existing_tags:
print(tag.replace("refs/tags/", ""))
sys.exit(1)
# Get the SHA of the branch
get_sha_cmd = [
"gh", "api", f"repos/{repo}/git/ref/heads/{branch}", "--jq", ".object.sha"
]
sha_result = subprocess.run(get_sha_cmd, capture_output=True, text=True, check=True)
sha = sha_result.stdout.strip()
# Create the tag
create_tag_cmd = [
"gh", "api", f"repos/{repo}/git/refs",
"-X", "POST",
"-F", f"ref=refs/tags/{version_tag}",
"-F", f"sha={sha}"
]
subprocess.run(create_tag_cmd, capture_output=True, text=True, check=True)
print(f"Successfully created and pushed tag '{version_tag}' to {repo}.")
except subprocess.CalledProcessError as e:
print(f"Error while creating/pushing tag: {e.stderr.strip() if e.stderr else e}")
sys.exit(1)
if __name__ == "__main__":
main()

309
script/release_checklist.py Executable file
View File

@@ -0,0 +1,309 @@
#!/usr/bin/env python3
import argparse
import yaml
import requests
import base64
import subprocess
import sys
import os
def parse_repos_config(file_path):
with open(file_path, "r") as f:
return yaml.safe_load(f)["repositories"]
def get_github_token():
try:
import subprocess
result = subprocess.run(['gh', 'auth', 'token'], capture_output=True, text=True)
if result.returncode == 0:
return result.stdout.strip()
except FileNotFoundError:
print("Warning: 'gh' CLI not found. Some API calls may be rate-limited.")
return None
def strip_rc_suffix(toolchain):
"""Remove -rcX suffix from the toolchain."""
return toolchain.split("-")[0]
def branch_exists(repo_url, branch, github_token):
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/branches/{branch}"
headers = {'Authorization': f'token {github_token}'} if github_token else {}
response = requests.get(api_url, headers=headers)
return response.status_code == 200
def tag_exists(repo_url, tag_name, github_token):
# Use /git/matching-refs/tags/ to get all matching tags
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/git/matching-refs/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 False
# Check if any of the returned refs exactly match our tag
matching_tags = response.json()
return any(tag["ref"] == f"refs/tags/{tag_name}" for tag in matching_tags)
def release_page_exists(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)
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_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}"
headers = {'Authorization': f'token {github_token}'} if github_token else {}
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
content = response.json().get("content", "")
content = content.replace("\n", "")
try:
return base64.b64decode(content).decode('utf-8').strip()
except Exception:
return None
return None
def parse_version(version_str):
# Remove 'v' prefix and extract version and release candidate suffix
if ':' in version_str:
version_str = version_str.split(':')[1]
version = version_str.lstrip('v')
parts = version.split('-')
base_version = tuple(map(int, parts[0].split('.')))
rc_part = parts[1] if len(parts) > 1 and parts[1].startswith('rc') else None
rc_number = int(rc_part[2:]) if rc_part else float('inf') # Treat non-rc as higher than rc
return base_version + (rc_number,)
def is_version_gte(version1, version2):
"""Check if version1 >= version2, including proper handling of release candidates."""
return parse_version(version1) >= parse_version(version2)
def is_merged_into_stable(repo_url, tag_name, stable_branch, github_token):
# First get the commit SHA for the tag
api_base = repo_url.replace("https://github.com/", "https://api.github.com/repos/")
headers = {'Authorization': f'token {github_token}'} if github_token else {}
# Get tag's commit SHA
tag_response = requests.get(f"{api_base}/git/refs/tags/{tag_name}", headers=headers)
if tag_response.status_code != 200:
return False
# Handle both single object and array responses
tag_data = tag_response.json()
if isinstance(tag_data, list):
# Find the exact matching tag in the list
matching_tags = [tag for tag in tag_data if tag['ref'] == f'refs/tags/{tag_name}']
if not matching_tags:
return False
tag_sha = matching_tags[0]['object']['sha']
else:
tag_sha = tag_data['object']['sha']
# Get commits on stable branch containing this SHA
commits_response = requests.get(
f"{api_base}/commits?sha={stable_branch}&per_page=100",
headers=headers
)
if commits_response.status_code != 200:
return False
# Check if any commit in stable's history matches our tag's SHA
stable_commits = [commit['sha'] for commit in commits_response.json()]
return tag_sha in stable_commits
def is_release_candidate(version):
return "-rc" in version
def check_cmake_version(repo_url, branch, version_major, version_minor, github_token):
"""Verify the CMake version settings in src/CMakeLists.txt."""
cmake_file_path = "src/CMakeLists.txt"
content = get_branch_content(repo_url, branch, cmake_file_path, github_token)
if content is None:
print(f" ❌ Could not retrieve {cmake_file_path} from {branch}")
return False
expected_lines = [
f"set(LEAN_VERSION_MAJOR {version_major})",
f"set(LEAN_VERSION_MINOR {version_minor})",
f"set(LEAN_VERSION_PATCH 0)",
f"set(LEAN_VERSION_IS_RELEASE 1)"
]
for line in expected_lines:
if not any(l.strip().startswith(line) for l in content.splitlines()):
print(f" ❌ Missing or incorrect line in {cmake_file_path}: {line}")
return False
print(f" ✅ CMake version settings are correct in {cmake_file_path}")
return True
def extract_org_repo_from_url(repo_url):
"""Extract the 'org/repo' part from a GitHub URL."""
if repo_url.startswith("https://github.com/"):
return repo_url.replace("https://github.com/", "").rstrip("/")
return repo_url
def get_next_version(version):
"""Calculate the next version number, ignoring RC suffix."""
# Strip v prefix and RC suffix if present
base_version = strip_rc_suffix(version.lstrip('v'))
major, minor, patch = map(int, base_version.split('.'))
# Next version is always .0
return f"v{major}.{minor + 1}.0"
def check_bump_branch_toolchain(url, bump_branch, github_token):
"""Check if the lean-toolchain file in bump branch starts with either 'leanprover/lean4:nightly-' or the next version."""
content = get_branch_content(url, bump_branch, "lean-toolchain", github_token)
if content is None:
print(f" ❌ No lean-toolchain file found in {bump_branch} branch")
return False
# Extract the next version from the bump branch name (bump/v4.X.0)
next_version = bump_branch.split('/')[1]
if not (content.startswith("leanprover/lean4:nightly-") or
content.startswith(f"leanprover/lean4:{next_version}")):
print(f" ❌ Bump branch toolchain should use either nightly or {next_version}, but found: {content}")
return False
print(f" ✅ Bump branch correctly uses toolchain: {content}")
return True
def main():
github_token = get_github_token()
if len(sys.argv) != 2:
print("Usage: python3 release_checklist.py <toolchain>")
sys.exit(1)
toolchain = sys.argv[1]
stripped_toolchain = strip_rc_suffix(toolchain)
lean_repo_url = "https://github.com/leanprover/lean4"
# Preliminary checks
print("\nPerforming preliminary checks...")
# Check for branch releases/v4.Y.0
version_major, version_minor, _ = map(int, stripped_toolchain.lstrip('v').split('.'))
branch_name = f"releases/v{version_major}.{version_minor}.0"
if branch_exists(lean_repo_url, branch_name, github_token):
print(f" ✅ Branch {branch_name} exists")
# Check CMake version settings
check_cmake_version(lean_repo_url, branch_name, version_major, version_minor, github_token)
else:
print(f" ❌ Branch {branch_name} does not exist")
# Check for tag v4.X.Y(-rcZ)
if tag_exists(lean_repo_url, toolchain, github_token):
print(f" ✅ Tag {toolchain} exists")
else:
print(f" ❌ Tag {toolchain} does not exist.")
# Check for release page
if release_page_exists(lean_repo_url, toolchain, github_token):
print(f" ✅ Release page for {toolchain} exists")
# Check the first line of the release notes
release_notes = get_release_notes(lean_repo_url, toolchain, github_token)
if release_notes and toolchain in release_notes.splitlines()[0].strip():
print(f" ✅ Release notes look good.")
else:
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}`.")
else:
print(f" ❌ Release page for {toolchain} does not exist")
# Load repositories and perform further checks
print("\nChecking repositories...")
with open(os.path.join(os.path.dirname(__file__), "release_repos.yml")) as f:
repos = yaml.safe_load(f)["repositories"]
for repo in repos:
name = repo["name"]
url = repo["url"]
branch = repo["branch"]
check_stable = repo["stable-branch"]
check_tag = repo.get("toolchain-tag", True)
check_bump = repo.get("bump-branch", False)
print(f"\nRepository: {name}")
# Check if branch is on at least the target toolchain
lean_toolchain_content = get_branch_content(url, branch, "lean-toolchain", github_token)
if lean_toolchain_content is None:
print(f" ❌ No lean-toolchain file found in {branch} branch")
continue
on_target_toolchain = is_version_gte(lean_toolchain_content.strip(), toolchain)
if not on_target_toolchain:
print(f" ❌ Not on target toolchain (needs ≥ {toolchain}, but {branch} is on {lean_toolchain_content.strip()})")
continue
print(f" ✅ On compatible toolchain (>= {toolchain})")
# Only check for tag if toolchain-tag is true
if check_tag:
if not tag_exists(url, toolchain, github_token):
print(f" ❌ Tag {toolchain} does not exist. Run `script/push_repo_release_tag.py {extract_org_repo_from_url(url)} {branch} {toolchain}`.")
else:
print(f" ✅ Tag {toolchain} exists")
# Only check merging into stable if stable-branch is true and not a release candidate
if check_stable and not is_release_candidate(toolchain):
if not is_merged_into_stable(url, toolchain, "stable", github_token):
print(f" ❌ Tag {toolchain} is not merged into stable")
else:
print(f" ✅ Tag {toolchain} is merged into stable")
# Check for bump branch if configured
if check_bump:
next_version = get_next_version(toolchain)
bump_branch = f"bump/{next_version}"
if branch_exists(url, bump_branch, github_token):
print(f" ✅ Bump branch {bump_branch} exists")
check_bump_branch_toolchain(url, bump_branch, github_token)
else:
print(f" ❌ Bump branch {bump_branch} does not exist")
# Check lean4 master branch for next development cycle
print("\nChecking lean4 master branch configuration...")
next_version = get_next_version(toolchain)
next_minor = int(next_version.split('.')[1])
cmake_content = get_branch_content(lean_repo_url, "master", "src/CMakeLists.txt", github_token)
if cmake_content is None:
print(" ❌ Could not retrieve CMakeLists.txt from master")
else:
cmake_lines = cmake_content.splitlines()
# Find the actual minor version in CMakeLists.txt
for line in cmake_lines:
if line.strip().startswith("set(LEAN_VERSION_MINOR "):
actual_minor = int(line.split()[-1].rstrip(")"))
version_minor_correct = actual_minor >= next_minor
break
else:
version_minor_correct = False
is_release_correct = any(
l.strip().startswith("set(LEAN_VERSION_IS_RELEASE 0)")
for l in cmake_lines
)
if not (version_minor_correct and is_release_correct):
print(" ❌ lean4 needs a \"begin dev cycle\" PR")
else:
print(" ✅ lean4 master branch is configured for next development cycle")
if __name__ == "__main__":
main()

181
script/release_notes.py Executable file
View File

@@ -0,0 +1,181 @@
#!/usr/bin/env python3
import sys
import re
import json
import requests
import subprocess
import argparse
from collections import defaultdict
from git import Repo
def get_commits_since_tag(repo, tag):
try:
tag_commit = repo.commit(tag)
commits = list(repo.iter_commits(f"{tag_commit.hexsha}..HEAD"))
return [
(commit.hexsha, commit.message.splitlines()[0], commit.message)
for commit in commits
]
except Exception as e:
sys.stderr.write(f"Error retrieving commits: {e}\n")
sys.exit(1)
def check_pr_number(first_line):
match = re.search(r"\(\#(\d+)\)$", first_line)
if match:
return int(match.group(1))
return None
def fetch_pr_labels(pr_number):
try:
# Use gh CLI to fetch PR details
result = subprocess.run([
"gh", "api", f"repos/leanprover/lean4/pulls/{pr_number}"
], capture_output=True, text=True, check=True)
pr_data = result.stdout
pr_json = json.loads(pr_data)
return [label["name"] for label in pr_json.get("labels", [])]
except subprocess.CalledProcessError as e:
sys.stderr.write(f"Failed to fetch PR #{pr_number} using gh: {e.stderr}\n")
return []
def format_section_title(label):
title = label.replace("changelog-", "").capitalize()
if title == "Doc":
return "Documentation"
elif title == "Pp":
return "Pretty Printing"
return title
def sort_sections_order():
return [
"Language",
"Library",
"Compiler",
"Pretty Printing",
"Documentation",
"Server",
"Lake",
"Other",
"Uncategorised"
]
def format_markdown_description(pr_number, description):
link = f"[#{pr_number}](https://github.com/leanprover/lean4/pull/{pr_number})"
return f"{link} {description}"
def commit_types():
# see doc/dev/commit_convention.md
return ['feat', 'fix', 'doc', 'style', 'refactor', 'test', 'chore', 'perf']
def count_commit_types(commits):
counts = {
'total': len(commits),
}
for commit_type in commit_types():
counts[commit_type] = 0
for _, first_line, _ in commits:
for commit_type in commit_types():
if first_line.startswith(f'{commit_type}:'):
counts[commit_type] += 1
break
return counts
def main():
parser = argparse.ArgumentParser(description='Generate release notes from Git commits')
parser.add_argument('--since', required=True, help='Git tag to generate release notes since')
args = parser.parse_args()
try:
repo = Repo(".")
except Exception as e:
sys.stderr.write(f"Error opening Git repository: {e}\n")
sys.exit(1)
commits = get_commits_since_tag(repo, args.since)
sys.stderr.write(f"Found {len(commits)} commits since tag {args.since}:\n")
for commit_hash, first_line, _ in commits:
sys.stderr.write(f"- {commit_hash}: {first_line}\n")
changelog = defaultdict(list)
for commit_hash, first_line, full_message in commits:
# Skip commits with the specific first lines
if first_line == "chore: update stage0" or first_line.startswith("chore: CI: bump "):
continue
pr_number = check_pr_number(first_line)
if not pr_number:
sys.stderr.write(f"No PR number found in commit:\n{commit_hash}\n{first_line}\n")
continue
# Remove the first line from the full_message for further processing
body = full_message[len(first_line):].strip()
paragraphs = body.split('\n\n')
description = paragraphs[0] if len(paragraphs) > 0 else ""
# If there's a third paragraph and second ends with colon, include it
if len(paragraphs) > 1 and description.endswith(':'):
description = description + '\n\n' + paragraphs[1]
labels = fetch_pr_labels(pr_number)
# Skip entries with the "changelog-no" label
if "changelog-no" in labels:
continue
report_errors = first_line.startswith("feat:") or first_line.startswith("fix:")
if not description.startswith("This PR "):
if report_errors:
sys.stderr.write(f"No PR description found in commit:\n{commit_hash}\n{first_line}\n{body}\n\n")
fallback_description = re.sub(r":$", "", first_line.split(" ", 1)[1]).rsplit(" (#", 1)[0]
markdown_description = format_markdown_description(pr_number, fallback_description)
else:
continue
else:
markdown_description = format_markdown_description(pr_number, description.replace("This PR ", ""))
changelog_labels = [label for label in labels if label.startswith("changelog-")]
if len(changelog_labels) > 1:
sys.stderr.write(f"Warning: Multiple changelog-* labels found for PR #{pr_number}: {changelog_labels}\n")
if not changelog_labels:
if report_errors:
sys.stderr.write(f"Warning: No changelog-* label found for PR #{pr_number}\n")
else:
continue
for label in changelog_labels:
changelog[label].append((pr_number, markdown_description))
# Add commit type counting
counts = count_commit_types(commits)
print(f"For this release, {counts['total']} changes landed. "
f"In addition to the {counts['feat']} feature additions and {counts['fix']} fixes listed below "
f"there were {counts['refactor']} refactoring changes, {counts['doc']} documentation improvements, "
f"{counts['perf']} performance improvements, {counts['test']} improvements to the test suite "
f"and {counts['style'] + counts['chore']} other changes.\n")
section_order = sort_sections_order()
sorted_changelog = sorted(changelog.items(), key=lambda item: section_order.index(format_section_title(item[0])) if format_section_title(item[0]) in section_order else len(section_order))
for label, entries in sorted_changelog:
section_title = format_section_title(label) if label != "Uncategorised" else "Uncategorised"
print(f"## {section_title}\n")
for _, entry in sorted(entries, key=lambda x: x[0]):
# Split entry into lines and indent all lines after the first
lines = entry.splitlines()
print(f"* {lines[0]}")
for line in lines[1:]:
print(f" {line}")
print() # Empty line after each entry
if __name__ == "__main__":
main()

95
script/release_repos.yml Normal file
View File

@@ -0,0 +1,95 @@
repositories:
- name: Batteries
url: https://github.com/leanprover-community/batteries
toolchain-tag: true
stable-branch: true
branch: main
bump-branch: true
dependencies: []
- name: lean4checker
url: https://github.com/leanprover/lean4checker
toolchain-tag: true
stable-branch: true
branch: master
dependencies: []
- name: quote4
url: https://github.com/leanprover-community/quote4
toolchain-tag: true
stable-branch: true
branch: master
dependencies: []
- name: doc-gen4
url: https://github.com/leanprover/doc-gen4
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: Verso
url: https://github.com/leanprover/verso
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: 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
- name: Aesop
url: https://github.com/leanprover-community/aesop
toolchain-tag: true
stable-branch: true
branch: master
dependencies:
- Batteries
- name: import-graph
url: https://github.com/leanprover-community/import-graph
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: plausible
url: https://github.com/leanprover-community/plausible
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: Mathlib
url: https://github.com/leanprover-community/mathlib4
toolchain-tag: true
stable-branch: true
branch: master
bump-branch: true
dependencies:
- Aesop
- ProofWidgets4
- lean4checker
- Batteries
- doc-gen4
- import-graph
- name: REPL
url: https://github.com/leanprover-community/repl
toolchain-tag: true
stable-branch: true
branch: master
dependencies:
- Mathlib

View File

@@ -10,7 +10,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 16)
set(LEAN_VERSION_MINOR 19)
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'")
@@ -144,11 +144,12 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# do not import the world from windows.h using appropriately named flag
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D WIN32_LEAN_AND_MEAN")
# DLLs must go next to executables on Windows
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY "bin")
else()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/lean")
set(CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY "lib/lean")
endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/lean")
# OSX default thread stack size is very small. Moreover, in Debug mode, each new stack frame consumes a lot of extra memory.
@@ -295,14 +296,15 @@ index 5e8e0166..f3b29134 100644
PATCH_COMMAND git reset --hard HEAD && printf "${LIBUV_PATCH}" > patch.diff && git apply patch.diff
BUILD_IN_SOURCE ON
INSTALL_COMMAND "")
set(LIBUV_INCLUDE_DIR "${CMAKE_BINARY_DIR}/libuv/src/libuv/include")
set(LIBUV_LIBRARIES "${CMAKE_BINARY_DIR}/libuv/src/libuv/libuv.a")
set(LIBUV_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/libuv/src/libuv/include")
set(LIBUV_LDFLAGS "${CMAKE_BINARY_DIR}/libuv/src/libuv/libuv.a")
else()
find_package(LibUV 1.0.0 REQUIRED)
endif()
include_directories(${LIBUV_INCLUDE_DIR})
include_directories(${LIBUV_INCLUDE_DIRS})
if(NOT LEAN_STANDALONE)
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${LIBUV_LIBRARIES}")
string(JOIN " " LIBUV_LDFLAGS ${LIBUV_LDFLAGS})
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${LIBUV_LDFLAGS}")
endif()
# Windows SDK (for ICU)
@@ -453,20 +455,20 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/lean/libLake.a.export -Wl,--no-whole-archive")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=$ORIGIN/../lib:$ORIGIN/../lib/lean")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec")
string(APPEND INIT_SHARED_LINKER_FLAGS " -install_name @rpath/libInit_shared.dylib")
string(APPEND LEANSHARED_1_LINKER_FLAGS " -install_name @rpath/libleanshared_1.dylib")
string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -install_name @rpath/libLake_shared.dylib")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libLake.a.export -install_name @rpath/libLake_shared.dylib")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libLake_shared.dll.a -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libLake_shared.dll.a -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/lean/libLake.a.export -Wl,--no-whole-archive")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@@ -513,7 +515,16 @@ if(USE_GITHASH)
message(STATUS "git commit sha1: ${GIT_SHA1}")
endif()
else()
set(GIT_SHA1 "")
if(USE_LAKE AND ${STAGE} EQUAL 0)
# we need to embed *some* hash for Lake to invalidate stage 1 on stage 0 changes
execute_process(
COMMAND git ls-tree HEAD "${CMAKE_CURRENT_SOURCE_DIR}/../../stage0" --object-only
OUTPUT_VARIABLE GIT_SHA1
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "stage0 sha1: ${GIT_SHA1}")
else()
set(GIT_SHA1 "")
endif()
endif()
configure_file("${LEAN_SOURCE_DIR}/githash.h.in" "${LEAN_BINARY_DIR}/githash.h")
@@ -540,6 +551,9 @@ include_directories(${LEAN_SOURCE_DIR})
include_directories(${CMAKE_BINARY_DIR}) # version.h etc., "private" headers
include_directories(${CMAKE_BINARY_DIR}/include) # config.h etc., "public" headers
# Lean code only needs this one include
string(APPEND LEANC_OPTS " -I${CMAKE_BINARY_DIR}/include")
# Use CMake profile C++ flags for building Lean libraries, but do not embed in `leanc`
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
string(APPEND LEANC_OPTS " ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
@@ -698,12 +712,12 @@ else()
endif()
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
add_custom_target(lake_lib ALL
add_custom_target(lake_lib
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS leanshared
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Lake
VERBATIM)
add_custom_target(lake_shared ALL
add_custom_target(lake_shared
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS lake_lib
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make libLake_shared
@@ -752,7 +766,12 @@ add_custom_target(clean-olean
DEPENDS clean-stdlib)
install(DIRECTORY "${CMAKE_BINARY_DIR}/lib/" DESTINATION lib
PATTERN temp EXCLUDE)
PATTERN temp
PATTERN "*.export"
PATTERN "*.hash"
PATTERN "*.trace"
PATTERN "*.rsp"
EXCLUDE)
# symlink source into expected installation location for go-to-definition, if file system allows it
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/src)
@@ -783,10 +802,32 @@ if(LEAN_INSTALL_PREFIX)
endif()
# Escape for `make`. Yes, twice.
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
string(REPLACE "$" "\\\$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE "${CMAKE_EXE_LINKER_FLAGS_MAKE}")
configure_file(${LEAN_SOURCE_DIR}/stdlib.make.in ${CMAKE_BINARY_DIR}/stdlib.make)
# hacky
function(toml_escape IN OUTVAR)
if(IN)
string(STRIP "${IN}" OUT)
string(REPLACE " " "\", \"" OUT "${OUT}")
set(${OUTVAR} "\"${OUT}\"" PARENT_SCOPE)
endif()
endfunction()
string(REPLACE "ROOT" "${CMAKE_BINARY_DIR}" LEANC_CC "${LEANC_CC}")
string(REPLACE "ROOT" "${CMAKE_BINARY_DIR}" LEANC_INTERNAL_FLAGS "${LEANC_INTERNAL_FLAGS}")
string(REPLACE "ROOT" "${CMAKE_BINARY_DIR}" LEANC_INTERNAL_LINKER_FLAGS "${LEANC_INTERNAL_LINKER_FLAGS}")
set(LEANC_OPTS_TOML "${LEANC_OPTS} ${LEANC_EXTRA_CC_FLAGS} ${LEANC_INTERNAL_FLAGS}")
set(LINK_OPTS_TOML "${LEANC_INTERNAL_LINKER_FLAGS} -L${CMAKE_BINARY_DIR}/lib/lean ${LEAN_EXTRA_LINKER_FLAGS}")
toml_escape("${LEAN_EXTRA_MAKE_OPTS}" LEAN_EXTRA_OPTS_TOML)
toml_escape("${LEANC_OPTS_TOML}" LEANC_OPTS_TOML)
toml_escape("${LINK_OPTS_TOML}" LINK_OPTS_TOML)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(LAKE_LIB_PREFIX "lib")
endif()
if(USE_LAKE AND STAGE EQUAL 1)
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/lakefile.toml)
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/../tests/lakefile.toml)

View File

@@ -37,3 +37,7 @@ import Init.MacroTrace
import Init.Grind
import Init.While
import Init.Syntax
import Init.Internal
import Init.Try
import Init.BinderNameHint
import Init.Task

View File

@@ -0,0 +1,42 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joachim Breitner
-/
prelude
import Init.Prelude
import Init.Tactics
set_option linter.unusedVariables false in
/--
The expression `binderNameHint v binder e` defined to be `e`.
If it is used on the right-hand side of an equation that is used for rewriting by `rw` or `simp`,
and `v` is a local variable, and `binder` is an expression that (after beta-reduction) is a binder
(`fun w => …` or `∀ w, …`), then it will rename `v` to the name used in that binder, and remove
the `binderNameHint`.
A typical use of this gadget would be as follows; the gadget ensures that after rewriting, the local
variable is still `name`, and not `x`:
```
theorem all_eq_not_any_not (l : List α) (p : α → Bool) :
l.all p = !l.any fun x => binderNameHint x p (!p x) := sorry
example (names : List String) : names.all (fun name => "Waldo".isPrefixOf name) = true := by
rw [all_eq_not_any_not]
-- ⊢ (!names.any fun name => !"Waldo".isPrefixOf name) = true
```
If `binder` is not a binder, then the name of `v` attains a macro scope. This only matters when the
resulting term is used in a non-hygienic way, e.g. in termination proofs for well-founded recursion.
This gadget is supported by
* `simp`, `dsimp` and `rw` in the right-hand-side of an equation
* `simp` in the assumptions of congruence rules
It is ineffective in other positions (hyptheses of rewrite rules) or when used by other tactics
(e.g. `apply`).
-/
@[simp ]
def binderNameHint {α : Sort u} {β : Sort v} {γ : Sort w} (v : α) (binder : β) (e : γ) : γ := e

View File

@@ -38,7 +38,8 @@ theorem apply_ite (f : α → β) (P : Prop) [Decidable P] (x y : α) :
apply_dite f P (fun _ => x) (fun _ => 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
@[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] :

View File

@@ -175,7 +175,10 @@ theorem or_iff_not_imp_right : a b ↔ (¬b → a) := Decidable.or_iff_not_i
theorem not_imp_iff_and_not : ¬(a b) a ¬b := Decidable.not_imp_iff_and_not
theorem not_and_iff_or_not_not : ¬(a b) ¬a ¬b := Decidable.not_and_iff_or_not_not
theorem not_and_iff_not_or_not : ¬(a b) ¬a ¬b := Decidable.not_and_iff_not_or_not
@[deprecated not_and_iff_not_or_not (since := "2025-03-18")]
abbrev not_and_iff_or_not_not := @not_and_iff_not_or_not
theorem not_iff : ¬(a b) (¬a b) := Decidable.not_iff
@@ -195,7 +198,7 @@ end Classical
/- Export for Mathlib compat. -/
export Classical (imp_iff_right_iff imp_and_neg_imp_iff and_or_imp not_imp)
/-- Extract an element from a existential statement, using `Classical.choose`. -/
/-- Extract an element from an existential statement, using `Classical.choose`. -/
-- This enables projection notation.
@[reducible] noncomputable def Exists.choose {p : α Prop} (P : a, p a) : α := Classical.choose P

View File

@@ -5,6 +5,7 @@ Author: Leonardo de Moura, Sebastian Ullrich
-/
prelude
import Init.Core
import Init.BinderNameHint
universe u v w
@@ -35,6 +36,12 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
simp [h]
rfl
@[wf_preprocess] theorem forIn_eq_forin' [d : Membership α ρ] [ForIn' m ρ α d] {β} [Monad m]
(x : ρ) (b : β) (f : (a : α) β m (ForInStep β)) :
forIn x b f = forIn' x b (fun x h => binderNameHint x f <| binderNameHint h () <| f x) := by
simp [binderNameHint]
rfl -- very strange why `simp` did not close it
/-- Extract the value from a `ForInStep`, ignoring whether it is `done` or `yield`. -/
def ForInStep.value (x : ForInStep α) : α :=
match x with
@@ -44,12 +51,28 @@ def ForInStep.value (x : ForInStep α) : α :=
@[simp] theorem ForInStep.value_done (b : β) : (ForInStep.done b).value = b := rfl
@[simp] theorem ForInStep.value_yield (b : β) : (ForInStep.yield b).value = b := rfl
/--
Maps a function over a functor, with parameters swapped so that the function comes last.
This function is `Functor.map` with the parameters reversed, typically used via the `<&>` operator.
-/
@[reducible]
def Functor.mapRev {f : Type u Type v} [Functor f] {α β : Type u} : f α (α β) f β :=
fun a f => f <$> a
@[inherit_doc Functor.mapRev]
infixr:100 " <&> " => Functor.mapRev
recommended_spelling "mapRev" for "<&>" in [Functor.mapRev, «term_<&>_»]
/--
Discards the value in a functor, retaining the functor's structure.
Discarding values is especially useful when using `Applicative` functors or `Monad`s to implement
effects, and some operation should be carried out only for its effects. In `do`-notation, statements
whose values are discarded must return `Unit`, and `discard` can be used to explicitly discard their
values.
-/
@[always_inline, inline]
def Functor.discard {f : Type u Type v} {α : Type u} [Functor f] (x : f α) : f PUnit :=
Functor.mapConst PUnit.unit x
@@ -69,7 +92,7 @@ Error recovery and state can interact subtly. For example, the implementation of
-/
-- NB: List instance is in mathlib. Once upstreamed, add
-- * `List`, where `failure` is the empty list and `<|>` concatenates.
class Alternative (f : Type u Type v) extends Applicative f : Type (max (u+1) v) where
class Alternative (f : Type u Type v) : Type (max (u+1) v) extends Applicative f where
/--
Produces an empty collection or recoverable failure. The `<|>` operator collects values or recovers
from failures. See `Alternative` for more details.
@@ -112,6 +135,13 @@ instance : ToBool Bool where
| true => t
| false => f
/--
Converts the result of the monadic action `x` to a `Bool`. If it is `true`, returns it and ignores
`y`; otherwise, runs `y` and returns its result.
This a monadic counterpart to the short-circuiting `||` operator, usually accessed via the `<||>`
operator.
-/
@[macro_inline] def orM {m : Type u Type v} {β : Type u} [Monad m] [ToBool β] (x y : m β) : m β := do
let b x
match toBool b with
@@ -120,6 +150,15 @@ instance : ToBool Bool where
infixr:30 " <||> " => orM
recommended_spelling "orM" for "<||>" in [orM, «term_<||>_»]
/--
Converts the result of the monadic action `x` to a `Bool`. If it is `true`, returns `y`; otherwise,
returns the original result of `x`.
This a monadic counterpart to the short-circuiting `&&` operator, usually accessed via the `<&&>`
operator.
-/
@[macro_inline] def andM {m : Type u Type v} {β : Type u} [Monad m] [ToBool β] (x y : m β) : m β := do
let b x
match toBool b with
@@ -128,6 +167,11 @@ infixr:30 " <||> " => orM
infixr:35 " <&&> " => andM
recommended_spelling "andM" for "<&&>" in [andM, «term_<&&>_»]
/--
Runs a monadic action and returns the negation of its result.
-/
@[macro_inline] def notM {m : Type Type v} [Applicative m] (x : m Bool) : m Bool :=
not <$> x
@@ -243,21 +287,61 @@ Using `control` means that `runInBase` can be used multiple times.
-/
/-- MonadControl is a way of stating that the monad `m` can be 'run inside' the monad `n`.
This is the same as [`MonadBaseControl`](https://hackage.haskell.org/package/monad-control-1.0.3.1/docs/Control-Monad-Trans-Control.html#t:MonadBaseControl) in Haskell.
To learn about `MonadControl`, see the comment above this docstring.
/--
A way to lift a computation from one monad to another while providing the lifted computation with a
means of interpreting computations from the outer monad. This provides a means of lifting
higher-order operations automatically.
Clients should typically use `control` or `controlAt`, which request an instance of `MonadControlT`:
the reflexive, transitive closure of `MonadControl`. New instances should be defined for
`MonadControl` itself.
-/
-- This is the same as
-- [`MonadBaseControl`](https://hackage.haskell.org/package/monad-control-1.0.3.1/docs/Control-Monad-Trans-Control.html#t:MonadBaseControl)
-- in Haskell.
class MonadControl (m : semiOutParam (Type u Type v)) (n : Type u Type w) where
/--
A type that can be used to reconstruct both a returned value and any state used by the outer
monad.
-/
stM : Type u Type u
/--
Lifts an action from the inner monad `m` to the outer monad `n`. The inner monad has access to a
reverse lifting operator that can run an `n` action, returning a value and state together.
-/
liftWith : {α : Type u} (({β : Type u} n β m (stM β)) m α) n α
/--
Lifts a monadic action that returns a state and a value in the inner monad to an action in the
outer monad. The extra state information is used to restore the results of effects from the
reverse lift passed to `liftWith`'s parameter.
-/
restoreM : {α : Type u} m (stM α) n α
/-- Transitive closure of MonadControl. -/
/--
A way to lift a computation from one monad to another while providing the lifted computation with a
means of interpreting computations from the outer monad. This provides a means of lifting
higher-order operations automatically.
Clients should typically use `control` or `controlAt`, which request an instance of `MonadControlT`:
the reflexive, transitive closure of `MonadControl`. New instances should be defined for
`MonadControl` itself.
-/
class MonadControlT (m : Type u Type v) (n : Type u Type w) where
/--
A type that can be used to reconstruct both a returned value and any state used by the outer
monad.
-/
stM : Type u Type u
/--
Lifts an action from the inner monad `m` to the outer monad `n`. The inner monad has access to a
reverse lifting operator that can run an `n` action, returning a value and state together.
-/
liftWith : {α : Type u} (({β : Type u} n β m (stM β)) m α) n α
/--
Lifts a monadic action that returns a state and a value in the inner monad to an action in the
outer monad. The extra state information is used to restore the results of effects from the
reverse lift passed to `liftWith`'s parameter.
-/
restoreM {α : Type u} : stM α n α
export MonadControlT (stM liftWith restoreM)
@@ -273,11 +357,28 @@ instance (m : Type u → Type v) [Pure m] : MonadControlT m m where
liftWith f := f fun x => x
restoreM x := pure x
/--
Lifts an operation from an inner monad to an outer monad, providing it with a reverse lifting
operator that allows outer monad computations to be run in the inner monad. The lifted operation is
required to return extra information that is required in order to reconstruct the reverse lift's
effects in the outer monad; this extra information is determined by `stM`.
This function takes the inner monad as an explicit parameter. Use `control` to infer the monad.
-/
@[always_inline, inline]
def controlAt (m : Type u Type v) {n : Type u Type w} [MonadControlT m n] [Bind n] {α : Type u}
(f : ({β : Type u} n β m (stM m n β)) m (stM m n α)) : n α :=
liftWith f >>= restoreM
/--
Lifts an operation from an inner monad to an outer monad, providing it with a reverse lifting
operator that allows outer monad computations to be run in the inner monad. The lifted operation is
required to return extra information that is required in order to reconstruct the reverse lift's
effects in the outer monad; this extra information is determined by `stM`.
This function takes the inner monad as an implicit parameter. Use `controlAt` to specify it
explicitly.
-/
@[always_inline, inline]
def control {m : Type u Type v} {n : Type u Type w} [MonadControlT m n] [Bind n] {α : Type u}
(f : ({β : Type u} n β m (stM m n β)) m (stM m n α)) : n α :=
@@ -315,3 +416,7 @@ def Bind.bindLeft [Bind m] (f : α → m β) (ma : m α) : m β :=
@[inherit_doc] infixr:55 " >=> " => Bind.kleisliRight
@[inherit_doc] infixr:55 " <=< " => Bind.kleisliLeft
@[inherit_doc] infixr:55 " =<< " => Bind.bindLeft
recommended_spelling "kleisliRight" for ">=>" in [Bind.kleisliRight, «term_>=>_»]
recommended_spelling "kleisliLeft" for "<=<" in [Bind.kleisliLeft, «term_<=<_»]
recommended_spelling "bindLeft" for "=<<" in [Bind.bindLeft, «term_=<<_»]

View File

@@ -13,10 +13,20 @@ import Init.Coe
namespace Except
variable {ε : Type u}
/--
A successful computation in the `Except ε` monad: `a` is returned, and no exception is thrown.
-/
@[always_inline, inline]
protected def pure (a : α) : Except ε α :=
Except.ok a
/--
Transforms a successful result with a function, doing nothing when an exception is thrown.
Examples:
* `(pure 2 : Except String Nat).map toString = pure 2`
* `(throw "Error" : Except String Nat).map toString = throw "Error"`
-/
@[always_inline, inline]
protected def map (f : α β) : Except ε α Except ε β
| Except.error err => Except.error err
@@ -27,36 +37,78 @@ protected def map (f : α → β) : Except ε α → Except ε β
intro e
simp [Except.map]; cases e <;> rfl
/--
Transforms exceptions with a function, doing nothing on successful results.
Examples:
* `(pure 2 : Except String Nat).mapError (·.length) = pure 2`
* `(throw "Error" : Except String Nat).mapError (·.length) = throw 5`
-/
@[always_inline, inline]
protected def mapError (f : ε ε') : Except ε α Except ε' α
| Except.error err => Except.error <| f err
| Except.ok v => Except.ok v
/--
Sequences two operations that may throw exceptions, allowing the second to depend on the value
returned by the first.
If the first operation throws an exception, then it is the result of the computation. If the first
succeeds but the second throws an exception, then that exception is the result. If both succeed,
then the result is the result of the second computation.
This is the implementation of the `>>=` operator for `Except ε`.
-/
@[always_inline, inline]
protected def bind (ma : Except ε α) (f : α Except ε β) : Except ε β :=
match ma with
| Except.error err => Except.error err
| Except.ok v => f v
/-- Returns true if the value is `Except.ok`, false otherwise. -/
/-- Returns `true` if the value is `Except.ok`, `false` otherwise. -/
@[always_inline, inline]
protected def toBool : Except ε α Bool
| Except.ok _ => true
| Except.error _ => false
@[inherit_doc Except.toBool]
abbrev isOk : Except ε α Bool := Except.toBool
/--
Returns `none` if an exception was thrown, or `some` around the value on success.
Examples:
* `(pure 10 : Except String Nat).toOption = some 10`
* `(throw "Failure" : Except String Nat).toOption = none`
-/
@[always_inline, inline]
protected def toOption : Except ε α Option α
| Except.ok a => some a
| Except.error _ => none
/--
Handles exceptions thrown in the `Except ε` monad.
If `ma` is successful, its result is returned. If it throws an exception, then `handle` is invoked
on the exception's value.
Examples:
* `(pure 2 : Except String Nat).tryCatch (pure ·.length) = pure 2`
* `(throw "Error" : Except String Nat).tryCatch (pure ·.length) = pure 5`
* `(throw "Error" : Except String Nat).tryCatch (fun x => throw ("E: " ++ x)) = throw "E: Error"`
-/
@[always_inline, inline]
protected def tryCatch (ma : Except ε α) (handle : ε Except ε α) : Except ε α :=
match ma with
| Except.ok a => Except.ok a
| Except.error e => handle e
/--
Recovers from exceptions thrown in the `Except ε` monad. Typically used via the `<|>` operator.
`Except.tryCatch` is a related operator that allows the recovery procedure to depend on _which_
exception was thrown.
-/
def orElseLazy (x : Except ε α) (y : Unit Except ε α) : Except ε α :=
match x with
| Except.ok a => Except.ok a
@@ -70,12 +122,26 @@ instance : Monad (Except ε) where
end Except
/--
Adds exceptions of type `ε` to a monad `m`.
-/
def ExceptT (ε : Type u) (m : Type u Type v) (α : Type u) : Type v :=
m (Except ε α)
/--
Use a monadic action that may return an exception's value as an action in the transformed monad that
may throw the corresponding exception.
This is the inverse of `ExceptT.run`.
-/
@[always_inline, inline]
def ExceptT.mk {ε : Type u} {m : Type u Type v} {α : Type u} (x : m (Except ε α)) : ExceptT ε m α := x
/--
Use a monadic action that may throw an exception as an action that may return an exception's value.
This is the inverse of `ExceptT.mk`.
-/
@[always_inline, inline]
def ExceptT.run {ε : Type u} {m : Type u Type v} {α : Type u} (x : ExceptT ε m α) : m (Except ε α) := x
@@ -83,25 +149,41 @@ namespace ExceptT
variable {ε : Type u} {m : Type u Type v} [Monad m]
/--
Returns the value `a` without throwing exceptions or having any other effect.
-/
@[always_inline, inline]
protected def pure {α : Type u} (a : α) : ExceptT ε m α :=
ExceptT.mk <| pure (Except.ok a)
/--
Handles exceptions thrown by an action that can have no effects _other_ than throwing exceptions.
-/
@[always_inline, inline]
protected def bindCont {α β : Type u} (f : α ExceptT ε m β) : Except ε α m (Except ε β)
| Except.ok a => f a
| Except.error e => pure (Except.error e)
/--
Sequences two actions that may throw exceptions. Typically used via `do`-notation or the `>>=`
operator.
-/
@[always_inline, inline]
protected def bind {α β : Type u} (ma : ExceptT ε m α) (f : α ExceptT ε m β) : ExceptT ε m β :=
ExceptT.mk <| ma >>= ExceptT.bindCont f
/--
Transforms a successful computation's value using `f`. Typically used via the `<$>` operator.
-/
@[always_inline, inline]
protected def map {α β : Type u} (f : α β) (x : ExceptT ε m α) : ExceptT ε m β :=
ExceptT.mk <| x >>= fun a => match a with
| (Except.ok a) => pure <| Except.ok (f a)
| (Except.error e) => pure <| Except.error e
/--
Runs a computation from an underlying monad in the transformed monad with exceptions.
-/
@[always_inline, inline]
protected def lift {α : Type u} (t : m α) : ExceptT ε m α :=
ExceptT.mk <| Except.ok <$> t
@@ -110,6 +192,9 @@ protected def lift {α : Type u} (t : m α) : ExceptT ε m α :=
instance : MonadLift (Except ε) (ExceptT ε m) := fun e => ExceptT.mk <| pure e
instance : MonadLift m (ExceptT ε m) := ExceptT.lift
/--
Handles exceptions produced in the `ExceptT ε` transformer.
-/
@[always_inline, inline]
protected def tryCatch {α : Type u} (ma : ExceptT ε m α) (handle : ε ExceptT ε m α) : ExceptT ε m α :=
ExceptT.mk <| ma >>= fun res => match res with
@@ -124,6 +209,11 @@ instance : Monad (ExceptT ε m) where
bind := ExceptT.bind
map := ExceptT.map
/--
Transforms exceptions using the function `f`.
This is the `ExceptT` version of `Except.mapError`.
-/
@[always_inline, inline]
protected def adapt {ε' α : Type u} (f : ε ε') : ExceptT ε m α ExceptT ε' m α := fun x =>
ExceptT.mk <| Except.mapError f <$> x
@@ -150,8 +240,12 @@ instance (ε) : MonadExceptOf ε (Except ε) where
namespace MonadExcept
variable {ε : Type u} {m : Type v Type w}
/-- Alternative orelse operator that allows to select which exception should be used.
The default is to use the first exception since the standard `orelse` uses the second. -/
/--
An alternative unconditional error recovery operator that allows callers to specify which exception
to throw in cases where both operations throw exceptions.
By default, the first is thrown, because the `<|>` operator throws the second.
-/
@[always_inline, inline]
def orelse' [MonadExcept ε m] {α : Type v} (t₁ t₂ : m α) (useFirstEx := true) : m α :=
tryCatch t₁ fun e₁ => tryCatch t₂ fun e₂ => throw (if useFirstEx then e₁ else e₂)
@@ -171,13 +265,24 @@ instance (ε : Type u) (m : Type u → Type v) [Monad m] : MonadControl m (Excep
liftWith f := liftM <| f fun x => x.run
restoreM x := x
/--
Monads that provide the ability to ensure an action happens, regardless of exceptions or other
failures.
`MonadFinally.tryFinally'` is used to desugar `try ... finally ...` syntax.
-/
class MonadFinally (m : Type u Type v) where
/-- `tryFinally' x f` runs `x` and then the "finally" computation `f`.
When `x` succeeds with `a : α`, `f (some a)` is returned. If `x` fails
for `m`'s definition of failure, `f none` is returned. Hence `tryFinally'`
can be thought of as performing the same role as a `finally` block in
an imperative programming language. -/
tryFinally' {α β} : m α (Option α m β) m (α × β)
/--
Runs an action, ensuring that some other action always happens afterward.
More specifically, `tryFinally' x f` runs `x` and then the “finally” computation `f`. If `x`
succeeds with some value `a : α`, `f (some a)` is returned. If `x` fails for `m`'s definition of
failure, `f none` is returned.
`tryFinally'` can be thought of as performing the same role as a `finally` block in an imperative
programming language.
-/
tryFinally' {α β} : (x : m α) (f : Option α m β) m (α × β)
export MonadFinally (tryFinally')

View File

@@ -10,19 +10,37 @@ import Init.Control.Lawful.Basic
The Exception monad transformer using CPS style.
-/
/--
Adds exceptions of type `ε` to a monad `m`.
Instead of using `Except ε` to model exceptions, this implementation uses continuation passing
style. This has different performance characteristics from `ExceptT ε`.
-/
def ExceptCpsT (ε : Type u) (m : Type u Type v) (α : Type u) := (β : Type u) (α m β) (ε m β) m β
namespace ExceptCpsT
/--
Use a monadic action that may throw an exception as an action that may return an exception's value.
-/
@[always_inline, inline]
def run {ε α : Type u} [Monad m] (x : ExceptCpsT ε m α) : m (Except ε α) :=
x _ (fun a => pure (Except.ok a)) (fun e => pure (Except.error e))
set_option linter.unusedVariables false in -- `s` unused
/--
Use a monadic action that may throw an exception by providing explicit success and failure
continuations.
-/
@[always_inline, inline]
def runK {ε α : Type u} (x : ExceptCpsT ε m α) (s : ε) (ok : α m β) (error : ε m β) : m β :=
x _ ok error
/--
Returns the value of a computation, forgetting whether it was an exception or a success.
This corresponds to early return.
-/
@[always_inline, inline]
def runCatch [Monad m] (x : ExceptCpsT α m α) : m α :=
x α pure pure
@@ -40,6 +58,9 @@ instance : MonadExceptOf ε (ExceptCpsT ε m) where
throw e := fun _ _ k => k e
tryCatch x handle := fun _ k₁ k₂ => x _ k₁ (fun e => handle e _ k₁ k₂)
/--
Run an action from the transformed monad in the exception monad.
-/
@[always_inline, inline]
def lift [Monad m] (x : m α) : ExceptCpsT ε m α :=
fun _ k _ => x >>= k

View File

@@ -10,6 +10,28 @@ import Init.Core
universe u
/--
The identity function on types, used primarily for its `Monad` instance.
The identity monad is useful together with monad transformers to construct monads for particular
purposes. Additionally, it can be used with `do`-notation in order to use control structures such as
local mutability, `for`-loops, and early returns in code that does not otherwise use monads.
Examples:
```lean example
def containsFive (xs : List Nat) : Bool := Id.run do
for x in xs do
if x == 5 then return true
return false
```
```lean example
#eval containsFive [1, 3, 5, 7]
```
```output
true
```
-/
def Id (type : Type u) : Type u := type
namespace Id
@@ -20,9 +42,18 @@ instance : Monad Id where
bind x f := f x
map f x := f x
/--
The identity monad has a `bind` operator.
-/
def hasBind : Bind Id :=
inferInstance
/--
Runs a computation in the identity monad.
This function is the identity function. Because its parameter has type `Id α`, it causes
`do`-notation in its arguments to use the `Monad Id` instance.
-/
@[always_inline, inline]
protected def run (x : Id α) : α := x

View File

@@ -6,3 +6,4 @@ Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
prelude
import Init.Control.Lawful.Basic
import Init.Control.Lawful.Instances
import Init.Control.Lawful.Lemmas

View File

@@ -13,17 +13,26 @@ open Function
rfl
/--
The `Functor` typeclass only contains the operations of a functor.
`LawfulFunctor` further asserts that these operations satisfy the laws of a functor,
including the preservation of the identity and composition laws:
```
id <$> x = x
(h ∘ g) <$> x = h <$> g <$> x
```
A functor satisfies the functor laws.
The `Functor` class contains the operations of a functor, but does not require that instances
prove they satisfy the laws of a functor. A `LawfulFunctor` instance includes proofs that the laws
are satisfied. Because `Functor` instances may provide optimized implementations of `mapConst`,
`LawfulFunctor` instances must also prove that the optimized implementation is equivalent to the
standard implementation.
-/
class LawfulFunctor (f : Type u Type v) [Functor f] : Prop where
/--
The `mapConst` implementation is equivalent to the default implementation.
-/
map_const : (Functor.mapConst : α f β f α) = Functor.map const β
/--
The `map` implementation preserves identity.
-/
id_map (x : f α) : id <$> x = x
/--
The `map` implementation preserves function composition.
-/
comp_map (g : α β) (h : β γ) (x : f α) : (h g) <$> x = h <$> g <$> x
export LawfulFunctor (map_const id_map comp_map)
@@ -38,21 +47,48 @@ attribute [simp] id_map
(comp_map _ _ _).symm
/--
The `Applicative` typeclass only contains the operations of an applicative functor.
`LawfulApplicative` further asserts that these operations satisfy the laws of an applicative functor:
```
pure id <*> v = v
pure (·∘·) <*> u <*> v <*> w = u <*> (v <*> w)
pure f <*> pure x = pure (f x)
u <*> pure y = pure (· y) <*> u
```
An applicative functor satisfies the laws of an applicative functor.
The `Applicative` class contains the operations of an applicative functor, but does not require that
instances prove they satisfy the laws of an applicative functor. A `LawfulApplicative` instance
includes proofs that the laws are satisfied.
Because `Applicative` instances may provide optimized implementations of `seqLeft` and `seqRight`,
`LawfulApplicative` instances must also prove that the optimized implementation is equivalent to the
standard implementation.
-/
class LawfulApplicative (f : Type u Type v) [Applicative f] extends LawfulFunctor f : Prop where
class LawfulApplicative (f : Type u Type v) [Applicative f] : Prop extends LawfulFunctor f where
/-- `seqLeft` is equivalent to the default implementation. -/
seqLeft_eq (x : f α) (y : f β) : x <* y = const β <$> x <*> y
/-- `seqRight` is equivalent to the default implementation. -/
seqRight_eq (x : f α) (y : f β) : x *> y = const α id <$> x <*> y
/--
`pure` before `seq` is equivalent to `Functor.map`.
This means that `pure` really is pure when occurring immediately prior to `seq`.
-/
pure_seq (g : α β) (x : f α) : pure g <*> x = g <$> x
/--
Mapping a function over the result of `pure` is equivalent to applying the function under `pure`.
This means that `pure` really is pure with respect to `Functor.map`.
-/
map_pure (g : α β) (x : α) : g <$> (pure x : f α) = pure (g x)
/--
`pure` after `seq` is equivalent to `Functor.map`.
This means that `pure` really is pure when occurring just after `seq`.
-/
seq_pure {α β : Type u} (g : f (α β)) (x : α) : g <*> pure x = (fun h => h x) <$> g
/--
`seq` is associative.
Changing the nesting of `seq` calls while maintaining the order of computations results in an
equivalent computation. This means that `seq` is not doing any more than sequencing.
-/
seq_assoc {α β γ : Type u} (x : f α) (g : f (α β)) (h : f (β γ)) : h <*> (g <*> x) = ((@comp α β γ) <$> h) <*> g <*> x
comp_map g h x := (by
repeat rw [ pure_seq]
@@ -66,21 +102,36 @@ attribute [simp] map_pure seq_pure
simp [pure_seq]
/--
The `Monad` typeclass only contains the operations of a monad.
`LawfulMonad` further asserts that these operations satisfy the laws of a monad,
including associativity and identity laws for `bind`:
```
pure x >>= f = f x
x >>= pure = x
x >>= f >>= g = x >>= (fun x => f x >>= g)
```
Lawful monads are those that satisfy a certain behavioral specification. While all instances of
`Monad` should satisfy these laws, not all implementations are required to prove this.
`LawfulMonad.mk'` is an alternative constructor containing useful defaults for many fields.
`LawfulMonad.mk'` is an alternative constructor that contains useful defaults for many fields.
-/
class LawfulMonad (m : Type u Type v) [Monad m] extends LawfulApplicative m : Prop where
class LawfulMonad (m : Type u Type v) [Monad m] : Prop extends LawfulApplicative m where
/--
A `bind` followed by `pure` composed with a function is equivalent to a functorial map.
This means that `pure` really is pure after a `bind` and has no effects.
-/
bind_pure_comp (f : α β) (x : m α) : x >>= (fun a => pure (f a)) = f <$> x
/--
A `bind` followed by a functorial map is equivalent to `Applicative` sequencing.
This means that the effect sequencing from `Monad` and `Applicative` are the same.
-/
bind_map {α β : Type u} (f : m (α β)) (x : m α) : f >>= (. <$> x) = f <*> x
/--
`pure` followed by `bind` is equivalent to function application.
This means that `pure` really is pure before a `bind` and has no effects.
-/
pure_bind (x : α) (f : α m β) : pure x >>= f = f x
/--
`bind` is associative.
Changing the nesting of `bind` calls while maintaining the order of computations results in an
equivalent computation. This means that `bind` is not doing more than data-dependent sequencing.
-/
bind_assoc (x : m α) (f : α m β) (g : β m γ) : x >>= f >>= g = x >>= fun x => f x >>= g
map_pure g x := (by rw [ bind_pure_comp, pure_bind])
seq_pure g x := (by rw [ bind_map]; simp [map_pure, bind_pure_comp])
@@ -136,6 +187,23 @@ theorem seqLeft_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x <* y
theorem Functor.map_unit [Monad m] [LawfulMonad m] {a : m PUnit} : (fun _ => PUnit.unit) <$> a = a := by
simp [map]
/--
This is just a duplicate of `LawfulApplicative.map_pure`,
but sometimes applies when that doesn't.
It is named with a prime to avoid conflict with the inherited field `LawfulMonad.map_pure`.
-/
@[simp] theorem LawfulMonad.map_pure' [Monad m] [LawfulMonad m] {a : α} :
(f <$> pure a : m β) = pure (f a) := by
simp only [map_pure]
/--
This is just a duplicate of `Functor.map_map`, but sometimes applies when that doesn't.
-/
@[simp] theorem LawfulMonad.map_map {m} [Monad m] [LawfulMonad m] {x : m α} :
g <$> f <$> x = (fun a => g (f a)) <$> x := by
simp only [Functor.map_map]
/--
An alternative constructor for `LawfulMonad` which has more
defaultable fields in the common case.

View File

@@ -0,0 +1,57 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Control.Lawful.Basic
import Init.RCases
import Init.ByCases
-- Mapping by a function with a left inverse is injective.
theorem map_inj_of_left_inverse [Functor m] [LawfulFunctor m] {f : α β}
(w : g : β α, x, g (f x) = x) {x y : m α} :
f <$> x = f <$> y x = y := by
constructor
· intro h
rcases w with g, w
replace h := congrArg (g <$> ·) h
simpa [w] using h
· rintro rfl
rfl
-- Mapping by an injective function is injective, as long as the domain is nonempty.
@[simp] theorem map_inj_right_of_nonempty [Functor m] [LawfulFunctor m] [Nonempty α] {f : α β}
(w : {x y}, f x = f y x = y) {x y : m α} :
f <$> x = f <$> y x = y := by
constructor
· intro h
apply (map_inj_of_left_inverse ?_).mp h
let a := Nonempty α
refine ?_, ?_
· intro b
by_cases p : a, f a = b
· exact Exists.choose p
· exact a
· intro b
simp only [exists_apply_eq_apply, reduceDIte]
apply w
apply Exists.choose_spec (p := fun a => f a = f b)
· rintro rfl
rfl
@[simp] theorem map_inj_right [Monad m] [LawfulMonad m]
{f : α β} (h : {x y : α}, f x = f y x = y) {x y : m α} :
f <$> x = f <$> y x = y := by
by_cases hempty : Nonempty α
· exact map_inj_right_of_nonempty h
· constructor
· intro h'
have (z : m α) : z = (do let a z; let b pure (f a); x) := by
conv => lhs; rw [ bind_pure z]
congr; funext a
exact (hempty a).elim
rw [this x, this y]
rw [ bind_assoc, map_eq_pure_bind, h', map_eq_pure_bind, bind_assoc]
· intro h'
rw [h']

View File

@@ -8,13 +8,22 @@ import Init.Data.Option.Basic
import Init.Control.Basic
import Init.Control.Except
set_option linter.missingDocs true
universe u v
instance : ToBool (Option α) := Option.isSome
/--
Adds the ability to fail to a monad. Unlike ordinary exceptions, there is no way to signal why a
failure occurred.
-/
def OptionT (m : Type u Type v) (α : Type u) : Type v :=
m (Option α)
/--
Executes an action that might fail in the underlying monad `m`, returning `none` in case of failure.
-/
@[always_inline, inline]
def OptionT.run {m : Type u Type v} {α : Type u} (x : OptionT m α) : m (Option α) :=
x
@@ -22,15 +31,25 @@ def OptionT.run {m : Type u → Type v} {α : Type u} (x : OptionT m α) : m (Op
namespace OptionT
variable {m : Type u Type v} [Monad m] {α β : Type u}
/--
Converts an action that returns an `Option` into one that might fail, with `none` indicating
failure.
-/
protected def mk (x : m (Option α)) : OptionT m α :=
x
/--
Sequences two potentially-failing actions. The second action is run only if the first succeeds.
-/
@[always_inline, inline]
protected def bind (x : OptionT m α) (f : α OptionT m β) : OptionT m β := OptionT.mk do
match ( x) with
| some a => f a
| none => pure none
/--
Succeeds with the provided value.
-/
@[always_inline, inline]
protected def pure (a : α) : OptionT m α := OptionT.mk do
pure (some a)
@@ -40,11 +59,17 @@ instance : Monad (OptionT m) where
pure := OptionT.pure
bind := OptionT.bind
/--
Recovers from failures. Typically used via the `<|>` operator.
-/
@[always_inline, inline] protected def orElse (x : OptionT m α) (y : Unit OptionT m α) : OptionT m α := OptionT.mk do
match ( x) with
| some a => pure (some a)
| _ => y ()
/--
A recoverable failure.
-/
@[always_inline, inline] protected def fail : OptionT m α := OptionT.mk do
pure none
@@ -52,6 +77,12 @@ instance : Alternative (OptionT m) where
failure := OptionT.fail
orElse := OptionT.orElse
/--
Converts a computation from the underlying monad into one that could fail, even though it does not.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline] protected def lift (x : m α) : OptionT m α := OptionT.mk do
return some ( x)
@@ -59,6 +90,9 @@ instance : MonadLift m (OptionT m) := ⟨OptionT.lift⟩
instance : MonadFunctor m (OptionT m) := fun f x => f x
/--
Handles failures by treating them as exceptions of type `Unit`.
-/
@[always_inline, inline] protected def tryCatch (x : OptionT m α) (handle : Unit OptionT m α) : OptionT m α := OptionT.mk do
let some a x | handle ()
pure a

View File

@@ -10,12 +10,21 @@ import Init.Control.Basic
import Init.Control.Id
import Init.Control.Except
set_option linter.missingDocs true
namespace ReaderT
/--
Recovers from errors. The same local value is provided to both branches. Typically used via the
`<|>` operator.
-/
@[always_inline, inline]
protected def orElse [Alternative m] (x₁ : ReaderT ρ m α) (x₂ : Unit ReaderT ρ m α) : ReaderT ρ m α :=
fun s => x₁ s <|> x₂ () s
/--
Fails with a recoverable error.
-/
@[always_inline, inline]
protected def failure [Alternative m] : ReaderT ρ m α :=
fun _ => failure
@@ -35,4 +44,8 @@ instance : MonadControl m (ReaderT ρ m) where
instance ReaderT.tryFinally [MonadFinally m] : MonadFinally (ReaderT ρ m) where
tryFinally' x h ctx := tryFinally' (x ctx) (fun a? => h a? ctx)
/--
A monad with access to a read-only value of type `ρ`. The value can be locally overridden by
`withReader`, but it cannot be mutated.
-/
@[reducible] def ReaderM (ρ : Type u) := ReaderT ρ Id

View File

@@ -9,19 +9,42 @@ prelude
import Init.Control.Basic
import Init.Control.Id
import Init.Control.Except
set_option linter.missingDocs true
universe u v w
/--
Adds a mutable state of type `σ` to a monad.
Actions in the resulting monad are functions that take an initial state and return, in `m`, a tuple
of a value and a state.
-/
def StateT (σ : Type u) (m : Type u Type v) (α : Type u) : Type (max u v) :=
σ m (α × σ)
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value paired with the final state.
-/
@[always_inline, inline]
def StateT.run {σ : Type u} {m : Type u Type v} {α : Type u} (x : StateT σ m α) (s : σ) : m (α × σ) :=
x s
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value, discarding the final state.
-/
@[always_inline, inline]
def StateT.run' {σ : Type u} {m : Type u Type v} [Functor m] {α : Type u} (x : StateT σ m α) (s : σ) : m α :=
(·.1) <$> x s
/--
A tuple-based state monad.
Actions in `StateM σ` are functions that take an initial state and return a value paired with a
final state.
-/
@[reducible]
def StateM (σ α : Type u) : Type u := StateT σ Id α
@@ -38,14 +61,23 @@ section
variable {σ : Type u} {m : Type u Type v}
variable [Monad m] {α β : Type u}
/--
Returns the given value without modifying the state. Typically used via `Pure.pure`.
-/
@[always_inline, inline]
protected def pure (a : α) : StateT σ m α :=
fun s => pure (a, s)
/--
Sequences two actions. Typically used via the `>>=` operator.
-/
@[always_inline, inline]
protected def bind (x : StateT σ m α) (f : α StateT σ m β) : StateT σ m β :=
fun s => do let (a, s) x s; f a s
/--
Modifies the value returned by a computation. Typically used via the `<$>` operator.
-/
@[always_inline, inline]
protected def map (f : α β) (x : StateT σ m α) : StateT σ m β :=
fun s => do let (a, s) x s; pure (f a, s)
@@ -56,10 +88,17 @@ instance : Monad (StateT σ m) where
bind := StateT.bind
map := StateT.map
/--
Recovers from errors. The state is rolled back on error recovery. Typically used via the `<|>`
operator.
-/
@[always_inline, inline]
protected def orElse [Alternative m] {α : Type u} (x₁ : StateT σ m α) (x₂ : Unit StateT σ m α) : StateT σ m α :=
fun s => x₁ s <|> x₂ () s
/--
Fails with a recoverable error. The state is rolled back on error recovery.
-/
@[always_inline, inline]
protected def failure [Alternative m] {α : Type u} : StateT σ m α :=
fun _ => failure
@@ -68,18 +107,40 @@ instance [Alternative m] : Alternative (StateT σ m) where
failure := StateT.failure
orElse := StateT.orElse
/--
Retrieves the current value of the monad's mutable state.
This increments the reference count of the state, which may inhibit in-place updates.
-/
@[always_inline, inline]
protected def get : StateT σ m σ :=
fun s => pure (s, s)
/--
Replaces the mutable state with a new value.
-/
@[always_inline, inline]
protected def set : σ StateT σ m PUnit :=
fun s' _ => pure (, s')
/--
Applies a function to the current state that both computes a new state and a value. The new state
replaces the current state, and the value is returned.
It is equivalent to `do let (a, s) := f (← StateT.get); StateT.set s; pure a`. However, using
`StateT.modifyGet` may lead to better performance because it doesn't add a new reference to the
state value, and additional references can inhibit in-place updates of data.
-/
@[always_inline, inline]
protected def modifyGet (f : σ α × σ) : StateT σ m α :=
fun s => pure (f s)
/--
Runs an action from the underlying monad in the monad with state. The state is not modified.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline]
protected def lift {α : Type u} (t : m α) : StateT σ m α :=
fun s => do let a t; pure (a, s)

View File

@@ -6,24 +6,45 @@ Authors: Leonardo de Moura
prelude
import Init.Control.Lawful.Basic
set_option linter.missingDocs true
/-!
The State monad transformer using CPS style.
-/
/--
An alternative implementation of a state monad transformer that internally uses continuation passing
style instead of tuples.
-/
def StateCpsT (σ : Type u) (m : Type u Type v) (α : Type u) := (δ : Type u) σ (α σ m δ) m δ
namespace StateCpsT
variable {α σ : Type u} {m : Type u Type v}
/--
Runs a stateful computation that's represented using continuation passing style by providing it with
an initial state and a continuation.
-/
@[always_inline, inline]
def runK (x : StateCpsT σ m α) (s : σ) (k : α σ m β) : m β :=
x _ s k
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value paired with the final state.
While the state is internally represented in continuation passing style, the resulting value is the
same as for a non-CPS state monad.
-/
@[always_inline, inline]
def run [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
runK x s (fun a s => pure (a, s))
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value, discarding the final state.
-/
@[always_inline, inline]
def run' [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
runK x s (fun a _ => pure a)
@@ -43,6 +64,12 @@ instance : MonadStateOf σ (StateCpsT σ m) where
set s := fun _ _ k => k s
modifyGet f := fun _ s k => let (a, s) := f s; k a s
/--
Runs an action from the underlying monad in the monad with state. The state is not modified.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline]
protected def lift [Monad m] (x : m α) : StateCpsT σ m α :=
fun _ s k => x >>= (k . s)

View File

@@ -8,10 +8,23 @@ The State monad transformer using IO references.
prelude
import Init.System.ST
set_option linter.missingDocs true
/--
A state monad that uses an actual mutable reference cell (i.e. an `ST.Ref ω σ`).
The macro `StateRefT σ m α` infers `ω` from `m`. It should normally be used instead.
-/
def StateRefT' (ω : Type) (σ : Type) (m : Type Type) (α : Type) : Type := ReaderT (ST.Ref ω σ) m α
/-! Recall that `StateRefT` is a macro that infers `ω` from the `m`. -/
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value paired with the final state.
The monad `m` must support `ST` effects in order to create and mutate reference cells.
-/
@[always_inline, inline]
def StateRefT'.run {ω σ : Type} {m : Type Type} [Monad m] [MonadLiftT (ST ω) m] {α : Type} (x : StateRefT' ω σ m α) (s : σ) : m (α × σ) := do
let ref ST.mkRef s
@@ -19,6 +32,12 @@ def StateRefT'.run {ω σ : Type} {m : Type → Type} [Monad m] [MonadLiftT (ST
let s ref.get
pure (a, s)
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value, discarding the final state.
The monad `m` must support `ST` effects in order to create and mutate reference cells.
-/
@[always_inline, inline]
def StateRefT'.run' {ω σ : Type} {m : Type Type} [Monad m] [MonadLiftT (ST ω) m] {α : Type} (x : StateRefT' ω σ m α) (s : σ) : m α := do
let (a, _) x.run s
@@ -27,6 +46,12 @@ def StateRefT'.run' {ω σ : Type} {m : Type → Type} [Monad m] [MonadLiftT (ST
namespace StateRefT'
variable {ω σ : Type} {m : Type Type} {α : Type}
/--
Runs an action from the underlying monad in the monad with state. The state is not modified.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline]
protected def lift (x : m α) : StateRefT' ω σ m α :=
fun _ => x
@@ -36,14 +61,30 @@ instance : MonadLift m (StateRefT' ω σ m) := ⟨StateRefT'.lift⟩
instance (σ m) : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
instance [Alternative m] [Monad m] : Alternative (StateRefT' ω σ m) := inferInstanceAs (Alternative (ReaderT _ _))
/--
Retrieves the current value of the monad's mutable state.
This increments the reference count of the state, which may inhibit in-place updates.
-/
@[inline]
protected def get [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
fun ref => ref.get
/--
Replaces the mutable state with a new value.
-/
@[inline]
protected def set [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
fun ref => ref.set s
/--
Applies a function to the current state that both computes a new state and a value. The new state
replaces the current state, and the value is returned.
It is equivalent to a `get` followed by a `set`. However, using `modifyGet` may lead to higher
performance because it doesn't add a new reference to the state value. Additional references can
inhibit in-place updates of data.
-/
@[inline]
protected def modifyGet [MonadLiftT (ST ω) m] (f : σ α × σ) : StateRefT' ω σ m α :=
fun ref => ref.modifyGet f

View File

@@ -150,6 +150,10 @@ See the `simp` tactic for more information. -/
syntax (name := simp) "simp" optConfig (discharger)? (&" only")?
(" [" withoutPosition((simpStar <|> simpErase <|> simpLemma),*) "]")? : conv
/-- `simp?` takes the same arguments as `simp`, but reports an equivalent call to `simp only`
that would be sufficient to close the goal. See the `simp?` tactic for more information. -/
syntax (name := simpTrace) "simp?" optConfig (discharger)? (&" only")? (simpArgs)? : conv
/--
`dsimp` is the definitional simplifier in `conv`-mode. It differs from `simp` in that it only
applies theorems that hold by reflexivity.
@@ -167,6 +171,9 @@ example (a : Nat): (0 + 0) = a - a := by
syntax (name := dsimp) "dsimp" optConfig (discharger)? (&" only")?
(" [" withoutPosition((simpErase <|> simpLemma),*) "]")? : conv
@[inherit_doc simpTrace]
syntax (name := dsimpTrace) "dsimp?" optConfig (&" only")? (dsimpArgs)? : conv
/-- `simp_match` simplifies match expressions. For example,
```
match [a, b] with

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,7 @@ class EvalInformation (α : Sort u) (β : Sort v) where
evalVar : α Nat β
def Context.var (ctx : Context α) (idx : Nat) : Variable ctx.op :=
ctx.vars.getD idx ctx.arbitrary, none
ctx.vars[idx]?.getD ctx.arbitrary, none
instance : ContextInformation (Context α) where
isNeutral ctx x := ctx.var x |>.neutral.isSome

View File

@@ -23,3 +23,8 @@ import Init.Data.Array.FinRange
import Init.Data.Array.Perm
import Init.Data.Array.Find
import Init.Data.Array.Lex
import Init.Data.Array.Range
import Init.Data.Array.Erase
import Init.Data.Array.Zip
import Init.Data.Array.InsertIdx
import Init.Data.Array.Extract

View File

@@ -6,20 +6,23 @@ Authors: Joachim Breitner, Mario Carneiro
prelude
import Init.Data.Array.Mem
import Init.Data.Array.Lemmas
import Init.Data.Array.Count
import Init.Data.List.Attach
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/--
`O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
but is defined only when all members of `l` satisfy `P`, using the proof
to apply `f`.
Maps a partially defined function (defined on those terms of `α` that satisfy a predicate `P`) over
an array `xs : Array α`, given a proof that every element of `xs` in fact satisfies `P`.
We replace this at runtime with a more efficient version via the `csimp` lemma `pmap_eq_pmapImpl`.
`Array.pmap`, named for “partial map,” is the equivalent of `Array.map` for such partial functions.
-/
def pmap {P : α Prop} (f : a, P a β) (l : Array α) (H : a l, P a) : Array β :=
(l.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
def pmap {P : α Prop} (f : a, P a β) (xs : Array α) (H : a xs, P a) : Array β :=
(xs.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
/--
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
@@ -28,14 +31,27 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
@[inline] private unsafe def attachWithImpl
(xs : Array α) (P : α Prop) (_ : x xs, P x) : Array {x // P x} := unsafeCast xs
/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array
with the same elements but in the type `{x // P x}`. -/
/--
“Attaches” individual proofs to an array of values that satisfy a predicate `P`, returning an array
of elements in the corresponding subtype `{ x // P x }`.
`O(1)`.
-/
@[implemented_by attachWithImpl] def attachWith
(xs : Array α) (P : α Prop) (H : x xs, P x) : Array {x // P x} :=
xs.toList.attachWith P fun x h => H x (Array.Mem.mk h)
/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array
with the same elements but in the type `{x // x ∈ xs}`. -/
/--
“Attaches” the proof that the elements of `xs` are in fact elements of `xs`, producing a new array with
the same elements but in the subtype `{ x // x ∈ xs }`.
`O(1)`.
This function is primarily used to allow definitions by [well-founded
recursion](lean-manual://section/well-founded-recursion) that use higher-order functions (such as
`Array.map`) to prove that an value taken from a list is smaller than the list. This allows the
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} :
@@ -50,35 +66,35 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
simp [pmap]
@[simp] theorem toList_attachWith {l : Array α} {P : α Prop} {H : x l, P x} :
(l.attachWith P H).toList = l.toList.attachWith P (by simpa [mem_toList] using H) := by
@[simp] theorem toList_attachWith {xs : Array α} {P : α Prop} {H : x xs, P x} :
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList] using H) := by
simp [attachWith]
@[simp] theorem toList_attach {α : Type _} {l : Array α} :
l.attach.toList = l.toList.attachWith (· l) (by simp [mem_toList]) := by
@[simp] theorem toList_attach {xs : Array α} :
xs.attach.toList = xs.toList.attachWith (· xs) (by simp [mem_toList]) := by
simp [attach]
@[simp] theorem toList_pmap {l : Array α} {P : α Prop} {f : a, P a β} {H : a l, P a} :
(l.pmap f H).toList = l.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
@[simp] theorem toList_pmap {xs : Array α} {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 (mem_def.mpr m)) := by
simp [pmap]
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
@[inline] private def pmapImpl {P : α Prop} (f : a, P a β) (l : Array α) (H : a l, P a) :
Array β := (l.attachWith _ H).map fun x, h' => f x h'
@[inline] private def pmapImpl {P : α Prop} (f : a, P a β) (xs : Array α) (H : a xs, P a) :
Array β := (xs.attachWith _ H).map fun x, h' => f x h'
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
funext α β p f L h'
cases L
simp only [pmap, pmapImpl, List.attachWith_toArray, List.map_toArray, mk.injEq, List.map_attachWith]
funext α β p f xs H
cases xs
simp only [pmap, pmapImpl, List.attachWith_toArray, List.map_toArray, mk.injEq, List.map_attachWith_eq_pmap]
apply List.pmap_congr_left
intro a m h₁ h₂
congr
@[simp] theorem pmap_empty {P : α Prop} (f : a, P a β) : pmap f #[] (by simp) = #[] := rfl
@[simp] theorem pmap_push {P : α Prop} (f : a, P a β) (a : α) (l : Array α) (h : b l.push a, P b) :
pmap f (l.push a) h =
(pmap f l (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
@[simp] theorem pmap_push {P : α Prop} (f : a, P a β) (a : α) (xs : Array α) (h : b xs.push a, P b) :
pmap f (xs.push a) h =
(pmap f xs (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
simp [pmap]
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
@@ -93,147 +109,158 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
simp
@[simp]
theorem pmap_eq_map (p : α Prop) (f : α β) (l : Array α) (H) :
@pmap _ _ p (fun a _ => f a) l H = map f l := by
cases l; simp
theorem pmap_eq_map (p : α Prop) (f : α β) (xs : Array α) (H) :
@pmap _ _ p (fun a _ => f a) xs H = map f xs := by
cases xs; simp
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (l : Array α) {H₁ H₂}
(h : a l, (h₁ h₂), f a h₁ = g a h₂) : pmap f l H₁ = pmap g l H₂ := by
cases l
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (xs : Array α) {H₁ H₂}
(h : a xs, (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
cases xs
simp only [mem_toArray] at h
simp only [List.pmap_toArray, mk.injEq]
rw [List.pmap_congr_left _ h]
theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (l H) :
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
cases l
theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (xs H) :
map g (pmap f xs H) = pmap (fun a h => g (f a h)) xs H := by
cases xs
simp [List.map_pmap]
theorem pmap_map {p : β Prop} (g : b, p b γ) (f : α β) (l H) :
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun _ h => H _ (mem_map_of_mem _ h) := by
cases l
theorem pmap_map {p : β Prop} (g : b, p b γ) (f : α β) (xs H) :
pmap g (map f xs) H = pmap (fun a h => g (f a) h) xs fun _ h => H _ (mem_map_of_mem _ h) := by
cases xs
simp [List.pmap_map]
theorem attach_congr {l₁ l₂ : Array α} (h : l₁ = l₂) :
l₁.attach = l₂.attach.map (fun x => x.1, h x.2) := by
theorem attach_congr {xs ys : Array α} (h : xs = ys) :
xs.attach = ys.attach.map (fun x => x.1, h x.2) := by
subst h
simp
theorem attachWith_congr {l₁ l₂ : Array α} (w : l₁ = l₂) {P : α Prop} {H : x l₁, P x} :
l₁.attachWith P H = l₂.attachWith P fun _ h => H _ (w h) := by
theorem attachWith_congr {xs ys : Array α} (w : xs = ys) {P : α Prop} {H : x xs, P x} :
xs.attachWith P H = ys.attachWith P fun _ h => H _ (w h) := by
subst w
simp
@[simp] theorem attach_push {a : α} {l : Array α} :
(l.push a).attach =
(l.attach.map (fun x, h => x, mem_push_of_mem a h)).push a, by simp := by
cases l
@[simp] theorem attach_push {a : α} {xs : Array α} :
(xs.push a).attach =
(xs.attach.map (fun x, h => x, mem_push_of_mem a h)).push a, by simp := by
cases xs
rw [attach_congr (List.push_toArray _ _)]
simp [Function.comp_def]
@[simp] theorem attachWith_push {a : α} {l : Array α} {P : α Prop} {H : x l.push a, P x} :
(l.push a).attachWith P H =
(l.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push a, H a (by simp) := by
cases l
@[simp] theorem attachWith_push {a : α} {xs : Array α} {P : α Prop} {H : x xs.push a, P x} :
(xs.push a).attachWith P H =
(xs.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push a, H a (by simp) := by
cases xs
simp [attachWith_congr (List.push_toArray _ _)]
theorem pmap_eq_map_attach {p : α Prop} (f : a, p a β) (l H) :
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
cases l
theorem pmap_eq_map_attach {p : α Prop} (f : a, p a β) (xs H) :
pmap f xs H = xs.attach.map fun x => f x.1 (H _ x.2) := by
cases xs
simp [List.pmap_eq_map_attach]
theorem attach_map_coe (l : Array α) (f : α β) :
(l.attach.map fun (i : {i // i l}) => f i) = l.map f := by
cases l
simp [List.attach_map_coe]
@[simp]
theorem pmap_eq_attachWith {p q : α Prop} (f : a, p a q a) (xs H) :
pmap (fun a h => a, f a h) xs H = xs.attachWith q (fun x h => f x (H x h)) := by
cases xs
simp [List.pmap_eq_attachWith]
theorem attach_map_val (l : Array α) (f : α β) : (l.attach.map fun i => f i.val) = l.map f :=
attach_map_coe _ _
theorem attach_map_val (xs : Array α) (f : α β) :
(xs.attach.map fun (i : {i // i xs}) => f i) = xs.map f := by
cases xs
simp
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
cases l; simp
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
theorem attachWith_map_coe {p : α Prop} (f : α β) (l : Array α) (H : a l, p a) :
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
cases l; simp
theorem attach_map_subtype_val (xs : Array α) : xs.attach.map Subtype.val = xs := by
cases xs; simp
theorem attachWith_map_val {p : α Prop} (f : α β) (l : Array α) (H : a l, p a) :
((l.attachWith p H).map fun i => f i.val) = l.map f :=
attachWith_map_coe _ _ _
theorem attachWith_map_val {p : α Prop} (f : α β) (xs : Array α) (H : a xs, p a) :
((xs.attachWith p H).map fun (i : { i // p i}) => f i) = xs.map f := by
cases xs; simp
theorem attachWith_map_subtype_val {p : α Prop} (l : Array α) (H : a l, p a) :
(l.attachWith p H).map Subtype.val = l := by
cases l; simp
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
theorem attachWith_map_subtype_val {p : α Prop} (xs : Array α) (H : a xs, p a) :
(xs.attachWith p H).map Subtype.val = xs := by
cases xs; simp
@[simp]
theorem mem_attach (l : Array α) : x, x l.attach
theorem mem_attach (xs : Array α) : x, x xs.attach
| a, h => by
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
rcases this with _, _, m, rfl
exact m
@[simp]
theorem mem_pmap {p : α Prop} {f : a, p a β} {l H b} :
b pmap f l H (a : _) (h : a l), f a (H a h) = b := by
theorem mem_attachWith (xs : Array α) {q : α Prop} (H) (x : {x // q x}) :
x xs.attachWith q H x.1 xs := by
cases xs
simp
@[simp]
theorem mem_pmap {p : α Prop} {f : a, p a β} {xs H b} :
b pmap f xs H (a : _) (h : a xs), f a (H a h) = b := by
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {l H} {a} (h : a l) :
f a (H a h) pmap f l H := by
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {xs H} {a} (h : a xs) :
f a (H a h) pmap f xs H := by
rw [mem_pmap]
exact a, h, rfl
@[simp]
theorem size_pmap {p : α Prop} {f : a, p a β} {l H} : (pmap f l H).size = l.size := by
cases l; simp
theorem size_pmap {p : α Prop} {f : a, p a β} {xs H} : (pmap f xs H).size = xs.size := by
cases xs; simp
@[simp]
theorem size_attach {L : Array α} : L.attach.size = L.size := by
cases L; simp
theorem size_attach {xs : Array α} : xs.attach.size = xs.size := by
cases xs; simp
@[simp]
theorem size_attachWith {p : α Prop} {l : Array α} {H} : (l.attachWith p H).size = l.size := by
cases l; simp
theorem size_attachWith {p : α Prop} {xs : Array α} {H} : (xs.attachWith p H).size = xs.size := by
cases xs; simp
@[simp]
theorem pmap_eq_empty_iff {p : α Prop} {f : a, p a β} {l H} : pmap f l H = #[] l = #[] := by
cases l; simp
theorem pmap_eq_empty_iff {p : α Prop} {f : a, p a β} {xs H} : pmap f xs H = #[] xs = #[] := by
cases xs; simp
theorem pmap_ne_empty_iff {P : α Prop} (f : (a : α) P a β) {xs : Array α}
(H : (a : α), a xs P a) : xs.pmap f H #[] xs #[] := by
cases xs; simp
theorem pmap_eq_self {l : Array α} {p : α Prop} {hp : (a : α), a l p a}
{f : (a : α) p a α} : l.pmap f hp = l a (h : a l), f a (hp a h) = a := by
cases l; simp [List.pmap_eq_self]
theorem pmap_eq_self {xs : Array α} {p : α Prop} {hp : (a : α), a xs p a}
{f : (a : α) p a α} : xs.pmap f hp = xs a (h : a xs), f a (hp a h) = a := by
cases xs; simp [List.pmap_eq_self]
@[simp]
theorem attach_eq_empty_iff {l : Array α} : l.attach = #[] l = #[] := by
cases l; simp
theorem attach_eq_empty_iff {xs : Array α} : xs.attach = #[] xs = #[] := by
cases xs; simp
theorem attach_ne_empty_iff {l : Array α} : l.attach #[] l #[] := by
cases l; simp
theorem attach_ne_empty_iff {xs : Array α} : xs.attach #[] xs #[] := by
cases xs; simp
@[simp]
theorem attachWith_eq_empty_iff {l : Array α} {P : α Prop} {H : a l, P a} :
l.attachWith P H = #[] l = #[] := by
cases l; simp
theorem attachWith_eq_empty_iff {xs : Array α} {P : α Prop} {H : a xs, P a} :
xs.attachWith P H = #[] xs = #[] := by
cases xs; simp
theorem attachWith_ne_empty_iff {l : Array α} {P : α Prop} {H : a l, P a} :
l.attachWith P H #[] l #[] := by
cases l; simp
theorem attachWith_ne_empty_iff {xs : Array α} {P : α Prop} {H : a xs, P a} :
xs.attachWith P H #[] xs #[] := by
cases xs; simp
@[simp]
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {l : Array α} (h : a l, p a) (n : Nat) :
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
cases l; simp
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {xs : Array α} (h : a xs, p a) (i : Nat) :
(pmap f xs h)[i]? = Option.pmap f xs[i]? fun x H => h x (mem_of_getElem? H) := by
cases xs; simp
@[simp]
theorem getElem_pmap {p : α Prop} (f : a, p a β) {l : Array α} (h : a l, p a) {n : Nat}
(hn : n < (pmap f l h).size) :
(pmap f l h)[n] =
f (l[n]'(@size_pmap _ _ p f l h hn))
(h _ (getElem_mem (@size_pmap _ _ p f l h hn))) := by
cases l; simp
theorem getElem_pmap {p : α Prop} (f : a, p a β) {xs : Array α} (h : a xs, p a) {i : Nat}
(hi : i < (pmap f xs h).size) :
(pmap f xs h)[i] =
f (xs[i]'(@size_pmap _ _ p f xs h hi))
(h _ (getElem_mem (@size_pmap _ _ p f xs h hi))) := by
cases xs; simp
@[simp]
theorem getElem?_attachWith {xs : Array α} {i : Nat} {P : α Prop} {H : a xs, P a} :
@@ -256,16 +283,42 @@ theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
xs.attach[i] = xs[i]'(by simpa using h), getElem_mem (by simpa using h) :=
getElem_attachWith h
theorem foldl_pmap (l : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a l P a) (g : γ β γ) (x : γ) :
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
@[simp] theorem pmap_attach (xs : Array α) {p : {x // x xs} Prop} (f : a, p a β) (H) :
pmap f xs.attach H =
xs.pmap (P := fun a => h : a xs, p a, h)
(fun a h => f a, h.1 h.2) (fun a h => h, H a, h (by simp)) := by
ext <;> simp
@[simp] theorem pmap_attachWith (xs : Array α) {p : {x // q x} Prop} (f : a, p a β) (H₁ H₂) :
pmap f (xs.attachWith q H₁) H₂ =
xs.pmap (P := fun a => h : q a, p a, h)
(fun a h => f a, h.1 h.2) (fun a h => H₁ _ h, H₂ a, H₁ _ h (by simpa)) := by
ext <;> simp
theorem foldl_pmap (xs : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a xs P a) (g : γ β γ) (x : γ) :
(xs.pmap f H).foldl g x = xs.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
rw [pmap_eq_map_attach, foldl_map]
theorem foldr_pmap (l : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a l P a) (g : β γ γ) (x : γ) :
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
theorem foldr_pmap (xs : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a xs P a) (g : β γ γ) (x : γ) :
(xs.pmap f H).foldr g x = xs.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
rw [pmap_eq_map_attach, foldr_map]
@[simp] theorem foldl_attachWith
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : β { x // q x} β} {b} (w : stop = xs.size) :
(xs.attachWith q H).foldl f b 0 stop = xs.attach.foldl (fun b a, h => f b a, H _ h) b := by
subst w
rcases xs with xs
simp [List.foldl_attachWith, List.foldl_map]
@[simp] theorem foldr_attachWith
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : { x // q x} β β} {b} (w : start = xs.size) :
(xs.attachWith q H).foldr f b start 0 = xs.attach.foldr (fun a acc => f a.1, H _ a.2 acc) b := by
subst w
rcases xs with xs
simp [List.foldr_attachWith, List.foldr_map]
/--
If we fold over `l.attach` with a function that ignores the membership predicate,
we get the same results as folding over `l` directly.
@@ -276,10 +329,10 @@ Unfortunately this can't be applied by `simp` because of the higher order unific
and even when rewriting we need to specify the function explicitly.
See however `foldl_subtype` below.
-/
theorem foldl_attach (l : Array α) (f : β α β) (b : β) :
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
rcases l with l
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.map_attach, size_toArray,
theorem foldl_attach (xs : Array α) (f : β α β) (b : β) :
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
congr
ext
@@ -295,81 +348,101 @@ Unfortunately this can't be applied by `simp` because of the higher order unific
and even when rewriting we need to specify the function explicitly.
See however `foldr_subtype` below.
-/
theorem foldr_attach (l : Array α) (f : α β β) (b : β) :
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
rcases l with l
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.map_attach, size_toArray,
theorem foldr_attach (xs : Array α) (f : α β β) (b : β) :
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.length_pmap, List.foldr_toArray', mem_toArray, List.foldr_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
theorem attach_map {l : Array α} (f : α β) :
(l.map f).attach = l.attach.map (fun x, h => f x, mem_map_of_mem f h) := by
cases l
theorem attach_map {xs : Array α} (f : α β) :
(xs.map f).attach = xs.attach.map (fun x, h => f x, mem_map_of_mem f h) := by
cases xs
ext <;> simp
theorem attachWith_map {l : Array α} (f : α β) {P : β Prop} {H : (b : β), b l.map f P b} :
(l.map f).attachWith P H = (l.attachWith (P f) (fun _ h => H _ (mem_map_of_mem f h))).map
theorem attachWith_map {xs : Array α} (f : α β) {P : β Prop} {H : (b : β), b xs.map f P b} :
(xs.map f).attachWith P H = (xs.attachWith (P f) (fun _ h => H _ (mem_map_of_mem f h))).map
fun x, h => f x, h := by
cases l
ext
· simp
· simp only [List.map_toArray, List.attachWith_toArray, List.getElem_toArray,
List.getElem_attachWith, List.getElem_map, Function.comp_apply]
erw [List.getElem_attachWith] -- Why is `erw` needed here?
cases xs
simp [List.attachWith_map]
theorem map_attachWith {l : Array α} {P : α Prop} {H : (a : α), a l P a}
@[simp] theorem map_attachWith {xs : Array α} {P : α Prop} {H : (a : α), a xs P a}
(f : { x // P x } β) :
(l.attachWith P H).map f =
l.pmap (fun a (h : a l P a) => f a, H _ h.1) (fun a h => h, H a h) := by
cases l
(xs.attachWith P H).map f = xs.attach.map fun x, h => f x, H _ h := by
cases xs <;> simp_all
theorem map_attachWith_eq_pmap {xs : Array α} {P : α Prop} {H : (a : α), a xs P a}
(f : { x // P x } β) :
(xs.attachWith P H).map f =
xs.pmap (fun a (h : a xs P a) => f a, H _ h.1) (fun a h => h, H a h) := by
cases xs
ext <;> simp
/-- See also `pmap_eq_map_attach` for writing `pmap` in terms of `map` and `attach`. -/
theorem map_attach {l : Array α} (f : { x // x l } β) :
l.attach.map f = l.pmap (fun a h => f a, h) (fun _ => id) := by
cases l
theorem map_attach_eq_pmap {xs : Array α} (f : { x // x xs } β) :
xs.attach.map f = xs.pmap (fun a h => f a, h) (fun _ => id) := by
cases xs
ext <;> simp
theorem attach_filterMap {l : Array α} {f : α Option β} :
(l.filterMap f).attach = l.attach.filterMap
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
abbrev map_attach := @map_attach_eq_pmap
theorem attach_filterMap {xs : Array α} {f : α Option β} :
(xs.filterMap f).attach = xs.attach.filterMap
fun x, h => (f x).pbind (fun b m => some b, mem_filterMap.mpr x, h, m) := by
cases l
cases xs
rw [attach_congr (List.filterMap_toArray f _)]
simp [List.attach_filterMap, List.map_filterMap, Function.comp_def]
theorem attach_filter {l : Array α} (p : α Bool) :
(l.filter p).attach = l.attach.filterMap
theorem attach_filter {xs : Array α} (p : α Bool) :
(xs.filter p).attach = xs.attach.filterMap
fun x => if w : p x.1 then some x.1, mem_filter.mpr x.2, w else none := by
cases l
cases xs
rw [attach_congr (List.filter_toArray p _)]
simp [List.attach_filter, List.map_filterMap, Function.comp_def]
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
-- Also missing are `filterMap_attach`, `filter_attach`, `filterMap_attachWith` and `filter_attachWith`.
theorem pmap_pmap {p : α Prop} {q : β Prop} (g : a, p a β) (f : b, q b γ) (l H₁ H₂) :
pmap f (pmap g l H₁) H₂ =
pmap (α := { x // x l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
@[simp]
theorem filterMap_attachWith {q : α Prop} {xs : Array α} {f : {x // q x} Option β} (H)
(w : stop = (xs.attachWith q H).size) :
(xs.attachWith q H).filterMap f 0 stop = xs.attach.filterMap (fun x, h => f x, H _ h) := by
subst w
cases xs
simp [Function.comp_def]
@[simp]
theorem filter_attachWith {q : α Prop} {xs : Array α} {p : {x // q x} Bool} (H)
(w : stop = (xs.attachWith q H).size) :
(xs.attachWith q H).filter p 0 stop =
(xs.attach.filter (fun x, h => p x, H _ h)).map (fun x, h => x, H _ h) := by
subst w
cases xs
simp [Function.comp_def, List.filter_map]
theorem pmap_pmap {p : α Prop} {q : β Prop} (g : a, p a β) (f : b, q b γ) (xs H₁ H₂) :
pmap f (pmap g xs H₁) H₂ =
pmap (α := { x // x xs }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) xs.attach
(fun a _ => H₁ a a.2) := by
cases l
cases xs
simp [List.pmap_pmap, List.pmap_map]
@[simp] theorem pmap_append {p : ι Prop} (f : a : ι, p a α) (l₁ l₂ : Array ι)
(h : a l₁ ++ l₂, p a) :
(l₁ ++ l₂).pmap f h =
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
l₂.pmap f fun a ha => h a (mem_append_right l₁ ha) := by
cases l₁
cases l₂
@[simp] theorem pmap_append {p : ι Prop} (f : a : ι, p a α) (xs ys : Array ι)
(h : a xs ++ ys, p a) :
(xs ++ ys).pmap f h =
(xs.pmap f fun a ha => h a (mem_append_left ys ha)) ++
ys.pmap f fun a ha => h a (mem_append_right xs ha) := by
cases xs
cases ys
simp
theorem pmap_append' {p : α Prop} (f : a : α, p a β) (l₁ l₂ : Array α)
(h₁ : a l₁, p a) (h₂ : a l₂, p a) :
((l₁ ++ l₂).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
pmap_append f l₁ l₂ _
theorem pmap_append' {p : α Prop} (f : a : α, p a β) (xs ys : Array α)
(h₁ : a xs, p a) (h₂ : a ys, p a) :
((xs ++ ys).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
xs.pmap f h₁ ++ ys.pmap f h₂ :=
pmap_append f xs ys _
@[simp] theorem attach_append (xs ys : Array α) :
(xs ++ ys).attach = xs.attach.map (fun x, h => x, mem_append_left ys h) ++
@@ -427,16 +500,48 @@ theorem reverse_attach (xs : Array α) :
@[simp] theorem back?_attachWith {P : α Prop} {xs : Array α}
{H : (a : α), a xs P a} :
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some a, H _ (mem_of_back?_eq_some h)) := by
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some a, H _ (mem_of_back? h)) := by
cases xs
simp
@[simp]
theorem back?_attach {xs : Array α} :
xs.attach.back? = xs.back?.pbind fun a h => some a, mem_of_back?_eq_some h := by
xs.attach.back? = xs.back?.pbind fun a h => some a, mem_of_back? h := by
cases xs
simp
@[simp]
theorem countP_attach (xs : Array α) (p : α Bool) :
xs.attach.countP (fun a : {x // x xs} => p a) = xs.countP p := by
cases xs
simp [Function.comp_def]
@[simp]
theorem countP_attachWith {p : α Prop} (xs : Array α) (H : a xs, p a) (q : α Bool) :
(xs.attachWith p H).countP (fun a : {x // p x} => q a) = xs.countP q := by
cases xs
simp
@[simp]
theorem count_attach [DecidableEq α] (xs : Array α) (a : {x // x xs}) :
xs.attach.count a = xs.count a := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.count_toArray]
rw [List.map_attach_eq_pmap, List.count_eq_countP]
simp only [Subtype.beq_iff]
rw [List.countP_pmap, List.countP_attach (p := (fun x => x == a.1)), List.count]
@[simp]
theorem count_attachWith [DecidableEq α] {p : α Prop} (xs : Array α) (H : a xs, p a) (a : {x // p x}) :
(xs.attachWith p H).count a = xs.count a := by
cases xs
simp
@[simp] theorem countP_pmap {p : α Prop} (g : a, p a β) (f : β Bool) (xs : Array α) (H₁) :
(xs.pmap g H₁).countP f =
xs.attach.countP (fun a, m => f (g a (H₁ a m))) := by
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
/-! ## unattach
`Array.unattach` is the (one-sided) inverse of `Array.attach`. It is a synonym for `Array.map Subtype.val`.
@@ -449,49 +554,63 @@ Further, we provide simp lemmas that push `unattach` inwards.
-/
/--
A synonym for `l.map (·.val)`. Mostly this should not be needed by users.
It is introduced as in intermediate step by lemmas such as `map_subtype`,
and is ideally subsequently simplified away by `unattach_attach`.
Maps an array of terms in a subtype to the corresponding terms in the type by forgetting that they
satisfy the predicate.
If not, usually the right approach is `simp [Array.unattach, -Array.map_subtype]` to unfold.
This is the inverse of `Array.attachWith` and a synonym for `xs.map (·.val)`.
Mostly this should not be needed by users. It is introduced as an intermediate step by lemmas such
as `map_subtype`, and is ideally subsequently simplified away by `unattach_attach`.
This function is usually inserted automatically by Lean as an intermediate step while proving
termination. It is rarely used explicitly in code. It is introduced as an intermediate step during
the elaboration of definitions by [well-founded
recursion](lean-manual://section/well-founded-recursion). If this function is encountered in a proof
state, the right approach is usually the tactic `simp [Array.unattach, -Array.map_subtype]`.
-/
def unattach {α : Type _} {p : α Prop} (l : Array { x // p x }) := l.map (·.val)
def unattach {α : Type _} {p : α Prop} (xs : Array { x // p x }) : Array α := xs.map (·.val)
@[simp] theorem unattach_nil {p : α Prop} : (#[] : Array { x // p x }).unattach = #[] := rfl
@[simp] theorem unattach_push {p : α Prop} {a : { x // p x }} {l : Array { x // p x }} :
(l.push a).unattach = l.unattach.push a.1 := by
@[simp] theorem unattach_nil {p : α Prop} : (#[] : Array { x // p x }).unattach = #[] := by
simp [unattach]
@[simp] theorem unattach_push {p : α Prop} {a : { x // p x }} {xs : Array { x // p x }} :
(xs.push a).unattach = xs.unattach.push a.1 := by
simp only [unattach, Array.map_push]
@[simp] theorem size_unattach {p : α Prop} {l : Array { x // p x }} :
l.unattach.size = l.size := by
@[simp] theorem mem_unattach {p : α Prop} {xs : Array { x // p x }} {a} :
a xs.unattach h : p a, a, h xs := by
simp only [unattach, mem_map, Subtype.exists, exists_and_right, exists_eq_right]
@[simp] theorem size_unattach {p : α Prop} {xs : Array { x // p x }} :
xs.unattach.size = xs.size := by
unfold unattach
simp
@[simp] theorem _root_.List.unattach_toArray {p : α Prop} {l : List { x // p x }} :
l.toArray.unattach = l.unattach.toArray := by
@[simp] 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]
@[simp] theorem toList_unattach {p : α Prop} {l : Array { x // p x }} :
l.unattach.toList = l.toList.unattach := by
@[simp] theorem toList_unattach {p : α Prop} {xs : Array { x // p x }} :
xs.unattach.toList = xs.toList.unattach := by
simp only [unattach, toList_map, List.unattach]
@[simp] theorem unattach_attach {l : Array α} : l.attach.unattach = l := by
cases l
@[simp] theorem unattach_attach {xs : Array α} : xs.attach.unattach = xs := by
cases xs
simp only [List.attach_toArray, List.unattach_toArray, List.unattach_attachWith]
@[simp] theorem unattach_attachWith {p : α Prop} {l : Array α}
{H : a l, p a} :
(l.attachWith p H).unattach = l := by
cases l
@[simp] theorem unattach_attachWith {p : α Prop} {xs : Array α}
{H : a xs, p a} :
(xs.attachWith p H).unattach = xs := by
cases xs
simp
@[simp] theorem getElem?_unattach {p : α Prop} {l : Array { x // p x }} (i : Nat) :
l.unattach[i]? = l[i]?.map Subtype.val := by
@[simp] theorem getElem?_unattach {p : α Prop} {xs : Array { x // p x }} (i : Nat) :
xs.unattach[i]? = xs[i]?.map Subtype.val := by
simp [unattach]
@[simp] theorem getElem_unattach
{p : α Prop} {l : Array { x // p x }} (i : Nat) (h : i < l.unattach.size) :
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
{p : α Prop} {xs : Array { x // p x }} (i : Nat) (h : i < xs.unattach.size) :
xs.unattach[i] = (xs[i]'(by simpa using h)).1 := by
simp [unattach]
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
@@ -500,20 +619,20 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
theorem foldl_subtype {p : α Prop} {l : Array { x // p x }}
theorem foldl_subtype {p : α Prop} {xs : Array { x // p x }}
{f : β { x // p x } β} {g : β α β} {x : β}
{hf : b x h, f b x, h = g b x} :
l.foldl f x = l.unattach.foldl g x := by
cases l
(hf : b x h, f b x, h = g b x) :
xs.foldl f x = xs.unattach.foldl g x := by
cases xs
simp only [List.foldl_toArray', List.unattach_toArray]
rw [List.foldl_subtype] -- Why can't simp do this?
simp [hf]
/-- Variant of `foldl_subtype` with side condition to check `stop = l.size`. -/
@[simp] theorem foldl_subtype' {p : α Prop} {l : Array { x // p x }}
@[simp] theorem foldl_subtype' {p : α Prop} {xs : Array { x // p x }}
{f : β { x // p x } β} {g : β α β} {x : β}
{hf : b x h, f b x, h = g b x} (h : stop = l.size) :
l.foldl f x 0 stop = l.unattach.foldl g x := by
(hf : b x h, f b x, h = g b x) (h : stop = xs.size) :
xs.foldl f x 0 stop = xs.unattach.foldl g x := by
subst h
rwa [foldl_subtype]
@@ -521,20 +640,20 @@ theorem foldl_subtype {p : α → Prop} {l : Array { x // p x }}
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
theorem foldr_subtype {p : α Prop} {l : Array { x // p x }}
theorem foldr_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β β} {g : α β β} {x : β}
{hf : x h b, f x, h b = g x b} :
l.foldr f x = l.unattach.foldr g x := by
cases l
(hf : x h b, f x, h b = g x b) :
xs.foldr f x = xs.unattach.foldr g x := by
cases xs
simp only [List.foldr_toArray', List.unattach_toArray]
rw [List.foldr_subtype]
simp [hf]
/-- Variant of `foldr_subtype` with side condition to check `stop = l.size`. -/
@[simp] theorem foldr_subtype' {p : α Prop} {l : Array { x // p x }}
@[simp] theorem foldr_subtype' {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β β} {g : α β β} {x : β}
{hf : x h b, f x, h b = g x b} (h : start = l.size) :
l.foldr f x start 0 = l.unattach.foldr g x := by
(hf : x h b, f x, h b = g x b) (h : start = xs.size) :
xs.foldr f x start 0 = xs.unattach.foldr g x := by
subst h
rwa [foldr_subtype]
@@ -542,40 +661,156 @@ theorem foldr_subtype {p : α → Prop} {l : Array { x // p x }}
This lemma identifies maps over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem map_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } β} {g : α β} {hf : x h, f x, h = g x} :
l.map f = l.unattach.map g := by
cases l
@[simp] theorem map_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β} {g : α β} (hf : x h, f x, h = g x) :
xs.map f = xs.unattach.map g := by
cases xs
simp only [List.map_toArray, List.unattach_toArray]
rw [List.map_subtype]
simp [hf]
@[simp] theorem filterMap_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} {hf : x h, f x, h = g x} :
l.filterMap f = l.unattach.filterMap g := by
cases l
simp only [size_toArray, List.filterMap_toArray', List.unattach_toArray, List.length_unattach,
@[simp] theorem filterMap_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
xs.filterMap f = xs.unattach.filterMap g := by
cases xs
simp only [List.size_toArray, List.filterMap_toArray', List.unattach_toArray, List.length_unattach,
mk.injEq]
rw [List.filterMap_subtype]
simp [hf]
@[simp] theorem unattach_filter {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} {hf : x h, f x, h = g x} :
(l.filter f).unattach = l.unattach.filter g := by
cases l
@[simp] theorem flatMap_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Array β} {g : α Array β} (hf : x h, f x, h = g x) :
(xs.flatMap f) = xs.unattach.flatMap g := by
cases xs
simp only [List.size_toArray, List.flatMap_toArray, List.unattach_toArray, List.length_unattach,
mk.injEq]
rw [List.flatMap_subtype]
simp [hf]
@[simp] theorem findSome?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
xs.findSome? f = xs.unattach.findSome? g := by
cases xs
simp
rw [List.findSome?_subtype hf]
@[simp] theorem find?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(xs.find? f).map Subtype.val = xs.unattach.find? g := by
cases xs
simp
rw [List.find?_subtype hf]
@[simp] theorem all_subtype {p : α Prop} {xs : Array { x // p x }} {f : { x // p x } Bool} {g : α Bool}
(hf : x h, f x, h = g x) (w : stop = xs.size) :
xs.all f 0 stop = xs.unattach.all g := by
subst w
rcases xs with xs
simp [hf]
@[simp] theorem any_subtype {p : α Prop} {xs : Array { x // p x }} {f : { x // p x } Bool} {g : α Bool}
(hf : x h, f x, h = g x) (w : stop = xs.size) :
xs.any f 0 stop = xs.unattach.any g := by
subst w
rcases xs with xs
simp [hf]
/-! ### Simp lemmas pushing `unattach` inwards. -/
@[simp] theorem unattach_reverse {p : α Prop} {l : Array { x // p x }} :
l.reverse.unattach = l.unattach.reverse := by
cases l
@[simp] theorem unattach_filter {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(xs.filter f).unattach = xs.unattach.filter g := by
cases xs
simp [hf]
@[simp] theorem unattach_reverse {p : α Prop} {xs : Array { x // p x }} :
xs.reverse.unattach = xs.unattach.reverse := by
cases xs
simp
@[simp] theorem unattach_append {p : α Prop} {l l : Array { x // p x }} :
(l ++ l).unattach = l.unattach ++ l.unattach := by
cases l
cases l
@[simp] theorem unattach_append {p : α Prop} {xs xs : Array { x // p x }} :
(xs ++ xs).unattach = xs.unattach ++ xs.unattach := by
cases xs
cases xs
simp
@[simp] theorem unattach_flatten {p : α Prop} {xs : Array (Array { x // p x })} :
xs.flatten.unattach = (xs.map unattach).flatten := by
unfold unattach
cases xs using array₂_induction
simp only [flatten_toArray, List.map_map, Function.comp_def, List.map_id_fun', id_eq,
List.map_toArray, List.map_flatten, map_subtype, map_id_fun', List.unattach_toArray, mk.injEq]
simp only [List.unattach]
@[simp] theorem unattach_replicate {p : α Prop} {n : Nat} {x : { x // p x }} :
(Array.replicate n x).unattach = Array.replicate n x.1 := by
simp [unattach]
@[deprecated unattach_replicate (since := "2025-03-18")]
abbrev unattach_mkArray := @unattach_replicate
/-! ### Well-founded recursion preprocessing setup -/
@[wf_preprocess] theorem Array.map_wfParam (xs : Array α) (f : α β) :
(wfParam xs).map f = xs.attach.unattach.map f := by
simp [wfParam]
@[wf_preprocess] theorem Array.map_unattach (P : α Prop) (xs : Array (Subtype P)) (f : α β) :
xs.unattach.map f = xs.map fun x, h =>
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[wf_preprocess] theorem foldl_wfParam (xs : Array α) (f : β α β) (x : β) :
(wfParam xs).foldl f x = xs.attach.unattach.foldl f x := by
simp [wfParam]
@[wf_preprocess] theorem foldl_unattach (P : α Prop) (xs : Array (Subtype P)) (f : β α β) (x : β):
xs.unattach.foldl f x = xs.foldl (fun s x, h =>
binderNameHint s f <| binderNameHint x (f s) <| binderNameHint h () <| f s (wfParam x)) x := by
simp [wfParam]
@[wf_preprocess] theorem foldr_wfParam (xs : Array α) (f : α β β) (x : β) :
(wfParam xs).foldr f x = xs.attach.unattach.foldr f x := by
simp [wfParam]
@[wf_preprocess] theorem foldr_unattach (P : α Prop) (xs : Array (Subtype P)) (f : α β β) (x : β):
xs.unattach.foldr f x = xs.foldr (fun x, h s =>
binderNameHint x f <| binderNameHint s (f x) <| binderNameHint h () <| f (wfParam x) s) x := by
simp [wfParam]
@[wf_preprocess] theorem filter_wfParam (xs : Array α) (f : α Bool) :
(wfParam xs).filter f = xs.attach.unattach.filter f:= by
simp [wfParam]
@[wf_preprocess] theorem filter_unattach (P : α Prop) (xs : Array (Subtype P)) (f : α Bool) :
xs.unattach.filter f = (xs.filter (fun x, h =>
binderNameHint x f <| binderNameHint h () <| f (wfParam x))).unattach := by
simp [wfParam]
@[wf_preprocess] theorem reverse_wfParam (xs : Array α) :
(wfParam xs).reverse = xs.attach.unattach.reverse := by simp [wfParam]
@[wf_preprocess] theorem reverse_unattach (P : α Prop) (xs : Array (Subtype P)) :
xs.unattach.reverse = xs.reverse.unattach := by simp
@[wf_preprocess] theorem filterMap_wfParam (xs : Array α) (f : α Option β) :
(wfParam xs).filterMap f = xs.attach.unattach.filterMap f := by
simp [wfParam]
@[wf_preprocess] theorem filterMap_unattach (P : α Prop) (xs : Array (Subtype P)) (f : α Option β) :
xs.unattach.filterMap f = xs.filterMap fun x, h =>
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[wf_preprocess] theorem flatMap_wfParam (xs : Array α) (f : α Array β) :
(wfParam xs).flatMap f = xs.attach.unattach.flatMap f := by
simp [wfParam]
@[wf_preprocess] theorem flatMap_unattach (P : α Prop) (xs : Array (Subtype P)) (f : α Array β) :
xs.unattach.flatMap f = xs.flatMap fun x, h =>
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
end Array

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,9 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Linear
import Init.NotationExtra
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : as = bs a = b := by
simp only [push, mk.injEq] at h
have h₁, h₂ := List.of_concat_eq_concat h
@@ -17,13 +20,13 @@ theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : a
private theorem List.size_toArrayAux (as : List α) (bs : Array α) : (as.toArrayAux bs).size = as.length + bs.size := by
induction as generalizing bs with
| nil => simp [toArrayAux]
| cons a as ih => simp_arith [toArrayAux, *]
| cons a as ih => simp +arith [toArrayAux, *]
private theorem List.of_toArrayAux_eq_toArrayAux {as bs : List α} {cs ds : Array α} (h : as.toArrayAux cs = bs.toArrayAux ds) (hlen : cs.size = ds.size) : as = bs cs = ds := by
match as, bs with
| [], [] => simp [toArrayAux] at h; simp [h]
| a::as, [] => simp [toArrayAux] at h; rw [ h] at hlen; simp_arith [size_toArrayAux] at hlen
| [], b::bs => simp [toArrayAux] at h; rw [h] at hlen; simp_arith [size_toArrayAux] at hlen
| a::as, [] => simp [toArrayAux] at h; rw [ h] at hlen; simp +arith [size_toArrayAux] at hlen
| [], b::bs => simp [toArrayAux] at h; rw [h] at hlen; simp +arith [size_toArrayAux] at hlen
| a::as, b::bs =>
simp [toArrayAux] at h
have : (cs.push a).size = (ds.push b).size := by simp [*]
@@ -35,6 +38,11 @@ private theorem List.of_toArrayAux_eq_toArrayAux {as bs : List α} {cs ds : Arra
theorem List.toArray_eq_toArray_eq (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) := by
simp
/--
Applies the monadic action `f` to every element in the array, left-to-right, and returns the array
of results. Furthermore, the resulting array's type guarantees that it contains the same number of
elements as the input array.
-/
def Array.mapM' [Monad m] (f : α m β) (as : Array α) : m { bs : Array β // bs.size = as.size } :=
go 0 mkEmpty as.size, rfl (by simp)
where
@@ -63,11 +71,19 @@ where
return as
/--
Monomorphic `Array.mapM`. The internal implementation uses pointer equality, and does not allocate a new array
if the result of each `f a` is a pointer equal value `a`.
Applies a monadic function to each element of an array, returning the array of results. The function is
monomorphic: it is required to return a value of the same type. The internal implementation uses
pointer equality, and does not allocate a new array if the result of each function call is
pointer-equal to its argument.
-/
@[implemented_by mapMonoMImp] def Array.mapMonoM [Monad m] (as : Array α) (f : α m α) : m (Array α) :=
as.mapM f
/--
Applies a function to each element of an array, returning the array of results. The function is
monomorphic: it is required to return a value of the same type. The internal implementation uses
pointer equality, and does not allocate a new array if the result of each function call is
pointer-equal to its argument.
-/
@[inline] def Array.mapMono (as : Array α) (f : α α) : Array α :=
Id.run <| as.mapMonoM f

View File

@@ -5,9 +5,13 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic
import Init.Data.Int.DivMod.Lemmas
import Init.Omega
universe u v
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- We do not use `linter.indexVariables` here as it is helpful to name the index variables as `lo`, `mid`, and `hi`.
namespace Array
@[specialize] def binSearchAux {α : Type u} {β : Type v} (lt : α α Bool) (found : Option α β) (as : Array α) (k : α) :
@@ -25,6 +29,16 @@ namespace Array
else found (some a)
termination_by lo hi => hi.1 - lo.1
/--
Binary search for an element equivalent to `k` in the sorted array `as`. Returns the element from
the array, if it is found, or `none` otherwise.
The array `as` must be sorted according to the comparison operator `lt`, which should be a total
order.
The optional parameters `lo` and `hi` determine the region of the array indices to be searched. Both
are inclusive, and default to searching the entire array.
-/
@[inline] def binSearch {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo := 0) (hi := as.size - 1) : Option α :=
if h : lo < as.size then
let hi := if hi < as.size then hi else as.size - 1
@@ -35,6 +49,16 @@ termination_by lo hi => hi.1 - lo.1
else
none
/--
Binary search for an element equivalent to `k` in the sorted array `as`. Returns `true` if the
element is found, or `false` otherwise.
The array `as` must be sorted according to the comparison operator `lt`, which should be a total
order.
The optional parameters `lo` and `hi` determine the region of the array indices to be searched. Both
are inclusive, and default to searching the entire array.
-/
@[inline] def binSearchContains {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo := 0) (hi := as.size - 1) : Bool :=
if h : lo < as.size then
let hi := if hi < as.size then hi else as.size - 1
@@ -64,6 +88,16 @@ termination_by lo hi => hi.1 - lo.1
as.modifyM mid <| fun v => merge v
termination_by lo hi => hi.1 - lo.1
/--
Inserts an element `k` into a sorted array `as` such that the resulting array is sorted.
The ordering predicate `lt` should be a total order on elements, and the array `as` should be sorted
with respect to `lt`.
If an element that `lt` equates to `k` is already present in `as`, then `merge` is applied to the
existing element to determine the value of that position in the resulting array. If no element equal
to `k` is present, then `add` is used to determine the value to be inserted.
-/
@[specialize] def binInsertM {α : Type u} {m : Type u Type v} [Monad m]
(lt : α α Bool)
(merge : α m α)
@@ -77,6 +111,21 @@ termination_by lo hi => hi.1 - lo.1
else if !lt k as[as.size - 1] then as.modifyM (as.size - 1) <| merge
else binInsertAux lt merge add as k 0, by omega as.size - 1, by omega (by simp) (by simpa using h')
/--
Inserts an element into a sorted array such that the resulting array is sorted. If the element is
already present in the array, it is not inserted.
The ordering predicate `lt` should be a total order on elements, and the array `as` should be sorted
with respect to `lt`.
`Array.binInsertM` is a more general operator that provides greater control over the handling of
duplicate elements in addition to running in a monad.
Examples:
* `#[0, 1, 3, 5].binInsert (· < ·) 2 = #[0, 1, 2, 3, 5]`
* `#[0, 1, 3, 5].binInsert (· < ·) 1 = #[0, 1, 3, 5]`
* `#[].binInsert (· < ·) 1 = #[1]`
-/
@[inline] def binInsert {α : Type u} (lt : α α Bool) (as : Array α) (k : α) : Array α :=
Id.run <| binInsertM lt (fun _ => k) (fun _ => k) as k

View File

@@ -13,116 +13,151 @@ import Init.Data.List.TakeDrop
This file contains some theorems about `Array` and `List` needed for `Init.Data.List.Impl`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/--
Use the indexing notation `a[i]` instead.
Access an element from an array without needing a runtime bounds checks,
using a `Nat` index and a proof that it is in bounds.
This function does not use `get_elem_tactic` to automatically find the proof that
the index is in bounds. This is because the tactic itself needs to look up values in
arrays.
-/
@[deprecated "Use indexing notation `as[i]` instead" (since := "2025-02-17")]
def get {α : Type u} (a : @& Array α) (i : @& Nat) (h : LT.lt i a.size) : α :=
a.toList.get i, h
/--
Use the indexing notation `a[i]!` instead.
Access an element from an array, or panic if the index is out of bounds.
-/
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17")]
def get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α :=
Array.getD a i default
theorem foldlM_toList.aux [Monad m]
(f : β α m β) (arr : Array α) (i j) (H : arr.size i + j) (b) :
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.toList.drop j).foldlM f b := by
(f : β α m β) (xs : Array α) (i j) (H : xs.size i + j) (b) :
foldlM.loop f xs xs.size (Nat.le_refl _) i j b = (xs.toList.drop j).foldlM f b := by
unfold foldlM.loop
split; split
· cases Nat.not_le_of_gt _ (Nat.zero_add _ H)
· rename_i i; rw [Nat.succ_add] at H
simp [foldlM_toList.aux f arr i (j+1) H]
simp [foldlM_toList.aux f xs i (j+1) H]
rw (occs := [2]) [ List.getElem_cons_drop_succ_eq_drop _]
rfl
· rw [List.drop_of_length_le (Nat.ge_of_not_lt _)]; rfl
@[simp] theorem foldlM_toList [Monad m]
(f : β α m β) (init : β) (arr : Array α) :
arr.toList.foldlM f init = arr.foldlM f init := by
(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 : β) (arr : Array α) :
arr.toList.foldl f init = arr.foldl f init :=
@[simp] theorem foldl_toList (f : β α β) (init : β) (xs : Array α) :
xs.toList.foldl f init = xs.foldl f init :=
List.foldl_eq_foldlM .. foldlM_toList ..
theorem foldrM_eq_reverse_foldlM_toList.aux [Monad m]
(f : α β m β) (arr : Array α) (init : β) (i h) :
(arr.toList.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f arr 0 i h init := by
(f : α β m β) (xs : Array α) (init : β) (i h) :
(xs.toList.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f xs 0 i h init := by
unfold foldrM.fold
match i with
| 0 => simp [List.foldlM, List.take]
| i+1 => rw [ List.take_concat_get _ _ h]; simp [ (aux f arr · i)]
| i+1 => rw [ List.take_concat_get _ _ h]; simp [ (aux f xs · i)]
theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α β m β) (init : β) (arr : Array α) :
arr.foldrM f init = arr.toList.reverse.foldlM (fun x y => f y x) init := by
have : arr = #[] 0 < arr.size :=
match arr with | [] => .inl rfl | a::l => .inr (Nat.zero_lt_succ _)
match arr, this with | _, .inl rfl => rfl | arr, .inr h => ?_
theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α β m β) (init : β) (xs : Array α) :
xs.foldrM f init = xs.toList.reverse.foldlM (fun x y => f y x) init := by
have : xs = #[] 0 < xs.size :=
match xs with | [] => .inl rfl | a::l => .inr (Nat.zero_lt_succ _)
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]
(f : α β m β) (init : β) (arr : Array α) :
arr.toList.foldrM f init = arr.foldrM f init := by
(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 : β) (arr : Array α) :
arr.toList.foldr f init = arr.foldr f init :=
@[simp] 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 (arr : Array α) (a : α) : (arr.push a).toList = arr.toList ++ [a] := by
@[simp] theorem push_toList (xs : Array α) (a : α) : (xs.push a).toList = xs.toList ++ [a] := by
simp [push, List.concat_eq_append]
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.toList ++ l := by
@[simp] theorem toListAppend_eq (xs : Array α) (l : List α) : xs.toListAppend l = xs.toList ++ l := by
simp [toListAppend, foldr_toList]
@[simp] theorem toListImpl_eq (arr : Array α) : arr.toListImpl = arr.toList := by
@[simp] theorem toListImpl_eq (xs : Array α) : xs.toListImpl = xs.toList := by
simp [toListImpl, foldr_toList]
@[simp] theorem pop_toList (arr : Array α) : arr.pop.toList = arr.toList.dropLast := rfl
@[simp] theorem toList_pop (xs : Array α) : xs.pop.toList = xs.toList.dropLast := rfl
@[simp] theorem append_eq_append (arr arr' : Array α) : arr.append arr' = arr ++ arr' := rfl
@[deprecated toList_pop (since := "2025-02-17")]
abbrev pop_toList := @Array.toList_pop
@[simp] theorem toList_append (arr arr' : Array α) :
(arr ++ arr').toList = arr.toList ++ arr'.toList := by
@[simp] theorem append_eq_append (xs ys : Array α) : xs.append ys = xs ++ ys := rfl
@[simp] theorem toList_append (xs ys : Array α) :
(xs ++ ys).toList = xs.toList ++ ys.toList := by
rw [ append_eq_append]; unfold Array.append
rw [ foldl_toList]
induction arr'.toList generalizing arr <;> simp [*]
induction ys.toList generalizing xs <;> simp [*]
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
@[simp] theorem append_empty (xs : Array α) : xs ++ #[] = xs := by
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by
@[deprecated append_empty (since := "2025-01-13")]
abbrev append_nil := @append_empty
@[simp] theorem empty_append (xs : Array α) : #[] ++ xs = xs := by
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
@[deprecated empty_append (since := "2025-01-13")]
abbrev nil_append := @empty_append
@[simp] theorem append_assoc (xs ys zs : Array α) : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
apply ext'; simp only [toList_append, List.append_assoc]
@[simp] theorem appendList_eq_append
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
(xs : Array α) (l : List α) : xs.appendList l = xs ++ l := rfl
@[simp] theorem toList_appendList (arr : Array α) (l : List α) :
(arr ++ l).toList = arr.toList ++ l := by
@[simp] theorem toList_appendList (xs : Array α) (l : List α) :
(xs ++ l).toList = xs.toList ++ l := by
rw [ appendList_eq_append]; unfold Array.appendList
induction l generalizing arr <;> simp [*]
induction l generalizing xs <;> simp [*]
@[deprecated toList_appendList (since := "2024-12-11")]
abbrev appendList_toList := @toList_appendList
@[deprecated "Use the reverse direction of `foldrM_toList`." (since := "2024-11-13")]
theorem foldrM_eq_foldrM_toList [Monad m]
(f : α β m β) (init : β) (arr : Array α) :
arr.foldrM f init = arr.toList.foldrM f init := by
(f : α β m β) (init : β) (xs : Array α) :
xs.foldrM f init = xs.toList.foldrM f init := by
simp
@[deprecated "Use the reverse direction of `foldlM_toList`." (since := "2024-11-13")]
theorem foldlM_eq_foldlM_toList [Monad m]
(f : β α m β) (init : β) (arr : Array α) :
arr.foldlM f init = arr.toList.foldlM f init:= by
(f : β α m β) (init : β) (xs : Array α) :
xs.foldlM f init = xs.toList.foldlM f init:= by
simp
@[deprecated "Use the reverse direction of `foldr_toList`." (since := "2024-11-13")]
theorem foldr_eq_foldr_toList
(f : α β β) (init : β) (arr : Array α) :
arr.foldr f init = arr.toList.foldr f init := by
(f : α β β) (init : β) (xs : Array α) :
xs.foldr f init = xs.toList.foldr f init := by
simp
@[deprecated "Use the reverse direction of `foldl_toList`." (since := "2024-11-13")]
theorem foldl_eq_foldl_toList
(f : β α β) (init : β) (arr : Array α) :
arr.foldl f init = arr.toList.foldl f init:= by
(f : β α β) (init : β) (xs : Array α) :
xs.foldl f init = xs.toList.foldl f init:= by
simp
@[deprecated foldlM_toList (since := "2024-09-09")]
@@ -147,7 +182,7 @@ abbrev push_data := @push_toList
abbrev toList_eq := @toListImpl_eq
@[deprecated pop_toList (since := "2024-09-09")]
abbrev pop_data := @pop_toList
abbrev pop_data := @toList_pop
@[deprecated toList_append (since := "2024-09-09")]
abbrev append_data := @toList_append

View File

@@ -0,0 +1,305 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.Count
/-!
# Lemmas about `Array.countP` and `Array.count`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
/-! ### countP -/
section countP
variable (p q : α Bool)
@[simp] theorem _root_.List.countP_toArray (l : List α) : countP p l.toArray = l.countP p := by
simp [countP]
induction l with
| nil => rfl
| cons hd tl ih =>
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
cases xs
simp
@[simp] theorem countP_empty : countP p #[] = 0 := rfl
@[simp] theorem countP_push_of_pos (xs) (pa : p a) : countP p (xs.push a) = countP p xs + 1 := by
rcases xs with xs
simp_all
@[simp] theorem countP_push_of_neg (xs) (pa : ¬p a) : countP p (xs.push a) = countP p xs := by
rcases xs with xs
simp_all
theorem countP_push (a : α) (xs) : countP p (xs.push a) = countP p xs + if p a then 1 else 0 := by
rcases xs with xs
simp_all
@[simp] theorem countP_singleton (a : α) : countP p #[a] = if p a then 1 else 0 := by
simp [countP_push]
theorem size_eq_countP_add_countP (xs) : xs.size = countP p xs + countP (fun a => ¬p a) xs := by
rcases xs with xs
simp [List.length_eq_countP_add_countP (p := p)]
theorem countP_eq_size_filter (xs) : countP p xs = (filter p xs).size := by
rcases xs with xs
simp [List.countP_eq_length_filter]
theorem countP_eq_size_filter' : countP p = size filter p := by
funext xs
apply countP_eq_size_filter
theorem countP_le_size : countP p xs xs.size := by
simp only [countP_eq_size_filter]
apply size_filter_le
@[simp] theorem countP_append (xs ys) : countP p (xs ++ ys) = countP p xs + countP p ys := by
rcases xs with xs
rcases ys with ys
simp
@[simp] theorem countP_pos_iff {p} : 0 < countP p xs a xs, p a := by
rcases xs with xs
simp
@[simp] theorem one_le_countP_iff {p} : 1 countP p xs a xs, p a :=
countP_pos_iff
@[simp] theorem countP_eq_zero {p} : countP p xs = 0 a xs, ¬p a := by
rcases xs with xs
simp
@[simp] theorem countP_eq_size {p} : countP p xs = xs.size a xs, p a := by
rcases xs with xs
simp
theorem countP_replicate (p : α Bool) (a : α) (n : Nat) :
countP p (replicate n a) = if p a then n else 0 := by
simp [ List.toArray_replicate, List.countP_replicate]
@[deprecated countP_replicate (since := "2025-03-18")]
abbrev countP_mkArray := @countP_replicate
theorem boole_getElem_le_countP (p : α Bool) (xs : Array α) (i : Nat) (h : i < xs.size) :
(if p xs[i] then 1 else 0) xs.countP p := by
rcases xs with xs
simp [List.boole_getElem_le_countP]
theorem countP_set (p : α Bool) (xs : Array α) (i : Nat) (a : α) (h : i < xs.size) :
(xs.set i a).countP p = xs.countP p - (if p xs[i] then 1 else 0) + (if p a then 1 else 0) := by
rcases xs with xs
simp [List.countP_set, h]
theorem countP_filter (xs : Array α) :
countP p (filter q xs) = countP (fun a => p a && q a) xs := by
rcases xs with xs
simp [List.countP_filter]
@[simp] theorem countP_true : (countP fun (_ : α) => true) = size := by
funext xs
simp
@[simp] theorem countP_false : (countP fun (_ : α) => false) = Function.const _ 0 := by
funext xs
simp
@[simp] theorem countP_map (p : β Bool) (f : α β) (xs : Array α) :
countP p (map f xs) = countP (p f) xs := by
rcases xs with xs
simp
theorem size_filterMap_eq_countP (f : α Option β) (xs : Array α) :
(filterMap f xs).size = countP (fun a => (f a).isSome) xs := by
rcases xs with xs
simp [List.length_filterMap_eq_countP]
theorem countP_filterMap (p : β Bool) (f : α Option β) (xs : Array α) :
countP p (filterMap f xs) = countP (fun a => ((f a).map p).getD false) xs := by
rcases xs with xs
simp [List.countP_filterMap]
@[simp] theorem countP_flatten (xss : Array (Array α)) :
countP p xss.flatten = (xss.map (countP p)).sum := by
cases xss using array₂_induction
simp [List.countP_flatten, Function.comp_def]
theorem countP_flatMap (p : β Bool) (xs : Array α) (f : α Array β) :
countP p (xs.flatMap f) = sum (map (countP p f) xs) := by
rcases xs with xs
simp [List.countP_flatMap, Function.comp_def]
@[simp] theorem countP_reverse (xs : Array α) : countP p xs.reverse = countP p xs := by
rcases xs with xs
simp [List.countP_reverse]
variable {p q}
theorem countP_mono_left (h : x xs, p x q x) : countP p xs countP q xs := by
rcases xs with xs
simpa using List.countP_mono_left (by simpa using h)
theorem countP_congr (h : x xs, p x q x) : countP p xs = countP q xs :=
Nat.le_antisymm
(countP_mono_left fun x hx => (h x hx).1)
(countP_mono_left fun x hx => (h x hx).2)
end countP
/-! ### count -/
section count
variable [BEq α]
@[simp] 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
cases xs
simp
@[simp] theorem count_empty (a : α) : count a #[] = 0 := rfl
theorem count_push (a b : α) (xs : Array α) :
count a (xs.push b) = count a xs + if b == a then 1 else 0 := by
simp [count, countP_push]
theorem count_eq_countP (a : α) (xs : Array α) : count a xs = countP (· == a) xs := rfl
theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
funext xs
apply count_eq_countP
theorem count_le_size (a : α) (xs : Array α) : count a xs xs.size := countP_le_size _
theorem count_le_count_push (a b : α) (xs : Array α) : count a xs count a (xs.push b) := by
simp [count_push]
theorem count_singleton (a b : α) : count a #[b] = if b == a then 1 else 0 := by
simp [count_eq_countP]
@[simp] theorem count_append (a : α) : xs ys, count a (xs ++ ys) = count a xs + count a ys :=
countP_append _
@[simp] theorem count_flatten (a : α) (xss : Array (Array α)) :
count a xss.flatten = (xss.map (count a)).sum := by
cases xss using array₂_induction
simp [List.count_flatten, Function.comp_def]
@[simp] theorem count_reverse (a : α) (xs : Array α) : count a xs.reverse = count a xs := by
rcases xs with xs
simp
theorem boole_getElem_le_count (a : α) (xs : Array α) (i : Nat) (h : i < xs.size) :
(if xs[i] == a then 1 else 0) xs.count a := by
rw [count_eq_countP]
apply boole_getElem_le_countP (· == a)
theorem count_set (a b : α) (xs : Array α) (i : Nat) (h : i < xs.size) :
(xs.set i a).count b = xs.count b - (if xs[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
simp [count_eq_countP, countP_set, h]
variable [LawfulBEq α]
@[simp] theorem count_push_self (a : α) (xs : Array α) : count a (xs.push a) = count a xs + 1 := by
simp [count_push]
@[simp] theorem count_push_of_ne (h : b a) (xs : Array α) : count a (xs.push b) = count a xs := by
simp_all [count_push, h]
theorem count_singleton_self (a : α) : count a #[a] = 1 := by simp
@[simp]
theorem count_pos_iff {a : α} {xs : Array α} : 0 < count a xs a xs := by
simp only [count, countP_pos_iff, beq_iff_eq, exists_eq_right]
@[simp] theorem one_le_count_iff {a : α} {xs : Array α} : 1 count a xs a xs :=
count_pos_iff
theorem count_eq_zero_of_not_mem {a : α} {xs : Array α} (h : a xs) : count a xs = 0 :=
Decidable.byContradiction fun h' => h <| count_pos_iff.1 (Nat.pos_of_ne_zero h')
theorem not_mem_of_count_eq_zero {a : α} {xs : Array α} (h : count a xs = 0) : a xs :=
fun h' => Nat.ne_of_lt (count_pos_iff.2 h') h.symm
theorem count_eq_zero {xs : Array α} : count a xs = 0 a xs :=
not_mem_of_count_eq_zero, count_eq_zero_of_not_mem
theorem count_eq_size {xs : Array α} : count a xs = xs.size b xs, a = b := by
rw [count, countP_eq_size]
refine fun h b hb => Eq.symm ?_, fun h b hb => ?_
· simpa using h b hb
· rw [h b hb, beq_self_eq_true]
@[simp] theorem count_replicate_self (a : α) (n : Nat) : count a (replicate n a) = n := by
simp [ List.toArray_replicate]
@[deprecated count_replicate_self (since := "2025-03-18")]
abbrev count_mkArray_self := @count_replicate_self
theorem count_replicate (a b : α) (n : Nat) : count a (replicate n b) = if b == a then n else 0 := by
simp [ List.toArray_replicate, List.count_replicate]
@[deprecated count_replicate (since := "2025-03-18")]
abbrev count_mkArray := @count_replicate
theorem filter_beq (xs : Array α) (a : α) : xs.filter (· == a) = replicate (count a xs) a := by
rcases xs with xs
simp [List.filter_beq]
theorem filter_eq {α} [DecidableEq α] (xs : Array α) (a : α) : xs.filter (· = a) = replicate (count a xs) a :=
filter_beq xs a
theorem replicate_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs.size) :
replicate (count a xs) a = xs := by
rcases xs with xs
rw [ toList_inj]
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
@[deprecated replicate_count_eq_of_count_eq_size (since := "2025-03-18")]
abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
@[simp] theorem count_filter {xs : Array α} (h : p a) : count a (filter p xs) = count a xs := by
rcases xs with xs
simp [List.count_filter, h]
theorem count_le_count_map [DecidableEq β] (xs : Array α) (f : α β) (x : α) :
count x xs count (f x) (map f xs) := by
rcases xs with xs
simp [List.count_le_count_map, countP_map]
theorem count_filterMap {α} [BEq β] (b : β) (f : α Option β) (xs : Array α) :
count b (filterMap f xs) = countP (fun a => f a == some b) xs := by
rcases xs with xs
simp [List.count_filterMap, countP_filterMap]
theorem count_flatMap {α} [BEq β] (xs : Array α) (f : α Array β) (x : β) :
count x (xs.flatMap f) = sum (map (count x f) xs) := by
rcases xs with xs
simp [List.count_flatMap, countP_flatMap, Function.comp_def]
-- FIXME these theorems can be restored once `List.erase` and `Array.erase` have been related.
-- theorem count_erase (a b : α) (l : Array α) : count a (l.erase b) = count a l - if b == a then 1 else 0 := by
-- sorry
-- @[simp] theorem count_erase_self (a : α) (l : Array α) :
-- count a (l.erase a) = count a l - 1 := by rw [count_erase, if_pos (by simp)]
-- @[simp] theorem count_erase_of_ne (ab : a ≠ b) (l : Array α) : count a (l.erase b) = count a l := by
-- rw [count_erase, if_neg (by simpa using ab.symm), Nat.sub_zero]
end count

View File

@@ -9,12 +9,15 @@ import Init.Data.BEq
import Init.Data.List.Nat.BEq
import Init.ByCases
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
theorem rel_of_isEqvAux
{r : α α Bool} {a b : Array α} (hsz : a.size = b.size) {i : Nat} (hi : i a.size)
(heqv : Array.isEqvAux a b hsz r i hi)
{j : Nat} (hj : j < i) : r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz hi))) := by
private theorem rel_of_isEqvAux
{r : α α Bool} {xs ys : Array α} (hsz : xs.size = ys.size) {i : Nat} (hi : i xs.size)
(heqv : Array.isEqvAux xs ys hsz r i hi)
{j : Nat} (hj : j < i) : r (xs[j]'(Nat.lt_of_lt_of_le hj hi)) (ys[j]'(Nat.lt_of_lt_of_le hj (hsz hi))) := by
induction i with
| zero => contradiction
| succ i ih =>
@@ -27,31 +30,32 @@ theorem rel_of_isEqvAux
subst hj'
exact heqv.left
theorem isEqvAux_of_rel {r : α α Bool} {a b : Array α} (hsz : a.size = b.size) {i : Nat} (hi : i a.size)
(w : j, (hj : j < i) r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz hi)))) : Array.isEqvAux a b hsz r i hi := by
private theorem isEqvAux_of_rel {r : α α Bool} {xs ys : Array α} (hsz : xs.size = ys.size) {i : Nat} (hi : i xs.size)
(w : j, (hj : j < i) r (xs[j]'(Nat.lt_of_lt_of_le hj hi)) (ys[j]'(Nat.lt_of_lt_of_le hj (hsz hi)))) : Array.isEqvAux xs ys hsz r i hi := by
induction i with
| zero => simp [Array.isEqvAux]
| succ i ih =>
simp only [isEqvAux, Bool.and_eq_true]
exact w i (Nat.lt_add_one i), ih _ fun j hj => w j (Nat.lt_add_right 1 hj)
theorem rel_of_isEqv {r : α α Bool} {a b : Array α} :
Array.isEqv a b r h : a.size = b.size, (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h h')) := by
-- This is private as the forward direction of `isEqv_iff_rel` may be used.
private theorem rel_of_isEqv {r : α α Bool} {xs ys : Array α} :
Array.isEqv xs ys r h : xs.size = ys.size, (i : Nat) (h' : i < xs.size), r (xs[i]) (ys[i]'(h h')) := by
simp only [isEqv]
split <;> rename_i h
· exact fun h' => h, fun i => rel_of_isEqvAux h (Nat.le_refl ..) h'
· intro; contradiction
theorem isEqv_iff_rel {a b : Array α} {r} :
Array.isEqv a b r h : a.size = b.size, (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h h')) :=
theorem isEqv_iff_rel {xs ys : Array α} {r} :
Array.isEqv xs ys r h : xs.size = ys.size, (i : Nat) (h' : i < xs.size), r (xs[i]) (ys[i]'(h h')) :=
rel_of_isEqv, fun h, w => by
simp only [isEqv, h, reduceDIte]
exact isEqvAux_of_rel h (by simp [h]) w
theorem isEqv_eq_decide (a b : Array α) (r) :
Array.isEqv a b r =
if h : a.size = b.size then decide ( (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h h'))) else false := by
by_cases h : Array.isEqv a b r
theorem isEqv_eq_decide (xs ys : Array α) (r) :
Array.isEqv xs ys r =
if h : xs.size = ys.size then decide ( (i : Nat) (h' : i < xs.size), r (xs[i]) (ys[i]'(h h'))) else false := by
by_cases h : Array.isEqv xs ys r
· simp only [h, Bool.true_eq]
simp only [isEqv_iff_rel] at h
obtain h, w := h
@@ -62,48 +66,58 @@ theorem isEqv_eq_decide (a b : Array α) (r) :
Bool.not_eq_true]
simpa [isEqv_iff_rel] using h'
@[simp] theorem isEqv_toList [BEq α] (a b : Array α) : (a.toList.isEqv b.toList r) = (a.isEqv b r) := by
@[simp] 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 α] (a b : Array α) (h : Array.isEqv a b (fun x y => x = y)) : a = b := by
theorem eq_of_isEqv [DecidableEq α] (xs ys : Array α) (h : Array.isEqv xs ys (fun x y => x = y)) : xs = ys := by
have h, h' := rel_of_isEqv h
exact ext _ _ h (fun i lt _ => by simpa using h' i lt)
theorem isEqvAux_self (r : α α Bool) (hr : a, r a a) (a : Array α) (i : Nat) (h : i a.size) :
Array.isEqvAux a a rfl r i h = true := by
private theorem isEqvAux_self (r : α α Bool) (hr : a, r a a) (xs : Array α) (i : Nat) (h : i xs.size) :
Array.isEqvAux xs xs rfl r i h = true := by
induction i with
| zero => simp [Array.isEqvAux]
| succ i ih =>
simp_all only [isEqvAux, Bool.and_self]
theorem isEqv_self_beq [BEq α] [ReflBEq α] (a : Array α) : Array.isEqv a a (· == ·) = true := by
theorem isEqv_self_beq [BEq α] [ReflBEq α] (xs : Array α) : Array.isEqv xs xs (· == ·) = true := by
simp [isEqv, isEqvAux_self]
theorem isEqv_self [DecidableEq α] (a : Array α) : Array.isEqv a a (· = ·) = true := by
theorem isEqv_self [DecidableEq α] (xs : Array α) : Array.isEqv xs xs (· = ·) = true := by
simp [isEqv, isEqvAux_self]
instance [DecidableEq α] : DecidableEq (Array α) :=
fun a b =>
match h:isEqv a b (fun a b => a = b) with
| true => isTrue (eq_of_isEqv a b h)
fun xs ys =>
match h:isEqv xs ys (fun a b => a = b) with
| true => isTrue (eq_of_isEqv xs ys h)
| false => isFalse fun h' => by subst h'; rw [isEqv_self] at h; contradiction
theorem beq_eq_decide [BEq α] (a b : Array α) :
(a == b) = if h : a.size = b.size then
decide ( (i : Nat) (h' : i < a.size), a[i] == b[i]'(h h')) else false := by
theorem beq_eq_decide [BEq α] (xs ys : Array α) :
(xs == ys) = if h : xs.size = ys.size then
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 α] (a b : Array α) : (a.toList == b.toList) = (a == b) := by
@[simp] 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 α] (a b : List α) : (a.toArray.isEqv b.toArray r) = (a.isEqv b r) := by
@[simp] 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 α] (a b : List α) : (a.toArray == b.toArray) = (a == b) := by
@[simp] theorem beq_toArray [BEq α] (as bs : List α) : (as.toArray == bs.toArray) = (as == bs) := by
simp [beq_eq_decide, Array.beq_eq_decide]
end List
namespace Array
instance [BEq α] [LawfulBEq α] : LawfulBEq (Array α) where
rfl := by simp [BEq.beq, isEqv_self_beq]
eq_of_beq := by
rintro _ _ h
simpa using h
end Array

View File

@@ -0,0 +1,428 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.Erase
import Init.Data.List.Nat.Basic
/-!
# Lemmas about `Array.eraseP`, `Array.erase`, and `Array.eraseIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
/-! ### eraseP -/
@[simp] theorem eraseP_empty : #[].eraseP p = #[] := by simp
theorem eraseP_of_forall_mem_not {xs : Array α} (h : a, a xs ¬p a) : xs.eraseP p = xs := by
rcases xs with xs
simp_all [List.eraseP_of_forall_not]
theorem eraseP_of_forall_getElem_not {xs : Array α} (h : i, (h : i < xs.size) ¬p xs[i]) : xs.eraseP p = xs :=
eraseP_of_forall_mem_not fun a m => by
rw [mem_iff_getElem] at m
obtain i, w, rfl := m
exact h i w
@[simp] theorem eraseP_eq_empty_iff {xs : Array α} {p : α Bool} : xs.eraseP p = #[] xs = #[] x, p x xs = #[x] := by
cases xs
simp
theorem eraseP_ne_empty_iff {xs : Array α} {p : α Bool} : xs.eraseP p #[] xs #[] x, p x xs #[x] := by
simp
theorem exists_of_eraseP {xs : Array α} {a} (hm : a xs) (hp : p a) :
a ys zs, ( b ys, ¬p b) p a xs = ys.push a ++ zs xs.eraseP p = ys ++ zs := by
rcases xs with xs
obtain a, l₁, l₂, h₁, h₂, rfl, h₃ := List.exists_of_eraseP (by simpa using hm) (hp)
refine a, l₁, l₂, by simpa using h₁, h₂, by simp, by simpa using h₃
theorem exists_or_eq_self_of_eraseP (p) (xs : Array α) :
xs.eraseP p = xs
a ys zs, ( b ys, ¬p b) p a xs = ys.push a ++ zs xs.eraseP p = ys ++ zs :=
if h : a xs, p a then
let _, ha, pa := h
.inr (exists_of_eraseP ha pa)
else
.inl (eraseP_of_forall_mem_not (h ·, ·, ·))
@[simp] theorem size_eraseP_of_mem {xs : Array α} (al : a xs) (pa : p a) :
(xs.eraseP p).size = xs.size - 1 := by
let _, ys, zs, _, _, e₁, e₂ := exists_of_eraseP al pa
rw [e₂]; simp [size_append, e₁]; omega
theorem size_eraseP {xs : Array α} : (xs.eraseP p).size = if xs.any p then xs.size - 1 else xs.size := by
split <;> rename_i h
· simp only [any_eq_true] at h
obtain i, h, w := h
simp [size_eraseP_of_mem (xs := xs) (by simp) w]
· simp only [any_eq_true] at h
rw [eraseP_of_forall_getElem_not]
simp_all
theorem size_eraseP_le (xs : Array α) : (xs.eraseP p).size xs.size := by
rcases xs with xs
simpa using List.length_eraseP_le xs
theorem le_size_eraseP (xs : Array α) : xs.size - 1 (xs.eraseP p).size := by
rcases xs with xs
simpa using List.le_length_eraseP xs
theorem mem_of_mem_eraseP {xs : Array α} : a xs.eraseP p a xs := by
rcases xs with xs
simpa using List.mem_of_mem_eraseP
@[simp] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a xs.eraseP p a xs := by
rcases xs with xs
simpa using List.mem_eraseP_of_neg pa
@[simp] theorem eraseP_eq_self_iff {xs : Array α} : xs.eraseP p = xs a xs, ¬ p a := by
rcases xs with xs
simp
theorem eraseP_map (f : β α) (xs : Array β) : (xs.map f).eraseP p = (xs.eraseP (p f)).map f := by
rcases xs with xs
simpa using List.eraseP_map f xs
theorem eraseP_filterMap (f : α Option β) (xs : Array α) :
(filterMap f xs).eraseP p = filterMap f (xs.eraseP (fun x => match f x with | some y => p y | none => false)) := by
rcases xs with xs
simpa using List.eraseP_filterMap f xs
theorem eraseP_filter (f : α Bool) (xs : Array α) :
(filter f xs).eraseP p = filter f (xs.eraseP (fun x => p x && f x)) := by
rcases xs with xs
simpa using List.eraseP_filter f xs
theorem eraseP_append_left {a : α} (pa : p a) {xs : Array α} {ys : Array α} (h : a xs) :
(xs ++ ys).eraseP p = xs.eraseP p ++ ys := by
rcases xs with xs
rcases ys with ys
simpa using List.eraseP_append_left pa ys (by simpa using h)
theorem eraseP_append_right {xs : Array α} ys (h : b xs, ¬p b) :
(xs ++ ys).eraseP p = xs ++ ys.eraseP p := by
rcases xs with xs
rcases ys with ys
simpa using List.eraseP_append_right ys (by simpa using h)
theorem eraseP_append {xs : Array α} {ys : Array α} :
(xs ++ ys).eraseP p = if xs.any p then xs.eraseP p ++ ys else xs ++ ys.eraseP p := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.eraseP_toArray, List.eraseP_append, List.any_toArray]
split <;> simp
theorem eraseP_replicate (n : Nat) (a : α) (p : α Bool) :
(replicate n a).eraseP p = if p a then replicate (n - 1) a else replicate n a := by
simp only [ List.toArray_replicate, List.eraseP_toArray, List.eraseP_replicate]
split <;> simp
@[deprecated eraseP_replicate (since := "2025-03-18")]
abbrev eraseP_mkArray := @eraseP_replicate
@[simp] theorem eraseP_replicate_of_pos {n : Nat} {a : α} (h : p a) :
(replicate n a).eraseP p = replicate (n - 1) a := by
simp only [ List.toArray_replicate, List.eraseP_toArray]
simp [h]
@[deprecated eraseP_replicate_of_pos (since := "2025-03-18")]
abbrev eraseP_mkArray_of_pos := @eraseP_replicate_of_pos
@[simp] theorem eraseP_replicate_of_neg {n : Nat} {a : α} (h : ¬p a) :
(replicate n a).eraseP p = replicate n a := by
simp only [ List.toArray_replicate, List.eraseP_toArray]
simp [h]
@[deprecated eraseP_replicate_of_neg (since := "2025-03-18")]
abbrev eraseP_mkArray_of_neg := @eraseP_replicate_of_neg
theorem eraseP_eq_iff {p} {xs : Array α} :
xs.eraseP p = ys
(( a xs, ¬ p a) xs = ys)
a as bs, ( b as, ¬ p b) p a xs = as.push a ++ bs ys = as ++ bs := by
rcases xs with l
rcases ys with ys
simp [List.eraseP_eq_iff]
constructor
· rintro (h | a, l₁, h₁, h₂, l, rfl, rfl)
· exact Or.inl h
· exact Or.inr a, l₁, by simpa using h₁, h₂, l, by simp
· rintro (h | a, l₁, h₁, h₂, l, rfl, rfl)
· exact Or.inl h
· exact Or.inr a, l₁, by simpa using h₁, h₂, l, by simp
theorem eraseP_comm {xs : Array α} (h : a xs, ¬ p a ¬ q a) :
(xs.eraseP p).eraseP q = (xs.eraseP q).eraseP p := by
rcases xs with xs
simpa using List.eraseP_comm (by simpa using h)
/-! ### erase -/
section erase
variable [BEq α]
theorem erase_of_not_mem [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) : xs.erase a = xs := by
rcases xs with xs
simp [List.erase_of_not_mem (by simpa using h)]
theorem erase_eq_eraseP' (a : α) (xs : Array α) : xs.erase a = xs.eraseP (· == a) := by
rcases xs with xs
simp [List.erase_eq_eraseP']
theorem erase_eq_eraseP [LawfulBEq α] (a : α) (xs : Array α) : xs.erase a = xs.eraseP (a == ·) := by
rcases xs with xs
simp [List.erase_eq_eraseP]
@[simp] theorem erase_eq_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
xs.erase a = #[] xs = #[] xs = #[a] := by
rcases xs with xs
simp [List.erase_eq_nil_iff]
theorem erase_ne_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
xs.erase a #[] xs #[] xs #[a] := by
rcases xs with xs
simp [List.erase_ne_nil_iff]
theorem exists_erase_eq [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) :
ys zs, a ys xs = ys.push a ++ zs xs.erase a = ys ++ zs := by
let _, ys, zs, h₁, e, h₂, h₃ := exists_of_eraseP h (beq_self_eq_true _)
rw [erase_eq_eraseP]; exact ys, zs, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e h₂, h₃
@[simp] theorem size_erase_of_mem [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) :
(xs.erase a).size = xs.size - 1 := by
rw [erase_eq_eraseP]; exact size_eraseP_of_mem h (beq_self_eq_true a)
theorem size_erase [LawfulBEq α] (a : α) (xs : Array α) :
(xs.erase a).size = if a xs then xs.size - 1 else xs.size := by
rw [erase_eq_eraseP, size_eraseP]
congr
simp [mem_iff_getElem, eq_comm (a := a)]
theorem size_erase_le (a : α) (xs : Array α) : (xs.erase a).size xs.size := by
rcases xs with xs
simpa using List.length_erase_le a xs
theorem le_size_erase [LawfulBEq α] (a : α) (xs : Array α) : xs.size - 1 (xs.erase a).size := by
rcases xs with xs
simpa using List.le_length_erase a xs
theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a xs.erase b) : a xs := by
rcases xs with xs
simpa using List.mem_of_mem_erase (by simpa using h)
@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a b) :
a xs.erase b a xs :=
erase_eq_eraseP b xs mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@[simp] theorem erase_eq_self_iff [LawfulBEq α] {xs : Array α} : xs.erase a = xs a xs := by
rw [erase_eq_eraseP', eraseP_eq_self_iff]
simp [forall_mem_ne']
theorem erase_filter [LawfulBEq α] (f : α Bool) (xs : Array α) :
(filter f xs).erase a = filter f (xs.erase a) := by
rcases xs with xs
simpa using List.erase_filter f xs
theorem erase_append_left [LawfulBEq α] {xs : Array α} (ys) (h : a xs) :
(xs ++ ys).erase a = xs.erase a ++ ys := by
rcases xs with xs
rcases ys with ys
simpa using List.erase_append_left ys (by simpa using h)
theorem erase_append_right [LawfulBEq α] {a : α} {xs : Array α} (ys : Array α) (h : a xs) :
(xs ++ ys).erase a = (xs ++ ys.erase a) := by
rcases xs with xs
rcases ys with ys
simpa using List.erase_append_right ys (by simpa using h)
theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
(xs ++ ys).erase a = if a xs then xs.erase a ++ ys else xs ++ ys.erase a := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
split <;> simp
theorem erase_replicate [LawfulBEq α] (n : Nat) (a b : α) :
(replicate n a).erase b = if b == a then replicate (n - 1) a else replicate n a := by
simp only [ List.toArray_replicate, List.erase_toArray]
simp only [List.erase_replicate, beq_iff_eq, List.toArray_replicate]
split <;> simp
@[deprecated erase_replicate (since := "2025-03-18")]
abbrev erase_mkArray := @erase_replicate
theorem erase_comm [LawfulBEq α] (a b : α) (xs : Array α) :
(xs.erase a).erase b = (xs.erase b).erase a := by
rcases xs with xs
simpa using List.erase_comm a b xs
theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
xs.erase a = ys
(a xs xs = ys)
as bs, a as xs = as.push a ++ bs ys = as ++ bs := by
rw [erase_eq_eraseP', eraseP_eq_iff]
simp only [beq_iff_eq, forall_mem_ne', exists_and_left]
constructor
· rintro (h, rfl | a', as, h, rfl, bs, rfl, rfl)
· left; simp_all
· right; refine as, h, bs, by simp
· rintro (h, rfl | as, h, bs, rfl, rfl)
· left; simp_all
· right; refine a, as, h, rfl, bs, by simp
@[simp] theorem erase_replicate_self [LawfulBEq α] {a : α} :
(replicate n a).erase a = replicate (n - 1) a := by
simp only [ List.toArray_replicate, List.erase_toArray]
simp [List.erase_replicate]
@[deprecated erase_replicate_self (since := "2025-03-18")]
abbrev erase_mkArray_self := @erase_replicate_self
@[simp] theorem erase_replicate_ne [LawfulBEq α] {a b : α} (h : !b == a) :
(replicate n a).erase b = replicate n a := by
rw [erase_of_not_mem]
simp_all
@[deprecated erase_replicate_ne (since := "2025-03-18")]
abbrev erase_mkArray_ne := @erase_replicate_ne
end erase
/-! ### eraseIdx -/
theorem eraseIdx_eq_eraseIdxIfInBounds {xs : Array α} {i : Nat} (h : i < xs.size) :
xs.eraseIdx i h = xs.eraseIdxIfInBounds i := by
simp [eraseIdxIfInBounds, h]
theorem eraseIdx_eq_take_drop_succ (xs : Array α) (i : Nat) (h) : xs.eraseIdx i = xs.take i ++ xs.drop (i + 1) := by
rcases xs with xs
simp only [List.size_toArray] at h
simp only [List.eraseIdx_toArray, List.eraseIdx_eq_take_drop_succ, take_eq_extract,
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, drop_eq_extract,
List.size_toArray, List.append_toArray, mk.injEq, List.append_cancel_left_eq]
rw [List.take_of_length_le]
simp
theorem getElem?_eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) :
(xs.eraseIdx i)[j]? = if j < i then xs[j]? else xs[j + 1]? := by
rcases xs with xs
simp [List.getElem?_eraseIdx]
theorem getElem?_eraseIdx_of_lt (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : j < i) :
(xs.eraseIdx i)[j]? = xs[j]? := by
rw [getElem?_eraseIdx]
simp [h']
theorem getElem?_eraseIdx_of_ge (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : i j) :
(xs.eraseIdx i)[j]? = xs[j + 1]? := by
rw [getElem?_eraseIdx]
simp only [dite_eq_ite, ite_eq_right_iff]
intro h'
omega
theorem getElem_eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : j < (xs.eraseIdx i).size) :
(xs.eraseIdx i)[j] = if h'' : j < i then
xs[j]
else
xs[j + 1]'(by rw [size_eraseIdx] at h'; omega) := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_eraseIdx]
split <;> simp
@[simp] theorem eraseIdx_eq_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i = #[] xs.size = 1 i = 0 := by
rcases xs with xs
simp only [List.eraseIdx_toArray, mk.injEq, List.eraseIdx_eq_nil_iff, List.size_toArray,
or_iff_right_iff_imp]
rintro rfl
simp_all
theorem eraseIdx_ne_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i #[] 2 xs.size := by
rcases xs with _ | a, (_ | b, l)
· simp
· simp at h
simp [h]
· simp
theorem mem_of_mem_eraseIdx {xs : Array α} {i : Nat} {h} {a : α} (h : a xs.eraseIdx i) : a xs := by
rcases xs with xs
simpa using List.mem_of_mem_eraseIdx (by simpa using h)
theorem eraseIdx_append_of_lt_size {xs : Array α} {k : Nat} (hk : k < xs.size) (ys : Array α) (h) :
eraseIdx (xs ++ ys) k = eraseIdx xs k ++ ys := by
rcases xs with l
rcases ys with l'
simp at hk
simp [List.eraseIdx_append_of_lt_length, *]
theorem eraseIdx_append_of_length_le {xs : Array α} {k : Nat} (hk : xs.size k) (ys : Array α) (h) :
eraseIdx (xs ++ ys) k = xs ++ eraseIdx ys (k - xs.size) (by simp at h; omega) := by
rcases xs with l
rcases ys with l'
simp at hk
simp [List.eraseIdx_append_of_length_le, *]
theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
(replicate n a).eraseIdx k = replicate (n - 1) a := by
simp at h
simp only [ List.toArray_replicate, List.eraseIdx_toArray]
simp [List.eraseIdx_replicate, h]
@[deprecated eraseIdx_replicate (since := "2025-03-18")]
abbrev eraseIdx_mkArray := @eraseIdx_replicate
theorem mem_eraseIdx_iff_getElem {x : α} {xs : Array α} {k} {h} : x xs.eraseIdx k h i w, i k xs[i]'w = x := by
rcases xs with xs
simp [List.mem_eraseIdx_iff_getElem, *]
theorem mem_eraseIdx_iff_getElem? {x : α} {xs : Array α} {k} {h} : x xs.eraseIdx k h i k, xs[i]? = some x := by
rcases xs with xs
simp [List.mem_eraseIdx_iff_getElem?, *]
theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α] (xs : Array α) (a : α) (i : Nat) (w : xs.idxOf a = i) (h : i < xs.size) :
xs.erase a = xs.eraseIdx i := by
rcases xs with xs
simp at w
simp [List.erase_eq_eraseIdx_of_idxOf, *]
theorem getElem_eraseIdx_of_lt (xs : Array α) (i : Nat) (w : i < xs.size) (j : Nat) (h : j < (xs.eraseIdx i).size) (h' : j < i) :
(xs.eraseIdx i)[j] = xs[j] := by
rcases xs with xs
simp [List.getElem_eraseIdx_of_lt, *]
theorem getElem_eraseIdx_of_ge (xs : Array α) (i : Nat) (w : i < xs.size) (j : Nat) (h : j < (xs.eraseIdx i).size) (h' : i j) :
(xs.eraseIdx i)[j] = xs[j + 1]'(by simp at h; omega) := by
rcases xs with xs
simp [List.getElem_eraseIdx_of_ge, *]
theorem eraseIdx_set_eq {xs : Array α} {i : Nat} {a : α} {h : i < xs.size} :
(xs.set i a).eraseIdx i (by simp; omega) = xs.eraseIdx i := by
rcases xs with xs
simp [List.eraseIdx_set_eq, *]
theorem eraseIdx_set_lt {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (h : j < i) :
(xs.set i a).eraseIdx j (by simp; omega) = (xs.eraseIdx j).set (i - 1) a (by simp; omega) := by
rcases xs with xs
simp [List.eraseIdx_set_lt, *]
theorem eraseIdx_set_gt {xs : Array α} {i : Nat} {j : Nat} {a : α} (h : i < j) {w : j < xs.size} :
(xs.set i a).eraseIdx j (by simp; omega) = (xs.eraseIdx j).set i a (by simp; omega) := by
rcases xs with xs
simp [List.eraseIdx_set_gt, *]
@[simp] theorem set_getElem_succ_eraseIdx_succ
{xs : Array α} {i : Nat} (h : i + 1 < xs.size) :
(xs.eraseIdx (i + 1)).set i xs[i + 1] (by simp; omega) = xs.eraseIdx i := by
rcases xs with xs
simp [List.set_getElem_succ_eraseIdx_succ, *]
end Array

View File

@@ -0,0 +1,445 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.TakeDrop
/-!
# Lemmas about `Array.extract`
This file follows the contents of `Init.Data.List.TakeDrop` and `Init.Data.List.Nat.TakeDrop`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Nat
namespace Array
/-! ### extract -/
@[simp] theorem extract_of_size_lt {as : Array α} {i j : Nat} (h : as.size < j) :
as.extract i j = as.extract i as.size := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract] at h₁ h₂
simp [h]
theorem size_extract_le {as : Array α} {i j : Nat} :
(as.extract i j).size j - i := by
simp
omega
theorem size_extract_le' {as : Array α} {i j : Nat} :
(as.extract i j).size as.size - i := by
simp
omega
theorem size_extract_of_le {as : Array α} {i j : Nat} (h : j as.size) :
(as.extract i j).size = j - i := by
simp
omega
@[simp]
theorem extract_push {as : Array α} {b : α} {start stop : Nat} (h : stop as.size) :
(as.push b).extract start stop = as.extract start stop := by
ext i h₁ h₂
· simp
omega
· simp only [size_extract, size_push] at h₁ h₂
simp only [getElem_extract, getElem_push]
rw [dif_pos (by omega)]
@[simp]
theorem extract_eq_pop {as : Array α} {stop : Nat} (h : stop = as.size - 1) :
as.extract 0 stop = as.pop := by
ext i h₁ h₂
· simp
omega
· simp only [size_extract, size_pop] at h₁ h₂
simp [getElem_extract, getElem_pop]
@[simp]
theorem extract_append_extract {as : Array α} {i j k : Nat} :
as.extract i j ++ as.extract j k = as.extract (min i j) (max j k) := by
ext l h₁ h₂
· simp
omega
· simp only [size_append, size_extract] at h₁ h₂
simp only [getElem_append, size_extract, getElem_extract]
split <;>
· congr 1
omega
@[simp]
theorem extract_eq_empty_iff {as : Array α} :
as.extract i j = #[] min j as.size i := by
constructor
· intro h
replace h := congrArg Array.size h
simp at h
omega
· intro h
exact eq_empty_of_size_eq_zero (by simp; omega)
theorem extract_eq_empty_of_le {as : Array α} (h : min j as.size i) :
as.extract i j = #[] :=
extract_eq_empty_iff.2 h
theorem lt_of_extract_ne_empty {as : Array α} (h : as.extract i j #[]) :
i < min j as.size :=
gt_of_not_le (mt extract_eq_empty_of_le h)
@[simp]
theorem extract_eq_self_iff {as : Array α} :
as.extract i j = as as.size = 0 i = 0 as.size j := by
constructor
· intro h
replace h := congrArg Array.size h
simp at h
omega
· intro h
ext l h₁ h₂
· simp
omega
· simp only [size_extract] at h₁
simp only [getElem_extract]
congr 1
omega
theorem extract_eq_self_of_le {as : Array α} (h : as.size j) :
as.extract 0 j = as :=
extract_eq_self_iff.2 (.inr rfl, h)
theorem le_of_extract_eq_self {as : Array α} (h : as.extract i j = as) :
as.size j := by
replace h := congrArg Array.size h
simp at h
omega
@[simp]
theorem extract_size_left {as : Array α} :
as.extract as.size j = #[] := by
simp
omega
@[simp]
theorem push_extract_getElem {as : Array α} {i j : Nat} (h : j < as.size) :
(as.extract i j).push as[j] = as.extract (min i j) (j + 1) := by
ext l h₁ h₂
· simp
omega
· simp only [size_push, size_extract] at h₁ h₂
simp only [getElem_push, size_extract, getElem_extract]
split <;>
· congr
omega
theorem extract_succ_right {as : Array α} {i j : Nat} (w : i < j + 1) (h : j < as.size) :
as.extract i (j + 1) = (as.extract i j).push as[j] := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, push_extract_getElem] at h₁ h₂
simp only [getElem_extract, push_extract_getElem]
congr
omega
theorem extract_sub_one {as : Array α} {i j : Nat} (h : j < as.size) :
as.extract i (j - 1) = (as.extract i j).pop := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, size_pop] at h₁ h₂
simp only [getElem_extract, getElem_pop]
@[simp]
theorem getElem?_extract_of_lt {as : Array α} {i j k : Nat} (h : k < min j as.size - i) :
(as.extract i j)[k]? = some (as[i + k]'(by omega)) := by
simp [getElem?_extract, h]
theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
(as.extract 0 (j + 1))[j]? = as[j]? := by
simp [getElem?_extract]
omega
@[simp] theorem extract_extract {as : Array α} {i j k l : Nat} :
(as.extract i j).extract k l = as.extract (i + k) (min (i + l) j) := by
ext m h₁ h₂
· simp
omega
· simp only [size_extract] at h₁ h₂
simp [Nat.add_assoc]
theorem extract_eq_empty_of_eq_empty {as : Array α} {i j : Nat} (h : as = #[]) :
as.extract i j = #[] := by
simp [h]
theorem ne_empty_of_extract_ne_empty {as : Array α} {i j : Nat} (h : as.extract i j #[]) :
as #[] :=
mt extract_eq_empty_of_eq_empty h
theorem extract_set {as : Array α} {i j k : Nat} (h : k < as.size) {a : α} :
(as.set k a).extract i j =
if _ : k < i then
as.extract i j
else if _ : k < min j as.size then
(as.extract i j).set (k - i) a (by simp; omega)
else as.extract i j := by
split
· ext l h₁ h₂
· simp
· simp at h₁ h₂
simp [getElem_set]
omega
· split
· ext l h₁ h₂
· simp
· simp only [getElem_extract, getElem_set]
split
· rw [if_pos]; omega
· rw [if_neg]; omega
· ext l h₁ h₂
· simp
· simp at h₁ h₂
simp [getElem_set]
omega
theorem set_extract {as : Array α} {i j k : Nat} (h : k < (as.extract i j).size) {a : α} :
(as.extract i j).set k a = (as.set (i + k) a (by simp at h; omega)).extract i j := by
ext l h₁ h₂
· simp
· simp_all [getElem_set]
@[simp]
theorem extract_append {as bs : Array α} {i j : Nat} :
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, size_append] at h₁ h₂
simp only [getElem_extract, getElem_append, size_extract]
split
· split
· rfl
· omega
· split
· omega
· congr 1
omega
theorem extract_append_left {as bs : Array α} :
(as ++ bs).extract 0 as.size = as.extract 0 as.size := by
simp
@[simp] theorem extract_append_right {as bs : Array α} :
(as ++ bs).extract as.size (as.size + i) = bs.extract 0 i := by
simp only [extract_append, extract_size_left, Nat.sub_self, empty_append]
congr 1
omega
@[simp] theorem map_extract {as : Array α} {i j : Nat} :
(as.extract i j).map f = (as.map f).extract i j := by
ext l h₁ h₂
· simp
· simp only [size_map, size_extract] at h₁ h₂
simp only [getElem_map, getElem_extract]
@[simp] theorem extract_replicate {a : α} {n i j : Nat} :
(replicate n a).extract i j = replicate (min j n - i) a := by
ext l h₁ h₂
· simp
· simp only [size_extract, size_replicate] at h₁ h₂
simp only [getElem_extract, getElem_replicate]
@[deprecated extract_replicate (since := "2025-03-18")]
abbrev extract_mkArray := @extract_replicate
theorem extract_eq_extract_right {as : Array α} {i j j' : Nat} :
as.extract i j = as.extract i j' min (j - i) (as.size - i) = min (j' - i) (as.size - i) := by
rcases as with as
simp
theorem extract_eq_extract_left {as : Array α} {i i' j : Nat} :
as.extract i j = as.extract i' j min j as.size - i = min j as.size - i' := by
constructor
· intro h
replace h := congrArg Array.size h
simpa using h
· intro h
ext l h₁ h₂
· simpa
· simp only [size_extract] at h₁ h₂
simp only [getElem_extract]
congr 1
omega
theorem extract_add_left {as : Array α} {i j k : Nat} :
as.extract (i + j) k = (as.extract i k).extract j (k - i) := by
simp [extract_eq_extract_right]
omega
theorem mem_extract_iff_getElem {as : Array α} {a : α} {i j : Nat} :
a as.extract i j (k : Nat) (hm : k < min j as.size - i), as[i + k] = a := by
rcases as with as
simp [List.mem_take_iff_getElem]
constructor <;>
· rintro k, h, rfl
exact k, by omega, rfl
theorem set_eq_push_extract_append_extract {as : Array α} {i : Nat} (h : i < as.size) {a : α} :
as.set i a = (as.extract 0 i).push a ++ (as.extract (i + 1) as.size) := by
rcases as with as
simp at h
simp [List.set_eq_take_append_cons_drop, h, List.take_of_length_le]
theorem extract_reverse {as : Array α} {i j : Nat} :
as.reverse.extract i j = (as.extract (as.size - j) (as.size - i)).reverse := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, size_reverse] at h₁ h₂
simp only [getElem_extract, getElem_reverse, size_extract]
congr 1
omega
theorem reverse_extract {as : Array α} {i j : Nat} :
(as.extract i j).reverse = as.reverse.extract (as.size - j) (as.size - i) := by
rw [extract_reverse]
simp
by_cases h : j as.size
· have : as.size - (as.size - j) = j := by omega
simp [this, extract_eq_extract_left]
omega
· have : as.size - (as.size - j) = as.size := by omega
simp only [Nat.not_le] at h
simp [h, this, extract_eq_extract_left]
omega
/-! ### takeWhile -/
theorem takeWhile_map (f : α β) (p : β Bool) (as : Array α) :
(as.map f).takeWhile p = (as.takeWhile (p f)).map f := by
rcases as with as
simp [List.takeWhile_map]
theorem popWhile_map (f : α β) (p : β Bool) (as : Array α) :
(as.map f).popWhile p = (as.popWhile (p f)).map f := by
rcases as with as
simp [List.dropWhile_map, List.map_reverse]
theorem takeWhile_filterMap (f : α Option β) (p : β Bool) (as : Array α) :
(as.filterMap f).takeWhile p = (as.takeWhile fun a => (f a).all p).filterMap f := by
rcases as with as
simp [List.takeWhile_filterMap]
theorem popWhile_filterMap (f : α Option β) (p : β Bool) (as : Array α) :
(as.filterMap f).popWhile p = (as.popWhile fun a => (f a).all p).filterMap f := by
rcases as with as
simp [List.dropWhile_filterMap, List.filterMap_reverse]
theorem takeWhile_filter (p q : α Bool) (as : Array α) :
(as.filter p).takeWhile q = (as.takeWhile fun a => !p a || q a).filter p := by
rcases as with as
simp [List.takeWhile_filter]
theorem popWhile_filter (p q : α Bool) (as : Array α) :
(as.filter p).popWhile q = (as.popWhile fun a => !p a || q a).filter p := by
rcases as with as
simp [List.dropWhile_filter, List.filter_reverse]
theorem takeWhile_append {xs ys : Array α} :
(xs ++ ys).takeWhile p =
if (xs.takeWhile p).size = xs.size then xs ++ ys.takeWhile p else xs.takeWhile p := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.takeWhile_toArray, List.takeWhile_append, List.size_toArray]
split <;> rfl
@[simp] theorem takeWhile_append_of_pos {p : α Bool} {xs ys : Array α} (h : a xs, p a) :
(xs ++ ys).takeWhile p = xs ++ ys.takeWhile p := by
rcases xs with xs
rcases ys with ys
simp at h
simp [List.takeWhile_append_of_pos h]
theorem popWhile_append {xs ys : Array α} :
(xs ++ ys).popWhile p =
if (ys.popWhile p).isEmpty then xs.popWhile p else xs ++ ys.popWhile p := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, List.dropWhile_append,
List.isEmpty_iff, List.isEmpty_toArray, List.isEmpty_reverse]
-- Why do these not fire with `simp`?
rw [List.popWhile_toArray, List.isEmpty_toArray, List.isEmpty_reverse]
split
· rfl
· simp
@[simp] theorem popWhile_append_of_pos {p : α Bool} {xs ys : Array α} (h : a ys, p a) :
(xs ++ ys).popWhile p = xs.popWhile p := by
rcases xs with xs
rcases ys with ys
simp at h
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, mk.injEq,
List.reverse_inj]
rw [List.dropWhile_append_of_pos]
simpa
@[simp] theorem takeWhile_replicate_eq_filter (p : α Bool) :
(replicate n a).takeWhile p = (replicate n a).filter p := by
simp [ List.toArray_replicate]
@[deprecated takeWhile_replicate_eq_filter (since := "2025-03-18")]
abbrev takeWhile_mkArray_eq_filter := @takeWhile_replicate_eq_filter
theorem takeWhile_replicate (p : α Bool) :
(replicate n a).takeWhile p = if p a then replicate n a else #[] := by
simp [takeWhile_replicate_eq_filter, filter_replicate]
@[deprecated takeWhile_replicate (since := "2025-03-18")]
abbrev takeWhile_mkArray := @takeWhile_replicate
@[simp] theorem popWhile_replicate_eq_filter_not (p : α Bool) :
(replicate n a).popWhile p = (replicate n a).filter (fun a => !p a) := by
simp [ List.toArray_replicate, List.filter_reverse]
@[deprecated popWhile_replicate_eq_filter_not (since := "2025-03-18")]
abbrev popWhile_mkArray_eq_filter_not := @popWhile_replicate_eq_filter_not
theorem popWhile_replicate (p : α Bool) :
(replicate n a).popWhile p = if p a then #[] else replicate n a := by
simp only [popWhile_replicate_eq_filter_not, size_replicate, filter_replicate, Bool.not_eq_eq_eq_not,
Bool.not_true]
split <;> simp_all
@[deprecated popWhile_replicate (since := "2025-03-18")]
abbrev popWhile_mkArray := @popWhile_replicate
theorem extract_takeWhile {as : Array α} {i : Nat} :
(as.takeWhile p).extract 0 i = (as.extract 0 i).takeWhile p := by
rcases as with as
simp [List.take_takeWhile]
@[simp] theorem all_takeWhile {as : Array α} :
(as.takeWhile p).all p = true := by
rcases as with as
rw [List.takeWhile_toArray] -- Not sure why this doesn't fire with `simp`.
simp
@[simp] theorem any_popWhile {as : Array α} :
(as.popWhile p).any (fun a => !p a) = !as.all p := by
rcases as with as
rw [List.popWhile_toArray] -- Not sure why this doesn't fire with `simp`.
simp
theorem takeWhile_eq_extract_findIdx_not {xs : Array α} {p : α Bool} :
takeWhile p xs = xs.extract 0 (xs.findIdx (fun a => !p a)) := by
rcases xs with xs
simp [List.takeWhile_eq_take_findIdx_not]
end Array

View File

@@ -5,10 +5,52 @@ Authors: François G. Dorais
-/
prelude
import Init.Data.List.FinRange
import Init.Data.Array.OfFn
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-- `finRange n` is the array of all elements of `Fin n` in order. -/
/--
Returns an array of all elements of `Fin n` in order, starting at `0`.
Examples:
* `Array.finRange 0 = (#[] : Array (Fin 0))`
* `Array.finRange 2 = (#[0, 1] : Array (Fin 2))`
-/
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
@[simp] theorem size_finRange (n) : (Array.finRange n).size = n := by
simp [Array.finRange]
@[simp] theorem getElem_finRange (i : Nat) (h : i < (Array.finRange n).size) :
(Array.finRange n)[i] = Fin.cast (size_finRange n) i, h := by
simp [Array.finRange]
@[simp] theorem finRange_zero : Array.finRange 0 = #[] := by simp [Array.finRange]
theorem finRange_succ (n) : Array.finRange (n+1) = #[0] ++ (Array.finRange n).map Fin.succ := by
ext
· simp [Nat.add_comm]
· simp [getElem_append]
split <;>
· simp; omega
theorem finRange_succ_last (n) :
Array.finRange (n+1) = (Array.finRange n).map Fin.castSucc ++ #[Fin.last n] := by
ext
· simp
· simp [getElem_push]
split
· simp
· simp_all
omega
theorem finRange_reverse (n) : (Array.finRange n).reverse = (Array.finRange n).map Fin.rev := by
ext i h
· simp
· simp
omega
end Array

View File

@@ -4,115 +4,128 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.List.Find
import Init.Data.List.Nat.Find
import Init.Data.Array.Lemmas
import Init.Data.Array.Attach
import Init.Data.Array.Range
/-!
# Lemmas about `Array.findSome?`, `Array.find?`.
# Lemmas about `Array.findSome?`, `Array.find?, `Array.findIdx`, `Array.findIdx?`, `Array.idxOf`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
/-! ### findSome? -/
@[simp] theorem findSomeRev?_push_of_isSome (l : Array α) (h : (f a).isSome) : (l.push a).findSomeRev? f = f a := by
cases l; simp_all
@[simp] theorem findSomeRev?_push_of_isSome (xs : Array α) (h : (f a).isSome) : (xs.push a).findSomeRev? f = f a := by
cases xs; simp_all
@[simp] theorem findSomeRev?_push_of_isNone (l : Array α) (h : (f a).isNone) : (l.push a).findSomeRev? f = l.findSomeRev? f := by
cases l; simp_all
@[simp] theorem findSomeRev?_push_of_isNone (xs : Array α) (h : (f a).isNone) : (xs.push a).findSomeRev? f = xs.findSomeRev? f := by
cases xs; simp_all
theorem exists_of_findSome?_eq_some {f : α Option β} {l : Array α} (w : l.findSome? f = some b) :
a, a l f a = b := by
cases l; simp_all [List.exists_of_findSome?_eq_some]
theorem exists_of_findSome?_eq_some {f : α Option β} {xs : Array α} (w : xs.findSome? f = some b) :
a, a xs f a = b := by
cases xs; simp_all [List.exists_of_findSome?_eq_some]
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none x l, p x = none := by
cases l; simp
@[simp] theorem findSome?_eq_none_iff : findSome? p xs = none x xs, p x = none := by
cases xs; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {l : Array α} :
(l.findSome? f).isSome x, x l (f x).isSome := by
cases l; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {xs : Array α} :
(xs.findSome? f).isSome x, x xs (f x).isSome := by
cases xs; simp
theorem findSome?_eq_some_iff {f : α Option β} {l : Array α} {b : β} :
l.findSome? f = some b (l₁ : Array α) (a : α) (l₂ : Array α), l = l₁.push a ++ l₂ f a = some b x l₁, f x = none := by
cases l
theorem findSome?_eq_some_iff {f : α Option β} {xs : Array α} {b : β} :
xs.findSome? f = some b (ys : Array α) (a : α) (zs : Array α), xs = ys.push a ++ zs f a = some b x ys, f x = none := by
cases xs
simp only [List.findSome?_toArray, List.findSome?_eq_some_iff]
constructor
· rintro l₁, a, l₂, rfl, h₁, h₂
exact l₁.toArray, a, l₂.toArray, by simp_all
· rintro l₁, a, l₂, h₀, h₁, h₂
exact l₁.toList, a, l₂.toList, by simpa using congrArg toList h₀, h₁, by simpa
· rintro xs, a, ys, h₀, h₁, h₂
exact xs.toList, a, ys.toList, by simpa using congrArg toList h₀, h₁, by simpa
@[simp] theorem findSome?_guard (l : Array α) : findSome? (Option.guard fun x => p x) l = find? p l := by
cases l; simp
@[simp] theorem findSome?_guard (xs : Array α) : findSome? (Option.guard fun x => p x) xs = find? p xs := by
cases xs; simp
@[simp] theorem getElem?_zero_filterMap (f : α Option β) (l : Array α) : (l.filterMap f)[0]? = l.findSome? f := by
cases l; simp [ List.head?_eq_getElem?]
theorem find?_eq_findSome?_guard (xs : Array α) : find? p xs = findSome? (Option.guard fun x => p x) xs :=
(findSome?_guard xs).symm
@[simp] theorem getElem_zero_filterMap (f : α Option β) (l : Array α) (h) :
(l.filterMap f)[0] = (l.findSome? f).get (by cases l; simpa [List.length_filterMap_eq_countP] using h) := by
cases l; simp [ List.head_eq_getElem, getElem?_zero_filterMap]
@[simp] theorem getElem?_zero_filterMap (f : α Option β) (xs : Array α) : (xs.filterMap f)[0]? = xs.findSome? f := by
cases xs; simp [ List.head?_eq_getElem?]
@[simp] theorem back?_filterMap (f : α Option β) (l : Array α) : (l.filterMap f).back? = l.findSomeRev? f := by
cases l; simp
@[simp] theorem getElem_zero_filterMap (f : α Option β) (xs : Array α) (h) :
(xs.filterMap f)[0] = (xs.findSome? f).get (by cases xs; simpa [List.length_filterMap_eq_countP] using h) := by
cases xs; simp [ List.head_eq_getElem, getElem?_zero_filterMap]
@[simp] theorem back!_filterMap [Inhabited β] (f : α Option β) (l : Array α) :
(l.filterMap f).back! = (l.findSomeRev? f).getD default := by
cases l; simp
@[simp] theorem back?_filterMap (f : α Option β) (xs : Array α) : (xs.filterMap f).back? = xs.findSomeRev? f := by
cases xs; simp
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (l : Array α) :
(l.findSome? f).map g = l.findSome? (Option.map g f) := by
cases l; simp
@[simp] theorem back!_filterMap [Inhabited β] (f : α Option β) (xs : Array α) :
(xs.filterMap f).back! = (xs.findSomeRev? f).getD default := by
cases xs; simp
theorem findSome?_map (f : β γ) (l : Array β) : findSome? p (l.map f) = l.findSome? (p f) := by
cases l; simp [List.findSome?_map]
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (xs : Array α) :
(xs.findSome? f).map g = xs.findSome? (Option.map g f) := by
cases xs; simp
theorem findSome?_append {l₁ l₂ : Array α} : (l₁ ++ l₂).findSome? f = (l₁.findSome? f).or (l₂.findSome? f) := by
cases l₁; cases l₂; simp [List.findSome?_append]
theorem findSome?_map (f : β γ) (xs : Array β) : findSome? p (xs.map f) = xs.findSome? (p f) := by
cases xs; simp [List.findSome?_map]
theorem getElem?_zero_flatten (L : Array (Array α)) :
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
cases L using array_array_induction
theorem findSome?_append {xs ys : Array α} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
cases xs; cases ys; simp [List.findSome?_append]
theorem getElem?_zero_flatten (xss : Array (Array α)) :
(flatten xss)[0]? = xss.findSome? fun xs => xs[0]? := by
cases xss using array₂_induction
simp [ List.head?_eq_getElem?, List.head?_flatten, List.findSome?_map, Function.comp_def]
theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.size) :
(L.findSome? fun l => l[0]?).isSome := by
cases L using array_array_induction
theorem getElem_zero_flatten.proof {xss : Array (Array α)} (h : 0 < xss.flatten.size) :
(xss.findSome? fun xs => xs[0]?).isSome := by
cases xss using array_induction
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
List.findSome?_isSome_iff, isSome_getElem?]
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
obtain _, xs, m, rfl, h := h
exact xs, m, by simpa using h
theorem getElem_zero_flatten {L : Array (Array α)} (h) :
(flatten L)[0] = (L.findSome? fun l => l[0]?).get (getElem_zero_flatten.proof h) := by
have t := getElem?_zero_flatten L
theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
(flatten xss)[0] = (xss.findSome? fun xs => xs[0]?).get (getElem_zero_flatten.proof h) := by
have t := getElem?_zero_flatten xss
simp [getElem?_eq_getElem, h] at t
simp [ t]
theorem back?_flatten {L : Array (Array α)} :
(flatten L).back? = (L.findSomeRev? fun l => l.back?) := by
cases L using array_array_induction
simp [List.getLast?_flatten, List.map_reverse, List.findSome?_map, Function.comp_def]
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
simp [ List.toArray_replicate, List.findSome?_replicate]
@[simp] theorem findSome?_mkArray_of_pos (h : 0 < n) : findSome? f (mkArray n a) = f a := by
simp [findSome?_mkArray, Nat.ne_of_gt h]
@[deprecated findSome?_replicate (since := "2025-03-18")]
abbrev findSome?_mkArray := @findSome?_replicate
@[simp] theorem findSome?_replicate_of_pos (h : 0 < n) : findSome? f (replicate n a) = f a := by
simp [findSome?_replicate, Nat.ne_of_gt h]
@[deprecated findSome?_replicate_of_pos (since := "2025-03-18")]
abbrev findSome?_mkArray_of_pos := @findSome?_replicate_of_pos
-- Argument is unused, but used to decide whether `simp` should unfold.
@[simp] theorem findSome?_mkArray_of_isSome (_ : (f a).isSome) :
findSome? f (mkArray n a) = if n = 0 then none else f a := by
simp [findSome?_mkArray]
@[simp] theorem findSome?_replicate_of_isSome (_ : (f a).isSome) :
findSome? f (replicate n a) = if n = 0 then none else f a := by
simp [findSome?_replicate]
@[simp] theorem findSome?_mkArray_of_isNone (h : (f a).isNone) :
findSome? f (mkArray n a) = none := by
@[deprecated findSome?_replicate_of_isSome (since := "2025-03-18")]
abbrev findSome?_mkArray_of_isSome := @findSome?_replicate_of_isSome
@[simp] theorem findSome?_replicate_of_isNone (h : (f a).isNone) :
findSome? f (replicate n a) = none := by
rw [Option.isNone_iff_eq_none] at h
simp [findSome?_mkArray, h]
simp [findSome?_replicate, h]
@[deprecated findSome?_replicate_of_isNone (since := "2025-03-18")]
abbrev findSome?_mkArray_of_isNone := @findSome?_replicate_of_isNone
/-! ### find? -/
@@ -120,16 +133,16 @@ theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else
#[a].find? p = if p a then some a else none := by
simp [singleton_eq_toArray_singleton]
@[simp] theorem findRev?_push_of_pos (l : Array α) (h : p a) :
findRev? p (l.push a) = some a := by
cases l; simp [h]
@[simp] theorem findRev?_push_of_pos (xs : Array α) (h : p a) :
findRev? p (xs.push a) = some a := by
cases xs; simp [h]
@[simp] theorem findRev?_cons_of_neg (l : Array α) (h : ¬p a) :
findRev? p (l.push a) = findRev? p l := by
cases l; simp [h]
@[simp] theorem findRev?_cons_of_neg (xs : Array α) (h : ¬p a) :
findRev? p (xs.push a) = findRev? p xs := by
cases xs; simp [h]
@[simp] theorem find?_eq_none : find? p l = none x l, ¬ p x := by
cases l; simp
@[simp] theorem find?_eq_none : find? p xs = none x xs, ¬ p x := by
cases xs; simp
theorem find?_eq_some_iff_append {xs : Array α} :
xs.find? p = some b p b (as bs : Array α), xs = as.push b ++ bs a as, !p a := by
@@ -138,10 +151,10 @@ theorem find?_eq_some_iff_append {xs : Array α} :
Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
constructor
· rintro as, x, rfl, h
exact as.toArray, x.toArray, by simp , by simpa using h
· rintro as, x, h', h
exact as.toList, x.toList, by simpa using congrArg Array.toList h',
· rintro as, xs, rfl, h
exact as.toArray, xs.toArray, by simp , by simpa using h
· rintro as, l, h', h
exact as.toList, l, by simpa using congrArg Array.toList h',
by simpa using h
@[simp]
@@ -170,22 +183,22 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
cases xs; simp
@[simp] theorem getElem?_zero_filter (p : α Bool) (l : Array α) :
(l.filter p)[0]? = l.find? p := by
cases l; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem?_zero_filter (p : α Bool) (xs : Array α) :
(xs.filter p)[0]? = xs.find? p := by
cases xs; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem_zero_filter (p : α Bool) (l : Array α) (h) :
(l.filter p)[0] =
(l.find? p).get (by cases l; simpa [ List.countP_eq_length_filter] using h) := by
cases l
@[simp] theorem getElem_zero_filter (p : α Bool) (xs : Array α) (h) :
(xs.filter p)[0] =
(xs.find? p).get (by cases xs; simpa [ List.countP_eq_length_filter] using h) := by
cases xs
simp [List.getElem_zero_eq_head]
@[simp] theorem back?_filter (p : α Bool) (l : Array α) : (l.filter p).back? = l.findRev? p := by
cases l; simp
@[simp] theorem back?_filter (p : α Bool) (xs : Array α) : (xs.filter p).back? = xs.findRev? p := by
cases xs; simp
@[simp] theorem back!_filter [Inhabited α] (p : α Bool) (l : Array α) :
(l.filter p).back! = (l.findRev? p).get! := by
cases l; simp [Option.get!_eq_getD]
@[simp] theorem back!_filter [Inhabited α] (p : α Bool) (xs : Array α) :
(xs.filter p).back! = (xs.findRev? p).get! := by
cases xs; simp [Option.get!_eq_getD]
@[simp] theorem find?_filterMap (xs : Array α) (f : α Option β) (p : β Bool) :
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
@@ -195,33 +208,36 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
find? p (xs.map f) = (xs.find? (p f)).map f := by
cases xs; simp
@[simp] theorem find?_append {l₁ l₂ : Array α} :
(l₁ ++ l₂).find? p = (l₁.find? p).or (l₂.find? p) := by
cases l₁
cases l₂
@[simp] theorem find?_append {xs ys : Array α} :
(xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
cases xs
cases ys
simp
@[simp] theorem find?_flatten (xs : Array (Array α)) (p : α Bool) :
xs.flatten.find? p = xs.findSome? (·.find? p) := by
cases xs using array_array_induction
@[simp] theorem find?_flatten (xss : Array (Array α)) (p : α Bool) :
xss.flatten.find? p = xss.findSome? (·.find? p) := by
cases xss using array_induction
simp [List.findSome?_map, Function.comp_def]
theorem find?_flatten_eq_none {xs : Array (Array α)} {p : α Bool} :
xs.flatten.find? p = none ys xs, x ys, !p x := by
theorem find?_flatten_eq_none_iff {xss : Array (Array α)} {p : α Bool} :
xss.flatten.find? p = none ys xss, x ys, !p x := by
simp
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
/--
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
Moreover, no earlier array in `xs` has an element satisfying `p`.
-/
theorem find?_flatten_eq_some {xs : Array (Array α)} {p : α Bool} {a : α} :
xs.flatten.find? p = some a
theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α Bool} {a : α} :
xss.flatten.find? p = some a
p a (as : Array (Array α)) (ys zs : Array α) (bs : Array (Array α)),
xs = as.push (ys.push a ++ zs) ++ bs
( a as, x a, !p x) ( x ys, !p x) := by
cases xs using array_array_induction
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some]
xss = as.push (ys.push a ++ zs) ++ bs
( ws as, x ws, !p x) ( x ys, !p x) := by
cases xss using array_induction
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some_iff]
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
constructor
@@ -235,47 +251,410 @@ theorem find?_flatten_eq_some {xs : Array (Array α)} {p : α → Bool} {a : α}
zs.toList, bs.toList.map Array.toList, by simpa using h,
by simpa using h₁, by simpa using h₂
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
@[simp] theorem find?_flatMap (xs : Array α) (f : α Array β) (p : β Bool) :
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
cases xs
simp [List.find?_flatMap, Array.flatMap_toArray]
theorem find?_flatMap_eq_none {xs : Array α} {f : α Array β} {p : β Bool} :
theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α Array β} {p : β Bool} :
(xs.flatMap f).find? p = none x xs, y f x, !p y := by
simp
theorem find?_mkArray :
find? p (mkArray n a) = if n = 0 then none else if p a then some a else none := by
@[deprecated find?_flatMap_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatMap_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
simp [ List.toArray_replicate, List.find?_replicate]
@[simp] theorem find?_mkArray_of_length_pos (h : 0 < n) :
find? p (mkArray n a) = if p a then some a else none := by
simp [find?_mkArray, Nat.ne_of_gt h]
@[deprecated find?_replicate (since := "2025-03-18")]
abbrev find?_mkArray := @find?_replicate
@[simp] theorem find?_mkArray_of_pos (h : p a) :
find? p (mkArray n a) = if n = 0 then none else some a := by
simp [find?_mkArray, h]
@[simp] theorem find?_replicate_of_size_pos (h : 0 < n) :
find? p (replicate n a) = if p a then some a else none := by
simp [find?_replicate, Nat.ne_of_gt h]
@[simp] theorem find?_mkArray_of_neg (h : ¬ p a) : find? p (mkArray n a) = none := by
simp [find?_mkArray, h]
@[deprecated find?_replicate_of_size_pos (since := "2025-03-18")]
abbrev find?_mkArray_of_length_pos := @find?_replicate_of_size_pos
@[simp] theorem find?_replicate_of_pos (h : p a) :
find? p (replicate n a) = if n = 0 then none else some a := by
simp [find?_replicate, h]
@[deprecated find?_replicate_of_pos (since := "2025-03-18")]
abbrev find?_mkArray_of_pos := @find?_replicate_of_pos
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
simp [find?_replicate, h]
@[deprecated find?_replicate_of_neg (since := "2025-03-18")]
abbrev find?_mkArray_of_neg := @find?_replicate_of_neg
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
theorem find?_mkArray_eq_none {n : Nat} {a : α} {p : α Bool} :
(mkArray n a).find? p = none n = 0 !p a := by
simp [ List.toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α Bool} :
(replicate n a).find? p = none n = 0 !p a := by
simp [ List.toArray_replicate, List.find?_replicate_eq_none_iff, Classical.or_iff_not_imp_left]
@[simp] theorem find?_mkArray_eq_some {n : Nat} {a b : α} {p : α Bool} :
(mkArray n a).find? p = some b n 0 p a a = b := by
@[deprecated find?_replicate_eq_none_iff (since := "2025-03-18")]
abbrev find?_mkArray_eq_none_iff := @find?_replicate_eq_none_iff
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α Bool} :
(replicate n a).find? p = some b n 0 p a a = b := by
simp [ List.toArray_replicate]
@[simp] theorem get_find?_mkArray (n : Nat) (a : α) (p : α Bool) (h) :
((mkArray n a).find? p).get h = a := by
@[deprecated find?_replicate_eq_some_iff (since := "2025-03-18")]
abbrev find?_mkArray_eq_some_iff := @find?_replicate_eq_some_iff
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
abbrev find?_mkArray_eq_some := @find?_replicate_eq_some_iff
@[simp] theorem get_find?_replicate (n : Nat) (a : α) (p : α Bool) (h) :
((replicate n a).find? p).get h = a := by
simp [ List.toArray_replicate]
@[deprecated get_find?_replicate (since := "2025-03-18")]
abbrev get_find?_mkArray := @get_find?_replicate
theorem find?_pmap {P : α Prop} (f : (a : α) P a β) (xs : Array α)
(H : (a : α), a xs P a) (p : β Bool) :
(xs.pmap f H).find? p = (xs.attach.find? (fun a, m => p (f a (H a m)))).map fun a, m => f a (H a m) := by
simp only [pmap_eq_map_attach, find?_map]
rfl
theorem find?_eq_some_iff_getElem {xs : Array α} {p : α Bool} {b : α} :
xs.find? p = some b p b i h, xs[i] = b j : Nat, (hj : j < i) !p xs[j] := by
rcases xs with xs
simp [List.find?_eq_some_iff_getElem]
/-! ### findIdx -/
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
rcases xs with xs
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
theorem findIdx_getElem {xs : Array α} {w : xs.findIdx p < xs.size} :
p xs[xs.findIdx p] :=
xs.findIdx_of_getElem?_eq_some (getElem?_eq_getElem w)
theorem findIdx_lt_size_of_exists {xs : Array α} (h : x xs, p x) :
xs.findIdx p < xs.size := by
rcases xs with xs
simpa using List.findIdx_lt_length_of_exists (by simpa using h)
theorem findIdx_getElem?_eq_getElem_of_exists {xs : Array α} (h : x xs, p x) :
xs[xs.findIdx p]? = some (xs[xs.findIdx p]'(xs.findIdx_lt_size_of_exists h)) :=
getElem?_eq_getElem (findIdx_lt_size_of_exists h)
@[simp]
theorem findIdx_eq_size {p : α Bool} {xs : Array α} :
xs.findIdx p = xs.size x xs, p x = false := by
rcases xs with xs
simp
theorem findIdx_eq_size_of_false {p : α Bool} {xs : Array α} (h : x xs, p x = false) :
xs.findIdx p = xs.size := by
rcases xs with xs
simp_all
theorem findIdx_le_size (p : α Bool) {xs : Array α} : xs.findIdx p xs.size := by
by_cases e : x xs, p x
· exact Nat.le_of_lt (findIdx_lt_size_of_exists e)
· simp at e
exact Nat.le_of_eq (findIdx_eq_size.mpr e)
@[simp]
theorem findIdx_lt_size {p : α Bool} {xs : Array α} :
xs.findIdx p < xs.size x xs, p x := by
rcases xs with xs
simp
/-- `p` does not hold for elements with indices less than `xs.findIdx p`. -/
theorem not_of_lt_findIdx {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.findIdx p) :
p (xs[i]'(Nat.le_trans h (findIdx_le_size p))) = false := by
rcases xs with xs
simpa using List.not_of_lt_findIdx (by simpa using h)
/-- If `¬ p xs[j]` for all `j < i`, then `i ≤ xs.findIdx p`. -/
theorem le_findIdx_of_not {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
(h2 : j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false) : i xs.findIdx p := by
apply Decidable.byContradiction
intro f
simp only [Nat.not_le] at f
exact absurd (@findIdx_getElem _ p xs (Nat.lt_trans f h)) (by simpa using h2 (xs.findIdx p) f)
/-- If `¬ p xs[j]` for all `j ≤ i`, then `i < xs.findIdx p`. -/
theorem lt_findIdx_of_not {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
(h2 : j (hji : j i), ¬p (xs[j]'(Nat.lt_of_le_of_lt hji h))) : i < xs.findIdx p := by
apply Decidable.byContradiction
intro f
simp only [Nat.not_lt] at f
exact absurd (@findIdx_getElem _ p xs (Nat.lt_of_le_of_lt f h)) (h2 (xs.findIdx p) f)
/-- `xs.findIdx p = i` iff `p xs[i]` and `¬ p xs [j]` for all `j < i`. -/
theorem findIdx_eq {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.size) :
xs.findIdx p = i p xs[i] j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false := by
refine fun f f (@findIdx_getElem _ p xs (f h)), fun _ hji not_of_lt_findIdx (f hji),
fun _, h2 ?_
apply Nat.le_antisymm _ (le_findIdx_of_not h h2)
apply Decidable.byContradiction
intro h3
simp at h3
simp_all [not_of_lt_findIdx h3]
theorem findIdx_append (p : α Bool) (xs ys : Array α) :
(xs ++ ys).findIdx p =
if xs.findIdx p < xs.size then xs.findIdx p else ys.findIdx p + xs.size := by
rcases xs with xs
rcases ys with ys
simp [List.findIdx_append]
theorem findIdx_le_findIdx {xs : Array α} {p q : α Bool} (h : x xs, p x q x) : xs.findIdx q xs.findIdx p := by
rcases xs with xs
simp_all [List.findIdx_le_findIdx]
@[simp] theorem findIdx_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findIdx f = xs.unattach.findIdx g := by
cases xs
simp [hf]
theorem false_of_mem_extract_findIdx {xs : Array α} {p : α Bool} (h : x xs.extract 0 (xs.findIdx p)) :
p x = false := by
rcases xs with xs
exact List.false_of_mem_take_findIdx (by simpa using h)
@[simp] theorem findIdx_extract {xs : Array α} {i : Nat} {p : α Bool} :
(xs.extract 0 i).findIdx p = min i (xs.findIdx p) := by
cases xs
simp
@[simp] theorem min_findIdx_findIdx {xs : Array α} {p q : α Bool} :
min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a) := by
cases xs
simp
/-! ### findIdx? -/
@[simp] theorem findIdx?_empty : (#[] : Array α).findIdx? p = none := by simp
@[simp]
theorem findIdx?_eq_none_iff {xs : Array α} {p : α Bool} :
xs.findIdx? p = none x, x xs p x = false := by
rcases xs with xs
simp
theorem findIdx?_isSome {xs : Array α} {p : α Bool} :
(xs.findIdx? p).isSome = xs.any p := by
rcases xs with xs
simp [List.findIdx?_isSome]
theorem findIdx?_isNone {xs : Array α} {p : α Bool} :
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
rcases xs with xs
simp [List.findIdx?_isNone]
theorem findIdx?_eq_some_iff_findIdx_eq {xs : Array α} {p : α Bool} {i : Nat} :
xs.findIdx? p = some i i < xs.size xs.findIdx p = i := by
rcases xs with xs
simp [List.findIdx?_eq_some_iff_findIdx_eq]
theorem findIdx?_eq_some_of_exists {xs : Array α} {p : α Bool} (h : x, x xs p x) :
xs.findIdx? p = some (xs.findIdx p) := by
rw [findIdx?_eq_some_iff_findIdx_eq]
exact findIdx_lt_size_of_exists h, rfl
theorem findIdx?_eq_none_iff_findIdx_eq {xs : Array α} {p : α Bool} :
xs.findIdx? p = none xs.findIdx p = xs.size := by
rcases xs with xs
simp [List.findIdx?_eq_none_iff_findIdx_eq]
theorem findIdx?_eq_guard_findIdx_lt {xs : Array α} {p : α Bool} :
xs.findIdx? p = Option.guard (fun i => i < xs.size) (xs.findIdx p) := by
rcases xs with xs
simp [List.findIdx?_eq_guard_findIdx_lt]
theorem findIdx?_eq_some_iff_getElem {xs : Array α} {p : α Bool} {i : Nat} :
xs.findIdx? p = some i
h : i < xs.size, p xs[i] j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji h)) := by
rcases xs with xs
simp [List.findIdx?_eq_some_iff_getElem]
theorem of_findIdx?_eq_some {xs : Array α} {p : α Bool} (w : xs.findIdx? p = some i) :
match xs[i]? with | some a => p a | none => false := by
rcases xs with xs
simpa using List.of_findIdx?_eq_some (by simpa using w)
theorem of_findIdx?_eq_none {xs : Array α} {p : α Bool} (w : xs.findIdx? p = none) :
i : Nat, match xs[i]? with | some a => ¬ p a | none => true := by
rcases xs with xs
simpa using List.of_findIdx?_eq_none (by simpa using w)
@[simp] theorem findIdx?_map (f : β α) (xs : Array β) : findIdx? p (xs.map f) = xs.findIdx? (p f) := by
rcases xs with xs
simp [List.findIdx?_map]
@[simp] theorem findIdx?_append :
(xs ++ ys : Array α).findIdx? p =
(xs.findIdx? p).or ((ys.findIdx? p).map fun i => i + xs.size) := by
rcases xs with xs
rcases ys with ys
simp [List.findIdx?_append]
theorem findIdx?_flatten {xss : Array (Array α)} {p : α Bool} :
xss.flatten.findIdx? p =
(xss.findIdx? (·.any p)).map
fun i => ((xss.take i).map Array.size).sum +
(xss[i]?.map fun xs => xs.findIdx p).getD 0 := by
cases xss using array₂_induction
simp [List.findIdx?_flatten, Function.comp_def]
@[simp] theorem findIdx?_replicate :
(replicate n a).findIdx? p = if 0 < n p a then some 0 else none := by
rw [ List.toArray_replicate]
simp only [List.findIdx?_toArray]
simp
@[deprecated findIdx?_replicate (since := "2025-03-18")]
abbrev findIdx?_mkArray := @findIdx?_replicate
theorem findIdx?_eq_findSome?_zipIdx {xs : Array α} {p : α Bool} :
xs.findIdx? p = xs.zipIdx.findSome? fun a, i => if p a then some i else none := by
rcases xs with xs
simp [List.findIdx?_eq_findSome?_zipIdx]
theorem findIdx?_eq_fst_find?_zipIdx {xs : Array α} {p : α Bool} :
xs.findIdx? p = (xs.zipIdx.find? fun x, _ => p x).map (·.2) := by
rcases xs with xs
simp [List.findIdx?_eq_fst_find?_zipIdx]
-- See also `findIdx_le_findIdx`.
theorem findIdx?_eq_none_of_findIdx?_eq_none {xs : Array α} {p q : α Bool} (w : x xs, p x q x) :
xs.findIdx? q = none xs.findIdx? p = none := by
rcases xs with xs
simpa using List.findIdx?_eq_none_of_findIdx?_eq_none (by simpa using w)
theorem findIdx_eq_getD_findIdx? {xs : Array α} {p : α Bool} :
xs.findIdx p = (xs.findIdx? p).getD xs.size := by
rcases xs with xs
simp [List.findIdx_eq_getD_findIdx?]
theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α Bool} (w : x xs, p x q x) {i : Nat}
(h : xs.findIdx? p = some i) : j, j i xs.findIdx? q = some j := by
rcases xs with xs
simp [List.findIdx?_eq_some_le_of_findIdx?_eq_some (by simpa using w) (by simpa using h)]
@[simp] theorem findIdx?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findIdx? f = xs.unattach.findIdx? g := by
cases xs
simp [hf]
@[simp] theorem findIdx?_take {xs : Array α} {i : Nat} {p : α Bool} :
(xs.take i).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun j => j < i)) := by
cases xs
simp
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_empty {p : α Bool} : findFinIdx? p #[] = none := by simp
-- We can't mark this as a `@[congr]` lemma since the head of the RHS is not `findFinIdx?`.
theorem findFinIdx?_congr {p : α Bool} {xs ys : Array α} (w : xs = ys) :
findFinIdx? p xs = (findFinIdx? p ys).map (fun i => i.cast (by simp [w])) := by
subst w
simp
theorem findFinIdx?_eq_pmap_findIdx? {xs : Array α} {p : α Bool} :
xs.findFinIdx? p =
(xs.findIdx? p).pmap
(fun i m => by simp [findIdx?_eq_some_iff_getElem] at m; exact i, m.choose)
(fun i h => h) := by
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
@[simp] theorem findFinIdx?_eq_none_iff {xs : Array α} {p : α Bool} :
xs.findFinIdx? p = none x, x xs ¬ p x := by
simp [findFinIdx?_eq_pmap_findIdx?]
@[simp]
theorem findFinIdx?_eq_some_iff {xs : Array α} {p : α Bool} {i : Fin xs.size} :
xs.findFinIdx? p = some i
p xs[i] j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji i.2)) := by
simp only [findFinIdx?_eq_pmap_findIdx?, Option.pmap_eq_some_iff, findIdx?_eq_some_iff_getElem,
Bool.not_eq_true, Option.mem_def, exists_and_left, and_exists_self, Fin.getElem_fin]
constructor
· rintro a, h, w₁, w₂, rfl
exact w₁, fun j hji => by simpa using w₂ j hji
· rintro h, w
exact i, i.2, h, fun j hji => w j, by omega hji, rfl
@[simp] theorem findFinIdx?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findFinIdx? f = (xs.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
cases xs
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
rw [findFinIdx?_congr List.unattach_toArray]
simp [Function.comp_def]
/-! ### idxOf
The verification API for `idxOf` is still incomplete.
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
-/
theorem idxOf_append [BEq α] [LawfulBEq α] {xs ys : Array α} {a : α} :
(xs ++ ys).idxOf a = if a xs then xs.idxOf a else ys.idxOf a + xs.size := by
rw [idxOf, findIdx_append]
split <;> rename_i h
· rw [if_pos]
simpa using h
· rw [if_neg]
simpa using h
theorem idxOf_eq_size [BEq α] [LawfulBEq α] {xs : Array α} (h : a xs) : xs.idxOf a = xs.size := by
rcases xs with xs
simp [List.idxOf_eq_length (by simpa using h)]
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {xs : Array α} (h : a xs) : xs.idxOf a < xs.size := by
rcases xs with xs
simp [List.idxOf_lt_length (by simpa using h)]
/-! ### idxOf?
The verification API for `idxOf?` is still incomplete.
The lemmas below should be made consistent with those for `findIdx?` (and proved using them).
-/
@[simp] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := by simp
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.idxOf? a = none a xs := by
rcases xs with xs
simp [List.idxOf?_eq_none_iff]
/-! ### finIdxOf?
The verification API for `finIdxOf?` is still incomplete.
The lemmas below should be made consistent with those for `findFinIdx?` (and proved using them).
-/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by simp
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.finIdxOf? a = none a xs := by
rcases xs with xs
simp [List.finIdxOf?_eq_none_iff]
@[simp] theorem finIdxOf?_eq_some_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} {i : Fin xs.size} :
xs.finIdxOf? a = some i xs[i] = a j (_ : j < i), ¬xs[j] = a := by
rcases xs with xs
simp [List.finIdxOf?_eq_some_iff]
end Array

View File

@@ -7,40 +7,43 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### getLit -/
-- auxiliary declaration used in the equation compiler when pattern matching array literals.
abbrev getLit {α : Type u} {n : Nat} (a : Array α) (i : Nat) (h₁ : a.size = n) (h₂ : i < n) : α :=
abbrev getLit {α : Type u} {n : Nat} (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : α :=
have := h₁.symm h₂
a[i]
xs[i]
theorem extLit {n : Nat}
(a b : Array α)
(hsz₁ : a.size = n) (hsz₂ : b.size = n)
(h : (i : Nat) (hi : i < n) a.getLit i hsz₁ hi = b.getLit i hsz₂ hi) : a = b :=
Array.ext a b (hsz₁.trans hsz₂.symm) fun i hi₁ _ => h i (hsz₁ hi₁)
(xs ys : Array α)
(hsz₁ : xs.size = n) (hsz₂ : ys.size = n)
(h : (i : Nat) (hi : i < n) xs.getLit i hsz₁ hi = ys.getLit i hsz₂ hi) : xs = ys :=
Array.ext xs ys (hsz₁.trans hsz₂.symm) fun i hi₁ _ => h i (hsz₁ hi₁)
def toListLitAux (a : Array α) (n : Nat) (hsz : a.size = n) : (i : Nat), i a.size List α List α
def toListLitAux (xs : Array α) (n : Nat) (hsz : xs.size = n) : (i : Nat), i xs.size List α List α
| 0, _, acc => acc
| (i+1), hi, acc => toListLitAux a n hsz i (Nat.le_of_succ_le hi) (a.getLit i hsz (Nat.lt_of_lt_of_eq (Nat.lt_of_lt_of_le (Nat.lt_succ_self i) hi) hsz) :: acc)
| (i+1), hi, acc => toListLitAux xs n hsz i (Nat.le_of_succ_le hi) (xs.getLit i hsz (Nat.lt_of_lt_of_eq (Nat.lt_of_lt_of_le (Nat.lt_succ_self i) hi) hsz) :: acc)
def toArrayLit (a : Array α) (n : Nat) (hsz : a.size = n) : Array α :=
List.toArray <| toListLitAux a n hsz n (hsz Nat.le_refl _) []
def toArrayLit (xs : Array α) (n : Nat) (hsz : xs.size = n) : Array α :=
List.toArray <| toListLitAux xs n hsz n (hsz Nat.le_refl _) []
theorem toArrayLit_eq (as : Array α) (n : Nat) (hsz : as.size = n) : as = toArrayLit as n hsz := by
theorem toArrayLit_eq (xs : Array α) (n : Nat) (hsz : xs.size = n) : xs = toArrayLit xs n hsz := by
apply ext'
simp [toArrayLit, toList_toArray]
have hle : n as.size := hsz Nat.le_refl _
have hge : as.size n := hsz Nat.le_refl _
simp [toArrayLit, List.toList_toArray]
have hle : n xs.size := hsz Nat.le_refl _
have hge : xs.size n := hsz Nat.le_refl _
have := go n hle
rw [List.drop_eq_nil_of_le hge] at this
rw [this]
where
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.toList i ((id (α := as.toList.length = n) h₁) h₂) :=
getLit_eq (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : xs.getLit i h₁ h₂ = getElem xs.toList i ((id (α := xs.toList.length = n) h₁) h₂) :=
rfl
go (i : Nat) (hi : i as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
go (i : Nat) (hi : i xs.size) : toListLitAux xs n hsz i hi (xs.toList.drop i) = xs.toList := by
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
end Array

View File

@@ -0,0 +1,132 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.InsertIdx
/-!
# insertIdx
Proves various lemmas about `Array.insertIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Function
open Nat
namespace Array
universe u
variable {α : Type u}
section InsertIdx
variable {a : α}
@[simp] theorem toList_insertIdx (xs : Array α) (i x) (h) :
(xs.insertIdx i x h).toList = xs.toList.insertIdx i x := by
rcases xs with xs
simp
@[simp]
theorem insertIdx_zero (xs : Array α) (x : α) : xs.insertIdx 0 x = #[x] ++ xs := by
rcases xs with xs
simp
@[simp] theorem size_insertIdx {xs : Array α} (h : i xs.size) : (xs.insertIdx i a).size = xs.size + 1 := by
rcases xs with xs
simp [List.length_insertIdx, h]
theorem eraseIdx_insertIdx (i : Nat) (xs : Array α) (h : i xs.size) :
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
rcases xs with xs
simp_all
theorem insertIdx_eraseIdx_of_ge {as : Array α}
(w₁ : i < as.size) (w₂ : j (as.eraseIdx i).size) (h : i j) :
(as.eraseIdx i).insertIdx j a =
(as.insertIdx (j + 1) a (by simp at w₂; omega)).eraseIdx i (by simp_all; omega) := by
cases as
simpa using List.insertIdx_eraseIdx_of_ge _ _ _ (by simpa) (by simpa)
theorem insertIdx_eraseIdx_of_le {as : Array α}
(w₁ : i < as.size) (w₂ : j (as.eraseIdx i).size) (h : j i) :
(as.eraseIdx i).insertIdx j a =
(as.insertIdx j a (by simp at w₂; omega)).eraseIdx (i + 1) (by simp_all) := by
cases as
simpa using List.insertIdx_eraseIdx_of_le _ _ _ (by simpa) (by simpa)
theorem insertIdx_comm (a b : α) (i j : Nat) (xs : Array α) (_ : i j) (_ : j xs.size) :
(xs.insertIdx i a).insertIdx (j + 1) b (by simpa) =
(xs.insertIdx j b).insertIdx i a (by simp; omega) := by
rcases xs with xs
simpa using List.insertIdx_comm a b i j _ (by simpa) (by simpa)
theorem mem_insertIdx {xs : Array α} {h : i xs.size} : a xs.insertIdx i b h a = b a xs := by
rcases xs with xs
simpa using List.mem_insertIdx (by simpa)
@[simp]
theorem insertIdx_size_self (xs : Array α) (x : α) : xs.insertIdx xs.size x = xs.push x := by
rcases xs with xs
simp
theorem getElem_insertIdx {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < (xs.insertIdx i x).size) :
(xs.insertIdx i x)[k] =
if h₁ : k < i then
xs[k]'(by simp [size_insertIdx] at h; omega)
else
if h₂ : k = i then
x
else
xs[k-1]'(by simp [size_insertIdx] at h; omega) := by
cases xs
simp [List.getElem_insertIdx, w]
theorem getElem_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < i) :
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k] := by
simp [getElem_insertIdx, w, h]
theorem getElem_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i xs.size) :
(xs.insertIdx i x)[i]'(by simp; omega) = x := by
simp [getElem_insertIdx, w]
theorem getElem_insertIdx_of_gt {xs : Array α} {x : α} {i k : Nat} (w : k xs.size) (h : k > i) :
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k - 1]'(by omega) := by
simp [getElem_insertIdx, w, h]
rw [dif_neg (by omega), dif_neg (by omega)]
theorem getElem?_insertIdx {xs : Array α} {x : α} {i k : Nat} (h : i xs.size) :
(xs.insertIdx i x)[k]? =
if k < i then
xs[k]?
else
if k = i then
if k xs.size then some x else none
else
xs[k-1]? := by
cases xs
simp [List.getElem?_insertIdx, h]
theorem getElem?_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < i) :
(xs.insertIdx i x)[k]? = xs[k]? := by
rw [getElem?_insertIdx, if_pos h]
theorem getElem?_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i xs.size) :
(xs.insertIdx i x)[i]? = some x := by
rw [getElem?_insertIdx, if_neg (by omega), if_pos rfl, if_pos w]
theorem getElem?_insertIdx_of_ge {xs : Array α} {x : α} {i k : Nat} (w : i < k) (h : k xs.size) :
(xs.insertIdx i x)[k]? = xs[k - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
end InsertIdx
end Array

View File

@@ -6,23 +6,32 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
@[inline] def Array.insertionSort (a : Array α) (lt : α α Bool := by exact (· < ·)) : Array α :=
traverse a 0 a.size
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
/--
Sorts an array using insertion sort.
The optional parameter `lt` specifies an ordering predicate. It defaults to `LT.lt`, which must be
decidable to be used for sorting.
-/
@[inline] def Array.insertionSort (xs : Array α) (lt : α α Bool := by exact (· < ·)) : Array α :=
traverse xs 0 xs.size
where
@[specialize] traverse (a : Array α) (i : Nat) (fuel : Nat) : Array α :=
@[specialize] traverse (xs : Array α) (i : Nat) (fuel : Nat) : Array α :=
match fuel with
| 0 => a
| 0 => xs
| fuel+1 =>
if h : i < a.size then
traverse (swapLoop a i h) (i+1) fuel
if h : i < xs.size then
traverse (swapLoop xs i h) (i+1) fuel
else
a
@[specialize] swapLoop (a : Array α) (j : Nat) (h : j < a.size) : Array α :=
xs
@[specialize] swapLoop (xs : Array α) (j : Nat) (h : j < xs.size) : Array α :=
match (generalizing := false) he:j with -- using `generalizing` because we don't want to refine the type of `h`
| 0 => a
| 0 => xs
| j'+1 =>
have h' : j' < a.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
if lt a[j] a[j'] then
swapLoop (a.swap j j') j' (by rw [size_swap]; assumption; done)
have h' : j' < xs.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
if lt xs[j] xs[j'] then
swapLoop (xs.swap j j') j' (by rw [size_swap]; assumption; done)
else
a
xs

File diff suppressed because it is too large Load Diff

View File

@@ -8,14 +8,18 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Lemmas
import Init.Data.Range
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/--
Lexicographic comparator for arrays.
Compares arrays lexicographically with respect to a comparison `lt` on their elements.
`lex as bs lt` is true if
- `bs` is larger than `as` and `as` is pairwise equivalent via `==` to the initial segment of `bs`, or
- there is an index `i` such that `lt as[i] bs[i]`, and for all `j < i`, `as[j] == bs[j]`.
Specifically, `Array.lex as bs lt` is true if
* `bs` is larger than `as` and `as` is pairwise equivalent via `==` to the initial segment of `bs`,
or
* there is an index `i` such that `lt as[i] bs[i]`, and for all `j < i`, `as[j] == bs[j]`.
-/
def lex [BEq α] (as bs : Array α) (lt : α α Bool := by exact (· < ·)) : Bool := Id.run do
for h : i in [0 : min as.size bs.size] do

View File

@@ -7,6 +7,9 @@ prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Lex
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### Lexicographic ordering -/
@@ -14,15 +17,15 @@ namespace Array
@[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] theorem lt_toList [LT α] (l₁ l₂ : Array α) : l₁.toList < l₂.toList l₁ < l₂ := Iff.rfl
@[simp] theorem le_toList [LT α] (l₁ l₂ : Array α) : l₁.toList l₂.toList 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
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 α) :
¬ l₁ l₂ l₂ < l₁ :=
Decidable.not_not
@[simp] theorem lex_empty [BEq α] {lt : α α Bool} (l : Array α) : l.lex #[] lt = false := by
@[simp] theorem lex_empty [BEq α] {lt : α α Bool} (xs : Array α) : xs.lex #[] lt = false := by
simp [lex, Id.run]
@[simp] theorem singleton_lex_singleton [BEq α] {lt : α α Bool} : #[a].lex #[b] lt = lt a b := by
@@ -33,7 +36,7 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
(#[a] ++ xs).lex (#[b] ++ ys) lt =
(lt a b || a == b && xs.lex ys lt) := by
simp only [lex, Id.run]
simp only [Std.Range.forIn'_eq_forIn'_range', size_append, size_toArray, List.length_singleton,
simp only [Std.Range.forIn'_eq_forIn'_range', size_append, List.size_toArray, List.length_singleton,
Nat.add_comm 1]
simp [Nat.add_min_add_right, List.range'_succ, getElem_append_left, List.range'_succ_left,
getElem_append_right]
@@ -52,35 +55,35 @@ 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) (l₁ l₂ : Array α) :
l₁.toList.lex l₂.toList lt = l₁.lex l₂ lt := by
cases l₁ <;> cases l₂ <;> simp
@[simp] 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
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (l : Array α) : ¬ l < l :=
List.lt_irrefl l.toList
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (xs : Array α) : ¬ xs < xs :=
List.lt_irrefl xs.toList
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Irrefl (α := Array α) (· < ·) where
irrefl := Array.lt_irrefl
@[simp] theorem not_lt_empty [LT α] (l : Array α) : ¬ l < #[] := List.not_lt_nil l.toList
@[simp] theorem empty_le [LT α] (l : Array α) : #[] l := List.nil_le l.toList
@[simp] theorem not_lt_empty [LT α] (xs : Array α) : ¬ xs < #[] := List.not_lt_nil xs.toList
@[simp] theorem empty_le [LT α] (xs : Array α) : #[] xs := List.nil_le xs.toList
@[simp] theorem le_empty [LT α] (l : Array α) : l #[] l = #[] := by
cases l
@[simp] theorem le_empty [LT α] (xs : Array α) : xs #[] xs = #[] := by
cases xs
simp
@[simp] theorem empty_lt_push [LT α] (l : Array α) (a : α) : #[] < l.push a := by
rcases l with (_ | x, l) <;> simp
@[simp] theorem empty_lt_push [LT α] (xs : Array α) (a : α) : #[] < xs.push a := by
rcases xs with (_ | x, xs) <;> simp
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (l : Array α) : l l :=
List.le_refl l.toList
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (xs : Array α) : xs xs :=
List.le_refl xs.toList
instance [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Refl (· · : Array α Array α Prop) where
refl := Array.le_refl
protected theorem lt_trans [LT α]
[i₁ : Trans (· < · : α α Prop) (· < ·) (· < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
{xs ys zs : Array α} (h₁ : xs < ys) (h₂ : ys < zs) : xs < zs :=
List.lt_trans h₁ h₂
instance [LT α] [Trans (· < · : α α Prop) (· < ·) (· < ·)] :
@@ -92,7 +95,7 @@ protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
List.lt_of_le_of_lt h₁ h₂
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
@@ -100,7 +103,7 @@ protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ l₃) : l₁ l₃ :=
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
instance [DecidableEq α] [LT α] [DecidableLT α]
@@ -113,7 +116,7 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
protected theorem lt_asymm [LT α]
[i : Std.Asymm (· < · : α α Prop)]
{l₁ l₂ : Array α} (h : l₁ < l₂) : ¬ l₂ < l₁ := List.lt_asymm h
{xs ys : Array α} (h : xs < ys) : ¬ ys < xs := List.lt_asymm h
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)] :
@@ -121,26 +124,26 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
asymm _ _ := Array.lt_asymm
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Total (¬ · < · : α α Prop)] (l₁ l₂ : Array α) : l₁ l₂ l₂ l₁ :=
List.le_total _ _
[i : Std.Total (¬ · < · : α α Prop)] (xs ys : Array α) : xs ys ys xs :=
List.le_total xs.toList ys.toList
@[simp] protected theorem not_lt [LT α]
{l₁ l₂ : Array α} : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
{xs ys : Array α} : ¬ xs < ys ys xs := Iff.rfl
@[simp] protected theorem not_le [DecidableEq α] [LT α] [DecidableLT α]
{l₁ l₂ : Array α} : ¬ l₂ l₁ l₁ < l₂ := Decidable.not_not
{xs ys : Array α} : ¬ ys xs xs < ys := Decidable.not_not
protected theorem le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Total (¬ · < · : α α Prop)]
{l₁ l₂ : Array α} (h : l₁ < l₂) : l₁ l₂ :=
{xs ys : Array α} (h : xs < ys) : xs ys :=
List.le_of_lt h
protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Total (¬ · < · : α α Prop)]
{l₁ l₂ : Array α} : l₁ l₂ l₁ < l₂ l₁ = l₂ := by
simpa using List.le_iff_lt_or_eq (l₁ := l₁.toList) (l₂ := l₂.toList)
{xs ys : Array α} : xs ys xs < ys xs = ys := by
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Total (¬ · < · : α α Prop)] :
@@ -148,22 +151,22 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
total := Array.le_total
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
{l₁ l₂ : Array α} : lex l₁ l₂ = true l₁ < l₂ := by
cases l₁
cases l₂
{xs ys : Array α} : lex xs ys = true xs < ys := by
cases xs
cases ys
simp
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
{l₁ l₂ : Array α} : lex l₁ l₂ = false l₂ l₁ := by
cases l₁
cases l₂
{xs ys : Array α} : lex xs ys = false ys xs := by
cases xs
cases ys
simp [List.not_lt_iff_ge]
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLT (Array α) :=
fun l₁ l₂ => decidable_of_iff (lex l₁ l₂ = true) lex_eq_true_iff_lt
fun xs ys => decidable_of_iff (lex xs ys = true) lex_eq_true_iff_lt
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLE (Array α) :=
fun l₁ l₂ => decidable_of_iff (lex l₂ l₁ = false) lex_eq_false_iff_ge
fun xs ys => decidable_of_iff (lex ys xs = false) lex_eq_false_iff_ge
/--
`l₁` is lexicographically less than `l₂` if either
@@ -211,58 +214,58 @@ theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : αα
cases l₂
simp_all [List.lex_eq_false_iff_exists]
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : Array α} :
l₁ < l₂
(l₁ = l₂.take l₁.size l₁.size < l₂.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {xs ys : Array α} :
xs < ys
(xs = ys.take xs.size xs.size < ys.size)
( (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
cases l₁
cases l₂
xs[j]'(Nat.lt_trans hj h₁) = ys[j]'(Nat.lt_trans hj h₂)) xs[i] < ys[i]) := by
cases xs
cases ys
simp [List.lt_iff_exists]
protected theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)] {l₁ l₂ : Array α} :
l₁ l₂
(l₁ = l₂.take l₁.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
[Std.Antisymm (¬ · < · : α α Prop)] {xs ys : Array α} :
xs ys
(xs = ys.take xs.size)
( (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
cases l₁
cases l₂
xs[j]'(Nat.lt_trans hj h₁) = ys[j]'(Nat.lt_trans hj h₂)) xs[i] < ys[i]) := by
cases xs
cases ys
simp [List.le_iff_exists]
theorem append_left_lt [LT α] {l₁ l₂ l₃ : Array α} (h : l₂ < l₃) :
l₁ ++ l₂ < l₁ ++ l₃ := by
cases l₁
cases l₂
cases l₃
theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
xs ++ ys < xs ++ zs := by
cases xs
cases ys
cases zs
simpa using List.append_left_lt h
theorem append_left_le [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
{l₁ l₂ l₃ : Array α} (h : l₂ l₃) :
l₁ ++ l₂ l₁ ++ l₃ := by
cases l₁
cases l₂
cases l₃
{xs ys zs : Array α} (h : ys zs) :
xs ++ ys xs ++ zs := by
cases xs
cases ys
cases zs
simpa using List.append_left_le h
theorem le_append_left [LT α] [Std.Irrefl (· < · : α α Prop)]
{l₁ l₂ : Array α} : l₁ l₁ ++ l₂ := by
cases l₁
cases l₂
{xs ys : Array α} : xs xs ++ ys := by
cases xs
cases ys
simpa using List.le_append_left
protected theorem map_lt [LT α] [LT β]
{l₁ l₂ : Array α} {f : α β} (w : x y, x < y f x < f y) (h : l₁ < l₂) :
map f l₁ < map f l₂ := by
cases l₁
cases l₂
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs < ys) :
map f xs < map f ys := by
cases xs
cases ys
simpa using List.map_lt w h
protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq β] [LT β] [DecidableLT β]
@@ -272,10 +275,10 @@ protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq
[Std.Irrefl (· < · : β β Prop)]
[Std.Asymm (· < · : β β Prop)]
[Std.Antisymm (¬ · < · : β β Prop)]
{l₁ l₂ : Array α} {f : α β} (w : x y, x < y f x < f y) (h : l₁ l₂) :
map f l₁ map f l₂ := by
cases l₁
cases l₂
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs ys) :
map f xs map f ys := by
cases xs
cases ys
simpa using List.map_le w h
end Array

View File

@@ -5,103 +5,111 @@ Authors: Mario Carneiro, Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.Array.Attach
import Init.Data.Array.OfFn
import Init.Data.List.MapIdx
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### mapFinIdx -/
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
theorem mapFinIdx_induction (as : Array α) (f : Fin as.size α β)
theorem mapFinIdx_induction (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β)
(motive : Nat Prop) (h0 : motive 0)
(p : Fin as.size β Prop)
(hs : i, motive i.1 p i (f i as[i]) motive (i + 1)) :
motive as.size eq : (Array.mapFinIdx as f).size = as.size,
i h, p i, h ((Array.mapFinIdx as f)[i]) := by
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : i h h', p i, h bs[i]) (hm : motive j) :
let arr : Array β := Array.mapFinIdxM.map (m := Id) as f i j h bs
motive as.size eq : arr.size = as.size, i h, p i, h arr[i] := by
(p : (i : Nat) β (h : i < xs.size) Prop)
(hs : i h, motive i p i (f i xs[i] h) h motive (i + 1)) :
motive xs.size eq : (Array.mapFinIdx xs f).size = xs.size,
i h, p i ((Array.mapFinIdx xs f)[i]) h := by
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : i h h', p i bs[i] h) (hm : motive j) :
let as : Array β := Array.mapFinIdxM.map (m := Id) xs f i j h bs
motive xs.size eq : as.size = xs.size, i h, p i as[i] h := by
induction i generalizing j bs with simp [mapFinIdxM.map]
| zero =>
have := (Nat.zero_add _).symm.trans h
exact this hm, h₁ this, fun _ _ => h₂ ..
| succ i ih =>
apply @ih (bs.push (f j, by omega as[j])) (j + 1) (by omega) (by simp; omega)
apply @ih (bs.push (f j xs[j] (by omega))) (j + 1) (by omega) (by simp; omega)
· intro i i_lt h'
rw [getElem_push]
split
· apply h₂
· simp only [size_push] at h'
obtain rfl : i = j := by omega
apply (hs i, by omega hm).1
· exact (hs j, by omega hm).2
apply (hs i (by omega) hm).1
· exact (hs j (by omega) hm).2
simp [mapFinIdx, mapFinIdxM]; exact go rfl nofun h0
theorem mapFinIdx_spec (as : Array α) (f : Fin as.size α β)
(p : Fin as.size β Prop) (hs : i, p i (f i as[i])) :
eq : (Array.mapFinIdx as f).size = as.size,
i h, p i, h ((Array.mapFinIdx as f)[i]) :=
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ => hs .., trivial).2
theorem mapFinIdx_spec (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β)
(p : (i : Nat) β (h : i < xs.size) Prop) (hs : i h, p i (f i xs[i] h) h) :
eq : (Array.mapFinIdx xs f).size = xs.size,
i h, p i ((Array.mapFinIdx xs f)[i]) h :=
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapFinIdx (a : Array α) (f : Fin a.size α β) : (a.mapFinIdx f).size = a.size :=
(mapFinIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
@[simp] theorem size_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) :
(xs.mapFinIdx f).size = xs.size :=
(mapFinIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
@[simp] theorem size_zipWithIndex (as : Array α) : as.zipWithIndex.size = as.size :=
@[simp] theorem size_zipIdx (xs : Array α) (k : Nat) : (xs.zipIdx k).size = xs.size :=
Array.size_mapFinIdx _ _
@[simp] theorem getElem_mapFinIdx (a : Array α) (f : Fin a.size α β) (i : Nat)
(h : i < (mapFinIdx a f).size) :
(a.mapFinIdx f)[i] = f i, by simp_all (a[i]'(by simp_all)) :=
(mapFinIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i _
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
@[simp] theorem getElem?_mapFinIdx (a : Array α) (f : Fin a.size α β) (i : Nat) :
(a.mapFinIdx f)[i]? =
a[i]?.pbind fun b h => f i, (getElem?_eq_some_iff.1 h).1 b := by
@[simp] theorem getElem_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) (i : Nat)
(h : i < (xs.mapFinIdx f).size) :
(xs.mapFinIdx f)[i] = f i (xs[i]'(by simp_all)) (by simp_all) :=
(mapFinIdx_spec _ _ (fun i b h => b = f i xs[i] h) fun _ _ => rfl).2 i _
@[simp] theorem getElem?_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) (i : Nat) :
(xs.mapFinIdx f)[i]? =
xs[i]?.pbind fun b h => f i b (getElem?_eq_some_iff.1 h).1 := by
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
split <;> simp_all
@[simp] theorem toList_mapFinIdx (a : Array α) (f : Fin a.size α β) :
(a.mapFinIdx f).toList = a.toList.mapFinIdx (fun i a => f i, by simp a) := by
@[simp] theorem toList_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) :
(xs.mapFinIdx f).toList = xs.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
apply List.ext_getElem <;> simp
/-! ### mapIdx -/
theorem mapIdx_induction (f : Nat α β) (as : Array α)
theorem mapIdx_induction (f : Nat α β) (xs : Array α)
(motive : Nat Prop) (h0 : motive 0)
(p : Fin as.size β Prop)
(hs : i, motive i.1 p i (f i as[i]) motive (i + 1)) :
motive as.size eq : (as.mapIdx f).size = as.size,
i h, p i, h ((as.mapIdx f)[i]) :=
mapFinIdx_induction as (fun i a => f i a) motive h0 p hs
(p : (i : Nat) β (h : i < xs.size) Prop)
(hs : i h, motive i p i (f i xs[i]) h motive (i + 1)) :
motive xs.size eq : (xs.mapIdx f).size = xs.size,
i h, p i ((xs.mapIdx f)[i]) h :=
mapFinIdx_induction xs (fun i a _ => f i a) motive h0 p hs
theorem mapIdx_spec (f : Nat α β) (as : Array α)
(p : Fin as.size β Prop) (hs : i, p i (f i as[i])) :
eq : (as.mapIdx f).size = as.size,
i h, p i, h ((as.mapIdx f)[i]) :=
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => hs .., trivial).2
theorem mapIdx_spec (f : Nat α β) (xs : Array α)
(p : (i : Nat) β (h : i < xs.size) Prop) (hs : i h, p i (f i xs[i]) h) :
eq : (xs.mapIdx f).size = xs.size,
i h, p i ((xs.mapIdx f)[i]) h :=
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapIdx (f : Nat α β) (as : Array α) : (as.mapIdx f).size = as.size :=
(mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
@[simp] theorem size_mapIdx (f : Nat α β) (xs : Array α) : (xs.mapIdx f).size = xs.size :=
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
@[simp] theorem getElem_mapIdx (f : Nat α β) (as : Array α) (i : Nat)
(h : i < (as.mapIdx f).size) :
(as.mapIdx f)[i] = f i (as[i]'(by simp_all)) :=
(mapIdx_spec _ _ (fun i b => b = f i as[i]) fun _ => rfl).2 i (by simp_all)
@[simp] theorem getElem_mapIdx (f : Nat α β) (xs : Array α) (i : Nat)
(h : i < (xs.mapIdx f).size) :
(xs.mapIdx f)[i] = f i (xs[i]'(by simp_all)) :=
(mapIdx_spec _ _ (fun i b h => b = f i xs[i]) fun _ _ => rfl).2 i (by simp_all)
@[simp] theorem getElem?_mapIdx (f : Nat α β) (as : Array α) (i : Nat) :
(as.mapIdx f)[i]? =
as[i]?.map (f i) := by
@[simp] theorem getElem?_mapIdx (f : Nat α β) (xs : Array α) (i : Nat) :
(xs.mapIdx f)[i]? =
xs[i]?.map (f i) := by
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
@[simp] theorem toList_mapIdx (f : Nat α β) (as : Array α) :
(as.mapIdx f).toList = as.toList.mapIdx (fun i a => f i a) := by
@[simp] theorem toList_mapIdx (f : Nat α β) (xs : Array α) :
(xs.mapIdx f).toList = xs.toList.mapIdx (fun i a => f i a) := by
apply List.ext_getElem <;> simp
end Array
namespace List
@[simp] theorem mapFinIdx_toArray (l : List α) (f : Fin l.length α β) :
@[simp] theorem mapFinIdx_toArray (l : List α) (f : (i : Nat) α (h : i < l.length) β) :
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
ext <;> simp
@@ -110,3 +118,388 @@ namespace List
ext <;> simp
end List
namespace Array
/-! ### zipIdx -/
@[simp] theorem getElem_zipIdx (xs : Array α) (k : Nat) (i : Nat) (h : i < (xs.zipIdx k).size) :
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
simp [zipIdx]
@[deprecated getElem_zipIdx (since := "2025-01-21")]
abbrev getElem_zipWithIndex := @getElem_zipIdx
@[simp] theorem zipIdx_toArray {l : List α} {k : Nat} :
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
ext i hi₁ hi₂ <;> simp [Nat.add_comm]
@[deprecated zipIdx_toArray (since := "2025-01-21")]
abbrev zipWithIndex_toArray := @zipIdx_toArray
@[simp] theorem toList_zipIdx (xs : Array α) (k : Nat) :
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
rcases xs with xs
simp
@[deprecated toList_zipIdx (since := "2025-01-21")]
abbrev toList_zipWithIndex := @toList_zipIdx
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {xs : Array α} :
(x, i) xs.zipIdx k k i xs[i - k]? = some x := by
rcases xs with xs
simp [List.mk_mem_zipIdx_iff_le_and_getElem?_sub]
/-- Variant of `mk_mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
to avoid the inequality and the subtraction. -/
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {xs : Array α} :
(x, i) xs.zipIdx xs[i]? = x := by
rw [mk_mem_zipIdx_iff_le_and_getElem?_sub]
simp
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {xs : Array α} {k : Nat} :
x xs.zipIdx k k x.2 xs[x.2 - k]? = some x.1 := by
cases x
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
/-- Variant of `mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
to avoid the inequality and the subtraction. -/
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {xs : Array α} :
x xs.zipIdx xs[x.2]? = some x.1 := by
rw [mk_mem_zipIdx_iff_getElem?]
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
abbrev mk_mem_zipWithIndex_iff_getElem? := @mk_mem_zipIdx_iff_getElem?
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-21")]
abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
/-! ### mapFinIdx -/
@[congr] theorem mapFinIdx_congr {xs ys : Array α} (w : xs = ys)
(f : (i : Nat) α (h : i < xs.size) β) :
mapFinIdx xs f = mapFinIdx ys (fun i a h => f i a (by simp [w]; omega)) := by
subst w
rfl
@[simp]
theorem mapFinIdx_empty {f : (i : Nat) α (h : i < 0) β} : mapFinIdx #[] f = #[] :=
rfl
theorem mapFinIdx_eq_ofFn {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = Array.ofFn fun i : Fin xs.size => f i xs[i] i.2 := by
cases xs
simp [List.mapFinIdx_eq_ofFn]
theorem mapFinIdx_append {xs ys : Array α} {f : (i : Nat) α (h : i < (xs ++ ys).size) β} :
(xs ++ ys).mapFinIdx f =
xs.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
ys.mapFinIdx (fun i a h => f (i + xs.size) a (by simp; omega)) := by
cases xs
cases ys
simp [List.mapFinIdx_append]
@[simp]
theorem mapFinIdx_push {xs : Array α} {a : α} {f : (i : Nat) α (h : i < (xs.push a).size) β} :
mapFinIdx (xs.push a) f =
(mapFinIdx xs (fun i a h => f i a (by simp; omega))).push (f xs.size a (by simp)) := by
simp [ append_singleton, mapFinIdx_append]
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) α (h : i < 1) β} :
#[a].mapFinIdx f = #[f 0 a (by simp)] := by
simp
theorem mapFinIdx_eq_zipIdx_map {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = xs.zipIdx.attach.map
fun x, i, m =>
f i x (by simp [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
ext <;> simp
@[deprecated mapFinIdx_eq_zipIdx_map (since := "2025-01-21")]
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
@[simp]
theorem mapFinIdx_eq_empty_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = #[] xs = #[] := by
cases xs
simp
theorem mapFinIdx_ne_empty_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f #[] xs #[] := by
simp
theorem exists_of_mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β}
(h : b xs.mapFinIdx f) : (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with xs
exact List.exists_of_mem_mapFinIdx (by simpa using h)
@[simp] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
b xs.mapFinIdx f (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with xs
simp
theorem mapFinIdx_eq_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {ys : Array β} :
xs.mapFinIdx f = ys h : ys.size = xs.size, (i : Nat) (h : i < xs.size), ys[i] = f i xs[i] h := by
rcases xs with xs
rcases ys with ys
simpa using List.mapFinIdx_eq_iff
@[simp] theorem mapFinIdx_eq_singleton_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {b : β} :
xs.mapFinIdx f = #[b] (a : α) (w : xs = #[a]), f 0 a (by simp [w]) = b := by
rcases xs with xs
simp
theorem mapFinIdx_eq_append_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {ys zs : Array β} :
xs.mapFinIdx f = ys ++ zs
(ys' : Array α) (zs' : Array α) (w : xs = ys' ++ zs'),
ys'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys
zs'.mapFinIdx (fun i a h => f (i + ys'.size) a (by simp [w]; omega)) = zs := by
rcases xs with l
rcases ys with l₁
rcases zs with l₂
simp only [List.mapFinIdx_toArray, List.append_toArray, mk.injEq, List.mapFinIdx_eq_append_iff,
toArray_eq_append_iff]
constructor
· rintro l₁, l₂, rfl, rfl, rfl
refine l₁.toArray, l₂.toArray, by simp_all
· rintro l₁, l₂, rfl, h₁, h₂
simp [ toList_inj] at h₁ h₂
obtain rfl := h₁
obtain rfl := h₂
refine l₁, l₂, by simp_all
theorem mapFinIdx_eq_push_iff {xs : Array α} {b : β} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = ys.push b
(zs : Array α) (a : α) (w : xs = zs.push a),
zs.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys b = f (xs.size - 1) a (by simp [w]) := by
rw [push_eq_append, mapFinIdx_eq_append_iff]
constructor
· rintro ys', zs', rfl, rfl, h₂
simp only [mapFinIdx_eq_singleton_iff, Nat.zero_add] at h₂
obtain a, rfl, rfl := h₂
exact ys', a, by simp
· rintro zs, a, rfl, rfl, rfl
exact zs, #[a], by simp
theorem mapFinIdx_eq_mapFinIdx_iff {xs : Array α} {f g : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = xs.mapFinIdx g (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i] h := by
rw [eq_comm, mapFinIdx_eq_iff]
simp
@[simp] theorem mapFinIdx_mapFinIdx {xs : Array α}
{f : (i : Nat) α (h : i < xs.size) β}
{g : (i : Nat) β (h : i < (xs.mapFinIdx f).size) γ} :
(xs.mapFinIdx f).mapFinIdx g = xs.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
simp [mapFinIdx_eq_iff]
theorem mapFinIdx_eq_replicate_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {b : β} :
xs.mapFinIdx f = replicate xs.size b (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with l
rw [ toList_inj]
simp [List.mapFinIdx_eq_replicate_iff]
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
abbrev mapFinIdx_eq_mkArray_iff := @mapFinIdx_eq_replicate_iff
@[simp] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) α (h : i < xs.reverse.size) β} :
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
rcases xs with l
simp [List.mapFinIdx_reverse]
/-! ### mapIdx -/
@[simp]
theorem mapIdx_empty {f : Nat α β} : mapIdx f #[] = #[] :=
rfl
@[simp] theorem mapFinIdx_eq_mapIdx {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {g : Nat α β}
(h : (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i]) :
xs.mapFinIdx f = xs.mapIdx g := by
simp_all [mapFinIdx_eq_iff]
theorem mapIdx_eq_mapFinIdx {xs : Array α} {f : Nat α β} :
xs.mapIdx f = xs.mapFinIdx (fun i a _ => f i a) := by
simp [mapFinIdx_eq_mapIdx]
theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat α β} :
xs.mapIdx f = xs.zipIdx.map fun a, i => f i a := by
ext <;> simp
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
theorem mapIdx_append {xs ys : Array α} :
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx (fun i => f (i + xs.size)) := by
rcases xs with xs
rcases ys with ys
simp [List.mapIdx_append]
@[simp]
theorem mapIdx_push {xs : Array α} {a : α} :
mapIdx f (xs.push a) = (mapIdx f xs).push (f xs.size a) := by
simp [ append_singleton, mapIdx_append]
theorem mapIdx_singleton {a : α} : mapIdx f #[a] = #[f 0 a] := by
simp
@[simp]
theorem mapIdx_eq_empty_iff {xs : Array α} : mapIdx f xs = #[] xs = #[] := by
rcases xs with xs
simp
theorem mapIdx_ne_empty_iff {xs : Array α} :
mapIdx f xs #[] xs #[] := by
simp
theorem exists_of_mem_mapIdx {b : β} {xs : Array α}
(h : b mapIdx f xs) : (i : Nat) (h : i < xs.size), f i xs[i] = b := by
rw [mapIdx_eq_mapFinIdx] at h
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
@[simp] theorem mem_mapIdx {b : β} {xs : Array α} :
b mapIdx f xs (i : Nat) (h : i < xs.size), f i xs[i] = b := by
constructor
· intro h
exact exists_of_mem_mapIdx h
· rintro i, h, rfl
rw [mem_iff_getElem]
exact i, by simpa using h, by simp
theorem mapIdx_eq_push_iff {xs : Array α} {b : β} :
mapIdx f xs = ys.push b
(a : α) (zs : Array α), xs = zs.push a mapIdx f zs = ys f zs.size a = b := by
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_push_iff]
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
constructor
· rintro zs, rfl, a, rfl, rfl
exact a, zs, by simp
· rintro a, zs, rfl, rfl, rfl
exact zs, rfl, a, by simp
@[simp] theorem mapIdx_eq_singleton_iff {xs : Array α} {f : Nat α β} {b : β} :
mapIdx f xs = #[b] (a : α), xs = #[a] f 0 a = b := by
rcases xs with xs
simp [List.mapIdx_eq_singleton_iff]
theorem mapIdx_eq_append_iff {xs : Array α} {f : Nat α β} {ys zs : Array β} :
mapIdx f xs = ys ++ zs
(xs' : Array α) (zs' : Array α), xs = xs' ++ zs'
xs'.mapIdx f = ys
zs'.mapIdx (fun i => f (i + xs'.size)) = zs := by
rcases xs with xs
rcases ys with ys
rcases zs with zs
simp only [List.mapIdx_toArray, List.append_toArray, mk.injEq, List.mapIdx_eq_append_iff,
toArray_eq_append_iff]
constructor
· rintro l₁, l₂, rfl, rfl, rfl
exact l₁.toArray, l₂.toArray, by simp
· rintro l₁, l₂, rfl, h₁, h₂
simp only [List.mapIdx_toArray, mk.injEq, List.size_toArray] at h₁ h₂
obtain rfl := h₁
obtain rfl := h₂
exact l₁, l₂, by simp
theorem mapIdx_eq_iff {xs : Array α} : mapIdx f xs = ys i : Nat, ys[i]? = xs[i]?.map (f i) := by
rcases xs with xs
rcases ys with ys
simp [List.mapIdx_eq_iff]
theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
mapIdx f xs = mapIdx g xs i : Nat, (h : i < xs.size) f i xs[i] = g i xs[i] := by
rcases xs with xs
simp [List.mapIdx_eq_mapIdx_iff]
@[simp] theorem mapIdx_set {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
(xs.set i a).mapIdx f = (xs.mapIdx f).set i (f i a) (by simpa) := by
rcases xs with xs
simp [List.mapIdx_set]
@[simp] theorem mapIdx_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
(xs.setIfInBounds i a).mapIdx f = (xs.mapIdx f).setIfInBounds i (f i a) := by
rcases xs with xs
simp [List.mapIdx_set]
@[simp] theorem back?_mapIdx {xs : Array α} {f : Nat α β} :
(mapIdx f xs).back? = (xs.back?).map (f (xs.size - 1)) := by
rcases xs with xs
simp [List.getLast?_mapIdx]
@[simp] theorem back_mapIdx {xs : Array α} {f : Nat α β} (h) :
(xs.mapIdx f).back h = f (xs.size - 1) (xs.back (by simpa using h)) := by
rcases xs with xs
simp [List.getLast_mapIdx]
@[simp] theorem mapIdx_mapIdx {xs : Array α} {f : Nat α β} {g : Nat β γ} :
(xs.mapIdx f).mapIdx g = xs.mapIdx (fun i => g i f i) := by
simp [mapIdx_eq_iff]
theorem mapIdx_eq_replicate_iff {xs : Array α} {f : Nat α β} {b : β} :
mapIdx f xs = replicate xs.size b (i : Nat) (h : i < xs.size), f i xs[i] = b := by
rcases xs with xs
rw [ toList_inj]
simp [List.mapIdx_eq_replicate_iff]
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
abbrev mapIdx_eq_mkArray_iff := @mapIdx_eq_replicate_iff
@[simp] theorem mapIdx_reverse {xs : Array α} {f : Nat α β} :
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
rcases xs with xs
simp [List.mapIdx_reverse]
end Array
namespace List
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) :
Array.mapFinIdxM.map l.toArray f i acc.size inv acc
= toArray <$> mapFinIdxM.go l f (l.drop acc.size) acc
(by simp [Nat.sub_add_cancel (Nat.le.intro (Nat.add_comm _ _ inv))]) := by
match i with
| 0 =>
rw [Nat.zero_add] at inv
simp only [Array.mapFinIdxM.map, inv, drop_length, mapFinIdxM.go, map_pure]
| k + 1 =>
conv => enter [2, 2, 3]; rw [ getElem_cons_drop l acc.size (by omega)]
simp only [Array.mapFinIdxM.map, mapFinIdxM.go, _root_.map_bind]
congr; funext x
conv => enter [1, 4]; rw [ Array.size_push _ x]
conv => enter [2, 2, 3]; rw [ Array.size_push _ x]
refine go k (acc.push x) _
simp only [Array.mapFinIdxM, mapFinIdxM]
exact go _ #[] _
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) :
mapFinIdxM.go l (fun i a h => f i a) bs acc inv = mapIdxM.go f bs acc := by
match bs with
| [] => simp only [mapFinIdxM.go, mapIdxM.go]
| x :: xs => simp only [mapFinIdxM.go, mapIdxM.go, go]
unfold Array.mapIdxM
rw [mapFinIdxM_toArray]
simp only [mapFinIdxM, mapIdxM]
rw [go]
end List
namespace Array
theorem toList_mapFinIdxM [Monad m] [LawfulMonad m] (xs : Array α)
(f : (i : Nat) α (h : i < xs.size) m β) :
toList <$> xs.mapFinIdxM f = xs.toList.mapFinIdxM f := by
rw [List.mapFinIdxM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_mapIdxM [Monad m] [LawfulMonad m] (xs : Array α)
(f : Nat α m β) :
toList <$> xs.mapIdxM f = xs.toList.mapIdxM f := by
rw [List.mapIdxM_toArray]
simp only [Functor.map_map, id_map']
end Array

View File

@@ -8,15 +8,18 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Linear
import Init.Data.List.BasicAux
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a as) : sizeOf a < sizeOf as := by
cases as with | _ as =>
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp_arith)
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp +arith)
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf (as.get i h) < sizeOf as := by
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf as[i] < sizeOf as := by
cases as with | _ as =>
simpa using Nat.lt_trans (List.sizeOf_get _ i, h) (by simp_arith)
simpa using Nat.lt_trans (List.sizeOf_get _ i, h) (by simp +arith)
@[simp] theorem sizeOf_getElem [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) :
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _ h
@@ -29,8 +32,8 @@ macro "array_get_dec" : tactic =>
-- subsumed by simp
-- | with_reducible apply sizeOf_get
-- | with_reducible apply sizeOf_getElem
| (with_reducible apply Nat.lt_of_lt_of_le (sizeOf_get ..)); simp_arith
| (with_reducible apply Nat.lt_of_lt_of_le (sizeOf_getElem ..)); simp_arith
| (with_reducible apply Nat.lt_of_lt_of_le (sizeOf_get ..)); simp +arith
| (with_reducible apply Nat.lt_of_lt_of_le (sizeOf_getElem ..)); simp +arith
)
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_get_dec)
@@ -45,7 +48,7 @@ macro "array_mem_dec" : tactic =>
| with_reducible
apply Nat.lt_of_lt_of_le (Array.sizeOf_lt_of_mem ?h)
case' h => assumption
simp_arith)
simp +arith)
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_mem_dec)

View File

@@ -12,6 +12,9 @@ import Init.Data.List.Monadic
# Lemmas about `Array.forIn'` and `Array.forIn`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -20,76 +23,116 @@ open Nat
/-! ### mapM -/
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α m β) (l : Array α) :
mapM f l = l.foldlM (fun acc a => return (acc.push ( f a))) #[] := by
rcases l with l
simp only [List.mapM_toArray, bind_pure_comp, size_toArray, List.foldlM_toArray']
@[simp] theorem mapM_pure [Monad m] [LawfulMonad m] (xs : Array α) (f : α β) :
xs.mapM (m := m) (pure <| f ·) = pure (xs.map f) := by
induction xs; simp_all
@[simp] theorem mapM_id {xs : Array α} {f : α Id β} : xs.mapM f = xs.map f :=
mapM_pure _ _
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] (f : α m β) {xs ys : Array α} :
(xs ++ ys).mapM f = (return ( xs.mapM f) ++ ( ys.mapM f)) := by
rcases xs with xs
rcases ys with ys
simp
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α m β) (xs : Array α) :
mapM f xs = xs.foldlM (fun acc a => return (acc.push ( f a))) #[] := by
rcases xs with xs
simp only [List.mapM_toArray, bind_pure_comp, List.size_toArray, List.foldlM_toArray']
rw [List.mapM_eq_reverse_foldlM_cons]
simp only [bind_pure_comp, Functor.map_map]
suffices (k), (fun a => a.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) k l =
List.foldlM (fun acc a => acc.push <$> f a) k.reverse.toArray l by
suffices (l), (fun l' => l'.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) l xs =
List.foldlM (fun acc a => acc.push <$> f a) l.reverse.toArray xs by
exact this []
intro k
induction l generalizing k with
intro l
induction xs generalizing l with
| nil => simp
| cons a as ih =>
simp [ih, List.foldlM_cons]
/-! ### foldlM and foldrM -/
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (l : Array β₁) (init : α) :
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
cases l
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (xs : Array β₁) (init : α) (w : stop = xs.size) :
(xs.map f).foldlM g init 0 stop = xs.foldlM (fun x y => g x (f y)) init 0 stop := by
subst w
cases xs
simp [List.foldlM_map]
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (l : Array β₁)
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
cases l
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (xs : Array β₁)
(init : α) (w : start = xs.size) :
(xs.map f).foldrM g init start 0 = xs.foldrM (fun x y => g (f x) y) init start 0 := by
subst w
cases xs
simp [List.foldrM_map]
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : γ β m γ) (l : Array α) (init : γ) :
(l.filterMap f).foldlM g init =
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
cases l
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : γ β m γ)
(xs : Array α) (init : γ) (w : stop = (xs.filterMap f).size) :
(xs.filterMap f).foldlM g init 0 stop =
xs.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
subst w
cases xs
simp [List.foldlM_filterMap]
rfl
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : β γ m γ) (l : Array α) (init : γ) :
(l.filterMap f).foldrM g init =
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
cases l
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : β γ m γ)
(xs : Array α) (init : γ) (w : start = (xs.filterMap f).size) :
(xs.filterMap f).foldrM g init start 0 =
xs.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
subst w
cases xs
simp [List.foldrM_filterMap]
rfl
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : β α m β) (l : Array α) (init : β) :
(l.filter p).foldlM g init =
l.foldlM (fun x y => if p y then g x y else pure x) init := by
cases l
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : β α m β)
(xs : Array α) (init : β) (w : stop = (xs.filter p).size) :
(xs.filter p).foldlM g init 0 stop =
xs.foldlM (fun x y => if p y then g x y else pure x) init := by
subst w
cases xs
simp [List.foldlM_filter]
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : α β m β) (l : Array α) (init : β) :
(l.filter p).foldrM g init =
l.foldrM (fun x y => if p x then g x y else pure y) init := by
cases l
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : α β m β)
(xs : Array α) (init : β) (w : start = (xs.filter p).size) :
(xs.filter p).foldrM g init start 0 =
xs.foldrM (fun x y => if p x then g x y else pure y) init := by
subst w
cases xs
simp [List.foldrM_filter]
@[simp] theorem foldlM_attachWith [Monad m]
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : β { x // q x} m β} {b} (w : stop = xs.size):
(xs.attachWith q H).foldlM f b 0 stop =
xs.attach.foldlM (fun b a, h => f b a, H _ h) b := by
subst w
rcases xs with xs
simp [List.foldlM_map]
@[simp] theorem foldrM_attachWith [Monad m] [LawfulMonad m]
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : { x // q x} β m β} {b} (w : start = xs.size):
(xs.attachWith q H).foldrM f b start 0 =
xs.attach.foldrM (fun a acc => f a.1, H _ a.2 acc) b := by
subst w
rcases xs with xs
simp [List.foldrM_map]
/-! ### forM -/
@[congr] theorem forM_congr [Monad m] {as bs : Array α} (w : as = bs)
{f : α m PUnit} :
forM f as = forM f bs := by
forM as f = forM bs f := by
cases as <;> cases bs
simp_all
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (l : Array α) (g : α β) (f : β m PUnit) :
(l.map g).forM f = l.forM (fun a => f (g a)) := by
cases l
@[simp] theorem forM_append [Monad m] [LawfulMonad m] (xs ys : Array α) (f : α m PUnit) :
forM (xs ++ ys) f = (do forM xs f; forM ys f) := by
rcases xs with xs
rcases ys with ys
simp
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (xs : Array α) (g : α β) (f : β m PUnit) :
forM (xs.map g) f = forM xs (fun a => f (g a)) := by
rcases xs with xs
simp
/-! ### forIn' -/
@@ -109,44 +152,41 @@ We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
(l : Array α) (f : (a : α) a l β m (ForInStep β)) (init : β) :
forIn' l init f = ForInStep.value <$>
l.attach.foldlM (fun b a, m => match b with
(xs : Array α) (f : (a : α) a xs β m (ForInStep β)) (init : β) :
forIn' xs init f = ForInStep.value <$>
xs.attach.foldlM (fun b a, m => match b with
| .yield b => f a m b
| .done b => pure (.done b)) (ForInStep.yield init) := by
cases l
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
simp only [List.forIn'_toArray, List.forIn'_eq_foldlM, List.attachWith_mem_toArray, size_toArray,
List.length_map, List.length_attach, List.foldlM_toArray', List.foldlM_map]
rcases xs with xs
simp [List.forIn'_eq_foldlM, List.foldlM_map]
congr
/-- We can express a for loop over an array which always yields as a fold. -/
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
(l : Array α) (f : (a : α) a l β m γ) (g : (a : α) a l β γ β) (init : β) :
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
l.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
cases l
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
(xs : Array α) (f : (a : α) a xs β m γ) (g : (a : α) a xs β γ β) (init : β) :
forIn' xs init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
xs.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
rcases xs with xs
simp [List.foldlM_map]
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : Array α) (f : (a : α) a l β β) (init : β) :
forIn' l init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (l.attach.foldl (fun b a, h => f a h b) init) := by
cases l
@[simp] theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(xs : Array α) (f : (a : α) a xs β β) (init : β) :
forIn' xs init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (xs.attach.foldl (fun b a, h => f a h b) init) := by
rcases xs with xs
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
@[simp] theorem forIn'_yield_eq_foldl
(l : Array α) (f : (a : α) a l β β) (init : β) :
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
l.attach.foldl (fun b a, h => f a h b) init := by
cases l
(xs : Array α) (f : (a : α) a xs β β) (init : β) :
forIn' (m := Id) xs init (fun a m b => .yield (f a m b)) =
xs.attach.foldl (fun b a, h => f a h b) init := by
rcases xs with xs
simp [List.foldl_map]
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
(l : Array α) (g : α β) (f : (b : β) b l.map g γ m (ForInStep γ)) :
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases l
(xs : Array α) (g : α β) (f : (b : β) b xs.map g γ m (ForInStep γ)) :
forIn' (xs.map g) init f = forIn' xs init fun a h y => f (g a) (mem_map_of_mem g h) y := by
rcases xs with xs
simp
/--
@@ -154,41 +194,290 @@ We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
(f : α β m (ForInStep β)) (init : β) (l : Array α) :
forIn l init f = ForInStep.value <$>
l.foldlM (fun b a => match b with
(f : α β m (ForInStep β)) (init : β) (xs : Array α) :
forIn xs init f = ForInStep.value <$>
xs.foldlM (fun b a => match b with
| .yield b => f a b
| .done b => pure (.done b)) (ForInStep.yield init) := by
cases l
simp only [List.forIn_toArray, List.forIn_eq_foldlM, size_toArray, List.foldlM_toArray']
rcases xs with xs
simp only [List.forIn_toArray, List.forIn_eq_foldlM, List.size_toArray, List.foldlM_toArray']
congr
/-- We can express a for loop over an array which always yields as a fold. -/
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
(l : Array α) (f : α β m γ) (g : α β γ β) (init : β) :
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
l.foldlM (fun b a => g a b <$> f a b) init := by
cases l
(xs : Array α) (f : α β m γ) (g : α β γ β) (init : β) :
forIn xs init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
xs.foldlM (fun b a => g a b <$> f a b) init := by
rcases xs with xs
simp [List.foldlM_map]
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : Array α) (f : α β β) (init : β) :
forIn l init (fun a b => pure (.yield (f a b))) =
pure (f := m) (l.foldl (fun b a => f a b) init) := by
cases l
@[simp] theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(xs : Array α) (f : α β β) (init : β) :
forIn xs init (fun a b => pure (.yield (f a b))) =
pure (f := m) (xs.foldl (fun b a => f a b) init) := by
rcases xs with xs
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
@[simp] theorem forIn_yield_eq_foldl
(l : Array α) (f : α β β) (init : β) :
forIn (m := Id) l init (fun a b => .yield (f a b)) =
l.foldl (fun b a => f a b) init := by
cases l
(xs : Array α) (f : α β β) (init : β) :
forIn (m := Id) xs init (fun a b => .yield (f a b)) =
xs.foldl (fun b a => f a b) init := by
rcases xs with xs
simp [List.foldl_map]
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
(l : Array α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
cases l
(xs : Array α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (xs.map g) init f = forIn xs init fun a y => f (g a) y := by
rcases xs with xs
simp
/-! ### allM and anyM -/
@[simp] theorem anyM_pure [Monad m] [LawfulMonad m] (p : α Bool) (xs : Array α) :
xs.anyM (m := m) (pure <| p ·) = pure (xs.any p) := by
cases xs
simp
@[simp] theorem allM_pure [Monad m] [LawfulMonad m] (p : α Bool) (xs : Array α) :
xs.allM (m := m) (pure <| p ·) = pure (xs.all p) := by
cases xs
simp
/-! ### findM? and findSomeM? -/
@[simp]
theorem findM?_pure {m} [Monad m] [LawfulMonad m] (p : α Bool) (xs : Array α) :
findM? (m := m) (pure <| p ·) xs = pure (xs.find? p) := by
cases xs
simp
@[simp]
theorem findSomeM?_pure [Monad m] [LawfulMonad m] (f : α Option β) (xs : Array α) :
findSomeM? (m := m) (pure <| f ·) xs = pure (xs.findSome? f) := by
cases xs
simp
end Array
namespace List
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]
generalize [] = acc
induction l generalizing acc with simp
| cons x xs ih =>
congr; funext b
cases b
· simp only [Bool.false_eq_true, reduceIte, pure_bind, cond_false]
exact ih acc
· simp only [reduceIte, reverse_cons, pure_bind, cond_true]
exact ih (x :: acc)
/-- Variant of `filterM_toArray` with a side condition for the stop position. -/
@[simp] theorem filterM_toArray' [Monad m] [LawfulMonad m] (l : List α) (p : α m Bool) (w : stop = l.length) :
l.toArray.filterM p 0 stop = toArray <$> l.filterM p := by
subst w
rw [filterM_toArray]
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]
simp only [filterM, bind_pure_comp, Functor.map_map, reverse_toArray, reverse_reverse]
/-- Variant of `filterRevM_toArray` with a side condition for the start position. -/
@[simp] theorem filterRevM_toArray' [Monad m] [LawfulMonad m] (l : List α) (p : α m Bool) (w : start = l.length) :
l.toArray.filterRevM p start 0 = toArray <$> l.filterRevM p := by
subst w
rw [filterRevM_toArray]
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]
generalize [] = acc
induction l generalizing acc with simp [filterMapM.loop]
| cons x xs ih =>
congr; funext o
cases o
· simp only [pure_bind]; exact ih acc
· simp only [pure_bind]; rw [ List.reverse_cons]; exact ih _
/-- Variant of `filterMapM_toArray` with a side condition for the stop position. -/
@[simp] theorem filterMapM_toArray' [Monad m] [LawfulMonad m] (l : List α) (f : α m (Option β)) (w : stop = l.length) :
l.toArray.filterMapM f 0 stop = toArray <$> l.filterMapM f := by
subst w
rw [filterMapM_toArray]
@[simp] 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
generalize [] = acc
induction l generalizing acc with
| nil => simp only [foldlM_nil, flatMapM.loop, map_pure]
| cons x xs ih =>
simp only [foldlM_cons, bind_map_left, flatMapM.loop, _root_.map_bind]
congr; funext xs
conv => lhs; rw [Array.toArray_append, flatten_concat, reverse_cons]
exact ih _
end List
namespace Array
@[congr] theorem filterM_congr [Monad m] {as bs : Array α} (w : as = bs)
{p : α m Bool} {q : α m Bool} (h : a, p a = q a) :
as.filterM p = bs.filterM q := by
subst w
simp [filterM, h]
@[congr] theorem filterRevM_congr [Monad m] {as bs : Array α} (w : as = bs)
{p : α m Bool} {q : α m Bool} (h : a, p a = q a) :
as.filterRevM p = bs.filterRevM q := by
subst w
simp [filterRevM, h]
@[congr] theorem filterMapM_congr [Monad m] {as bs : Array α} (w : as = bs)
{f : α m (Option β)} {g : α m (Option β)} (h : a, f a = g a) :
as.filterMapM f = bs.filterMapM g := by
subst w
simp [filterMapM, h]
@[congr] theorem flatMapM_congr [Monad m] {as bs : Array α} (w : as = bs)
{f : α m (Array β)} {g : α m (Array β)} (h : a, f a = g a) :
as.flatMapM f = bs.flatMapM g := by
subst w
simp [flatMapM, h]
theorem toList_filterM [Monad m] [LawfulMonad m] (xs : Array α) (p : α m Bool) :
toList <$> xs.filterM p = xs.toList.filterM p := by
rw [List.filterM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_filterRevM [Monad m] [LawfulMonad m] (xs : Array α) (p : α m Bool) :
toList <$> xs.filterRevM p = xs.toList.filterRevM p := by
rw [List.filterRevM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_filterMapM [Monad m] [LawfulMonad m] (xs : Array α) (f : α m (Option β)) :
toList <$> xs.filterMapM f = xs.toList.filterMapM f := by
rw [List.filterMapM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_flatMapM [Monad m] [LawfulMonad m] (xs : Array α) (f : α m (Array β)) :
toList <$> xs.flatMapM f = xs.toList.flatMapM (fun a => toList <$> f a) := by
rw [List.flatMapM_toArray]
simp only [Functor.map_map, id_map']
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
/--
This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem foldlM_subtype [Monad m] {p : α Prop} {xs : Array { x // p x }}
{f : β { x // p x } m β} {g : β α m β} {x : β}
(hf : b x h, f b x, h = g b x) (w : stop = xs.size) :
xs.foldlM f x 0 stop = xs.unattach.foldlM g x 0 stop := by
subst w
rcases xs with l
simp
rw [List.foldlM_subtype hf]
@[wf_preprocess] theorem foldlM_wfParam [Monad m] (xs : Array α) (f : β α m β) (init : β) :
(wfParam xs).foldlM f init = xs.attach.unattach.foldlM f init := by
simp [wfParam]
@[wf_preprocess] theorem foldlM_unattach [Monad m] (P : α Prop) (xs : Array (Subtype P)) (f : β α m β) (init : β) :
xs.unattach.foldlM f init = xs.foldlM (init := init) fun b x, h =>
binderNameHint b f <| binderNameHint x (f b) <| binderNameHint h () <|
f b (wfParam x) := by
simp [wfParam]
/--
This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem foldrM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β m β} {g : α β m β} {x : β}
(hf : x h b, f x, h b = g x b) (w : start = xs.size) :
xs.foldrM f x start 0 = xs.unattach.foldrM g x start 0:= by
subst w
rcases xs with xs
simp
rw [List.foldrM_subtype hf]
@[wf_preprocess] theorem foldrM_wfParam [Monad m] [LawfulMonad m] (xs : Array α) (f : α β m β) (init : β) :
(wfParam xs).foldrM f init = xs.attach.unattach.foldrM f init := by
simp [wfParam]
@[wf_preprocess] theorem foldrM_unattach [Monad m] [LawfulMonad m] (P : α Prop) (xs : Array (Subtype P)) (f : α β m β) (init : β):
xs.unattach.foldrM f init = xs.foldrM (init := init) fun x, h b =>
binderNameHint x f <| binderNameHint h () <| binderNameHint b (f x) <|
f (wfParam x) b := by
simp [wfParam]
/--
This lemma identifies monadic maps over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem mapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } m β} {g : α m β} (hf : x h, f x, h = g x) :
xs.mapM f = xs.unattach.mapM g := by
rcases xs with xs
simp
rw [List.mapM_subtype hf]
@[wf_preprocess] theorem mapM_wfParam [Monad m] [LawfulMonad m] (xs : Array α) (f : α m β) :
(wfParam xs).mapM f = xs.attach.unattach.mapM f := by
simp [wfParam]
@[wf_preprocess] theorem mapM_unattach [Monad m] [LawfulMonad m] (P : α Prop) (xs : Array (Subtype P)) (f : α m β) :
xs.unattach.mapM f = xs.mapM fun x, h =>
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[simp] theorem filterMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } m (Option β)} {g : α m (Option β)} (hf : x h, f x, h = g x) (w : stop = xs.size) :
xs.filterMapM f 0 stop = xs.unattach.filterMapM g := by
subst w
rcases xs with xs
simp
rw [List.filterMapM_subtype hf]
@[wf_preprocess] theorem filterMapM_wfParam [Monad m] [LawfulMonad m]
(xs : Array α) (f : α m (Option β)) :
(wfParam xs).filterMapM f = xs.attach.unattach.filterMapM f := by
simp [wfParam]
@[wf_preprocess] theorem filterMapM_unattach [Monad m] [LawfulMonad m]
(P : α Prop) (xs : Array (Subtype P)) (f : α m (Option β)) :
xs.unattach.filterMapM f = xs.filterMapM fun x, h =>
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[simp] theorem flatMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } m (Array β)} {g : α m (Array β)} (hf : x h, f x, h = g x) :
(xs.flatMapM f) = xs.unattach.flatMapM g := by
rcases xs with xs
simp
rw [List.flatMapM_subtype]
simp [hf]
@[wf_preprocess] theorem flatMapM_wfParam [Monad m] [LawfulMonad m]
(xs : Array α) (f : α m (Array β)) :
(wfParam xs).flatMapM f = xs.attach.unattach.flatMapM f := by
simp [wfParam]
@[wf_preprocess] theorem flatMapM_unattach [Monad m] [LawfulMonad m]
(P : α Prop) (xs : Array (Subtype P)) (f : α m (Array β)) :
xs.unattach.flatMapM f = xs.flatMapM fun x, h =>
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
end Array

View File

@@ -0,0 +1,53 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.OfFn
/-!
# Theorems about `Array.ofFn`
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
@[simp] theorem ofFn_zero (f : Fin 0 α) : ofFn f = #[] := by
simp [ofFn, ofFn.go]
theorem ofFn_succ (f : Fin (n+1) α) :
ofFn f = (ofFn (fun (i : Fin n) => f i.castSucc)).push (f n, by omega) := by
ext i h₁ h₂
· simp
· simp [getElem_push]
split <;> rename_i h₃
· rfl
· congr
simp at h₁ h₂
omega
@[simp] theorem _rooy_.List.toArray_ofFn (f : Fin n α) : (List.ofFn f).toArray = Array.ofFn f := by
ext <;> simp
@[simp] theorem toList_ofFn (f : Fin n α) : (Array.ofFn f).toList = List.ofFn f := by
apply List.ext_getElem <;> simp
@[simp]
theorem ofFn_eq_empty_iff {f : Fin n α} : ofFn f = #[] n = 0 := by
rw [ Array.toList_inj]
simp
@[simp 500]
theorem mem_ofFn {n} (f : Fin n α) (a : α) : a ofFn f i, f i = a := by
constructor
· intro w
obtain i, h, rfl := getElem_of_mem w
exact i, by simpa using h, by simp
· rintro i, rfl
apply mem_of_getElem (i := i) <;> simp
end Array

View File

@@ -7,6 +7,9 @@ prelude
import Init.Data.List.Nat.Perm
import Init.Data.Array.Lemmas
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open List
@@ -27,38 +30,38 @@ theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs ↔ as.toList ~ bs.toL
@[simp] theorem perm_toArray (as bs : List α) : as.toArray ~ bs.toArray as ~ bs := by
simp [perm_iff_toList_perm]
@[simp, refl] protected theorem Perm.refl (l : Array α) : l ~ l := by
cases l
@[simp, refl] protected theorem Perm.refl (xs : Array α) : xs ~ xs := by
cases xs
simp
protected theorem Perm.rfl {l : List α} : l ~ l := .refl _
protected theorem Perm.rfl {xs : List α} : xs ~ xs := .refl _
theorem Perm.of_eq {l₁ l₂ : Array α} (h : l₁ = l₂) : l₁ ~ l₂ := h .rfl
theorem Perm.of_eq {xs ys : Array α} (h : xs = ys) : xs ~ ys := h .rfl
protected theorem Perm.symm {l₁ l₂ : Array α} (h : l₁ ~ l₂) : l₂ ~ l₁ := by
cases l₁; cases l₂
protected theorem Perm.symm {xs ys : Array α} (h : xs ~ ys) : ys ~ xs := by
cases xs; cases ys
simp only [perm_toArray] at h
simpa using h.symm
protected theorem Perm.trans {l₁ l₂ l₃ : Array α} (h₁ : l₁ ~ l₂) (h₂ : l₂ ~ l₃) : l₁ ~ l₃ := by
cases l₁; cases l₂; cases l₃
protected theorem Perm.trans {xs ys zs : Array α} (h₁ : xs ~ ys) (h₂ : ys ~ zs) : xs ~ zs := by
cases xs; cases ys; cases zs
simp only [perm_toArray] at h₁ h₂
simpa using h₁.trans h₂
instance : Trans (Perm (α := α)) (Perm (α := α)) (Perm (α := α)) where
trans h₁ h₂ := Perm.trans h₁ h₂
theorem perm_comm {l₁ l₂ : Array α} : l₁ ~ l₂ l₂ ~ l₁ := Perm.symm, Perm.symm
theorem perm_comm {xs ys : Array α} : xs ~ ys ys ~ xs := Perm.symm, Perm.symm
theorem Perm.push (x y : α) {l₁ l₂ : Array α} (p : l₁ ~ l₂) :
(l₁.push x).push y ~ (l₂.push y).push x := by
cases l₁; cases l₂
theorem Perm.push (x y : α) {xs ys : Array α} (p : xs ~ ys) :
(xs.push x).push y ~ (ys.push y).push x := by
cases xs; cases ys
simp only [perm_toArray] at p
simp only [push_toArray, List.append_assoc, singleton_append, perm_toArray]
exact p.append (Perm.swap' _ _ Perm.nil)
theorem swap_perm {as : Array α} {i j : Nat} (h₁ : i < as.size) (h₂ : j < as.size) :
as.swap i j ~ as := by
theorem swap_perm {xs : Array α} {i j : Nat} (h₁ : i < xs.size) (h₂ : j < xs.size) :
xs.swap i j ~ xs := by
simp only [swap, perm_iff_toList_perm, toList_set]
apply set_set_perm

View File

@@ -7,6 +7,9 @@ prelude
import Init.Data.Vector.Basic
import Init.Data.Ord
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- We do not enable `linter.indexVariables` because it is helpful to name index variables `lo`, `mid`, `hi`, etc.
namespace Array
private def qpartition {n} (as : Vector α n) (lt : α α Bool) (lo hi : Nat)
@@ -27,6 +30,16 @@ private def qpartition {n} (as : Vector α n) (lt : αα → Bool) (lo hi :
(i, ilo, as.swap i hi)
loop as lo lo
/--
Sorts an array using the Quicksort algorithm.
The optional parameter `lt` specifies an ordering predicate. It defaults to `LT.lt`, which must be
decidable to be used for sorting. Use `Array.qsortOrd` to sort the array according to the `Ord α`
instance.
The optional parameters `low` and `high` delimit the region of the array that is sorted. Both are
inclusive, and default to sorting the entire array.
-/
@[inline] def qsort (as : Array α) (lt : α α Bool := by exact (· < ·))
(low := 0) (high := as.size - 1) : Array α :=
let rec @[specialize] sort {n} (as : Vector α n) (lo hi : Nat)
@@ -47,7 +60,7 @@ private def qpartition {n} (as : Vector α n) (lt : αα → Bool) (lo hi :
set_option linter.unusedVariables.funArgs false in
/--
Sort an array using `compare` to compare elements.
Sorts an array using the Quicksort algorithm, using `Ord.compare` to compare elements.
-/
def qsortOrd [ord : Ord α] (xs : Array α) : Array α :=
xs.qsort fun x y => compare x y |>.isLT

View File

@@ -0,0 +1,301 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.Array.OfFn
import Init.Data.Array.MapIdx
import Init.Data.Array.Zip
import Init.Data.List.Nat.Range
/-!
# Lemmas about `Array.range'`, `Array.range`, and `Array.zipIdx`
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
/-! ## Ranges and enumeration -/
/-! ### range' -/
theorem range'_succ (s n step) : range' s (n + 1) step = #[s] ++ range' (s + step) n step := by
rw [ toList_inj]
simp [List.range'_succ]
@[simp] theorem range'_eq_empty_iff : range' s n step = #[] n = 0 := by
rw [ size_eq_zero_iff, size_range']
theorem range'_ne_empty_iff (s : Nat) {n step : Nat} : range' s n step #[] n 0 := by
cases n <;> simp
@[simp] theorem range'_zero : range' s 0 step = #[] := by
simp
@[simp] theorem range'_one {s step : Nat} : range' s 1 step = #[s] := by
simp [range', ofFn, ofFn.go]
@[simp] theorem range'_inj : range' s n = range' s' n' n = n' (n = 0 s = s') := by
rw [ toList_inj]
simp [List.range'_inj]
theorem mem_range' {n} : m range' s n step i < n, m = s + step * i := by
simp [range']
constructor
· rintro i, w, h, h'
exact i, w, by simp_all
· rintro i, w, h'
exact i, w, by simp_all
theorem pop_range' : (range' s n step).pop = range' s (n - 1) step := by
ext <;> simp
theorem map_add_range' (a) (s n step) : map (a + ·) (range' s n step) = range' (a + s) n step := by
ext <;> simp <;> omega
theorem range'_succ_left : range' (s + 1) n step = (range' s n step).map (· + 1) := by
ext <;> simp <;> omega
theorem range'_append (s m n step : Nat) :
range' s m step ++ range' (s + step * m) n step = range' s (m + n) step := by
ext i h₁ h₂
· simp
· simp only [size_append, size_range'] at h₁ h₂
simp only [getElem_append, size_range', getElem_range', Nat.mul_sub_left_distrib, dite_eq_ite,
ite_eq_left_iff, Nat.not_lt]
intro h
have : step * m step * i := by exact mul_le_mul_left step h
omega
@[simp] theorem range'_append_1 (s m n : Nat) :
range' s m ++ range' (s + m) n = range' s (m + n) := by simpa using range'_append s m n 1
theorem range'_concat (s n : Nat) : range' s (n + 1) step = range' s n step ++ #[s + step * n] := by
simpa using (range'_append s n 1 step).symm
theorem range'_1_concat (s n : Nat) : range' s (n + 1) = range' s n ++ #[s + n] := by
simp [range'_concat]
@[simp] theorem mem_range'_1 : m range' s n s m m < s + n := by
simp [mem_range']; exact
fun i, h, e => e Nat.le_add_right .., Nat.add_lt_add_left h _,
fun h₁, h₂ => m - s, Nat.sub_lt_left_of_lt_add h₁ h₂, (Nat.add_sub_cancel' h₁).symm
theorem map_sub_range' (a s n : Nat) (h : a s) :
map (· - a) (range' s n step) = range' (s - a) n step := by
conv => lhs; rw [ Nat.add_sub_cancel' h]
rw [ map_add_range', map_map, (?_ : __ = _), map_id]
funext x; apply Nat.add_sub_cancel_left
@[simp] theorem range'_eq_singleton_iff {s n a : Nat} : range' s n = #[a] s = a n = 1 := by
rw [ toList_inj]
simp
theorem range'_eq_append_iff : range' s n = xs ++ ys k, k n xs = range' s k ys = range' (s + k) (n - k) := by
simp [ toList_inj, List.range'_eq_append_iff]
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat Bool} :
(range' s n).find? p = some i p i i range' s n j, s j j < i !p j := by
rw [ List.toArray_range']
simp only [List.find?_toArray, mem_toArray]
simp [List.find?_range'_eq_some]
@[simp] theorem find?_range'_eq_none {s n : Nat} {p : Nat Bool} :
(range' s n).find? p = none i, s i i < s + n !p i := by
rw [ List.toArray_range']
simp only [List.find?_toArray]
simp
theorem erase_range' :
(range' s n).erase i =
range' s (min n (i - s)) ++ range' (max s (i + 1)) (min s (i + 1) + n - (i + 1)) := by
simp only [ List.toArray_range', List.erase_toArray]
simp [List.erase_range']
/-! ### range -/
theorem range_eq_range' (n : Nat) : range n = range' 0 n := by
simp [range, range']
theorem range_succ_eq_map (n : Nat) : range (n + 1) = #[0] ++ map succ (range n) := by
ext i h₁ h₂
· simp
omega
· simp only [getElem_range, getElem_append, List.size_toArray, List.length_cons, List.length_nil,
Nat.zero_add, lt_one_iff, List.getElem_toArray, List.getElem_singleton, getElem_map,
succ_eq_add_one, dite_eq_ite]
split <;> omega
theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) := by
rw [range_eq_range', map_add_range']; rfl
@[simp] theorem range_eq_empty_iff {n : Nat} : range n = #[] n = 0 := by
rw [ size_eq_zero_iff, size_range]
theorem range_ne_empty_iff {n : Nat} : range n #[] n 0 := by
cases n <;> simp
theorem range_succ (n : Nat) : range (succ n) = range n ++ #[n] := by
ext i h₁ h₂
· simp
· simp only [succ_eq_add_one, size_range] at h₁
simp only [succ_eq_add_one, getElem_range, append_singleton, getElem_push, size_range,
dite_eq_ite]
split <;> omega
theorem range_add (n m : Nat) : range (n + m) = range n ++ (range m).map (n + ·) := by
rw [ range'_eq_map_range]
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 n m).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]
theorem mem_range {m n : Nat} : m range n m < n := by
simp only [range_eq_range', mem_range'_1, Nat.zero_le, true_and, Nat.zero_add]
theorem not_mem_range_self {n : Nat} : n range n := by simp
theorem self_mem_range_succ (n : Nat) : n range (n + 1) := by simp
@[simp] theorem take_range (i n : Nat) : take (range n) i = range (min i n) := by
ext <;> simp
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
(range n).find? p = some i p i i range n j, j < i !p j := by
simp [range_eq_range']
@[simp] theorem find?_range_eq_none {n : Nat} {p : Nat Bool} :
(range n).find? p = none i, i < n !p i := by
simp only [ List.toArray_range, List.find?_toArray, List.find?_range_eq_none]
theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n - (i + 1)) := by
simp [range_eq_range', erase_range']
/-! ### zipIdx -/
@[simp]
theorem zipIdx_eq_empty_iff {xs : Array α} {i : Nat} : xs.zipIdx i = #[] xs = #[] := by
cases xs
simp
@[simp]
theorem getElem?_zipIdx (xs : Array α) (i j) : (zipIdx xs i)[j]? = xs[j]?.map fun a => (a, i + j) := by
simp [getElem?_def]
theorem map_snd_add_zipIdx_eq_zipIdx (xs : Array α) (n k : Nat) :
map (Prod.map id (· + n)) (zipIdx xs k) = zipIdx xs (n + k) :=
ext_getElem? fun i by simp [(· ·), Nat.add_comm, Nat.add_left_comm]; rfl
@[simp]
theorem zipIdx_map_snd (i) (xs : Array α) : map Prod.snd (zipIdx xs i) = range' i xs.size := by
cases xs
simp
@[simp]
theorem zipIdx_map_fst (i) (xs : Array α) : map Prod.fst (zipIdx xs i) = xs := by
cases xs
simp
theorem zipIdx_eq_zip_range' (xs : Array α) {i : Nat} : xs.zipIdx i = xs.zip (range' i xs.size) := by
simp [zip_of_prod (zipIdx_map_fst _ _) (zipIdx_map_snd _ _)]
@[simp]
theorem unzip_zipIdx_eq_prod (xs : Array α) {i : Nat} :
(xs.zipIdx i).unzip = (xs, range' i xs.size) := by
simp only [zipIdx_eq_zip_range', unzip_zip, size_range']
/-- Replace `zipIdx` with a starting index `n+1` with `zipIdx` starting from `n`,
followed by a `map` increasing the indices by one. -/
theorem zipIdx_succ (xs : Array α) (i : Nat) :
xs.zipIdx (i + 1) = (xs.zipIdx i).map (fun a, j => (a, j + 1)) := by
cases xs
simp [List.zipIdx_succ]
/-- Replace `zipIdx` with a starting index with `zipIdx` starting from 0,
followed by a `map` increasing the indices. -/
theorem zipIdx_eq_map_add (xs : Array α) (i : Nat) :
xs.zipIdx i = (xs.zipIdx 0).map (fun a, j => (a, i + j)) := by
cases xs
simp only [zipIdx_toArray, List.map_toArray, mk.injEq]
rw [List.zipIdx_eq_map_add]
@[simp]
theorem zipIdx_singleton (x : α) (k : Nat) : zipIdx #[x] k = #[(x, k)] :=
rfl
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {xs : Array α} :
(x, k + i) zipIdx xs k xs[i]? = some x := by
simp [mem_iff_getElem?, and_left_comm]
theorem le_snd_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) :
k x.2 :=
(mk_mem_zipIdx_iff_le_and_getElem?_sub.1 h).1
theorem snd_lt_add_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) :
x.2 < k + xs.size := by
rcases mem_iff_getElem.1 h with i, h', rfl
simpa using h'
theorem snd_lt_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) : x.2 < xs.size + k := by
simpa [Nat.add_comm] using snd_lt_add_of_mem_zipIdx h
theorem map_zipIdx (f : α β) (xs : Array α) (k : Nat) :
map (Prod.map f id) (zipIdx xs k) = zipIdx (xs.map f) k := by
cases xs
simp [List.map_zipIdx]
theorem fst_mem_of_mem_zipIdx {x : α × Nat} {xs : Array α} {k : Nat} (h : x zipIdx xs k) : x.1 xs :=
zipIdx_map_fst k xs mem_map_of_mem _ h
theorem fst_eq_of_mem_zipIdx {x : α × Nat} {xs : Array α} {k : Nat} (h : x zipIdx xs k) :
x.1 = xs[x.2 - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) := by
cases xs
exact List.fst_eq_of_mem_zipIdx (by simpa using h)
theorem mem_zipIdx {x : α} {i : Nat} {xs : Array α} {k : Nat} (h : (x, i) xs.zipIdx k) :
k i i < k + xs.size
x = xs[i - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) :=
le_snd_of_mem_zipIdx h, snd_lt_add_of_mem_zipIdx h, fst_eq_of_mem_zipIdx h
/-- Variant of `mem_zipIdx` specialized at `k = 0`. -/
theorem mem_zipIdx' {x : α} {i : Nat} {xs : Array α} (h : (x, i) xs.zipIdx) :
i < xs.size x = xs[i]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) :=
by simpa using snd_lt_add_of_mem_zipIdx h, fst_eq_of_mem_zipIdx h
theorem zipIdx_map (xs : Array α) (k : Nat) (f : α β) :
zipIdx (xs.map f) k = (zipIdx xs k).map (Prod.map f id) := by
cases xs
simp [List.zipIdx_map]
theorem zipIdx_append (xs ys : Array α) (k : Nat) :
zipIdx (xs ++ ys) k = zipIdx xs k ++ zipIdx ys (k + xs.size) := by
cases xs
cases ys
simp [List.zipIdx_append]
theorem zipIdx_eq_append_iff {xs : Array α} {k : Nat} :
zipIdx xs k = ys ++ zs
ys' zs', xs = ys' ++ zs' ys = zipIdx ys' k zs = zipIdx zs' (k + ys'.size) := by
rcases xs with xs
rcases ys with ys
rcases zs with zs
simp only [zipIdx_toArray, List.append_toArray, mk.injEq, List.zipIdx_eq_append_iff,
toArray_eq_append_iff]
constructor
· rintro l₁', l₂', rfl, rfl, rfl
exact l₁', l₂', by simp
· rintro l₁', l₂', rfl, h
simp only [zipIdx_toArray, mk.injEq, List.size_toArray] at h
obtain rfl, rfl := h
exact l₁', l₂', by simp
end Array

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