Compare commits

...

409 Commits

Author SHA1 Message Date
Leonardo de Moura
ba71869c2b feat: Float32
This PR adds support for `Float32` to the Lean runtime.

We need an update stage0, and then remove `#exit` from new
`Float32.lean` file.
2024-12-09 13:19:18 -08:00
Kim Morrison
520d4b698f chore: cleanup of Array lemmas (#6343)
Continuing cleanup of Array lemmas.
2024-12-09 14:04:16 +00:00
Kim Morrison
c7b8c5c6a6 chore: alignment of Array and List lemmas (#6342)
Further alignment of `Array` and `List` lemmas. Moved lemmas about
`List.toArray` to a separate file, and aligned lemmas about membership.
2024-12-09 11:30:45 +00:00
Kyle Miller
3f791933f1 chore: release notes for 4.14.0 (#6339) 2024-12-09 05:30:50 +00:00
Kyle Miller
63791f0177 feat: _ separators in numeric literals (#6204)
This PR 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]
```

Closes #6199
2024-12-08 22:23:12 +00:00
Kim Morrison
6abb8aad43 chore: cleanup of Array lemmas (#6337)
This PRs continues cleaning up Array lemmas and improving alignment with
List.
2024-12-08 22:03:23 +00:00
Kim Morrison
4dd182c554 chore: remove deprecated aliases for Int.tdiv and Int.tmod (#6322)
This PR removes the deprecated aliases `Int.div := Int.tdiv` and
`Int.mod := Int.tmod`. Later we will rename `Int.ediv` to `Int.div` and
`Int.emod` to `Int.mod`.
2024-12-08 05:19:42 +00:00
jsr-p
762c5758f5 doc: missing (type := true) in reader monad example (#6196)
This PR adds missing `(types := true)` to `#reduce` example in [Readers
example](https://lean-lang.org/lean4/doc/monads/readers.lean.html).
Since [4.10](https://lean-lang.org/blog/2024-8-1-lean-4100/) the `(types
:= true)` is necessary for the `ReaderM Environment String` type to be
reduced into `Environment → String`.
2024-12-07 15:59:36 +00:00
Joachim Breitner
6447fda253 feat: FunInd: omit unused parameters (#6330)
This PR removes unnecessary parameters from the funcion induction
principles. This is a breaking change; broken code can typically be adjusted
simply by passing fewer parameters.

Part 2, adjusting after stage0 update.

Closes #6320
2024-12-07 04:19:21 +01:00
Joachim Breitner
279f36b4cc chore: update stage0 2024-12-07 04:19:21 +01:00
Joachim Breitner
d2853ecbc4 feat: FunInd: omit unused parameters (#6330)
This PR removes unnecessary parameters from the funcion induction
principles. This is a breaking change; broken code can typically be adjusted
simply by passing fewer parameters.

Part 1, before stage0 update.

Closes #6320
2024-12-07 04:19:21 +01:00
Kim Morrison
6e60d13084 feat: getElem lemmas for Vector operations (#6324)
This PR adds `GetElem` lemmas for the basic `Vector` operations.

The `Vector` API is still very sparse, but I'm hoping to infill rapidly.
2024-12-06 01:45:19 +00:00
Kim Morrison
019f8e175f chore: protect Fin.cast and BitVec.cast (#6315)
This PR 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.
2024-12-05 06:11:45 +00:00
Kim Morrison
c366a291ca chore: generalize universe in Array.find? (#6318)
This PR generalizes the universe level for `Array.find?`, by giving it a
separate implementation from `Array.findM?`.
2024-12-05 06:11:40 +00:00
Alex Keizer
1400b95ffb feat: upstream ToLevel from mathlib (#6285)
This PR 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.

This implements part one of the plan to upstream a derive handler for
`ToExpr`, as discussed in #5906 and #5909.

---------

Co-authored-by: Kyle Miller <kmill31415@gmail.com>
Co-authored-by: Tobias Grosser <tobias@grosser.es>
2024-12-05 05:50:32 +00:00
Kim Morrison
00c7b85261 feat: lemmas about for loops over Option (#6316)
This PR adds lemmas simplifying `for` loops over `Option` into
`Option.pelim`, giving parity with lemmas simplifying `for` loops of
`List` into `List.fold`.
2024-12-05 05:09:07 +00:00
Leonardo de Moura
f6e88e5a05 fix: missing HEq support at ToLCNF (#6311)
This PR adds support for `HEq` to the new code generator.
2024-12-04 19:49:16 +00:00
Sebastian Ullrich
88573c802d test: do not filter output for non-diff tests (#6308) 2024-12-04 17:49:35 +00:00
Henrik Böving
faf07e58db chore: remove unused imports (#6305)
This PR removes an unused import in the time library that can yield to
import cycles when building stuff that gets imported by `Std.Internal`
but also wants to import `Std.Time`.
2024-12-04 12:46:08 +00:00
Tobias Grosser
c5181569f9 feat: BitVec.[toInt|toFin]_concat and Bool.toInt (#6182)
This PR 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.

We also add `Bool.toInt`.
2024-12-04 01:53:30 +00:00
Siddharth
77211029da feat: BitVec.toFin/ToInt BitVec.ushiftRight (#6238)
This PR 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.

```lean
theorem toInt_ushiftRight_eq_ite {x : BitVec w} {n : Nat} :
  (x >>> n).toInt = if n = 0 then x.toInt else x.toNat >>> n
```

```lean
theorem toFin_uShiftRight {x : BitVec w} {n : Nat} :
  (x >>> n).toFin = x.toFin / (Fin.ofNat' (2^w) (2^n))
```

---------

Co-authored-by: Harun Khan <harun19@stanford.edu>
Co-authored-by: Tobias Grosser <github@grosser.es>
2024-12-04 01:49:58 +00:00
Lean stage0 autoupdater
da9a0c4190 chore: update stage0 2024-12-04 00:04:00 +00:00
Leonardo de Moura
b9bf94313a feat: add debug.proofAsSorry (#6300)
This PR adds the `debug.proofAsSorry` option. When enabled, the proofs
of theorems are ignored and replaced with `sorry`.
2024-12-03 23:21:38 +00:00
Sebastian Ullrich
2a891a3889 chore: CMAKE_CXX_SYSROOT_FLAG is also needed for linking (#6297)
Fixes #6296
2024-12-03 16:14:22 +00:00
Sebastian Ullrich
00718c3959 chore: clean up Elab.async handling (#6299)
* Make sure metaprogramming users cannot be surprised by its
introduction
* Make `#guard_msgs` compatible with its use
2024-12-03 12:42:02 +00:00
Sebastian Ullrich
473274f145 chore: update stage0 2024-12-03 13:59:37 +01:00
Kim Morrison
7b98fbece4 feat: reverse HashMap.toList, so it agrees with HashMap.toArray (#6244)
This PR changes the implementation of `HashMap.toList`, so the ordering
agrees with `HashMap.toArray`.

Currently there are no verification lemmas about `HashMap.toList`, so no
contract is being broken yet!
2024-12-03 12:25:35 +00:00
Henrik Böving
24b412ebe3 refactor: move IO.Channel and IO.Mutex to Std.Sync (#6282)
This PR moves `IO.Channel` and `IO.Mutex` from `Init` to `Std.Sync` and
renames them to `Std.Channel` and `Std.Mutex`.

Note that the original files are retained and the deprecation is written
manually as we cannot import `Std` from `Init` so this is the only way
to deprecate without a hard breaking change. In particular we do not yet
move `Std.Queue` from `Init` to `Std` both because it needs to be
retained for this deprecation to work but also because it is already
within the `Std` namespace and as such we cannot maintain two copies of
the file at once. After the deprecation period is finished `Std.Queue`
will find a new home in `Std.Data.Queue`.
2024-12-03 09:36:50 +00:00
Kim Morrison
cb600ed9b4 chore: restore broken proofs
This reverts commit d099f560f72b5f18695c7fb586a9da93af0cb17e.
2024-12-03 17:59:23 +11:00
Kim Morrison
57d83c835e feat: add simp configuration to norm_cast macros 2024-12-03 17:59:23 +11:00
Kim Morrison
ce27d49e31 chore: update stage0 2024-12-03 17:59:23 +11:00
Kim Morrison
8a7889d602 chore: temporarily sorry broken proofs 2024-12-03 17:59:23 +11:00
Kim Morrison
69340297be chore: add simp configuration to norm_cast syntax
chore: define NormCastConfig earlier
2024-12-03 17:59:23 +11:00
Kim Morrison
222abdd43d feat: simprocs for other Fin operations (#6295)
This PR sets up simprocs for all the remaining operations defined in
`Init.Data.Fin.Basic`
2024-12-03 04:42:17 +00:00
François G. Dorais
490be9282e chore: specialize fold loops (#6293)
This PR adds `specialize` and `semireducible` attributes to loops for
`Fin.fold[lr]M?`
2024-12-03 02:44:19 +00:00
Kim Morrison
cda6d5c67a chore: upstream List.length_flatMap (#6294)
This PR upstreams `List.length_flatMap`, `countP_flatMap` and
`count_flatMap` from Mathlib. These were not possible to state before we
upstreamed `List.sum`.
2024-12-03 01:59:32 +00:00
Kim Morrison
904404303b chore: robustify for byAsSorry (#6287)
This PR makes some proofs more robust so they will still work with
`byAsSorry`. Unfortunately, they are not a complete fix and there are
remaining problems building with `byAsSorry`.
2024-12-02 23:53:16 +00:00
Mac Malone
f6bc6b2eb1 fix: lake: properly prepend job log in ensureJob (#6291)
This PR 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`.
2024-12-02 23:43:12 +00:00
Mac Malone
d9d54c1f99 chore: lake: use & check prelude (#6289)
This PR adapts Lake modules to use `prelude` and includes them in the
`check-prelude` CI.
2024-12-02 19:55:05 +00:00
Henrik Böving
b2336fd980 perf: speed up bv_decide reflection using Lean.RArray (#6288)
This PR uses Lean.RArray in bv_decide's reflection proofs. Giving
speedups on problems with lots of variables.

Implement like #6068, speedup:
```
# before
λ hyperfine "lean +nightly-2024-12-02 tests/lean/run/bv_reflection_stress.lean"
Benchmark 1: lean +nightly-2024-12-02 tests/lean/run/bv_reflection_stress.lean
  Time (mean ± σ):      1.939 s ±  0.007 s    [User: 1.549 s, System: 0.104 s]
  Range (min … max):    1.928 s …  1.947 s    10 runs
# after
λ hyperfine "lean tests/lean/run/bv_reflection_stress.lean"                                                                                                                                                                                                                        
Benchmark 1: lean tests/lean/run/bv_reflection_stress.lean
  Time (mean ± σ):      1.409 s ±  0.006 s    [User: 1.058 s, System: 0.073 s]
  Range (min … max):    1.401 s …  1.419 s    10 runs
```
2024-12-02 17:44:58 +00:00
Mac Malone
f156f22d7c feat: lake: build without leanc (#6176)
This PR 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.
2024-12-02 17:11:27 +00:00
dependabot[bot]
3c348d4526 chore: CI: bump dawidd6/action-download-artifact from 6 to 7 (#6274)
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 6 to 7.
<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>v7</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump fast-xml-parser from 4.4.0 to 4.4.1 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/299">dawidd6/action-download-artifact#299</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.7 to
2.1.9 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/300">dawidd6/action-download-artifact#300</a></li>
<li>build(deps): bump adm-zip from 0.5.14 to 0.5.15 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/301">dawidd6/action-download-artifact#301</a></li>
<li>build(deps): bump adm-zip from 0.5.15 to 0.5.16 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/306">dawidd6/action-download-artifact#306</a></li>
<li>build(deps): bump path-to-regexp from 6.2.2 to 6.3.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/307">dawidd6/action-download-artifact#307</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.9 to
2.1.10 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/311">dawidd6/action-download-artifact#311</a></li>
<li>build(deps): bump <code>@​actions/core</code> from 1.10.1 to 1.11.0
by <a href="https://github.com/dependabot"><code>@​dependabot</code></a>
in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/310">dawidd6/action-download-artifact#310</a></li>
<li>build(deps): bump <code>@​actions/core</code> from 1.11.0 to 1.11.1
by <a href="https://github.com/dependabot"><code>@​dependabot</code></a>
in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/312">dawidd6/action-download-artifact#312</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.10 to
2.1.11 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/313">dawidd6/action-download-artifact#313</a></li>
<li>build(deps): Fix cross-spawn &gt;=7.0.0 &lt;= 7.0.5 vulnerability by
<a href="https://github.com/alexcouret"><code>@​alexcouret</code></a> in
<a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/317">dawidd6/action-download-artifact#317</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/alexcouret"><code>@​alexcouret</code></a> made
their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/317">dawidd6/action-download-artifact#317</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v6...v7">https://github.com/dawidd6/action-download-artifact/compare/v6...v7</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="80620a5d27"><code>80620a5</code></a>
node_modules: update</li>
<li><a
href="b15e003f46"><code>b15e003</code></a>
node_modules: install</li>
<li><a
href="1ee9a455fd"><code>1ee9a45</code></a>
build(deps): Fix cross-spawn &gt;=7.0.0 &lt;= 7.0.5 vulnerability (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/317">#317</a>)</li>
<li><a
href="b2f2706ac4"><code>b2f2706</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.10 to 2.1.11
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/313">#313</a>)</li>
<li><a
href="fdbeba027c"><code>fdbeba0</code></a>
build(deps): bump <code>@​actions/core</code> from 1.11.0 to 1.11.1 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/312">#312</a>)</li>
<li><a
href="a74b42987a"><code>a74b429</code></a>
build(deps): bump <code>@​actions/core</code> from 1.10.1 to 1.11.0 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/310">#310</a>)</li>
<li><a
href="24e807a70c"><code>24e807a</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.9 to 2.1.10
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/311">#311</a>)</li>
<li><a
href="9592e3c4ab"><code>9592e3c</code></a>
build(deps): bump path-to-regexp from 6.2.2 to 6.3.0 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/307">#307</a>)</li>
<li><a
href="5f966b63eb"><code>5f966b6</code></a>
build(deps): bump adm-zip from 0.5.15 to 0.5.16 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/306">#306</a>)</li>
<li><a
href="db9477a3eb"><code>db9477a</code></a>
build(deps): bump adm-zip from 0.5.14 to 0.5.15 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/301">#301</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v6...v7">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=6&new-version=7)](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>
2024-12-02 16:09:50 +00:00
Sebastian Ullrich
0b8f50f78d feat: async linting (#4460)
This PR runs all linters for a single command (together) on a separate
thread from further elaboration, making a first step towards
parallelizing the elaborator.
2024-12-02 14:37:03 +00:00
Henrik Böving
0d89f0194b perf: bv_decide uses rfl in reflection if possible (#6286)
This PR 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.
2024-12-02 14:27:49 +00:00
Kim Morrison
e157fcbcd1 chore: missing Array/Vector injectivity lemmas (#6284) 2024-12-02 11:00:03 +00:00
Henrik Böving
95dbac26cf chore: shake Std.Time (#6283)
This PR reduces the import closure of `Std.Time` such that it doesn't
have to be rebuilt on every change in `Init.Data`.

Noticed while working on `Init` refactorings.
2024-12-02 10:52:43 +00:00
dependabot[bot]
be63c8280e chore: CI: bump dcarbone/install-jq-action from 2.1.0 to 3.0.1 (#6275)
Bumps
[dcarbone/install-jq-action](https://github.com/dcarbone/install-jq-action)
from 2.1.0 to 3.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dcarbone/install-jq-action/releases">dcarbone/install-jq-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Use sh in action by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/15">dcarbone/install-jq-action#15</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v3.0.0...v3.0.1">https://github.com/dcarbone/install-jq-action/compare/v3.0.0...v3.0.1</a></p>
<h2>v3.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>updating matrix versions by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/12">dcarbone/install-jq-action#12</a></li>
<li>trying out posix sh by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/14">dcarbone/install-jq-action#14</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v2...v3.0.0">https://github.com/dcarbone/install-jq-action/compare/v2...v3.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e397bd8743"><code>e397bd8</code></a>
Use sh in action (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/15">#15</a>)</li>
<li><a
href="36b228ee68"><code>36b228e</code></a>
Add dependabot for github-actions</li>
<li><a
href="d5935278d5"><code>d593527</code></a>
updating examples</li>
<li><a
href="ca8101273e"><code>ca81012</code></a>
trying out posix sh (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/14">#14</a>)</li>
<li><a
href="de7c0d1fb1"><code>de7c0d1</code></a>
updating matrix versions (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/12">#12</a>)</li>
<li>See full diff in <a
href="https://github.com/dcarbone/install-jq-action/compare/v2.1.0...v3.0.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dcarbone/install-jq-action&package-manager=github_actions&previous-version=2.1.0&new-version=3.0.1)](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>
2024-12-02 10:33:27 +00:00
Sebastian Ullrich
6fcf35e930 chore: script/mathlib-bench (#6280)
A simple approach to benchmarking lean4 PRs against Mathlib
2024-12-02 10:00:57 +00:00
Marc Huisinga
b3e0c9c3fa fix: use sensible notion of indentation in structure instance field completion (#6279)
This PR fixes a bug in structure instance field completion that caused
it to not function correctly for bracketed structure instances written
in Mathlib style.
2024-12-02 09:37:12 +00:00
Kim Morrison
3c5e612dc5 chore: begin development cycle for v4.16.0 (#6277) 2024-12-02 04:11:10 +00:00
Kim Morrison
29e84fa7ea feat: omega doesn't get stuck on bare Int.negSucc (#6276)
This PR ensures `omega` doesn't get stuck on bare `Int.negSucc` terms in
goals.

This came up in https://github.com/ImperialCollegeLondon/FLT/pull/260.
2024-12-01 23:57:15 +00:00
Mac Malone
6bf8ff32f0 feat: more UInt bitwise theorems (#6188)
This PR 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.
2024-12-01 22:38:49 +00:00
Henrik Böving
62b8238782 chore: remove accidentally added file (#6262)
This PR removes an accidentally comitted file.
2024-12-01 21:11:44 +00:00
Kyle Miller
0a2a8e8aa4 feat: make "foo has been deprecated" warning be hoverable (#6273)
This PR modifies the "foo has been deprecated: use betterFoo instead"
warning so that foo and betterFoo are hoverable.
2024-12-01 19:12:42 +00:00
Kyle Miller
23236ef520 fix: have Lean.Meta.isConstructorApp'? be aware of n + k Nat offsets (#6270)
This PR 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`.

Closes #5064
2024-12-01 18:04:32 +00:00
Kim Morrison
b2f70dad52 feat: Array.swap_perm (#6272)
This PR introduces the basic theory of permutations of `Array`s and
proves `Array.swap_perm`.

The API falls well short of what is available for `List` at this point.
2024-12-01 08:35:28 +00:00
Kim Morrison
819cb879e1 chore: upstream Vector lemmas (#6271)
This PR upstreams existing lemmas about `Vector` from Batteries.

Thanks to @fgdorais for preparing these in
https://github.com/leanprover-community/batteries/pull/1062. Further
contributions to the `Vector` API welcome via PR here.
2024-12-01 06:44:14 +00:00
Kim Morrison
3ee2842e77 feat: remove runtime bounds checks and partial from qsort (#6241)
This PR 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.
2024-12-01 06:26:00 +00:00
Kyle Miller
7b8504cf06 chore: post-stage0 cleanup for #6165 (#6268)
This PR puts code in terms of syntax quotations now that there has been
a stage0 update. Fixes a lingering bug in StructInst where some
intermediate syntax was malformed, but this had no observable effects
outside of some debug messages.
2024-12-01 00:20:59 +00:00
Lean stage0 autoupdater
ca96922b4b chore: update stage0 2024-11-30 21:22:30 +00:00
Kyle Miller
a1c3a36433 feat: parity between structure instance notation and where notation (#6165)
This PR 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

def p : PosFun :=
  { f n := n + 1
    pos := by simp }

def p' : PosFun :=
  { f | 0 => 1
      | n + 1 => n + 1
    pos := by rintro (_|_) <;> simp }
```
Just like for the structure `where` notation, a field `f x y z : ty :=
val` expands to `f := fun x y z => (val : ty)`. The type ascription is
optional.

The PR also is setting things up for future expansion. Pending some
discussion, in the future structure/`where` notation could have have
embedded `where` clauses; rather than `{ a := { x := 1, y := z } }` one
could write `{ a where x := 1; y := z }`.
2024-11-30 20:27:25 +00:00
Lean stage0 autoupdater
734ea3071d chore: update stage0 2024-11-30 12:58:59 +00:00
Kyle Miller
f3f00451c8 feat: add structInstFieldDecl syntax category (#6265)
This PR is preparation for changes to structure instance notation in
#6165. It adds a syntax category that will be used for field syntax.
2024-11-30 12:12:53 +00:00
Leonardo de Moura
27df5e968a feat: Simp.Config.implicitDefEqProofs (#4595)
This PR 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.

The default setting does change the existing behavior. Users can use
`simp -implicitDefEqProofs` to force `simp` to create a proof term for
`rfl`-theorems. This can positively impact proof checking time in the
kernel.

This PR also fixes an issue in the `split` tactic that has been exposed
by this feature. It was looking for `split` candidates in proofs and
implicit arguments. See new test for issue exposed by the previous
feature.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-11-29 22:29:27 +00:00
Lean stage0 autoupdater
3752241edd chore: update stage0 2024-11-29 21:32:14 +00:00
Marc Huisinga
39bffb6fda fix: don't walk full project file tree on every file save (#6246)
This PR 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.

This issue was originally reported at
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Compiling.20too.20slow/near/484386515
and uncovered in a lengthy investigation. The performance bug that
causes the Lean language server to walk the full project file tree when
the file watcher for .ilean files is triggered was introduced when the
.ileans were first introduced, whereas the specific issue of file saving
also triggering the walk was introduced by #3247 in 4.8.0 and the use of
the file watcher for .lean files, which would then also trigger the
directory walk. Combining this with VS Code's auto-save feature causes
the language server to walk the full project file tree on every change
of the document.

It somehow hasn't really been much of an issue until now, but we still
do way too much work in the watchdog main loop. I'll look into resolving
that more general issue in the future.
2024-11-29 15:34:44 +00:00
Sebastian Ullrich
86f303774a chore: harden markPersistent uses (#6257)
This API may or may not have been a footgun, better to be safe than
`sorry`
2024-11-29 14:33:33 +00:00
Sebastian Ullrich
d97af36867 feat: simpler trace timing annotation logic (#6259)
This PR ensures that nesting trace nodes are annotated with timing
information iff `trace.profiler` is active.

The previous connection to the otherwise unrelated `profiler` option was
a remnant from before `trace.profiler` existed; if users want to
annotate explicitly activated trace classes only, they can instead
increase `trace.profiler.threshold`.
2024-11-29 14:03:01 +00:00
Mac Malone
27cc0c8039 feat: USize.reduceToNat (#6190)
This PR adds the builtin simproc `USize.reduceToNat` which reduces the
`USize.toNat` operation on literals less than `UInt32.size` (i.e.,
`4294967296`).
2024-11-29 08:24:40 +00:00
Mac Malone
c9ee66fb1f chore: lake: fix typo in materialize error (#6250) 2024-11-29 06:20:51 +00:00
Kim Morrison
5c7e027b03 chore: cleanup of List/Array lemmas (#6249)
This PR performs further cleanup of `List/Lemmas.lean` and
`Array/Lemmas.lean`, trying to make them more parallel.

Still a long way to go.
2024-11-29 06:12:38 +00:00
Mac Malone
4969ec9cdb feat: more UInt lemmas (#6205)
This PR 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.

**Summary of all changes:**

* Upstreamed and added `toNat` constructors lemmas: `toNat_mk`,
`ofNat_toNat`, `toNat_ofNat`, `toNat_ofNatCore`, and
`USize.toNat_ofNat32`
* Upstreamed and added `toNat` canonicalization; `val_val_eq_toNat` and
`toNat_toBitVec_eq_toNat`
* Added injectivity iffs: `toBitVec_inj`, `toNat_inj`, and `val_inj`
* Added inequality iffs: `le_iff_toNat_le` and `lt_iff_toNat_lt`
* Upstreamed antisymmetry lemmas: `le_antisymm` and `le_antisymm_iff`
* Upstreamed missing `toNat` lemmas on arithmetic operations:
`toNat_add`, `toNat_sub`, `toNat_mul`
* Upstreamed and added missing conversion lemmas: `toNat_toUInt*` and
`toNat_USize`
* Added missing `USize` conversions: `USize.toUInt8`, `UInt8.toUSize`,
`USize.toUInt16`, `UInt16.toUSize`
2024-11-29 02:08:52 +00:00
Mac Malone
827062f807 feat: System.Platform.numBits inequalities (#6247)
This PR adds the theorems `numBits_pos`, `le_numBits`, `numBits_le` ,
which make proving inequalities about `System.Platform.numBits` easier.
2024-11-28 21:20:47 +00:00
Kim Morrison
6d495586a1 chore: deprecate Fin.ofNat (replaced by Fin.ofNat', subsequently to be renamed) (#6242)
This PR deprecates `Fin.ofNat` in favour of `Fin.ofNat'` (which takes an
`[NeZero]` instance, rather than returning an element of `Fin (n+1)`).

After leaving the deprecation warning in place for some time, we will
then rename `ofNat'` back to `ofNat`.
2024-11-28 05:23:23 +00:00
Kim Morrison
10d1d2cc25 chore: cleanup in Array/Lemmas (#6243) 2024-11-28 03:50:41 +00:00
Wojciech Nawrocki
2325f5c7b9 doc: explain abstraction order (#6239)
This PR explains the order in which `Expr.abstract` introduces de Bruijn
indices.
2024-11-28 01:37:30 +00:00
Sofia Rodrigues
88e3a2b1ab fix: improve directory fallback on Linux and trim local time identifier (#6221)
This PR 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.
2024-11-27 14:52:35 +00:00
Lean stage0 autoupdater
b378fe98a7 chore: update stage0 2024-11-27 14:20:47 +00:00
Sebastian Ullrich
5f1ff42a15 fix: Runtime.markPersistent is unsafe (#6209)
This PR documents under which conditions `Runtime.markPersistent` is
unsafe and adjusts the elaborator accordingly
2024-11-27 13:32:05 +00:00
Jens Petersen
30d01f7a9a fix: add cmake COPY_CADICAL option to allow turning off install copy (#5931)
This PR adds a cmake knob to allow turning off installing a copy of
`cadical`.
This can be useful for custom builds/installs where cadical is already
available in the system.

Closes: #5603
2024-11-27 13:21:20 +00:00
Sebastian Ullrich
81b85d8e2f fix: reparsing may need to backtrack two commands (#6236)
This PR fixes an issue where edits to a command containing a nested
docstring fail to reparse the entire command.

Fixes #6227
2024-11-27 13:06:57 +00:00
Sebastian Ullrich
5982a6d230 chore: default parseQuotWithCurrentStage to true in stage 0 (#6212)
Use the default that solves bootstrapping issues in exchange for an
insignificant(?) perf overhead
2024-11-27 12:58:44 +00:00
Mac Malone
ac1197ff59 feat: Lean.loadPlugin (#6130)
This PR adds `Lean.loadPlugin` which exposes functionality similar to
the `lean` executable's `--plugin` option to Lean code.

This will allow custom Lean frontends (e.g., Lake, the Lean language
server) to also load plugins.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-11-27 09:56:31 +00:00
Kim Morrison
609346f5e0 feat: relate Nat.fold/foldRev/any/all to List.finRange (#6235)
This PR relates that operations `Nat.fold`/`foldRev`/`any`/`all` to the
corresponding List operations over `List.finRange`.
2024-11-27 05:38:18 +00:00
Mac Malone
04f80a1f9f feat: lake: detailed Reservoir fetch error (#6231)
This PR 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.

Closes #5330.
2024-11-27 05:07:09 +00:00
Kim Morrison
7e9dd5668b feat: upstream List.finRange from Batteries (#6234)
This PR upstreams the definition and basic lemmas about `List.finRange`
from Batteries.

Thanks for contributors to Batteries and Mathlib who've previously
worked on this material. Further PRs are welcome here. I'll be adding
more API later.
2024-11-27 04:27:22 +00:00
Kim Morrison
79f050b816 feat: upstream Vector lemmas (#6233)
This PR upstreams lemmas about `Vector` from Batteries.

I'll be adding more soon, and PRs are welcome, particularly from those
who have previously contributed to `Vector` in Batteries.
2024-11-27 04:19:30 +00:00
Siddharth
af4a3f2251 feat: BitVec.toInt_abs (#6154)
This PR implements `BitVec.toInt_abs`.


The absolute value of `x : BitVec w` is naively a case split on the sign
of `x`.
However, recall that when `x = intMin w`, `-x = x`.
Thus, the full value of `abs x` is computed by the case split:
- If `x : BitVec w` is `intMin`, then its absolute value is also `intMin
w`, and
  thus `toInt` will equal `intMin.toInt`.
- Otherwise, if `x` is negative, then `x.abs.toInt = (-x).toInt`.
- Finally, when `x` is nonnegative, then `x.abs.toInt = x.toInt`.

```lean
theorem toInt_abs {x : BitVec w} :
  x.abs.toInt =
    if x = intMin w then (intMin w).toInt
    else if x.msb then -x.toInt
    else x.toInt
```

We also provide a variant of `toInt_abs` that
hides the case split for `x` being positive or negative by using
`natAbs`.
```lean
theorem toInt_abs_eq_natAbs {x : BitVec w} : x.abs.toInt =
    if x = intMin w then (intMin w).toInt else x.toInt.natAbs
```

Supercedes https://github.com/leanprover/lean4/pull/5787

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2024-11-27 03:50:55 +00:00
Siddharth
7692343720 feat: BitVec.toNat BitVec.signExtend (#6155)
This PR adds `toNat` theorems for `BitVec.signExtend.`

Sign extending to a larger bitwidth depends on the msb. If the msb is
false, then the result equals the original value. If the msb is true,
then we add a value of `(2^v - 2^w)`, which arises from the sign
extension.

```lean
theorem toNat_signExtend (x : BitVec w) {v : Nat} :
    (x.signExtend v).toNat = (x.setWidth v).toNat + if x.msb then 2^v - 2^w else 0
```

Co-authored-by: Harun Khan <harun19@stanford.edu>
2024-11-27 03:50:15 +00:00
Luisa Cicolini
597ef8cfee feat: add Nat.mod_eq_sub and fix dependencies from Nat.sub_mul_eq_mod_of_lt_of_le (#6160)
This PR 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.
2024-11-27 03:48:59 +00:00
Kim Morrison
321e148f51 feat: Array fold lemmas (#6230)
This PR copies some lemmas about `List.foldX` to `Array`.
2024-11-27 02:09:41 +00:00
Kyle Miller
ce692436f4 feat: expose diff at "synthesized type class instance is not definitionally equal" error (#6213)
This PR exposes the difference in "synthesized type class instance is
not definitionally equal" errors.
2024-11-27 00:52:58 +00:00
Mac Malone
23bec25fce feat: Nat.lt_pow_self (#6200)
This PR upstreams `Nat.lt_pow_self` and `Nat.lt_two_pow` from Mathlib
and uses them to prove the simp theorem `Nat.mod_two_pow`.

This simplifies expressions like `System.Platform.numBits % 2 ^
System.Platform.numBits = System.Platform.numBits`, which is needed for
#6188.
2024-11-26 23:42:23 +00:00
Mac Malone
3d511a582a feat: USize.size inequalities (#6203)
This PR adds the theorems `le_usize_size` and `usize_size_le`, which
make proving inequalities about `USize.size` easier.

It also deprecates `usize_size_gt_zero` in favor of `usize_size_pos` (as
that seems more consistent with our naming covention) and adds
`USize.toNat_ofNat_of_lt_32` for dealing with small USize literals.

It also moves `USize.ofNat32` and `USize.toUInt64` to
`Init.Data.UInt.Basic` as neither are used in `Init.Prelude` anymore.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-11-26 23:42:15 +00:00
Mac Malone
51015bf5c0 fix: lake: eager logging when materializing deps (#6225)
This PR makes `lake build` also eagerly print package materialization
log lines. Previously, only a `lake update` performed eager logging.
2024-11-26 22:11:23 +00:00
Mac Malone
3ece36de9d feat: GitHub cloud releases do not clobber prebuilt artifacts (#6218)
This PR 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`.
2024-11-26 22:10:42 +00:00
Leonardo de Moura
54c48363ca feat: proper let_fun support in simp (#6220)
This PR adds proper support for `let_fun` in `simp`.
2024-11-26 21:42:08 +00:00
Markus Himmel
0a22f8fa6f chore: improve consistency & documentation for hash table insert and insertMany (#6222)
This PR 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.

---------

Co-authored-by: Kim Morrison <scott.morrison@gmail.com>
2024-11-26 11:22:23 +00:00
Kim Morrison
f70b7e5722 feat: @[deprecated] requires a replacement identifier or message, and a since field (#6112)
This PR 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.
2024-11-26 08:45:54 +00:00
Kim Morrison
9a17919ef1 feat: missing lemmas about List's BEq (#6217)
This PR adds `simp` lemmas about `List`'s `==` operation.
2024-11-25 22:55:03 +00:00
Kyle Miller
606aeddf06 feat: make dot notation be affected by export/open (#6189)
This PR 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.

This also fixes a bug in explicit-mode generalized field notation
(`@x.f`) where `x` could be passed as the wrong argument. This was not a
bug for explicit-mode structure projections.

Closes #3031. Addresses the `Function` namespace issue in #1629.
2024-11-25 18:38:17 +00:00
Kyle Miller
0eca3bd55d feat: add a coercion from List Nat to Lean.Meta.Occurrences (#6206)
This PR 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`.
2024-11-25 13:19:23 +00:00
Kim Morrison
43dfc2a25f chore: fix Vector.indexOf? (#6208)
Just a better defeq.
2024-11-25 10:47:58 +00:00
Mac Malone
935fcfb6ec feat: non-opaque UInt64.toUSize (#6202)
This PR makes `USize.toUInt64` a regular non-opaque definition. 

It also moves it to `Init.Data.UInt.Basic`, as it is not actually used
in `Init.Prelude` anymore.
2024-11-25 08:33:53 +00:00
Kim Morrison
20acc72a29 feat: ensure Fin.foldl/r are semireducible (#6207)
This PR 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.

Thanks @eric-wieser and @digama0 for diagnosing on
[Zulip](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/.60List.2EfinRange.60.20in.20Mathlib/near/484191814).
2024-11-25 03:21:36 +00:00
Kim Morrison
c3948cba24 feat: upstream definition of Vector from Batteries (#6197)
This PR upstreams the definition of `Vector` from Batteries, along with
the basic functions.
2024-11-24 23:01:32 +00:00
Kim Morrison
4e885be96d feat: rename Array.setD to setIfInBounds (#6195)
This PR renames `Array.setD` to `Array.setIfInBounds`.
2024-11-24 08:54:19 +00:00
Kim Morrison
42e98bd3c9 feat: Array.swap takes Nat arguments, with tactic provided proofs (#6194)
This PR changes the signature of `Array.swap`, so it takes `Nat`
arguments with tactic provided bounds checking. It also renames
`Array.swap!` to `Array.swapIfInBounds`.
2024-11-24 07:59:57 +00:00
Kim Morrison
884a9ea2ff feat: remove partial keyword and runtime bounds checks from Array.binSearch (#6193)
This PR completes the TODO in `Init.Data.Array.BinSearch`, removing the
`partial` keyword and converting runtime bounds checks to compile time
bounds checks.
2024-11-24 06:08:16 +00:00
Kyle Miller
2f5c7d0465 fix: structures with copied parents can now use other parents as instances (#6175)
This PR 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.

Note: there is still the limitation that parents that are not
represented as subobjects do not themselves provide instances to other
parents.
2024-11-24 04:22:39 +00:00
Kim Morrison
a5ffef7e13 feat: Array.zipWithAll (#6191)
This PR adds `Array.zipWithAll`, and the basic lemmas relating it to
`List.zipWithAll`.
2024-11-24 03:49:57 +00:00
Kim Morrison
442c3d5097 chore: missing deprecations for Lean.HashMap (#6192)
This PR adds deprecations for `Lean.HashMap` functions which did not
receive deprecation attributes initially.

(Requested on
[zulip](https://leanprover.zulipchat.com/#narrow/channel/348111-batteries/topic/Unifying.20.60Batteries.2EHashMap.60.20and.20.60Std.2EHashMap.60.2E/near/484113660).)

Note that I've used the original deprecation date of 2024-08-08, when
the type itself was deprecated; this will not delay removal.
2024-11-24 03:29:48 +00:00
Joachim Breitner
bf13b24692 doc: refine kernel code comments (#6150)
I just spent too much time being confused about the kernel type checker
until I noticed that `lazy_delta_reduction` modifies its arguments.
2024-11-23 17:13:51 +00:00
Andrii Kurdiumov
51d1cc61d7 fix: remove obsolete sentence in doc-string (#6185)
Even if this sentence is technically true, it do not add anything to the
explanation of typechecker and code.
2024-11-23 07:56:31 +00:00
Siddharth
107a2e8b2e feat: BitVec.toInt BitVec.signExtend (#6157)
This PR adds toInt theorems for BitVec.signExtend.

If the current width `w` is larger than the extended width `v`,
then the value when interpreted as an integer is truncated,
and we compute a modulo by `2^v`.

```lean
theorem toInt_signExtend_of_le (x : BitVec w) (hv : v ≤ w) :
    (x.signExtend v).toInt = Int.bmod (x.toNat) (2^v)
```

Co-authored-by: Siddharth Bhat <siddu.druid@gmail.com>
Co-authored-by: Harun Khan <harun19@stanford.edu>


Stacked on top of #6155

---------

Co-authored-by: Harun Khan <harun19@stanford.edu>
2024-11-23 07:29:08 +00:00
Kim Morrison
c4b0b94c91 chore: use Array.findFinIdx? where it is better than findIdx? (#6184)
This PR uses `Array.findFinIdx?` in preference to `Array.findIdx?` where
it allows converting a runtime bounds check to a compile time bounds
check.

(and some other minor cleanup)
2024-11-23 07:22:31 +00:00
Kyle Miller
ba3f2b3ecf fix: make sure #check id heeds pp.raw (#6181)
This PR 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.
2024-11-23 00:39:58 +00:00
Leonardo de Moura
4a69643858 fix: nontermination while generating equation lemmas for match-expressions (#6180)
This PR 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.

closes #6067
2024-11-23 00:06:34 +00:00
Kyle Miller
b6a0d63612 feat: have "motive is not type correct" come with an explanation (#6168)
This PR 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.

Suggested [on
Zulip](https://leanprover.zulipchat.com/#narrow/channel/113489-new-members/topic/tactic.20'rewrite'.20failed.2C.20motive.20is.20not.20type.20correct/near/483545154).
2024-11-22 23:56:17 +00:00
Kyle Miller
5145030ff4 chore: refactor Elab.StructInst to use mutual for its structures/inductives (#6174)
Making use of #6125.
2024-11-22 19:17:48 +00:00
Kyle Miller
d3cb812fb6 chore: add test for recursive structures (#6173)
Closes #6140. This was fixed by #6125.
2024-11-22 18:53:59 +00:00
Lean stage0 autoupdater
e066c17a65 chore: update stage0 2024-11-22 18:29:01 +00:00
Sebastian Ullrich
38cff08888 feat: creation and reporting for asynchronous elaboration tasks (#6170)
This PR adds core metaprogramming functions for forking off background
tasks from elaboration such that their results are visible to reporting
and the language server
2024-11-22 17:12:30 +00:00
David Thrane Christiansen
3388fc8d06 doc: fix typo and make docstring more precise (#6009)
This PR fixes a typo in the docstring for prec and makes the text
slightly more precise.
2024-11-22 16:30:01 +00:00
Eric Wieser
5adcd520fa fix: make the stack handling more robust to sanitizers and -O3 (#6143)
This PR 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.

The approach used here is the same as the one used by clang.
2024-11-22 15:10:20 +00:00
David Thrane Christiansen
1126407d9b feat: create temporary directories (#6148)
This PR adds a primitive for creating temporary directories, akin to the
existing functionality for creating temporary files.
2024-11-22 12:24:32 +00:00
Kyle Miller
a19ff61e15 feat: allow structure in mutual blocks (#6125)
This PR 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.

Internally, this is a large refactor of both the `inductive` and
`structure` commands. Common material is now in
`Lean.Elab.MutualInductive`, and each command plugs into this mutual
inductive elaboration framework with the logic specific to the
respective command. For example, `structure` has code to add projections
after the inductive types are added to the environment.

Closes #4182
2024-11-22 09:20:07 +00:00
Lean stage0 autoupdater
6202461a21 chore: update stage0 2024-11-22 04:42:45 +00:00
Kim Morrison
ea221f3283 feat: Nat.(fold|foldRev|any|all)M? take a function which sees the upper bound (#6139)
This PR 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.
2024-11-22 03:05:51 +00:00
Kyle Miller
7c50d597c3 feat: add builtin attribute to support elaboration of mutual inductives/structures (#6166)
This PR is a prerequisite for #6125.
2024-11-22 01:48:37 +00:00
Tony Beta Lambda
99031695bd feat: display coercions with a type ascription (#6119)
This PR adds a new delab option `pp.coercions.types` which, when
enabled, will display all coercions with an explicit type ascription.

[Link to Zulip
discussion](https://leanprover.zulipchat.com/#narrow/channel/239415-metaprogramming-.2F-tactics/topic/Roundtripping.20delaboration.20involving.20coercions)

Towards #4315
2024-11-21 23:02:47 +00:00
JovanGerb
b7248d5295 fix: revert creates natural metavariable goal (#6145)
This PR fixes the `revert` tactic so that it creates a `syntheticOpaque`
metavariable as the new goal, instead of a `natural` metavariable

I reported it on
[Zulip](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/.60revert.60.20gives.20natural.20metavariable.20goal/near/483388096)
2024-11-21 23:00:57 +00:00
Tobias Grosser
7f2e7e56d2 feat: BitVec.getMsbD_[ofNatLt|allOnes|not] (#6149)
This PR completes the elementwise accessors for `ofNatLt`, `allOnes`,
and `not` by adding their implementations of `getMsbD`.
2024-11-21 22:13:09 +00:00
Tobias Grosser
1fe66737ad feat: BitVec.toInt_[or|and|xor|not] (#6151)
This PR completes the `toInt` interface for `BitVec` bitwise operations.
2024-11-21 22:10:33 +00:00
Bhavik Mehta
765eb02279 doc: adjust file reference in Data.Sum (#6158)
This file was upstreamed from batteries; I just got bitten by the
invalid reference and it took quite a while to figure out that this one
had been moved!
2024-11-21 21:48:27 +00:00
Henrik Böving
a101377054 perf: speed up reflection of if in bv_decide (#6162)
This PR adds a slight performance improvement to reflection of `if`
statements that I noticed by profiling Leanwuzla against SMTCOMP's
`non-incremental/QF_BV/fft/Sz256_6616.smt2`.

In particular:
1. The profile showed about 4 percent of the total run time were spent
constructing these decidable instances in reflection of `if` statements.
We can construct them much quicker by hand as they always have the same
structure
2. This delays construction of these statements until we actually
generate the reflection proof that we wish to submit to the kernel. Thus
if we encounter a SAT instad of an UNSAT problem we will not spend time
generating these expressions anymore.

```
baseline
  Time (mean ± σ):     31.236 s ±  0.258 s
  Range (min … max):   30.899 s … 31.661 s    10 runs

after
  Time (mean ± σ):     30.671 s ±  0.288 s
  Range (min … max):   30.350 s … 31.156 s    10 runs
```
2024-11-21 19:40:14 +00:00
Kyle Miller
aca9929d84 fix: make sure whitespace is printed before tactic configuration (#6161)
This PR ensures whitespace is printed before `+opt` and `-opt`
configuration options when pretty printing, improving the experience of
tactics such as `simp?`.

Reported [on
Zulip](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Minor.20simp.3F.20annoyances/near/483736310)
2024-11-21 19:21:59 +00:00
Sebastian Ullrich
19a701e5c9 refactor: one more recursive structure (#6159) 2024-11-21 18:30:28 +00:00
Leonardo de Moura
fc4305ab15 fix: nontermination when generating the match-expression splitter theorem (#6146)
This PR 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.

closes #6065
2024-11-21 17:20:33 +00:00
Kim Morrison
9cf83706e7 chore: add changelog-* labels via comment (#6147)
This PR enables contributors to modify `changelog-*` labels simply by
writing a comment with the desired label.
2024-11-21 07:23:13 +00:00
Tobias Grosser
459c6e2a46 feat: BitVec.getElem_[sub|neg|sshiftRight'|abs] (#6126)
This PR adds lemmas for extracting a given bit of a `BitVec` obtained
via `sub`/`neg`/`sshiftRight'`/`abs`.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2024-11-21 07:01:11 +00:00
Kim Morrison
72e952eadc chore: avoid runtime array bounds checks (#6134)
This PR avoids runtime array bounds checks in places where it can
trivially be done at compile time.

None of these changes are of particular consequence: I mostly wanted to
learn how much we do this, and what the obstacles are to doing it less.
2024-11-21 05:04:52 +00:00
damiano
56a80dec1b doc: doc-strings to module docs in Data/Array/Lemmas (#6144)
This PR converts 3 doc-string to module docs since it seems that this is
what they were intended to be!
2024-11-21 05:04:09 +00:00
JovanGerb
b894464191 fix: type occurs check bug (#6128)
This PR 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)

We get rid of `skipAtMostNumBinders`. This function was originally
defined for the purpose of making this test work, but it is a hack
because it allows cycles in the metavariable context.

It would make sense to split these changes into 2 PRs, but I combined
them here to show that the combination of them closes #6013 without
breaking anything

Closes #6013
2024-11-21 00:28:36 +00:00
Sebastian Ullrich
b30903d1fc refactor: make use of recursive structures in snapshot types (#6141) 2024-11-20 15:15:14 +00:00
Sebastian Ullrich
7fbe8e3b36 fix: Inhabited Float produced a bogus run-time value (#6136)
This PR fixes the run-time evaluation of `(default : Float)`.
2024-11-20 10:43:59 +00:00
Sebastian Ullrich
2fbc46641d fix: trace.profiler pretty-printing (#6138)
This PR fixes `trace.profiler.pp` not using the term pretty printer.

Fixes #5872
2024-11-20 10:21:02 +00:00
Sebastian Ullrich
17419aca7f feat: thread support for trace.profiler.output (#6137)
This PR adds support for displaying multiple threads in the trace
profiler output.

`TraceState.tid` needs to be adjusted for this purpose, which is not
done yet by the Lean elaborator as it is still single-threaded.
2024-11-20 10:02:39 +00:00
Kim Morrison
f85c66789d feat: Array.insertIdx/eraseIdx take a tactic-provided proof (#6133)
This PR 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.
2024-11-20 09:52:38 +00:00
Kim Morrison
c8b4f6b511 feat: duplicate List.attach/attachWith/pmap API for Array (#6132)
This PR duplicates the verification API for
`List.attach`/`attachWith`/`pmap` over to `Array`.
2024-11-20 01:16:48 +00:00
Luisa Cicolini
3c7555168d feat: add BitVec.(msb, getMsbD)_(rotateLeft, rotateRight) (#6120)
This PR adds theorems `BitVec.(getMsbD, msb)_(rotateLeft, rotateRight)`.

We follow the same strategy taken for `getLsbD`, constructing the
necessary auxilliary theorems first (relying on different hypotheses)
and then generalizing.

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
Co-authored-by: Tobias Grosser <tobias@grosser.es>
2024-11-19 23:04:14 +00:00
Kyle Miller
5eef3d27fb feat: have #print show precise fields of structures (#6096)
This PR 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.

Example output for `#print Monad`:
```
class Monad.{u, v} (m : Type u → Type v) : Type (max (u + 1) v)
number of parameters: 1
parents:
  Monad.toApplicative : Applicative m
  Monad.toBind : Bind m
fields:
  Functor.map : {α β : Type u} → (α → β) → m α → m β
  Functor.mapConst : {α β : Type u} → α → m β → m α
  Pure.pure : {α : Type u} → α → m α
  Seq.seq : {α β : Type u} → m (α → β) → (Unit → m α) → m β
  SeqLeft.seqLeft : {α β : Type u} → m α → (Unit → m β) → m α
  SeqRight.seqRight : {α β : Type u} → m α → (Unit → m β) → m β
  Bind.bind : {α β : Type u} → m α → (α → m β) → m β
constructor:
  Monad.mk.{u, v} {m : Type u → Type v} [toApplicative : Applicative m] [toBind : Bind m] : Monad m
resolution order:
  Monad, Applicative, Bind, Functor, Pure, Seq, SeqLeft, SeqRight
```

Suggested by Floris van Doorn [on
Zulip](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/.23print.20command.20for.20structures/near/482503637).
2024-11-19 21:54:45 +00:00
Leonardo de Moura
75d1504af2 fix: isDefEq for constants with different universe parameters (#6131)
This PR 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.

closes #6117
2024-11-19 21:39:13 +00:00
Mario Carneiro
a00cf6330f fix: add a missing case to Level.geq (#2689)
This PR adds a case to `Level.geq` that is present in the kernel's level
`is_geq` procedure, making them consistent with one another.

This came up during testing of `lean4lean`. Currently `Level.geq`
differs from `level::is_geq` in the case of `max u v >= imax u v`. The
elaborator function is overly pessimistic and yields `false` on this
while the kernel function yields true. This comes up concretely in the
`Trans` class:
```lean
class Trans (r : α → β → Sort u) (s : β → γ → Sort v) (t : outParam (α → γ → Sort w)) where
  trans : r a b → s b c → t a c
```
The type of this class is `Sort (max (max (max (max (max (max 1 u) u_1)
u_2) u_3) v) w)` (where `u_1 u_2 u_3` are the levels of `α β γ`), but if
you try writing that type explicitly then the `class` command fails.
Omitting the type leaves the `class` to infer the universe level (the
command assumes the level is correct, and the kernel agrees it is), but
including the type then the elaborator checks the level inequality with
`Level.geq` and fails.

---------

Co-authored-by: Kyle Miller <kmill31415@gmail.com>
2024-11-19 21:27:00 +00:00
Leonardo de Moura
1f32477385 fix: isDefEq when zetaDelta := false (#6129)
This PR fixes a bug at `isDefEq` when `zetaDelta := false`. See new test
for a small example that exposes the issue.
2024-11-19 21:22:02 +00:00
Thomas Köppe
91c14c7ee9 fix: only consider salient bytes in sharecommon eq, hash (#5840)
This PR changes `lean_sharecommon_{eq,hash}` to only consider the
salient bytes of an object, and not any bytes of any
unspecified/uninitialized unused capacity.

Accessing uninitialized storage results in undefined behaviour.

This does not seem to have any semantics disadvantages: If objects
compare equal after this change, their salient bytes are still equal. By
contrast, if the actual identity of allocations needs to be
distinguished, that can be done by just comparing pointers to the
storage.

If we wanted to retain the current logic, we would need initialize the
otherwise unused parts to some specific value to avoid the undefined
behaviour.

Closes #5831
2024-11-19 13:56:46 +00:00
Lean stage0 autoupdater
69530afdf9 chore: update stage0 2024-11-19 13:06:43 +00:00
Marc Huisinga
b7667c1604 fix: don't issue atomic id completions when there is a dangling dot (#5837)
This PR fixes an old auto-completion bug where `x.` would issue
nonsensical completions when `x.` could not be elaborated as a dot
completion.
2024-11-19 12:23:41 +00:00
Eric Wieser
d6f898001b chore: generalize List.get_mem (#6095)
This is syntactically more general than before, though up to eta
expansion it make no difference.
2024-11-19 11:08:10 +00:00
Marc Huisinga
a38566693b test: fix brittle structure instance completion test (#6127)
#5835 contains a brittle test that uses an FVar ID, which caused a
failure on master. This PR changes that test to use a declaration
instead.
2024-11-19 10:13:51 +00:00
Marc Huisinga
4bef3588b5 chore: update stage0 2024-11-19 09:26:58 +01:00
Marc Huisinga
64538cf6e8 chore: prepare for bootstrap
Co-Authored-By: Sebastian Ullrich <sebasti@nullri.ch>
2024-11-19 09:26:58 +01:00
Marc Huisinga
aadf3f1d2c feat: use new structInstFields parser to tag structure instance fields 2024-11-19 09:26:58 +01:00
Marc Huisinga
95bf45ff8b refactor: split Completion.lean 2024-11-19 09:26:58 +01:00
Marc Huisinga
2a02c121cf feat: structure auto-completion & partial InfoTrees 2024-11-19 09:26:58 +01:00
Mac Malone
4600bb16fc feat: use BaseIO at IO.rand (#6102)
This PR moves `IO.rand` and `IO.setRandSeed` to be in the `BaseIO`
monad.

This is their proper monad as neither can error.
2024-11-19 05:26:03 +00:00
Kim Morrison
7ccdfc30ff chore: turn off pp.mvars in apply? results (#6108)
Per request on
[zulip](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/apply.3F.20using.20tombstones/near/482895588).
2024-11-19 02:02:32 +00:00
Kim Morrison
7f0bdefb6e chore: fix apply? error reporting when out of heartbeats (#6121) 2024-11-19 00:57:59 +00:00
Joachim Breitner
799b2b6628 fix: handle reordered indices in structural recursion (#6116)
This PR 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.

Fixes #6015.
2024-11-18 11:28:02 +00:00
David Thrane Christiansen
b8d6e44c4f fix: liberalize rules for atoms by allowing leading '' (#6114)
This PR 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.
2024-11-18 10:19:20 +00:00
Kim Morrison
5a99cb326c chore: make Lean.Elab.Command.mkMetaContext public (#6113) 2024-11-18 06:14:34 +00:00
Kim Morrison
e10fac93a6 feat: lemmas for Array.findSome? and find? (#6111)
This PR fills in the API for `Array.findSome?` and `Array.find?`,
transferring proofs from the corresponding List statements.
2024-11-18 04:19:56 +00:00
Kyle Miller
62ae320e1c chore: document Lean.Elab.StructInst, refactor (#6110)
This PR does some mild refactoring of the `Lean.Elab.StructInst` module
while adding documentation.

Documentation is drawn from @thorimur's #1928.
2024-11-18 02:57:22 +00:00
Leonardo de Moura
98b1edfc1f fix: backtrack at injection failure (#6109)
This PR 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.
2024-11-18 02:26:06 +00:00
Leonardo de Moura
ab162b3f52 fix: isDefEq, whnf, simp caching and configuration (#6053)
This PR 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`.
2024-11-18 01:17:26 +00:00
Kim Morrison
b8a13ab755 chore: fix naming of left/right injectivity lemmas (#6106)
We've been internally inconsistent on the naming of these lemmas in
Lean; this changes them to match Mathlib (which, moreover, I think is
correct).
2024-11-18 00:53:46 +00:00
Sebastian Ullrich
405593ea28 chore: avoid stack overflow in debug tests (#6103) 2024-11-17 14:54:49 +00:00
Kim Morrison
24f305c0e3 chore: fix canonicalizer handling over forall/lambda (#6082)
This PR 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).
2024-11-17 07:34:45 +00:00
Leonardo de Moura
5d553d6369 fix: circular assignment at structure instance elaborator (#6105)
This PR fixes a stack overflow caused by a cyclic assignment in the
metavariable context. The cycle is unintentionally introduced by the
structure instance elaborator.

closes #3150
2024-11-17 00:56:52 +00:00
Sebastian Ullrich
a449e3fdd6 feat: IO.getTID (#6049)
This PR adds a primitive for accessing the current thread ID

To be used in a thread-aware trace profiler
2024-11-16 19:13:11 +00:00
Kyle Miller
764386734c fix: improvements to change tactic (#6022)
This PR 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`
```
2024-11-16 07:08:29 +00:00
Kyle Miller
7f1d7a595b fix: use Expr.equal instead of == in MVarId.replaceTargetDefEq and MVarId.replaceLocalDeclDefEq (#6098)
This PR 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.
2024-11-16 02:03:16 +00:00
Leonardo de Moura
f13e5ca852 chore: naming convention and NaN normalization (#6097)
Changes:
- `Float.fromBits` => `Float.ofBits`
- NaN normalization
2024-11-16 00:14:28 +00:00
Leonardo de Moura
ecbaeff24b feat: add Float.toBits and Float.fromBits (#6094)
This PR 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.

closes #6071
2024-11-15 19:45:19 +00:00
Kyle Miller
691acde696 feat: pp.parens option to pretty print with all parentheses (#2934)
This PR 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)`.

Any notations with precedence greater than or equal to `maxPrec` do not
receive such discretionary parentheses, since this precedence level is
considered to be infinity.

This option was a feature in the Lean 3 community edition.
2024-11-15 19:11:54 +00:00
Kyle Miller
b1e0c1b594 chore: remove decide! tactic (#6016)
This PR removes the `decide!` tactic in favor of `decide +kernel`
(breaking change).
2024-11-15 17:49:33 +00:00
Joachim Breitner
93b4ec0351 refactor: use mkFreshUserName in ArgsPacker (#6093)
and other small refinements done while investigating an issue; not
actually user-visible.
2024-11-15 15:59:14 +00:00
JovanGerb
f06fc30c0b perf: remove @[specialize] from mkBinding (#6019)
This PR 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.

As expected, the mathlib bench shows a very small improvement. About 95%
of files show a speedup.
(http://speed.lean-fro.org/mathlib4/compare/e7b27246-a3e6-496a-b552-ff4b45c7236e/to/6033df75-aa53-44d9-819d-51f93fc05e94?hash1=b28f0d7f7e9cc3949a9a3556a6b36513f37f690d)
2024-11-15 15:06:49 +00:00
Markus Himmel
64b35a8c19 perf: add LEAN_ALWAYS_INLINE to some functions (#6045)
Otherwise, clang refuses to inline them for large functions which leads
to a performance cliff.
2024-11-15 15:05:32 +00:00
Markus Himmel
688ee4c887 fix: constant folding for Nat.ble and Nat.blt (#6087)
This PR fixes a bug in the constant folding for the `Nat.ble` and
`Nat.blt` function in the old code generator, leading to a
miscompilation.

Closes #6086
2024-11-15 12:09:52 +00:00
Henrik Böving
9a3dd615e0 chore: bv_decide remove noop rewrites (#6080)
Merely removes rules that are actually just syntactic aliases but equal
at the `Expr` level.
2024-11-15 11:41:54 +00:00
Violeta Hernández
7e6363dc05 chore: join → flatten in docstring (#6040)
Update the docstring of `List.flatten`.
2024-11-15 10:11:42 +00:00
Kim Morrison
a074bd9a2b feat: implementation of Array.pmap (#6052)
This PR adds `Array.pmap`, as well as a `@[csimp]` lemma in terms of the
no-copy `Array.attachWith`.
2024-11-15 02:10:04 +00:00
Kyle Miller
498d41633b fix: pretty print .coeFun with terminfo of coercee (#6085)
This PR 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.
2024-11-15 01:45:38 +00:00
Sofia Rodrigues
e0d7c3ac79 feat: add date and time functionality (#4904)
This PR introduces date and time functionality to the Lean 4 Std.

Breaking Changes:
- `Lean.Data.Rat` is now `Std.Internal.Rat` because it's used by the
DateTime library.

---------

Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-11-14 14:04:19 +00:00
Joachim Breitner
6a5b122b40 perf: use RArray in simp_arith meta code (#6068 part 2)
This PR makes `simp_arith` use `RArray` for the context of the
reflection proofs, which scales better when there are many variables.

On our synthetic benchmark:
```
simp_arith1               instructions    -25.1% (-4892.6 σ)
```

No effect on mathlib, though, guess it’s not used much on large goals there:
http://speed.lean-fro.org/mathlib4/compare/873b982b-2038-462a-9b68-0c0fc457f90d/to/56e66691-2f1f-4947-a922-37b80680315d
2024-11-14 14:08:48 +01:00
Joachim Breitner
bf9ddf2c74 chore: update stage0 2024-11-14 14:08:48 +01:00
Joachim Breitner
3f47871e73 perf: use RArray in simp_arith meta code (#6068 part 1)
This PR prepares #6068 by using the `RArray` data structure in
`simp_arith` the simp-arith meta code.

After the subsequent stage0 we can change the simp-arith theorems in
`Init`.
2024-11-14 14:08:48 +01:00
Joachim Breitner
85f25967ea feat: Lean.RArray (#6070)
This PR adds the Lean.RArray data structure.

This data structure is equivalent to `Fin n → α` or `Array α`, but
optimized for a fast kernel-reduction `get` operation.

It is not suitable as a general-purpose data structure. The primary
intended use case is the “denote” function of a typical proof by
reflection proof, where only the `get` operation is necessary, and where
using `List.get` unnecessarily slows down proofs with more than a
hand-full of atomic expressions.


There is no well-formedness invariant attached to this data structure,
to keep it concise; it's semantics is given through `RArray.get`. In
that way one can also view an `RArray` as a decision tree implementing
`Nat → α`.

In #6068 this data structure is used in `simp_arith`.
2024-11-14 10:56:50 +00:00
David Thrane Christiansen
8e1ddbc5aa fix: validate atoms modulo leading and trailing whitespace (#6012)
This PR 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.

Closes #6011
2024-11-14 10:40:17 +00:00
Henrik Böving
e6e39f502f feat: add options to configure all of bv_decide's preprocessing (#6077)
This PR adds options to `bv_decide`'s configuration structure such that
all non mandatory preprocessing passes can be disabled.
2024-11-14 09:22:23 +00:00
Henrik Böving
debb82bc20 perf: make andFlattening work on deeply nested hyps in one pass (#6075)
No changelog as this PR improves performance of a feature that is not
yet released.
2024-11-14 09:09:25 +00:00
Violeta Hernández
9a85433477 refactor: allow Sort u in Squash (#6074)
Co-authored-by: Kim Morrison <kim@tqft.net>
2024-11-14 05:55:21 +00:00
Mac Malone
4616c0ac3e refactor: lake: avoid v! in builtin code (#6073)
Use of `v!` in Lake code can cause bootstrapping failures and is easily
avoided. It is perfectly safe in user code.
2024-11-14 05:00:02 +00:00
Leonardo de Moura
e55b681774 feat: add Context.setConfig (#6072)
This PR adds `Lean.Simp.Context.setConfig` function.
2024-11-14 00:32:13 +00:00
Kim Morrison
63132105ba feat: lemmas about for loops over Array (#6055)
This PR adds lemmas about for loops over `Array`, following the existing
lemmas for `List`.
2024-11-13 23:23:55 +00:00
Kim Morrison
350b36411c chore: upstream some NameMap functions (#6056) 2024-11-13 23:22:01 +00:00
Kim Morrison
1c30c76e72 chore: remove >6 month old deprecations (#6057) 2024-11-13 23:21:23 +00:00
Alissa Tung
d5adadc00e chore: add newline at end of file for lake new templates (#6026)
This PR adds a newline at end of each Lean file generated by `lake new`
templates.

I have tested it with a locally compiled Lean with this commit. I hope
these changes make `lake new`'s behavior more consistent with the Lean 4
plugins and libraries newlines convention.
2024-11-13 19:39:47 +00:00
Mac Malone
f08805e5c4 feat: message kinds (#5945)
This PR 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`.

The tag of trace messages has also been changed from `_traceMsg` to the
more friendly `trace`.
2024-11-13 18:05:52 +00:00
Joachim Breitner
256b49bda9 perf: optimize Nat.Linear.Poly.norm (#6064)
Not a huge benefit, but actually reduces the code complexity (no need
for the `.fuse` function), and can help with problems with many repeated
varibles.
2024-11-13 17:36:51 +00:00
Kyle Miller
28cf146d00 fix: make sure monad lift coercion elaborator has no side effects (#6024)
This PR 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.
2024-11-13 16:22:31 +00:00
Joachim Breitner
970261b1e1 perf: optimize Nat.Linear.Expr.toPoly (#6062) 2024-11-13 15:54:29 +00:00
Joachim Breitner
6b811f8c92 test: synthetic simp_arith benchmark (#6061)
This PR adds a simp_arith benchmark.

This benchmark highlights some improvable asymptotics in `Nat.Linear`,
which
will be fixed subsequently.
2024-11-13 15:49:52 +00:00
Henrik Böving
f721f94045 feat: Bool.to(U)IntX (#6060)
This PR implements conversion functions from `Bool` to all `UIntX` and
`IntX` types.

Note that `Bool.toUInt64` already existed in previous versions of Lean.
2024-11-13 15:49:16 +00:00
Sebastian Ullrich
86524d5c23 fix: line break in simp? output (#6048)
This PR fixes `simp?` suggesting output with invalid indentation 

Fixes #6006
2024-11-13 15:49:11 +00:00
Joachim Breitner
f18d9e04bc refactor: omega: avoid MVar machinery (#5991)
This PR simplifies the implementation of `omega`.

When constructing the proof, `omega` is using MVars only for the purpose
of doing case analysis on `Or`. We can simplify the implementation a
fair bit if we just produce the proof directly using `Or.elim`.

While it didn’t yield the performance benefits I was hoping for, this
still seems a worthwhile simplification, now that we already have it.
2024-11-13 15:49:03 +00:00
Joachim Breitner
fa33423c84 chore: pr-body: run as part of merge_group, but do not do anything (#6069) 2024-11-13 15:47:58 +00:00
Leonardo de Moura
1315266dd3 refactor: mark the Simp.Context constructor as private
motivation: this is the first step to fix the mismatch
between `isDefEq` and the discrimination tree indexing.
2024-11-13 14:12:55 +11:00
Leonardo de Moura
b1e52f1475 chore: mark Meta.Context.config as private (#6051)
Motivation: we want to modify the internal representation and improve
`isDefEq` caching.
This PR is preparing the stage for future modifications.
2024-11-13 13:30:06 +11:00
Kim Morrison
985600f448 chore: update stage0 2024-11-13 11:16:34 +11:00
Kim Morrison
ace6248e20 chore: deprecate Array.sequenceMap 2024-11-13 11:16:34 +11:00
Lean stage0 autoupdater
9f42368e1a chore: update stage0 2024-11-12 13:28:14 +00:00
Kim Morrison
a401368384 feat: various minor changes to List/Array API (#6044)
Minor emendations to the List/Array API, collected from other PRs that
are still in the pipeline.
2024-11-12 08:27:36 +00:00
Kim Morrison
5e01e628b2 chore: review Array operations argument order (#6041)
This PR 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.
2024-11-12 04:55:03 +00:00
Kim Morrison
3a408e0e54 feat: change Array.get to take a Nat and a proof (#6032)
This PR 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.

We may restore `Fin` based versions, either here or downstream, as
needed, but they won't be the "main" functions.

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-11-12 03:30:46 +00:00
Kyle Miller
675d2d5a11 feat: only direct parents of classes create projections (#5920)
This PR 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.

Features:
- Only parents that are not ancestors of other parents get instances.
This allows "discretionary" indirect parents to be inserted for the
purpose of computing strict resolution orders when
`structure.strictResolutionOrder` is enabled, without having an impact
on typeclass synthesis.
- Non-subobject projections are now theorems if the parent is a
proposition. These are also no longer `@[reducible]`.

Closes #2905
2024-11-12 01:55:17 +00:00
Henrik Böving
281c07ca97 fix: bv_decide embedded constraint substitution changes models (#6037)
This PR fixes `bv_decide`'s embedded constraint substitution to generate
correct counter examples in the corner case where duplicate theorems are
in the local context.
2024-11-11 16:33:21 +00:00
Sebastian Ullrich
004430b568 fix: avoid new term info around def bodies (#6031)
This PR fixes a regression with go-to-definition and document highlight
misbehaving on tactic blocks.

We explicitly avoid creating term info nodes around `by` blocks, which
#5338 might accidentally do; as the new info is not relevant for the
server, it is instead moved into a custom info.

Reported at
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Go-to-def.20for.20tactics.20broken.20on.20v4.2E14.2E0-rc1.
2024-11-11 14:54:59 +00:00
Henrik Böving
61f7dcb36b feat: bv_decide and flattening (#6035)
This PR 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.

Beyond this I also added some profiling infra structure for the passes.
2024-11-11 13:28:37 +00:00
Joachim Breitner
5c611f7814 fix: simp only [· ∈ ·] (#6030)
This PR fixes `simp only [· ∈ ·]` after #5020.

Fixes #5905
2024-11-11 10:03:27 +00:00
Siddharth
722cb73019 feat: BitVec normalization rule for udiv by twoPow (#6029)
This PR 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:

```lean
example {x : BitVec 16} : x / (BitVec.twoPow 16 2) = x >>> 2 := by bv_normalize
example {x : BitVec 16} : x / (BitVec.ofNat 16 8) = x >>> 3 := by bv_normalize
```
2024-11-11 09:45:47 +00:00
Kim Morrison
258d3725e7 feat: change Array.set to take a Nat and a tactic provided bound (#5988)
This PR changes the signature of `Array.set` to take a `Nat`, and a
tactic-provided bound, rather than a `Fin`.

Corresponding changes (but without the auto-param) for `Array.get` will
arrive shortly, after which I'll go more pervasively through the Array
API.
2024-11-11 07:53:24 +00:00
Kim Morrison
456e6d2b79 chore: deprecate duplicated Fin.size_pos (#6025) 2024-11-11 04:06:13 +00:00
Kim Morrison
48e3d76173 feat: variants of List.forIn_eq_foldlM (#6023) 2024-11-11 02:30:40 +00:00
Siddharth
78fe92507c feat: BitVec lemmas for smtUDiv, smtSDiv when denominator is zero (#5616)
This PR 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.

We build some `slt` theory, connecting it to `msb` for a clean proof. I
chose not to characterize `slt` in terms of `msb` a `simp` lemma, since
I anticipate use cases where we want to keep the arithmetic
interpretation of `slt`.
2024-11-10 22:08:43 +00:00
JovanGerb
811d8fb3c0 chore: cleanup (#6021)
This PR removes
- a duplicate `MonadMCtx` instance in `MetavarContext.lean`
- `:= return ←` that I had left there accidentally in a previous PR.
- the unnecessary application of `mapMetaM` in `withTransparency`.
2024-11-09 23:16:12 +00:00
Sebastian Ullrich
f55a9a71cb chore: CI: do not run check-pr-body in merge group 2024-11-09 12:58:53 +01:00
Henrik Böving
d12df6c2ad fix: bv_decide benchmarks (#6017)
This PR fixes the nightly build after bv_decide changed its options
2024-11-09 11:18:33 +00:00
Kyle Miller
d1a99d8d45 fix: avoid delaborating with field notation if object is a metavariable (#6014)
This PR prevents `Nat.succ ?_` from pretty printing as `?_.succ`, which
should make `apply?` be more usable.

Closes #5993
2024-11-08 20:57:37 +00:00
Kyle Miller
c10e4c2256 feat: prop instance yields theorems (#5856)
This PR adds a feature to the the mutual def elaborator where the
`instance` command yields theorems instead of definitions when the class
is a `Prop`.

Closes #5672
2024-11-08 18:18:10 +00:00
Kyle Miller
e3420c08f1 feat: decide +revert and improvements to native_decide (#5999)
This PR 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.

Closes #2072
2024-11-08 18:17:46 +00:00
Sebastian Ullrich
4f7aa8c3c8 chore: CI: exempt drafts from PR body check (#6002) 2024-11-08 15:53:48 +00:00
Sebastian Ullrich
dac73c15c8 perf: avoid negative environment lookup (#5429)
Avoids some `Environment.find?` lookup misses that become especially
expensive on the async branch
2024-11-08 15:37:39 +00:00
Marc Huisinga
cb40ddad69 fix: avoid max heartbeat error in completion (#5996)
This now occurs for some large completions downstream of `import
Mathlib`. I'd like to get rid of this `whnf` call entirely in the
future, but this is a decent quick mitigation.
2024-11-08 13:47:10 +00:00
Alex Keizer
fc0529b020 fix: ensure instantiateMVarsProfiling adds a trace node (#5501)
We add a new `Meta.instantiateMVars` trace node to the
`instantiateMVarsProfiling` definition used in `elabMutualDef`, and we
replace various uses of plain `instantiateMVars` with the profiled
version (which necessitated pulling up the definition to be higher in
the file).

This fixes a "time leak" when profiling large proofs, where
instantiating the goal metavariable can take a significant amount of
time, that previously would not be accounted for when using the trace
profiler.
2024-11-08 13:26:44 +00:00
Henrik Böving
837a67bedb feat: change bv_decide to an elaborated config (#6010)
This PR 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.

The latter feature was requested by people using `bv_decide` on SMTLIB
which has ginormous terms that exceed the default.
2024-11-08 13:15:04 +00:00
Kyle Miller
85f2213d5a fix: unset trailing for simpa? "try this" suggestion (#5907)
Closes #4581
2024-11-08 12:36:49 +00:00
Lukas Gerlach
9b167e2051 feat: verify keys method on HashMaps (#5866)
This PR verifies the `keys` function on `Std.HashMap`.

---

Initial discussions have already happend with @TwoFX and we are
collaborating on this matter.
This will remain a draft as long as not all desired results have been
added.

If we should still create an issue for the topic of this PR, let us
know.
Of course, any other feedback is appreciated as well :)

---------

Co-authored-by: Markus Himmel <markus@lean-fro.org>
Co-authored-by: monsterkrampe <monsterkrampe@users.noreply.github.com>
Co-authored-by: jt0202 <johannes.tantow@gmail.com>
2024-11-08 07:24:58 +00:00
Kim Morrison
1870c003d0 chore: missing @[ext] attribute on monad transformer ext lemmas (#6008) 2024-11-08 06:53:49 +00:00
Kim Morrison
680177049f chore: List.modifyTailIdx naming fix (#6007) 2024-11-08 02:42:06 +00:00
Sebastian Ullrich
1b806c5535 chore: revert "CI: give Linux Debug unlimited test stack size" (#6001)
#5967 was the correct fix

Reverts leanprover/lean4#5953
2024-11-07 21:15:08 +00:00
Sebastian Ullrich
9b18262567 chore: new PR changelog template (#5976)
Enables us to auto-generate the changelog from the list of PRs for a
modicum of summarizing/categorizing work on PR creation.

Does not (yet) allow external contributors to set category labels by
themselves as this creates issues with triggering one workflow from
another, it is not clear whether they should be allowed to create new
categories, and the reviewer/triage team likely is in a better position
to do the categorization anyway.
2024-11-07 16:59:45 +00:00
Henrik Böving
d76d631856 feat: BitVec.sshiftRight' in bv_decide (#5995) 2024-11-07 15:23:45 +00:00
Henrik Böving
17e6f3b3c2 style: fix style in bv_decide normalizer (#5992)
Address comments by Markus in #5987
2024-11-07 11:56:12 +00:00
Sebastian Ullrich
5f7a40ae48 chore: fix test exclusion (#5990)
You cannot pass `-E` to `ctest` multiple times
2024-11-07 10:41:47 +00:00
Joachim Breitner
70435dfb5f refactor: name the default SizeOf instance (#5981)
This PR names the default SizeOf instance `instSizeOfDefault`

I regularly have to debug termination checking failures where I end up
hovering over some termination measure, and seeing `instSizeOfDefault`
is more likely to tell me that the default instance is used than
`instSizeOf`.
2024-11-07 09:21:32 +00:00
Henrik Böving
59ee47ad44 feat: BitVec.getMsbD in bv_decide (#5987)
Closes #5983.
2024-11-07 07:59:14 +00:00
Kim Morrison
ebc02fc6e8 feat: lemmas relating Array.findX and List.findX (#5985)
This PR 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).
2024-11-07 03:30:11 +00:00
Kim Morrison
05caf1bda9 feat: interactions between List.foldX and List.filterX (#5984)
This PR adds lemmas for `List` for the interactions between {`foldl`,
`foldr`, `foldlM`, `foldlrM`} and {`filter`, `filterMap`}.
2024-11-07 02:37:20 +00:00
Kim Morrison
b1dee4a42e chore: upstream List.insertIdx from Batteries, lemmas from Mathlib, and revise lemmas (#5969)
To follow, connecting this to `Array.insertAt` (and renaming).
2024-11-06 23:29:27 +00:00
Kim Morrison
a54226196d feat: minor lemmas about List.ofFn (#5982)
`List.ofFn` still has very incomplete API.
2024-11-06 23:05:42 +00:00
Henrik Böving
196b1e9250 feat: BitVec.twoPow in bv_decide (#5979) 2024-11-06 17:51:44 +00:00
Sebastian Ullrich
345ecd20c9 chore: tag prerelease builds with -pre (#5943) 2024-11-06 14:47:52 +00:00
dependabot[bot]
7f0fe20315 chore: CI: bump mymindstorm/setup-emsdk from 12 to 14 (#5963)
Bumps
[mymindstorm/setup-emsdk](https://github.com/mymindstorm/setup-emsdk)
from 12 to 14.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/mymindstorm/setup-emsdk/releases">mymindstorm/setup-emsdk's
releases</a>.</em></p>
<blockquote>
<h2>Version 14</h2>
<h1>Breaking Changes</h1>
<p>The default cache key naming scheme was changed from
<code>{Emscripten version}-{OS type}-${CPU architecture}-master</code>
to <code>{Github workflow name}-{Emscripten version}-{OS type}-${CPU
architecture}</code>. If <code>actions-cache-folder</code> is defined,
ensure that there are no conflicts with other caches to prevent
issues.</p>
<h1>Changelog</h1>
<ul>
<li>Add option to override cache key naming scheme (<a
href="https://redirect.github.com/mymindstorm/setup-emsdk/issues/20">#20</a>)</li>
<li>Add workflow name to cache key naming scheme (<a
href="https://redirect.github.com/mymindstorm/setup-emsdk/issues/20">#20</a>)</li>
<li>Updated dependencies to latest versions</li>
</ul>
<h2>Version 13</h2>
<ul>
<li>Updated to Node 20</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="6ab9eb1bda"><code>6ab9eb1</code></a>
v13 -&gt; v14</li>
<li><a
href="bb630c3bf4"><code>bb630c3</code></a>
Update all dependencies to latest versions</li>
<li><a
href="74881103d0"><code>7488110</code></a>
Add workflow ID to cache key and cache key override option (<a
href="https://redirect.github.com/mymindstorm/setup-emsdk/issues/40">#40</a>)</li>
<li><a
href="d233ac12b0"><code>d233ac1</code></a>
v13</li>
<li><a
href="1749b22b40"><code>1749b22</code></a>
npm audit fix + update runtime to node20</li>
<li>See full diff in <a
href="https://github.com/mymindstorm/setup-emsdk/compare/v12...v14">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=mymindstorm/setup-emsdk&package-manager=github_actions&previous-version=12&new-version=14)](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>
2024-11-06 10:45:31 +00:00
Kim Morrison
1e98fd7f2d feat: add another List.find?_eq_some lemma (#5974)
Inspired by https://github.com/leanprover-community/mathlib4/pull/18593
2024-11-06 10:02:25 +00:00
Markus Himmel
76d32cbd2a chore: exclude leanruntest_task_test_io for now (#5973)
To be reenabled after investigation.
2024-11-06 09:40:20 +00:00
Kim Morrison
15139b6ef6 feat: relate Array.zipWith/zip/unzip with List versions (#5972) 2024-11-06 09:22:08 +00:00
Sebastian Ullrich
14c3d4b1a6 chore: CI: remove link checker for old manual
It started failing frequently after updating it and we're not actively working on this text anyway
2024-11-06 10:27:25 +01:00
Kim Morrison
910b20fb2c chore: consolidate decide_True and decide_true_eq_true (#5949) 2024-11-06 05:12:25 +00:00
Kim Morrison
4df71ed24f feat: relate Array.isPrefixOf with List.isPrefixOf (#5971) 2024-11-06 02:44:14 +00:00
Kyle Miller
406da78fc6 fix: arg conv tactic misreported number of arguments on error (#5968) 2024-11-06 02:13:24 +00:00
Kim Morrison
5d2bd1e2e4 chore: deprecate Array.split in favour of identical Array.partition (#5970) 2024-11-06 00:37:33 +00:00
Kyle Miller
c31daece6c chore: fix all_goals test, simulate the max rec depth error (#5967) 2024-11-05 20:09:06 +00:00
Markus Himmel
c157ddda11 fix: do not link statically against pthread/dl/rt (#5966) 2024-11-05 18:20:42 +00:00
Henrik Böving
c77b6a2c64 feat: define ISize and basic operations on it (#5961) 2024-11-05 15:08:19 +00:00
dependabot[bot]
c6e4947f4a chore: CI: bump dcarbone/install-jq-action from 1.0.1 to 2.1.0 (#5965)
Bumps
[dcarbone/install-jq-action](https://github.com/dcarbone/install-jq-action)
from 1.0.1 to 2.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dcarbone/install-jq-action/releases">dcarbone/install-jq-action's
releases</a>.</em></p>
<blockquote>
<h2>v2.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Support running action inside containers by <a
href="https://github.com/TaxBusby"><code>@​TaxBusby</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/10">dcarbone/install-jq-action#10</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/TaxBusby"><code>@​TaxBusby</code></a>
made their first contribution in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/10">dcarbone/install-jq-action#10</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v2.0.2...v2.1.0">https://github.com/dcarbone/install-jq-action/compare/v2.0.2...v2.1.0</a></p>
<h2>v2.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>use curl instead of wget to avoid download failure on macOS by <a
href="https://github.com/vaidyakhil"><code>@​vaidyakhil</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/8">dcarbone/install-jq-action#8</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/vaidyakhil"><code>@​vaidyakhil</code></a> made
their first contribution in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/8">dcarbone/install-jq-action#8</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v2.0.1...v2.0.2">https://github.com/dcarbone/install-jq-action/compare/v2.0.1...v2.0.2</a></p>
<h2>v2.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>using macos as dl link os prefix in lieu of osx by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/7">dcarbone/install-jq-action#7</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v2.0.0...v2.0.1">https://github.com/dcarbone/install-jq-action/compare/v2.0.0...v2.0.1</a></p>
<h2>v2.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>quick &amp; dirty 1.7 support by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/4">dcarbone/install-jq-action#4</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/dcarbone"><code>@​dcarbone</code></a>
made their first contribution in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/4">dcarbone/install-jq-action#4</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v1.0.1...v2.0.0">https://github.com/dcarbone/install-jq-action/compare/v1.0.1...v2.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8867ddb478"><code>8867ddb</code></a>
remove windows gubbins from container tests</li>
<li><a
href="945d84920f"><code>945d849</code></a>
Support running action inside containers (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/10">#10</a>)</li>
<li><a
href="1090b8bd11"><code>1090b8b</code></a>
use curl instead of wget to fix failure on macOS runners (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/8">#8</a>)</li>
<li><a
href="ff922c75b7"><code>ff922c7</code></a>
Update example-windows.yaml</li>
<li><a
href="7f4d6f4833"><code>7f4d6f4</code></a>
Update example-macos.yaml</li>
<li><a
href="bfb9fa8e7d"><code>bfb9fa8</code></a>
Update example-linux.yaml</li>
<li><a
href="c1548c666d"><code>c1548c6</code></a>
using macos as dl link os prefix in lieu of osx (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/7">#7</a>)</li>
<li><a
href="f07422da1e"><code>f07422d</code></a>
fixing version</li>
<li><a
href="183bc8df0e"><code>183bc8d</code></a>
trying without stupid</li>
<li><a
href="f6b58bacfe"><code>f6b58ba</code></a>
its late.</li>
<li>Additional commits viewable in <a
href="https://github.com/dcarbone/install-jq-action/compare/v1.0.1...v2.1.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dcarbone/install-jq-action&package-manager=github_actions&previous-version=1.0.1&new-version=2.1.0)](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>
2024-11-05 11:23:59 +00:00
dependabot[bot]
01814185a6 chore: CI: bump dawidd6/action-download-artifact from 2 to 6 (#5964)
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 2 to 6.
<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>v6</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v5...v6">https://github.com/dawidd6/action-download-artifact/compare/v5...v6</a></p>
<h2>v5</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v4...v5">https://github.com/dawidd6/action-download-artifact/compare/v4...v5</a></p>
<h2>v4</h2>
<h2>What's Changed</h2>
<ul>
<li><strong>VERSIONING CHANGE</strong>: now there will only be major
releases of this action, e.g. v5, v6 and so on</li>
<li>build(deps): bump undici from 5.28.3 to 5.28.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/284">dawidd6/action-download-artifact#284</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.4 to
2.1.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/285">dawidd6/action-download-artifact#285</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.5 to
2.1.7 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/287">dawidd6/action-download-artifact#287</a></li>
<li>build(deps): bump adm-zip from 0.5.12 to 0.5.13 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/289">dawidd6/action-download-artifact#289</a></li>
<li>Set allow_forks to false by default by <a
href="https://github.com/timweri"><code>@​timweri</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/290">dawidd6/action-download-artifact#290</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/timweri"><code>@​timweri</code></a> made
their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/290">dawidd6/action-download-artifact#290</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3...v4">https://github.com/dawidd6/action-download-artifact/compare/v3...v4</a></p>
<h2>v3.1.4</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump adm-zip from 0.5.10 to 0.5.12 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/282">dawidd6/action-download-artifact#282</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.2 to
2.1.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/280">dawidd6/action-download-artifact#280</a></li>
<li>fix: accept expired artifacts with documentation url by <a
href="https://github.com/wdconinc"><code>@​wdconinc</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/283">dawidd6/action-download-artifact#283</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/wdconinc"><code>@​wdconinc</code></a>
made their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/283">dawidd6/action-download-artifact#283</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3...v3.1.4">https://github.com/dawidd6/action-download-artifact/compare/v3...v3.1.4</a></p>
<h2>v3.1.3</h2>
<h2>What's Changed</h2>
<ul>
<li>node_modules: upgrade by <a
href="https://github.com/dawidd6"><code>@​dawidd6</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/276">dawidd6/action-download-artifact#276</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.1 to
2.1.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/277">dawidd6/action-download-artifact#277</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3.1.2...v3.1.3">https://github.com/dawidd6/action-download-artifact/compare/v3.1.2...v3.1.3</a></p>
<h2>v3.1.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Read workflow_search input as a boolean by <a
href="https://github.com/klutchell"><code>@​klutchell</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/273">dawidd6/action-download-artifact#273</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/klutchell"><code>@​klutchell</code></a>
made their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/273">dawidd6/action-download-artifact#273</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3.1.1...v3.1.2">https://github.com/dawidd6/action-download-artifact/compare/v3.1.1...v3.1.2</a></p>
<h2>v3.1.1</h2>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bf251b5aa9"><code>bf251b5</code></a>
node_modules: upgrade</li>
<li><a
href="93c6296611"><code>93c6296</code></a>
README: v5</li>
<li><a
href="deb3bb8325"><code>deb3bb8</code></a>
node_modules: upgrade</li>
<li><a
href="1d93f37db2"><code>1d93f37</code></a>
README: v4</li>
<li><a
href="854e2de939"><code>854e2de</code></a>
Set allow_forks to false by default (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/290">#290</a>)</li>
<li><a
href="436c9d3774"><code>436c9d3</code></a>
build(deps): bump adm-zip from 0.5.12 to 0.5.13 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/289">#289</a>)</li>
<li><a
href="14040524bb"><code>1404052</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.5 to 2.1.7
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/287">#287</a>)</li>
<li><a
href="8a9be734dc"><code>8a9be73</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.4 to 2.1.5
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/285">#285</a>)</li>
<li><a
href="df593bbd04"><code>df593bb</code></a>
build(deps): bump undici from 5.28.3 to 5.28.4 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/284">#284</a>)</li>
<li><a
href="09f2f74827"><code>09f2f74</code></a>
fix: accept expired artifacts with documentation url (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/283">#283</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v2...v6">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=2&new-version=6)](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>
2024-11-05 11:12:20 +00:00
dependabot[bot]
47d0060934 chore: CI: bump actions/github-script from 6 to 7 (#5962)
Bumps [actions/github-script](https://github.com/actions/github-script)
from 6 to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/github-script/releases">actions/github-script's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add base-url option by <a
href="https://github.com/robandpdx"><code>@​robandpdx</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/429">actions/github-script#429</a></li>
<li>Expose async-function argument type by <a
href="https://github.com/viktorlott"><code>@​viktorlott</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/402">actions/github-script#402</a>,
see for details <a
href="https://github.com/actions/github-script#use-scripts-with-jsdoc-support">https://github.com/actions/github-script#use-scripts-with-jsdoc-support</a></li>
<li>Update dependencies and use Node 20 by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/425">actions/github-script#425</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/navarroaxel"><code>@​navarroaxel</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/285">actions/github-script#285</a></li>
<li><a href="https://github.com/robandpdx"><code>@​robandpdx</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/429">actions/github-script#429</a></li>
<li><a
href="https://github.com/viktorlott"><code>@​viktorlott</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/402">actions/github-script#402</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v6.4.1...v7.0.0">https://github.com/actions/github-script/compare/v6.4.1...v7.0.0</a></p>
<h2>v6.4.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Add <code>@​octokit/plugin-request-log</code>, to produce debug
output for requests by <a
href="https://github.com/mjpieters"><code>@​mjpieters</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/358">actions/github-script#358</a></li>
<li>fix input handling by <a
href="https://github.com/mjpieters"><code>@​mjpieters</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/357">actions/github-script#357</a></li>
<li>Remove unused dependencies by <a
href="https://github.com/mjpieters"><code>@​mjpieters</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/356">actions/github-script#356</a></li>
<li>Default debug to current runner debug state by <a
href="https://github.com/mjpieters"><code>@​mjpieters</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/363">actions/github-script#363</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/mjpieters"><code>@​mjpieters</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/358">actions/github-script#358</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v6.4.0...v6.4.1">https://github.com/actions/github-script/compare/v6.4.0...v6.4.1</a></p>
<h2>v6.4.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump json5 from 2.1.3 to 2.2.3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/319">actions/github-script#319</a></li>
<li>Bump minimatch from 3.0.4 to 3.1.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/320">actions/github-script#320</a></li>
<li>Add node-fetch by <a
href="https://github.com/danmichaelo"><code>@​danmichaelo</code></a> in
<a
href="https://redirect.github.com/actions/github-script/pull/321">actions/github-script#321</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/jongwooo"><code>@​jongwooo</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/313">actions/github-script#313</a></li>
<li><a
href="https://github.com/austinvazquez"><code>@​austinvazquez</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/306">actions/github-script#306</a></li>
<li><a
href="https://github.com/danmichaelo"><code>@​danmichaelo</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/321">actions/github-script#321</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v6.3.3...v6.4.0">https://github.com/actions/github-script/compare/v6.3.3...v6.4.0</a></p>
<h2>v6.3.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update <code>@actions/glob</code> to 0.3.0 by <a
href="https://github.com/nineinchnick"><code>@​nineinchnick</code></a>
in <a
href="https://redirect.github.com/actions/github-script/pull/279">actions/github-script#279</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/nineinchnick"><code>@​nineinchnick</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/279">actions/github-script#279</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v6.3.2...v6.3.3">https://github.com/actions/github-script/compare/v6.3.2...v6.3.3</a></p>
<h2>v6.3.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Update <code>@​actions/core</code> to 1.10.0 by <a
href="https://github.com/rentziass"><code>@​rentziass</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/295">actions/github-script#295</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="60a0d83039"><code>60a0d83</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/440">#440</a>
from actions/joshmgross/v7.0.1</li>
<li><a
href="b7fb2001b4"><code>b7fb200</code></a>
Update version to 7.0.1</li>
<li><a
href="12e22ed06b"><code>12e22ed</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/439">#439</a>
from actions/joshmgross/avoid-setting-base-url</li>
<li><a
href="d319f8f5b5"><code>d319f8f</code></a>
Avoid setting <code>baseUrl</code> to undefined when input is not
provided</li>
<li><a
href="e69ef5462f"><code>e69ef54</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/425">#425</a>
from actions/joshmgross/node-20</li>
<li><a
href="ee0914b839"><code>ee0914b</code></a>
Update licenses</li>
<li><a
href="d6fc56f33b"><code>d6fc56f</code></a>
Use <code>@types/node</code> for Node 20</li>
<li><a
href="384d6cf581"><code>384d6cf</code></a>
Fix quotations in tests</li>
<li><a
href="84724927e3"><code>8472492</code></a>
Only validate GraphQL <code>previews</code></li>
<li><a
href="84903f5182"><code>84903f5</code></a>
Remove <code>node-fetch</code> from type</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/github-script/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/github-script&package-manager=github_actions&previous-version=6&new-version=7)](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>
2024-11-05 11:06:39 +00:00
dependabot[bot]
b1c2d851e5 chore: CI: bump lycheeverse/lychee-action from 1.9.0 to 2.0.2 (#5959)
Bumps
[lycheeverse/lychee-action](https://github.com/lycheeverse/lychee-action)
from 1.9.0 to 2.0.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/lycheeverse/lychee-action/releases">lycheeverse/lychee-action's
releases</a>.</em></p>
<blockquote>
<h2>Version 2.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix a typos by <a
href="https://github.com/szepeviktor"><code>@​szepeviktor</code></a> in
<a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/257">lycheeverse/lychee-action#257</a></li>
<li>Document and use correct permissions in the GitHub workflows by <a
href="https://github.com/dscho"><code>@​dscho</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/258">lycheeverse/lychee-action#258</a></li>
<li>Add security policy by <a
href="https://github.com/mondeja"><code>@​mondeja</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/259">lycheeverse/lychee-action#259</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/szepeviktor"><code>@​szepeviktor</code></a>
made their first contribution in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/257">lycheeverse/lychee-action#257</a></li>
<li><a href="https://github.com/mondeja"><code>@​mondeja</code></a> made
their first contribution in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/259">lycheeverse/lychee-action#259</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/lycheeverse/lychee-action/compare/v2...v2.0.2">https://github.com/lycheeverse/lychee-action/compare/v2...v2.0.2</a></p>
<h2>Version 2.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Don't remove the lychee config file by <a
href="https://github.com/dmathieu"><code>@​dmathieu</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/255">lycheeverse/lychee-action#255</a></li>
<li>Bump lycheeverse/lychee-action from 1 to 2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/252">lycheeverse/lychee-action#252</a></li>
<li>Fix variable name in docs by <a
href="https://github.com/kdeldycke"><code>@​kdeldycke</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/253">lycheeverse/lychee-action#253</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/dmathieu"><code>@​dmathieu</code></a>
made their first contribution in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/255">lycheeverse/lychee-action#255</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/lycheeverse/lychee-action/compare/v2...v2.0.1">https://github.com/lycheeverse/lychee-action/compare/v2...v2.0.1</a></p>
<h2>Version 2.0.0</h2>
<h2>Breaking Changes</h2>
<p><strong>Note:</strong> This release improves the action's robustness
by changing default behaviors. Changes are only required if you want to
opt out of the new failure conditions. Most users won't need to modify
their existing configurations.</p>
<h3>Fail pipeline on error by default</h3>
<p>We've changed the default behavior: pipelines will now fail on broken
links automatically. This addresses user feedback that not failing on
broken links was unexpected (see [issue <a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/71">#71</a>](<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/71">lycheeverse/lychee-action#71</a>)).</p>
<p><strong>What you need to do:</strong></p>
<ul>
<li>Update to version 2 of this action to apply this change.</li>
<li>Users of the <code>lychee-action@master</code> branch don't need to
make any changes, as <code>fail: true</code> has been the default there
for a while.</li>
<li>If you prefer the old behavior, explicitly set <code>fail</code> to
<code>false</code> when updating:</li>
</ul>
<pre lang="yaml"><code>- name: Link Checker
  id: lychee
  uses: lycheeverse/lychee-action@v2
  with:
    fail: false  # Don't fail action on broken links
</code></pre>
<h3>Fail pipeline if no links were found</h3>
<p>Similar to the above change, we now fail the pipeline if no links are
found during a run. This helps warn users about potential configuration
issues.</p>
<p><strong>What you need to do:</strong></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="7cd0af4c74"><code>7cd0af4</code></a>
Merge commit from fork</li>
<li><a
href="8ad54d3568"><code>8ad54d3</code></a>
fix link</li>
<li><a
href="762333c189"><code>762333c</code></a>
Create SECURITY.md (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/259">#259</a>)</li>
<li><a
href="71a38a3bd7"><code>71a38a3</code></a>
Document and use correct permissions in the GitHub workflows (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/258">#258</a>)</li>
<li><a
href="f141760066"><code>f141760</code></a>
Fix a typos (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/257">#257</a>)</li>
<li><a
href="2bb232618b"><code>2bb2326</code></a>
don't remove the lychee config file (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/255">#255</a>)</li>
<li><a
href="731bf1a2af"><code>731bf1a</code></a>
Fix variable name (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/253">#253</a>)</li>
<li><a
href="e360f3c891"><code>e360f3c</code></a>
Bump lycheeverse/lychee-action from 1 to 2 (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/252">#252</a>)</li>
<li><a
href="f87f0a6299"><code>f87f0a6</code></a>
Update version to <code>lycheeverse/lychee-action@v2</code> in docs</li>
<li><a
href="7da8ec1fc4"><code>7da8ec1</code></a>
Test latest lychee version tag (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/236">#236</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/lycheeverse/lychee-action/compare/v1.9.0...v2.0.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=lycheeverse/lychee-action&package-manager=github_actions&previous-version=1.9.0&new-version=2.0.2)](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>
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-11-05 10:41:16 +00:00
Sebastian Ullrich
970dc6f7aa chore: CI: give Linux Debug unlimited test stack size (#5953) 2024-11-05 10:06:53 +00:00
dependabot[bot]
8e2f92607f chore: CI: bump actions/stale from 8 to 9 (#5958)
Bumps [actions/stale](https://github.com/actions/stale) from 8 to 9.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/stale/releases">actions/stale's
releases</a>.</em></p>
<blockquote>
<h2>v9.0.0</h2>
<h2>Breaking Changes</h2>
<ol>
<li>Action is now stateful: If the action ends because of <a
href="https://github.com/actions/stale#operations-per-run">operations-per-run</a>
then the next run will start from the first unprocessed issue skipping
the issues processed during the previous run(s). The state is reset when
all the issues are processed. This should be considered for scheduling
workflow runs.</li>
<li>Version 9 of this action updated the runtime to Node.js 20. All
scripts are now run with Node.js 20 instead of Node.js 16 and are
affected by any breaking changes between Node.js 16 and 20.</li>
</ol>
<h2>What Else Changed</h2>
<ol>
<li>Performance optimization that removes unnecessary API calls by <a
href="https://github.com/dsame"><code>@​dsame</code></a> <a
href="https://redirect.github.com/actions/stale/pull/1033/">#1033</a>
fixes <a
href="https://redirect.github.com/actions/stale/issues/792">#792</a></li>
<li>Logs displaying current github API rate limit by <a
href="https://github.com/dsame"><code>@​dsame</code></a> <a
href="https://redirect.github.com/actions/stale/pull/1032">#1032</a>
addresses <a
href="https://redirect.github.com/actions/stale/issues/1029">#1029</a></li>
</ol>
<p>For more information, please read the <a
href="https://github.com/actions/stale#readme">action documentation</a>
and its <a href="https://github.com/actions/stale#statefulness">section
about statefulness</a></p>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/jmeridth"><code>@​jmeridth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/stale/pull/984">actions/stale#984</a></li>
<li><a
href="https://github.com/nikolai-laevskii"><code>@​nikolai-laevskii</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/stale/pull/1020">actions/stale#1020</a></li>
<li><a
href="https://github.com/dusan-trickovic"><code>@​dusan-trickovic</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/stale/pull/1056">actions/stale#1056</a></li>
<li><a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/stale/pull/1110">actions/stale#1110</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/stale/compare/v8...v9.0.0">https://github.com/actions/stale/compare/v8...v9.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/stale/blob/main/CHANGELOG.md">actions/stale's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h1>[7.0.0]</h1>
<p>⚠️ Breaking change ⚠️</p>
<ul>
<li>Allow daysBeforeStale options to be float by <a
href="https://github.com/irega"><code>@​irega</code></a> in <a
href="https://redirect.github.com/actions/stale/pull/841">actions/stale#841</a></li>
<li>Use cache in check-dist.yml by <a
href="https://github.com/jongwooo"><code>@​jongwooo</code></a> in <a
href="https://redirect.github.com/actions/stale/pull/876">actions/stale#876</a></li>
<li>fix print outputs step in existing workflows by <a
href="https://github.com/irega"><code>@​irega</code></a> in <a
href="https://redirect.github.com/actions/stale/pull/859">actions/stale#859</a></li>
<li>Update issue and PR templates, add/delete workflow files by <a
href="https://github.com/IvanZosimov"><code>@​IvanZosimov</code></a> in
<a
href="https://redirect.github.com/actions/stale/pull/880">actions/stale#880</a></li>
<li>Update how stale handles exempt items by <a
href="https://github.com/johnsudol"><code>@​johnsudol</code></a> in <a
href="https://redirect.github.com/actions/stale/pull/874">actions/stale#874</a></li>
</ul>
<h1>[6.0.1]</h1>
<p>Update <code>@​actions/core</code> to v1.10.0 (<a
href="https://redirect.github.com/actions/stale/pull/839">#839</a>)</p>
<h1>[6.0.0]</h1>
<p>⚠️ Breaking change ⚠️</p>
<p>Issues/PRs default <code>close-issue-reason</code> is now
<code>not_planned</code>(<a
href="https://redirect.github.com/actions/stale/issues/789">#789</a>)</p>
<h1>[5.1.0]</h1>
<p><a href="https://redirect.github.com/actions/stale/issues/696">Don't
process stale issues right after they're marked stale</a>
[Add close-issue-reason option]<a
href="https://redirect.github.com/actions/stale/pull/764">#764</a><a
href="https://redirect.github.com/actions/stale/pull/772">#772</a>
Various dependabot/dependency updates</p>
<h2><a
href="https://github.com/actions/stale/compare/v3.0.19...v4.1.0">4.1.0</a>
(2021-07-14)</h2>
<h2>Features</h2>
<ul>
<li><a
href="9912fa74d1">Ability
to exempt draft PRs</a></li>
</ul>
<h2><a
href="https://github.com/actions/stale/compare/v3.0.19...v4.0.0">4.0.0</a>
(2021-07-14)</h2>
<h3>Features</h3>
<ul>
<li><strong>options:</strong> simplify config by removing skip stale
message options (<a
href="https://redirect.github.com/actions/stale/issues/457">#457</a>)
(<a
href="6ec637d238">6ec637d</a>),
closes <a
href="https://redirect.github.com/actions/stale/issues/405">#405</a> <a
href="https://redirect.github.com/actions/stale/issues/455">#455</a></li>
<li><strong>output:</strong> print output parameters (<a
href="https://redirect.github.com/actions/stale/issues/458">#458</a>)
(<a
href="3e6d35b685">3e6d35b</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>dry-run:</strong> forbid mutations in dry-run (<a
href="https://redirect.github.com/actions/stale/issues/500">#500</a>)
(<a
href="f1017f33dd">f1017f3</a>),
closes <a
href="https://redirect.github.com/actions/stale/issues/499">#499</a></li>
<li><strong>logs:</strong> coloured logs (<a
href="https://redirect.github.com/actions/stale/issues/465">#465</a>)
(<a
href="5fbbfba142">5fbbfba</a>)</li>
<li><strong>operations:</strong> fail fast the current batch to respect
the operations limit (<a
href="https://redirect.github.com/actions/stale/issues/474">#474</a>)
(<a
href="5f6f311ca6">5f6f311</a>),
closes <a
href="https://redirect.github.com/actions/stale/issues/466">#466</a></li>
<li><strong>label comparison</strong>: make label comparison case
insensitive <a
href="https://redirect.github.com/actions/stale/pull/517">#517</a>,
closes <a
href="https://redirect.github.com/actions/stale/pull/516">#516</a></li>
<li><strong>filtering comments by actor could have strange
behavior</strong>: &quot;stale&quot; comments are now detected based on
if the message is the stale message not <em>who</em> made the comment(<a
href="https://redirect.github.com/actions/stale/pull/519">#519</a>),
fixes <a
href="https://redirect.github.com/actions/stale/pull/441">#441</a>, <a
href="https://redirect.github.com/actions/stale/pull/509">#509</a>, <a
href="https://redirect.github.com/actions/stale/pull/518">#518</a></li>
</ul>
<h3>Breaking Changes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="28ca103628"><code>28ca103</code></a>
Upgrade Node to v20 (<a
href="https://redirect.github.com/actions/stale/issues/1110">#1110</a>)</li>
<li><a
href="b69b346013"><code>b69b346</code></a>
build(deps-dev): bump <code>@​types/node</code> from 18.16.18 to 20.5.1
(<a
href="https://redirect.github.com/actions/stale/issues/1079">#1079</a>)</li>
<li><a
href="88a6f4f6cb"><code>88a6f4f</code></a>
build(deps-dev): bump typescript from 5.1.3 to 5.2.2 (<a
href="https://redirect.github.com/actions/stale/issues/1083">#1083</a>)</li>
<li><a
href="796531a7b3"><code>796531a</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/stale/issues/1080">#1080</a>
from akv-platform/fix-delete-cache</li>
<li><a
href="8986f6218b"><code>8986f62</code></a>
Don not try to delete cache if it does not exists</li>
<li><a
href="cab99b362b"><code>cab99b3</code></a>
fix typo proceeded/processed</li>
<li><a
href="184e7afe93"><code>184e7af</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/stale/issues/1064">#1064</a>
from actions/dependabot/npm_and_yarn/typescript-esli...</li>
<li><a
href="523885cf3c"><code>523885c</code></a>
chore: update eslint-plugin, parser and eslint-plugin-jest</li>
<li><a
href="2487a1dc2b"><code>2487a1d</code></a>
build(deps-dev): bump
<code>@​typescript-eslint/eslint-plugin</code></li>
<li><a
href="60c722ee97"><code>60c722e</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/stale/issues/1063">#1063</a>
from actions/dependabot/npm_and_yarn/jest-29.6.2</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/stale/compare/v8...v9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/stale&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>
2024-11-05 09:53:55 +00:00
dependabot[bot]
ee1fa6eeb7 chore: CI: bump raven-actions/actionlint from 1 to 2 (#5957)
Bumps
[raven-actions/actionlint](https://github.com/raven-actions/actionlint)
from 1 to 2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/raven-actions/actionlint/releases">raven-actions/actionlint's
releases</a>.</em></p>
<blockquote>
<h2>v2.0.0</h2>
<h2>🔄️ What's Changed</h2>
<ul>
<li>node20 support</li>
<li>ci(linter): add workflow permissions <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/24">#24</a>)</li>
<li>ci(deps): Bump actions/cache from 3 to 4 <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/20">#20</a>)</li>
</ul>
<h2>🚀 Features</h2>
<ul>
<li>feat: switch to pipx &amp; add github-token <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/23">#23</a>)</li>
</ul>
<h2>👥 Contributors</h2>
<p><a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>,
<a href="https://github.com/dependabot"><code>@​dependabot</code></a>
and <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]</p>
<p>See details of all code changes: <a
href="https://github.com/raven-actions/actionlint/compare/v1.0.3...v2.0.0">https://github.com/raven-actions/actionlint/compare/v1.0.3...v2.0.0</a>
since previous release.</p>
<h2>v1.0.3</h2>
<h2>🔄️ What's Changed</h2>
<ul>
<li>chore: yamllint config and files lint <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/18">#18</a>)</li>
<li>⬆️ github-actions(deps): Bump actions/github-script from 6 to 7 <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/17">#17</a>)</li>
<li>⬆️ github-actions(deps): bump actions/checkout from 3 to 4 <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/12">#12</a>)</li>
</ul>
<h2>🚀 Features</h2>
<ul>
<li>Make yamllint happy <a
href="https://github.com/bhundven"><code>@​bhundven</code></a> (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/16">#16</a>)</li>
<li>Fix debian install shellcheck <a
href="https://github.com/bhundven"><code>@​bhundven</code></a> (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/15">#15</a>)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>fix: user flags parser <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/19">#19</a>)</li>
<li>Fix debian install shellcheck <a
href="https://github.com/bhundven"><code>@​bhundven</code></a> (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/15">#15</a>)</li>
</ul>
<h2>👥 Contributors</h2>
<p><a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>,
<a href="https://github.com/bhundven"><code>@​bhundven</code></a>, <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> and
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]</p>
<p>See details of all code changes: <a
href="https://github.com/raven-actions/actionlint/compare/v1.0.2...v1.0.3">https://github.com/raven-actions/actionlint/compare/v1.0.2...v1.0.3</a>
since previous release.</p>
<h2>v1.0.2</h2>
<h2>🔄️ What's Changed</h2>
<ul>
<li> feat(inputs): group-result <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/10">#10</a>)</li>
<li>👷 chore(github): ci adjustments <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/9">#9</a>)</li>
<li>👷 refactor(ci): change to debug action <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/7">#7</a>)</li>
<li>📝 chore: minor docs and CI adjustments <a
href="https://github.com/DariuszPorowski"><code>@​DariuszPorowski</code></a>
(<a
href="https://redirect.github.com/raven-actions/actionlint/issues/6">#6</a>)</li>
</ul>
<h2>👥 Contributors</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="01fce4f43a"><code>01fce4f</code></a>
ci(linter): add workflow permissions (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/24">#24</a>)</li>
<li><a
href="a30be5376b"><code>a30be53</code></a>
feat: switch to pipx &amp; add github-token (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/23">#23</a>)</li>
<li><a
href="ea4eb57846"><code>ea4eb57</code></a>
ci(deps): Bump actions/cache from 3 to 4 (<a
href="https://redirect.github.com/raven-actions/actionlint/issues/20">#20</a>)</li>
<li>See full diff in <a
href="https://github.com/raven-actions/actionlint/compare/v1...v2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=raven-actions/actionlint&package-manager=github_actions&previous-version=1&new-version=2)](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>
2024-11-05 09:49:23 +00:00
dependabot[bot]
9d2a017704 chore: CI: bump softprops/action-gh-release from 1 to 2 (#5955)
Bumps
[softprops/action-gh-release](https://github.com/softprops/action-gh-release)
from 1 to 2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's
releases</a>.</em></p>
<blockquote>
<h2>v2.0.0</h2>
<ul>
<li>update actions.yml declaration to node20 to address warnings</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's
changelog</a>.</em></p>
<blockquote>
<h2>0.1.12</h2>
<ul>
<li>fix bug leading to empty strings subsituted for inputs users don't
provide breaking api calls <a
href="https://redirect.github.com/softprops/action-gh-release/pull/144">#144</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e7a8f85e1c"><code>e7a8f85</code></a>
chore: release 2.0.9</li>
<li><a
href="04afa1392e"><code>04afa13</code></a>
chore(deps): bump actions/setup-node from 4.0.4 to 4.1.0 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/535">#535</a>)</li>
<li><a
href="894468a03c"><code>894468a</code></a>
chore(deps): bump actions/checkout from 4.2.1 to 4.2.2 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/534">#534</a>)</li>
<li><a
href="3bd23aa9ec"><code>3bd23aa</code></a>
chore(deps): bump <code>@​types/node</code> from 22.7.5 to 22.8.2 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/533">#533</a>)</li>
<li><a
href="21eb2f9554"><code>21eb2f9</code></a>
chore(deps): bump <code>@​types/jest</code> from 29.5.13 to 29.5.14 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/532">#532</a>)</li>
<li><a
href="cd8b57e572"><code>cd8b57e</code></a>
remove unused imports (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/521">#521</a>)</li>
<li><a
href="820a5adc43"><code>820a5ad</code></a>
chore(deps): bump actions/checkout from 4.2.0 to 4.2.1 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/522">#522</a>)</li>
<li><a
href="9d04f90cd8"><code>9d04f90</code></a>
chore(deps): bump <code>@​octokit/plugin-throttling</code> from 9.3.1 to
9.3.2 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/523">#523</a>)</li>
<li><a
href="aaf1d5f6d5"><code>aaf1d5f</code></a>
chore(deps): bump <code>@​actions/core</code> from 1.10.1 to 1.11.1 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/524">#524</a>)</li>
<li><a
href="7d33a7ecc3"><code>7d33a7e</code></a>
chore(deps): bump <code>@​types/node</code> from 22.5.5 to 22.7.5 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/525">#525</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/softprops/action-gh-release/compare/v1...v2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=softprops/action-gh-release&package-manager=github_actions&previous-version=1&new-version=2)](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>
2024-11-05 09:40:03 +00:00
dependabot[bot]
574b86c247 chore: CI: bump nwtgck/actions-netlify from 2.0 to 3.0 (#5956)
Bumps
[nwtgck/actions-netlify](https://github.com/nwtgck/actions-netlify) from
2.0 to 3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/nwtgck/actions-netlify/releases">nwtgck/actions-netlify's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
<li>Updates the default runtime to node20</li>
</ul>
<h2>v2.1.0</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
</ul>
<h3>Added</h3>
<ul>
<li>Add &quot;enable-github-deployment&quot; input <a
href="https://redirect.github.com/nwtgck/actions-netlify/pull/901">#901</a>
by <a href="https://github.com/a-tokyo"><code>@​a-tokyo</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/nwtgck/actions-netlify/blob/develop/CHANGELOG.md">nwtgck/actions-netlify's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a
href="https://keepachangelog.com/en/1.0.0/">Keep a Changelog</a></p>
<h2>[Unreleased]</h2>
<h2>[3.0.0] - 2024-03-10</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
<li>Updates the default runtime to node20</li>
</ul>
<h2>[2.1.0] - 2023-08-18</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
</ul>
<h3>Added</h3>
<ul>
<li>Add &quot;enable-github-deployment&quot; input <a
href="https://redirect.github.com/nwtgck/actions-netlify/pull/901">#901</a>
by <a href="https://github.com/a-tokyo"><code>@​a-tokyo</code></a></li>
</ul>
<h2>[2.0.0] - 2022-12-08</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
<li>Updates the default runtime to node16</li>
</ul>
<h2>[1.2.4] - 2022-10-14</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
</ul>
<h2>[1.2.3] - 2021-12-20</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
</ul>
<h2>[1.2.2] - 2021-05-08</h2>
<h3>Fixed</h3>
<ul>
<li>Fix GitHub deployment description</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
</ul>
<h2>[1.2.1] - 2021-05-05</h2>
<h3>Added</h3>
<ul>
<li>Add &quot;fails-without-credentials&quot; input to fail if the
credentials not provided <a
href="https://redirect.github.com/nwtgck/actions-netlify/pull/532">#532</a></li>
</ul>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
</ul>
<h2>[1.2.0] - 2021-04-29</h2>
<h3>Changed</h3>
<ul>
<li>Update dependencies</li>
<li>(breaking change for <code>overwrites-pull-request-comment:
true</code>): Support multiple app deploys in a single PR <a
href="https://redirect.github.com/nwtgck/actions-netlify/pull/484">#484</a>
by <a
href="https://github.com/kaisermann"><code>@​kaisermann</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4cbaf4c08f"><code>4cbaf4c</code></a>
Merge branch 'release/3.0.0'</li>
<li><a
href="6b45669baf"><code>6b45669</code></a>
bump: 3.0.0</li>
<li><a
href="8d5d80bf73"><code>8d5d80b</code></a>
Merge pull request <a
href="https://redirect.github.com/nwtgck/actions-netlify/issues/1151">#1151</a>
from nwtgck/actions-build/nwtgck-dependabot/npm_and_...</li>
<li><a
href="85c2e8e35a"><code>85c2e8e</code></a>
build</li>
<li><a
href="ea3c314fcd"><code>ea3c314</code></a>
Build(deps): bump <code>@​actions/github</code> from 5.1.1 to 6.0.0</li>
<li><a
href="333815eadd"><code>333815e</code></a>
updates the default runtime to node20</li>
<li><a
href="06de7de77b"><code>06de7de</code></a>
Build(deps-dev): bump <code>@​vercel/ncc</code> from 0.36.1 to 0.38.1
(<a
href="https://redirect.github.com/nwtgck/actions-netlify/issues/1121">#1121</a>)</li>
<li><a
href="a7f64ad4e2"><code>a7f64ad</code></a>
deps: update</li>
<li><a
href="fee801f039"><code>fee801f</code></a>
Build(deps): bump actions/setup-node from 3 to 4 (<a
href="https://redirect.github.com/nwtgck/actions-netlify/issues/1124">#1124</a>)</li>
<li><a
href="e4998d22a0"><code>e4998d2</code></a>
README.md, sample workflow: bump to latest action versions (<a
href="https://redirect.github.com/nwtgck/actions-netlify/issues/1149">#1149</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/nwtgck/actions-netlify/compare/v2.0...v3.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nwtgck/actions-netlify&package-manager=github_actions&previous-version=2.0&new-version=3.0)](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>
2024-11-05 09:38:06 +00:00
Sebastian Ullrich
75602f7c29 chore: CI: adjust Dependabot prefix 2024-11-05 10:31:37 +01:00
Sebastian Ullrich
0fd90c1283 chore: CI: check for GitHub Actions updates once per month (#5954) 2024-11-05 10:20:23 +01:00
Kim Morrison
128b049904 feat: relate Array.eraseIdx with List.eraseIdx (#5952) 2024-11-05 06:13:29 +00:00
Kim Morrison
0e3f26e6df feat: relate Array.takeWhile with List.takeWhile (#5950) 2024-11-05 05:05:53 +00:00
Kim Morrison
1148e6e142 chore: remove @[simp] from BitVec.ofFin_sub and sub_ofFin (#5951)
Unused, and hurts confluence.
2024-11-05 04:56:21 +00:00
Violeta Hernández
02baaa42ff feat: add Option.or_some' (#5926)
`o.or (some a) = o.getD a`.

As discussed on
[Zulip](https://leanprover.zulipchat.com/#narrow/channel/217875-Is-there-code-for-X.3F/topic/a.2Eor.20.28some.20b.29.20.3D.20a.2EgetD.20b/near/472785093).
2024-11-05 01:39:02 +00:00
Violeta Hernández
e573676db1 feat: List.pmap_eq_self (#5927)
This is a `pmap` analog of
[`List.map_id''`](https://leanprover-community.github.io/mathlib4_docs/Init/Data/List/Lemmas.html#List.map_id'').

As discussed on
[Zulip](https://leanprover.zulipchat.com/#narrow/channel/217875-Is-there-code-for-X.3F/topic/.60pmap_eq_self.60/near/472496933).
2024-11-05 01:38:13 +00:00
Kim Morrison
4dab6a108c chore: port release notes for v4.13.0 to master (#5947) 2024-11-05 01:34:52 +00:00
Kyle Miller
a4d521cf96 fix: make all_goals admit goals on failure (#5934)
New behavior: when in recovery mode, if any tactic fails in `all_goals`
then the metacontext is restored and all goals are admitted.

Without this, it can leave partially-solved metavariables and incomplete
goal lists.
2024-11-04 21:12:59 +00:00
Mac Malone
99070bf304 feat: update toolchain on lake update (#5684)
Lake will now 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.

Closes #2582. Closes #2752. Closes #5615.

### Toolchain update details

To determine "newest compatible" toolchain, Lake parses the toolchain
listed in the packages' `lean-toolchain` files into four categories:
release , nightly, PR, and other. For newness, release toolchains are
compared by semantic version (e.g., `"v4.4.0" < "v4.8.0"` and
`"v4.6.0-rc1" < "v4.6.0"`) and nightlies are compared by date (e.g.,
`"nightly-2024-01-10" < "nightly-2014-10-01"`). All other toolchain
types and mixtures are incompatible. If there is not a single newest
toolchain, Lake will print a warning and continue updating without
changing the toolchain.

If Lake does find a new toolchain, Lake updates the workspace's
`lean-toolchain` file accordingly and restarts the update process on the
new Lake. If Elan is detected, it will spawn the new Lake process via
`elan run` with the same arguments Lake was initially run with. If Elan
is missing, it will prompt the user to restart Lake manually and exit
with a special error code (4).

### Other changes

To implement this new logic, various other refactors were needed. Here
are some key highlights:

* Logs emitted during package and workspace loading are now eagerly
printed.
* The Elan executable used by Lake is now configurable by the `ELAN`
environment variable.
* The `--lean` CLI option was removed. Use the `LEAN` environment
variable instead.
* `Package.deps` / `Package.opaqueDeps` have been removed. Use
`findPackage?` with a dependency's name instead.
* The dependency resolver now uses a pure breadth-first traversal to
resolve dependencies. It also resolves dependencies in reverse order,
which is done for consistency with targets. Latter targets shadow
earlier ones and latter dependencies take precedence over earlier ones.
**These changes mean the order of dependencies in a Lake manifest will
change after the first `lake update` on this version of Lake.**
2024-11-04 14:31:40 +00:00
Henrik Böving
93dd6f2b36 feat: add Int16/Int32/Int64 (#5885)
This adds all fixed width integers with the exception of `ssize_t` so
the code is quick to review as everything just behaves the same.
2024-11-04 13:18:05 +00:00
Henrik Böving
c61ced3f15 feat: introduce synthetic atoms in bv_decide (#5942)
This introduces a notion of synthetic atoms into `bv_decide`'s
reflection framework. An atom can be declared synthetic if its behavior
is fully specified by additional lemmas that are added in the process of
creating it. This is for example useful in the code that handles `if` as
the entire `if` block is abstracted as an atom and then two lemmas to
describe either branch are added. Previously this had the effect of
creating error messages about potentially unsound counterexamples, now
the synthetic atoms get filtered from the counter example generation.
2024-11-04 10:14:51 +00:00
Kim Morrison
c779f3a039 feat: List.mapFinIdx, lemmas, relate to Array version (#5941) 2024-11-04 05:29:41 +00:00
Kim Morrison
fc17468f78 chore: upstream List.ofFn and relate to Array.ofFn (#5938) 2024-11-04 01:35:29 +00:00
Kim Morrison
8b7e3b8942 chore: upstream lemmas about Fin.foldX (#5937) 2024-11-04 00:52:59 +00:00
Kim Morrison
9129990833 chore: begin development cycle for v4.15 (#5936) 2024-11-03 23:25:03 +00:00
Kyle Miller
1659f3bfe2 fix: .. in patterns should not make use of optparams or autoparams (#5933)
In patterns, ellipsis should always fill in each remaining argument as
an implicit argument, even if it is an optparam or autoparam. This
prevents examples such as the one in #4555 from failing:
```lean
match e with
| .internal .. => sorry
| .error .. => sorry
```
The `internal` constructor has an optparam (`| internal (id :
InternalExceptionId) (extra : KVMap := {})`).

We may consider having ellipsis suppress optparams and autoparams in
general. We avoid doing so for now since it's possible to opt-out of
them individually (for example with `.internal (extra := _) ..`) but
it's not possible to opt-in, and it is plausible that `..` with
optparams is useful in contexts such as the `refine` tactic. With
patterns however, it is hard to imagine a use case that offsets the
inconvenience of optparams being eagerly supplied.

Closes #4555
2024-11-03 18:40:21 +00:00
Lean stage0 autoupdater
87d3f1f2c8 chore: update stage0 2024-11-03 17:21:54 +00:00
Kyle Miller
b75cc35db2 feat: update omega/solve_by_elim to use new tactic syntax, use new tactic syntax (#5932)
Following up #5928, updates the syntax for `omega` and `solve_by_elim`
and restores the syntax quotations in their implementations.

Following up #5898, uses the new tactic syntax in the library, replacing
all uses of `(config := ...)`.
2024-11-03 16:23:37 +00:00
Jens Petersen
3952689fb1 feat: add --short-version (-V) option to display short version (#5930)
This just adds a `--short-version` (`-V`) option to the lean command,
which is useful for external tooling, etc.

Closes #5929
2024-11-03 15:18:23 +00:00
Lean stage0 autoupdater
cd24e9dad4 chore: update stage0 2024-11-03 07:04:44 +00:00
Kyle Miller
0de925eafc chore: prepare omega and solve_by_elim for new tactic config syntax (#5928)
The tactic elaborators match a too-restrictive syntax for the migration
to the new configuration syntax. This generalizes what they accept, and
the code will return to using quotations after a stage0 update and
syntax change.
2024-11-03 06:20:15 +00:00
Mac Malone
79428827b8 feat: add text option for buildFile* utilities (#5924)
Adds an optional `text` argument to the `fetchFile*` and `buildFile*`
definitions that can be used to hash built files as text files (with
normalized line endings) instead of as binary files (the previous
default).

Separately, this change also significantly expands the documentation in
the `Lake.Build.Trace` module and preforms minor touchups of some build
job signatures.
2024-11-03 00:23:39 +00:00
Kyle Miller
3c15ab3c09 feat: make MapDeclarationExtension tolerate multiple insertions (#5911)
Simplifies the definition of `MapDeclarationExtension` so that it only
contains a `NameMap` without an additional `List (Name × α)`. Uses the
`NameMap`'s natural ordering during export rather than sorting.

This fixes issues from inserting into a `MapDeclarationExtension`
multiple times with the same key. Inside a module it appears that each
insertion overwrites the data, since those queries access the `NameMap`.
But across modules, only the first insertion is accessible, since each
insertion was actually pushed to the front of a `List`.

Mathlib needs this for a documentation extension feature, and [they are
considering a PR with a
workaround](https://github.com/leanprover-community/mathlib4/pull/17043)
that digs into the `MapDeclarationExtension` data structures.
2024-11-02 15:28:34 +00:00
Lean stage0 autoupdater
3f33cd6fcd chore: update stage0 2024-11-01 23:33:27 +00:00
David Thrane Christiansen
1f8d7561fa chore: remove unused deriving handler argument syntax (#5265)
As far as I can tell, the ability to pass a structure instance to a
deriving handler is not actually used in practice. It didn't seem to be
used in the test suite, at least.

Do we want to remove this, or do we want to use and document it? This PR
removes it, but that's not something I feel strongly about - but seeing
if it breaks Mathlib is a useful data point.
2024-11-01 22:41:38 +00:00
Alex
16e5e09ffd feat: better error message for invalid induction alternative name (#5888)
Closes #5887
2024-11-01 21:33:15 +00:00
Kyle Miller
5549e0509f feat: on "type mismatch" errors, expose differences in functions and pi types (#5922)
Example: Normally subtype notation pretty prints as `{ x // x > 0 }`,
but now the difference in domains is exposed:
```lean
example (h : {x : Int // x > 0}) : {x : Nat // x > 0} := h
/-
error: type mismatch
  h
has type
  { x : Int // x > 0 } : Type
but is expected to have type
  { x : Nat // x > 0 } : Type
-/
```
2024-11-01 18:42:14 +00:00
Kyle Miller
c7f5fd9a83 feat: make "type mismatch" error add numeric type ascriptions (#5919)
Example:
```lean
example : 0 = (0 : Nat) := by
  exact Eq.refl (0 : Int)
/-
error: type mismatch
  Eq.refl 0
has type
  (0 : Int) = 0 : Prop
but is expected to have type
  (0 : Nat) = 0 : Prop
-/
```
2024-11-01 16:44:52 +00:00
Henrik Böving
a4057d373e fix: bv_normalize loose mvars (#5918)
`bv_normalize` would just silently drop other goals if called while not
focused on a singular goal, for example:
```lean
theorem mvarid (x y : Bool) (h : x ∨ y) : y ∨ x := by
  cases h
  bv_normalize
  -- we want to write another bv_normalize here but all goals are gone
```
Would make the second subgoal disappear and then throw an error about
meta variables in the kernel.
2024-11-01 15:16:11 +00:00
Sebastian Ullrich
fd08c92060 chore: update src/library/module.cpp after update stage0
Co-authored-by: Eric Wieser <wieser.eric@gmail.com>

Update src/library/module.cpp

Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
2024-11-01 22:48:49 +11:00
Kim Morrison
be6507fe5b chore: update stage0 2024-11-01 22:48:49 +11:00
Sebastian Ullrich
c723ae7f97 chore: CI: build 64-bit platforms consistently with GMP
fix

arm64?

try different fix

`uses_gmp` .olean bit, bump .olean version

add lean_version

make sure to use cache gmp on x86 Linux
2024-11-01 22:48:49 +11:00
Lean stage0 autoupdater
0973ba3e42 chore: update stage0 2024-11-01 03:36:00 +00:00
Kim Morrison
a75a03c077 feat: relate for loops over List with foldlM (#5913)
There are many more lemmas about `foldlM`, so this may be useful for
reasoning about for loops by transforming them into folds.

The transformation includes accounting for monad effects, but does have
a mild performance difference in that short-circuiting on
`ForInStep.done` is replaced by traversing the rest of the list with a
noop.
2024-11-01 02:41:05 +00:00
Kim Morrison
6922832327 chore: minor tweaks to Array lemmas (#5912) 2024-11-01 02:20:16 +00:00
Kyle Miller
f1707117f0 feat: conv arg now can access more arguments (#5894)
Specializes the congr lemma generated for the `arg` conv tactic to only
rewrite the chosen argument. This makes it much more likely that the
chosen argument is able to be accessed.

Lets `arg` access the domain and codomain of pi types via `arg 1` and
`arg 2` in more situations. Upstreams `pi_congr` for this from mathlib.

Adds a negative indexing option, where `arg -2` accesses the
second-to-last argument for example, making the behavior of `lhs`
available to `arg`. This works for `enter` as well.

Other improvement: when there is an error in the `enter [...]` tactic,
individual locations get underlined with the error. The tactic info now
also is like `rw`, so you can see the intermediate conv states.

Closes #5871
2024-11-01 02:12:14 +00:00
Kyle Miller
3b80d1eb1f feat: activate new tactic configuration syntax for most tactics (#5898)
PR #5883 added a new syntax for tactic configuration, and this PR
enables it in most tactics. Example: `simp +contextual`.

There will be followup PRs to modify the remaining ones.

Breaking change: Tactics that are macros for `simp` or other core
tactics need to adapt. The easiest way is to replace `(config)?` with
`optConfig` and then in the syntax quotations replace `$[$cfg]?` by
`$cfg:optConfig`. For tactics that manipulate the configuration, see
`erw` for an example:
```lean
macro "erw" c:optConfig s:rwRuleSeq loc:(location)? : tactic => do
  `(tactic| rw $[$(getConfigItems c)]* (transparency := .default) $s:rwRuleSeq $(loc)?)
```
Configuration options are processed left-to-right, so this forces the
`transparency` to always be `.default`.
2024-11-01 02:08:53 +00:00
Luisa Cicolini
7730ddd1a0 feat: add BitVec.(msb, getMsbD, getLsbD)_(neg, abs) (#5721)
Co-authored-by: Alex Keizer <alex@keizer.dev>
Co-authored-by: Tobias Grosser <github@grosser.es>
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
Co-authored-by: Kyle Miller <kmill31415@gmail.com>
Co-authored-by: Henrik Böving <hargonix@gmail.com>
Co-authored-by: Tobias Grosser <tobias@grosser.es>
Co-authored-by: Kim Morrison <scott.morrison@gmail.com>
Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
Co-authored-by: Marc Huisinga <mhuisi@protonmail.com>
Co-authored-by: Markus Himmel <markus@lean-fro.org>
Co-authored-by: FR <zhao.yu-yang@foxmail.com>
Co-authored-by: Aaron Tomb <aarontomb@gmail.com>
Co-authored-by: Arthur Adjedj <arthur.adjedj@gmail.com>
Co-authored-by: Yann Herklotz <git@yannherklotz.com>
Co-authored-by: Lean stage0 autoupdater <>
2024-11-01 01:27:34 +00:00
Kim Morrison
e4a2c3d8f0 feat: interim implementation of HashMap.modify/alter (#5880)
These implementations could be made more efficient by promoting them to
primitive operations, but I propose installing these in the meantime to
encourage users to avoid non-linearity problems.
2024-11-01 01:21:21 +00:00
Kim Morrison
c2391c45b9 chore: remove @[simp] from Sum.forall and Sum.exists (#5900) 2024-11-01 01:21:04 +00:00
Kyle Miller
465ed8af46 feat: resolve generalized field notation using all parents (#5770)
* Now `getPathToBaseStructure?` can navigate to all parent structures,
not just through subobjects.
* Adds a "resolution order" for methods. This is the order that
generalized field notation visits parent structures when trying to
resolve names. The algorithm to compute a resolution order is the
commonly used C3 (used for instance by Python). By default we use a
relaxed version of the algorithm that tolerates inconsistencies. Using
`set_option structure.strictResolutionOrder true` makes inconsistent
parent orderings into warnings.
* This makes generalized field notation be able to resolve names for all
parent structures, not just those that are embedded as subobjects.
Closes #3467. (And addresses side note in #1881.)
* Modifies `getAllParentStructures` to return *all* parents. This
improves dot completion in the editor.
2024-10-31 21:04:50 +00:00
Joachim Breitner
008537abbd fix: FunInd: unfold aux definitions more carefully (#5904)
fixes #5903
2024-10-31 18:04:36 +00:00
Kyle Miller
f8242fa965 fix: delta derived instances now have declaration ranges (#5899)
Fixes an issue where go-to definition on such instances does not work.

Reported [on
Zulip](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/mystery.20guest/near/479820367)
2024-10-31 15:40:17 +00:00
Henrik Böving
844e7ae7eb chore: remove native code for UInt8.modn (#5901)
Closes #5818
2024-10-31 12:42:24 +00:00
Kim Morrison
218601009b chore: rename Array.back to back! (#5897) 2024-10-31 09:18:18 +00:00
Kim Morrison
4af93813f2 chore: move @[simp] from back_eq_back? to back_push (#5896) 2024-10-31 08:25:19 +00:00
Kim Morrison
34be25620f feat: LawfulBEq (Array α) ↔ LawfulBEq α (#5895) 2024-10-31 08:00:06 +00:00
Kim Morrison
a826de8a3d chore: remove duplicated ForIn instances (#5892)
I'd previously added an instance from `ForIn'` to `ForIn`, but this then
caused some non-defeq duplication. It seems fine to just remove the
concrete `ForIn` instances in cases where the `ForIn'` instance exists
too. We can even remove a number of type-specific lemmas in favour of
the general ones.
2024-10-31 07:40:09 +00:00
Kyle Miller
0fcee100e7 feat: enable recursive structure command (#5783)
Now that the elaborator supports primitive projections for recursive
inductive types (#5822), enable defining recursive inductive types with
the `structure` command, which was set up in #5842.

Example:
```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
```

Note for kernel re-implementors: recursive structures are exercising the
kernel feature where primitive projections are valid for one-constructor
inductive types in general, so long as the structure isn't a `Prop` and
doesn't have any non-`Prop` fields, not just ones that are non-indexed
and non-recursive.

Closes #2512
2024-10-31 05:23:12 +00:00
Kyle Miller
03c6e99ef7 fix: bring elaborator in line with kernel for primitive projections (#5822)
The kernel supports primitive projections for all inductive types with
one construtor. The elaborator was assuming primitive projections only
work for "structure-likes", non-recursive inductive types with no
indices.

Enables numeric projection notation for general one-constructor
inductives.

Extracted from #5783.
2024-10-31 03:16:52 +00:00
Lean stage0 autoupdater
0c8d28e9ba chore: update stage0 2024-10-31 02:11:42 +00:00
Kyle Miller
66d68484af fix: make structure parent info persist (#5890)
Modifies the `structureExt` from being a `SimplePersistentEnvExtension`
to a `PersistentEnvExtension`. The simple version contains a `List` of
all added entries, which we do not need since we already have a
`PersistentHashMap` of them in the state. The oversight was that this
`List` contained duplicate entries due to `setStructureParents`
re-adding entries.
2024-10-31 01:22:34 +00:00
Kim Morrison
5c70e5d845 chore: (belatedly) begin development cycle for v4.14.0 (#5889)
This hasn't affected release candidates or stables, but I realised that
I haven't been updating `LEAN_VERSION_MINOR` on `master` the last two
months, so it still says v4.12.0. This advances it to v4.14.0.
2024-10-30 23:48:02 +00:00
Kyle Miller
d4b1be094d feat: adds optConfig syntax for tactic configuration (#5883)
This PR adds a new syntax for tactic and command configurations. It also
updates the elaborator construction command to be able to process this
new syntax.

We do not update core tactics yet. Once tactics switch over to it,
rather than (for example) writing `simp (config := { contextual := true,
maxSteps := 22})`, one can write `simp +contextual (maxSteps := 22)`.
The new syntax is reverse compatible in the sense that `(config := ...)`
still sets the entire configuration.

Note to metaprogrammers: Use `optConfig` instead of `(config)?`. The
elaborator generated by `declare_config_elab` accepts both old and new
configurations. The elaborator has also been written to be tolerant to
null nodes, so adapting to `optConfig` should be as easy as changing
just the syntax for your tactics and deleting `mkOptionalNode`.

Breaking change: The new system is mostly reverse compatible, however
the type of the generated elaborator now lands 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`.
2024-10-30 23:31:34 +00:00
Kyle Miller
c3cbc92a0c feat: upstream and update #where command (#5065)
This command comes from Lean 3, which I had previously ported and
contributed to Batteries (née Std). In this new version, `#where`
produces actual command Syntax for all features of a top-level scope
(rather than splicing together strings), and it also now reports
included variables.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-10-30 18:00:08 +00:00
Joachim Breitner
0d12618539 fix: declareSimpLikeTactic macro to use mkSynthetic (#5838)
this fixes #5597
2024-10-30 14:27:56 +00:00
Henrik Böving
ac80e261bd feat: add embedded constraint substitution to bv_decide (#5886)
This adds the embedded constraint substitution preprocessing pass from
Bitwuzla to `bv_decide`.
It looks for hypotheses of the form `h : x = true` and then attempts to
find occurrences of
`x` within other hypotheses to replace them with true.
2024-10-30 11:43:40 +00:00
Kim Morrison
38c39482f4 chore: add missing deprecation dates (#5884) 2024-10-30 05:37:36 +00:00
Kyle Miller
09802e83cd chore: mention #version in bug report template (#5769) 2024-10-30 02:46:48 +00:00
Alex Keizer
b5bbc57059 feat: prove that intMin is indeed the smallest signed bitvector (#5778) 2024-10-30 02:45:16 +00:00
Mac Malone
4714f84fb9 fix: lake: do not delete path dependencies (#5878)
Fixes a serious issue where Lake would delete path dependencies when
attempting to cleanup a dependency required with an incorrect name.

Closes #5876. Originally part of #5684, but also independently
discovered by François.
2024-10-30 02:31:20 +00:00
Kim Morrison
5e7d02e4ea feat: Hashable (BitVec n) (#5881) 2024-10-30 02:26:18 +00:00
Kim Morrison
5357fd2369 chore: rename List.groupBy to splitBy (#5879)
This makes room for adding a function that returns a HashMap, parallel
to `Array.groupByKey` (which I may also rename to `Array.groupBy`.
2024-10-30 00:56:52 +00:00
えび (ebi_chan)
3450c2a8ac feat: add Nat.log2_two_pow (#5756) 2024-10-29 23:46:17 +00:00
Kyle Miller
95d3b4b58f chore: move MessageData.ofConstName earlier (#5877)
Makes `MessageData.ofConstName` available without needing to import the
pretty printer. Any code making use of `MessageData` can write `m!" ...
{.ofConstName n} ... "` to have the name print with hover information.
More error messages now have hover information.

* Now `.ofConstName` also has a boolean flag to make names print fully
qualified. Default: false.
* Now `.ofConstName` will sanitize names that aren't constants. It is OK
to use it in `"unknown constant '{.ofConstName constName}'"` errors.

Usability note: it is more user-friendly to have "has already been
declared" errors report the fully qualified name. For this, write
`m!"{.ofConstName n true} has already been declared"`.
2024-10-29 21:23:51 +00:00
Kyle Miller
cdbe29b46d feat: accurate binder names in signatures (like in output of #check) (#5827)
An important part of the interface of a function is the parameter names,
for making used of named arguments. This PR makes the parameter names
print in a reliable way. The parameters of the type now appear as
hygienic names if they cannot be used as named arguments.

Modifies the heuristic for how parameters are chosen to appear before or
after the colon. The rule is now that parameters start appearing after
the colon at the first non-dependent non-instance-implicit parameter
that has a name unusable as a named argument. This is a refinement of
#2846.

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)`.

Breaking change: `Lean.PrettyPrinter.Formatter.pushToken` now takes an
additional boolean `ident` argument, which should be `true` for
identifiers. Used to insert discretionary space between consecutive
identifiers.

Closes #5810
2024-10-29 16:43:11 +00:00
Xin Hao
0d471513c5 fix: init git only not inside git work tree (#5789)
Addresses part of #2758.
2024-10-29 13:37:11 +00:00
Lean stage0 autoupdater
d23a231908 chore: update stage0 2024-10-29 12:02:31 +00:00
Joachim Breitner
6514385bb9 feat: attribute [simp ←] (#5870)
This adds the ability to add the converse direction of a rewrite rule
not just in simp arguments `simp [← thm]`, but also as a global
attribute

```lean
attribute [simp ←] thm
```

This fixes #5828.

This can be undone with `attribute [-simp]`, although note that
`[-simp]` wins and cannot be undone at the moment (#5868).

Like `simp [← thm]` (see #4290), this will do an implicit `attribute
[-simp] thm` if the other direction is already defined.
2024-10-29 11:07:08 +00:00
Lean stage0 autoupdater
4ee44ceb1d chore: update stage0 2024-10-29 00:17:47 +00:00
Kyle Miller
1437033e69 fix: prevent addPPExplicitToExposeDiff from assigning metavariables (#5276)
Type mismatch errors have a nice feature where expressions are annotated
with `pp.explicit` to expose differences via `isDefEq` checking.
However, this procedure has side effects since `isDefEq` may assign
metavariables. This PR wraps the procedure with `withoutModifyingState`
to prevent assignments from escaping.

Assignments can lead to confusing behavior. For example, in the
following a higher-order unification fails, but the difference-finding
procedure unifies metavariables in a naive way, producing a baffling
error message:
```lean
theorem test {f g : Nat → Nat} (n : Nat) (hfg : ∀a, f (g a) = a) :
    f (g n) = n := hfg n

example {g2 : ℕ → ℕ} (n2 : ℕ) : (λx => x * 2) (g2 n2) = n2 := by
  with_reducible refine test n2 ?_
  /-
  type mismatch
    test n2 ?m.648
  has type
    (fun x ↦ x * 2) (g2 n2) = n2 : Prop
  but is expected to have type
    (fun x ↦ x * 2) (g2 n2) = n2 : Prop
  -/
```
With the change, it now says `has type ?m.153 (?m.154 n2) = n2`.

Note: this uses `withoutModifyingState` instead of `withNewMCtxDepth`
because we want to know something about where `isDefEq` failed — we are
trying to simulate a very basic version of `isDefEq` for function
applications, and we want the state at the point of failure to know
which argument is "at fault".
2024-10-28 22:51:41 +00:00
Kyle Miller
b308f2bb55 fix: let simp arguments elaborate with error recovery (#5863)
Modifies `simp` to elaborate all simp arguments without disabling error
recovery. Like in #4177, simp arguments with elaboration errors are not
added to the simp set. Error recovery is still disabled when `simp` is
used in combinators such as `first`.

This enables better term info and features like tab completion when
there are elaboration errors.

Also included is a fix to the `all_goals` and `<;>` tactic combinators.
Recall that `try`/`catch` for the Tactic monad restores the state on
failure. This meant that all messages were being cleared on tactic
failure. The fix is to use `Tactic.tryCatch` instead, which doesn't
restore state.

Part of addressing #3831

Closes #4888
2024-10-28 21:39:03 +00:00
Kyle Miller
9eded87462 fix: remove withoutRecover from apply elaboration (#5862)
The assumptions behind disabling error recovery for the `apply` tactic
no longer seem to hold, since tactic combinators like `first` themselves
disable error recovery when it makes sense.

This addresses part of #3831

Breaking change: `elabTermForApply` no longer uses `withoutRecover`.
Tactics using `elabTermForApply` should evaluate whether it makes sense
to wrap it with `withoutRecover`, which is generally speaking when it's
used to elaborate identifiers.
2024-10-28 21:27:14 +00:00
Kyle Miller
19bebfc22f feat: improved calc error messages (#5719)
Makes the error messages report on RHSs and LHSs that do not match the
expected values when the relations are defeq. If the relations are not
defeq, the error message now no longer mentions the value of the whole
`calc` expression.

Adds a field to `mkCoe` with an optional callback to use to generate
error messages.

Note: it is tempting to try to make use of expected types when
elaborating the `calc` expression, but this runs into issue #2073.

Closes #4318
2024-10-28 20:38:45 +00:00
Henrik Böving
c57d054b87 feat: support all the SMTLIB BitVec divison/remainder operations in bv_decide (#5869) 2024-10-28 16:37:06 +00:00
Luisa Cicolini
2f1dc878e4 feat: add BitVec.(msb, getMsbD)_concat (#5865) 2024-10-28 12:10:02 +00:00
Tobias Grosser
f558402ab8 feat: add BitVec.[zero_ushiftRight|zero_sshiftRight|zero_mul] and cle… (#5858)
…an up BVDecide

- Fix names

  shiftLeft_zero_eq -> shiftLeft_zero
  ushiftRight_zero_eq -> ushiftRight_zero

- Remove duplicate prefixes

  BitVec.mul_zero -> mul_zero
  BitVec.mul_add  -> mul_add

- Adapt BVDecide/Normalize/BitVec by reusing the following functions

  zero_add | add_zero
  and_self
  mul_zero | zero_mul
  shiftLeft_zero | zero_shiftLeft
  sshiftRight_zero | zero_sshiftRight
  ushiftRight_zero | zero_ushiftRight
2024-10-28 08:47:29 +00:00
Kyle Miller
62521f4f2d fix: let congr conv tactic handle "over-applied" functions (#5861)
Adds ability to chain congruence lemmas when a function's arity is less
than the number of supplied arguments. This improves `congr` as well as
all conv tactics implemented using `congr`, like `arg` and `enter`.

(The non-conv `congr` tactic still needs to be fixed.)

Toward #2942.
2024-10-28 07:34:33 +00:00
Kyle Miller
9847923f9b feat: record all structure parents in StructureInfo (#5853)
Followup to #5841. Makes the `structure` command populate the new
`parentInfo` field with all the structures in the `extends` clause.

This will require a stage0 update to fully take effect.

Breaking change: now it's a warning if a structure extends a parent
multiple times.

Breaking change: now `getParentStructures` is `getStructureSubobjects`.
Adds `getStructureParentInfo` for getting all the immediate parents.
Note that the set of subobjects is neither a subset nor a superset of
the immediate parents.

Closes #1881
2024-10-28 01:23:48 +00:00
Kyle Miller
709ea6cdf8 feat: make it possible to use dot notation in m! strings (#5857)
This default instance makes it possible to write things like `m!"the
constant is {.ofConstName n}"`.

Breaking change: This weakly causes terms to have a type of
`MessageData` if their type is otherwise unknown. For example:
* `m!"... {x} ..."` can cause `x` to have type `MessageData`, causing
the `let` definition of `x` to fail to elaborate. Fix: give `x` an
explicit type.
* Arithmetic expressions in `m!` strings may need a type ascription. For
example, if the type of `i` is unknown at the time the arithmetic
expression is elaborated, then `m!"... {i + 1} ..."` can fail saying
that it cannot find an `HAdd Nat Nat MessageData` instance. Two fixes:
either ensure that the type of `i` is known, or add a type ascription to
guide the `MessageData` coercion, like `m!"... {(i + 1 : Nat)} ..."`.
2024-10-27 22:55:29 +00:00
Henrik Böving
8c7f7484f9 feat: if support and more in bv_decide (#5855)
Using the same strategy as #5852 this provides `bv_decide` support for
`Bool` and `BitVec` ifs
this in turn instantly enables support for:
- `sdiv`
- `smod`
- `abs`

and thus closes our last discrepancies to QF_BV!
2024-10-27 08:40:38 +00:00
Kyle Miller
c50f04ace0 feat: add delaborators for <|>, <*>, >>, <*, and *> (#5854)
Closes #5668
2024-10-26 23:49:16 +00:00
Henrik Böving
8b5443eb22 feat: support BitVec.ofBool in bv_decide (#5852)
This is the first step towards fixing the issue of not having mutual
recursion between the `Bool` and `BitVec` fragment of `QF_BV` in
`bv_decide`. This PR adds support for `BitVec.ofBool` by doing the
following:
1. Introduce a new mechanism into the reification engine that allows us
to add additional lemmas to the top level on the fly as we are
traversing the expression tree.
2. If we encounter an expression `BitVec.ofBool boolExpr` we reify
`boolExpr` and then abstract `BitVec.ofBool boolExpr` as some atom `a`
3. We add two lemmas `boolExpr = true -> a = 1#1` and `boolExpr = false
-> a = 0#1`. This mirrors the full behavior of `BitVec.ofBool` and thus
makes our atom `a` correctly interpreted again.

In order to do the reification in step 2 mutual recursion in the
reification engine is required. For this reason I started pulling out
logic from the, now rather large, mutual block into other files and
document the invariants that they assume explicitly.
2024-10-26 19:08:07 +00:00
Luisa Cicolini
08c36e4306 feat: add (msb, getMsbD)_twoPow (#5851) 2024-10-26 17:27:37 +00:00
Joachim Breitner
8f0328b777 fix: deprecations in Init.Data.Array.Basic (#5848) 2024-10-26 10:33:47 +00:00
Joachim Breitner
38490a4ac7 refactor: Predefinition.Structural code cleanup (#5850)
useful bits from the shelved #5849
2024-10-26 10:21:47 +00:00
Kyle Miller
13036655e9 fix: reduce types when constructing default values in structure instance notation (#5844)
A step of expanding structure instances is to determine all the default
values, and part of this is reducing projections that appear in the
default values so that they get replaced with the user-provided values.
Binder types in foralls, lambdas, and lets have to be reduced too.

Closes #2186
2024-10-26 00:45:21 +00:00
Kyle Miller
4068cf00ee chore: remove unnecessary private Inhabited instance (#5846)
Since `partial` inhabitation is stronger in #5821, this private instance
is no longer needed.
2024-10-25 23:31:18 +00:00
Kyle Miller
abe6d5bca7 fix: declaration ranges changed after stage0 update (#5845)
Recently declaration ranges have changed slightly to include attribute
lists. Fixes a test that broke.
2024-10-25 21:38:06 +00:00
Lean stage0 autoupdater
f292184642 chore: update stage0 2024-10-25 20:35:09 +00:00
Kyle Miller
a310488b7f chore: refactor structure command, fixes (#5842)
Refactors the `structure` command to support recursive structures. These
are disabled for now, pending additional elaborator support in #5822.
This refactor is also a step toward `structure` appearing in `mutual`
blocks.

Error reporting is now more precise, and this fixes an issue where
general errors could appear on the last field. Adds "don't know how to
synthesize placeholder" errors for default values.

Closes #2512
2024-10-25 19:46:17 +00:00
Joachim Breitner
57a95c8b5f test: test case for #5836 (#5843) 2024-10-25 19:34:09 +00:00
Kyle Miller
266ae428dc feat: preliminary work for parent projections in StructureInfo (#5841)
This adds a `parentInfo` field to the `StructureInfo`, which will
eventually be populated with the actual parents of a structure. This is
work toward #1881. Also documents fields of the structure info data
structures.

Requires a stage0 update before the next steps.
2024-10-25 18:54:32 +00:00
Kim Morrison
4c0d12b3f1 chore: cleanup some deprecations in tests (#5834) 2024-10-25 11:11:22 +00:00
Sebastian Ullrich
748f0d6c15 fix: instantiateMVars slowdown in the language server (#5805)
Fixes #5614
2024-10-25 09:35:41 +00:00
Kim Morrison
07ea626560 feat: Array.forIn', and relate to List (#5833)
Adds support for `for h : x in my_array do`, and relates this to the
existing `List` version.
2024-10-25 07:24:39 +00:00
Henrik Böving
193b6f2bec feat: define Int8 (#5790) 2024-10-25 06:06:40 +00:00
Yann Herklotz
19ce2040a2 fix: wildcard generalize only generalizes visible theorems (#4846)
`generalize ... at *` sometimes will try to modify the recursive
hypothesis corresponding to the current theorem being defined, which may
not be the expected behaviour. It should only try to `generalize`
hypotheses that it can actually modify and are visible, not
implementation details. Otherwise this means that there are
discrepancies between `generalize ... at *` and `generalize ... at H`,
even though `H` is the only hypothesis in the context.

This commit uses `getLocalHyps` instead of `getFVarIds` to get the
current valid `FVarIds` in the context. This uses
`isImplementationDetail` to filter out `FVarIds` that are implementation
details in the context and are not visible to the user and should not be
manipulated by `generalize`.

Closes #4845
2024-10-25 05:09:28 +00:00
Kim Morrison
059674d967 chore: minor fixes in Array lemmas (#5832) 2024-10-25 04:28:41 +00:00
Arthur Adjedj
7150a0d538 fix: reduce let-bodies correctly in StructInst (#3152)
Closes #3146

Reduction doesn't trigger correctly on the bodies of `let`-expressions
in `StructInst`, leading some meta-variables to linger in the terms of
some fields. Because of this, default fields may try multiple times (and
fail) to be generated, leading to an unexpected error.

The solution implemented here is to modify the values of the introduced
variables in the local context so as to reduce them correctly.
2024-10-24 23:33:33 +00:00
Kyle Miller
0725cd39a2 fix: liftCommandElabM now carries more state over (#5800)
The `liftCommandElabM : CommandElabM α -> CoreM α` function now carries
over macro scopes, the name generator, info trees, and messages.

Adds a flag `throwOnError`, which is true by default. When it is true,
then if the messages contain an error message, it is converted into an
exception. In this case, the infotrees and messages are not carried
over; the motivation is that `throwOnError` is likely used for synthetic
syntax, and so the info and messages on errors will just be noise.
2024-10-24 23:19:06 +00:00
Kyle Miller
e07272a53a chore: review delaborators, make sure they respond to pp.explicit (#5830)
Rule: if an expression contains an implicit argument that the
delaborator would omit, only use the delaborator if `pp.explicit` is
false.
2024-10-24 22:56:47 +00:00
Sebastian Ullrich
9157c1f279 test: big_omega benchmark (#5817)
Extracted from #5614
2024-10-24 07:26:29 +00:00
Kim Morrison
09e1a05ee9 chore: cleanup imports (#5825) 2024-10-23 23:51:13 +00:00
Henrik Böving
8822b0fca7 feat: bv_decide BitVec.sdiv (#5823) 2024-10-23 21:10:27 +00:00
Kyle Miller
249530f3c1 feat: partial inhabitation uses local Inhabited instances created from parameters (#5821)
Rather than having a special pass where `mkInhabitantFor` uses the
`assumption` tactic, it creates `Inhabited` instances for each parameter
and just searches for an `Inhabited`/`Nonempty` instance for the return
type.

This makes examples like the following work:
```lean
partial def f (x : X) : Bool × X := ...
```

Removes the strategy where it looks for `Inhabited`/`Nonempty` instances
for every suffix of the signature.

This is a follow-up to #5780. Motivated [by
Zulip](https://leanprover.zulipchat.com/#narrow/channel/113489-new-members/topic/Why.20return.20type.20of.20partial.20function.20MUST.20.60inhabited.60.3F/near/477905312).
2024-10-23 18:15:31 +00:00
Sebastian Ullrich
174a5f345a refactor: nicer modifiers/ranges API (#5788)
Cleanup of #5650 

* default `Modifiers.stx` to missing
* rename and clarify `addDeclarationRangesFromSyntax` as the main
convenience function for user metaprograms
2024-10-23 09:21:50 +00:00
Aaron Tomb
45b1b367ca test: add a benchmark that is slow to elaborate (#5656)
Add an example Lean file that includes an unusually large definition
that takes a long time to elaborate.

It may be that it's difficult to process it more efficiently, but
perhaps someone will discover a way to improve it if it's in the
benchmark suite. Improved performance on this benchmark will likely make
some program analysis and verification tasks within Lean more feasible.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-10-23 08:20:15 +00:00
Kim Morrison
c1143d9432 feat: more lemmas for List.modify (#5816) 2024-10-23 06:45:20 +00:00
Kyle Miller
66dbad911e fix: improve error message for partial inhabitation and add delta deriving (#5780)
Example new output:
```text
failed to compile 'partial' definition 'checkMyList', could not prove that the type
  ListNode → Bool × ListNode
is nonempty.

This process uses multiple strategies:
- It looks for a parameter that matches the return type.
- It tries synthesizing 'Inhabited' and 'Nonempty' instances for the return type.
- It tries unfolding the return type.

If the return type is defined using the 'structure' or 'inductive' command, you can try
adding a 'deriving Nonempty' clause to it.
```
The inhabitation prover now also unfolds definitions when trying to
prove inhabitation. For example,
```lean
def T (α : Type) := α × α

partial def f (n : Nat) : T Nat := f n
```

Motivated [by
Zulip](https://leanprover.zulipchat.com/#narrow/channel/113489-new-members/topic/Why.20return.20type.20of.20partial.20function.20MUST.20.60inhabited.60.3F/near/477905312)
2024-10-23 06:32:11 +00:00
FR
fad57cf5a2 chore: remove redundant Decidable assumptions (#5812) 2024-10-23 04:52:54 +00:00
Kyle Miller
83129b7e3a fix: inductive elaboration should keep track of universe level parameters created in binders (#5814)
Refactors `inductive` elaborator to keep track of universe level
parameters created during elaboration of `variable`s and binders. This
fixes an issue in Mathlib where its `Type*` elaborator can result in
unexpected universe levels.

For example, in
```lean4
variable {F : Type*}
inductive I1 (A B : Type*) (x : F) : Type
```
before this change the signature would be
```
I1.{u_1, u_2} {F : Type u_1} (A : Type u_1) (B : Type u_2) (x : F) : Type
```
but now it is
```
I1.{u_1, u_2, u_3} {F : Type u_1} (A : Type u_2) (B : Type u_3) (x : F) : Type
```
Fixes this for the `axiom` elaborator too.

Adds more accurate universe level validation for mutual inductives.

Breaking change: removes `Lean.Elab.Command.expandDeclId`. Use
`Lean.Elab.Term.expandDeclId` from within `runCommandElabM`.
2024-10-23 04:07:40 +00:00
Kyle Miller
fa711253d6 feat: improved error message for unfold (#5815)
When `unfold` is trying to unfold a local variable that's not a local
definition, throws an error.

For issue from
[Zulip](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Unqualified.20unfold.20no.20longer.20works/near/478387250)
2024-10-23 03:35:15 +00:00
Joachim Breitner
eddbdd77b8 doc: refine rwa docstring (#5811)
fixes #5792
2024-10-22 16:02:39 +00:00
Markus Himmel
f0c190239a feat: compile against Windows SDK headers under Windows (#5753)
Breaking changes:

To build Lean from source on Windows, it is now necessary to install the
[Windows
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/).
The build instructions have been updated to reflect this. Note that the
Windows SDK is **not** needed to compile Lean programs using a Lean
toolchain obtained using `elan`. The Windows SDK is only needed to build
Lean itself from source.

Furthermore, we are dropping support for Windows versions older than
Windows 10 1903 (released in May 2019).

No Windows version that is still supported by Microsoft as part of
mainstream support is affected by this.

The following Windows versions are still supported by Microsoft as part
of commercial extended support but are no longer supported by Lean:

- Windows 10 Enterprise LTSC 2015
- Windows 10 Enterprise LTSC 2016
- Windows 10 Enterprise LTSC 2019
- Windows Server 2019
2024-10-22 13:00:02 +00:00
Joachim Breitner
bab6aff173 chore: nix-ci.yml: fix test-results.xml path (#5804) 2024-10-22 11:18:40 +00:00
Joachim Breitner
5bea46deb0 fix: FunInd: withLetDecl and mkLetVar don’t mix (#5803)
Fixes: #5767
2024-10-22 10:15:14 +00:00
Marc Huisinga
462e52d0c0 feat: use "eureka!" icon for theorem completions (#5801)
It's difficult to distinguish theorems from regular definitions in the
completion menu, which is annoying when using completion for searching
one or the other. This PR makes theorem completions use the "Eureka!"
icon (![eureka
icon](https://code.visualstudio.com/assets/docs/editor/intellisense/symbol-event.svg))
to distinguish them more clearly from other completions.

NB: We are very limited in terms of which icons we can pick here since
[the completion kinds provided by LSP / VS
Code](https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions)
are optimized for object-oriented programming languages, but I think
this choice strikes a nice balance between being easy to identify,
having some visual connection to theorem proving and not being used a
lot in other languages and thus not clashing with pre-existing
associations.
2024-10-22 10:07:37 +00:00
Sebastian Ullrich
d0abe1d382 fix: restore synchronous fast-forwarding path in language processor (#5802)
Between #3106 and this, it was possible that reparsing the file up to
the current position was stuck waiting in the threadpool queue,
displaying a yellow bar and not displaying any info on the unchanged
prefix.
2024-10-22 09:50:30 +00:00
Eric Wieser
f752ce2db9 doc: stub for ellipsis notation (#5794)
This is certainly better than no documentation, though it's not obvious
to me whether the `_` insertion is greedy, lazy, or somewhere in
between.
2024-10-22 01:33:46 +00:00
Kim Morrison
07c09ee579 feat: relate Array.forIn and List.forIn (#5799) 2024-10-22 01:20:13 +00:00
Kim Morrison
919f64b2e6 chore: upstream List.modify, add lemmas, relate to Array.modify (#5798)
Note that the order of arguments still differs between `List.modify` and
`Array.modify`. I'll settle this later.
2024-10-22 01:01:32 +00:00
Kim Morrison
71122696a1 feat: rename Array.shrink to take, and relate to List.take (#5796) 2024-10-21 23:35:32 +00:00
1935 changed files with 47551 additions and 11672 deletions

View File

@@ -39,7 +39,7 @@ Please put an X between the brackets as you perform the following steps:
### Versions
[Output of `#eval Lean.versionString`]
[Output of `#version` or `#eval Lean.versionString`]
[OS version, if not using live.lean-lang.org.]
### Additional Information

View File

@@ -5,6 +5,10 @@
* Include the link to your `RFC` or `bug` issue in the description.
* If the issue does not already have approval from a developer, submit the PR as draft.
* The PR title/description will become the commit message. Keep it up-to-date as the PR evolves.
* For `feat/fix` PRs, the first paragraph starting with "This PR" must be present and will become a
changelog entry unless the PR is labeled with `no-changelog`. If the PR does not have this label,
it must instead be categorized with one of the `changelog-*` labels (which will be done by a
reviewer for external PRs).
* A toolchain of the form `leanprover/lean4-pr-releases:pr-release-NNNN` for Linux and M-series Macs will be generated upon build. To generate binaries for Windows and Intel-based Macs as well, write a comment containing `release-ci` on its own line.
* If you rebase your PR onto `nightly-with-mathlib` then CI will test Mathlib against your PR.
* You can manage the `awaiting-review`, `awaiting-author`, and `WIP` labels yourself, by writing a comment containing one of these labels on its own line.
@@ -12,4 +16,6 @@
---
Closes #0000 (`RFC` or `bug` issue number fixed by this PR, if any)
This PR <short changelog summary for feat/fix, see above>.
Closes <`RFC` or `bug` issue number fixed by this PR, if any>

8
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
commit-message:
prefix: "chore: CI"

View File

@@ -17,6 +17,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: actionlint
uses: raven-actions/actionlint@v1
uses: raven-actions/actionlint@v2
with:
pyflakes: false # we do not use python scripts

View File

@@ -14,6 +14,7 @@ jobs:
sparse-checkout: |
src/Lean
src/Std
src/lake/Lake
- name: Check Prelude
run: |
failed_files=""
@@ -21,7 +22,7 @@ jobs:
if ! grep -q "^prelude$" "$file"; then
failed_files="$failed_files$file\n"
fi
done < <(find src/Lean src/Std -name '*.lean' -print0)
done < <(find src/Lean src/Std src/lake/Lake -name '*.lean' -print0)
if [ -n "$failed_files" ]; then
echo -e "The following files should use 'prelude':\n$failed_files"
exit 1

View File

@@ -217,7 +217,7 @@ jobs:
"release": true,
"check-level": 2,
"shell": "msys2 {0}",
"CMAKE_OPTIONS": "-G \"Unix Makefiles\" -DUSE_GMP=OFF",
"CMAKE_OPTIONS": "-G \"Unix Makefiles\"",
// for reasons unknown, interactivetests are flaky on Windows
"CTEST_OPTIONS": "--repeat until-pass:2",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
@@ -227,7 +227,7 @@ jobs:
{
"name": "Linux aarch64",
"os": "nscloud-ubuntu-22.04-arm64-4x8",
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64",
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-linux_aarch64",
"release": true,
"check-level": 2,
"shell": "nix develop .#oldGlibcAArch -c bash -euxo pipefail {0}",
@@ -318,7 +318,7 @@ jobs:
if: github.event_name == 'pull_request'
# (needs to be after "Checkout" so files don't get overridden)
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v12
uses: mymindstorm/setup-emsdk@v14
with:
version: 3.1.44
actions-cache-folder: emsdk
@@ -492,7 +492,7 @@ jobs:
with:
path: artifacts
- name: Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
files: artifacts/*/*
fail_on_unmatched_files: true
@@ -536,7 +536,7 @@ jobs:
echo -e "\n*Full commit log*\n" >> diff.md
git log --oneline "$last_tag"..HEAD | sed 's/^/* /' >> diff.md
- name: Release Nightly
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
body_path: diff.md
prerelease: true

View File

@@ -1,7 +1,8 @@
# This workflow allows any user to add one of the `awaiting-review`, `awaiting-author`, `WIP`,
# or `release-ci` labels by commenting on the PR or issue.
# `release-ci`, or a `changelog-XXX` label by commenting on the PR or issue.
# If any labels from the set {`awaiting-review`, `awaiting-author`, `WIP`} are added, other labels
# from that set are removed automatically at the same time.
# Similarly, if any `changelog-XXX` label is added, other `changelog-YYY` labels are removed.
name: Label PR based on Comment
@@ -11,7 +12,7 @@ on:
jobs:
update-label:
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP') || contains(github.event.comment.body, 'release-ci'))
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP') || contains(github.event.comment.body, 'release-ci') || contains(github.event.comment.body, 'changelog-'))
runs-on: ubuntu-latest
steps:
@@ -20,13 +21,14 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo, number: issue_number } = context.issue;
const { owner, repo, number: issue_number } = context.issue;
const commentLines = context.payload.comment.body.split('\r\n');
const awaitingReview = commentLines.includes('awaiting-review');
const awaitingAuthor = commentLines.includes('awaiting-author');
const wip = commentLines.includes('WIP');
const releaseCI = commentLines.includes('release-ci');
const changelogMatch = commentLines.find(line => line.startsWith('changelog-'));
if (awaitingReview || awaitingAuthor || wip) {
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'awaiting-review' }).catch(() => {});
@@ -47,3 +49,19 @@ jobs:
if (releaseCI) {
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['release-ci'] });
}
if (changelogMatch) {
const changelogLabel = changelogMatch.trim();
const { data: existingLabels } = await github.rest.issues.listLabelsOnIssue({ owner, repo, issue_number });
const changelogLabels = existingLabels.filter(label => label.name.startsWith('changelog-'));
// Remove all other changelog labels
for (const label of changelogLabels) {
if (label.name !== changelogLabel) {
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label.name }).catch(() => {});
}
}
// Add the new changelog label
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [changelogLabel] });
}

View File

@@ -96,7 +96,7 @@ jobs:
nix build $NIX_BUILD_ARGS .#cacheRoots -o push-build
- name: Test
run: |
nix build --keep-failed $NIX_BUILD_ARGS .#test -o push-test || (ln -s /tmp/nix-build-*/source/src/build/ ./push-test; false)
nix build --keep-failed $NIX_BUILD_ARGS .#test -o push-test || (ln -s /tmp/nix-build-*/build/source/src/build ./push-test; false)
- name: Test Summary
uses: test-summary/action@v2
with:
@@ -110,14 +110,6 @@ jobs:
# https://github.com/netlify/cli/issues/1809
cp -r --dereference ./result ./dist
if: matrix.name == 'Nix Linux'
- name: Check manual for broken links
id: lychee
uses: lycheeverse/lychee-action@v1.9.0
with:
fail: false # report errors but do not block CI on temporary failures
# gmplib.org consistently times out from GH actions
# the GitHub token is to avoid rate limiting
args: --base './dist' --no-progress --github-token ${{ secrets.GITHUB_TOKEN }} --exclude 'gmplib.org' './dist/**/*.html'
- name: Rebuild Nix Store Cache
run: |
rm -rf nix-store-cache || true
@@ -129,7 +121,7 @@ jobs:
python3 -c 'import base64; print("alias="+base64.urlsafe_b64encode(bytes.fromhex("${{github.sha}}")).decode("utf-8").rstrip("="))' >> "$GITHUB_OUTPUT"
echo "message=`git log -1 --pretty=format:"%s"`" >> "$GITHUB_OUTPUT"
- name: Publish manual to Netlify
uses: nwtgck/actions-netlify@v2.0
uses: nwtgck/actions-netlify@v3.0
id: publish-manual
with:
publish-dir: ./dist

25
.github/workflows/pr-body.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Check PR body for changelog convention
on:
merge_group:
pull_request:
types: [opened, synchronize, reopened, edited, labeled, converted_to_draft, ready_for_review]
jobs:
check-pr-body:
runs-on: ubuntu-latest
steps:
- name: Check PR body
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const { title, body, labels, draft } = context.payload.pull_request;
if (!draft && /^(feat|fix):/.test(title) && !labels.some(label => label.name == "changelog-no")) {
if (!labels.some(label => label.name.startsWith("changelog-"))) {
core.setFailed('feat/fix PR must have a `changelog-*` label');
}
if (!/^This PR [^<]/.test(body)) {
core.setFailed('feat/fix PR must have changelog summary starting with "This PR ..." as first line.');
}
}

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@v2 # https://github.com/marketplace/actions/download-workflow-artifact
uses: dawidd6/action-download-artifact@v7 # https://github.com/marketplace/actions/download-workflow-artifact
with:
run_id: ${{ github.event.workflow_run.id }}
path: artifacts
@@ -60,7 +60,7 @@ jobs:
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
- name: Release
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
# There are coredumps files here as well, but all in deeper subdirectories.
@@ -75,7 +75,7 @@ jobs:
- name: Report release status
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.createCommitStatus({
@@ -111,7 +111,7 @@ jobs:
- name: 'Setup jq'
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
uses: dcarbone/install-jq-action@v1.0.1
uses: dcarbone/install-jq-action@v3.0.1
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
- name: Check merge-base and nightly-testing-YYYY-MM-DD
@@ -208,7 +208,7 @@ jobs:
- name: Report mathlib base
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' }}
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
script: |
const description =

View File

@@ -11,7 +11,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
- uses: actions/stale@v9
with:
days-before-stale: -1
days-before-pr-stale: 30

View File

@@ -8,6 +8,613 @@ This file contains work-in-progress notes for the upcoming release, as well as p
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status
of each version.
v4.16.0
----------
Development in progress.
v4.15.0
----------
Release candidate, release notes will be copied from the branch `releases/v4.15.0` once completed.
v4.14.0
----------
**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))
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`
v4.12.0
----------

View File

@@ -1 +0,0 @@
[0829/202002.254:ERROR:crashpad_client_win.cc(868)] not connected

View File

@@ -103,10 +103,21 @@ your PR using rebase merge, bypassing the merge queue.
As written above, changes in meta code in the current stage usually will only
affect later stages. This is an issue in two specific cases.
* For the special case of *quotations*, it is desirable to have changes in builtin parsers affect them immediately: when the changes in the parser become active in the next stage, builtin macros implemented via quotations should generate syntax trees compatible with the new parser, and quotation patterns in builtin macros and elaborators should be able to match syntax created by the new parser and macros.
Since quotations capture the syntax tree structure during execution of the current stage and turn it into code for the next stage, we need to run the current stage's builtin parsers in quotations via the interpreter for this to work.
Caveats:
* We activate this behavior by default when building stage 1 by setting `-Dinternal.parseQuotWithCurrentStage=true`.
We force-disable it inside `macro/macro_rules/elab/elab_rules` via `suppressInsideQuot` as they are guaranteed not to run in the next stage and may need to be run in the current one, so the stage 0 parser is the correct one to use for them.
It may be necessary to extend this disabling to functions that contain quotations and are (exclusively) used by one of the mentioned commands. A function using quotations should never be used by both builtin and non-builtin macros/elaborators. Example: https://github.com/leanprover/lean4/blob/f70b7e5722da6101572869d87832494e2f8534b7/src/Lean/Elab/Tactic/Config.lean#L118-L122
* The parser needs to be reachable via an `import` statement, otherwise the version of the previous stage will silently be used.
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading tokens is taken from the previous stage.
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422R13
* For *non-builtin* meta code such as `notation`s or `macro`s in
`Notation.lean`, we expect changes to affect the current file and all later
files of the same stage immediately, just like outside the stdlib. To ensure
this, we need to build the stage using `-Dinterpreter.prefer_native=false` -
this, we build stage 1 using `-Dinterpreter.prefer_native=false` -
otherwise, when executing a macro, the interpreter would notice that there is
already a native symbol available for this function and run it instead of the
new IR, but the symbol is from the previous stage!
@@ -124,26 +135,11 @@ affect later stages. This is an issue in two specific cases.
further stages (e.g. after an `update-stage0`) will then need to be compiled
with the flag set to `false` again since they will expect the new signature.
For an example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
When enabling `prefer_native`, we usually want to *disable* `parseQuotWithCurrentStage` as it would otherwise make quotations use the interpreter after all.
However, there is a specific case where we want to set both options to `true`: when we make changes to a non-builtin parser like `simp` that has a builtin elaborator, we cannot have the new parser be active outside of quotations in stage 1 as the builtin elaborator from stage 0 would not understand them; on the other hand, we need quotations in e.g. the builtin `simp` elaborator to produce the new syntax in the next stage.
As this issue usually affects only tactics, enabling `debug.byAsSorry` instead of `prefer_native` can be a simpler solution.
* For the special case of *quotations*, it is desirable to have changes in
built-in parsers affect them immediately: when the changes in the parser
become active in the next stage, macros implemented via quotations should
generate syntax trees compatible with the new parser, and quotation patterns
in macro and elaborators should be able to match syntax created by the new
parser and macros. Since quotations capture the syntax tree structure during
execution of the current stage and turn it into code for the next stage, we
need to run the current stage's built-in parsers in quotation via the
interpreter for this to work. Caveats:
* Since interpreting full parsers is not nearly as cheap and we rarely change
built-in syntax, this needs to be opted in using `-Dinternal.parseQuotWithCurrentStage=true`.
* The parser needs to be reachable via an `import` statement, otherwise the
version of the previous stage will silently be used.
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading
tokens is taken from the previous stage.
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422
(from before the flag defaulted to `false`).
For a `prefer_native` example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
To modify either of these flags both for building and editing the stdlib, adjust
the code in `stage0/src/stdlib_flags.h`. The flags will automatically be reset

View File

@@ -12,17 +12,17 @@ Remark: this example is based on an example found in the Idris manual.
Vectors
--------
A `Vector` is a list of size `n` whose elements belong to a type `α`.
A `Vec` is a list of size `n` whose elements belong to a type `α`.
-/
inductive Vector (α : Type u) : Nat Type u
| nil : Vector α 0
| cons : α Vector α n Vector α (n+1)
inductive Vec (α : Type u) : Nat Type u
| nil : Vec α 0
| cons : α Vec α n Vec α (n+1)
/-!
We can overload the `List.cons` notation `::` and use it to create `Vector`s.
We can overload the `List.cons` notation `::` and use it to create `Vec`s.
-/
infix:67 " :: " => Vector.cons
infix:67 " :: " => Vec.cons
/-!
Now, we define the types of our simple functional language.
@@ -50,11 +50,11 @@ the builtin instance for `Add Int` as the solution.
/-!
Expressions are indexed by the types of the local variables, and the type of the expression itself.
-/
inductive HasType : Fin n Vector Ty n Ty Type where
inductive HasType : Fin n Vec Ty n Ty Type where
| stop : HasType 0 (ty :: ctx) ty
| pop : HasType k ctx ty HasType k.succ (u :: ctx) ty
inductive Expr : Vector Ty n Ty Type where
inductive Expr : Vec Ty n Ty Type where
| var : HasType i ctx ty Expr ctx ty
| val : Int Expr ctx Ty.int
| lam : Expr (a :: ctx) ty Expr ctx (Ty.fn a ty)
@@ -102,8 +102,8 @@ indexed over the types in scope. Since an environment is just another form of li
to the vector of local variable types, we overload again the notation `::` so that we can use the usual list syntax.
Given a proof that a variable is defined in the context, we can then produce a value from the environment.
-/
inductive Env : Vector Ty n Type where
| nil : Env Vector.nil
inductive Env : Vec Ty n Type where
| nil : Env Vec.nil
| cons : Ty.interp a Env ctx Env (a :: ctx)
infix:67 " :: " => Env.cons

View File

@@ -82,9 +82,7 @@ theorem Expr.typeCheck_correct (h₁ : HasType e ty) (h₂ : e.typeCheck ≠ .un
/-!
Now, we prove that if `Expr.typeCheck e` returns `Maybe.unknown`, then forall `ty`, `HasType e ty` does not hold.
The notation `e.typeCheck` is sugar for `Expr.typeCheck e`. Lean can infer this because we explicitly said that `e` has type `Expr`.
The proof is by induction on `e` and case analysis. The tactic `rename_i` is used to rename "inaccessible" variables.
We say a variable is inaccessible if it is introduced by a tactic (e.g., `cases`) or has been shadowed by another variable introduced
by the user. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes
The proof is by induction on `e` and case analysis. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes
the cases corresponding to the constructors `Expr.nat` and `Expr.bool`.
-/
theorem Expr.typeCheck_complete {e : Expr} : e.typeCheck = .unknown ¬ HasType e ty := by

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
source ../../tests/common.sh
exec_check lean -Dlinter.all=false "$f"
exec_check_raw lean -Dlinter.all=false "$f"

View File

@@ -128,16 +128,16 @@ Numeric literals can be specified in various bases.
```
numeral : numeral10 | numeral2 | numeral8 | numeral16
numeral10 : [0-9]+
numeral2 : "0" [bB] [0-1]+
numeral8 : "0" [oO] [0-7]+
numeral16 : "0" [xX] hex_char+
numeral10 : [0-9]+ ("_"+ [0-9]+)*
numeral2 : "0" [bB] ("_"* [0-1]+)+
numeral8 : "0" [oO] ("_"* [0-7]+)+
numeral16 : "0" [xX] ("_"* hex_char+)+
```
Floating point literals are also possible with optional exponent:
```
float : [0-9]+ "." [0-9]+ [[eE[+-][0-9]+]
float : numeral10 "." numeral10? [eE[+-]numeral10]
```
For example:
@@ -147,6 +147,7 @@ constant w : Int := 55
constant x : Nat := 26085
constant y : Nat := 0x65E5
constant z : Float := 2.548123e-05
constant b : Bool := 0b_11_01_10_00
```
Note: that negative numbers are created by applying the "-" negation prefix operator to the number, for example:

View File

@@ -1,6 +1,6 @@
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](doc/dev/index.md).
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
We strongly suggest that new users instead follow the [Quickstart](doc/quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
Requirements
------------

View File

@@ -15,6 +15,13 @@ Mode](https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-devi
which will allow Lean to create symlinks that e.g. enable go-to-definition in
the stdlib.
## Installing the Windows SDK
Install the Windows SDK from [Microsoft](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/).
The oldest supported version is 10.0.18362.0. If you installed the Windows SDK to the default location,
then there should be a directory with the version number at `C:\Program Files (x86)\Windows Kits\10\Include`.
If there are multiple directories, only the highest version number matters.
## Installing dependencies
[The official webpage of MSYS2][msys2] provides one-click installers.

View File

@@ -138,8 +138,8 @@ definition:
-/
instance : Applicative List where
pure := List.pure
seq f x := List.bind f fun y => Functor.map y (x ())
pure := List.singleton
seq f x := List.flatMap f fun y => Functor.map y (x ())
/-!
Notice you can now sequence a _list_ of functions and a _list_ of items.

View File

@@ -128,8 +128,8 @@ Applying the identity function through an applicative structure should not chang
values or structure. For example:
-/
instance : Applicative List where
pure := List.pure
seq f x := List.bind f fun y => Functor.map y (x ())
pure := List.singleton
seq f x := List.flatMap f fun y => Functor.map y (x ())
#eval pure id <*> [1, 2, 3] -- [1, 2, 3]
/-!
@@ -235,8 +235,8 @@ structure or its values.
Left identity is `x >>= pure = x` and is demonstrated by the following examples on a monadic `List`:
-/
instance : Monad List where
pure := List.pure
bind := List.bind
pure := List.singleton
bind := List.flatMap
def a := ["apple", "orange"]

View File

@@ -192,8 +192,8 @@ implementation of `pure` and `bind`.
-/
instance : Monad List where
pure := List.pure
bind := List.bind
pure := List.singleton
bind := List.flatMap
/-!
Like you saw with the applicative `seq` operator, the `bind` operator applies the given function

View File

@@ -139,7 +139,7 @@ You might be wondering, how does the context actually move through the `ReaderM`
add an input argument to a function by modifying its return type? There is a special command in
Lean that will show you the reduced types:
-/
#reduce ReaderM Environment String -- Environment → String
#reduce (types := true) ReaderM Environment String -- Environment → String
/-!
And you can see here that this type is actually a function! It's a function that takes an
`Environment` as input and returns a `String`.
@@ -196,4 +196,4 @@ entirely.
Now it's time to move on to [StateM Monad](states.lean.md) which is like a `ReaderM` that is
also updatable.
-/
-/

View File

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

View File

@@ -38,7 +38,11 @@
# more convenient `ctest` output
CTEST_OUTPUT_ON_FAILURE = 1;
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
GMP = pkgsDist.gmp.override { withStatic = true; };
GMP = (pkgsDist.gmp.override { withStatic = true; }).overrideAttrs (attrs:
pkgs.lib.optionalAttrs (pkgs.stdenv.system == "aarch64-linux") {
# would need additional linking setup on Linux aarch64, we don't use it anywhere else either
hardeningDisable = [ "stackprotector" ];
});
LIBUV = pkgsDist.libuv.overrideAttrs (attrs: {
configureFlags = ["--enable-static"];
hardeningDisable = [ "stackprotector" ];

View File

@@ -170,7 +170,7 @@ lib.warn "The Nix-based build is deprecated" rec {
ln -sf ${lean-all}/* .
'';
buildPhase = ''
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi' -j$NIX_BUILD_CORES
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi|leanruntest_timeIO' -j$NIX_BUILD_CORES
'';
installPhase = ''
mkdir $out

12
script/mathlib-bench Executable file
View File

@@ -0,0 +1,12 @@
#! /bin/env bash
# Open a Mathlib4 PR for benchmarking a given Lean 4 PR
set -euo pipefail
[ $# -eq 1 ] || (echo "usage: $0 <lean4 PR #>"; exit 1)
LEAN_PR=$1
PR_RESPONSE=$(gh api repos/leanprover-community/mathlib4/pulls -X POST -f head=lean-pr-testing-$LEAN_PR -f base=nightly-testing -f title="leanprover/lean4#$LEAN_PR benchmarking" -f draft=true -f body="ignore me")
PR_NUMBER=$(echo "$PR_RESPONSE" | jq '.number')
echo "opened https://github.com/leanprover-community/mathlib4/pull/$PR_NUMBER"
gh api repos/leanprover-community/mathlib4/issues/$PR_NUMBER/comments -X POST -f body="!bench" > /dev/null

View File

@@ -64,7 +64,7 @@ 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 -lpthread -ldl -lrt -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
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'"
# 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

@@ -31,14 +31,20 @@ cp /clang64/lib/{crtbegin,crtend,crt2,dllcrt2}.o stage1/lib/
# runtime
(cd llvm; cp --parents lib/clang/*/lib/*/libclang_rt.builtins* ../stage1)
# further dependencies
cp /clang64/lib/lib{m,bcrypt,mingw32,moldname,mingwex,msvcrt,pthread,advapi32,shell32,user32,kernel32,ucrtbase,psapi,iphlpapi,userenv,ws2_32,dbghelp,ole32}.* /clang64/lib/libgmp.a /clang64/lib/libuv.a llvm/lib/lib{c++,c++abi,unwind}.a stage1/lib/
# Note: even though we're linking against libraries like `libbcrypt.a` which appear to be static libraries from the file name,
# we're not actually linking statically against the code.
# Rather, `libbcrypt.a` is an import library (see https://en.wikipedia.org/wiki/Dynamic-link_library#Import_libraries) that just
# tells the compiler how to dynamically link against `bcrypt.dll` (which is located in the System32 folder).
# This distinction is relevant specifically for `libicu.a`/`icu.dll` because there we want updates to the time zone database to
# be delivered to users via Windows Update without having to recompile Lean or Lean programs.
cp /clang64/lib/lib{m,bcrypt,mingw32,moldname,mingwex,msvcrt,pthread,advapi32,shell32,user32,kernel32,ucrtbase,psapi,iphlpapi,userenv,ws2_32,dbghelp,ole32,icu}.* /clang64/lib/libgmp.a /clang64/lib/libuv.a llvm/lib/lib{c++,c++abi,unwind}.a stage1/lib/
echo -n " -DLEAN_STANDALONE=ON"
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang.exe -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER=$PWD/llvm/bin/clang++.exe -DCMAKE_CXX_COMPILER_WORKS=1 -DLEAN_CXX_STDLIB='-lc++ -lc++abi'"
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'"
# when not using the above flags, link GMP dynamically/as usual
# 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
echo -n " -DAUTO_THREAD_FINALIZATION=OFF -DSTAGE0_AUTO_THREAD_FINALIZATION=OFF"

View File

@@ -10,13 +10,15 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 12)
set(LEAN_VERSION_MINOR 16)
set(LEAN_VERSION_PATCH 0)
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
set(LEAN_VERSION_STRING "${LEAN_VERSION_MAJOR}.${LEAN_VERSION_MINOR}.${LEAN_VERSION_PATCH}")
if (LEAN_SPECIAL_VERSION_DESC)
string(APPEND LEAN_VERSION_STRING "-${LEAN_SPECIAL_VERSION_DESC}")
elseif (NOT LEAN_VERSION_IS_RELEASE)
string(APPEND LEAN_VERSION_STRING "-pre")
endif()
set(LEAN_PLATFORM_TARGET "" CACHE STRING "LLVM triple of the target platform")
@@ -49,6 +51,8 @@ option(LLVM "LLVM" OFF)
option(USE_GITHASH "GIT_HASH" ON)
# When ON we install LICENSE files to CMAKE_INSTALL_PREFIX
option(INSTALL_LICENSE "INSTALL_LICENSE" ON)
# When ON we install a copy of cadical
option(INSTALL_CADICAL "Install a copy of cadical" ON)
# When ON thread storage is automatically finalized, it assumes platform support pthreads.
# This option is important when using Lean as library that is invoked from a different programming language (e.g., Haskell).
option(AUTO_THREAD_FINALIZATION "AUTO_THREAD_FINALIZATION" ON)
@@ -118,7 +122,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
# From https://emscripten.org/docs/compiling/WebAssembly.html#backends:
# > The simple and safe thing is to pass all -s flags at both compile and link time.
set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -fwasm-exceptions -pthread -flto")
string(APPEND LEANC_EXTRA_FLAGS " -pthread")
string(APPEND LEANC_EXTRA_CC_FLAGS " -pthread")
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}")
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}")
endif()
@@ -153,7 +157,11 @@ if ((${MULTI_THREAD} MATCHES "ON") AND (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
endif ()
# We want explicit stack probes in huge Lean stack frames for robust stack overflow detection
string(APPEND LEANC_EXTRA_FLAGS " -fstack-clash-protection")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fstack-clash-protection")
# This makes signed integer overflow guaranteed to match 2's complement.
string(APPEND CMAKE_CXX_FLAGS " -fwrapv")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fwrapv")
if(NOT MULTI_THREAD)
message(STATUS "Disabled multi-thread support, it will not be safe to run multiple threads in parallel")
@@ -297,6 +305,23 @@ if(NOT LEAN_STANDALONE)
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${LIBUV_LIBRARIES}")
endif()
# Windows SDK (for ICU)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# Pass 'tools' to skip MSVC version check (as MSVC/Visual Studio is not necessarily installed)
find_package(WindowsSDK REQUIRED COMPONENTS tools)
# This will give a semicolon-separated list of include directories
get_windowssdk_include_dirs(${WINDOWSSDK_LATEST_DIR} WINDOWSSDK_INCLUDE_DIRS)
# To successfully build against Windows SDK headers, the Windows SDK headers must have lower
# priority than other system headers, so use `-idirafter`. Unfortunately, CMake does not
# support this using `include_directories`.
string(REPLACE ";" "\" -idirafter \"" WINDOWSSDK_INCLUDE_DIRS "${WINDOWSSDK_INCLUDE_DIRS}")
string(APPEND CMAKE_CXX_FLAGS " -idirafter \"${WINDOWSSDK_INCLUDE_DIRS}\"")
string(APPEND LEAN_EXTRA_LINKER_FLAGS " -licu")
endif()
# ccache
if(CCACHE AND NOT CMAKE_CXX_COMPILER_LAUNCHER AND NOT CMAKE_C_COMPILER_LAUNCHER)
find_program(CCACHE_PATH ccache)
@@ -426,7 +451,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
endif()
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
@@ -439,7 +464,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libLake_shared.dll.a -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
endif()
@@ -454,7 +479,7 @@ if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND NOT(${CMAKE_SYSTEM_NAME} MATC
string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic")
# hide all other symbols
string(APPEND CMAKE_CXX_FLAGS " -fvisibility=hidden -fvisibility-inlines-hidden")
string(APPEND LEANC_EXTRA_FLAGS " -fvisibility=hidden")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fvisibility=hidden")
endif()
# On Windows, add bcrypt for random number generation
@@ -480,7 +505,7 @@ endif()
# Git HASH
if(USE_GITHASH)
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
get_git_head_revision(GIT_REFSPEC GIT_SHA1 ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
if(${GIT_SHA1} MATCHES "GITDIR-NOTFOUND")
message(STATUS "Failed to read git_sha1")
set(GIT_SHA1 "")
@@ -519,9 +544,10 @@ include_directories(${CMAKE_BINARY_DIR}/include) # config.h etc., "public" head
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
string(APPEND LEANC_OPTS " ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
# Do embed flag for finding system libraries in dev builds
# Do embed flag for finding system headers and libraries in dev builds
if(CMAKE_OSX_SYSROOT AND NOT LEAN_STANDALONE)
string(APPEND LEANC_EXTRA_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
string(APPEND LEANC_EXTRA_CC_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
endif()
add_subdirectory(initialize)
@@ -593,7 +619,7 @@ else()
OUTPUT_NAME leancpp)
endif()
if((${STAGE} GREATER 0) AND CADICAL)
if((${STAGE} GREATER 0) AND CADICAL AND INSTALL_CADICAL)
add_custom_target(copy-cadical
COMMAND cmake -E copy_if_different "${CADICAL}" "${CMAKE_BINARY_DIR}/bin/cadical${CMAKE_EXECUTABLE_SUFFIX}")
add_dependencies(leancpp copy-cadical)
@@ -715,7 +741,7 @@ file(COPY ${LEAN_SOURCE_DIR}/bin/leanmake DESTINATION ${CMAKE_BINARY_DIR}/bin)
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/" USE_SOURCE_PERMISSIONS DESTINATION bin)
if (${STAGE} GREATER 0 AND CADICAL)
if (${STAGE} GREATER 0 AND CADICAL AND INSTALL_CADICAL)
install(PROGRAMS "${CADICAL}" DESTINATION bin)
endif()

View File

@@ -36,3 +36,4 @@ import Init.Omega
import Init.MacroTrace
import Init.Grind
import Init.While
import Init.Syntax

View File

@@ -8,6 +8,42 @@ import Init.Core
universe u v w
/--
A `ForIn'` instance, which handles `for h : x in c do`,
can also handle `for x in x do` by ignoring `h`, and so provides a `ForIn` instance.
Note that this instance will cause a potentially non-defeq duplication if both `ForIn` and `ForIn'`
instances are provided for the same type.
-/
-- We set the priority to 500 so it is below the default,
-- but still above the low priority instance from `Stream`.
instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α where
forIn x b f := forIn' x b fun a _ => f a
@[simp] theorem forIn'_eq_forIn [d : Membership α ρ] [ForIn' m ρ α d] {β} [Monad m] (x : ρ) (b : β)
(f : (a : α) a x β m (ForInStep β)) (g : (a : α) β m (ForInStep β))
(h : a m b, f a m b = g a b) :
forIn' x b f = forIn x b g := by
simp [instForInOfForIn']
congr
apply funext
intro a
apply funext
intro m
apply funext
intro b
simp [h]
rfl
/-- Extract the value from a `ForInStep`, ignoring whether it is `done` or `yield`. -/
def ForInStep.value (x : ForInStep α) : α :=
match x with
| ForInStep.done b => b
| ForInStep.yield b => b
@[simp] theorem ForInStep.value_done (b : β) : (ForInStep.done b).value = b := rfl
@[simp] theorem ForInStep.value_yield (b : β) : (ForInStep.yield b).value = b := rfl
@[reducible]
def Functor.mapRev {f : Type u Type v} [Functor f] {α β : Type u} : f α (α β) f β :=
fun a f => f <$> a

View File

@@ -7,6 +7,7 @@ prelude
import Init.Control.Lawful.Basic
import Init.Control.Except
import Init.Control.StateRef
import Init.Ext
open Function
@@ -14,7 +15,7 @@ open Function
namespace ExceptT
theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
@[ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
simp [run] at h
assumption
@@ -105,7 +106,7 @@ instance : LawfulFunctor (Except ε) := inferInstance
namespace ReaderT
theorem ext {x y : ReaderT ρ m α} (h : ctx, x.run ctx = y.run ctx) : x = y := by
@[ext] theorem ext {x y : ReaderT ρ m α} (h : ctx, x.run ctx = y.run ctx) : x = y := by
simp [run] at h
exact funext h
@@ -167,7 +168,7 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
namespace StateT
theorem ext {x y : StateT σ m α} (h : s, x.run s = y.run s) : x = y :=
@[ext] theorem ext {x y : StateT σ m α} (h : s, x.run s = y.run s) : x = y :=
funext h
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=

View File

@@ -6,8 +6,7 @@ Authors: Leonardo de Moura, Sebastian Ullrich
The State monad transformer using IO references.
-/
prelude
import Init.System.IO
import Init.Control.State
import Init.System.ST
def StateRefT' (ω : Type) (σ : Type) (m : Type Type) (α : Type) : Type := ReaderT (ST.Ref ω σ) m α

View File

@@ -7,6 +7,7 @@ Notation for operators defined at Prelude.lean
-/
prelude
import Init.Tactics
import Init.Meta
namespace Lean.Parser.Tactic.Conv
@@ -46,12 +47,20 @@ scoped syntax (name := withAnnotateState)
/-- `skip` does nothing. -/
syntax (name := skip) "skip" : conv
/-- Traverses into the left subterm of a binary operator.
(In general, for an `n`-ary operator, it traverses into the second to last argument.) -/
/--
Traverses into the left subterm of a binary operator.
In general, for an `n`-ary operator, it traverses into the second to last argument.
It is a synonym for `arg -2`.
-/
syntax (name := lhs) "lhs" : conv
/-- Traverses into the right subterm of a binary operator.
(In general, for an `n`-ary operator, it traverses into the last argument.) -/
/--
Traverses into the right subterm of a binary operator.
In general, for an `n`-ary operator, it traverses into the last argument.
It is a synonym for `arg -1`.
-/
syntax (name := rhs) "rhs" : conv
/-- Traverses into the function of a (unary) function application.
@@ -74,13 +83,17 @@ subgoals for all the function arguments. For example, if the target is `f x y` t
`congr` produces two subgoals, one for `x` and one for `y`. -/
syntax (name := congr) "congr" : conv
syntax argArg := "@"? "-"? num
/--
* `arg i` traverses into the `i`'th argument of the target. For example if the
target is `f a b c d` then `arg 1` traverses to `a` and `arg 3` traverses to `c`.
The index may be negative; `arg -1` traverses into the last argument,
`arg -2` into the second-to-last argument, and so on.
* `arg @i` is the same as `arg i` but it counts all arguments instead of just the
explicit arguments.
* `arg 0` traverses into the function. If the target is `f a b c d`, `arg 0` traverses into `f`. -/
syntax (name := arg) "arg " "@"? num : conv
syntax (name := arg) "arg " argArg : conv
/-- `ext x` traverses into a binder (a `fun x => e` or `∀ x, e` expression)
to target `e`, introducing name `x` in the process. -/
@@ -130,11 +143,11 @@ For example, if we are searching for `f _` in `f (f a) = f b`:
syntax (name := pattern) "pattern " (occs)? term : conv
/-- `rw [thm]` rewrites the target using `thm`. See the `rw` tactic for more information. -/
syntax (name := rewrite) "rewrite" (config)? rwRuleSeq : conv
syntax (name := rewrite) "rewrite" optConfig rwRuleSeq : conv
/-- `simp [thm]` performs simplification using `thm` and marked `@[simp]` lemmas.
See the `simp` tactic for more information. -/
syntax (name := simp) "simp" (config)? (discharger)? (&" only")?
syntax (name := simp) "simp" optConfig (discharger)? (&" only")?
(" [" withoutPosition((simpStar <|> simpErase <|> simpLemma),*) "]")? : conv
/--
@@ -151,7 +164,7 @@ example (a : Nat): (0 + 0) = a - a := by
rw [← Nat.sub_self a]
```
-/
syntax (name := dsimp) "dsimp" (config)? (discharger)? (&" only")?
syntax (name := dsimp) "dsimp" optConfig (discharger)? (&" only")?
(" [" withoutPosition((simpErase <|> simpLemma),*) "]")? : conv
/-- `simp_match` simplifies match expressions. For example,
@@ -247,12 +260,12 @@ macro (name := failIfSuccess) tk:"fail_if_success " s:convSeq : conv =>
/-- `rw [rules]` applies the given list of rewrite rules to the target.
See the `rw` tactic for more information. -/
macro "rw" c:(config)? s:rwRuleSeq : conv => `(conv| rewrite $[$c]? $s)
macro "rw" c:optConfig s:rwRuleSeq : conv => `(conv| rewrite $c:optConfig $s)
/-- `erw [rules]` is a shorthand for `rw (config := { transparency := .default }) [rules]`.
/-- `erw [rules]` is a shorthand for `rw (transparency := .default) [rules]`.
This does rewriting up to unfolding of regular definitions (by comparison to regular `rw`
which only unfolds `@[reducible]` definitions). -/
macro "erw" s:rwRuleSeq : conv => `(conv| rw (config := { transparency := .default }) $s)
macro "erw" c:optConfig s:rwRuleSeq : conv => `(conv| rw $[$(getConfigItems c)]* (transparency := .default) $s:rwRuleSeq)
/-- `args` traverses into all arguments. Synonym for `congr`. -/
macro "args" : conv => `(conv| congr)
@@ -263,7 +276,7 @@ macro "right" : conv => `(conv| rhs)
/-- `intro` traverses into binders. Synonym for `ext`. -/
macro "intro" xs:(ppSpace colGt ident)* : conv => `(conv| ext $xs*)
syntax enterArg := ident <|> ("@"? num)
syntax enterArg := ident <|> argArg
/-- `enter [arg, ...]` is a compact way to describe a path to a subterm.
It is a shorthand for other conv tactics as follows:
@@ -272,12 +285,7 @@ It is a shorthand for other conv tactics as follows:
* `enter [x]` (where `x` is an identifier) is equivalent to `ext x`.
For example, given the target `f (g a (fun x => x b))`, `enter [1, 2, x, 1]`
will traverse to the subterm `b`. -/
syntax "enter" " [" withoutPosition(enterArg,+) "]" : conv
macro_rules
| `(conv| enter [$i:num]) => `(conv| arg $i)
| `(conv| enter [@$i]) => `(conv| arg @$i)
| `(conv| enter [$id:ident]) => `(conv| ext $id)
| `(conv| enter [$arg, $args,*]) => `(conv| (enter [$arg]; enter [$args,*]))
syntax (name := enter) "enter" " [" withoutPosition(enterArg,+) "]" : conv
/-- The `apply thm` conv tactic is the same as `apply thm` the tactic.
There are no restrictions on `thm`, but strange results may occur if `thm`

View File

@@ -324,7 +324,6 @@ class ForIn' (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)
export ForIn' (forIn')
/--
Auxiliary type used to compile `do` notation. It is used when compiling a do block
nested inside a combinator like `tryCatch`. It encodes the possible ways the
@@ -862,16 +861,21 @@ theorem Exists.elim {α : Sort u} {p : α → Prop} {b : Prop}
/-! # Decidable -/
theorem decide_true_eq_true (h : Decidable True) : @decide True h = true :=
@[simp] theorem decide_true (h : Decidable True) : @decide True h = true :=
match h with
| isTrue _ => rfl
| isFalse h => False.elim <| h
theorem decide_false_eq_false (h : Decidable False) : @decide False h = false :=
@[simp] theorem decide_false (h : Decidable False) : @decide False h = false :=
match h with
| isFalse _ => rfl
| isTrue h => False.elim h
set_option linter.missingDocs false in
@[deprecated decide_true (since := "2024-11-05")] abbrev decide_true_eq_true := decide_true
set_option linter.missingDocs false in
@[deprecated decide_false (since := "2024-11-05")] abbrev decide_false_eq_false := decide_false
/-- Similar to `decide`, but uses an explicit instance -/
@[inline] def toBoolUsing {p : Prop} (d : Decidable p) : Bool :=
decide (h := d)
@@ -1918,12 +1922,12 @@ represents an element of `Squash α` the same as `α` itself
`Squash.lift` will extract a value in any subsingleton `β` from a function on `α`,
while `Nonempty.rec` can only do the same when `β` is a proposition.
-/
def Squash (α : Type u) := Quot (fun (_ _ : α) => True)
def Squash (α : Sort u) := Quot (fun (_ _ : α) => True)
/-- The canonical quotient map into `Squash α`. -/
def Squash.mk {α : Type u} (x : α) : Squash α := Quot.mk _ x
def Squash.mk {α : Sort u} (x : α) : Squash α := Quot.mk _ x
theorem Squash.ind {α : Type u} {motive : Squash α Prop} (h : (a : α), motive (Squash.mk a)) : (q : Squash α), motive q :=
theorem Squash.ind {α : Sort u} {motive : Squash α Prop} (h : (a : α), motive (Squash.mk a)) : (q : Squash α), motive q :=
Quot.ind h
/-- If `β` is a subsingleton, then a function `α → β` lifts to `Squash α → β`. -/

View File

@@ -19,7 +19,9 @@ import Init.Data.ByteArray
import Init.Data.FloatArray
import Init.Data.Fin
import Init.Data.UInt
import Init.Data.SInt
import Init.Data.Float
import Init.Data.Float32
import Init.Data.Option
import Init.Data.Ord
import Init.Data.Random
@@ -41,3 +43,5 @@ import Init.Data.PLift
import Init.Data.Zero
import Init.Data.NeZero
import Init.Data.Function
import Init.Data.RArray
import Init.Data.Vector

View File

@@ -17,3 +17,8 @@ import Init.Data.Array.TakeDrop
import Init.Data.Array.Bootstrap
import Init.Data.Array.GetLit
import Init.Data.Array.MapIdx
import Init.Data.Array.Set
import Init.Data.Array.Monadic
import Init.Data.Array.FinRange
import Init.Data.Array.Perm
import Init.Data.Array.Find

View File

@@ -10,6 +10,17 @@ import Init.Data.List.Attach
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`.
We replace this at runtime with a more efficient version via the `csimp` lemma `pmap_eq_pmapImpl`.
-/
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
/--
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
`Array {x // P x}` is the same as the input `Array α`.
@@ -35,6 +46,10 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
l.toArray.attach = (l.attachWith (· l.toArray) (by simp)).toArray := by
simp [attach]
@[simp] theorem _root_.List.pmap_toArray {l : List α} {P : α Prop} {f : a, P a β} {H : a l.toArray, P a} :
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 [attachWith]
@@ -43,6 +58,387 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
l.attach.toList = l.toList.attachWith (· l) (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 [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'
@[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]
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 [pmap]
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
@[simp] theorem attachWith_empty {P : α Prop} (H : x #[], P x) : (#[] : Array α).attachWith P H = #[] := rfl
@[simp] theorem _root_.List.attachWith_mem_toArray {l : List α} :
l.attachWith (fun x => x l.toArray) (fun x h => by simpa using h) =
l.attach.map fun x, h => x, by simpa using h := by
simp only [List.attachWith, List.attach, List.map_pmap]
apply List.pmap_congr_left
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_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
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
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
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
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
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
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 [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
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]
theorem attach_map_val (l : Array α) (f : α β) : (l.attach.map fun i => f i.val) = l.map f :=
attach_map_coe _ _
@[simp]
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
cases l; simp
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 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 _ _ _
@[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
@[simp]
theorem mem_attach (l : Array α) : x, x l.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
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
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
@[simp]
theorem size_attach {L : Array α} : L.attach.size = L.size := by
cases L; simp
@[simp]
theorem size_attachWith {p : α Prop} {l : Array α} {H} : (l.attachWith p H).size = l.size := by
cases l; 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_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]
@[simp]
theorem attach_eq_empty_iff {l : Array α} : l.attach = #[] l = #[] := by
cases l; simp
theorem attach_ne_empty_iff {l : Array α} : l.attach #[] l #[] := by
cases l; 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_ne_empty_iff {l : Array α} {P : α Prop} {H : a l, P a} :
l.attachWith P H #[] l #[] := by
cases l; 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
@[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
@[simp]
theorem getElem?_attachWith {xs : Array α} {i : Nat} {P : α Prop} {H : a xs, P a} :
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
getElem?_pmap ..
@[simp]
theorem getElem?_attach {xs : Array α} {i : Nat} :
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
getElem?_attachWith
@[simp]
theorem getElem_attachWith {xs : Array α} {P : α Prop} {H : a xs, P a}
{i : Nat} (h : i < (xs.attachWith P H).size) :
(xs.attachWith P H)[i] = xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h)) :=
getElem_pmap _ _ h
@[simp]
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
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
rw [pmap_eq_map_attach, 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.
This is useful when we need to use `attach` to show termination.
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
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,
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
/--
If we fold over `l.attach` with a function that ignores the membership predicate,
we get the same results as folding over `l` directly.
This is useful when we need to use `attach` to show termination.
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
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,
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
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
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?
theorem map_attachWith {l : Array α} {P : α Prop} {H : (a : α), a l 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
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
ext <;> simp
theorem attach_filterMap {l : Array α} {f : α Option β} :
(l.filterMap f).attach = l.attach.filterMap
fun x, h => (f x).pbind (fun b m => some b, mem_filterMap.mpr x, h, m) := by
cases l
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
fun x => if w : p x.1 then some x.1, mem_filter.mpr x.2, w else none := by
cases l
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
(fun a _ => H₁ a a.2) := by
cases l
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 β) (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₂ _
@[simp] theorem attach_append (xs ys : Array α) :
(xs ++ ys).attach = xs.attach.map (fun x, h => x, mem_append_left ys h) ++
ys.attach.map fun x, h => x, mem_append_right xs h := by
cases xs
cases ys
rw [attach_congr (List.append_toArray _ _)]
simp [List.attach_append, Function.comp_def]
@[simp] theorem attachWith_append {P : α Prop} {xs ys : Array α}
{H : (a : α), a xs ++ ys P a} :
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
simp [attachWith, attach_append, map_pmap, pmap_append]
@[simp] theorem pmap_reverse {P : α Prop} (f : (a : α) P a β) (xs : Array α)
(H : (a : α), a xs.reverse P a) :
xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
induction xs <;> simp_all
theorem reverse_pmap {P : α Prop} (f : (a : α) P a β) (xs : Array α)
(H : (a : α), a xs P a) :
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
rw [pmap_reverse]
@[simp] theorem attachWith_reverse {P : α Prop} {xs : Array α}
{H : (a : α), a xs.reverse P a} :
xs.reverse.attachWith P H =
(xs.attachWith P (fun a h => H a (by simpa using h))).reverse := by
cases xs
simp
theorem reverse_attachWith {P : α Prop} {xs : Array α}
{H : (a : α), a xs P a} :
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) := by
cases xs
simp
@[simp] theorem attach_reverse (xs : Array α) :
xs.reverse.attach = xs.attach.reverse.map fun x, h => x, by simpa using h := by
cases xs
rw [attach_congr (List.reverse_toArray _)]
simp
theorem reverse_attach (xs : Array α) :
xs.attach.reverse = xs.reverse.attach.map fun x, h => x, by simpa using h := by
cases xs
simp
@[simp] theorem back?_pmap {P : α Prop} (f : (a : α) P a β) (xs : Array α)
(H : (a : α), a xs P a) :
(xs.pmap f H).back? = xs.attach.back?.map fun a, m => f a (H a m) := by
cases xs
simp
@[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
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
cases xs
simp
/-! ## unattach
`Array.unattach` is the (one-sided) inverse of `Array.attach`. It is a synonym for `Array.map Subtype.val`.
@@ -83,7 +479,7 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (
@[simp] theorem unattach_attach {l : Array α} : l.attach.unattach = l := by
cases l
simp
simp only [List.attach_toArray, List.unattach_toArray, List.unattach_attachWith]
@[simp] theorem unattach_attachWith {p : α Prop} {l : Array α}
{H : a l, p a} :
@@ -91,6 +487,15 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (
cases l
simp
@[simp] theorem getElem?_unattach {p : α Prop} {l : Array { x // p x }} (i : Nat) :
l.unattach[i]? = l[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
simp [unattach]
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
/--

View File

@@ -11,7 +11,9 @@ import Init.Data.UInt.BasicAux
import Init.Data.Repr
import Init.Data.ToString.Basic
import Init.GetElem
import Init.Data.List.ToArray
import Init.Data.List.ToArrayImpl
import Init.Data.Array.Set
universe u v w
/-! ### Array literal syntax -/
@@ -25,11 +27,12 @@ variable {α : Type u}
namespace Array
@[deprecated size (since := "2024-10-13")] abbrev data := @toList
@[deprecated toList (since := "2024-10-13")] abbrev data := @toList
/-! ### Preliminary theorems -/
@[simp] theorem size_set (a : Array α) (i : Fin a.size) (v : α) : (set a i v).size = a.size :=
@[simp] theorem size_set (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
(set a i v h).size = a.size :=
List.length_set ..
@[simp] theorem size_push (a : Array α) (v : α) : (push a v).size = a.size + 1 :=
@@ -82,6 +85,27 @@ theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := rfl
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
-- NB: This is defined as a structure rather than a plain def so that a lemma
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
structure Mem (as : Array α) (a : α) : Prop where
val : a as.toList
instance : Membership α (Array α) where
mem := Mem
theorem mem_def {a : α} {as : Array α} : a as a as.toList :=
fun | .mk h => h, Array.Mem.mk
@[simp] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
simp [mem_def]
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] l := by
rw [Array.mem_def, getElem_toList]
apply List.getElem_mem
end Array
namespace List
@@ -125,7 +149,7 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
`fset` may be slightly slower than `uset`. -/
@[extern "lean_array_uset"]
def uset (a : Array α) (i : USize) (v : α) (h : i.toNat < a.size) : Array α :=
a.set i.toNat, h v
a.set i.toNat v h
@[extern "lean_array_pop"]
def pop (a : Array α) : Array α where
@@ -147,14 +171,15 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_fswap"]
def swap (a : Array α) (i j : @& Fin a.size) : Array α :=
let v₁ := a.get i
let v₂ := a.get j
def swap (a : Array α) (i j : @& Nat) (hi : i < a.size := by get_elem_tactic) (hj : j < a.size := by get_elem_tactic) : Array α :=
let v₁ := a[i]
let v₂ := a[j]
let a' := a.set i v₂
a'.set (size_set a i v₂ j) v₁
a'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set a i v₂ _).symm)
@[simp] theorem size_swap (a : Array α) (i j : Fin a.size) : (a.swap i j).size = a.size := by
show ((a.set i (a.get j)).set (size_set a i _ j) (a.get i)).size = a.size
@[simp] theorem size_swap (a : Array α) (i j : Nat) {hi hj} : (a.swap i j hi hj).size = a.size := by
show ((a.set i a[j]).set j a[i]
(Nat.lt_of_lt_of_eq hj (size_set a i a[j] _).symm)).size = a.size
rw [size_set, size_set]
/--
@@ -164,12 +189,14 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_swap"]
def swap! (a : Array α) (i j : @& Nat) : Array α :=
def swapIfInBounds (a : Array α) (i j : @& Nat) : Array α :=
if h₁ : i < a.size then
if h₂ : j < a.size then swap a i, h₁ j, h₂
if h₂ : j < a.size then swap a i j
else a
else a
@[deprecated swapIfInBounds (since := "2024-11-24")] abbrev swap! := @swapIfInBounds
/-! ### GetElem instance for `USize`, backed by `uget` -/
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
@@ -214,60 +241,63 @@ def ofFn {n} (f : Fin n → α) : Array α := go 0 (mkEmpty n) where
/-- The array `#[0, 1, ..., n - 1]`. -/
def range (n : Nat) : Array Nat :=
n.fold (flip Array.push) (mkEmpty n)
ofFn fun (i : Fin n) => i
def singleton (v : α) : Array α :=
mkArray 1 v
def back [Inhabited α] (a : Array α) : α :=
a.get! (a.size - 1)
def back! [Inhabited α] (a : Array α) : α :=
a[a.size - 1]!
@[deprecated back! (since := "2024-10-31")] abbrev back := @back!
def get? (a : Array α) (i : Nat) : Option α :=
if h : i < a.size then some a[i] else none
def back? (a : Array α) : Option α :=
a.get? (a.size - 1)
a[a.size - 1]?
@[inline] def swapAt (a : Array α) (i : Fin a.size) (v : α) : α × Array α :=
let e := a.get i
@[inline] def swapAt (a : Array α) (i : Nat) (v : α) (hi : i < a.size := by get_elem_tactic) : α × Array α :=
let e := a[i]
let a := a.set i v
(e, a)
@[inline]
def swapAt! (a : Array α) (i : Nat) (v : α) : α × Array α :=
if h : i < a.size then
swapAt a i, h v
swapAt a i v
else
have : Inhabited (α × Array α) := (v, a)
panic! ("index " ++ toString i ++ " out of bounds")
def shrink (a : Array α) (n : Nat) : Array α :=
/-- `take a n` returns the first `n` elements of `a`. -/
def take (a : Array α) (n : Nat) : Array α :=
let rec loop
| 0, a => a
| n+1, a => loop n a.pop
loop (a.size - n) a
@[deprecated take (since := "2024-10-22")] abbrev shrink := @take
@[inline]
unsafe def modifyMUnsafe [Monad m] (a : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < a.size then
let idx : Fin a.size := i, h
let v := a.get idx
let v := a[i]
-- Replace a[i] by `box(0)`. This ensures that `v` remains unshared if possible.
-- Note: we assume that arrays have a uniform representation irrespective
-- of the element type, and that it is valid to store `box(0)` in any array.
let a' := a.set idx (unsafeCast ())
let a' := a.set i (unsafeCast ())
let v f v
pure <| a'.set (size_set a .. idx) v
pure <| a'.set i v (Nat.lt_of_lt_of_eq h (size_set a ..).symm)
else
pure a
@[implemented_by modifyMUnsafe]
def modifyM [Monad m] (a : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < a.size then
let idx := i, h
let v := a.get idx
let v := a[i]
let v f v
pure <| a.set idx v
pure <| a.set i v
else
pure a
@@ -283,21 +313,21 @@ def modifyOp (self : Array α) (idx : Nat) (f : αα) : Array α :=
We claim this unsafe implementation is correct because an array cannot have more than `usizeSz` elements in our runtime.
This kind of low level trick can be removed with a little bit of compiler support. For example, if the compiler simplifies `as.size < usizeSz` to true. -/
@[inline] unsafe def forInUnsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (b : β) (f : α β m (ForInStep β)) : m β :=
@[inline] unsafe def forIn'Unsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) a as β m (ForInStep β)) : m β :=
let sz := as.usize
let rec @[specialize] loop (i : USize) (b : β) : m β := do
if i < sz then
let a := as.uget i lcProof
match ( f a b) with
match ( f a lcProof b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop (i+1) b
else
pure b
loop 0 b
/-- Reference implementation for `forIn` -/
@[implemented_by Array.forInUnsafe]
protected def forIn {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (b : β) (f : α β m (ForInStep β)) : m β :=
/-- Reference implementation for `forIn'` -/
@[implemented_by Array.forIn'Unsafe]
protected def forIn' {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) a as β m (ForInStep β)) : m β :=
let rec loop (i : Nat) (h : i as.size) (b : β) : m β := do
match i, h with
| 0, _ => pure b
@@ -305,15 +335,17 @@ protected def forIn {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
match ( f as[as.size - 1 - i] b) with
match ( f as[as.size - 1 - i] (getElem_mem this) b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
instance : ForIn m (Array α) α where
forIn := Array.forIn
instance : ForIn' m (Array α) α inferInstance where
forIn' := Array.forIn'
/-- See comment at `forInUnsafe` -/
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
/-- See comment at `forIn'Unsafe` -/
@[inline]
unsafe def foldlMUnsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : β α m β) (init : β) (as : Array α) (start := 0) (stop := as.size) : m β :=
let rec @[specialize] fold (i : USize) (stop : USize) (b : β) : m β := do
@@ -348,7 +380,7 @@ def foldlM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β
else
fold as.size (Nat.le_refl _)
/-- See comment at `forInUnsafe` -/
/-- See comment at `forIn'Unsafe` -/
@[inline]
unsafe def foldrMUnsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α β m β) (init : β) (as : Array α) (start := as.size) (stop := 0) : m β :=
let rec @[specialize] fold (i : USize) (stop : USize) (b : β) : m β := do
@@ -387,7 +419,7 @@ def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
else
pure init
/-- See comment at `forInUnsafe` -/
/-- See comment at `forIn'Unsafe` -/
@[inline]
unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β) :=
let sz := as.usize
@@ -418,6 +450,8 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
decreasing_by simp_wf; decreasing_trivial_pre_omega
map 0 (mkEmpty as.size)
@[deprecated mapM (since := "2024-11-11")] abbrev sequenceMap := @mapM
/-- Variant of `mapIdxM` which receives the index as a `Fin as.size`. -/
@[inline]
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m]
@@ -430,30 +464,34 @@ def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
rw [ inv, Nat.add_assoc, Nat.add_comm 1 j, Nat.add_comm]
apply Nat.le_add_right
have : i + (j + 1) = as.size := by rw [ inv, Nat.add_comm j 1, Nat.add_assoc]
map i (j+1) this (bs.push ( f j, j_lt (as.get j, j_lt)))
map i (j+1) this (bs.push ( f j, j_lt (as.get j j_lt)))
map as.size 0 rfl (mkEmpty as.size)
@[inline]
def mapIdxM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (f : Nat α m β) : m (Array β) :=
def mapIdxM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : Nat α m β) (as : Array α) : m (Array β) :=
as.mapFinIdxM fun i a => f i a
@[inline]
def findSomeM? {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (f : α m (Option β)) : m (Option β) := do
def findSomeM? {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m (Option β)) (as : Array α) : m (Option β) := do
for a in as do
match ( f a) with
| some b => return b
| _ => pure
return none
/--
Note that the universe level is contrained to `Type` here,
to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
-/
@[inline]
def findM? {α : Type} {m : Type Type} [Monad m] (as : Array α) (p : α m Bool) : m (Option α) := do
def findM? {α : Type} {m : Type Type} [Monad m] (p : α m Bool) (as : Array α) : m (Option α) := do
for a in as do
if ( p a) then
return a
return none
@[inline]
def findIdxM? [Monad m] (as : Array α) (p : α m Bool) : m (Option Nat) := do
def findIdxM? [Monad m] (p : α m Bool) (as : Array α) : m (Option Nat) := do
let mut i := 0
for a in as do
if ( p a) then
@@ -505,7 +543,7 @@ def allM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as :
return !( as.anyM (start := start) (stop := stop) fun v => return !( p v))
@[inline]
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (f : α m (Option β)) : m (Option β) :=
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m (Option β)) (as : Array α) : m (Option β) :=
let rec @[specialize] find : (i : Nat) i as.size m (Option β)
| 0, _ => pure none
| i+1, h => do
@@ -519,7 +557,7 @@ def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
find as.size (Nat.le_refl _)
@[inline]
def findRevM? {α : Type} {m : Type Type w} [Monad m] (as : Array α) (p : α m Bool) : m (Option α) :=
def findRevM? {α : Type} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) : m (Option α) :=
as.findSomeRevM? fun a => return if ( p a) then some a else none
@[inline]
@@ -548,7 +586,7 @@ def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : Fin as.size →
Id.run <| as.mapFinIdxM f
@[inline]
def mapIdx {α : Type u} {β : Type v} (as : Array α) (f : Nat α β) : Array β :=
def mapIdx {α : Type u} {β : Type v} (f : Nat α β) (as : Array α) : Array β :=
Id.run <| as.mapIdxM f
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
@@ -556,29 +594,33 @@ def zipWithIndex (arr : Array α) : Array (α × Nat) :=
arr.mapIdx fun i a => (a, i)
@[inline]
def find? {α : Type} (as : Array α) (p : α Bool) : Option α :=
Id.run <| as.findM? p
def find? {α : Type u} (p : α Bool) (as : Array α) : Option α :=
Id.run do
for a in as do
if p a then
return a
return none
@[inline]
def findSome? {α : Type u} {β : Type v} (as : Array α) (f : α Option β) : Option β :=
def findSome? {α : Type u} {β : Type v} (f : α Option β) (as : Array α) : Option β :=
Id.run <| as.findSomeM? f
@[inline]
def findSome! {α : Type u} {β : Type v} [Inhabited β] (a : Array α) (f : α Option β) : β :=
match findSome? a f with
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α Option β) (a : Array α) : β :=
match a.findSome? f with
| some b => b
| none => panic! "failed to find element"
@[inline]
def findSomeRev? {α : Type u} {β : Type v} (as : Array α) (f : α Option β) : Option β :=
def findSomeRev? {α : Type u} {β : Type v} (f : α Option β) (as : Array α) : Option β :=
Id.run <| as.findSomeRevM? f
@[inline]
def findRev? {α : Type} (as : Array α) (p : α Bool) : Option α :=
def findRev? {α : Type} (p : α Bool) (as : Array α) : Option α :=
Id.run <| as.findRevM? p
@[inline]
def findIdx? {α : Type u} (as : Array α) (p : α Bool) : Option Nat :=
def findIdx? {α : Type u} (p : α Bool) (as : Array α) : Option Nat :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
loop (j : Nat) :=
if h : j < as.size then
@@ -587,14 +629,20 @@ def findIdx? {α : Type u} (as : Array α) (p : α → Bool) : Option Nat :=
decreasing_by simp_wf; decreasing_trivial_pre_omega
loop 0
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
a.findIdx? fun a => a == v
@[inline]
def findFinIdx? {α : Type u} (p : α Bool) (as : Array α) : Option (Fin as.size) :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
loop (j : Nat) :=
if h : j < as.size then
if p as[j] then some j, h else loop (j + 1)
else none
decreasing_by simp_wf; decreasing_trivial_pre_omega
loop 0
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) :=
if h : i < a.size then
let idx : Fin a.size := i, h;
if a.get idx == v then some idx
if a[i] == v then some i, h
else indexOfAux a v (i+1)
else none
decreasing_by simp_wf; decreasing_trivial_pre_omega
@@ -602,6 +650,10 @@ decreasing_by simp_wf; decreasing_trivial_pre_omega
def indexOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
indexOfAux a v 0
@[deprecated indexOf? (since := "2024-11-20")]
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
a.findIdx? fun a => a == v
@[inline]
def any (as : Array α) (p : α Bool) (start := 0) (stop := as.size) : Bool :=
Id.run <| as.anyM p start stop
@@ -642,7 +694,7 @@ instance : HAppend (Array α) (List α) (Array α) := ⟨Array.appendList⟩
def flatMapM [Monad m] (f : α m (Array β)) (as : Array α) : m (Array β) :=
as.foldlM (init := empty) fun bs a => do return bs ++ ( f a)
@[deprecated concatMapM (since := "2024-10-16")] abbrev concatMapM := @flatMapM
@[deprecated flatMapM (since := "2024-10-16")] abbrev concatMapM := @flatMapM
@[inline]
def flatMap (f : α Array β) (as : Array α) : Array β :=
@@ -710,7 +762,7 @@ where
loop (as : Array α) (i : Nat) (j : Fin as.size) :=
if h : i < j then
have := termination h
let as := as.swap i, Nat.lt_trans h j.2 j
let as := as.swap i j (Nat.lt_trans h j.2)
have : j-1 < as.size := by rw [size_swap]; exact Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
loop as (i+1) j-1, this
else
@@ -719,7 +771,7 @@ where
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def popWhile (p : α Bool) (as : Array α) : Array α :=
if h : as.size > 0 then
if p (as.get as.size - 1, Nat.sub_lt h (by decide)) then
if p (as[as.size - 1]'(Nat.sub_lt h (by decide))) then
popWhile p as.pop
else
as
@@ -731,7 +783,7 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
go (i : Nat) (r : Array α) : Array α :=
if h : i < as.size then
let a := as.get i, h
let a := as[i]
if p a then
go (i+1) (r.push a)
else
@@ -741,49 +793,63 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
decreasing_by simp_wf; decreasing_trivial_pre_omega
go 0 #[]
/-- Remove the element at a given index from an array without bounds checks, using a `Fin` index.
/--
Remove the element at a given index from an array without a runtime bounds checks,
using a `Nat` index and a tactic-provided bound.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def feraseIdx (a : Array α) (i : Fin a.size) : Array α :=
if h : i.val + 1 < a.size then
let a' := a.swap i.val + 1, h i
let i' : Fin a'.size := i.val + 1, by simp [a', h]
a'.feraseIdx i'
def eraseIdx (a : Array α) (i : Nat) (h : i < a.size := by get_elem_tactic) : Array α :=
if h' : i + 1 < a.size then
let a' := a.swap (i + 1) i
a'.eraseIdx (i + 1) (by simp [a', h'])
else
a.pop
termination_by a.size - i.val
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ i.isLt
termination_by a.size - i
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
-- This is required in `Lean.Data.PersistentHashMap`.
@[simp] theorem size_feraseIdx (a : Array α) (i : Fin a.size) : (a.feraseIdx i).size = a.size - 1 := by
induction a, i using Array.feraseIdx.induct with
| @case1 a i h a' _ ih =>
unfold feraseIdx
simp [h, a', ih]
| case2 a i h =>
unfold feraseIdx
simp [h]
@[simp] theorem size_eraseIdx (a : Array α) (i : Nat) (h) : (a.eraseIdx i h).size = a.size - 1 := by
induction a, i, h using Array.eraseIdx.induct with
| @case1 a i h h' a' ih =>
unfold eraseIdx
simp [h', a', ih]
| case2 a i h h' =>
unfold eraseIdx
simp [h']
/-- Remove the element at a given index from an array, or do nothing if the index is out of bounds.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
def eraseIdx (a : Array α) (i : Nat) : Array α :=
if h : i < a.size then a.feraseIdx i, h else a
def eraseIdxIfInBounds (a : Array α) (i : Nat) : Array α :=
if h : i < a.size then a.eraseIdx i h else a
/-- Remove the element at a given index from an array, or panic if the index is out of bounds.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`. -/
def eraseIdx! (a : Array α) (i : Nat) : Array α :=
if h : i < a.size then a.eraseIdx i h else panic! "invalid index"
def erase [BEq α] (as : Array α) (a : α) : Array α :=
match as.indexOf? a with
| none => as
| some i => as.feraseIdx i
| some i => as.eraseIdx i
/-- Erase the first element that satisfies the predicate `p`. -/
def eraseP (as : Array α) (p : α Bool) : Array α :=
match as.findIdx? p with
| none => as
| some i => as.eraseIdxIfInBounds i
/-- Insert element `a` at position `i`. -/
@[inline] def insertAt (as : Array α) (i : Fin (as.size + 1)) (a : α) : Array α :=
@[inline] def insertIdx (as : Array α) (i : Nat) (a : α) (_ : i as.size := by get_elem_tactic) : Array α :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
loop (as : Array α) (j : Fin as.size) :=
if i.1 < j then
let j' := j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
if i < j then
let j' : Fin as.size := j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
let as := as.swap j' j
loop as j', by rw [size_swap]; exact j'.2
else
@@ -793,12 +859,23 @@ def erase [BEq α] (as : Array α) (a : α) : Array α :=
let as := as.push a
loop as j, size_push .. j.lt_succ_self
@[deprecated insertIdx (since := "2024-11-20")] abbrev insertAt := @insertIdx
/-- Insert element `a` at position `i`. Panics if `i` is not `i ≤ as.size`. -/
def insertAt! (as : Array α) (i : Nat) (a : α) : Array α :=
def insertIdx! (as : Array α) (i : Nat) (a : α) : Array α :=
if h : i as.size then
insertAt as i, Nat.lt_succ_of_le h a
insertIdx as i a
else panic! "invalid index"
@[deprecated insertIdx! (since := "2024-11-20")] abbrev insertAt! := @insertIdx!
/-- Insert element `a` at position `i`, or do nothing if `as.size < i`. -/
def insertIdxIfInBounds (as : Array α) (i : Nat) (a : α) : Array α :=
if h : i as.size then
insertIdx as i a
else
as
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size bs.size) (i : Nat) : Bool :=
if h : i < as.size then
@@ -822,12 +899,12 @@ def isPrefixOf [BEq α] (as bs : Array α) : Bool :=
false
@[semireducible, specialize] -- This is otherwise irreducible because it uses well-founded recursion.
def zipWithAux (f : α β γ) (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) : Array γ :=
def zipWithAux (as : Array α) (bs : Array β) (f : α β γ) (i : Nat) (cs : Array γ) : Array γ :=
if h : i < as.size then
let a := as[i]
if h : i < bs.size then
let b := bs[i]
zipWithAux f as bs (i+1) <| cs.push <| f a b
zipWithAux as bs f (i+1) <| cs.push <| f a b
else
cs
else
@@ -835,14 +912,27 @@ def zipWithAux (f : α → β → γ) (as : Array α) (bs : Array β) (i : Nat)
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[inline] def zipWith (as : Array α) (bs : Array β) (f : α β γ) : Array γ :=
zipWithAux f as bs 0 #[]
zipWithAux as bs f 0 #[]
def zip (as : Array α) (bs : Array β) : Array (α × β) :=
zipWith as bs Prod.mk
def zipWithAll (as : Array α) (bs : Array β) (f : Option α Option β γ) : Array γ :=
go as bs 0 #[]
where go (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) :=
if i < max as.size bs.size then
let a := as[i]?
let b := bs[i]?
go as bs (i+1) (cs.push (f a b))
else
cs
termination_by max as.size bs.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
def unzip (as : Array (α × β)) : Array α × Array β :=
as.foldl (init := (#[], #[])) fun (as, bs) (a, b) => (as.push a, bs.push b)
@[deprecated partition (since := "2024-11-06")]
def split (as : Array α) (p : α Bool) : Array α × Array α :=
as.foldl (init := (#[], #[])) fun (as, bs) a =>
if p a then (as.push a, bs) else (as, bs.push a)

View File

@@ -60,7 +60,7 @@ where
if ptrEq a b then
go (i+1) as
else
go (i+1) (as.set i, h b)
go (i+1) (as.set i b h)
else
return as

View File

@@ -5,59 +5,64 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic
import Init.Omega
universe u v
-- TODO: CLEANUP
namespace Array
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
-- TODO: remove `partial` using well-founded recursion
@[specialize] partial def binSearchAux {α : Type u} {β : Type v} [Inhabited β] (lt : α α Bool) (found : Option α β) (as : Array α) (k : α) : Nat Nat β
| lo, hi =>
if lo <= hi then
let _ := Inhabited.mk k
let m := (lo + hi)/2
let a := as.get! m
if lt a k then binSearchAux lt found as k (m+1) hi
else if lt k a then
if m == 0 then found none
else binSearchAux lt found as k lo (m-1)
else found (some a)
else found none
@[specialize] def binSearchAux {α : Type u} {β : Type v} (lt : α α Bool) (found : Option α β) (as : Array α) (k : α) :
(lo : Fin (as.size + 1)) (hi : Fin as.size) (lo.1 hi.1) β
| lo, hi, h =>
let m := (lo.1 + hi.1)/2
let a := as[m]
if lt a k then
if h' : m + 1 hi.1 then
binSearchAux lt found as k m+1, by omega hi h'
else found none
else if lt k a then
if h' : m = 0 m - 1 < lo.1 then found none
else binSearchAux lt found as k lo m-1, by omega (by simp; omega)
else found (some a)
termination_by lo hi => hi.1 - lo.1
@[inline] def binSearch {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo := 0) (hi := as.size - 1) : Option α :=
if lo < as.size then
if h : lo < as.size then
let hi := if hi < as.size then hi else as.size - 1
binSearchAux lt id as k lo hi
if w : lo hi then
binSearchAux lt id as k lo, by omega hi, by simp [hi]; split <;> omega (by simp [hi]; omega)
else
none
else
none
@[inline] def binSearchContains {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo := 0) (hi := as.size - 1) : Bool :=
if lo < as.size then
if h : lo < as.size then
let hi := if hi < as.size then hi else as.size - 1
binSearchAux lt Option.isSome as k lo hi
if w : lo hi then
binSearchAux lt Option.isSome as k lo, by omega hi, by simp [hi]; split <;> omega (by simp [hi]; omega)
else
false
else
false
@[specialize] private partial def binInsertAux {α : Type u} {m : Type u Type v} [Monad m]
@[specialize] private def binInsertAux {α : Type u} {m : Type u Type v} [Monad m]
(lt : α α Bool)
(merge : α m α)
(add : Unit m α)
(as : Array α)
(k : α) : Nat Nat m (Array α)
| lo, hi =>
let _ := Inhabited.mk k
-- as[lo] < k < as[hi]
let mid := (lo + hi)/2
let midVal := as.get! mid
if lt midVal k then
if mid == lo then do let v add (); pure <| as.insertAt! (lo+1) v
else binInsertAux lt merge add as k mid hi
else if lt k midVal then
binInsertAux lt merge add as k lo mid
(k : α) : (lo : Fin as.size) (hi : Fin as.size) (lo.1 hi.1) (lt as[lo] k) m (Array α)
| lo, hi, h, w =>
let mid := (lo.1 + hi.1)/2
let midVal := as[mid]
if w₁ : lt midVal k then
if h' : mid = lo then do let v add (); pure <| as.insertIdx (lo+1) v
else binInsertAux lt merge add as k mid, by omega hi (by simp; omega) w₁
else if w₂ : lt k midVal then
have : mid lo := fun z => by simp [midVal, z] at w₁; simp_all
binInsertAux lt merge add as k lo mid, by omega (by simp; omega) w
else do
as.modifyM mid <| fun v => merge v
termination_by lo hi => hi.1 - lo.1
@[specialize] def binInsertM {α : Type u} {m : Type u Type v} [Monad m]
(lt : α α Bool)
@@ -65,13 +70,12 @@ namespace Array
(add : Unit m α)
(as : Array α)
(k : α) : m (Array α) :=
let _ := Inhabited.mk k
if as.isEmpty then do let v add (); pure <| as.push v
else if lt k (as.get! 0) then do let v add (); pure <| as.insertAt! 0 v
else if !lt (as.get! 0) k then as.modifyM 0 <| merge
else if lt as.back k then do let v add (); pure <| as.push v
else if !lt k as.back then as.modifyM (as.size - 1) <| merge
else binInsertAux lt merge add as k 0 (as.size - 1)
if h : as.size = 0 then do let v add (); pure <| as.push v
else if lt k as[0] then do let v add (); pure <| as.insertIdx 0 v
else if h' : !lt as[0] k then as.modifyM 0 <| merge
else if lt as[as.size - 1] k then do let v add (); pure <| as.push v
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')
@[inline] def binInsert {α : Type u} (lt : α α Bool) (as : Array α) (k : α) : Array α :=
Id.run <| binInsertM lt (fun _ => k) (fun _ => k) as k

View File

@@ -15,26 +15,26 @@ This file contains some theorems about `Array` and `List` needed for `Init.Data.
namespace Array
theorem foldlM_eq_foldlM_toList.aux [Monad m]
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
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_eq_foldlM_toList.aux f arr i (j+1) H]
rw (config := {occs := .pos [2]}) [ List.get_drop_eq_drop _ _ _]
simp [foldlM_toList.aux f arr 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
theorem foldlM_eq_foldlM_toList [Monad m]
@[simp] theorem foldlM_toList [Monad m]
(f : β α m β) (init : β) (arr : Array α) :
arr.foldlM f init = arr.toList.foldlM f init := by
simp [foldlM, foldlM_eq_foldlM_toList.aux]
arr.toList.foldlM f init = arr.foldlM f init := by
simp [foldlM, foldlM_toList.aux]
theorem foldl_eq_foldl_toList (f : β α β) (init : β) (arr : Array α) :
arr.foldl f init = arr.toList.foldl f init :=
List.foldl_eq_foldlM .. foldlM_eq_foldlM_toList ..
@[simp] theorem foldl_toList (f : β α β) (init : β) (arr : Array α) :
arr.toList.foldl f init = arr.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) :
@@ -51,23 +51,23 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α → β → m β) (init
match arr, this with | _, .inl rfl => rfl | arr, .inr h => ?_
simp [foldrM, h, foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
theorem foldrM_eq_foldrM_toList [Monad m]
@[simp] theorem foldrM_toList [Monad m]
(f : α β m β) (init : β) (arr : Array α) :
arr.foldrM f init = arr.toList.foldrM f init := by
arr.toList.foldrM f init = arr.foldrM f init := by
rw [foldrM_eq_reverse_foldlM_toList, List.foldlM_reverse]
theorem foldr_eq_foldr_toList (f : α β β) (init : β) (arr : Array α) :
arr.foldr f init = arr.toList.foldr f init :=
List.foldr_eq_foldrM .. foldrM_eq_foldrM_toList ..
@[simp] theorem foldr_toList (f : α β β) (init : β) (arr : Array α) :
arr.toList.foldr f init = arr.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 [push, List.concat_eq_append]
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.toList ++ l := by
simp [toListAppend, foldr_eq_foldr_toList]
simp [toListAppend, foldr_toList]
@[simp] theorem toListImpl_eq (arr : Array α) : arr.toListImpl = arr.toList := by
simp [toListImpl, foldr_eq_foldr_toList]
simp [toListImpl, foldr_toList]
@[simp] theorem pop_toList (arr : Array α) : arr.pop.toList = arr.toList.dropLast := rfl
@@ -76,9 +76,20 @@ theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α
@[simp] theorem toList_append (arr arr' : Array α) :
(arr ++ arr').toList = arr.toList ++ arr'.toList := by
rw [ append_eq_append]; unfold Array.append
rw [foldl_eq_foldl_toList]
rw [ foldl_toList]
induction arr'.toList generalizing arr <;> simp [*]
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := 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
apply ext'; simp only [toList_append, List.append_assoc]
@[simp] theorem appendList_eq_append
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
@@ -87,20 +98,44 @@ theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α
rw [ appendList_eq_append]; unfold Array.appendList
induction l generalizing arr <;> simp [*]
@[deprecated foldlM_eq_foldlM_toList (since := "2024-09-09")]
abbrev foldlM_eq_foldlM_data := @foldlM_eq_foldlM_toList
@[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
simp
@[deprecated foldl_eq_foldl_toList (since := "2024-09-09")]
abbrev foldl_eq_foldl_data := @foldl_eq_foldl_toList
@[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
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
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
simp
@[deprecated foldlM_toList (since := "2024-09-09")]
abbrev foldlM_eq_foldlM_data := @foldlM_toList
@[deprecated foldl_toList (since := "2024-09-09")]
abbrev foldl_eq_foldl_data := @foldl_toList
@[deprecated foldrM_eq_reverse_foldlM_toList (since := "2024-09-09")]
abbrev foldrM_eq_reverse_foldlM_data := @foldrM_eq_reverse_foldlM_toList
@[deprecated foldrM_eq_foldrM_toList (since := "2024-09-09")]
abbrev foldrM_eq_foldrM_data := @foldrM_eq_foldrM_toList
@[deprecated foldrM_toList (since := "2024-09-09")]
abbrev foldrM_eq_foldrM_data := @foldrM_toList
@[deprecated foldr_eq_foldr_toList (since := "2024-09-09")]
abbrev foldr_eq_foldr_data := @foldr_eq_foldr_toList
@[deprecated foldr_toList (since := "2024-09-09")]
abbrev foldr_eq_foldr_data := @foldr_toList
@[deprecated push_toList (since := "2024-09-09")]
abbrev push_data := @push_toList

View File

@@ -6,16 +6,15 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
import Init.Data.BEq
import Init.Data.Nat.Lemmas
import Init.Data.List.Nat.BEq
import Init.ByCases
namespace Array
theorem rel_of_isEqvAux
(r : α α Bool) (a b : Array α) (hsz : a.size = b.size) (i : Nat) (hi : i a.size)
{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
{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
induction i with
| zero => contradiction
| succ i ih =>
@@ -28,7 +27,7 @@ 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)
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
induction i with
| zero => simp [Array.isEqvAux]
@@ -36,18 +35,18 @@ theorem isEqvAux_of_rel (r : αα → Bool) (a b : Array α) (hsz : a.size
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 α) :
theorem rel_of_isEqv {r : α α Bool} {a b : Array α} :
Array.isEqv a b r h : a.size = b.size, (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h h')) := by
simp only [isEqv]
split <;> rename_i h
· exact fun h' => h, rel_of_isEqvAux r a b h a.size (Nat.le_refl ..) h'
· 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')) :=
rel_of_isEqv r a b, fun h, w => by
rel_of_isEqv, fun h, w => by
simp only [isEqv, h, reduceDIte]
exact isEqvAux_of_rel r a b h a.size (by simp [h]) w
exact isEqvAux_of_rel h (by simp [h]) w
theorem isEqv_eq_decide (a b : Array α) (r) :
Array.isEqv a b r =
@@ -67,7 +66,7 @@ theorem isEqv_eq_decide (a b : Array α) (r) :
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
have h, h' := rel_of_isEqv (fun x y => x = y) a b h
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) :

View File

@@ -0,0 +1,14 @@
/-
Copyright (c) 2024 François G. Dorais. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: François G. Dorais
-/
prelude
import Init.Data.List.FinRange
namespace Array
/-- `finRange n` is the array of all elements of `Fin n` in order. -/
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
end Array

View File

@@ -0,0 +1,281 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.List.Find
import Init.Data.Array.Lemmas
import Init.Data.Array.Attach
/-!
# Lemmas about `Array.findSome?`, `Array.find?`.
-/
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_isNone (l : Array α) (h : (f a).isNone) : (l.push a).findSomeRev? f = l.findSomeRev? f := by
cases l; 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]
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none x l, p x = none := by
cases l; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {l : Array α} :
(l.findSome? f).isSome x, x l (f x).isSome := by
cases l; 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
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
@[simp] theorem findSome?_guard (l : Array α) : findSome? (Option.guard fun x => p x) l = find? p l := by
cases l; 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?]
@[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 back?_filterMap (f : α Option β) (l : Array α) : (l.filterMap f).back? = l.findSomeRev? f := by
cases l; simp
@[simp] theorem back!_filterMap [Inhabited β] (f : α Option β) (l : Array α) :
(l.filterMap f).back! = (l.findSomeRev? f).getD default := by
cases l; 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
theorem findSome?_map (f : β γ) (l : Array β) : findSome? p (l.map f) = l.findSome? (p f) := by
cases l; simp [List.findSome?_map]
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 getElem?_zero_flatten (L : Array (Array α)) :
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
cases L using array_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
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,
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
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
simp [mkArray_eq_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]
-- 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?_mkArray_of_isNone (h : (f a).isNone) :
findSome? f (mkArray n a) = none := by
rw [Option.isNone_iff_eq_none] at h
simp [findSome?_mkArray, h]
/-! ### find? -/
@[simp] theorem find?_singleton (a : α) (p : α Bool) :
#[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?_cons_of_neg (l : Array α) (h : ¬p a) :
findRev? p (l.push a) = findRev? p l := by
cases l; simp [h]
@[simp] theorem find?_eq_none : find? p l = none x l, ¬ p x := by
cases l; 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
rcases xs with xs
simp only [List.find?_toArray, List.find?_eq_some_iff_append, Bool.not_eq_eq_eq_not,
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',
by simpa using h
@[simp]
theorem find?_push_eq_some {xs : Array α} :
(xs.push a).find? p = some b xs.find? p = some b (xs.find? p = none (p a a = b)) := by
cases xs; simp
@[simp] theorem find?_isSome {xs : Array α} {p : α Bool} : (xs.find? p).isSome x, x xs p x := by
cases xs; simp
theorem find?_some {xs : Array α} (h : find? p xs = some a) : p a := by
cases xs
simp at h
exact List.find?_some h
theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a xs := by
cases xs
simp at h
simpa using List.mem_of_find?_eq_some h
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h xs := by
cases xs
simp [List.get_find?_mem]
@[simp] theorem find?_filter {xs : Array α} (p q : α Bool) :
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
cases xs; simp
@[simp] theorem getElem?_zero_filter (p : α Bool) (l : Array α) :
(l.filter p)[0]? = l.find? p := by
cases l; 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 [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 [Inhabited α] (p : α Bool) (l : Array α) :
(l.filter p).back! = (l.findRev? p).get! := by
cases l; 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
cases xs; simp
@[simp] theorem find?_map (f : β α) (xs : Array β) :
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
@[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 [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
simp
/--
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
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]
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
constructor
· rintro as, ys, zs, bs, rfl, h₁, h₂
exact as.toArray.map List.toArray, ys.toArray,
zs.toArray, bs.toArray.map List.toArray, by simp, by simpa using h₁, by simpa using h₂
· rintro as, ys, zs, bs, h, h₁, h₂
replace h := congrArg (·.map Array.toList) (congrArg Array.toList h)
simp [Function.comp_def] at h
exact as.toList.map Array.toList, ys.toList,
zs.toList, bs.toList.map Array.toList, by simpa using h,
by simpa using h₁, by simpa using h₂
@[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} :
(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
simp [mkArray_eq_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]
@[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?_mkArray_of_neg (h : ¬ p a) : find? p (mkArray n a) = none := by
simp [find?_mkArray, h]
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
theorem find?_mkArray_eq_none {n : Nat} {a : α} {p : α Bool} :
(mkArray n a).find? p = none n = 0 !p a := by
simp [mkArray_eq_toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
@[simp] theorem find?_mkArray_eq_some {n : Nat} {a b : α} {p : α Bool} :
(mkArray n a).find? p = some b n 0 p a a = b := by
simp [mkArray_eq_toArray_replicate]
@[simp] theorem get_find?_mkArray (n : Nat) (a : α) (p : α Bool) (h) :
((mkArray n a).find? p).get h = a := by
simp [mkArray_eq_toArray_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
end Array

View File

@@ -41,6 +41,6 @@ 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₂) :=
rfl
go (i : Nat) (hi : i as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.get_drop_eq_drop, *]
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
end Array

View File

@@ -6,7 +6,7 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
@[inline] def Array.insertionSort (a : Array α) (lt : α α Bool) : Array α :=
@[inline] def Array.insertionSort (a : Array α) (lt : α α Bool := by exact (· < ·)) : Array α :=
traverse a 0 a.size
where
@[specialize] traverse (a : Array α) (i : Nat) (fuel : Nat) : Array α :=
@@ -23,6 +23,6 @@ where
| 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, h j', h') j' (by rw [size_swap]; assumption; done)
swapLoop (a.swap j j') j' (by rw [size_swap]; assumption; done)
else
a

File diff suppressed because it is too large Load Diff

View File

@@ -60,33 +60,53 @@ theorem mapFinIdx_spec (as : Array α) (f : Fin as.size → α → β)
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
apply List.ext_getElem <;> simp
/-! ### mapIdx -/
theorem mapIdx_induction (as : Array α) (f : Nat α β)
theorem mapIdx_induction (f : Nat α β) (as : 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 : (Array.mapIdx as f).size = as.size,
i h, p i, h ((Array.mapIdx as f)[i]) :=
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
theorem mapIdx_spec (as : Array α) (f : Nat α β)
theorem mapIdx_spec (f : Nat α β) (as : Array α)
(p : Fin as.size β Prop) (hs : i, p i (f i as[i])) :
eq : (Array.mapIdx as f).size = as.size,
i h, p i, h ((Array.mapIdx as f)[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
@[simp] theorem size_mapIdx (a : Array α) (f : Nat α β) : (a.mapIdx f).size = a.size :=
@[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 getElem_mapIdx (a : Array α) (f : Nat α β) (i : Nat)
(h : i < (mapIdx a f).size) :
(a.mapIdx f)[i] = f i (a[i]'(by simp_all)) :=
(mapIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i (by simp_all)
@[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 (a : Array α) (f : Nat α β) (i : Nat) :
(a.mapIdx f)[i]? =
a[i]?.map (f i) := by
@[simp] theorem getElem?_mapIdx (f : Nat α β) (as : Array α) (i : Nat) :
(as.mapIdx f)[i]? =
as[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
apply List.ext_getElem <;> simp
end Array
namespace List
@[simp] theorem mapFinIdx_toArray (l : List α) (f : Fin l.length α β) :
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
ext <;> simp
@[simp] theorem mapIdx_toArray (f : Nat α β) (l : List α) :
l.toArray.mapIdx f = (l.mapIdx f).toArray := by
ext <;> simp
end List

View File

@@ -10,25 +10,16 @@ import Init.Data.List.BasicAux
namespace Array
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
-- NB: This is defined as a structure rather than a plain def so that a lemma
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
structure Mem (as : Array α) (a : α) : Prop where
val : a as.toList
instance : Membership α (Array α) where
mem := Mem
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)
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf (as.get i h) < sizeOf as := by
cases as with | _ as =>
exact Nat.lt_trans (List.sizeOf_get ..) (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 _ _
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _ h
/-- This tactic, added to the `decreasing_trivial` toolbox, proves that
`sizeOf arr[i] < sizeOf arr`, which is useful for well founded recursions

View File

@@ -0,0 +1,159 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.Array.Attach
import Init.Data.List.Monadic
/-!
# Lemmas about `Array.forIn'` and `Array.forIn`.
-/
namespace Array
open Nat
/-! ## Monadic operations -/
/-! ### 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']
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
exact this []
intro k
induction l generalizing k 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`?
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`?
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`?
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`?
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`?
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`?
simp [List.foldrM_filter]
/-! ### forIn' -/
/--
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
| .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]
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`?
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 [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
simp [List.foldl_map]
/--
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
| .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']
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
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 [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
simp [List.foldl_map]
end Array

View File

@@ -0,0 +1,65 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.List.Nat.Perm
import Init.Data.Array.Lemmas
namespace Array
open List
/--
`Perm as bs` asserts that `as` and `bs` are permutations of each other.
This is a wrapper around `List.Perm`, and for now has much less API.
For more complicated verification, use `perm_iff_toList_perm` and the `List` API.
-/
def Perm (as bs : Array α) : Prop :=
as.toList ~ bs.toList
@[inherit_doc] scoped infixl:50 " ~ " => Perm
theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs as.toList ~ bs.toList := Iff.rfl
@[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
protected theorem Perm.rfl {l : List α} : l ~ l := .refl _
theorem Perm.of_eq {l₁ l₂ : Array α} (h : l₁ = l₂) : l₁ ~ l₂ := h .rfl
protected theorem Perm.symm {l₁ l₂ : Array α} (h : l₁ ~ l₂) : l₂ ~ l₁ := by
cases l₁; cases l₂
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₃
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.push (x y : α) {l₁ l₂ : Array α} (p : l₁ ~ l₂) :
(l₁.push x).push y ~ (l₂.push y).push x := by
cases l₁; cases l₂
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
simp only [swap, perm_iff_toList_perm, toList_set]
apply set_set_perm
end Array

View File

@@ -4,46 +4,46 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic
import Init.Data.Vector.Basic
import Init.Data.Ord
namespace Array
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
def qpartition (as : Array α) (lt : α α Bool) (lo hi : Nat) : Nat × Array α :=
if h : as.size = 0 then (0, as) else have : Inhabited α := as[0]'(by revert h; cases as.size <;> simp) -- TODO: remove
private def qpartition {n} (as : Vector α n) (lt : α α Bool) (lo hi : Nat)
(hlo : lo < n := by omega) (hhi : hi < n := by omega) : {n : Nat // lo n} × Vector α n :=
let mid := (lo + hi) / 2
let as := if lt (as.get! mid) (as.get! lo) then as.swap! lo mid else as
let as := if lt (as.get! hi) (as.get! lo) then as.swap! lo hi else as
let as := if lt (as.get! mid) (as.get! hi) then as.swap! mid hi else as
let pivot := as.get! hi
let rec loop (as : Array α) (i j : Nat) :=
let as := if lt as[mid] as[lo] then as.swap lo mid else as
let as := if lt as[hi] as[lo] then as.swap lo hi else as
let as := if lt as[mid] as[hi] then as.swap mid hi else as
let pivot := as[hi]
let rec loop (as : Vector α n) (i j : Nat)
(ilo : lo i := by omega) (jh : j < n := by omega) (w : i j := by omega) :=
if h : j < hi then
if lt (as.get! j) pivot then
let as := as.swap! i j
loop as (i+1) (j+1)
if lt as[j] pivot then
loop (as.swap i j) (i+1) (j+1)
else
loop as i (j+1)
else
let as := as.swap! i hi
(i, as)
termination_by hi - j
decreasing_by all_goals simp_wf; decreasing_trivial_pre_omega
(i, ilo, as.swap i hi)
loop as lo lo
@[inline] partial def qsort (as : Array α) (lt : α α Bool) (low := 0) (high := as.size - 1) : Array α :=
let rec @[specialize] sort (as : Array α) (low high : Nat) :=
if low < high then
let p := qpartition as lt low high;
-- TODO: fix `partial` support in the equation compiler, it breaks if we use `let (mid, as) := partition as lt low high`
let mid := p.1
let as := p.2
if mid >= high then as
@[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)
(hlo : lo < n := by omega) (hhi : hi < n := by omega) :=
if h₁ : lo < hi then
let mid, hmid, as := qpartition as lt lo hi
if h₂ : mid hi then
as
else
let as := sort as low mid
sort as (mid+1) high
sort (sort as lo mid) (mid+1) hi
else as
sort as low high
if h : as.size = 0 then
as
else
let low := min low (as.size - 1)
let high := min high (as.size - 1)
sort as, rfl low high |>.toArray
set_option linter.unusedVariables.funArgs false in
/--

View File

@@ -0,0 +1,41 @@
/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Mario Carneiro
-/
prelude
import Init.Tactics
/--
Set an element in an array, using a proof that the index is in bounds.
(This proof can usually be omitted, and will be synthesized automatically.)
This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_fset"]
def Array.set (a : Array α) (i : @& Nat) (v : α) (h : i < a.size := by get_elem_tactic) :
Array α where
toList := a.toList.set i v
/--
Set an element in an array, or do nothing if the index is out of bounds.
This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[inline] def Array.setIfInBounds (a : Array α) (i : Nat) (v : α) : Array α :=
dite (LT.lt i a.size) (fun h => a.set i v h) (fun _ => a)
@[deprecated Array.setIfInBounds (since := "2024-11-24")] abbrev Array.setD := @Array.setIfInBounds
/--
Set an element in an array, or panic if the index is out of bounds.
This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_set"]
def Array.set! (a : Array α) (i : @& Nat) (v : α) : Array α :=
Array.setIfInBounds a i v

View File

@@ -15,15 +15,6 @@ structure Subarray (α : Type u) where
start_le_stop : start stop
stop_le_array_size : stop array.size
@[deprecated Subarray.array (since := "2024-04-13")]
abbrev Subarray.as (s : Subarray α) : Array α := s.array
@[deprecated Subarray.start_le_stop (since := "2024-04-13")]
theorem Subarray.h₁ (s : Subarray α) : s.start s.stop := s.start_le_stop
@[deprecated Subarray.stop_le_array_size (since := "2024-04-13")]
theorem Subarray.h₂ (s : Subarray α) : s.stop s.array.size := s.stop_le_array_size
namespace Subarray
def size (s : Subarray α) : Nat :=
@@ -48,7 +39,7 @@ instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
getElem xs i h := xs.get i, h
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
if h : i < s.size then s.get i, h else v₀
if h : i < s.size then s[i] else v₀
abbrev get! [Inhabited α] (s : Subarray α) (i : Nat) : α :=
getD s i default

View File

@@ -23,16 +23,13 @@ def split (s : Subarray α) (i : Fin s.size.succ) : (Subarray α × Subarray α)
let i', isLt := i
have := s.start_le_stop
have := s.stop_le_array_size
have : i' s.stop - s.start := Nat.lt_succ.mp isLt
have : s.start + i' s.stop := by omega
have : s.start + i' s.array.size := by omega
have : s.start + i' s.stop := by
simp only [size] at isLt
omega
let pre := {s with
stop := s.start + i',
start_le_stop := by omega,
stop_le_array_size := by assumption
stop_le_array_size := by omega
}
let post := {s with
start := s.start + i'
@@ -48,9 +45,7 @@ def drop (arr : Subarray α) (i : Nat) : Subarray α where
array := arr.array
start := min (arr.start + i) arr.stop
stop := arr.stop
start_le_stop := by
rw [Nat.min_def]
split <;> simp only [Nat.le_refl, *]
start_le_stop := by omega
stop_le_array_size := arr.stop_le_array_size
/--
@@ -63,9 +58,7 @@ def take (arr : Subarray α) (i : Nat) : Subarray α where
stop := min (arr.start + i) arr.stop
start_le_stop := by
have := arr.start_le_stop
rw [Nat.min_def]
split <;> omega
omega
stop_le_array_size := by
have := arr.stop_le_array_size
rw [Nat.min_def]
split <;> omega
omega

View File

@@ -12,7 +12,7 @@ namespace Array
theorem exists_of_uset (self : Array α) (i d h) :
l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ List.length l₁ = i.toNat
(self.uset i d h).toList = l₁ ++ d :: l₂ := by
simpa only [ugetElem_eq_getElem, getElem_eq_getElem_toList, uset, toList_set] using
simpa only [ugetElem_eq_getElem, getElem_toList, uset, toList_set] using
List.exists_of_set _
end Array

View File

@@ -29,9 +29,6 @@ section Nat
instance natCastInst : NatCast (BitVec w) := BitVec.ofNat w
@[deprecated isLt (since := "2024-03-12")]
theorem toNat_lt (x : BitVec n) : x.toNat < 2^n := x.isLt
/-- Theorem for normalizing the bit vector literal representation. -/
-- TODO: This needs more usage data to assess which direction the simp should go.
@[simp, bv_toNat] theorem ofNat_eq_ofNat : @OfNat.ofNat (BitVec n) i _ = .ofNat n i := rfl
@@ -354,17 +351,17 @@ end relations
section cast
/-- `cast eq x` embeds `x` into an equal `BitVec` type. -/
@[inline] def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq x.isLt)
@[inline] protected def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq x.isLt)
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
cast h (BitVec.ofNat n x) = BitVec.ofNat m x := by
(BitVec.ofNat n x).cast h = BitVec.ofNat m x := by
subst h; rfl
@[simp] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
cast h (cast h x) = cast (h₁ h₂) x :=
(x.cast h).cast h = x.cast (h₁ h₂) :=
rfl
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : cast h x = x := rfl
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : x.cast h = x := rfl
/--
Extraction of bits `start` to `start + len - 1` from a bit vector of size `n` to yield a
@@ -634,6 +631,16 @@ def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i
end bitwise
/-- Compute a hash of a bitvector, combining 64-bit words using `mixHash`. -/
def hash (bv : BitVec n) : UInt64 :=
if n 64 then
bv.toFin.val.toUInt64
else
mixHash (bv.toFin.val.toUInt64) (hash ((bv >>> 64).setWidth (n - 64)))
instance : Hashable (BitVec n) where
hash := hash
section normalization_eqs
/-! We add simp-lemmas that rewrite bitvector operations into the equivalent notation -/
@[simp] theorem append_eq (x : BitVec w) (y : BitVec v) : BitVec.append x y = x ++ y := rfl

View File

@@ -76,7 +76,7 @@ to prove the correctness of the circuit that is built by `bv_decide`.
def blastMul (aig : AIG BVBit) (input : AIG.BinaryRefVec aig w) : AIG.RefVecEntry BVBit w
theorem denote_blastMul (aig : AIG BVBit) (lhs rhs : BitVec w) (assign : Assignment) :
...
⟦(blastMul aig input).aig, (blastMul aig input).vec.get idx hidx, assign.toAIGAssignment⟧
⟦(blastMul aig input).aig, (blastMul aig input).vec[idx], assign.toAIGAssignment⟧
=
(lhs * rhs).getLsbD idx
```
@@ -174,6 +174,30 @@ theorem carry_succ (i : Nat) (x y : BitVec w) (c : Bool) :
exact mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ ..
cases x.toNat.testBit i <;> cases y.toNat.testBit i <;> (simp; omega)
theorem carry_succ_one (i : Nat) (x : BitVec w) (h : 0 < w) :
carry (i+1) x (1#w) false = decide ( j i, x.getLsbD j = true) := by
induction i with
| zero => simp [carry_succ, h]
| succ i ih =>
rw [carry_succ, ih]
simp only [getLsbD_one, add_one_ne_zero, decide_false, Bool.and_false, atLeastTwo_false_mid]
cases hx : x.getLsbD (i+1)
case false =>
have : j i + 1, x.getLsbD j = false :=
i+1, by omega, hx
simpa
case true =>
suffices
( (j : Nat), j i x.getLsbD j = true)
( (j : Nat), j i + 1 x.getLsbD j = true) by
simpa
constructor
· intro h j hj
rcases Nat.le_or_eq_of_le_succ hj with (hj' | rfl)
· apply h; assumption
· exact hx
· intro h j hj; apply h; omega
/--
If `x &&& y = 0`, then the carry bit `(x + y + 0)` is always `false` for any index `i`.
Intuitively, this is because a carry is only produced when at least two of `x`, `y`, and the
@@ -225,7 +249,7 @@ theorem getLsbD_add_add_bool {i : Nat} (i_lt : i < w) (x y : BitVec w) (c : Bool
[ Nat.testBit_mod_two_pow,
Nat.testBit_mul_two_pow_add_eq,
i_lt,
decide_True,
decide_true,
Bool.true_and,
Nat.add_assoc,
Nat.add_left_comm (_%_) (_ * _) _,
@@ -322,6 +346,10 @@ theorem getMsbD_sub {i : Nat} {i_lt : i < w} {x y : BitVec w} :
· rfl
· omega
theorem getElem_sub {i : Nat} {x y : BitVec w} (h : i < w) :
(x - y)[i] = (x[i] ^^ ((~~~y + 1#w)[i] ^^ carry i x (~~~y + 1#w) false)) := by
simp [ getLsbD_eq_getElem, getLsbD_sub, h]
theorem msb_sub {x y: BitVec w} :
(x - y).msb
= (x.msb ^^ ((~~~y + 1#w).msb ^^ carry (w - 1 - 0) x (~~~y + 1#w) false)) := by
@@ -352,6 +380,121 @@ theorem bit_neg_eq_neg (x : BitVec w) : -x = (adc (((iunfoldr (fun (i : Fin w) c
simp [ sub_toAdd, BitVec.sub_add_cancel]
· simp [bit_not_testBit x _]
/--
Remember that negating a bitvector is equal to incrementing the complement
by one, i.e., `-x = ~~~x + 1`. See also `neg_eq_not_add`.
This computation has two crucial properties:
- The least significant bit of `-x` is the same as the least significant bit of `x`, and
- The `i+1`-th least significant bit of `-x` is the complement of the `i+1`-th bit of `x`, unless
all of the preceding bits are `false`, in which case the bit is equal to the `i+1`-th bit of `x`
-/
theorem getLsbD_neg {i : Nat} {x : BitVec w} :
getLsbD (-x) i =
(getLsbD x i ^^ decide (i < w) && decide ( j < i, getLsbD x j = true)) := by
rw [neg_eq_not_add]
by_cases hi : i < w
· rw [getLsbD_add hi]
have : 0 < w := by omega
simp only [getLsbD_not, hi, decide_true, Bool.true_and, getLsbD_one, this, not_bne,
_root_.true_and, not_eq_eq_eq_not]
cases i with
| zero =>
have carry_zero : carry 0 ?x ?y false = false := by
simp [carry]; omega
simp [hi, carry_zero]
| succ =>
rw [carry_succ_one _ _ (by omega), Bool.xor_not, decide_not]
simp only [add_one_ne_zero, decide_false, getLsbD_not, and_eq_true, decide_eq_true_eq,
not_eq_eq_eq_not, Bool.not_true, false_bne, not_exists, _root_.not_and, not_eq_true,
bne_right_inj, decide_eq_decide]
constructor
· rintro h j hj; exact And.right <| h j (by omega)
· rintro h j hj; exact by omega, h j (by omega)
· have h_ge : w i := by omega
simp [getLsbD_ge _ _ h_ge, h_ge, hi]
theorem getElem_neg {i : Nat} {x : BitVec w} (h : i < w) :
(-x)[i] = (x[i] ^^ decide ( j < i, x.getLsbD j = true)) := by
simp [ getLsbD_eq_getElem, getLsbD_neg, h]
theorem getMsbD_neg {i : Nat} {x : BitVec w} :
getMsbD (-x) i =
(getMsbD x i ^^ decide ( j < w, i < j getMsbD x j = true)) := by
simp only [getMsbD, getLsbD_neg, Bool.decide_and, Bool.and_eq_true, decide_eq_true_eq]
by_cases hi : i < w
case neg =>
simp [hi]; omega
case pos =>
have h₁ : w - 1 - i < w := by omega
simp only [hi, decide_true, h₁, Bool.true_and, Bool.bne_right_inj, decide_eq_decide]
constructor
· rintro j, hj, h
refine w - 1 - j, by omega, by omega, by omega, _root_.cast ?_ h
congr; omega
· rintro j, hj₁, hj₂, -, h
exact w - 1 - j, by omega, h
theorem msb_neg {w : Nat} {x : BitVec w} :
(-x).msb = ((x != 0#w && x != intMin w) ^^ x.msb) := by
simp only [BitVec.msb, getMsbD_neg]
by_cases hmin : x = intMin _
case pos =>
have : ( j, j < w 0 < j 0 < w j = 0) False := by
simp; omega
simp [hmin, getMsbD_intMin, this]
case neg =>
by_cases hzero : x = 0#w
case pos => simp [hzero]
case neg =>
have w_pos : 0 < w := by
cases w
· rw [@of_length_zero x] at hzero
contradiction
· omega
suffices j, j < w 0 < j x.getMsbD j = true
by simp [show x != 0#w by simpa, show x != intMin w by simpa, this]
false_or_by_contra
rename_i getMsbD_x
simp only [not_exists, _root_.not_and, not_eq_true] at getMsbD_x
/- `getMsbD` says that all bits except the msb are `false` -/
cases hmsb : x.msb
case true =>
apply hmin
apply eq_of_getMsbD_eq
rintro i, hi
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
cases i
case zero => exact hmsb
case succ => exact getMsbD_x _ hi (by omega)
case false =>
apply hzero
apply eq_of_getMsbD_eq
rintro i, hi
simp only [getMsbD_zero]
cases i
case zero => exact hmsb
case succ => exact getMsbD_x _ hi (by omega)
/-! ### abs -/
theorem msb_abs {w : Nat} {x : BitVec w} :
x.abs.msb = (decide (x = intMin w) && decide (0 < w)) := by
simp only [BitVec.abs, getMsbD_neg, ne_eq, decide_not, Bool.not_bne]
by_cases h₀ : 0 < w
· by_cases h₁ : x = intMin w
· simp [h₁, msb_intMin]
· simp only [neg_eq, h₁, decide_false]
by_cases h₂ : x.msb
· simp [h₂, msb_neg]
and_intros
· by_cases h₃ : x = 0#w
· simp [h₃] at h₂
· simp [h₃]
· simp [h₁]
· simp [h₂]
· simp [BitVec.msb, show w = 0 by omega]
/-! ### Inequalities (le / lt) -/
theorem ult_eq_not_carry (x y : BitVec w) : x.ult y = !carry w x (~~~y) true := by
@@ -431,18 +574,18 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
rw [add_eq_or_of_and_eq_zero]
· ext k
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
by_cases hik : i = k
· subst hik
simp
· simp only [getLsbD_twoPow, hik, decide_False, Bool.and_false, Bool.or_false]
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
by_cases hik' : k < (i + 1)
· have hik'' : k < i := by omega
simp [hik', hik'']
· have hik'' : ¬ (k < i) := by omega
simp [hik', hik'']
· ext k
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and,
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and,
getLsbD_zero, and_eq_false_imp, and_eq_true, decide_eq_true_eq, and_imp]
by_cases hi : x.getLsbD i <;> simp [hi] <;> omega
@@ -957,8 +1100,8 @@ def sshiftRightRec (x : BitVec w₁) (y : BitVec w₂) (n : Nat) : BitVec w₁ :
@[simp]
theorem sshiftRightRec_zero_eq (x : BitVec w₁) (y : BitVec w₂) :
sshiftRightRec x y 0 = x.sshiftRight' (y &&& 1#w₂) := by
simp only [sshiftRightRec, twoPow_zero]
sshiftRightRec x y 0 = x.sshiftRight' (y &&& twoPow w₂ 0) := by
simp only [sshiftRightRec]
@[simp]
theorem sshiftRightRec_succ_eq (x : BitVec w₁) (y : BitVec w₂) (n : Nat) :

View File

@@ -65,7 +65,7 @@ theorem iunfoldr_getLsbD' {f : Fin w → αα × Bool} (state : Nat → α)
intro
apply And.intro
· intro i
have := Fin.size_pos i
have := Fin.pos i
contradiction
· rfl
case step =>

File diff suppressed because it is too large Load Diff

View File

@@ -238,8 +238,8 @@ theorem not_bne_not : ∀ (x y : Bool), ((!x) != (!y)) = (x != y) := by simp
@[simp] theorem bne_assoc : (x y z : Bool), ((x != y) != z) = (x != (y != z)) := by decide
instance : Std.Associative (· != ·) := bne_assoc
@[simp] theorem bne_left_inj : {x y z : Bool}, (x != y) = (x != z) y = z := by decide
@[simp] theorem bne_right_inj : {x y z : Bool}, (x != z) = (y != z) x = y := by decide
@[simp] theorem bne_right_inj : {x y z : Bool}, (x != y) = (x != z) y = z := by decide
@[simp] theorem bne_left_inj : {x y z : Bool}, (x != z) = (y != z) x = y := by decide
theorem eq_not_of_ne : {x y : Bool}, x y x = !y := by decide
@@ -295,9 +295,9 @@ theorem xor_right_comm : ∀ (x y z : Bool), ((x ^^ y) ^^ z) = ((x ^^ z) ^^ y) :
theorem xor_assoc : (x y z : Bool), ((x ^^ y) ^^ z) = (x ^^ (y ^^ z)) := bne_assoc
theorem xor_left_inj : {x y z : Bool}, (x ^^ y) = (x ^^ z) y = z := bne_left_inj
theorem xor_right_inj : {x y z : Bool}, (x ^^ y) = (x ^^ z) y = z := bne_right_inj
theorem xor_right_inj : {x y z : Bool}, (x ^^ z) = (y ^^ z) x = y := bne_right_inj
theorem xor_left_inj : {x y z : Bool}, (x ^^ z) = (y ^^ z) x = y := bne_left_inj
/-! ### le/lt -/
@@ -384,6 +384,15 @@ theorem toNat_lt (b : Bool) : b.toNat < 2 :=
@[simp] theorem toNat_eq_one {b : Bool} : b.toNat = 1 b = true := by
cases b <;> simp
/-! ## toInt -/
/-- convert a `Bool` to an `Int`, `false -> 0`, `true -> 1` -/
def toInt (b : Bool) : Int := cond b 1 0
@[simp] theorem toInt_false : false.toInt = 0 := rfl
@[simp] theorem toInt_true : true.toInt = 1 := rfl
/-! ### ite -/
@[simp] theorem if_true_left (p : Prop) [h : Decidable p] (f : Bool) :

View File

@@ -42,7 +42,7 @@ def usize (a : @& ByteArray) : USize :=
a.size.toUSize
@[extern "lean_byte_array_uget"]
def uget : (a : @& ByteArray) (i : USize) i.toNat < a.size UInt8
def uget : (a : @& ByteArray) (i : USize) (h : i.toNat < a.size := by get_elem_tactic) UInt8
| bs, i, h => bs[i]
@[extern "lean_byte_array_get"]
@@ -50,11 +50,11 @@ def get! : (@& ByteArray) → (@& Nat) → UInt8
| bs, i => bs.get! i
@[extern "lean_byte_array_fget"]
def get : (a : @& ByteArray) (@& Fin a.size) UInt8
| bs, i => bs.get i
def get : (a : @& ByteArray) (i : @& Nat) (h : i < a.size := by get_elem_tactic) UInt8
| bs, i, _ => bs[i]
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
getElem xs i h := xs.get i, h
getElem xs i h := xs.get i
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
getElem xs i h := xs.uget i h
@@ -64,11 +64,11 @@ def set! : ByteArray → (@& Nat) → UInt8 → ByteArray
| bs, i, b => bs.set! i b
@[extern "lean_byte_array_fset"]
def set : (a : ByteArray) (@& Fin a.size) UInt8 ByteArray
| bs, i, b => bs.set i b
def set : (a : ByteArray) (i : @& Nat) UInt8 (h : i < a.size := by get_elem_tactic) ByteArray
| bs, i, b, h => bs.set i b h
@[extern "lean_byte_array_uset"]
def uset : (a : ByteArray) (i : USize) UInt8 i.toNat < a.size ByteArray
def uset : (a : ByteArray) (i : USize) UInt8 (h : i.toNat < a.size := by get_elem_tactic) ByteArray
| bs, i, v, h => bs.uset i v h
@[extern "lean_byte_array_hash"]
@@ -108,8 +108,18 @@ def toList (bs : ByteArray) : List UInt8 :=
@[inline] def findIdx? (a : ByteArray) (p : UInt8 Bool) (start := 0) : Option Nat :=
let rec @[specialize] loop (i : Nat) :=
if i < a.size then
if p (a.get! i) then some i else loop (i+1)
if h : i < a.size then
if p a[i] then some i else loop (i+1)
else
none
termination_by a.size - i
decreasing_by decreasing_trivial_pre_omega
loop start
@[inline] def findFinIdx? (a : ByteArray) (p : UInt8 Bool) (start := 0) : Option (Fin a.size) :=
let rec @[specialize] loop (i : Nat) :=
if h : i < a.size then
if p a[i] then some i, h else loop (i+1)
else
none
termination_by a.size - i
@@ -144,7 +154,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteAr
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
match ( f (as.get as.size - 1 - i, this) b) with
match ( f as[as.size - 1 - i] b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
@@ -178,7 +188,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 →
match i with
| 0 => pure b
| i'+1 =>
loop i' (j+1) ( f b (as.get j, Nat.lt_of_lt_of_le hlt h))
loop i' (j+1) ( f b as[j])
else
pure b
loop (stop - start) start init

View File

@@ -8,6 +8,8 @@ import Init.Data.Queue
import Init.System.Promise
import Init.System.Mutex
set_option linter.deprecated false
namespace IO
/--
@@ -15,6 +17,7 @@ Internal state of an `Channel`.
We maintain the invariant that at all times either `consumers` or `values` is empty.
-/
@[deprecated "Use Std.Channel.State from Std.Sync.Channel instead" (since := "2024-12-02")]
structure Channel.State (α : Type) where
values : Std.Queue α :=
consumers : Std.Queue (Promise (Option α)) :=
@@ -27,12 +30,14 @@ FIFO channel with unbounded buffer, where `recv?` returns a `Task`.
A channel can be closed. Once it is closed, all `send`s are ignored, and
`recv?` returns `none` once the queue is empty.
-/
@[deprecated "Use Std.Channel from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel (α : Type) : Type := Mutex (Channel.State α)
instance : Nonempty (Channel α) :=
inferInstanceAs (Nonempty (Mutex _))
/-- Creates a new `Channel`. -/
@[deprecated "Use Std.Channel.new from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.new : BaseIO (Channel α) :=
Mutex.new {}
@@ -41,6 +46,7 @@ Sends a message on an `Channel`.
This function does not block.
-/
@[deprecated "Use Std.Channel.send from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
ch.atomically do
let st get
@@ -54,6 +60,7 @@ def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
/--
Closes an `Channel`.
-/
@[deprecated "Use Std.Channel.close from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.close (ch : Channel α) : BaseIO Unit :=
ch.atomically do
let st get
@@ -67,6 +74,7 @@ Every message is only received once.
Returns `none` if the channel is closed and the queue is empty.
-/
@[deprecated "Use Std.Channel.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
ch.atomically do
let st get
@@ -85,6 +93,7 @@ def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
Note that if this function is called twice, each `forAsync` only gets half the messages.
-/
@[deprecated "Use Std.Channel.forAsync from Std.Sync.Channel instead" (since := "2024-12-02")]
partial def Channel.forAsync (f : α BaseIO Unit) (ch : Channel α)
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
BaseIO.bindTask (prio := prio) ( ch.recv?) fun
@@ -96,11 +105,13 @@ Receives all currently queued messages from the channel.
Those messages are dequeued and will not be returned by `recv?`.
-/
@[deprecated "Use Std.Channel.recvAllCurrent from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.recvAllCurrent (ch : Channel α) : BaseIO (Array α) :=
ch.atomically do
modifyGet fun st => (st.values.toArray, { st with values := })
/-- Type tag for synchronous (blocking) operations on a `Channel`. -/
@[deprecated "Use Std.Channel.Sync from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.Sync := Channel
/--
@@ -110,6 +121,7 @@ For example, `ch.sync.recv?` blocks until the next message,
and `for msg in ch.sync do ...` iterates synchronously over the channel.
These functions should only be used in dedicated threads.
-/
@[deprecated "Use Std.Channel.sync from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.sync (ch : Channel α) : Channel.Sync α := ch
/--
@@ -118,9 +130,11 @@ Synchronously receives a message from the channel.
Every message is only received once.
Returns `none` if the channel is closed and the queue is empty.
-/
@[deprecated "Use Std.Channel.Sync.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.Sync.recv? (ch : Channel.Sync α) : BaseIO (Option α) := do
IO.wait ( Channel.recv? ch)
@[deprecated "Use Std.Channel.Sync.forIn from Std.Sync.Channel instead" (since := "2024-12-02")]
private partial def Channel.Sync.forIn [Monad m] [MonadLiftT BaseIO m]
(ch : Channel.Sync α) (f : α β m (ForInStep β)) : β m β := fun b => do
match ch.recv? with

View File

@@ -36,12 +36,6 @@ def succ : Fin n → Fin (n + 1)
variable {n : Nat}
/--
Returns `a` modulo `n + 1` as a `Fin n.succ`.
-/
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)
/--
Returns `a` modulo `n` as a `Fin n`.
@@ -50,9 +44,12 @@ The assumption `NeZero n` ensures that `Fin n` is nonempty.
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
a % n, Nat.mod_lt _ (pos_of_neZero n)
-- We intend to deprecate `Fin.ofNat` in favor of `Fin.ofNat'` (and later rename).
-- This is waiting on https://github.com/leanprover/lean4/pull/5323
-- attribute [deprecated Fin.ofNat' (since := "2024-09-16")] Fin.ofNat
/--
Returns `a` modulo `n + 1` as a `Fin n.succ`.
-/
@[deprecated Fin.ofNat' (since := "2024-11-27")]
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)
private theorem mlt {b : Nat} : {a : Nat} a < n b % n < n
| 0, h => Nat.mod_lt _ h
@@ -165,6 +162,7 @@ theorem modn_lt : ∀ {m : Nat} (i : Fin n), m > 0 → (modn i m).val < m
theorem val_lt_of_le (i : Fin b) (h : b n) : i.val < n :=
Nat.lt_of_lt_of_le i.isLt h
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
protected theorem pos (i : Fin n) : 0 < n :=
Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
@@ -178,7 +176,7 @@ protected theorem pos (i : Fin n) : 0 < n :=
@[inline] def castLE (h : n m) (i : Fin n) : Fin m := i, Nat.lt_of_lt_of_le i.2 h
/-- `cast eq i` embeds `i` into an equal `Fin` type. -/
@[inline] def cast (eq : n = m) (i : Fin n) : Fin m := i, eq i.2
@[inline] protected def cast (eq : n = m) (i : Fin n) : Fin m := i, eq i.2
/-- `castAdd m i` embeds `i : Fin n` in `Fin (n+m)`. See also `Fin.natAdd` and `Fin.addNat`. -/
@[inline] def castAdd (m) : Fin n Fin (n + m) :=

View File

@@ -5,22 +5,217 @@ Authors: François G. Dorais
-/
prelude
import Init.Data.Nat.Linear
import Init.Control.Lawful.Basic
import Init.Data.Fin.Lemmas
namespace Fin
/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/
@[inline] def foldl (n) (f : α Fin n α) (init : α) : α := loop init 0 where
/-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/
loop (x : α) (i : Nat) : α :=
@[semireducible, specialize] loop (x : α) (i : Nat) : α :=
if h : i < n then loop (f x i, h) (i+1) else x
termination_by n - i
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
@[inline] def foldr (n) (f : Fin n α α) (init : α) : α := loop n (Nat.le_refl n) init where
/-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/
@[specialize] loop : (i : _) i n α α
| 0, _, x => x
| i+1, h, x => loop i (Nat.le_of_lt h) (f i, h x)
termination_by structural i => i
/--
Folds a monadic function over `Fin n` from left to right:
```
Fin.foldlM n f x₀ = do
let x₁ ← f x₀ 0
let x₂ ← f x₁ 1
...
let xₙ ← f xₙ₋₁ (n-1)
pure xₙ
```
-/
@[inline] def foldlM [Monad m] (n) (f : α Fin n m α) (init : α) : m α := loop init 0 where
/--
Inner loop for `Fin.foldlM`.
```
Fin.foldlM.loop n f xᵢ i = do
let xᵢ₊₁ ← f xᵢ i
...
let xₙ ← f xₙ₋₁ (n-1)
pure xₙ
```
-/
@[semireducible, specialize] loop (x : α) (i : Nat) : m α := do
if h : i < n then f x i, h >>= (loop · (i+1)) else pure x
termination_by n - i
decreasing_by decreasing_trivial_pre_omega
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
@[inline] def foldr (n) (f : Fin n α α) (init : α) : α := loop n, Nat.le_refl n init where
/-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/
loop : {i // i n} α α
| 0, _, x => x
| i+1, h, x => loop i, Nat.le_of_lt h (f i, h x)
/--
Folds a monadic function over `Fin n` from right to left:
```
Fin.foldrM n f xₙ = do
let xₙ₋₁ ← f (n-1) xₙ
let xₙ₋₂ ← f (n-2) xₙ₋₁
...
let x₀ ← f 0 x₁
pure x₀
```
-/
@[inline] def foldrM [Monad m] (n) (f : Fin n α m α) (init : α) : m α :=
loop n, Nat.le_refl n init where
/--
Inner loop for `Fin.foldrM`.
```
Fin.foldrM.loop n f i xᵢ = do
let xᵢ₋₁ ← f (i-1) xᵢ
...
let x₁ ← f 1 x₂
let x₀ ← f 0 x₁
pure x₀
```
-/
@[semireducible, specialize] loop : {i // i n} α m α
| 0, _, x => pure x
| i+1, h, x => f i, h x >>= loop i, Nat.le_of_lt h
/-! ### foldlM -/
theorem foldlM_loop_lt [Monad m] (f : α Fin n m α) (x) (h : i < n) :
foldlM.loop n f x i = f x i, h >>= (foldlM.loop n f . (i+1)) := by
rw [foldlM.loop, dif_pos h]
theorem foldlM_loop_eq [Monad m] (f : α Fin n m α) (x) : foldlM.loop n f x n = pure x := by
rw [foldlM.loop, dif_neg (Nat.lt_irrefl _)]
theorem foldlM_loop [Monad m] (f : α Fin (n+1) m α) (x) (h : i < n+1) :
foldlM.loop (n+1) f x i = f x i, h >>= (foldlM.loop n (fun x j => f x j.succ) . i) := by
if h' : i < n then
rw [foldlM_loop_lt _ _ h]
congr; funext
rw [foldlM_loop_lt _ _ h', foldlM_loop]; rfl
else
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
rw [foldlM_loop_lt]
congr; funext
rw [foldlM_loop_eq, foldlM_loop_eq]
termination_by n - i
@[simp] theorem foldlM_zero [Monad m] (f : α Fin 0 m α) (x) : foldlM 0 f x = pure x :=
foldlM_loop_eq ..
theorem foldlM_succ [Monad m] (f : α Fin (n+1) m α) (x) :
foldlM (n+1) f x = f x 0 >>= foldlM n (fun x j => f x j.succ) := foldlM_loop ..
/-! ### foldrM -/
theorem foldrM_loop_zero [Monad m] (f : Fin n α m α) (x) :
foldrM.loop n f 0, Nat.zero_le _ x = pure x := by
rw [foldrM.loop]
theorem foldrM_loop_succ [Monad m] (f : Fin n α m α) (x) (h : i < n) :
foldrM.loop n f i+1, h x = f i, h x >>= foldrM.loop n f i, Nat.le_of_lt h := by
rw [foldrM.loop]
theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) α m α) (x) (h : i+1 n+1) :
foldrM.loop (n+1) f i+1, h x =
foldrM.loop n (fun j => f j.succ) i, Nat.le_of_succ_le_succ h x >>= f 0 := by
induction i generalizing x with
| zero =>
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
conv => rhs; rw [bind_pure (f 0 x)]
congr; funext
| succ i ih =>
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
congr; funext; exact ih ..
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 α m α) (x) : foldrM 0 f x = pure x :=
foldrM_loop_zero ..
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) α m α) (x) :
foldrM (n+1) f x = foldrM n (fun i => f i.succ) x >>= f 0 := foldrM_loop ..
/-! ### foldl -/
theorem foldl_loop_lt (f : α Fin n α) (x) (h : i < n) :
foldl.loop n f x i = foldl.loop n f (f x i, h) (i+1) := by
rw [foldl.loop, dif_pos h]
theorem foldl_loop_eq (f : α Fin n α) (x) : foldl.loop n f x n = x := by
rw [foldl.loop, dif_neg (Nat.lt_irrefl _)]
theorem foldl_loop (f : α Fin (n+1) α) (x) (h : i < n+1) :
foldl.loop (n+1) f x i = foldl.loop n (fun x j => f x j.succ) (f x i, h) i := by
if h' : i < n then
rw [foldl_loop_lt _ _ h]
rw [foldl_loop_lt _ _ h', foldl_loop]; rfl
else
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
rw [foldl_loop_lt]
rw [foldl_loop_eq, foldl_loop_eq]
@[simp] theorem foldl_zero (f : α Fin 0 α) (x) : foldl 0 f x = x :=
foldl_loop_eq ..
theorem foldl_succ (f : α Fin (n+1) α) (x) :
foldl (n+1) f x = foldl n (fun x i => f x i.succ) (f x 0) :=
foldl_loop ..
theorem foldl_succ_last (f : α Fin (n+1) α) (x) :
foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by
rw [foldl_succ]
induction n generalizing x with
| zero => simp [foldl_succ, Fin.last]
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp [succ_castSucc]
theorem foldl_eq_foldlM (f : α Fin n α) (x) :
foldl n f x = foldlM (m:=Id) n f x := by
induction n generalizing x <;> simp [foldl_succ, foldlM_succ, *]
/-! ### foldr -/
theorem foldr_loop_zero (f : Fin n α α) (x) :
foldr.loop n f 0 (Nat.zero_le _) x = x := by
rw [foldr.loop]
theorem foldr_loop_succ (f : Fin n α α) (x) (h : i < n) :
foldr.loop n f (i+1) h x = foldr.loop n f i (Nat.le_of_lt h) (f i, h x) := by
rw [foldr.loop]
theorem foldr_loop (f : Fin (n+1) α α) (x) (h : i+1 n+1) :
foldr.loop (n+1) f (i+1) h x =
f 0 (foldr.loop n (fun j => f j.succ) i (Nat.le_of_succ_le_succ h) x) := by
induction i generalizing x with
| zero => simp [foldr_loop_succ, foldr_loop_zero]
| succ i ih => rw [foldr_loop_succ, ih]; rfl
@[simp] theorem foldr_zero (f : Fin 0 α α) (x) : foldr 0 f x = x :=
foldr_loop_zero ..
theorem foldr_succ (f : Fin (n+1) α α) (x) :
foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop ..
theorem foldr_succ_last (f : Fin (n+1) α α) (x) :
foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by
induction n generalizing x with
| zero => simp [foldr_succ, Fin.last]
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp [succ_castSucc]
theorem foldr_eq_foldrM (f : Fin n α α) (x) :
foldr n f x = foldrM (m:=Id) n f x := by
induction n <;> simp [foldr_succ, foldrM_succ, *]
theorem foldl_rev (f : Fin n α α) (x) :
foldl n (fun x i => f i.rev x) x = foldr n f x := by
induction n generalizing x with
| zero => simp
| succ n ih => rw [foldl_succ, foldr_succ_last, ih]; simp [rev_succ]
theorem foldr_rev (f : α Fin n α) (x) :
foldr n (fun i x => f x i.rev) x = foldl n f x := by
induction n generalizing x with
| zero => simp
| succ n ih => rw [foldl_succ_last, foldr_succ, ih]; simp [rev_succ]
end Fin

View File

@@ -13,17 +13,19 @@ import Init.Omega
namespace Fin
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
theorem size_pos (i : Fin n) : 0 < n := Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
@[deprecated Fin.pos (since := "2024-11-11")]
theorem size_pos (i : Fin n) : 0 < n := i.pos
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
rfl
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.size_pos) := rfl
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.pos) := rfl
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.size_pos) := rfl
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.pos) := rfl
theorem size_pos' : [Nonempty (Fin n)], 0 < n | i => i.size_pos
theorem pos' : [Nonempty (Fin n)], 0 < n | i => i.pos
@[deprecated pos' (since := "2024-11-11")] abbrev size_pos' := @pos'
@[simp] theorem is_lt (a : Fin n) : (a : Nat) < n := a.2
@@ -240,7 +242,7 @@ theorem fin_one_eq_zero (a : Fin 1) : a = 0 := Subsingleton.elim a 0
rw [eq_comm]
simp
theorem add_def (a b : Fin n) : a + b = Fin.mk ((a + b) % n) (Nat.mod_lt _ a.size_pos) := rfl
theorem add_def (a b : Fin n) : a + b = Fin.mk ((a + b) % n) (Nat.mod_lt _ a.pos) := rfl
theorem val_add (a b : Fin n) : (a + b).val = (a.val + b.val) % n := rfl
@@ -368,25 +370,25 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
Fin.castLE mn Fin.castLE km = Fin.castLE (Nat.le_trans km mn) :=
funext (castLE_castLE km mn)
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i := rfl
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' :=
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : (last n).cast h = last n' :=
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h i, hn = i, h hn := rfl
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : Fin.cast h i, hn = i, h hn := rfl
@[simp] theorem cast_refl (n : Nat) (h : n = n) : cast h = id := by
@[simp] theorem cast_refl (n : Nat) (h : n = n) : Fin.cast h = id := by
ext
simp
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
cast h' (cast h i) = cast (Eq.trans h h') i := rfl
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m n} : castLE h' = Fin.cast h := rfl
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n Fin (n + 0)) = cast rfl := rfl
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n Fin (n + 0)) = Fin.cast rfl := rfl
theorem castAdd_lt {m : Nat} (n : Nat) (i : Fin m) : (castAdd n i : Nat) < m := by simp
@@ -404,37 +406,37 @@ theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := Fin.ext rfl
theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) := rfl
(i.castAdd m).cast h = (i.cast (Nat.add_right_cancel h)).castAdd m := rfl
@[simp] theorem cast_castAdd_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
cast h (castAdd m' i) = castAdd m i := rfl
(i.castAdd m').cast h = i.castAdd m := rfl
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
castAdd p (castAdd n i) = cast (Nat.add_assoc ..).symm (castAdd (n + p) i) := rfl
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
the reverse direction. -/
@[simp] theorem cast_succ_eq {n' : Nat} (i : Fin n) (h : n.succ = n'.succ) :
cast h i.succ = (cast (Nat.succ.inj h) i).succ := rfl
i.succ.cast h = (i.cast (Nat.succ.inj h)).succ := rfl
theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
(cast h i).succ = cast (by rw [h]) i.succ := rfl
(i.cast h).succ = i.succ.cast (by rw [h]) := rfl
@[simp] theorem coe_castSucc (i : Fin n) : (Fin.castSucc i : Nat) = i := rfl
@[simp] theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
@[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc i, h = i, Nat.lt.step h := rfl
@[simp] theorem cast_castSucc {n' : Nat} {h : n + 1 = n' + 1} {i : Fin n} :
cast h (castSucc i) = castSucc (cast (Nat.succ.inj h) i) := rfl
i.castSucc.cast h = (i.cast (Nat.succ.inj h)).castSucc := rfl
theorem castSucc_lt_succ (i : Fin n) : Fin.castSucc i < i.succ :=
theorem castSucc_lt_succ (i : Fin n) : i.castSucc < i.succ :=
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i Fin.castSucc j i < j.succ := by
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i j.castSucc i < j.succ := by
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
Fin.castSucc i < j i.succ j := .rfl
i.castSucc < j i.succ j := .rfl
@[simp] theorem succ_last (n : Nat) : (last n).succ = last n.succ := rfl
@@ -442,48 +444,48 @@ theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
i.succ = last (n + 1) i = last n := by rw [ succ_last, succ_inj]
@[simp] theorem castSucc_castLT (i : Fin (n + 1)) (h : (i : Nat) < n) :
castSucc (castLT i h) = i := rfl
(castLT i h).castSucc = i := rfl
@[simp] theorem castLT_castSucc {n : Nat} (a : Fin n) (h : (a : Nat) < n) :
castLT (castSucc a) h = a := rfl
castLT a.castSucc h = a := rfl
@[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
Fin.castSucc a < Fin.castSucc b a < b := .rfl
a.castSucc < b.castSucc a < b := .rfl
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b a = b := by simp [Fin.ext_iff]
theorem castSucc_inj {a b : Fin n} : a.castSucc = b.castSucc a = b := by simp [Fin.ext_iff]
theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
theorem castSucc_lt_last (a : Fin n) : a.castSucc < last n := a.is_lt
@[simp] theorem castSucc_zero : castSucc (0 : Fin (n + 1)) = 0 := rfl
@[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 := rfl
/-- `castSucc i` is positive when `i` is positive -/
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i := by
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < i.castSucc := by
simpa [lt_def] using h
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : castSucc a = 0 a = 0 := by simp [Fin.ext_iff]
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : a.castSucc = 0 a = 0 := by simp [Fin.ext_iff]
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : castSucc a 0 a 0 :=
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : a.castSucc 0 a 0 :=
not_congr <| castSucc_eq_zero_iff
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
castSucc (Fin.succ j) = Fin.succ (castSucc j) := by simp [Fin.ext_iff]
j.succ.castSucc = (j.castSucc).succ := by simp [Fin.ext_iff]
@[simp]
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ := by
theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
cases n
· exact a.elim0
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
theorem lt_succ {a : Fin n} : castSucc a < a.succ := by
theorem lt_succ {a : Fin n} : a.castSucc < a.succ := by
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : ( j, castSucc j = i) i last n :=
fun j, hj => hj Fin.ne_of_lt j.castSucc_lt_last,
fun hi => i.castLT <| Fin.val_lt_last hi, rfl
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = castSucc i.succ := rfl
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = i.succ.castSucc := rfl
@[simp] theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
@@ -500,17 +502,17 @@ theorem le_coe_addNat (m : Nat) (i : Fin n) : m ≤ addNat i m :=
addNat i, hi n = i + n, Nat.add_lt_add_right hi n := rfl
@[simp] theorem cast_addNat_zero {n n' : Nat} (i : Fin n) (h : n + 0 = n') :
cast h (addNat i 0) = cast ((Nat.add_zero _).symm.trans h) i := rfl
(addNat i 0).cast h = i.cast ((Nat.add_zero _).symm.trans h) := rfl
/-- For rewriting in the reverse direction, see `Fin.cast_addNat_left`. -/
theorem addNat_cast {n n' m : Nat} (i : Fin n') (h : n' = n) :
addNat (cast h i) m = cast (congrArg (. + m) h) (addNat i m) := rfl
addNat (i.cast h) m = (addNat i m).cast (congrArg (. + m) h) := rfl
theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
cast h (addNat i m) = addNat (cast (Nat.add_right_cancel h) i) m := rfl
(addNat i m).cast h = addNat (i.cast (Nat.add_right_cancel h)) m := rfl
@[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
cast h (addNat i m') = addNat i m :=
(addNat i m').cast h = addNat i m :=
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
@@ -520,46 +522,46 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
theorem le_coe_natAdd (m : Nat) (i : Fin n) : m natAdd m i := Nat.le_add_right ..
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = cast (Nat.zero_add n).symm := by ext; simp
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = Fin.cast (Nat.zero_add n).symm := by ext; simp
/-- For rewriting in the reverse direction, see `Fin.cast_natAdd_right`. -/
theorem natAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
natAdd m (cast h i) = cast (congrArg _ h) (natAdd m i) := rfl
natAdd m (i.cast h) = (natAdd m i).cast (congrArg _ h) := rfl
theorem cast_natAdd_right {n n' m : Nat} (i : Fin n') (h : m + n' = m + n) :
cast h (natAdd m i) = natAdd m (cast (Nat.add_left_cancel h) i) := rfl
(natAdd m i).cast h = natAdd m (i.cast (Nat.add_left_cancel h)) := rfl
@[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
cast h (natAdd m' i) = natAdd m i :=
(natAdd m' i).cast h = natAdd m i :=
Fin.ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) := rfl
castAdd p (natAdd m i) = (natAdd m (castAdd p i)).cast (Nat.add_assoc ..).symm := rfl
theorem natAdd_castAdd (p m : Nat) {n : Nat} (i : Fin n) :
natAdd m (castAdd p i) = cast (Nat.add_assoc ..) (castAdd p (natAdd m i)) := rfl
natAdd m (castAdd p i) = (castAdd p (natAdd m i)).cast (Nat.add_assoc ..) := rfl
theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) :=
natAdd m (natAdd n i) = (natAdd (m + n) i).cast (Nat.add_assoc ..) :=
Fin.ext <| (Nat.add_assoc ..).symm
@[simp]
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i :=
(natAdd 0 i).cast h = i.cast ((Nat.zero_add _).symm.trans h) :=
Fin.ext <| Nat.zero_add _
@[simp]
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := Fin.ext <| Nat.add_comm ..
(natAdd n i).cast (Nat.add_comm ..) = addNat i n := Fin.ext <| Nat.add_comm ..
@[simp]
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := Fin.ext <| Nat.add_comm ..
(addNat i m).cast (Nat.add_comm ..) = natAdd m i := Fin.ext <| Nat.add_comm ..
@[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
@[simp] theorem addNat_last (n : Nat) :
addNat (last n) m = cast (by omega) (last (n + m)) := by
addNat (last n) m = (last (n + m)).cast (by omega) := by
ext
simp
@@ -640,7 +642,7 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
ext
simp
@[simp] theorem subNat_one_succ (i : Fin (n + 1)) (h : 1 i) : (subNat 1 i h).succ = i := by
@[simp] theorem subNat_one_succ (i : Fin (n + 1)) (h : 1 (i : Nat)) : (subNat 1 i h).succ = i := by
ext
simp
omega
@@ -655,7 +657,7 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
subNat m (addNat i m) h = i := Fin.ext <| Nat.add_sub_cancel i m
@[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n i) :
natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i := by simp [ cast_addNat]
natAdd n (subNat n (i.cast (Nat.add_comm ..)) h) = i := by simp [ cast_addNat]
/-! ### recursion and induction principles -/

View File

@@ -31,7 +31,7 @@ opaque floatSpec : FloatSpec := {
structure Float where
val : floatSpec.float
instance : Inhabited Float := { val := floatSpec.val }
instance : Nonempty Float := { val := floatSpec.val }
@[extern "lean_float_add"] opaque Float.add : Float Float Float
@[extern "lean_float_sub"] opaque Float.sub : Float Float Float
@@ -47,6 +47,25 @@ def Float.lt : Float → Float → Prop := fun a b =>
def Float.le : Float Float Prop := fun a b =>
floatSpec.le a.val b.val
/--
Raw transmutation from `UInt64`.
Floats and UInts have the same endianness on all supported platforms.
IEEE 754 very precisely specifies the bit layout of floats.
-/
@[extern "lean_float_of_bits"] opaque Float.ofBits : UInt64 Float
/--
Raw transmutation to `UInt64`.
Floats and UInts have the same endianness on all supported platforms.
IEEE 754 very precisely specifies the bit layout of floats.
Note that this function is distinct from `Float.toUInt64`, which attempts
to preserve the numeric value, and not the bitwise value.
-/
@[extern "lean_float_to_bits"] opaque Float.toBits : Float UInt64
instance : Add Float := Float.add
instance : Sub Float := Float.sub
instance : Mul Float := Float.mul
@@ -117,6 +136,9 @@ instance : ToString Float where
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
instance : Inhabited Float where
default := UInt64.toFloat 0
instance : Repr Float where
reprPrec n prec := if n < UInt64.toFloat 0 then Repr.addAppParen (toString n) prec else toString n

180
src/Init/Data/Float32.lean Normal file
View File

@@ -0,0 +1,180 @@
/-
Copyright (c) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Core
import Init.Data.Int.Basic
import Init.Data.ToString.Basic
import Init.Data.Float
/-
#exit -- TODO: Remove after update stage0
-- Just show FloatSpec is inhabited.
opaque float32Spec : FloatSpec := {
float := Unit,
val := (),
lt := fun _ _ => True,
le := fun _ _ => True,
decLt := fun _ _ => inferInstanceAs (Decidable True),
decLe := fun _ _ => inferInstanceAs (Decidable True)
}
/-- Native floating point type, corresponding to the IEEE 754 *binary32* format
(`float` in C or `f32` in Rust). -/
structure Float32 where
val : float32Spec.float
instance : Nonempty Float32 := ⟨{ val := float32Spec.val }⟩
@[extern "lean_float32_add"] opaque Float32.add : Float32 → Float32 → Float32
@[extern "lean_float32_sub"] opaque Float32.sub : Float32 → Float32 → Float32
@[extern "lean_float32_mul"] opaque Float32.mul : Float32 → Float32 → Float32
@[extern "lean_float32_div"] opaque Float32.div : Float32 → Float32 → Float32
@[extern "lean_float32_negate"] opaque Float32.neg : Float32 → Float32
set_option bootstrap.genMatcherCode false
def Float32.lt : Float32 → Float32 → Prop := fun a b =>
match a, b with
| ⟨a⟩, ⟨b⟩ => float32Spec.lt a b
def Float32.le : Float32 → Float32 → Prop := fun a b =>
float32Spec.le a.val b.val
/--
Raw transmutation from `UInt32`.
Float32s and UInts have the same endianness on all supported platforms.
IEEE 754 very precisely specifies the bit layout of floats.
-/
@[extern "lean_float32_of_bits"] opaque Float32.ofBits : UInt32 → Float32
/--
Raw transmutation to `UInt32`.
Float32s and UInts have the same endianness on all supported platforms.
IEEE 754 very precisely specifies the bit layout of floats.
Note that this function is distinct from `Float32.toUInt32`, which attempts
to preserve the numeric value, and not the bitwise value.
-/
@[extern "lean_float32_to_bits"] opaque Float32.toBits : Float32 → UInt32
instance : Add Float32 := ⟨Float32.add⟩
instance : Sub Float32 := ⟨Float32.sub⟩
instance : Mul Float32 := ⟨Float32.mul⟩
instance : Div Float32 := ⟨Float32.div⟩
instance : Neg Float32 := ⟨Float32.neg⟩
instance : LT Float32 := ⟨Float32.lt⟩
instance : LE Float32 := ⟨Float32.le⟩
/-- Note: this is not reflexive since `NaN != NaN`.-/
@[extern "lean_float32_beq"] opaque Float32.beq (a b : Float32) : Bool
instance : BEq Float32 := ⟨Float32.beq⟩
@[extern "lean_float32_decLt"] opaque Float32.decLt (a b : Float32) : Decidable (a < b) :=
match a, b with
| ⟨a⟩, ⟨b⟩ => float32Spec.decLt a b
@[extern "lean_float32_decLe"] opaque Float32.decLe (a b : Float32) : Decidable (a ≤ b) :=
match a, b with
| ⟨a⟩, ⟨b⟩ => float32Spec.decLe a b
instance float32DecLt (a b : Float32) : Decidable (a < b) := Float32.decLt a b
instance float32DecLe (a b : Float32) : Decidable (a ≤ b) := Float32.decLe a b
@[extern "lean_float32_to_string"] opaque Float32.toString : Float32 → String
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt8` (including Inf), returns the maximum value of `UInt8`
(i.e. `UInt8.size - 1`).
-/
@[extern "lean_float32_to_uint8"] opaque Float32.toUInt8 : Float32 → UInt8
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt16` (including Inf), returns the maximum value of `UInt16`
(i.e. `UInt16.size - 1`).
-/
@[extern "lean_float32_to_uint16"] opaque Float32.toUInt16 : Float32 → UInt16
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt32` (including Inf), returns the maximum value of `UInt32`
(i.e. `UInt32.size - 1`).
-/
@[extern "lean_float32_to_uint32"] opaque Float32.toUInt32 : Float32 → UInt32
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt64` (including Inf), returns the maximum value of `UInt64`
(i.e. `UInt64.size - 1`).
-/
@[extern "lean_float32_to_uint64"] opaque Float32.toUInt64 : Float32 → UInt64
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `USize` (including Inf), returns the maximum value of `USize`
(i.e. `USize.size - 1`). This value is platform dependent).
-/
@[extern "lean_float32_to_usize"] opaque Float32.toUSize : Float32 → USize
@[extern "lean_float32_isnan"] opaque Float32.isNaN : Float32 → Bool
@[extern "lean_float32_isfinite"] opaque Float32.isFinite : Float32 → Bool
@[extern "lean_float32_isinf"] opaque Float32.isInf : Float32 → Bool
/-- Splits the given float `x` into a significand/exponent pair `(s, i)`
such that `x = s * 2^i` where `s ∈ (-1;-0.5] [0.5; 1)`.
Returns an undefined value if `x` is not finite.
-/
@[extern "lean_float32_frexp"] opaque Float32.frExp : Float32 → Float32 × Int
instance : ToString Float32 where
toString := Float32.toString
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat32 (n : UInt64) : Float32
instance : Inhabited Float32 where
default := UInt64.toFloat32 0
instance : Repr Float32 where
reprPrec n prec := if n < UInt64.toFloat32 0 then Repr.addAppParen (toString n) prec else toString n
instance : ReprAtom Float32 := ⟨⟩
@[extern "sinf"] opaque Float32.sin : Float32 → Float32
@[extern "cosf"] opaque Float32.cos : Float32 → Float32
@[extern "tanf"] opaque Float32.tan : Float32 → Float32
@[extern "asinf"] opaque Float32.asin : Float32 → Float32
@[extern "acosf"] opaque Float32.acos : Float32 → Float32
@[extern "atanf"] opaque Float32.atan : Float32 → Float32
@[extern "atan2f"] opaque Float32.atan2 : Float32 → Float32 → Float32
@[extern "sinhf"] opaque Float32.sinh : Float32 → Float32
@[extern "coshf"] opaque Float32.cosh : Float32 → Float32
@[extern "tanhf"] opaque Float32.tanh : Float32 → Float32
@[extern "asinhf"] opaque Float32.asinh : Float32 → Float32
@[extern "acoshf"] opaque Float32.acosh : Float32 → Float32
@[extern "atanhf"] opaque Float32.atanh : Float32 → Float32
@[extern "expf"] opaque Float32.exp : Float32 → Float32
@[extern "exp2f"] opaque Float32.exp2 : Float32 → Float32
@[extern "logf"] opaque Float32.log : Float32 → Float32
@[extern "log2f"] opaque Float32.log2 : Float32 → Float32
@[extern "log10f"] opaque Float32.log10 : Float32 → Float32
@[extern "powf"] opaque Float32.pow : Float32 → Float32 → Float32
@[extern "sqrtf"] opaque Float32.sqrt : Float32 → Float32
@[extern "cbrtf"] opaque Float32.cbrt : Float32 → Float32
@[extern "ceilf"] opaque Float32.ceil : Float32 → Float32
@[extern "floorf"] opaque Float32.floor : Float32 → Float32
@[extern "roundf"] opaque Float32.round : Float32 → Float32
@[extern "fabsf"] opaque Float32.abs : Float32 → Float32
instance : HomogeneousPow Float32 := ⟨Float32.pow⟩
instance : Min Float32 := minOfLe
instance : Max Float32 := maxOfLe
/--
Efficiently computes `x * 2^i`.
-/
@[extern "lean_float32_scaleb"]
opaque Float32.scaleB (x : Float32) (i : @& Int) : Float32
-/

View File

@@ -46,8 +46,8 @@ def uget : (a : @& FloatArray) → (i : USize) → i.toNat < a.size → Float
| ds, i, h => ds[i]
@[extern "lean_float_array_fget"]
def get : (ds : @& FloatArray) (@& Fin ds.size) Float
| ds, i => ds.get i
def get : (ds : @& FloatArray) (i : @& Nat) (h : i < ds.size := by get_elem_tactic) Float
| ds, i, h => ds.get i h
@[extern "lean_float_array_get"]
def get! : (@& FloatArray) (@& Nat) Float
@@ -55,23 +55,23 @@ def get! : (@& FloatArray) → (@& Nat) → Float
def get? (ds : FloatArray) (i : Nat) : Option Float :=
if h : i < ds.size then
ds.get i, h
some (ds.get i h)
else
none
instance : GetElem FloatArray Nat Float fun xs i => i < xs.size where
getElem xs i h := xs.get i, h
getElem xs i h := xs.get i h
instance : GetElem FloatArray USize Float fun xs i => i.val < xs.size where
getElem xs i h := xs.uget i h
@[extern "lean_float_array_uset"]
def uset : (a : FloatArray) (i : USize) Float i.toNat < a.size FloatArray
def uset : (a : FloatArray) (i : USize) Float (h : i.toNat < a.size := by get_elem_tactic) FloatArray
| ds, i, v, h => ds.uset i v h
@[extern "lean_float_array_fset"]
def set : (ds : FloatArray) (@& Fin ds.size) Float FloatArray
| ds, i, d => ds.set i d
def set : (ds : FloatArray) (i : @& Nat) Float (h : i < ds.size := by get_elem_tactic) FloatArray
| ds, i, d, h => ds.set i d h
@[extern "lean_float_array_set"]
def set! : FloatArray (@& Nat) Float FloatArray
@@ -83,7 +83,7 @@ def isEmpty (s : FloatArray) : Bool :=
partial def toList (ds : FloatArray) : List Float :=
let rec loop (i r) :=
if h : i < ds.size then
loop (i+1) (ds.get i, h :: r)
loop (i+1) (ds[i] :: r)
else
r.reverse
loop 0 []
@@ -115,7 +115,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : FloatA
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
match ( f (as.get as.size - 1 - i, this) b) with
match ( f as[as.size - 1 - i] b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
@@ -149,7 +149,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → Float →
match i with
| 0 => pure b
| i'+1 =>
loop i' (j+1) ( f b (as.get j, Nat.lt_of_lt_of_le hlt h))
loop i' (j+1) ( f b (as[j]'(Nat.lt_of_lt_of_le hlt h)))
else
pure b
loop (stop - start) start init

View File

@@ -48,6 +48,9 @@ instance : Hashable UInt64 where
instance : Hashable USize where
hash n := n.toUInt64
instance : Hashable ByteArray where
hash as := as.foldl (fun r a => mixHash r (hash a)) 7
instance : Hashable (Fin n) where
hash v := v.val.toUInt64

View File

@@ -34,4 +34,8 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
simp [Int.shiftRight_eq_div_pow]
@[simp]
theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
simp [Int.shiftRight_eq_div_pow]
end Int

View File

@@ -29,6 +29,8 @@ At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with
In September 2024, we decided to do this rename (with deprecations in place),
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
ever need to use these functions and their associated lemmas.
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
-/
/-! ### T-rounding division -/
@@ -71,8 +73,6 @@ def tdiv : (@& Int) → (@& Int) → Int
| -[m +1], ofNat n => -ofNat (succ m / n)
| -[m +1], -[n +1] => ofNat (succ m / succ n)
@[deprecated tdiv (since := "2024-09-11")] abbrev div := tdiv
/-- Integer modulo. This function uses the
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
@@ -107,8 +107,6 @@ def tmod : (@& Int) → (@& Int) → Int
| -[m +1], ofNat n => -ofNat (succ m % n)
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
@[deprecated tmod (since := "2024-09-11")] abbrev mod := tmod
/-! ### F-rounding division
This pair satisfies `fdiv x y = floor (x / y)`.
-/
@@ -251,8 +249,6 @@ instance : Mod Int where
theorem ofNat_tdiv (m n : Nat) : (m / n) = tdiv m n := rfl
@[deprecated ofNat_tdiv (since := "2024-09-11")] abbrev ofNat_div := ofNat_tdiv
theorem ofNat_fdiv : m n : Nat, (m / n) = fdiv m n
| 0, _ => by simp [fdiv]
| succ _, _ => rfl

View File

@@ -125,7 +125,7 @@ theorem eq_one_of_mul_eq_one_right {a b : Int} (H : 0 ≤ a) (H' : a * b = 1) :
eq_one_of_dvd_one H b, H'.symm
theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 b) (H' : a * b = 1) : b = 1 :=
eq_one_of_mul_eq_one_right H <| by rw [Int.mul_comm, H']
eq_one_of_mul_eq_one_right (b := a) H <| by rw [Int.mul_comm, H']
/-! ### *div zero -/
@@ -1267,7 +1267,7 @@ theorem bmod_le {x : Int} {m : Nat} (h : 0 < m) : bmod x m ≤ (m - 1) / 2 := by
_ = ((m + 1 - 2) + 2)/2 := by simp
_ = (m - 1) / 2 + 1 := by
rw [add_ediv_of_dvd_right]
· simp (config := {decide := true}) only [Int.ediv_self]
· simp +decide only [Int.ediv_self]
congr 2
rw [Int.add_sub_assoc, Int.sub_neg]
congr
@@ -1285,7 +1285,7 @@ theorem bmod_natAbs_plus_one (x : Int) (w : 1 < x.natAbs) : bmod x (x.natAbs + 1
simp only [bmod, ofNat_eq_coe, natAbs_ofNat, natCast_add, ofNat_one,
emod_self_add_one (ofNat_nonneg x)]
match x with
| 0 => rw [if_pos] <;> simp (config := {decide := true})
| 0 => rw [if_pos] <;> simp +decide
| (x+1) =>
rw [if_neg]
· simp [ Int.sub_sub]
@@ -1315,65 +1315,3 @@ theorem bmod_natAbs_plus_one (x : Int) (w : 1 < x.natAbs) : bmod x (x.natAbs + 1
all_goals decide
· exact ofNat_nonneg x
· exact succ_ofNat_pos (x + 1)
/-! ### Deprecations -/
@[deprecated Int.zero_tdiv (since := "2024-09-11")] protected abbrev zero_div := @Int.zero_tdiv
@[deprecated Int.tdiv_zero (since := "2024-09-11")] protected abbrev div_zero := @Int.tdiv_zero
@[deprecated tdiv_eq_ediv (since := "2024-09-11")] abbrev div_eq_ediv := @tdiv_eq_ediv
@[deprecated fdiv_eq_tdiv (since := "2024-09-11")] abbrev fdiv_eq_div := @fdiv_eq_tdiv
@[deprecated zero_tmod (since := "2024-09-11")] abbrev zero_mod := @zero_tmod
@[deprecated tmod_zero (since := "2024-09-11")] abbrev mod_zero := @tmod_zero
@[deprecated tmod_add_tdiv (since := "2024-09-11")] abbrev mod_add_div := @tmod_add_tdiv
@[deprecated tdiv_add_tmod (since := "2024-09-11")] abbrev div_add_mod := @tdiv_add_tmod
@[deprecated tmod_add_tdiv' (since := "2024-09-11")] abbrev mod_add_div' := @tmod_add_tdiv'
@[deprecated tdiv_add_tmod' (since := "2024-09-11")] abbrev div_add_mod' := @tdiv_add_tmod'
@[deprecated tmod_def (since := "2024-09-11")] abbrev mod_def := @tmod_def
@[deprecated tmod_eq_emod (since := "2024-09-11")] abbrev mod_eq_emod := @tmod_eq_emod
@[deprecated fmod_eq_tmod (since := "2024-09-11")] abbrev fmod_eq_mod := @fmod_eq_tmod
@[deprecated Int.tdiv_one (since := "2024-09-11")] protected abbrev div_one := @Int.tdiv_one
@[deprecated Int.tdiv_neg (since := "2024-09-11")] protected abbrev div_neg := @Int.tdiv_neg
@[deprecated Int.neg_tdiv (since := "2024-09-11")] protected abbrev neg_div := @Int.neg_tdiv
@[deprecated Int.neg_tdiv_neg (since := "2024-09-11")] protected abbrev neg_div_neg := @Int.neg_tdiv_neg
@[deprecated Int.tdiv_nonneg (since := "2024-09-11")] protected abbrev div_nonneg := @Int.tdiv_nonneg
@[deprecated Int.tdiv_nonpos (since := "2024-09-11")] protected abbrev div_nonpos := @Int.tdiv_nonpos
@[deprecated Int.tdiv_eq_zero_of_lt (since := "2024-09-11")] abbrev div_eq_zero_of_lt := @Int.tdiv_eq_zero_of_lt
@[deprecated Int.mul_tdiv_cancel (since := "2024-09-11")] protected abbrev mul_div_cancel := @Int.mul_tdiv_cancel
@[deprecated Int.mul_tdiv_cancel_left (since := "2024-09-11")] protected abbrev mul_div_cancel_left := @Int.mul_tdiv_cancel_left
@[deprecated Int.tdiv_self (since := "2024-09-11")] protected abbrev div_self := @Int.tdiv_self
@[deprecated Int.mul_tdiv_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev mul_div_cancel_of_mod_eq_zero := @Int.mul_tdiv_cancel_of_tmod_eq_zero
@[deprecated Int.tdiv_mul_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev div_mul_cancel_of_mod_eq_zero := @Int.tdiv_mul_cancel_of_tmod_eq_zero
@[deprecated Int.dvd_of_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_of_mod_eq_zero := @Int.dvd_of_tmod_eq_zero
@[deprecated Int.mul_tdiv_assoc (since := "2024-09-11")] protected abbrev mul_div_assoc := @Int.mul_tdiv_assoc
@[deprecated Int.mul_tdiv_assoc' (since := "2024-09-11")] protected abbrev mul_div_assoc' := @Int.mul_tdiv_assoc'
@[deprecated Int.tdiv_dvd_tdiv (since := "2024-09-11")] abbrev div_dvd_div := @Int.tdiv_dvd_tdiv
@[deprecated Int.natAbs_tdiv (since := "2024-09-11")] abbrev natAbs_div := @Int.natAbs_tdiv
@[deprecated Int.tdiv_eq_of_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_right := @Int.tdiv_eq_of_eq_mul_right
@[deprecated Int.eq_tdiv_of_mul_eq_right (since := "2024-09-11")] protected abbrev eq_div_of_mul_eq_right := @Int.eq_tdiv_of_mul_eq_right
@[deprecated Int.ofNat_tmod (since := "2024-09-11")] abbrev ofNat_mod := @Int.ofNat_tmod
@[deprecated Int.tmod_one (since := "2024-09-11")] abbrev mod_one := @Int.tmod_one
@[deprecated Int.tmod_eq_of_lt (since := "2024-09-11")] abbrev mod_eq_of_lt := @Int.tmod_eq_of_lt
@[deprecated Int.tmod_lt_of_pos (since := "2024-09-11")] abbrev mod_lt_of_pos := @Int.tmod_lt_of_pos
@[deprecated Int.tmod_nonneg (since := "2024-09-11")] abbrev mod_nonneg := @Int.tmod_nonneg
@[deprecated Int.tmod_neg (since := "2024-09-11")] abbrev mod_neg := @Int.tmod_neg
@[deprecated Int.mul_tmod_left (since := "2024-09-11")] abbrev mul_mod_left := @Int.mul_tmod_left
@[deprecated Int.mul_tmod_right (since := "2024-09-11")] abbrev mul_mod_right := @Int.mul_tmod_right
@[deprecated Int.tmod_eq_zero_of_dvd (since := "2024-09-11")] abbrev mod_eq_zero_of_dvd := @Int.tmod_eq_zero_of_dvd
@[deprecated Int.dvd_iff_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_iff_mod_eq_zero := @Int.dvd_iff_tmod_eq_zero
@[deprecated Int.neg_mul_tmod_right (since := "2024-09-11")] abbrev neg_mul_mod_right := @Int.neg_mul_tmod_right
@[deprecated Int.neg_mul_tmod_left (since := "2024-09-11")] abbrev neg_mul_mod_left := @Int.neg_mul_tmod_left
@[deprecated Int.tdiv_mul_cancel (since := "2024-09-11")] protected abbrev div_mul_cancel := @Int.tdiv_mul_cancel
@[deprecated Int.mul_tdiv_cancel' (since := "2024-09-11")] protected abbrev mul_div_cancel' := @Int.mul_tdiv_cancel'
@[deprecated Int.eq_mul_of_tdiv_eq_right (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_right := @Int.eq_mul_of_tdiv_eq_right
@[deprecated Int.tmod_self (since := "2024-09-11")] abbrev mod_self := @Int.tmod_self
@[deprecated Int.neg_tmod_self (since := "2024-09-11")] abbrev neg_mod_self := @Int.neg_tmod_self
@[deprecated Int.lt_tdiv_add_one_mul_self (since := "2024-09-11")] abbrev lt_div_add_one_mul_self := @Int.lt_tdiv_add_one_mul_self
@[deprecated Int.tdiv_eq_iff_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_right := @Int.tdiv_eq_iff_eq_mul_right
@[deprecated Int.tdiv_eq_iff_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_left := @Int.tdiv_eq_iff_eq_mul_left
@[deprecated Int.eq_mul_of_tdiv_eq_left (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_left := @Int.eq_mul_of_tdiv_eq_left
@[deprecated Int.tdiv_eq_of_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_left := @Int.tdiv_eq_of_eq_mul_left
@[deprecated Int.eq_zero_of_tdiv_eq_zero (since := "2024-09-11")] protected abbrev eq_zero_of_div_eq_zero := @Int.eq_zero_of_tdiv_eq_zero
@[deprecated Int.tdiv_left_inj (since := "2024-09-11")] protected abbrev div_left_inj := @Int.tdiv_left_inj
@[deprecated Int.tdiv_sign (since := "2024-09-11")] abbrev div_sign := @Int.tdiv_sign
@[deprecated Int.sign_eq_tdiv_abs (since := "2024-09-11")] protected abbrev sign_eq_div_abs := @Int.sign_eq_tdiv_abs
@[deprecated Int.tdiv_eq_ediv_of_dvd (since := "2024-09-11")] abbrev div_eq_ediv_of_dvd := @Int.tdiv_eq_ediv_of_dvd

View File

@@ -329,22 +329,22 @@ theorem toNat_sub (m n : Nat) : toNat (m - n) = m - n := by
/- ## add/sub injectivity -/
@[simp]
protected theorem add_right_inj {i j : Int} (k : Int) : (i + k = j + k) i = j := by
protected theorem add_left_inj {i j : Int} (k : Int) : (i + k = j + k) i = j := by
apply Iff.intro
· intro p
rw [Int.add_sub_cancel i k, Int.add_sub_cancel j k, p]
· exact congrArg (· + k)
@[simp]
protected theorem add_left_inj {i j : Int} (k : Int) : (k + i = k + j) i = j := by
protected theorem add_right_inj {i j : Int} (k : Int) : (k + i = k + j) i = j := by
simp [Int.add_comm k]
@[simp]
protected theorem sub_left_inj {i j : Int} (k : Int) : (k - i = k - j) i = j := by
protected theorem sub_right_inj {i j : Int} (k : Int) : (k - i = k - j) i = j := by
simp [Int.sub_eq_add_neg, Int.neg_inj]
@[simp]
protected theorem sub_right_inj {i j : Int} (k : Int) : (i - k = j - k) i = j := by
protected theorem sub_left_inj {i j : Int} (k : Int) : (i - k = j - k) i = j := by
simp [Int.sub_eq_add_neg]
/- ## Ring properties -/

View File

@@ -1007,9 +1007,9 @@ theorem sign_eq_neg_one_iff_neg {a : Int} : sign a = -1 ↔ a < 0 :=
match x with
| 0 => rfl
| .ofNat (_ + 1) =>
simp (config := { decide := true }) only [sign, true_iff]
simp +decide only [sign, true_iff]
exact Int.le_add_one (ofNat_nonneg _)
| .negSucc _ => simp (config := { decide := true }) [sign]
| .negSucc _ => simp +decide [sign]
theorem mul_sign : i : Int, i * sign i = natAbs i
| succ _ => Int.mul_one _

View File

@@ -24,4 +24,7 @@ import Init.Data.List.Zip
import Init.Data.List.Perm
import Init.Data.List.Sort
import Init.Data.List.ToArray
import Init.Data.List.ToArrayImpl
import Init.Data.List.MapIdx
import Init.Data.List.OfFn
import Init.Data.List.FinRange

View File

@@ -13,7 +13,7 @@ namespace List
`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`. -/
@[simp] def pmap {P : α Prop} (f : a, P a β) : l : List α, (H : a l, P a) List β
def pmap {P : α Prop} (f : a, P a β) : l : List α, (H : a l, P a) List β
| [], _ => []
| a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2
@@ -46,6 +46,11 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
| cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx)
exact go L h'
@[simp] theorem pmap_nil {P : α Prop} (f : a, P a β) : pmap f [] (by simp) = [] := rfl
@[simp] theorem pmap_cons {P : α Prop} (f : a, P a β) (a : α) (l : List α) (h : b a :: l, P b) :
pmap f (a :: l) h = f a (forall_mem_cons.1 h).1 :: pmap f l (forall_mem_cons.1 h).2 := rfl
@[simp] theorem attach_nil : ([] : List α).attach = [] := rfl
@[simp] theorem attachWith_nil : ([] : List α).attachWith P H = [] := rfl
@@ -148,7 +153,7 @@ theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h :
exact a, h, rfl
@[simp]
theorem length_pmap {p : α Prop} {f : a, p a β} {l H} : length (pmap f l H) = length l := by
theorem length_pmap {p : α Prop} {f : a, p a β} {l H} : (pmap f l H).length = l.length := by
induction l
· rfl
· simp only [*, pmap, length]
@@ -169,6 +174,13 @@ theorem pmap_ne_nil_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Li
(H : (a : α), a xs P a) : xs.pmap f H [] xs [] := by
simp
theorem pmap_eq_self {l : List α} {p : α Prop} (hp : (a : α), a l p a)
(f : (a : α) p a α) : l.pmap f hp = l a (h : a l), f a (hp a h) = a := by
rw [pmap_eq_map_attach]
conv => lhs; rhs; rw [ attach_map_subtype_val l]
rw [map_inj_left]
simp
@[simp]
theorem attach_eq_nil_iff {l : List α} : l.attach = [] l = [] :=
pmap_eq_nil_iff
@@ -192,7 +204,7 @@ theorem attachWith_ne_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l,
@[simp]
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) (n : Nat) :
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (getElem?_mem H) := by
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
induction l generalizing n with
| nil => simp
| cons hd tl hl =>
@@ -208,7 +220,7 @@ theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h
· simp_all
theorem get?_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) (n : Nat) :
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (get?_mem H) := by
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (mem_of_get? H) := by
simp only [get?_eq_getElem?]
simp [getElem?_pmap, h]
@@ -231,18 +243,18 @@ theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h :
(hn : n < (pmap f l h).length) :
get (pmap f l h) n, hn =
f (get l n, @length_pmap _ _ p f l h hn)
(h _ (get_mem l n (@length_pmap _ _ p f l h hn))) := by
(h _ (getElem_mem (@length_pmap _ _ p f l h hn))) := by
simp only [get_eq_getElem]
simp [getElem_pmap]
@[simp]
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α Prop} {H : a xs, P a} :
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (getElem?_mem a)) :=
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
getElem?_pmap ..
@[simp]
theorem getElem?_attach {xs : List α} {i : Nat} :
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => getElem?_mem a) :=
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
getElem?_attachWith
@[simp]
@@ -326,6 +338,7 @@ This is useful when we need to use `attach` to show termination.
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
and even when rewriting we need to specify the function explicitly.
See however `foldl_subtype` below.
-/
theorem foldl_attach (l : List α) (f : β α β) (b : β) :
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
@@ -341,6 +354,7 @@ This is useful when we need to use `attach` to show termination.
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
and even when rewriting we need to specify the function explicitly.
See however `foldr_subtype` below.
-/
theorem foldr_attach (l : List α) (f : α β β) (b : β) :
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
@@ -445,16 +459,16 @@ theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ l₂ :
pmap_append f l₁ l₂ _
@[simp] theorem attach_append (xs ys : List α) :
(xs ++ ys).attach = xs.attach.map (fun x, h => x, mem_append_of_mem_left ys h) ++
ys.attach.map fun x, h => x, mem_append_of_mem_right xs h := by
(xs ++ ys).attach = xs.attach.map (fun x, h => x, mem_append_left ys h) ++
ys.attach.map fun x, h => x, mem_append_right xs h := by
simp only [attach, attachWith, pmap, map_pmap, pmap_append]
congr 1 <;>
exact pmap_congr_left _ fun _ _ _ _ => rfl
@[simp] theorem attachWith_append {P : α Prop} {xs ys : List α}
{H : (a : α), a xs ++ ys P a} :
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_of_mem_left ys h)) ++
ys.attachWith P (fun a h => H a (mem_append_of_mem_right xs h)) := by
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
simp only [attachWith, attach_append, map_pmap, pmap_append]
@[simp] theorem pmap_reverse {P : α Prop} (f : (a : α) P a β) (xs : List α)
@@ -591,6 +605,15 @@ def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) := l.map (
| nil => simp
| cons a l ih => simp [ih, Function.comp_def]
@[simp] theorem getElem?_unattach {p : α Prop} {l : List { x // p x }} (i : Nat) :
l.unattach[i]? = l[i]?.map Subtype.val := by
simp [unattach]
@[simp] theorem getElem_unattach
{p : α Prop} {l : List { x // p x }} (i : Nat) (h : i < l.unattach.length) :
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
simp [unattach]
/-! ### Recognizing higher order functions on subtypes using a function that only depends on the value. -/
/--

View File

@@ -29,7 +29,7 @@ The operations are organized as follow:
* Lexicographic ordering: `lt`, `le`, and instances.
* Head and tail operators: `head`, `head?`, `headD?`, `tail`, `tail?`, `tailD`.
* Basic operations:
`map`, `filter`, `filterMap`, `foldr`, `append`, `flatten`, `pure`, `bind`, `replicate`, and
`map`, `filter`, `filterMap`, `foldr`, `append`, `flatten`, `pure`, `flatMap`, `replicate`, and
`reverse`.
* Additional functions defined in terms of these: `leftpad`, `rightPad`, and `reduceOption`.
* Operations using indexes: `mapIdx`.
@@ -38,14 +38,14 @@ The operations are organized as follow:
* Sublists: `take`, `drop`, `takeWhile`, `dropWhile`, `partition`, `dropLast`,
`isPrefixOf`, `isPrefixOf?`, `isSuffixOf`, `isSuffixOf?`, `Subset`, `Sublist`,
`rotateLeft` and `rotateRight`.
* Manipulating elements: `replace`, `insert`, `erase`, `eraseP`, `eraseIdx`.
* Manipulating elements: `replace`, `modify`, `insert`, `insertIdx`, `erase`, `eraseP`, `eraseIdx`.
* Finding elements: `find?`, `findSome?`, `findIdx`, `indexOf`, `findIdx?`, `indexOf?`,
`countP`, `count`, and `lookup`.
* Logic: `any`, `all`, `or`, and `and`.
* Zippers: `zipWith`, `zip`, `zipWithAll`, and `unzip`.
* Ranges and enumeration: `range`, `iota`, `enumFrom`, and `enum`.
* Minima and maxima: `min?` and `max?`.
* Other functions: `intersperse`, `intercalate`, `eraseDups`, `eraseReps`, `span`, `groupBy`,
* Other functions: `intersperse`, `intercalate`, `eraseDups`, `eraseReps`, `span`, `splitBy`,
`removeAll`
(currently these functions are mostly only used in meta code,
and do not have API suitable for verification).
@@ -231,7 +231,7 @@ theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n)
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
/-- Deprecated alias for `ext_get?`. The preferred extensionality theorem is now `ext_getElem?`. -/
@[deprecated (since := "2024-06-07")] abbrev ext := @ext_get?
@[deprecated ext_get? (since := "2024-06-07")] abbrev ext := @ext_get?
/-! ### getD -/
@@ -551,7 +551,7 @@ theorem reverseAux_eq_append (as bs : List α) : reverseAux as bs = reverseAux a
/-! ### flatten -/
/--
`O(|flatten L|)`. `join L` concatenates all the lists in `L` into one list.
`O(|flatten L|)`. `flatten L` concatenates all the lists in `L` into one list.
* `flatten [[a], [], [b, c], [d, e, f]] = [a, b, c, d, e, f]`
-/
def flatten : List (List α) List α
@@ -682,7 +682,7 @@ theorem elem_cons [BEq α] {a : α} :
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
/-- `notElem a l` is `!(elem a l)`. -/
@[deprecated (since := "2024-06-15")]
@[deprecated "Use `!(elem a l)` instead."(since := "2024-06-15")]
def notElem [BEq α] (a : α) (as : List α) : Bool :=
!(as.elem a)
@@ -726,13 +726,13 @@ theorem elem_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : List α} (h :
instance [BEq α] [LawfulBEq α] (a : α) (as : List α) : Decidable (a as) :=
decidable_of_decidable_of_iff (Iff.intro mem_of_elem_eq_true elem_eq_true_of_mem)
theorem mem_append_of_mem_left {a : α} {as : List α} (bs : List α) : a as a as ++ bs := by
theorem mem_append_left {a : α} {as : List α} (bs : List α) : a as a as ++ bs := by
intro h
induction h with
| head => apply Mem.head
| tail => apply Mem.tail; assumption
theorem mem_append_of_mem_right {b : α} {bs : List α} (as : List α) : b bs b as ++ bs := by
theorem mem_append_right {b : α} {bs : List α} (as : List α) : b bs b as ++ bs := by
intro h
induction as with
| nil => simp [h]
@@ -1113,12 +1113,50 @@ theorem replace_cons [BEq α] {a : α} :
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
rfl
/-! ### modify -/
/--
Apply a function to the nth tail of `l`. Returns the input without
using `f` if the index is larger than the length of the List.
```
modifyTailIdx f 2 [a, b, c] = [a, b] ++ f [c]
```
-/
@[simp] def modifyTailIdx (f : List α List α) : Nat List α List α
| 0, l => f l
| _+1, [] => []
| n+1, a :: l => a :: modifyTailIdx f n l
/-- Apply `f` to the head of the list, if it exists. -/
@[inline] def modifyHead (f : α α) : List α List α
| [] => []
| a :: l => f a :: l
@[simp] theorem modifyHead_nil (f : α α) : [].modifyHead f = [] := by rw [modifyHead]
@[simp] theorem modifyHead_cons (a : α) (l : List α) (f : α α) :
(a :: l).modifyHead f = f a :: l := by rw [modifyHead]
/--
Apply `f` to the nth element of the list, if it exists, replacing that element with the result.
-/
def modify (f : α α) : Nat List α List α :=
modifyTailIdx (modifyHead f)
/-! ### insert -/
/-- Inserts an element into a list without duplication. -/
@[inline] protected def insert [BEq α] (a : α) (l : List α) : List α :=
if l.elem a then l else a :: l
/--
`insertIdx n a l` inserts `a` into the list `l` after the first `n` elements of `l`
```
insertIdx 2 1 [1, 2, 3, 4] = [1, 2, 1, 3, 4]
```
-/
def insertIdx (n : Nat) (a : α) : List α List α :=
modifyTailIdx (cons a) n
/-! ### erase -/
/--
@@ -1389,10 +1427,10 @@ def zipWithAll (f : Option α → Option β → γ) : List α → List β → Li
| a :: as, [] => (a :: as).map fun a => f (some a) none
| a :: as, b :: bs => f a b :: zipWithAll f as bs
@[simp] theorem zipWithAll_nil_right :
@[simp] theorem zipWithAll_nil :
zipWithAll f as [] = as.map fun a => f (some a) none := by
cases as <;> rfl
@[simp] theorem zipWithAll_nil_left :
@[simp] theorem nil_zipWithAll :
zipWithAll f [] bs = bs.map fun b => f none (some b) := rfl
@[simp] theorem zipWithAll_cons_cons :
zipWithAll f (a :: as) (b :: bs) = f (some a) (some b) :: zipWithAll f as bs := rfl
@@ -1610,23 +1648,23 @@ where
| true => loop as (a::rs)
| false => (rs.reverse, a::as)
/-! ### groupBy -/
/-! ### splitBy -/
/--
`O(|l|)`. `groupBy R l` splits `l` into chains of elements
`O(|l|)`. `splitBy R l` splits `l` into chains of elements
such that adjacent elements are related by `R`.
* `groupBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]`
* `groupBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]`
* `splitBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]`
* `splitBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]`
-/
@[specialize] def groupBy (R : α α Bool) : List α List (List α)
@[specialize] def splitBy (R : α α Bool) : List α List (List α)
| [] => []
| a::as => loop as a [] []
where
/--
The arguments of `groupBy.loop l ag g gs` represent the following:
The arguments of `splitBy.loop l ag g gs` represent the following:
- `l : List α` are the elements which we still need to group.
- `l : List α` are the elements which we still need to split.
- `ag : α` is the previous element for which a comparison was performed.
- `g : List α` is the group currently being assembled, in **reverse order**.
- `gs : List (List α)` is all of the groups that have been completed, in **reverse order**.
@@ -1637,6 +1675,8 @@ where
| false => loop as a [] ((ag::g).reverse::gs)
| [], ag, g, gs => ((ag::g).reverse::gs).reverse
@[deprecated splitBy (since := "2024-10-30"), inherit_doc splitBy] abbrev groupBy := @splitBy
/-! ### removeAll -/
/-- `O(|xs|)`. Computes the "set difference" of lists,

View File

@@ -155,7 +155,8 @@ def mapMono (as : List α) (f : αα) : List α :=
/-! ## Additional lemmas required for bootstrapping `Array`. -/
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h'} : (as ++ bs)[i] = as[i] := by
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h' : i < (as ++ bs).length} :
(as ++ bs)[i] = as[i] := by
induction as generalizing i with
| nil => trivial
| cons a as ih =>

View File

@@ -5,6 +5,8 @@ Author: Leonardo de Moura
-/
prelude
import Init.Control.Basic
import Init.Control.Id
import Init.Control.Lawful
import Init.Data.List.Basic
namespace List
@@ -207,6 +209,16 @@ def findM? {m : Type → Type u} [Monad m] {α : Type} (p : α → m Bool) : Lis
| true => pure (some a)
| false => findM? p as
@[simp]
theorem findM?_id (p : α Bool) (as : List α) : findM? (m := Id) p as = as.find? p := by
induction as with
| nil => rfl
| cons a as ih =>
simp only [findM?, find?]
cases p a with
| true => rfl
| false => rw [ih]; rfl
@[specialize]
def findSomeM? {m : Type u Type v} [Monad m] {α : Type w} {β : Type u} (f : α m (Option β)) : List α m (Option β)
| [] => pure none
@@ -215,26 +227,27 @@ def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f
| some b => pure (some b)
| none => findSomeM? f as
@[inline] protected def forIn {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : List α) (init : β) (f : α β m (ForInStep β)) : m β :=
let rec @[specialize] loop
| [], b => pure b
| a::as, b => do
match ( f a b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop as b
loop as init
@[simp]
theorem findSomeM?_id (f : α Option β) (as : List α) : findSomeM? (m := Id) f as = as.findSome? f := by
induction as with
| nil => rfl
| cons a as ih =>
simp only [findSomeM?, findSome?]
cases f a with
| some b => rfl
| none => rw [ih]; rfl
instance : ForIn m (List α) α where
forIn := List.forIn
@[simp] theorem forIn_eq_forIn [Monad m] : @List.forIn α β m _ = forIn := rfl
@[simp] theorem forIn_nil [Monad m] (f : α β m (ForInStep β)) (b : β) : forIn [] b f = pure b :=
rfl
@[simp] theorem forIn_cons [Monad m] (f : α β m (ForInStep β)) (a : α) (as : List α) (b : β)
: forIn (a::as) b f = f a b >>= fun | ForInStep.done b => pure b | ForInStep.yield b => forIn as b f :=
rfl
theorem findM?_eq_findSomeM? [Monad m] [LawfulMonad m] (p : α m Bool) (as : List α) :
as.findM? p = as.findSomeM? fun a => return if ( p a) then some a else none := by
induction as with
| nil => rfl
| cons a as ih =>
simp only [findM?, findSomeM?]
simp [ih]
congr
apply funext
intro b
cases b <;> simp
@[inline] protected def forIn' {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : List α) (init : β) (f : (a : α) a as β m (ForInStep β)) : m β :=
let rec @[specialize] loop : (as' : List α) (b : β) Exists (fun bs => bs ++ as' = as) m β
@@ -243,7 +256,7 @@ instance : ForIn m (List α) α where
have : a as := by
have bs, h := h
subst h
exact mem_append_of_mem_right _ (Mem.head ..)
exact mem_append_right _ (Mem.head ..)
match ( f a this b) with
| ForInStep.done b => pure b
| ForInStep.yield b =>
@@ -254,14 +267,15 @@ instance : ForIn m (List α) α where
instance : ForIn' m (List α) α inferInstance where
forIn' := List.forIn'
@[simp] theorem forIn'_eq_forIn {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : List α) (init : β) (f : α β m (ForInStep β)) : forIn' as init (fun a _ b => f a b) = forIn as init f := by
simp [forIn', forIn, List.forIn, List.forIn']
have : cs h, List.forIn'.loop cs (fun a _ b => f a b) as init h = List.forIn.loop f as init := by
intro cs h
induction as generalizing cs init with
| nil => intros; rfl
| cons a as ih => intros; simp [List.forIn.loop, List.forIn'.loop, ih]
apply this
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
@[simp] theorem forIn'_eq_forIn' [Monad m] : @List.forIn' α β m _ = forIn' := rfl
@[simp] theorem forIn'_nil [Monad m] (f : (a : α) a [] β m (ForInStep β)) (b : β) : forIn' [] b f = pure b :=
rfl
@[simp] theorem forIn_nil [Monad m] (f : α β m (ForInStep β)) (b : β) : forIn [] b f = pure b :=
rfl
instance : ForM m (List α) α where
forM := List.forM

View File

@@ -153,7 +153,7 @@ theorem countP_filterMap (p : β → Bool) (f : α → Option β) (l : List α)
simp only [length_filterMap_eq_countP]
congr
ext a
simp (config := { contextual := true }) [Option.getD_eq_iff, Option.isSome_eq_isSome]
simp +contextual [Option.getD_eq_iff, Option.isSome_eq_isSome]
@[simp] theorem countP_flatten (l : List (List α)) :
countP p l.flatten = (l.map (countP p)).sum := by
@@ -162,6 +162,10 @@ theorem countP_filterMap (p : β → Bool) (f : α → Option β) (l : List α)
@[deprecated countP_flatten (since := "2024-10-14")] abbrev countP_join := @countP_flatten
theorem countP_flatMap (p : β Bool) (l : List α) (f : α List β) :
countP p (l.flatMap f) = sum (map (countP p f) l) := by
rw [List.flatMap, countP_flatten, map_map]
@[simp] theorem countP_reverse (l : List α) : countP p l.reverse = countP p l := by
simp [countP_eq_length_filter, filter_reverse]
@@ -315,7 +319,7 @@ theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = len
theorem count_le_count_map [DecidableEq β] (l : List α) (f : α β) (x : α) :
count x l count (f x) (map f l) := by
rw [count, count, countP_map]
apply countP_mono_left; simp (config := { contextual := true })
apply countP_mono_left; simp +contextual
theorem count_filterMap {α} [BEq β] (b : β) (f : α Option β) (l : List α) :
count b (filterMap f l) = countP (fun a => f a == some b) l := by
@@ -326,6 +330,9 @@ theorem count_filterMap {α} [BEq β] (b : β) (f : α → Option β) (l : List
· simp
· simp
theorem count_flatMap {α} [BEq β] (l : List α) (f : α List β) (x : β) :
count x (l.flatMap f) = sum (map (count x f) l) := countP_flatMap _ _ _
theorem count_erase (a b : α) :
l : List α, count a (l.erase b) = count a l - if b == a then 1 else 0
| [] => by simp

View File

@@ -0,0 +1,48 @@
/-
Copyright (c) 2024 François G. Dorais. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: François G. Dorais
-/
prelude
import Init.Data.List.OfFn
namespace List
/-- `finRange n` lists all elements of `Fin n` in order -/
def finRange (n : Nat) : List (Fin n) := ofFn fun i => i
@[simp] theorem length_finRange (n) : (List.finRange n).length = n := by
simp [List.finRange]
@[simp] theorem getElem_finRange (i : Nat) (h : i < (List.finRange n).length) :
(finRange n)[i] = Fin.cast (length_finRange n) i, h := by
simp [List.finRange]
@[simp] theorem finRange_zero : finRange 0 = [] := by simp [finRange, ofFn]
theorem finRange_succ (n) : finRange (n+1) = 0 :: (finRange n).map Fin.succ := by
apply List.ext_getElem; simp; intro i; cases i <;> simp
theorem finRange_succ_last (n) :
finRange (n+1) = (finRange n).map Fin.castSucc ++ [Fin.last n] := by
apply List.ext_getElem
· simp
· intros
simp only [List.finRange, List.getElem_ofFn, getElem_append, length_map, length_ofFn,
getElem_map, Fin.castSucc_mk, getElem_singleton]
split
· rfl
· next h => exact Fin.eq_last_of_not_lt h
theorem finRange_reverse (n) : (finRange n).reverse = (finRange n).map Fin.rev := by
induction n with
| zero => simp
| succ n ih =>
conv => lhs; rw [finRange_succ_last]
conv => rhs; rw [finRange_succ]
rw [reverse_append, reverse_cons, reverse_nil, nil_append, singleton_append, map_reverse,
map_cons, ih, map_map, map_map]
congr; funext
simp [Fin.rev_succ]
end List

View File

@@ -10,7 +10,8 @@ import Init.Data.List.Sublist
import Init.Data.List.Range
/-!
# Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, and `List.indexOf`.
Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, `List.indexOf`,
and `List.lookup`.
-/
namespace List
@@ -95,22 +96,22 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
· simp only [Option.guard_eq_none] at h
simp [ih, h]
@[simp] theorem filterMap_head? (f : α Option β) (l : List α) : (l.filterMap f).head? = l.findSome? f := by
@[simp] theorem head?_filterMap (f : α Option β) (l : List α) : (l.filterMap f).head? = l.findSome? f := by
induction l with
| nil => simp
| cons x xs ih =>
simp only [filterMap_cons, findSome?_cons]
split <;> simp [*]
@[simp] theorem filterMap_head (f : α Option β) (l : List α) (h) :
(l.filterMap f).head h = (l.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
@[simp] theorem head_filterMap (f : α Option β) (l : List α) (h) :
(l.filterMap f).head h = (l.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
simp [head_eq_iff_head?_eq_some]
@[simp] theorem filterMap_getLast? (f : α Option β) (l : List α) : (l.filterMap f).getLast? = l.reverse.findSome? f := by
@[simp] theorem getLast?_filterMap (f : α Option β) (l : List α) : (l.filterMap f).getLast? = l.reverse.findSome? f := by
rw [getLast?_eq_head?_reverse]
simp [ filterMap_reverse]
@[simp] theorem filterMap_getLast (f : α Option β) (l : List α) (h) :
@[simp] theorem getLast_filterMap (f : α Option β) (l : List α) (h) :
(l.filterMap f).getLast h = (l.reverse.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
simp [getLast_eq_iff_getLast_eq_some]
@@ -179,7 +180,7 @@ theorem IsPrefix.findSome?_eq_some {l₁ l₂ : List α} {f : α → Option β}
List.findSome? f l₁ = some b List.findSome? f l₂ = some b := by
rw [IsPrefix] at h
obtain t, rfl := h
simp (config := {contextual := true}) [findSome?_append]
simp +contextual [findSome?_append]
theorem IsPrefix.findSome?_eq_none {l₁ l₂ : List α} {f : α Option β} (h : l₁ <+: l₂) :
List.findSome? f l₂ = none List.findSome? f l₁ = none :=
@@ -206,7 +207,8 @@ theorem IsInfix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (
@[simp] theorem find?_eq_none : find? p l = none x l, ¬ p x := by
induction l <;> simp [find?_cons]; split <;> simp [*]
theorem find?_eq_some : xs.find? p = some b p b as bs, xs = as ++ b :: bs a as, !p a := by
theorem find?_eq_some_iff_append :
xs.find? p = some b p b as bs, xs = as ++ b :: bs a as, !p a := by
induction xs with
| nil => simp
| cons x xs ih =>
@@ -242,6 +244,9 @@ theorem find?_eq_some : xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b
cases h₁
simp
@[deprecated find?_eq_some_iff_append (since := "2024-11-06")]
abbrev find?_eq_some := @find?_eq_some_iff_append
@[simp]
theorem find?_cons_eq_some : (a :: xs).find? p = some b (p a a = b) (!p a xs.find? p = some b) := by
rw [find?_cons]
@@ -287,18 +292,18 @@ theorem get_find?_mem (xs : List α) (p : α → Bool) (h) : (xs.find? p).get h
· simp only [find?_cons]
split <;> simp_all
@[simp] theorem filter_head? (p : α Bool) (l : List α) : (l.filter p).head? = l.find? p := by
rw [ filterMap_eq_filter, filterMap_head?, findSome?_guard]
@[simp] theorem head?_filter (p : α Bool) (l : List α) : (l.filter p).head? = l.find? p := by
rw [ filterMap_eq_filter, head?_filterMap, findSome?_guard]
@[simp] theorem filter_head (p : α Bool) (l : List α) (h) :
@[simp] theorem head_filter (p : α Bool) (l : List α) (h) :
(l.filter p).head h = (l.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
simp [head_eq_iff_head?_eq_some]
@[simp] theorem filter_getLast? (p : α Bool) (l : List α) : (l.filter p).getLast? = l.reverse.find? p := by
@[simp] theorem getLast?_filter (p : α Bool) (l : List α) : (l.filter p).getLast? = l.reverse.find? p := by
rw [getLast?_eq_head?_reverse]
simp [ filter_reverse]
@[simp] theorem filter_getLast (p : α Bool) (l : List α) (h) :
@[simp] theorem getLast_filter (p : α Bool) (l : List α) (h) :
(l.filter p).getLast h = (l.reverse.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
simp [getLast_eq_iff_getLast_eq_some]
@@ -347,7 +352,7 @@ theorem find?_flatten_eq_some {xs : List (List α)} {p : α → Bool} {a : α} :
xs.flatten.find? p = some a
p a as ys zs bs, xs = as ++ (ys ++ a :: zs) :: bs
( a as, x a, !p x) ( x ys, !p x) := by
rw [find?_eq_some]
rw [find?_eq_some_iff_append]
constructor
· rintro h, ys, zs, h₁, h₂
refine h, ?_
@@ -436,7 +441,7 @@ theorem IsPrefix.find?_eq_some {l₁ l₂ : List α} {p : α → Bool} (h : l₁
List.find? p l₁ = some b List.find? p l₂ = some b := by
rw [IsPrefix] at h
obtain t, rfl := h
simp (config := {contextual := true}) [find?_append]
simp +contextual [find?_append]
theorem IsPrefix.find?_eq_none {l₁ l₂ : List α} {p : α Bool} (h : l₁ <+: l₂) :
List.find? p l₂ = none List.find? p l₁ = none :=
@@ -562,7 +567,7 @@ theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
| inr e =>
have ipm := Nat.succ_pred_eq_of_pos e
have ilt := Nat.le_trans ho (findIdx_le_length p)
simp (config := { singlePass := true }) only [ ipm, getElem_cons_succ]
simp +singlePass only [ ipm, getElem_cons_succ]
rw [ ipm, Nat.succ_lt_succ_iff] at h
simpa using ih h
@@ -595,15 +600,14 @@ theorem findIdx_eq {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.length
theorem findIdx_append (p : α Bool) (l₁ l₂ : List α) :
(l₁ ++ l₂).findIdx p =
if x, x l₁ p x = true then l₁.findIdx p else l₂.findIdx p + l₁.length := by
if l₁.findIdx p < l₁.length then l₁.findIdx p else l₂.findIdx p + l₁.length := by
induction l₁ with
| nil => simp
| cons x xs ih =>
simp only [findIdx_cons, length_cons, cons_append]
by_cases h : p x
· simp [h]
· simp only [h, ih, cond_eq_if, Bool.false_eq_true, reduceIte, mem_cons, exists_eq_or_imp,
false_or]
· simp only [h, ih, cond_eq_if, Bool.false_eq_true, reduceIte, add_one_lt_add_one_iff]
split <;> simp [Nat.add_assoc]
theorem IsPrefix.findIdx_le {l₁ l₂ : List α} {p : α Bool} (h : l₁ <+: l₂) :

View File

@@ -23,7 +23,7 @@ namespace List
The following operations are already tail-recursive, and do not need `@[csimp]` replacements:
`get`, `foldl`, `beq`, `isEqv`, `reverse`, `elem` (and hence `contains`), `drop`, `dropWhile`,
`partition`, `isPrefixOf`, `isPrefixOf?`, `find?`, `findSome?`, `lookup`, `any` (and hence `or`),
`all` (and hence `and`) , `range`, `eraseDups`, `eraseReps`, `span`, `groupBy`.
`all` (and hence `and`) , `range`, `eraseDups`, `eraseReps`, `span`, `splitBy`.
The following operations are still missing `@[csimp]` replacements:
`concat`, `zipWithAll`.
@@ -38,7 +38,7 @@ The following operations were already given `@[csimp]` replacements in `Init/Dat
The following operations are given `@[csimp]` replacements below:
`set`, `filterMap`, `foldr`, `append`, `bind`, `join`,
`take`, `takeWhile`, `dropLast`, `replace`, `erase`, `eraseIdx`, `zipWith`,
`take`, `takeWhile`, `dropLast`, `replace`, `modify`, `insertIdx`, `erase`, `eraseIdx`, `zipWith`,
`enumFrom`, and `intercalate`.
-/
@@ -91,7 +91,7 @@ The following operations are given `@[csimp]` replacements below:
@[specialize] def foldrTR (f : α β β) (init : β) (l : List α) : β := l.toArray.foldr f init
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_toList, -Array.size_toArray]
funext α β f init l; simp [foldrTR, Array.foldr_toList, -Array.size_toArray]
/-! ### flatMap -/
@@ -197,6 +197,41 @@ The following operations are given `@[csimp]` replacements below:
· simp [*]
· intro h; rw [IH] <;> simp_all
/-! ### modify -/
/-- Tail-recursive version of `modify`. -/
def modifyTR (f : α α) (n : Nat) (l : List α) : List α := go l n #[] where
/-- Auxiliary for `modifyTR`: `modifyTR.go f l n acc = acc.toList ++ modify f n l`. -/
go : List α Nat Array α List α
| [], _, acc => acc.toList
| a :: l, 0, acc => acc.toListAppend (f a :: l)
| a :: l, n+1, acc => go l n (acc.push a)
theorem modifyTR_go_eq : l n, modifyTR.go f l n acc = acc.toList ++ modify f n l
| [], n => by cases n <;> simp [modifyTR.go, modify]
| a :: l, 0 => by simp [modifyTR.go, modify]
| a :: l, n+1 => by simp [modifyTR.go, modify, modifyTR_go_eq l]
@[csimp] theorem modify_eq_modifyTR : @modify = @modifyTR := by
funext α f n l; simp [modifyTR, modifyTR_go_eq]
/-! ### insertIdx -/
/-- Tail-recursive version of `insertIdx`. -/
@[inline] def insertIdxTR (n : Nat) (a : α) (l : List α) : List α := go n l #[] where
/-- Auxiliary for `insertIdxTR`: `insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l`. -/
go : Nat List α Array α List α
| 0, l, acc => acc.toListAppend (a :: l)
| _, [], acc => acc.toList
| n+1, a :: l, acc => go n l (acc.push a)
theorem insertIdxTR_go_eq : n l, insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l
| 0, l | _+1, [] => by simp [insertIdxTR.go, insertIdx]
| n+1, a :: l => by simp [insertIdxTR.go, insertIdx, insertIdxTR_go_eq n l]
@[csimp] theorem insertIdx_eq_insertIdxTR : @insertIdx = @insertIdxTR := by
funext α f n l; simp [insertIdxTR, insertIdxTR_go_eq]
/-! ### erase -/
/-- Tail recursive version of `List.erase`. -/
@@ -296,7 +331,7 @@ def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
| a::as, n => by
rw [ show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
simp [enumFrom, f]
rw [Array.foldr_eq_foldr_toList]
rw [ Array.foldr_toList]
simp [go]
/-! ## Other list operations -/

View File

@@ -83,44 +83,12 @@ open Nat
@[simp] theorem nil_eq {α} {xs : List α} : [] = xs xs = [] := by
cases xs <;> simp
/-! ### cons -/
theorem cons_ne_nil (a : α) (l : List α) : a :: l [] := nofun
@[simp]
theorem cons_ne_self (a : α) (l : List α) : a :: l l := mt (congrArg length) (Nat.succ_ne_self _)
@[simp] theorem ne_cons_self {a : α} {l : List α} : l a :: l := by
rw [ne_eq, eq_comm]
simp
theorem head_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂ := (cons.inj H).1
theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (cons.inj H).2
theorem cons_inj_right (a : α) {l l' : List α} : a :: l = a :: l' l = l' :=
tail_eq_of_cons_eq, congrArg _
@[deprecated (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' a = b l = l' :=
List.cons.injEq .. .rfl
theorem exists_cons_of_ne_nil : {l : List α}, l [] b L, l = b :: L
| c :: l', _ => c, l', rfl
theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] a = b := by
simp
/-! ### length -/
theorem eq_nil_of_length_eq_zero (_ : length l = 0) : l = [] := match l with | [] => rfl
theorem ne_nil_of_length_eq_add_one (_ : length l = n + 1) : l [] := fun _ => nomatch l
@[deprecated ne_nil_of_length_eq_add_one (since := "2024-06-16")]
abbrev ne_nil_of_length_eq_succ := @ne_nil_of_length_eq_add_one
theorem ne_nil_of_length_pos (_ : 0 < length l) : l [] := fun _ => nomatch l
@[simp] theorem length_eq_zero : length l = 0 l = [] :=
@@ -156,6 +124,36 @@ theorem length_pos {l : List α} : 0 < length l ↔ l ≠ [] :=
theorem length_eq_one {l : List α} : length l = 1 a, l = [a] :=
fun h => match l, h with | [_], _ => _, rfl, fun _, h => by simp [h]
/-! ### cons -/
theorem cons_ne_nil (a : α) (l : List α) : a :: l [] := nofun
@[simp]
theorem cons_ne_self (a : α) (l : List α) : a :: l l := mt (congrArg length) (Nat.succ_ne_self _)
@[simp] theorem ne_cons_self {a : α} {l : List α} : l a :: l := by
rw [ne_eq, eq_comm]
simp
theorem head_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂ := (cons.inj H).1
theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (cons.inj H).2
theorem cons_inj_right (a : α) {l l' : List α} : a :: l = a :: l' l = l' :=
tail_eq_of_cons_eq, congrArg _
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' a = b l = l' :=
List.cons.injEq .. .rfl
theorem exists_cons_of_ne_nil : {l : List α}, l [] b L, l = b :: L
| c :: l', _ => c, l', rfl
theorem ne_nil_iff_exists_cons {l : List α} : l [] b L, l = b :: L :=
exists_cons_of_ne_nil, fun _, _, eq => eq.symm cons_ne_nil _ _
theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] a = b := by
simp
/-! ## L[i] and L[i]? -/
/-! ### `get` and `get?`.
@@ -163,57 +161,29 @@ theorem length_eq_one {l : List α} : length l = 1 ↔ ∃ a, l = [a] :=
We simplify `l.get i` to `l[i.1]'i.2` and `l.get? i` to `l[i]?`.
-/
theorem get_cons_zero : get (a::l) (0 : Fin (l.length + 1)) = a := rfl
@[simp] theorem get_eq_getElem (l : List α) (i : Fin l.length) : l.get i = l[i.1]'i.2 := rfl
theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
(a :: as).get i+1, h = as.get i, Nat.lt_of_succ_lt_succ h := rfl
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
(a :: as).get i.succ = as.get i := rfl
@[deprecated (since := "2024-07-09")]
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl
theorem get_mk_zero : {l : List α} (h : 0 < l.length), l.get 0, h = l.head (length_pos.mp h)
| _::_, _ => rfl
theorem get?_zero (l : List α) : l.get? 0 = l.head? := by cases l <;> rfl
theorem get?_len_le : {l : List α} {n}, length l n l.get? n = none
theorem get?_eq_none : {l : List α} {n}, length l n l.get? n = none
| [], _, _ => rfl
| _ :: l, _+1, h => get?_len_le (l := l) <| Nat.le_of_succ_le_succ h
| _ :: l, _+1, h => get?_eq_none (l := l) <| Nat.le_of_succ_le_succ h
theorem get?_eq_get : {l : List α} {n} (h : n < l.length), l.get? n = some (get l n, h)
| _ :: _, 0, _ => rfl
| _ :: l, _+1, _ => get?_eq_get (l := l) _
theorem get?_eq_some : l.get? n = some a h, get l n, h = a :=
theorem get?_eq_some_iff : l.get? n = some a h, get l n, h = a :=
fun e =>
have : n < length l := Nat.gt_of_not_le fun hn => by cases get?_len_le hn e
have : n < length l := Nat.gt_of_not_le fun hn => by cases get?_eq_none hn e
this, by rwa [get?_eq_get this, Option.some.injEq] at e,
fun _, e => e get?_eq_get _
theorem get?_eq_none : l.get? n = none length l n :=
fun e => Nat.ge_of_not_lt (fun h' => by cases e get?_eq_some.2 h', rfl), get?_len_le
theorem get?_eq_none_iff : l.get? n = none length l n :=
fun e => Nat.ge_of_not_lt (fun h' => by cases e get?_eq_some_iff.2 h', rfl), get?_eq_none
@[simp] theorem get?_eq_getElem? (l : List α) (i : Nat) : l.get? i = l[i]? := by
simp only [getElem?, decidableGetElem?]; split
simp only [getElem?_def]; split
· exact (get?_eq_get _)
· exact (get?_eq_none.2 <| Nat.not_lt.1 _)
@[simp] theorem get_eq_getElem (l : List α) (i : Fin l.length) : l.get i = l[i.1]'i.2 := rfl
theorem getElem?_eq_some {l : List α} : l[i]? = some a h : i < l.length, l[i]'h = a := by
simpa using get?_eq_some
/--
If one has `l.get i` in an expression (with `i : Fin l.length`) and `h : l = l'`,
`rw [h]` will give a "motive it not type correct" error, as it cannot rewrite the
`i : Fin l.length` to `Fin l'.length` directly. The theorem `get_of_eq` can be used to make
such a rewrite, with `rw [get_of_eq h]`.
-/
theorem get_of_eq {l l' : List α} (h : l = l') (i : Fin l.length) :
get l i = get l' i, h i.2 := by cases h; rfl
· exact (get?_eq_none_iff.2 <| Nat.not_lt.1 _)
/-! ### getD
@@ -224,71 +194,54 @@ Because of this, there is only minimal API for `getD`.
@[simp] theorem getD_eq_getElem?_getD (l) (n) (a : α) : getD l n a = (l[n]?).getD a := by
simp [getD]
@[deprecated getD_eq_getElem?_getD (since := "2024-06-12")]
theorem getD_eq_get? : l n (a : α), getD l n a = (get? l n).getD a := by simp
/-! ### get!
We simplify `l.get! n` to `l[n]!`.
-/
theorem get!_of_get? [Inhabited α] : {l : List α} {n}, get? l n = some a get! l n = a
| _a::_, 0, rfl => rfl
| _::l, _+1, e => get!_of_get? (l := l) e
theorem get!_eq_getD [Inhabited α] : (l : List α) n, l.get! n = l.getD n default
| [], _ => rfl
| _a::_, 0 => rfl
| _a::l, n+1 => get!_eq_getD l n
theorem get!_len_le [Inhabited α] : {l : List α} {n}, length l n l.get! n = (default : α)
| [], _, _ => rfl
| _ :: l, _+1, h => get!_len_le (l := l) <| Nat.le_of_succ_le_succ h
@[simp] theorem get!_eq_getElem! [Inhabited α] (l : List α) (n) : l.get! n = l[n]! := by
simp [get!_eq_getD]
rfl
/-! ### getElem! -/
/-! ### getElem!
@[simp] theorem getElem!_nil [Inhabited α] {n : Nat} : ([] : List α)[n]! = default := rfl
We simplify `l[n]!` to `(l[n]?).getD default`.
-/
@[simp] theorem getElem!_cons_zero [Inhabited α] {l : List α} : (a::l)[0]! = a := by
rw [getElem!_pos] <;> simp
@[simp] theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[n+1]! = l[n]! := by
by_cases h : n < l.length
· rw [getElem!_pos, getElem!_pos] <;> simp_all [Nat.succ_lt_succ_iff]
· rw [getElem!_neg, getElem!_neg] <;> simp_all [Nat.succ_lt_succ_iff]
@[simp] theorem getElem!_eq_getElem?_getD [Inhabited α] (l : List α) (n : Nat) :
l[n]! = (l[n]?).getD (default : α) := by
simp only [getElem!_def]
split <;> simp_all
/-! ### getElem? and getElem -/
@[simp] theorem getElem?_eq_getElem {l : List α} {n} (h : n < l.length) : l[n]? = some l[n] := by
simp only [getElem?_def, h, reduceDIte]
theorem getElem?_eq_some_iff {l : List α} : l[n]? = some a h : n < l.length, l[n] = a := by
simp only [ get?_eq_getElem?, get?_eq_some, get_eq_getElem]
theorem some_eq_getElem?_iff {l : List α} : some a = l[n]? h : n < l.length, l[n] = a := by
rw [eq_comm, getElem?_eq_some_iff]
@[simp] theorem getElem?_eq_none_iff : l[n]? = none length l n := by
simp only [ get?_eq_getElem?, get?_eq_none]
simp only [ get?_eq_getElem?, get?_eq_none_iff]
@[simp] theorem none_eq_getElem?_iff {l : List α} {n : Nat} : none = l[n]? length l n := by
simp [eq_comm (a := none)]
theorem getElem?_eq_none (h : length l n) : l[n]? = none := getElem?_eq_none_iff.mpr h
theorem getElem?_eq (l : List α) (i : Nat) :
l[i]? = if h : i < l.length then some l[i] else none := by
split <;> simp_all
@[simp] theorem getElem?_eq_getElem {l : List α} {n} (h : n < l.length) : l[n]? = some l[n] :=
getElem?_pos ..
@[simp] theorem some_getElem_eq_getElem?_iff {α} (xs : List α) (i : Nat) (h : i < xs.length) :
theorem getElem?_eq_some_iff {l : List α} : l[n]? = some a h : n < l.length, l[n] = a := by
simp only [ get?_eq_getElem?, get?_eq_some_iff, get_eq_getElem]
theorem some_eq_getElem?_iff {l : List α} : some a = l[n]? h : n < l.length, l[n] = a := by
rw [eq_comm, getElem?_eq_some_iff]
@[simp] theorem some_getElem_eq_getElem?_iff (xs : List α) (i : Nat) (h : i < xs.length) :
(some xs[i] = xs[i]?) True := by
simp [h]
@[simp] theorem getElem?_eq_some_getElem_iff {α} (xs : List α) (i : Nat) (h : i < xs.length) :
@[simp] theorem getElem?_eq_some_getElem_iff (xs : List α) (i : Nat) (h : i < xs.length) :
(xs[i]? = some xs[i]) True := by
simp [h]
@@ -300,11 +253,13 @@ theorem getElem_eq_getElem?_get (l : List α) (i : Nat) (h : i < l.length) :
l[i] = l[i]?.get (by simp [getElem?_eq_getElem, h]) := by
simp [getElem_eq_iff]
@[deprecated getElem_eq_getElem?_get (since := "2024-09-04")] abbrev getElem_eq_getElem? :=
@getElem_eq_getElem?_get
@[simp] theorem getElem?_nil {n : Nat} : ([] : List α)[n]? = none := rfl
theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
(a :: l)[i] =
if h : i = 0 then a else l[i-1]'(match i, h with | i+1, _ => succ_lt_succ_iff.mp w) := by
cases i <;> simp
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by simp
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[n+1]? = l[n]? := by
@@ -314,10 +269,12 @@ theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by simp
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
cases i <;> simp
theorem getElem?_len_le : {l : List α} {n}, length l n l[n]? = none
| [], _, _ => rfl
| _ :: l, _+1, h => by
rw [getElem?_cons_succ, getElem?_len_le (l := l) <| Nat.le_of_succ_le_succ h]
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : [a][i] = a :=
match i, h with
| 0, _ => rfl
theorem getElem?_singleton (a : α) (i : Nat) : [a][i]? = if i = 0 then some a else none := by
simp [getElem?_cons]
/--
If one has `l[i]` in an expression and `h : l = l'`,
@@ -328,24 +285,10 @@ such a rewrite, with `rw [getElem_of_eq h]`.
theorem getElem_of_eq {l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) :
l[i] = l'[i]'(h w) := by cases h; rfl
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : [a][i] = a :=
match i, h with
| 0, _ => rfl
@[deprecated getElem_singleton (since := "2024-06-12")]
theorem get_singleton (a : α) (n : Fin 1) : get [a] n = a := by simp
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos.mp h) :=
match l, h with
| _ :: _, _ => rfl
theorem getElem!_of_getElem? [Inhabited α] : {l : List α} {n : Nat}, l[n]? = some a l[n]! = a
| _a::_, 0, _ => by
rw [getElem!_pos] <;> simp_all
| _::l, _+1, e => by
simp at e
simp_all [getElem!_of_getElem? (l := l) e]
@[ext] theorem ext_getElem? {l₁ l₂ : List α} (h : n : Nat, l₁[n]? = l₂[n]?) : l₁ = l₂ :=
ext_get? fun n => by simp_all
@@ -356,11 +299,7 @@ theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
simp_all [getElem?_eq_getElem]
else by
have h₁ := Nat.le_of_not_lt h₁
rw [getElem?_len_le h₁, getElem?_len_le]; rwa [ hl]
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
(h : n h₁ h₂, get l₁ n, h₁ = get l₂ n, h₂) : l₁ = l₂ :=
ext_getElem hl (by simp_all)
rw [getElem?_eq_none h₁, getElem?_eq_none]; rwa [ hl]
@[simp] theorem getElem_concat_length : (l : List α) (a : α) (i) (_ : i = l.length) (w), (l ++ [a])[i]'w = a
| [], a, _, h, _ => by subst h; simp
@@ -369,9 +308,6 @@ theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
theorem getElem?_concat_length (l : List α) (a : α) : (l ++ [a])[l.length]? = some a := by
simp
@[deprecated getElem?_concat_length (since := "2024-06-12")]
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
/-! ### mem -/
@[simp] theorem not_mem_nil (a : α) : ¬ a [] := nofun
@@ -383,9 +319,9 @@ theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = s
theorem mem_cons_self (a : α) (l : List α) : a a :: l := .head ..
theorem mem_concat_self (xs : List α) (a : α) : a xs ++ [a] :=
mem_append_of_mem_right xs (mem_cons_self a _)
mem_append_right xs (mem_cons_self a _)
theorem mem_append_cons_self : a xs ++ a :: ys := mem_append_of_mem_right _ (mem_cons_self _ _)
theorem mem_append_cons_self : a xs ++ a :: ys := mem_append_right _ (mem_cons_self _ _)
theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a xs) :
as bs, xs = as ++ a :: bs a as := by
@@ -482,42 +418,19 @@ theorem getElem_of_mem : ∀ {a} {l : List α}, a ∈ l → ∃ (n : Nat) (h : n
| _, _ :: _, .head .. => 0, Nat.succ_pos _, rfl
| _, _ :: _, .tail _ m => let n, h, e := getElem_of_mem m; n+1, Nat.succ_lt_succ h, e
theorem get_of_mem {a} {l : List α} (h : a l) : n, get l n = a := by
obtain n, h, e := getElem_of_mem h
exact n, h, e
theorem getElem?_of_mem {a} {l : List α} (h : a l) : n : Nat, l[n]? = some a := by
let n, _, e := getElem_of_mem h
exact n, e getElem?_eq_getElem _
theorem getElem?_of_mem {a} {l : List α} (h : a l) : n : Nat, l[n]? = some a :=
let n, _, e := getElem_of_mem h; n, e getElem?_eq_getElem _
theorem get?_of_mem {a} {l : List α} (h : a l) : n, l.get? n = some a :=
let n, _, e := get_of_mem h; n, e get?_eq_get _
@[simp] theorem getElem_mem : {l : List α} {n} (h : n < l.length), l[n]'h l
| _ :: _, 0, _ => .head ..
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
theorem get_mem : (l : List α) n h, get l n, h l
| _ :: _, 0, _ => .head ..
| _ :: l, _+1, _ => .tail _ (get_mem l ..)
theorem getElem?_mem {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a l :=
theorem mem_of_getElem? {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a l :=
let _, e := getElem?_eq_some_iff.1 e; e getElem_mem ..
theorem get?_mem {l : List α} {n a} (e : l.get? n = some a) : a l :=
let _, e := get?_eq_some.1 e; e get_mem ..
theorem mem_iff_getElem {a} {l : List α} : a l (n : Nat) (h : n < l.length), l[n]'h = a :=
getElem_of_mem, fun _, _, e => e getElem_mem ..
theorem mem_iff_get {a} {l : List α} : a l n, get l n = a :=
get_of_mem, fun _, e => e get_mem ..
theorem mem_iff_getElem? {a} {l : List α} : a l n : Nat, l[n]? = some a := by
simp [getElem?_eq_some_iff, mem_iff_getElem]
theorem mem_iff_get? {a} {l : List α} : a l n, l.get? n = some a := by
simp [getElem?_eq_some_iff, Fin.exists_iff, mem_iff_get]
theorem forall_getElem {l : List α} {p : α Prop} :
( (n : Nat) h, p (l[n]'h)) a, a l p a := by
induction l with
@@ -554,7 +467,7 @@ theorem isEmpty_iff {l : List α} : l.isEmpty ↔ l = [] := by
cases l <;> simp
theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
(List.isEmpty xs = false) x, x xs := by
xs.isEmpty = false x, x xs := by
cases xs <;> simp
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty l.length = 0 := by
@@ -568,18 +481,6 @@ theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 :=
/-! ### any / all -/
theorem any_beq [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => a == x) a l := by
induction l <;> simp_all
theorem any_beq' [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => x == a) a l := by
induction l <;> simp_all [eq_comm (a := a)]
theorem all_bne [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => a != x) a l := by
induction l <;> simp_all
theorem all_bne' [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => x != a) a l := by
induction l <;> simp_all [eq_comm (a := a)]
theorem any_eq {l : List α} : l.any p = decide ( x, x l p x) := by induction l <;> simp [*]
theorem all_eq {l : List α} : l.all p = decide ( x, x l p x) := by induction l <;> simp [*]
@@ -604,6 +505,18 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
@[simp] theorem all_eq_false {l : List α} : l.all p = false x, x l ¬p x := by
simp [all_eq]
theorem any_beq [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => a == x) a l := by
simp
theorem any_beq' [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => x == a) a l := by
simp
theorem all_bne [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => a != x) a l := by
induction l <;> simp_all
theorem all_bne' [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => x != a) a l := by
induction l <;> simp_all [eq_comm (a := a)]
/-! ### set -/
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
@@ -621,19 +534,10 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
| _ :: _, 0 => by simp
| _ :: l, i + 1 => by simp [getElem_set_self]
@[deprecated getElem_set_self (since := "2024-09-04")] abbrev getElem_set_eq := @getElem_set_self
@[deprecated getElem_set_self (since := "2024-06-12")]
theorem get_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
(l.set i a).get i, h = a := by
simp
@[simp] theorem getElem?_set_self {l : List α} {i : Nat} {a : α} (h : i < l.length) :
(l.set i a)[i]? = some a := by
simp_all [getElem?_eq_some_iff]
@[deprecated getElem?_set_self (since := "2024-09-04")] abbrev getElem?_set_eq := @getElem?_set_self
/-- This differs from `getElem?_set_self` by monadically mapping `Function.const _ a` over the `Option`
returned by `l[i]?`. -/
theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
@@ -655,12 +559,6 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
have g : i j := h congrArg (· + 1)
simp [getElem_set_ne g]
@[deprecated getElem_set_ne (since := "2024-06-12")]
theorem get_set_ne {l : List α} {i j : Nat} (h : i j) {a : α}
(hj : j < (l.set i a).length) :
(l.set i a).get j, hj = l.get j, by simp at hj; exact hj := by
simp [h]
@[simp] theorem getElem?_set_ne {l : List α} {i j : Nat} (h : i j) {a : α} :
(l.set i a)[j]? = l[j]? := by
by_cases hj : j < (l.set i a).length
@@ -675,11 +573,6 @@ theorem getElem_set {l : List α} {m n} {a} (h) :
else
simp [h]
@[deprecated getElem_set (since := "2024-06-12")]
theorem get_set {l : List α} {m n} {a : α} (h) :
(set l m a).get n, h = if m = n then a else l.get n, length_set .. h := by
simp [getElem_set]
theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
(l.set i a)[j]? = if i = j then if i < l.length then some a else none else l[j]? := by
if h : i = j then
@@ -699,6 +592,14 @@ theorem getElem?_set' {l : List α} {i j : Nat} {a : α} :
· simp only [getElem?_set_self', Option.map_eq_map, reduceIte, *]
· simp only [ne_eq, not_false_eq_true, getElem?_set_ne, reduceIte, *]
@[simp] theorem set_getElem_self {as : List α} {i : Nat} (h : i < as.length) :
as.set i as[i] = as := by
apply ext_getElem
· simp
· intro n h₁ h₂
rw [getElem_set]
split <;> simp_all
theorem set_eq_of_length_le {l : List α} {n : Nat} (h : l.length n) {a : α} :
l.set n a = l := by
induction l generalizing n with
@@ -713,8 +614,6 @@ theorem set_eq_of_length_le {l : List α} {n : Nat} (h : l.length ≤ n) {a : α
@[simp] theorem set_eq_nil_iff {l : List α} (n : Nat) (a : α) : l.set n a = [] l = [] := by
cases l <;> cases n <;> simp [set]
@[deprecated set_eq_nil_iff (since := "2024-09-05")] abbrev set_eq_nil := @set_eq_nil_iff
theorem set_comm (a b : α) : {n m : Nat} (l : List α), n m
(l.set n a).set m b = (l.set m b).set n a
| _, _, [], _ => by simp
@@ -780,6 +679,24 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.s
· intro a
simp
@[simp] theorem beq_nil_iff [BEq α] {l : List α} : (l == []) = l.isEmpty := by
cases l <;> rfl
@[simp] theorem nil_beq_iff [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
cases l <;> rfl
@[simp] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l₁.length = l₂.length :=
match l₁, l₂ with
| [], [] => rfl
| [], _ :: _ => by simp [beq_nil_iff] at h
| _ :: _, [] => by simp [nil_beq_iff] at h
| a :: l₁, b :: l₂ => by
simp at h
simpa [Nat.add_one_inj]using length_eq_of_beq h.2
/-! ### Lexicographic ordering -/
protected theorem lt_irrefl [LT α] (lt_irrefl : x : α, ¬x < x) (l : List α) : ¬l < l := by
@@ -845,6 +762,12 @@ theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
l.foldr f b = l.foldrM (m := Id) f b := by
induction l <;> simp [*, foldr]
@[simp] theorem id_run_foldlM (f : β α Id β) (b) (l : List α) :
Id.run (l.foldlM f b) = l.foldl f b := (foldl_eq_foldlM f b l).symm
@[simp] theorem id_run_foldrM (f : α β Id β) (b) (l : List α) :
Id.run (l.foldrM f b) = l.foldr f b := (foldr_eq_foldrM f b l).symm
/-! ### foldl and foldr -/
@[simp] theorem foldr_cons_eq_append (l : List α) : l.foldr cons l' = l ++ l' := by
@@ -867,14 +790,30 @@ theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : List α
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
induction l generalizing init <;> simp [*]
theorem foldl_map' {α β : Type u} (g : α β) (f : α α α) (f' : β β β) (a : α) (l : List α)
theorem foldl_filterMap (f : α Option β) (g : γ β γ) (l : List α) (init : γ) :
(l.filterMap f).foldl g init = l.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filterMap_cons, foldl_cons]
cases f a <;> simp [ih]
theorem foldr_filterMap (f : α Option β) (g : β γ γ) (l : List α) (init : γ) :
(l.filterMap f).foldr g init = l.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filterMap_cons, foldr_cons]
cases f a <;> simp [ih]
theorem foldl_map' (g : α β) (f : α α α) (f' : β β β) (a : α) (l : List α)
(h : x y, f' (g x) (g y) = g (f x y)) :
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
induction l generalizing a
· simp
· simp [*, h]
theorem foldr_map' {α β : Type u} (g : α β) (f : α α α) (f' : β β β) (a : α) (l : List α)
theorem foldr_map' (g : α β) (f : α α α) (f' : β β β) (a : α) (l : List α)
(h : x y, f' (g x) (g y) = g (f x y)) :
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
induction l generalizing a
@@ -987,6 +926,21 @@ theorem foldr_rel {l : List α} {f g : α → β → β} {a b : β} (r : β →
· simp
· exact ih h fun a m c c' h => h' _ (by simp_all) _ _ h
@[simp] theorem foldl_add_const (l : List α) (a b : Nat) :
l.foldl (fun x _ => x + a) b = b + a * l.length := by
induction l generalizing b with
| nil => simp
| cons y l ih =>
simp only [foldl_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc,
Nat.add_comm a]
@[simp] theorem foldr_add_const (l : List α) (a b : Nat) :
l.foldr (fun _ x => x + a) b = b + a * l.length := by
induction l generalizing b with
| nil => simp
| cons y l ih =>
simp only [foldr_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc]
/-! ### getLast -/
theorem getLast_eq_getElem : (l : List α) (h : l []),
@@ -998,6 +952,10 @@ theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
| _ :: _ :: _, _ => by
simp [getLast, get, Nat.succ_sub_succ, getLast_eq_getElem]
theorem getElem_length_sub_one_eq_getLast (l : List α) (h : l.length - 1 < l.length) :
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
rw [ getLast_eq_getElem]
@[deprecated getLast_eq_getElem (since := "2024-07-15")]
theorem getLast_eq_get (l : List α) (h : l []) :
getLast l h = l.get l.length - 1, by
@@ -1018,7 +976,7 @@ theorem getLast_eq_getLastD (a l h) : @getLast α (a::l) h = getLastD l a := by
@[simp] theorem getLast_singleton (a h) : @getLast α [a] h = a := rfl
theorem getLast!_cons [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
simp [getLast!, getLast_eq_getLastD]
@[simp] theorem getLast_mem : {l : List α} (h : l []), getLast l h l
@@ -1082,7 +1040,12 @@ theorem getLastD_concat (a b l) : @getLastD α (l ++ [b]) a = b := by
/-! ### getLast! -/
@[simp] theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
@[simp] theorem getLast!_eq_getLast?_getD [Inhabited α] {l : List α} : getLast! l = (getLast? l).getD default := by
cases l with
| nil => simp [getLast!_nil]
| cons _ _ => simp [getLast!, getLast?_eq_getLast]
theorem getLast!_of_getLast? [Inhabited α] : {l : List α}, getLast? l = some a getLast! l = a
| _ :: _, rfl => rfl
@@ -1117,6 +1080,12 @@ theorem head_eq_getElem (l : List α) (h : l ≠ []) : head l h = l[0]'(length_p
| nil => simp at h
| cons _ _ => simp
theorem getElem_zero_eq_head (l : List α) (h : 0 < l.length) :
l[0] = head l (by simpa [length_pos] using h) := by
cases l with
| nil => simp at h
| cons _ _ => simp
theorem head_eq_iff_head?_eq_some {xs : List α} (h) : xs.head h = a xs.head? = some a := by
cases xs with
| nil => simp at h
@@ -1461,6 +1430,22 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
| [] => rfl
| a :: l => by by_cases hp : p a <;> by_cases hq : q a <;> simp [hp, hq, filter_filter _ l]
theorem foldl_filter (p : α Bool) (f : β α β) (l : List α) (init : β) :
(l.filter p).foldl f init = l.foldl (fun x y => if p y then f x y else x) init := by
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filter_cons, foldl_cons]
split <;> simp [ih]
theorem foldr_filter (p : α Bool) (f : α β β) (l : List α) (init : β) :
(l.filter p).foldr f init = l.foldr (fun x y => if p x then f x y else y) init := by
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filter_cons, foldr_cons]
split <;> simp [ih]
theorem filter_map (f : β α) (l : List β) : filter p (map f l) = map f (filter (p f) l) := by
induction l with
| nil => rfl
@@ -1688,7 +1673,7 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
@[simp] theorem cons_append_fun (a : α) (as : List α) :
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h) :
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h : n < (l₁ ++ l₂).length) :
(l₁ ++ l₂)[n] = if h' : n < l₁.length then l₁[n] else l₂[n - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
split <;> rename_i h'
· rw [getElem_append_left h']
@@ -1728,7 +1713,7 @@ theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {n : Nat} (hn :
l₂[n] = (l₁ ++ l₂)[n + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hn _) := by
rw [getElem_append_right] <;> simp [*, le_add_left]
@[deprecated (since := "2024-06-12")]
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
theorem get_append_right_aux {l₁ l₂ : List α} {n : Nat}
(h₁ : l₁.length n) (h₂ : n < (l₁ ++ l₂).length) : n - l₁.length < l₂.length := by
rw [length_append] at h₂
@@ -1745,7 +1730,7 @@ theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.l
rw [ getElem?_eq_getElem, eq, getElem?_append_right (h Nat.le_refl _), h]
simp
@[deprecated (since := "2024-06-12")]
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
theorem get_of_append_proof {l : List α}
(eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) : n < length l := eq h by simp_arith
@@ -1929,11 +1914,8 @@ theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t
theorem mem_append_eq (a : α) (s t : List α) : (a s ++ t) = (a s a t) :=
propext mem_append
theorem mem_append_left {a : α} {l₁ : List α} (l₂ : List α) (h : a l₁) : a l₁ ++ l₂ :=
mem_append.2 (Or.inl h)
theorem mem_append_right {a : α} (l₁ : List α) {l₂ : List α} (h : a l₂) : a l₁ ++ l₂ :=
mem_append.2 (Or.inr h)
@[deprecated mem_append_left (since := "2024-11-20")] abbrev mem_append_of_mem_left := @mem_append_left
@[deprecated mem_append_right (since := "2024-11-20")] abbrev mem_append_of_mem_right := @mem_append_right
theorem mem_iff_append {a : α} {l : List α} : a l s t : List α, l = s ++ a :: t :=
append_of_mem, fun s, t, e => e by simp
@@ -2233,6 +2215,11 @@ theorem flatMap_def (l : List α) (f : α → List β) : l.flatMap f = flatten (
@[simp] theorem flatMap_id (l : List (List α)) : List.flatMap l id = l.flatten := by simp [flatMap_def]
@[simp]
theorem length_flatMap (l : List α) (f : α List β) :
length (l.flatMap f) = sum (map (length f) l) := by
rw [List.flatMap, length_flatten, map_map]
@[simp] theorem mem_flatMap {f : α List β} {b} {l : List α} : b l.flatMap f a, a l b f a := by
simp [flatMap_def, mem_flatten]
exact fun _, a, h₁, rfl, h₂ => a, h₁, h₂, fun a, h₁, h₂ => _, a, h₁, rfl, h₂
@@ -2347,7 +2334,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[simp] theorem getElem_replicate (a : α) {n : Nat} {m} (h : m < (replicate n a).length) :
(replicate n a)[m] = a :=
eq_of_mem_replicate (get_mem _ _ _)
eq_of_mem_replicate (getElem_mem _)
@[deprecated getElem_replicate (since := "2024-06-12")]
theorem get_replicate (a : α) {n : Nat} (m : Fin _) : (replicate n a).get m = a := by
@@ -2704,6 +2691,12 @@ theorem flatMap_reverse {β} (l : List α) (f : α → List β) : (l.reverse.fla
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
(foldl_reverse ..).symm.trans <| by simp
theorem foldl_eq_foldr_reverse (l : List α) (f : β α β) (b) :
l.foldl f b = l.reverse.foldr (fun x y => f y x) b := by simp
theorem foldr_eq_foldl_reverse (l : List α) (f : α β β) (b) :
l.foldr f b = l.reverse.foldl (fun x y => f y x) b := by simp
@[simp] theorem reverse_replicate (n) (a : α) : reverse (replicate n a) = replicate n a :=
eq_replicate_iff.2
by rw [length_reverse, length_replicate],
@@ -2847,6 +2840,10 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
l.contains a a' l, a == a' := by
induction l <;> simp_all
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
l.contains a a l := by
simp
/-! ## Sublists -/
/-! ### partition
@@ -2879,7 +2876,7 @@ are often used for theorems about `Array.pop`.
@[simp] theorem getElem_dropLast : (xs : List α) (i : Nat) (h : i < xs.dropLast.length),
xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. Nat.pred_le _))
| _::_::_, 0, _ => rfl
| _::_::_, i+1, _ => getElem_dropLast _ i _
| _::_::_, i+1, h => getElem_dropLast _ i (Nat.add_one_lt_add_one_iff.mp h)
@[deprecated getElem_dropLast (since := "2024-06-12")]
theorem get_dropLast (xs : List α) (i : Fin xs.dropLast.length) :
@@ -3254,10 +3251,10 @@ theorem any_eq_not_all_not (l : List α) (p : α → Bool) : l.any p = !l.all (!
theorem all_eq_not_any_not (l : List α) (p : α Bool) : l.all p = !l.any (!p .) := by
simp only [not_any_eq_all_not, Bool.not_not]
@[simp] theorem any_map {l : List α} {p : α Bool} : (l.map f).any p = l.any (p f) := by
@[simp] theorem any_map {l : List α} {p : β Bool} : (l.map f).any p = l.any (p f) := by
induction l with simp | cons _ _ ih => rw [ih]
@[simp] theorem all_map {l : List α} {p : α Bool} : (l.map f).all p = l.all (p f) := by
@[simp] theorem all_map {l : List α} {p : β Bool} : (l.map f).all p = l.all (p f) := by
induction l with simp | cons _ _ ih => rw [ih]
@[simp] theorem any_filter {l : List α} {p q : α Bool} :
@@ -3332,7 +3329,7 @@ theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!
@[simp] theorem all_replicate {n : Nat} {a : α} :
(replicate n a).all f = if n = 0 then true else f a := by
cases n <;> simp (config := {contextual := true}) [replicate_succ]
cases n <;> simp +contextual [replicate_succ]
@[simp] theorem any_insert [BEq α] [LawfulBEq α] {l : List α} {a : α} :
(l.insert a).any f = (f a || l.any f) := by
@@ -3342,17 +3339,137 @@ theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!
(l.insert a).all f = (f a && l.all f) := by
simp [all_eq]
/-! ### Legacy lemmas about `get`, `get?`, and `get!`.
Hopefully these should not be needed, in favour of lemmas about `xs[i]`, `xs[i]?`, and `xs[i]!`,
to which these simplify.
We may consider deprecating or downstreaming these lemmas.
-/
theorem get_cons_zero : get (a::l) (0 : Fin (l.length + 1)) = a := rfl
theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
(a :: as).get i+1, h = as.get i, Nat.lt_of_succ_lt_succ h := rfl
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
(a :: as).get i.succ = as.get i := rfl
theorem get_mk_zero : {l : List α} (h : 0 < l.length), l.get 0, h = l.head (length_pos.mp h)
| _::_, _ => rfl
theorem get?_zero (l : List α) : l.get? 0 = l.head? := by cases l <;> rfl
/--
If one has `l.get i` in an expression (with `i : Fin l.length`) and `h : l = l'`,
`rw [h]` will give a "motive is not type correct" error, as it cannot rewrite the
`i : Fin l.length` to `Fin l'.length` directly. The theorem `get_of_eq` can be used to make
such a rewrite, with `rw [get_of_eq h]`.
-/
theorem get_of_eq {l l' : List α} (h : l = l') (i : Fin l.length) :
get l i = get l' i, h i.2 := by cases h; rfl
theorem get!_of_get? [Inhabited α] : {l : List α} {n}, get? l n = some a get! l n = a
| _a::_, 0, rfl => rfl
| _::l, _+1, e => get!_of_get? (l := l) e
theorem get!_len_le [Inhabited α] : {l : List α} {n}, length l n l.get! n = (default : α)
| [], _, _ => rfl
| _ :: l, _+1, h => get!_len_le (l := l) <| Nat.le_of_succ_le_succ h
theorem getElem!_nil [Inhabited α] {n : Nat} : ([] : List α)[n]! = default := rfl
theorem getElem!_cons_zero [Inhabited α] {l : List α} : (a::l)[0]! = a := by
rw [getElem!_pos] <;> simp
theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[n+1]! = l[n]! := by
by_cases h : n < l.length
· rw [getElem!_pos, getElem!_pos] <;> simp_all [Nat.succ_lt_succ_iff]
· rw [getElem!_neg, getElem!_neg] <;> simp_all [Nat.succ_lt_succ_iff]
theorem getElem!_of_getElem? [Inhabited α] : {l : List α} {n : Nat}, l[n]? = some a l[n]! = a
| _a::_, 0, _ => by
rw [getElem!_pos] <;> simp_all
| _::l, _+1, e => by
simp at e
simp_all [getElem!_of_getElem? (l := l) e]
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
(h : n h₁ h₂, get l₁ n, h₁ = get l₂ n, h₂) : l₁ = l₂ :=
ext_getElem hl (by simp_all)
theorem get_of_mem {a} {l : List α} (h : a l) : n, get l n = a := by
obtain n, h, e := getElem_of_mem h
exact n, h, e
theorem get?_of_mem {a} {l : List α} (h : a l) : n, l.get? n = some a :=
let n, _, e := get_of_mem h; n, e get?_eq_get _
theorem get_mem : (l : List α) n, get l n l
| _ :: _, 0, _ => .head ..
| _ :: l, _+1, _ => .tail _ (get_mem l ..)
theorem mem_of_get? {l : List α} {n a} (e : l.get? n = some a) : a l :=
let _, e := get?_eq_some_iff.1 e; e get_mem ..
theorem mem_iff_get {a} {l : List α} : a l n, get l n = a :=
get_of_mem, fun _, e => e get_mem ..
theorem mem_iff_get? {a} {l : List α} : a l n, l.get? n = some a := by
simp [getElem?_eq_some_iff, Fin.exists_iff, mem_iff_get]
/-! ### Deprecations -/
@[deprecated getD_eq_getElem?_getD (since := "2024-06-12")]
theorem getD_eq_get? : l n (a : α), getD l n a = (get? l n).getD a := by simp
@[deprecated getElem_singleton (since := "2024-06-12")]
theorem get_singleton (a : α) (n : Fin 1) : get [a] n = a := by simp
@[deprecated getElem?_concat_length (since := "2024-06-12")]
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
@[deprecated getElem_set_self (since := "2024-06-12")]
theorem get_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
(l.set i a).get i, h = a := by
simp
@[deprecated getElem_set_ne (since := "2024-06-12")]
theorem get_set_ne {l : List α} {i j : Nat} (h : i j) {a : α}
(hj : j < (l.set i a).length) :
(l.set i a).get j, hj = l.get j, by simp at hj; exact hj := by
simp [h]
@[deprecated getElem_set (since := "2024-06-12")]
theorem get_set {l : List α} {m n} {a : α} (h) :
(set l m a).get n, h = if m = n then a else l.get n, length_set .. h := by
simp [getElem_set]
@[deprecated cons_inj_right (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
@[deprecated ne_nil_of_length_eq_add_one (since := "2024-06-16")]
abbrev ne_nil_of_length_eq_succ := @ne_nil_of_length_eq_add_one
@[deprecated "Deprecated without replacement." (since := "2024-07-09")]
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl
@[deprecated filter_flatten (since := "2024-08-26")]
theorem join_map_filter (p : α Bool) (l : List (List α)) :
(l.map (filter p)).flatten = (l.flatten).filter p := by
rw [filter_flatten]
@[deprecated getElem_eq_getElem?_get (since := "2024-09-04")] abbrev getElem_eq_getElem? :=
@getElem_eq_getElem?_get
@[deprecated flatten_eq_nil_iff (since := "2024-09-05")] abbrev join_eq_nil := @flatten_eq_nil_iff
@[deprecated flatten_ne_nil_iff (since := "2024-09-05")] abbrev join_ne_nil := @flatten_ne_nil_iff
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons_iff := @flatten_eq_cons_iff
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons := @flatten_eq_cons_iff
@[deprecated flatten_eq_append_iff (since := "2024-09-05")] abbrev join_eq_append := @flatten_eq_append_iff
@[deprecated mem_of_getElem? (since := "2024-09-06")] abbrev getElem?_mem := @mem_of_getElem?
@[deprecated mem_of_get? (since := "2024-09-06")] abbrev get?_mem := @mem_of_get?
@[deprecated getElem_set_self (since := "2024-09-04")] abbrev getElem_set_eq := @getElem_set_self
@[deprecated getElem?_set_self (since := "2024-09-04")] abbrev getElem?_set_eq := @getElem?_set_self
@[deprecated set_eq_nil_iff (since := "2024-09-05")] abbrev set_eq_nil := @set_eq_nil_iff
@[deprecated flatten_nil (since := "2024-10-14")] abbrev join_nil := @flatten_nil
@[deprecated flatten_cons (since := "2024-10-14")] abbrev join_cons := @flatten_cons
@[deprecated length_flatten (since := "2024-10-14")] abbrev length_join := @length_flatten
@[deprecated flatten_singleton (since := "2024-10-14")] abbrev join_singleton := @flatten_singleton
@[deprecated mem_flatten (since := "2024-10-14")] abbrev mem_join := @mem_flatten
@[deprecated flatten_eq_nil_iff (since := "2024-09-05")] abbrev join_eq_nil := @flatten_eq_nil_iff
@[deprecated flatten_eq_nil_iff (since := "2024-10-14")] abbrev join_eq_nil_iff := @flatten_eq_nil_iff
@[deprecated flatten_ne_nil_iff (since := "2024-09-05")] abbrev join_ne_nil := @flatten_ne_nil_iff
@[deprecated flatten_ne_nil_iff (since := "2024-10-14")] abbrev join_ne_nil_iff := @flatten_ne_nil_iff
@[deprecated exists_of_mem_flatten (since := "2024-10-14")] abbrev exists_of_mem_join := @exists_of_mem_flatten
@[deprecated mem_flatten_of_mem (since := "2024-10-14")] abbrev mem_join_of_mem := @mem_flatten_of_mem
@@ -3366,16 +3483,9 @@ theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!
@[deprecated filter_flatten (since := "2024-10-14")] abbrev filter_join := @filter_flatten
@[deprecated flatten_filter_not_isEmpty (since := "2024-10-14")] abbrev join_filter_not_isEmpty := @flatten_filter_not_isEmpty
@[deprecated flatten_filter_ne_nil (since := "2024-10-14")] abbrev join_filter_ne_nil := @flatten_filter_ne_nil
@[deprecated filter_flatten (since := "2024-08-26")]
theorem join_map_filter (p : α Bool) (l : List (List α)) :
(l.map (filter p)).flatten = (l.flatten).filter p := by
rw [filter_flatten]
@[deprecated flatten_append (since := "2024-10-14")] abbrev join_append := @flatten_append
@[deprecated flatten_concat (since := "2024-10-14")] abbrev join_concat := @flatten_concat
@[deprecated flatten_flatten (since := "2024-10-14")] abbrev join_join := @flatten_flatten
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons_iff := @flatten_eq_cons_iff
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons := @flatten_eq_cons_iff
@[deprecated flatten_eq_append_iff (since := "2024-09-05")] abbrev join_eq_append := @flatten_eq_append_iff
@[deprecated flatten_eq_append_iff (since := "2024-10-14")] abbrev join_eq_append_iff := @flatten_eq_append_iff
@[deprecated eq_iff_flatten_eq (since := "2024-10-14")] abbrev eq_iff_join_eq := @eq_iff_flatten_eq
@[deprecated flatten_replicate_nil (since := "2024-10-14")] abbrev join_replicate_nil := @flatten_replicate_nil
@@ -3410,4 +3520,23 @@ theorem join_map_filter (p : α → Bool) (l : List (List α)) :
@[deprecated any_flatMap (since := "2024-10-16")] abbrev any_bind := @any_flatMap
@[deprecated all_flatMap (since := "2024-10-16")] abbrev all_bind := @all_flatMap
@[deprecated get?_eq_none (since := "2024-11-29")] abbrev get?_len_le := @get?_eq_none
@[deprecated getElem?_eq_some_iff (since := "2024-11-29")]
abbrev getElem?_eq_some := @getElem?_eq_some_iff
@[deprecated get?_eq_some_iff (since := "2024-11-29")]
abbrev get?_eq_some := @get?_eq_some_iff
@[deprecated LawfulGetElem.getElem?_def (since := "2024-11-29")]
theorem getElem?_eq (l : List α) (i : Nat) :
l[i]? = if h : i < l.length then some l[i] else none :=
getElem?_def _ _
@[deprecated getElem?_eq_none (since := "2024-11-29")] abbrev getElem?_len_le := @getElem?_eq_none
@[deprecated _root_.isSome_getElem? (since := "2024-12-09")]
theorem isSome_getElem? {l : List α} {n : Nat} : l[n]?.isSome n < l.length := by
simp
@[deprecated _root_.isNone_getElem? (since := "2024-12-09")]
theorem isNone_getElem? {l : List α} {n : Nat} : l[n]?.isNone l.length n := by
simp
end List

View File

@@ -7,6 +7,9 @@ Authors: Kim Morrison, Mario Carneiro
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.Range
import Init.Data.List.OfFn
import Init.Data.Fin.Lemmas
import Init.Data.Option.Attach
namespace List
@@ -14,8 +17,21 @@ namespace List
/-! ### mapIdx -/
/--
Given a function `f : Nat → α → β` and `as : list α`, `as = [a₀, a₁, ...]`, returns the list
Given a list `as = [a₀, a₁, ...]` function `f : Fin as.length → α → β`, returns the list
`[f 0 a₀, f 1 a₁, ...]`.
-/
@[inline] def mapFinIdx (as : List α) (f : Fin as.length α β) : List β := go as #[] (by simp) where
/-- Auxiliary for `mapFinIdx`:
`mapFinIdx.go [a₀, a₁, ...] acc = acc.toList ++ [f 0 a₀, f 1 a₁, ...]` -/
@[specialize] go : (bs : List α) (acc : Array β) bs.length + acc.size = as.length List β
| [], acc, h => acc.toList
| a :: as, acc, h =>
go as (acc.push (f acc.size, by simp at h; omega a)) (by simp at h ; omega)
/--
Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁, ...]`, returns the list
`[f 0 a₀, f 1 a₁, ...]`.
-/
@[inline] def mapIdx (f : Nat α β) (as : List α) : List β := go as #[] where
@@ -25,34 +41,178 @@ Given a function `f : Nat → α → β` and `as : list α`, `as = [a₀, a₁,
| [], acc => acc.toList
| a :: as, acc => go as (acc.push (f acc.size a))
/-! ### mapFinIdx -/
@[simp]
theorem mapFinIdx_nil {f : Fin 0 α β} : mapFinIdx [] f = [] :=
rfl
@[simp] theorem length_mapFinIdx_go :
(mapFinIdx.go as f bs acc h).length = as.length := by
induction bs generalizing acc with
| nil => simpa using h
| cons _ _ ih => simp [mapFinIdx.go, ih]
@[simp] theorem length_mapFinIdx {as : List α} {f : Fin as.length α β} :
(as.mapFinIdx f).length = as.length := by
simp [mapFinIdx, length_mapFinIdx_go]
theorem getElem_mapFinIdx_go {as : List α} {f : Fin as.length α β} {i : Nat} {h} {w} :
(mapFinIdx.go as f bs acc h)[i] =
if w' : i < acc.size then acc[i] else f i, by simp at w; omega (bs[i - acc.size]'(by simp at w; omega)) := by
induction bs generalizing acc with
| nil =>
simp only [length_mapFinIdx_go, length_nil, Nat.zero_add] at w h
simp only [mapFinIdx.go, Array.getElem_toList]
rw [dif_pos]
| cons _ _ ih =>
simp [mapFinIdx.go]
rw [ih]
simp
split <;> rename_i h₁ <;> split <;> rename_i h₂
· rw [Array.getElem_push_lt]
· have h₃ : i = acc.size := by omega
subst h₃
simp
· omega
· have h₃ : i - acc.size = (i - (acc.size + 1)) + 1 := by omega
simp [h₃]
@[simp] theorem getElem_mapFinIdx {as : List α} {f : Fin as.length α β} {i : Nat} {h} :
(as.mapFinIdx f)[i] = f i, by simp at h; omega (as[i]'(by simp at h; omega)) := by
simp [mapFinIdx, getElem_mapFinIdx_go]
theorem mapFinIdx_eq_ofFn {as : List α} {f : Fin as.length α β} :
as.mapFinIdx f = List.ofFn fun i : Fin as.length => f i as[i] := by
apply ext_getElem <;> simp
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : Fin l.length α β} {i : Nat} :
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f i, by simp [getElem?_eq_some_iff] at m; exact m.1 x := by
simp only [getElem?_def, length_mapFinIdx, getElem_mapFinIdx]
split <;> simp
@[simp]
theorem mapFinIdx_cons {l : List α} {a : α} {f : Fin (l.length + 1) α β} :
mapFinIdx (a :: l) f = f 0 a :: mapFinIdx l (fun i => f i.succ) := by
apply ext_getElem
· simp
· rintro (_|i) h₁ h₂ <;> simp
theorem mapFinIdx_append {K L : List α} {f : Fin (K ++ L).length α β} :
(K ++ L).mapFinIdx f =
K.mapFinIdx (fun i => f (i.castLE (by simp))) ++ L.mapFinIdx (fun i => f ((i.natAdd K.length).cast (by simp))) := by
apply ext_getElem
· simp
· intro i h₁ h₂
rw [getElem_append]
simp only [getElem_mapFinIdx, length_mapFinIdx]
split <;> rename_i h
· rw [getElem_append_left]
congr
· simp only [Nat.not_lt] at h
rw [getElem_append_right h]
congr
simp
omega
@[simp] theorem mapFinIdx_concat {l : List α} {e : α} {f : Fin (l ++ [e]).length α β}:
(l ++ [e]).mapFinIdx f = l.mapFinIdx (fun i => f (i.castLE (by simp))) ++ [f l.length, by simp e] := by
simp [mapFinIdx_append]
congr
theorem mapFinIdx_singleton {a : α} {f : Fin 1 α β} :
[a].mapFinIdx f = [f 0, by simp a] := by
simp
theorem mapFinIdx_eq_enum_map {l : List α} {f : Fin l.length α β} :
l.mapFinIdx f = l.enum.attach.map
fun i, x, m =>
f i, by rw [mk_mem_enum_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1 x := by
apply ext_getElem <;> simp
@[simp]
theorem mapFinIdx_eq_nil_iff {l : List α} {f : Fin l.length α β} :
l.mapFinIdx f = [] l = [] := by
rw [mapFinIdx_eq_enum_map, map_eq_nil_iff, attach_eq_nil_iff, enum_eq_nil_iff]
theorem mapFinIdx_ne_nil_iff {l : List α} {f : Fin l.length α β} :
l.mapFinIdx f [] l [] := by
simp
theorem exists_of_mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length α β}
(h : b l.mapFinIdx f) : (i : Fin l.length), f i l[i] = b := by
rw [mapFinIdx_eq_enum_map] at h
replace h := exists_of_mem_map h
simp only [mem_attach, true_and, Subtype.exists, Prod.exists, mk_mem_enum_iff_getElem?] at h
obtain i, b, h, rfl := h
rw [getElem?_eq_some_iff] at h
obtain h', rfl := h
exact i, h', rfl
@[simp] theorem mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length α β} :
b l.mapFinIdx f (i : Fin l.length), f i l[i] = b := by
constructor
· intro h
exact exists_of_mem_mapFinIdx h
· rintro i, h, rfl
rw [mem_iff_getElem]
exact i, by simp
theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : Fin l.length α β} :
l.mapFinIdx f = b :: l₂
(a : α) (l₁ : List α) (h : l = a :: l₁),
f 0, by simp [h] a = b l₁.mapFinIdx (fun i => f (i.succ.cast (by simp [h]))) = l₂ := by
cases l with
| nil => simp
| cons x l' =>
simp only [mapFinIdx_cons, cons.injEq, length_cons, Fin.zero_eta, Fin.cast_succ_eq,
exists_and_left]
constructor
· rintro rfl, rfl
refine x, rfl, l', by simp
· rintro a, rfl, h, _, rfl, rfl, h
exact rfl, h
theorem mapFinIdx_eq_cons_iff' {l : List α} {b : β} {f : Fin l.length α β} :
l.mapFinIdx f = b :: l₂
l.head?.pbind (fun x m => (f 0, by cases l <;> simp_all x)) = some b
l.tail?.attach.map (fun t, m => t.mapFinIdx fun i => f (i.succ.cast (by cases l <;> simp_all))) = some l₂ := by
cases l <;> simp
theorem mapFinIdx_eq_iff {l : List α} {f : Fin l.length α β} :
l.mapFinIdx f = l' h : l'.length = l.length, (i : Nat) (h : i < l.length), l'[i] = f i, h l[i] := by
constructor
· rintro rfl
simp
· rintro h, w
apply ext_getElem <;> simp_all
theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : Fin l.length α β} :
l.mapFinIdx f = l.mapFinIdx g (i : Fin l.length), f i l[i] = g i l[i] := by
rw [eq_comm, mapFinIdx_eq_iff]
simp [Fin.forall_iff]
@[simp] theorem mapFinIdx_mapFinIdx {l : List α} {f : Fin l.length α β} {g : Fin _ β γ} :
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i => g (i.cast (by simp)) f i) := by
simp [mapFinIdx_eq_iff]
theorem mapFinIdx_eq_replicate_iff {l : List α} {f : Fin l.length α β} {b : β} :
l.mapFinIdx f = replicate l.length b (i : Fin l.length), f i l[i] = b := by
simp [eq_replicate_iff, length_mapFinIdx, mem_mapFinIdx, forall_exists_index, true_and]
@[simp] theorem mapFinIdx_reverse {l : List α} {f : Fin l.reverse.length α β} :
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i => f l.length - 1 - i, by simp; omega)).reverse := by
simp [mapFinIdx_eq_iff]
intro i h
congr
omega
/-! ### mapIdx -/
@[simp]
theorem mapIdx_nil {f : Nat α β} : mapIdx f [] = [] :=
rfl
theorem mapIdx_go_append {l₁ l₂ : List α} {arr : Array β} :
mapIdx.go f (l₁ ++ l₂) arr = mapIdx.go f l₂ (List.toArray (mapIdx.go f l₁ arr)) := by
generalize h : (l₁ ++ l₂).length = len
induction len generalizing l₁ arr with
| zero =>
have l₁_nil : l₁ = [] := by
cases l₁
· rfl
· contradiction
have l₂_nil : l₂ = [] := by
cases l₂
· rfl
· rw [List.length_append] at h; contradiction
rw [l₁_nil, l₂_nil]; simp only [mapIdx.go, List.toArray_toList]
| succ len ih =>
cases l₁ with
| nil =>
simp only [mapIdx.go, nil_append, List.toArray_toList]
| cons head tail =>
simp only [mapIdx.go, List.append_eq]
rw [ih]
· simp only [cons_append, length_cons, length_append, Nat.succ.injEq] at h
simp only [length_append, h]
theorem mapIdx_go_length {arr : Array β} :
length (mapIdx.go f l arr) = length l + arr.size := by
induction l generalizing arr with
@@ -60,16 +220,6 @@ theorem mapIdx_go_length {arr : Array β} :
| cons _ _ ih =>
simp only [mapIdx.go, ih, Array.size_push, Nat.add_succ, length_cons, Nat.add_comm]
@[simp] theorem mapIdx_concat {l : List α} {e : α} :
mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := by
unfold mapIdx
rw [mapIdx_go_append]
simp only [mapIdx.go, Array.size_toArray, mapIdx_go_length, length_nil, Nat.add_zero,
Array.push_toList]
@[simp] theorem mapIdx_singleton {a : α} : mapIdx f [a] = [f 0 a] := by
simpa using mapIdx_concat (l := [])
theorem length_mapIdx_go : {l : List α} {arr : Array β},
(mapIdx.go f l arr).length = l.length + arr.size
| [], _ => by simp [mapIdx.go]
@@ -86,16 +236,16 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
(mapIdx.go f l arr)[i]? =
if h : i < arr.size then some arr[i] else Option.map (f i) l[i - arr.size]?
| [], arr, i => by
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_eq, Array.length_toList,
Array.getElem_eq_getElem_toList, length_nil, Nat.not_lt_zero, reduceDIte, Option.map_none']
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
Array.getElem_toList, length_nil, Nat.not_lt_zero, reduceDIte, Option.map_none']
| a :: l, arr, i => by
rw [mapIdx.go, getElem?_mapIdx_go]
simp only [Array.size_push]
split <;> split
· simp only [Option.some.injEq]
rw [Array.getElem_eq_getElem_toList]
rw [ Array.getElem_toList]
simp only [Array.push_toList]
rw [getElem_append_left, Array.getElem_eq_getElem_toList]
rw [getElem_append_left, Array.getElem_toList]
· have : i = arr.size := by omega
simp_all
· omega
@@ -112,6 +262,15 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
rw [ getElem?_eq_getElem, getElem?_mapIdx, getElem?_eq_getElem (by simpa using h)]
simp
@[simp] theorem mapFinIdx_eq_mapIdx {l : List α} {f : Fin l.length α β} {g : Nat α β}
(h : (i : Fin l.length), f i l[i] = g i l[i]) :
l.mapFinIdx f = l.mapIdx g := by
simp_all [mapFinIdx_eq_iff]
theorem mapIdx_eq_mapFinIdx {l : List α} {f : Nat α β} :
l.mapIdx f = l.mapFinIdx (fun i => f i) := by
simp [mapFinIdx_eq_mapIdx]
theorem mapIdx_eq_enum_map {l : List α} :
l.mapIdx f = l.enum.map (Function.uncurry f) := by
ext1 i
@@ -130,9 +289,16 @@ theorem mapIdx_append {K L : List α} :
| nil => rfl
| cons _ _ ih => simp [ih (f := fun i => f (i + 1)), Nat.add_assoc]
@[simp] theorem mapIdx_concat {l : List α} {e : α} :
mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := by
simp [mapIdx_append]
theorem mapIdx_singleton {a : α} : mapIdx f [a] = [f 0 a] := by
simp
@[simp]
theorem mapIdx_eq_nil_iff {l : List α} : List.mapIdx f l = [] l = [] := by
rw [List.mapIdx_eq_enum_map, List.map_eq_nil_iff, List.enum_eq_nil]
rw [List.mapIdx_eq_enum_map, List.map_eq_nil_iff, List.enum_eq_nil_iff]
theorem mapIdx_ne_nil_iff {l : List α} :
List.mapIdx f l [] l [] := by
@@ -140,13 +306,8 @@ theorem mapIdx_ne_nil_iff {l : List α} :
theorem exists_of_mem_mapIdx {b : β} {l : List α}
(h : b mapIdx f l) : (i : Nat) (h : i < l.length), f i l[i] = b := by
rw [mapIdx_eq_enum_map] at h
replace h := exists_of_mem_map h
simp only [Prod.exists, mk_mem_enum_iff_getElem?, Function.uncurry_apply_pair] at h
obtain i, b, h, rfl := h
rw [getElem?_eq_some_iff] at h
obtain h, rfl := h
exact i, h, rfl
rw [mapIdx_eq_mapFinIdx] at h
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
@[simp] theorem mem_mapIdx {b : β} {l : List α} :
b mapIdx f l (i : Nat) (h : i < l.length), f i l[i] = b := by

View File

@@ -5,6 +5,7 @@ Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, M
-/
prelude
import Init.Data.List.TakeDrop
import Init.Data.List.Attach
/-!
# Lemmas about `List.mapM` and `List.forM`.
@@ -48,6 +49,9 @@ theorem mapM'_eq_mapM [Monad m] [LawfulMonad m] (f : α → m β) (l : List α)
@[simp] theorem mapM_cons [Monad m] [LawfulMonad m] (f : α m β) :
(a :: l).mapM f = (return ( f a) :: ( l.mapM f)) := by simp [ mapM'_eq_mapM, mapM']
@[simp] theorem mapM_id {l : List α} {f : α Id β} : l.mapM f = l.map f := by
induction l <;> simp_all
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] (f : α m β) {l₁ l₂ : List α} :
(l₁ ++ l₂).mapM f = (return ( l₁.mapM f) ++ ( l₂.mapM f)) := by induction l₁ <;> simp [*]
@@ -72,6 +76,52 @@ theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] (f : α → m β)
reverse_cons, reverse_nil, nil_append, singleton_append]
simp [bind_pure_comp]
/-! ### foldlM and foldrM -/
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (l : List β₁) (init : α) :
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
induction l generalizing g init <;> simp [*]
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (l : List β₁)
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
induction l generalizing g init <;> simp [*]
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : γ β m γ) (l : List α) (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
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filterMap_cons, foldlM_cons]
cases f a <;> simp [ih]
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : β γ m γ) (l : List α) (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
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filterMap_cons, foldrM_cons]
cases f a <;> simp [ih]
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : β α m β) (l : List α) (init : β) :
(l.filter p).foldlM g init =
l.foldlM (fun x y => if p y then g x y else pure x) init := by
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filter_cons, foldlM_cons]
split <;> simp [ih]
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : α β m β) (l : List α) (init : β) :
(l.filter p).foldrM g init =
l.foldrM (fun x y => if p x then g x y else pure y) init := by
induction l generalizing init with
| nil => rfl
| cons a l ih =>
simp only [filter_cons, foldrM_cons]
split <;> simp [ih]
/-! ### forM -/
-- We use `List.forM` as the simp normal form, rather that `ForM.forM`.
@@ -87,6 +137,176 @@ theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] (f : α → m β)
(l₁ ++ l₂).forM f = (do l₁.forM f; l₂.forM f) := by
induction l₁ <;> simp [*]
/-! ### forIn' -/
theorem forIn'_loop_congr [Monad m] {as bs : List α}
{f : (a' : α) a' as β m (ForInStep β)}
{g : (a' : α) a' bs β m (ForInStep β)}
{b : β} (ha : ys, ys ++ xs = as) (hb : ys, ys ++ xs = bs)
(h : a m m' b, f a m b = g a m' b) : forIn'.loop as f xs b ha = forIn'.loop bs g xs b hb := by
induction xs generalizing b with
| nil => simp [forIn'.loop]
| cons a xs ih =>
simp only [forIn'.loop] at *
congr 1
· rw [h]
· funext s
obtain b | b := s
· rfl
· simp
rw [ih]
@[simp] theorem forIn'_cons [Monad m] {a : α} {as : List α}
(f : (a' : α) a' a :: as β m (ForInStep β)) (b : β) :
forIn' (a::as) b f = f a (mem_cons_self a as) b >>=
fun | ForInStep.done b => pure b | ForInStep.yield b => forIn' as b fun a' m b => f a' (mem_cons_of_mem a m) b := by
simp only [forIn', List.forIn', forIn'.loop]
congr 1
funext s
obtain b | b := s
· rfl
· apply forIn'_loop_congr
intros
rfl
@[simp] theorem forIn_cons [Monad m] (f : α β m (ForInStep β)) (a : α) (as : List α) (b : β) :
forIn (a::as) b f = f a b >>= fun | ForInStep.done b => pure b | ForInStep.yield b => forIn as b f := by
have := forIn'_cons (a := a) (as := as) (fun a' _ b => f a' b) b
simpa only [forIn'_eq_forIn]
@[congr] theorem forIn'_congr [Monad m] {as bs : List α} (w : as = bs)
{b b' : β} (hb : b = b')
{f : (a' : α) a' as β m (ForInStep β)}
{g : (a' : α) a' bs β m (ForInStep β)}
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
forIn' as b f = forIn' bs b' g := by
induction bs generalizing as b b' with
| nil =>
subst w
simp [hb, forIn'_nil]
| cons b bs ih =>
cases as with
| nil => simp at w
| cons a as =>
simp only [cons.injEq] at w
obtain rfl, rfl := w
simp only [forIn'_cons]
congr 1
· simp [h, hb]
· funext s
obtain b | b := s
· rfl
· simp
rw [ih rfl rfl]
intro a m b
exact h a (mem_cons_of_mem _ m) b
/--
We can express a for loop over a list as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
(l : List α) (f : (a : α) a l β m (ForInStep β)) (init : β) :
forIn' l init f = ForInStep.value <$>
l.attach.foldlM (fun b a, m => match b with
| .yield b => f a m b
| .done b => pure (.done b)) (ForInStep.yield init) := by
induction l generalizing init with
| nil => simp
| cons a as ih =>
simp only [forIn'_cons, attach_cons, foldlM_cons, _root_.map_bind]
congr 1
funext x
match x with
| .done b =>
clear ih
dsimp
induction as with
| nil => simp
| cons a as ih =>
simp only [attach_cons, map_cons, map_map, Function.comp_def, foldlM_cons, pure_bind]
specialize ih (fun a m b => f a (by
simp only [mem_cons] at m
rcases m with rfl|m
· apply mem_cons_self
· exact mem_cons_of_mem _ (mem_cons_of_mem _ m)) b)
simp [ih, List.foldlM_map]
| .yield b =>
simp [ih, List.foldlM_map]
/-- We can express a for loop over a list which always yields as a fold. -/
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
(l : List α) (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
simp only [forIn'_eq_foldlM]
generalize l.attach = l'
induction l' generalizing init <;> simp_all
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : List α) (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
simp only [forIn'_eq_foldlM]
generalize l.attach = l'
induction l' generalizing init <;> simp_all
@[simp] theorem forIn'_yield_eq_foldl
(l : List α) (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
simp only [forIn'_eq_foldlM]
generalize l.attach = l'
induction l' generalizing init <;> simp_all
/--
We can express a for loop over a list as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
(f : α β m (ForInStep β)) (init : β) (l : List α) :
forIn l init f = ForInStep.value <$>
l.foldlM (fun b a => match b with
| .yield b => f a b
| .done b => pure (.done b)) (ForInStep.yield init) := by
induction l generalizing init with
| nil => simp
| cons a as ih =>
simp only [foldlM_cons, bind_pure_comp, forIn_cons, _root_.map_bind]
congr 1
funext x
match x with
| .done b =>
clear ih
dsimp
induction as with
| nil => simp
| cons a as ih => simp [ih]
| .yield b =>
simp [ih]
/-- We can express a for loop over a list which always yields as a fold. -/
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
(l : List α) (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
simp only [forIn_eq_foldlM]
induction l generalizing init <;> simp_all
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : List α) (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
simp only [forIn_eq_foldlM]
induction l generalizing init <;> simp_all
@[simp] theorem forIn_yield_eq_foldl
(l : List α) (f : α β β) (init : β) :
forIn (m := Id) l init (fun a b => .yield (f a b)) =
l.foldl (fun b a => f a b) init := by
simp only [forIn_eq_foldlM]
induction l generalizing init <;> simp_all
/-! ### allM -/
theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α m Bool) (as : List α) :
@@ -99,14 +319,4 @@ theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α → m Bool) (as :
funext b
split <;> simp_all
/-! ### foldlM and foldrM -/
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (l : List β₁) (init : α) :
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
induction l generalizing g init <;> simp [*]
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (l : List β₁)
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
induction l generalizing g init <;> simp [*]
end List

View File

@@ -13,3 +13,6 @@ import Init.Data.List.Nat.Count
import Init.Data.List.Nat.Erase
import Init.Data.List.Nat.Find
import Init.Data.List.Nat.BEq
import Init.Data.List.Nat.Modify
import Init.Data.List.Nat.InsertIdx
import Init.Data.List.Nat.Perm

View File

@@ -9,7 +9,7 @@ import Init.Data.List.Basic
namespace List
/-! ### isEqv-/
/-! ### isEqv -/
theorem isEqv_eq_decide (a b : List α) (r) :
isEqv a b r = if h : a.length = b.length then

View File

@@ -64,3 +64,82 @@ theorem getElem_eraseIdx_of_ge (l : List α) (i : Nat) (j : Nat) (h : j < (l.era
(l.eraseIdx i)[j] = l[j + 1]'(by rw [length_eraseIdx] at h; split at h <;> omega) := by
rw [getElem_eraseIdx, dif_neg]
omega
theorem eraseIdx_set_eq {l : List α} {i : Nat} {a : α} :
(l.set i a).eraseIdx i = l.eraseIdx i := by
apply ext_getElem
· simp [length_eraseIdx]
· intro n h₁ h₂
rw [getElem_eraseIdx, getElem_eraseIdx]
split <;>
· rw [getElem_set_ne]
omega
theorem eraseIdx_set_lt {l : List α} {i : Nat} {j : Nat} {a : α} (h : j < i) :
(l.set i a).eraseIdx j = (l.eraseIdx j).set (i - 1) a := by
apply ext_getElem
· simp [length_eraseIdx]
· intro n h₁ h₂
simp only [length_eraseIdx, length_set] at h₁
simp only [getElem_eraseIdx, getElem_set]
split
· split
· split
· rfl
· omega
· split
· omega
· rfl
· split
· split
· rfl
· omega
· have t : i - 1 n := by omega
simp [t]
theorem eraseIdx_set_gt {l : List α} {i : Nat} {j : Nat} {a : α} (h : i < j) :
(l.set i a).eraseIdx j = (l.eraseIdx j).set i a := by
apply ext_getElem
· simp [length_eraseIdx]
· intro n h₁ h₂
simp only [length_eraseIdx, length_set] at h₁
simp only [getElem_eraseIdx, getElem_set]
split
· rfl
· split
· split
· rfl
· omega
· have t : i n := by omega
simp [t]
@[simp] theorem set_getElem_succ_eraseIdx_succ
{l : List α} {i : Nat} (h : i + 1 < l.length) :
(l.eraseIdx (i + 1)).set i l[i + 1] = l.eraseIdx i := by
apply ext_getElem
· simp only [length_set, length_eraseIdx, h, reduceIte]
rw [if_pos]
omega
· intro n h₁ h₂
simp [getElem_set, getElem_eraseIdx]
split
· split
· omega
· simp_all
· split
· split
· rfl
· omega
· have t : ¬ n < i := by omega
simp [t]
@[simp] theorem eraseIdx_length_sub_one (l : List α) :
(l.eraseIdx (l.length - 1)) = l.dropLast := by
apply ext_getElem
· simp [length_eraseIdx]
omega
· intro n h₁ h₂
rw [getElem_eraseIdx_of_lt, getElem_dropLast]
simp_all
end List

View File

@@ -9,6 +9,32 @@ import Init.Data.List.Find
namespace List
open Nat
theorem find?_eq_some_iff_getElem {xs : List α} {p : α Bool} {b : α} :
xs.find? p = some b p b i h, xs[i] = b j : Nat, (hj : j < i) !p xs[j] := by
rw [find?_eq_some_iff_append]
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
constructor
· rintro as, bs, rfl, h
refine as.length, ?_, ?_, ?_
· simp only [length_append, length_cons]
refine Nat.lt_add_of_pos_right (zero_lt_succ bs.length)
· rw [getElem_append_right (Nat.le_refl as.length)]
simp
· intro j h'
rw [getElem_append_left h']
exact h _ (getElem_mem h')
· rintro i, h, rfl, h'
refine xs.take i, xs.drop (i+1), ?_, ?_
· rw [getElem_cons_drop, take_append_drop]
· intro a m
rw [mem_take_iff_getElem] at m
obtain j, h, rfl := m
apply h'
omega
theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : List α} {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
simp only [findIdx?_eq_findSome?_enum] at h

View File

@@ -0,0 +1,242 @@
/-
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
-/
prelude
import Init.Data.List.Nat.Modify
/-!
# insertIdx
Proves various lemmas about `List.insertIdx`.
-/
open Function
open Nat
namespace List
universe u
variable {α : Type u}
section InsertIdx
variable {a : α}
@[simp]
theorem insertIdx_zero (s : List α) (x : α) : insertIdx 0 x s = x :: s :=
rfl
@[simp]
theorem insertIdx_succ_nil (n : Nat) (a : α) : insertIdx (n + 1) a [] = [] :=
rfl
@[simp]
theorem insertIdx_succ_cons (s : List α) (hd x : α) (n : Nat) :
insertIdx (n + 1) x (hd :: s) = hd :: insertIdx n x s :=
rfl
theorem length_insertIdx : n as, (insertIdx n a as).length = if n as.length then as.length + 1 else as.length
| 0, _ => by simp
| n + 1, [] => by simp
| n + 1, a :: as => by
simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_le_add_iff_right]
split <;> rfl
theorem length_insertIdx_of_le_length (h : n length as) : length (insertIdx n a as) = length as + 1 := by
simp [length_insertIdx, h]
theorem length_insertIdx_of_length_lt (h : length as < n) : length (insertIdx n a as) = length as := by
simp [length_insertIdx, h]
theorem eraseIdx_insertIdx (n : Nat) (l : List α) : (l.insertIdx n a).eraseIdx n = l := by
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
exact modifyTailIdx_id _ _
theorem insertIdx_eraseIdx_of_ge :
n m as,
n < length as n m insertIdx m a (as.eraseIdx n) = (as.insertIdx (m + 1) a).eraseIdx n
| 0, 0, [], has, _ => (Nat.lt_irrefl _ has).elim
| 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertIdx]
| 0, _ + 1, _ :: _, _, _ => rfl
| n + 1, m + 1, a :: as, has, hmn =>
congrArg (cons a) <|
insertIdx_eraseIdx_of_ge n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
theorem insertIdx_eraseIdx_of_le :
n m as,
n < length as m n insertIdx m a (as.eraseIdx n) = (as.insertIdx m a).eraseIdx (n + 1)
| _, 0, _ :: _, _, _ => rfl
| n + 1, m + 1, a :: as, has, hmn =>
congrArg (cons a) <|
insertIdx_eraseIdx_of_le n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
theorem insertIdx_comm (a b : α) :
(i j : Nat) (l : List α) (_ : i j) (_ : j length l),
(l.insertIdx i a).insertIdx (j + 1) b = (l.insertIdx j b).insertIdx i a
| 0, j, l => by simp [insertIdx]
| _ + 1, 0, _ => fun h => (Nat.not_lt_zero _ h).elim
| i + 1, j + 1, [] => by simp
| i + 1, j + 1, c :: l => fun h₀ h₁ => by
simp only [insertIdx_succ_cons, cons.injEq, true_and]
exact insertIdx_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁)
theorem mem_insertIdx {a b : α} :
{n : Nat} {l : List α} (_ : n l.length), a l.insertIdx n b a = b a l
| 0, as, _ => by simp
| _ + 1, [], h => (Nat.not_succ_le_zero _ h).elim
| n + 1, a' :: as, h => by
rw [List.insertIdx_succ_cons, mem_cons, mem_insertIdx (Nat.le_of_succ_le_succ h),
or_assoc, @or_comm (a = a'), or_assoc, mem_cons]
theorem insertIdx_of_length_lt (l : List α) (x : α) (n : Nat) (h : l.length < n) :
insertIdx n x l = l := by
induction l generalizing n with
| nil =>
cases n
· simp at h
· simp
| cons x l ih =>
cases n
· simp at h
· simp only [Nat.succ_lt_succ_iff, length] at h
simpa using ih _ h
@[simp]
theorem insertIdx_length_self (l : List α) (x : α) : insertIdx l.length x l = l ++ [x] := by
induction l with
| nil => simp
| cons x l ih => simpa using ih
theorem length_le_length_insertIdx (l : List α) (x : α) (n : Nat) :
l.length (insertIdx n x l).length := by
simp only [length_insertIdx]
split <;> simp
theorem length_insertIdx_le_succ (l : List α) (x : α) (n : Nat) :
(insertIdx n x l).length l.length + 1 := by
simp only [length_insertIdx]
split <;> simp
theorem getElem_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (hn : k < n)
(hk : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] = l[k]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
induction n generalizing k l with
| zero => simp at hn
| succ n ih =>
cases l with
| nil => simp
| cons _ _=>
cases k
· simp [get]
· rw [Nat.succ_lt_succ_iff] at hn
simpa using ih hn _
@[simp]
theorem getElem_insertIdx_self {l : List α} {x : α} {n : Nat} (hn : n < (insertIdx n x l).length) :
(insertIdx n x l)[n] = x := by
induction l generalizing n with
| nil =>
simp [length_insertIdx] at hn
split at hn
· simp_all
· omega
| cons _ _ ih =>
cases n
· simp
· simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_lt_add_iff_right] at hn ih
simpa using ih hn
theorem getElem_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (hn : n + 1 k)
(hk : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] = l[k - 1]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
induction l generalizing n k with
| nil =>
cases n with
| zero =>
simp only [insertIdx_zero, length_singleton, lt_one_iff] at hk
omega
| succ n => simp at hk
| cons _ _ ih =>
cases n with
| zero =>
simp only [insertIdx_zero] at hk
cases k with
| zero => omega
| succ k => simp
| succ n =>
cases k with
| zero => simp
| succ k =>
simp only [insertIdx_succ_cons, getElem_cons_succ]
rw [ih (by omega)]
cases k with
| zero => omega
| succ k => simp
theorem getElem_insertIdx {l : List α} {x : α} {n k : Nat} (h : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] =
if h₁ : k < n then
l[k]'(by simp [length_insertIdx] at h; split at h <;> omega)
else
if h₂ : k = n then
x
else
l[k-1]'(by simp [length_insertIdx] at h; split at h <;> omega) := by
split <;> rename_i h₁
· rw [getElem_insertIdx_of_lt h₁]
· split <;> rename_i h₂
· subst h₂
rw [getElem_insertIdx_self h]
· rw [getElem_insertIdx_of_ge (by omega)]
theorem getElem?_insertIdx {l : List α} {x : α} {n k : Nat} :
(insertIdx n x l)[k]? =
if k < n then
l[k]?
else
if k = n then
if k l.length then some x else none
else
l[k-1]? := by
rw [getElem?_def]
split <;> rename_i h
· rw [getElem_insertIdx h]
simp only [length_insertIdx] at h
split <;> rename_i h₁
· rw [getElem?_def, dif_pos]
· split <;> rename_i h₂
· rw [if_pos]
split at h <;> omega
· rw [getElem?_def]
simp only [Option.some_eq_dite_none_right, exists_prop, and_true]
split at h <;> omega
· simp only [length_insertIdx] at h
split <;> rename_i h₁
· rw [getElem?_eq_none]
split at h <;> omega
· split <;> rename_i h₂
· rw [if_neg]
split at h <;> omega
· rw [getElem?_eq_none]
split at h <;> omega
theorem getElem?_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (h : k < n) :
(insertIdx n x l)[k]? = l[k]? := by
rw [getElem?_insertIdx, if_pos h]
theorem getElem?_insertIdx_self {l : List α} {x : α} {n : Nat} :
(insertIdx n x l)[n]? = if n l.length then some x else none := by
rw [getElem?_insertIdx, if_neg (by omega)]
simp
theorem getElem?_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (h : n + 1 k) :
(insertIdx n x l)[k]? = l[k - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
end InsertIdx
end List

View File

@@ -0,0 +1,314 @@
/-
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
-/
prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Nat.Erase
namespace List
/-! ### modifyHead -/
@[simp] theorem length_modifyHead {f : α α} {l : List α} : (l.modifyHead f).length = l.length := by
cases l <;> simp [modifyHead]
theorem modifyHead_eq_set [Inhabited α] (f : α α) (l : List α) :
l.modifyHead f = l.set 0 (f (l[0]?.getD default)) := by cases l <;> simp [modifyHead]
@[simp] theorem modifyHead_eq_nil_iff {f : α α} {l : List α} :
l.modifyHead f = [] l = [] := by cases l <;> simp [modifyHead]
@[simp] theorem modifyHead_modifyHead {l : List α} {f g : α α} :
(l.modifyHead f).modifyHead g = l.modifyHead (g f) := by cases l <;> simp [modifyHead]
theorem getElem_modifyHead {l : List α} {f : α α} {n} (h : n < (l.modifyHead f).length) :
(l.modifyHead f)[n] = if h' : n = 0 then f (l[0]'(by simp at h; omega)) else l[n]'(by simpa using h) := by
cases l with
| nil => simp at h
| cons hd tl => cases n <;> simp
@[simp] theorem getElem_modifyHead_zero {l : List α} {f : α α} {h} :
(l.modifyHead f)[0] = f (l[0]'(by simpa using h)) := by simp [getElem_modifyHead]
@[simp] theorem getElem_modifyHead_succ {l : List α} {f : α α} {n} (h : n + 1 < (l.modifyHead f).length) :
(l.modifyHead f)[n + 1] = l[n + 1]'(by simpa using h) := by simp [getElem_modifyHead]
theorem getElem?_modifyHead {l : List α} {f : α α} {n} :
(l.modifyHead f)[n]? = if n = 0 then l[n]?.map f else l[n]? := by
cases l with
| nil => simp
| cons hd tl => cases n <;> simp
@[simp] theorem getElem?_modifyHead_zero {l : List α} {f : α α} :
(l.modifyHead f)[0]? = l[0]?.map f := by simp [getElem?_modifyHead]
@[simp] theorem getElem?_modifyHead_succ {l : List α} {f : α α} {n} :
(l.modifyHead f)[n + 1]? = l[n + 1]? := by simp [getElem?_modifyHead]
@[simp] theorem head_modifyHead (f : α α) (l : List α) (h) :
(l.modifyHead f).head h = f (l.head (by simpa using h)) := by
cases l with
| nil => simp at h
| cons hd tl => simp
@[simp] theorem head?_modifyHead {l : List α} {f : α α} :
(l.modifyHead f).head? = l.head?.map f := by cases l <;> simp
@[simp] theorem tail_modifyHead {f : α α} {l : List α} :
(l.modifyHead f).tail = l.tail := by cases l <;> simp
@[simp] theorem take_modifyHead {f : α α} {l : List α} {n} :
(l.modifyHead f).take n = (l.take n).modifyHead f := by
cases l <;> cases n <;> simp
@[simp] theorem drop_modifyHead_of_pos {f : α α} {l : List α} {n} (h : 0 < n) :
(l.modifyHead f).drop n = l.drop n := by
cases l <;> cases n <;> simp_all
@[simp] theorem eraseIdx_modifyHead_zero {f : α α} {l : List α} :
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by cases l <;> simp
@[simp] theorem eraseIdx_modifyHead_of_pos {f : α α} {l : List α} {n} (h : 0 < n) :
(l.modifyHead f).eraseIdx n = (l.eraseIdx n).modifyHead f := by cases l <;> cases n <;> simp_all
@[simp] theorem modifyHead_id : modifyHead (id : α α) = id := by funext l; cases l <;> simp
/-! ### modifyTailIdx -/
@[simp] theorem modifyTailIdx_id : n (l : List α), l.modifyTailIdx id n = l
| 0, _ => rfl
| _+1, [] => rfl
| n+1, a :: l => congrArg (cons a) (modifyTailIdx_id n l)
theorem eraseIdx_eq_modifyTailIdx : n (l : List α), eraseIdx l n = modifyTailIdx tail n l
| 0, l => by cases l <;> rfl
| _+1, [] => rfl
| _+1, _ :: _ => congrArg (cons _) (eraseIdx_eq_modifyTailIdx _ _)
@[simp] theorem length_modifyTailIdx (f : List α List α) (H : l, length (f l) = length l) :
n l, length (modifyTailIdx f n l) = length l
| 0, _ => H _
| _+1, [] => rfl
| _+1, _ :: _ => congrArg (·+1) (length_modifyTailIdx _ H _ _)
theorem modifyTailIdx_add (f : List α List α) (n) (l₁ l₂ : List α) :
modifyTailIdx f (l₁.length + n) (l₁ ++ l₂) = l₁ ++ modifyTailIdx f n l₂ := by
induction l₁ <;> simp [*, Nat.succ_add]
theorem modifyTailIdx_eq_take_drop (f : List α List α) (H : f [] = []) :
n l, modifyTailIdx f n l = take n l ++ f (drop n l)
| 0, _ => rfl
| _ + 1, [] => H.symm
| n + 1, b :: l => congrArg (cons b) (modifyTailIdx_eq_take_drop f H n l)
theorem exists_of_modifyTailIdx (f : List α List α) {n} {l : List α} (h : n l.length) :
l₁ l₂, l = l₁ ++ l₂ l₁.length = n modifyTailIdx f n l = l₁ ++ f l₂ :=
have _, _, eq, hl : l₁ l₂, l = l₁ ++ l₂ l₁.length = n :=
_, _, (take_append_drop n l).symm, length_take_of_le h
_, _, eq, hl, hl eq modifyTailIdx_add (n := 0) ..
theorem modifyTailIdx_modifyTailIdx {f g : List α List α} (m : Nat) :
(n) (l : List α),
(l.modifyTailIdx f n).modifyTailIdx g (m + n) =
l.modifyTailIdx (fun l => (f l).modifyTailIdx g m) n
| 0, _ => rfl
| _ + 1, [] => rfl
| n + 1, a :: l => congrArg (List.cons a) (modifyTailIdx_modifyTailIdx m n l)
theorem modifyTailIdx_modifyTailIdx_le {f g : List α List α} (m n : Nat) (l : List α)
(h : n m) :
(l.modifyTailIdx f n).modifyTailIdx g m =
l.modifyTailIdx (fun l => (f l).modifyTailIdx g (m - n)) n := by
rcases Nat.exists_eq_add_of_le h with m, rfl
rw [Nat.add_comm, modifyTailIdx_modifyTailIdx, Nat.add_sub_cancel]
theorem modifyTailIdx_modifyTailIdx_self {f g : List α List α} (n : Nat) (l : List α) :
(l.modifyTailIdx f n).modifyTailIdx g n = l.modifyTailIdx (g f) n := by
rw [modifyTailIdx_modifyTailIdx_le n n l (Nat.le_refl n), Nat.sub_self]; rfl
/-! ### modify -/
@[simp] theorem modify_nil (f : α α) (n) : [].modify f n = [] := by cases n <;> rfl
@[simp] theorem modify_zero_cons (f : α α) (a : α) (l : List α) :
(a :: l).modify f 0 = f a :: l := rfl
@[simp] theorem modify_succ_cons (f : α α) (a : α) (l : List α) (n) :
(a :: l).modify f (n + 1) = a :: l.modify f n := by rfl
theorem modifyHead_eq_modify_zero (f : α α) (l : List α) :
l.modifyHead f = l.modify f 0 := by cases l <;> simp
@[simp] theorem modify_eq_nil_iff (f : α α) (n) (l : List α) :
l.modify f n = [] l = [] := by cases l <;> cases n <;> simp
theorem getElem?_modify (f : α α) :
n (l : List α) m, (modify f n l)[m]? = (fun a => if n = m then f a else a) <$> l[m]?
| n, l, 0 => by cases l <;> cases n <;> simp
| n, [], _+1 => by cases n <;> rfl
| 0, _ :: l, m+1 => by cases h : l[m]? <;> simp [h, modify, m.succ_ne_zero.symm]
| n+1, a :: l, m+1 => by
simp only [modify_succ_cons, getElem?_cons_succ, Nat.reduceEqDiff, Option.map_eq_map]
refine (getElem?_modify f n l m).trans ?_
cases h' : l[m]? <;> by_cases h : n = m <;>
simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h']
@[simp] theorem length_modify (f : α α) : n l, length (modify f n l) = length l :=
length_modifyTailIdx _ fun l => by cases l <;> rfl
@[simp] theorem getElem?_modify_eq (f : α α) (n) (l : List α) :
(modify f n l)[n]? = f <$> l[n]? := by
simp only [getElem?_modify, if_pos]
@[simp] theorem getElem?_modify_ne (f : α α) {m n} (l : List α) (h : m n) :
(modify f m l)[n]? = l[n]? := by
simp only [getElem?_modify, if_neg h, id_map']
theorem getElem_modify (f : α α) (n) (l : List α) (m) (h : m < (modify f n l).length) :
(modify f n l)[m] =
if n = m then f (l[m]'(by simp at h; omega)) else l[m]'(by simp at h; omega) := by
rw [getElem_eq_iff, getElem?_modify]
simp at h
simp [h]
@[simp] theorem getElem_modify_eq (f : α α) (n) (l : List α) (h) :
(modify f n l)[n] = f (l[n]'(by simpa using h)) := by simp [getElem_modify]
@[simp] theorem getElem_modify_ne (f : α α) {m n} (l : List α) (h : m n) (h') :
(modify f m l)[n] = l[n]'(by simpa using h') := by simp [getElem_modify, h]
theorem modify_eq_self {f : α α} {n} {l : List α} (h : l.length n) :
l.modify f n = l := by
apply ext_getElem
· simp
· intro m h₁ h₂
simp only [getElem_modify, ite_eq_right_iff]
intro h
omega
theorem modify_modify_eq (f g : α α) (n) (l : List α) :
(modify f n l).modify g n = modify (g f) n l := by
apply ext_getElem
· simp
· intro m h₁ h₂
simp only [getElem_modify, Function.comp_apply]
split <;> simp
theorem modify_modify_ne (f g : α α) {m n} (l : List α) (h : m n) :
(modify f m l).modify g n = (l.modify g n).modify f m := by
apply ext_getElem
· simp
· intro m' h₁ h₂
simp only [getElem_modify, getElem_modify_ne, h₂]
split <;> split <;> first | rfl | omega
theorem modify_eq_set [Inhabited α] (f : α α) (n) (l : List α) :
modify f n l = l.set n (f (l[n]?.getD default)) := by
apply ext_getElem
· simp
· intro m h₁ h₂
simp [getElem_modify, getElem_set, h₂]
split <;> rename_i h
· subst h
simp only [length_modify] at h₁
simp [h₁]
· rfl
theorem modify_eq_take_drop (f : α α) :
n l, modify f n l = take n l ++ modifyHead f (drop n l) :=
modifyTailIdx_eq_take_drop _ rfl
theorem modify_eq_take_cons_drop {f : α α} {n} {l : List α} (h : n < l.length) :
modify f n l = take n l ++ f l[n] :: drop (n + 1) l := by
rw [modify_eq_take_drop, drop_eq_getElem_cons h]; rfl
theorem exists_of_modify (f : α α) {n} {l : List α} (h : n < l.length) :
l₁ a l₂, l = l₁ ++ a :: l₂ l₁.length = n modify f n l = l₁ ++ f a :: l₂ :=
match exists_of_modifyTailIdx _ (Nat.le_of_lt h) with
| _, _::_, eq, hl, H => _, _, _, eq, hl, H
| _, [], eq, hl, _ => nomatch Nat.ne_of_gt h (eq append_nil _ hl)
@[simp] theorem modify_id (n) (l : List α) : l.modify id n = l := by
simp [modify]
theorem take_modify (f : α α) (n m) (l : List α) :
(modify f m l).take n = (take n l).modify f m := by
induction n generalizing l m with
| zero => simp
| succ n ih =>
cases l with
| nil => simp
| cons hd tl =>
cases m with
| zero => simp
| succ m => simp [ih]
theorem drop_modify_of_lt (f : α α) (n m) (l : List α) (h : n < m) :
(modify f n l).drop m = l.drop m := by
apply ext_getElem
· simp
· intro m' h₁ h₂
simp only [getElem_drop, getElem_modify, ite_eq_right_iff]
intro h'
omega
theorem drop_modify_of_ge (f : α α) (n m) (l : List α) (h : n m) :
(modify f n l).drop m = modify f (n - m) (drop m l) := by
apply ext_getElem
· simp
· intro m' h₁ h₂
simp [getElem_drop, getElem_modify, ite_eq_right_iff]
split <;> split <;> first | rfl | omega
theorem eraseIdx_modify_of_eq (f : α α) (n) (l : List α) :
(modify f n l).eraseIdx n = l.eraseIdx n := by
apply ext_getElem
· simp [length_eraseIdx]
· intro m h₁ h₂
simp only [getElem_eraseIdx, getElem_modify]
split <;> split <;> first | rfl | omega
theorem eraseIdx_modify_of_lt (f : α α) (i j) (l : List α) (h : j < i) :
(modify f i l).eraseIdx j = (l.eraseIdx j).modify f (i - 1) := by
apply ext_getElem
· simp [length_eraseIdx]
· intro k h₁ h₂
simp only [getElem_eraseIdx, getElem_modify]
by_cases h' : i - 1 = k
repeat' split
all_goals (first | rfl | omega)
theorem eraseIdx_modify_of_gt (f : α α) (i j) (l : List α) (h : j > i) :
(modify f i l).eraseIdx j = (l.eraseIdx j).modify f i := by
apply ext_getElem
· simp [length_eraseIdx]
· intro k h₁ h₂
simp only [getElem_eraseIdx, getElem_modify]
by_cases h' : i = k
repeat' split
all_goals (first | rfl | omega)
theorem modify_eraseIdx_of_lt (f : α α) (i j) (l : List α) (h : j < i) :
(l.eraseIdx i).modify f j = (l.modify f j).eraseIdx i := by
apply ext_getElem
· simp [length_eraseIdx]
· intro k h₁ h₂
simp only [getElem_eraseIdx, getElem_modify]
by_cases h' : j = k + 1
repeat' split
all_goals (first | rfl | omega)
theorem modify_eraseIdx_of_ge (f : α α) (i j) (l : List α) (h : j i) :
(l.eraseIdx i).modify f j = (l.modify f (j + 1)).eraseIdx i := by
apply ext_getElem
· simp [length_eraseIdx]
· intro k h₁ h₂
simp only [getElem_eraseIdx, getElem_modify]
by_cases h' : j + 1 = k + 1
repeat' split
all_goals (first | rfl | omega)
end List

View File

@@ -0,0 +1,54 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Perm
namespace List
/-- Helper lemma for `set_set_perm`-/
private theorem set_set_perm' {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : i + j < as.length)
(hj : 0 < j) :
(as.set i as[i + j]).set (i + j) as[i] ~ as := by
have : as =
as.take i ++ as[i] :: (as.take (i + j)).drop (i + 1) ++ as[i + j] :: as.drop (i + j + 1) := by
simp only [getElem_cons_drop, append_assoc, cons_append]
rw [ drop_append_of_le_length]
· simp
· simp; omega
conv => lhs; congr; congr; rw [this]
conv => rhs; rw [this]
rw [set_append_left _ _ (by simp; omega)]
rw [set_append_right _ _ (by simp; omega)]
rw [set_append_right _ _ (by simp; omega)]
simp only [length_append, length_take, length_set, length_cons, length_drop]
rw [(show i - min i as.length = 0 by omega)]
rw [(show i + j - (min i as.length + (min (i + j) as.length - (i + 1) + 1)) = 0 by omega)]
simp only [set_cons_zero]
simp only [append_assoc]
apply Perm.append_left
apply cons_append_cons_perm
theorem set_set_perm {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : j < as.length) :
(as.set i as[j]).set j as[i] ~ as := by
if h₃ : i = j then
simp [h₃]
else
if h₃ : i < j then
let j' := j - i
have t : j = i + j' := by omega
generalize j' = j' at t
subst t
exact set_set_perm' _ _ (by omega)
else
rw [set_comm _ _ _ (by omega)]
let i' := i - j
have t : i = j + i' := by omega
generalize i' = i' at t
subst t
apply set_set_perm' _ _ (by omega)
end List

View File

@@ -108,7 +108,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
@[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 [find?_eq_some]
rw [find?_eq_some_iff_append]
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_range'_1,
and_congr_right_iff]
simp only [range'_eq_append_iff, eq_comm (a := i :: _), range'_eq_cons_iff]
@@ -169,7 +169,7 @@ 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
theorem pairwise_lt_range (n : Nat) : Pairwise (· < ·) (range n) := by
simp (config := {decide := true}) only [range_eq_range', pairwise_lt_range']
simp +decide only [range_eq_range', pairwise_lt_range']
theorem pairwise_le_range (n : Nat) : Pairwise (· ·) (range n) :=
Pairwise.imp Nat.le_of_lt (pairwise_lt_range _)
@@ -177,10 +177,10 @@ theorem pairwise_le_range (n : Nat) : Pairwise (· ≤ ·) (range n) :=
theorem take_range (m n : Nat) : take m (range n) = range (min m n) := by
apply List.ext_getElem
· simp
· simp (config := { contextual := true }) [getElem_take, Nat.lt_min]
· simp +contextual [getElem_take, Nat.lt_min]
theorem nodup_range (n : Nat) : Nodup (range n) := by
simp (config := {decide := true}) only [range_eq_range', nodup_range']
simp +decide only [range_eq_range', nodup_range']
@[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
@@ -282,7 +282,7 @@ theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
@[simp] theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
(iota n).find? p = some i p i i iota n j, i < j j n !p j := by
rw [find?_eq_some]
rw [find?_eq_some_iff_append]
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
nil_append, Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_reverse, mem_range'_1,
and_congr_right_iff]
@@ -430,7 +430,10 @@ theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
/-! ### enum -/
@[simp]
theorem enum_eq_nil {l : List α} : List.enum l = [] l = [] := enumFrom_eq_nil
theorem enum_eq_nil_iff {l : List α} : List.enum l = [] l = [] := enumFrom_eq_nil
@[deprecated enum_eq_nil_iff (since := "2024-11-04")]
theorem enum_eq_nil {l : List α} : List.enum l = [] l = [] := enum_eq_nil_iff
@[simp] theorem enum_singleton (x : α) : enum [x] = [(0, x)] := rfl

View File

@@ -187,6 +187,9 @@ theorem take_add (l : List α) (m n : Nat) : l.take (m + n) = l.take m ++ (l.dro
· apply length_take_le
· apply Nat.le_add_right
theorem take_one {l : List α} : l.take 1 = l.head?.toList := by
induction l <;> simp
theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
(l.take n).dropLast = l.take (n - 1) := by
simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, Nat.min_eq_left, take_take, sub_le]
@@ -282,14 +285,14 @@ theorem mem_drop_iff_getElem {l : List α} {a : α} :
· rintro i, hm, rfl
refine i, by simp; omega, by rw [getElem_drop]
theorem head?_drop (l : List α) (n : Nat) :
@[simp] theorem head?_drop (l : List α) (n : Nat) :
(l.drop n).head? = l[n]? := by
rw [head?_eq_getElem?, getElem?_drop, Nat.add_zero]
theorem head_drop {l : List α} {n : Nat} (h : l.drop n []) :
@[simp] theorem head_drop {l : List α} {n : Nat} (h : l.drop n []) :
(l.drop n).head h = l[n]'(by simp_all) := by
have w : n < l.length := length_lt_of_drop_ne_nil h
simpa [getElem?_eq_getElem, h, w, head_eq_iff_head?_eq_some] using head?_drop l n
simp [getElem?_eq_getElem, h, w, head_eq_iff_head?_eq_some]
theorem getLast?_drop {l : List α} : (l.drop n).getLast? = if l.length n then none else l.getLast? := by
rw [getLast?_eq_getElem?, getElem?_drop]
@@ -300,7 +303,7 @@ theorem getLast?_drop {l : List α} : (l.drop n).getLast? = if l.length ≤ n th
congr
omega
theorem getLast_drop {l : List α} (h : l.drop n []) :
@[simp] theorem getLast_drop {l : List α} (h : l.drop n []) :
(l.drop n).getLast h = l.getLast (ne_nil_of_length_pos (by simp at h; omega)) := by
simp only [ne_eq, drop_eq_nil_iff] at h
apply Option.some_inj.1
@@ -342,7 +345,7 @@ theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l
rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;>
simp [Nat.add_sub_cancel_left, Nat.le_add_right]
theorem set_eq_take_append_cons_drop {l : List α} {n : Nat} {a : α} :
theorem set_eq_take_append_cons_drop (l : List α) (n : Nat) (a : α) :
l.set n a = if n < l.length then l.take n ++ a :: l.drop (n + 1) else l := by
split <;> rename_i h
· ext1 m
@@ -449,6 +452,26 @@ theorem reverse_drop {l : List α} {n : Nat} :
rw [w, take_zero, drop_of_length_le, reverse_nil]
omega
theorem take_add_one {l : List α} {n : Nat} :
l.take (n + 1) = l.take n ++ l[n]?.toList := by
simp [take_add, take_one]
theorem drop_eq_getElem?_toList_append {l : List α} {n : Nat} :
l.drop n = l[n]?.toList ++ l.drop (n + 1) := by
induction l generalizing n with
| nil => simp
| cons hd tl ih =>
cases n
· simp
· simp only [drop_succ_cons, getElem?_cons_succ]
rw [ih]
theorem drop_sub_one {l : List α} {n : Nat} (h : 0 < n) :
l.drop (n - 1) = l[n - 1]?.toList ++ l.drop n := by
rw [drop_eq_getElem?_toList_append]
congr
omega
/-! ### findIdx -/
theorem false_of_mem_take_findIdx {xs : List α} {p : α Bool} (h : x xs.take (xs.findIdx p)) :

View File

@@ -0,0 +1,80 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Kim Morrison
-/
prelude
import Init.Data.List.Basic
import Init.Data.Fin.Fold
/-!
# Theorems about `List.ofFn`
-/
namespace List
/--
`ofFn f` with `f : fin n → α` returns the list whose ith element is `f i`
```
ofFn f = [f 0, f 1, ... , f (n - 1)]
```
-/
def ofFn {n} (f : Fin n α) : List α := Fin.foldr n (f · :: ·) []
@[simp]
theorem length_ofFn (f : Fin n α) : (ofFn f).length = n := by
simp only [ofFn]
induction n with
| zero => simp
| succ n ih => simp [Fin.foldr_succ, ih]
@[simp]
protected theorem getElem_ofFn (f : Fin n α) (i : Nat) (h : i < (ofFn f).length) :
(ofFn f)[i] = f i, by simp_all := by
simp only [ofFn]
induction n generalizing i with
| zero => simp at h
| succ n ih =>
match i with
| 0 => simp [Fin.foldr_succ]
| i+1 =>
simp only [Fin.foldr_succ]
apply ih
simp_all
@[simp]
protected theorem getElem?_ofFn (f : Fin n α) (i) : (ofFn f)[i]? = if h : i < n then some (f i, h) else none :=
if h : i < (ofFn f).length
then by
rw [getElem?_eq_getElem h, List.getElem_ofFn]
· simp only [length_ofFn] at h; simp [h]
else by
rw [dif_neg] <;>
simpa using h
/-- `ofFn` on an empty domain is the empty list. -/
@[simp]
theorem ofFn_zero (f : Fin 0 α) : ofFn f = [] :=
ext_get (by simp) (fun i hi₁ hi₂ => by contradiction)
@[simp]
theorem ofFn_succ {n} (f : Fin (n + 1) α) : ofFn f = f 0 :: ofFn fun i => f i.succ :=
ext_get (by simp) (fun i hi₁ hi₂ => by
cases i
· simp
· simp)
@[simp]
theorem ofFn_eq_nil_iff {f : Fin n α} : ofFn f = [] n = 0 := by
cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq]
theorem head_ofFn {n} (f : Fin n α) (h : ofFn f []) :
(ofFn f).head h = f 0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h) := by
rw [ getElem_zero (length_ofFn _ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)),
List.getElem_ofFn]
theorem getLast_ofFn {n} (f : Fin n α) (h : ofFn f []) :
(ofFn f).getLast h = f n - 1, Nat.sub_one_lt (mt ofFn_eq_nil_iff.2 h) := by
simp [getLast_eq_getElem, length_ofFn, List.getElem_ofFn]
end List

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