Compare commits

...

117 Commits

Author SHA1 Message Date
Kim Morrison
6b9e5e111b oops, error in pattern 2025-09-11 22:38:42 +10:00
Kim Morrison
244d1080af oops, turn off option 2025-09-11 22:08:52 +10:00
Kim Morrison
e7bc38a6c1 oops, missed one 2025-09-11 22:00:10 +10:00
Kim Morrison
28e6556682 chore: fix remainining discrepancies for change in grind pattern heuristics 2025-09-11 21:23:19 +10:00
Joachim Breitner
e7d1cdd36a refactor: reimplement mkNoConfusionType in Lean (#10334)
This PR reimplements `mkNoConfusionType` in lean, thus removing the
remaining C code related to this construction.

Also uses the ctor elimination principles only when there are more than
three ctors.
2025-09-11 07:56:59 +00:00
Kim Morrison
dfcb5bb3a8 chore: remove a bad grind algebra instance (#10324)
This PR disables an unused instance that causes expensive typeclass
searches.
2025-09-11 06:44:47 +00:00
Kim Morrison
01ed345643 chore: more review of @[grind] annotations (#10340)
This PR completes the review of `@[grind]` annotations without a sigil
(e.g. `=` or `←`), replacing most of them with more specific annotations
or patterns.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2025-09-11 06:09:52 +00:00
Lean stage0 autoupdater
176fb1cf0e chore: update stage0 2025-09-11 06:13:42 +00:00
Leonardo de Moura
6b387da032 feat: new E-matching pattern inference for grind (#10342)
This PR implements a new E-matching pattern inference procedure that is
faithful to the behavior documented in the reference manual regarding
minimal indexable subexpressions. The old inference procedure was
failing to enforce this condition. For example, the manual documents
`[grind ->]` as follows

`[@grind →]` selects a multi-pattern from the hypotheses of the theorem.
In other words, `grind` will use the theorem for forwards reasoning.

To generate a pattern, it traverses the hypotheses of the theorem from
left to right. Each time it encounters a **minimal indexable
subexpression** which covers an argument which was not previously
covered, it adds that subexpression as a pattern, until all arguments
have been covered.

That said, the new procedure is currently disabled, and the following
option must be used to enable it.
```
set_option backward.grind.inferPattern false
```
Users can inspect differences between the old a new procedures using the
option
```
set_option backward.grind.checkInferPatternDiscrepancy true 
```
Example:
```lean
/--
warning: found discrepancy between old and new `grind` pattern inference procedures, old:
  [@List.length #2 (@toList _ #1 #0)]
new:
  [@toList #2 #1 #0]
use `set_option backward.grind.inferPattern true` to force old procedure
-/
#guard_msgs in
set_option backward.grind.checkInferPatternDiscrepancy true in
@[grind] theorem Vector.length_toList' (xs : Vector α n) : xs.toList.length = n := by sorry
```
2025-09-11 05:27:11 +00:00
Kim Morrison
c3667e2861 feat: upstream Function.Injective/Surjective (#10341)
This PR moves the definitions and basic facts about `Function.Injective`
and `Function.Surjective` up from Mathlib. We can do a better job of
arguing via injectivity in `grind` if these are available.
2025-09-11 04:04:46 +00:00
Leonardo de Moura
33266b23cd chore: use [grind =] (#10337) 2025-09-11 03:21:37 +00:00
Leonardo de Moura
a4a2bfa426 fix: minor issues in grind (#10339)
This PR fixes a few minor issues and applies a few cleanups.
2025-09-11 02:54:36 +00:00
Kim Morrison
b7520e7232 chore: cleanup grind annotations in List (#10338)
This PR updates `@[grind]` annotations which should be `@[grind =]`, for
robustness (and, presumably, in some fraction of cases the existing
heuristic for `@[grind]` is already too liberal).
2025-09-11 02:36:18 +00:00
Leonardo de Moura
0b84c3912e fix: over applied Grind.nestedProof marker (#10335)
This PR fixes the nested proof term detection in `grind`. It must check
whether the gadget `Grind.nestedProof` is over-applied.

closes #10327
2025-09-10 16:48:36 +00:00
Joachim Breitner
e96467f500 refactor: introduce SameCtorUtils (#10316)
This PR shares common functionality relate to equalities between same
constructors, and when these are type-correct. In particular it uses the
more complete logic from `mkInjectivityThm` also in other places, such
as `CasesOnSameCtor` and the deriving code for `BEq`, `DecidableEq`,
`Ord`, for more consistency and better error messages.
2025-09-10 14:32:58 +00:00
Sebastian Ullrich
bdab63048a doc: testing Lean while avoiding rebuilds for downstream projects (#10328) 2025-09-10 13:53:34 +00:00
Joachim Breitner
30a041902b refactor: implement mkNoConfusionImp in Lean (#10331)
This PR implements `mkNoConfusionImp` in Lean rather than in C. This
reduces our reliance on C, and may bring performance benefits from not
reducing `noConfusionType` during elaboration time (it still gets
reduced by the kernel when type-checking).
2025-09-10 13:51:23 +00:00
Eric Wieser
fbcad8f593 feat: allow separate handlers for literals and interpolations in expandInterpolatedStr (#6763)
This PR makes it possible to write custom interpolation notation which
treats interpolated `String`s specially.

Sometimes it is desirable for `let w := "world"; foo!"hello {w}"` and
`foo!"hello world"` to mean different things; for instance, if debugging
and wanting to show all interpolands with `repr`. The current approach
forces `hello` to also be rendered with `repr`, which is not desirable.

This doesn't modify any existing formatters.

Requested in [#lean4 > ✔ dbg_trace should use &#96;Repr&#96; instance @
💬](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/.E2.9C.94.20dbg_trace.20should.20use.20.60Repr.60.20instance/near/495082575)

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2025-09-10 13:22:17 +00:00
Sebastian Ullrich
0a6bd5c0c6 chore: make Environment.evalConst [noinline] 2025-09-10 12:56:42 +02:00
Sebastian Ullrich
de2e935f30 fix: run @[init] declarations in declaration order (#10217)
This PR ensures `@[init]` declarations such as from `initialize` are run
in the order they were declared on import.

Fixes #10175
2025-09-10 09:52:10 +00:00
Sebastian Ullrich
57bce526f9 fix: further exporting control (#10261)
More proof generation nested in general metaprograms, uncovered by Shake
2025-09-10 09:14:11 +00:00
Sebastian Ullrich
b136906939 perf: do not publicly export docstrings (#10305)
This PR ensures changes to docstrings do not trigger downstream rebuilds
under the module system.
2025-09-10 09:10:04 +00:00
Lean stage0 autoupdater
f4c7a0d25c chore: update stage0 2025-09-10 07:49:18 +00:00
David Thrane Christiansen
3e2124bb48 feat: docstrings with Verso syntax (#10307)
This PR upstreams the Verso parser and adds preliminary support for
Verso in docstrings. This will allow the compiler to check examples and
cross-references in documentation.

After a `stage0` update, a follow-up PR will add the appropriate
attributes that allow the feature to be used. The parser tests from
Verso also remain to be upstreamed, and user-facing documentation will
be added once the feature has been used on more internals.
2025-09-10 07:03:57 +00:00
Leonardo de Moura
fc6a6cc4e2 fix: unnecessary NatModules in grind linarith (#10326)
This PR fixes a performance issue in `grind linarith`. It was creating
unnecessary `NatModule`/`IntModule` structures for commutative rings
without an order. This kind of type should be handled by `grind ring`
only.
2025-09-10 03:51:51 +00:00
Kim Morrison
bb61a2d481 chore: add grind test for numeral normalization (#10292) 2025-09-10 03:19:49 +00:00
Leonardo de Moura
2d8de4235d feat: model-based theory combination for ToInt types (#10325)
This PR implements model-based theory combination for types `A` which
implement the `ToInt` interface. Examples:
```lean
example {C : Type} (h : Fin 4 → C) (x : Fin 4)
    : 3 ≤ x → x ≤ 3 → h x = h (-1) := by
  grind

example {C : Type} (h : UInt8 → C) (x y z w : UInt8)
    : y + 1 + w ≤ x + w → x + w ≤ z → z ≤ y + w + 1 → h (x + w) = h (y + w + 1) := by
  grind

example {C : Type} (h : Fin 8 → C) (x y w r : Fin 8)
    : y + 1 + w ≤ r → r ≤ y + w + x → x = 1 → h r = h (y + w + 1) := by
  grind
```
2025-09-10 03:12:11 +00:00
Kim Morrison
a0ecff4610 chore: remove over-eager grind lemma eq_empty_of_append_eq_empty (#10162)
This PR removes `grind →` annotations that fire too often, unhelpfully.
It would be nice for `grind` to instantiate these lemmas, but only if
they already see `xs ++ ys` and `#[]` in the same equivalence class, not
just as soon as it sees `xs ++ ys`.

In the meantime, let's see what is using these.
2025-09-10 02:35:54 +00:00
Kim Morrison
923c3d10a2 feat: cutsat and grobner frontends for grind (#10322)
This PR introduces limited functionality frontends `cutsat` and
`grobner` for `grind`. We disable theorem instantiation (and case
splitting for `grobner`), and turn off all other solvers. Both still
allow `grind` configuration options, so for example one can use `cutsat
+ring` (or `grobner +cutsat`) to solve problems that require both.

For `cutsat`, it is helpful to instantiate a limited set of theorems
(e.g. `Nat.max_def`). Currently this isn't supported, but we intend to
add this later.
2025-09-10 02:26:52 +00:00
Leonardo de Moura
ac4c752608 fix: OfNat.ofNat grind canonicalizer (#10323)
This PR fixes the `grind` canonicalizer for `OfNat.ofNat` applications.
Example:
```lean
example {C : Type} (h : Fin 2 → C) :
    -- `0` in the first `OfNat.ofNat` is not a raw literal
    h (@OfNat.ofNat (Fin (1 + 1)) 0 Fin.instOfNat) = h 0 := by
  grind
```
2025-09-10 00:21:04 +00:00
Leonardo de Moura
4d2576362b fix: use local metavar ids in grind (#10321)
This PR ensures that the auxiliary temporary metavariable IDs created by
the E-matching module used in `grind` are not affected by what has been
executed before invoking `grind`. The goal is to increase `grind`’s
robustness.

For example, in the E-matching module we use `Expr.quickLt` to sort
candidates. `Expr.quickLt` depends on the `Expr` hash code, which in
turn depends on metavariable IDs. Thus, before this change, the initial
next metavariable ID at the time of `grind` invocation could affect the
order in which instances were generated, and consequently the `grind`
search.
2025-09-09 22:22:52 +00:00
Leonardo de Moura
f6a2c6d07c fix: bug at assignUnassignedLevelMVars in grind (#10320) 2025-09-09 21:45:06 +00:00
Kyle Miller
1a203c7fe5 feat: intermediate tactic info on simpa (#10309)
This PR modifies the `simpa` tactic so that in `simpa ... using e` there
is tactic info on the range `simpa ... using` that shows the simplified
goal.
2025-09-09 20:24:27 +00:00
Rob23oba
e75e6fbe9e chore: don't include redundant empty strings in string interpolation (#10269)
This PR changes the string interpolation procedure to omit redundant
empty parts. For example `s!"{1}{2}"` previously elaborated to `toString
"" ++ toString 1 ++ toString "" ++ toString 2 ++ toString ""` and now
elaborates to `toString 1 ++ toString 2`.
2025-09-09 14:27:26 +00:00
Copilot
d98b626633 doc: improve docstrings for simp!, simp_all!, dsimp! and autoUnfold (#9991)
- [x] Updated docstrings for `simp!`, `simp_all!`, `dsimp!` to use
user-friendly language
- [x] Updated docstrings for `autoUnfold` fields to use user-friendly
language
- [x] Fixed broken test by updating expected output for simp! hover
documentation
- [x] Replaced technical terms with clear language: "will unfold
applications of functions defined by pattern matching, when one of the
patterns applies"

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nomeata <148037+nomeata@users.noreply.github.com>
2025-09-09 13:34:16 +00:00
Paul Reichert
fd0177afe3 feat: add missing lemmas about insertMany and get? for container types (#10247)
This PR adds missing the lemmas `ofList_eq_insertMany_empty`,
`get?_eq_some_iff`, `getElem?_eq_some_iff` and `getKey?_eq_some_iff` to
all container types.
2025-09-09 13:27:43 +00:00
dependabot[bot]
757426b099 chore: CI: bump actions/checkout from 4 to 5 (#10219)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to
5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2238">actions/checkout#2238</a></li>
</ul>
<h2>⚠️ Minimum Compatible Runner Version</h2>
<p><strong>v2.327.1</strong><br />
<a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<p>Make sure your runner is updated to this version or newer to use this
release.</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v5.0.0">https://github.com/actions/checkout/compare/v4...v5.0.0</a></p>
<h2>v4.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
<li>Prepare release v4.3.0 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2237">actions/checkout#2237</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/motss"><code>@​motss</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li><a href="https://github.com/mouismail"><code>@​mouismail</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li><a href="https://github.com/benwells"><code>@​benwells</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li><a href="https://github.com/nebuk89"><code>@​nebuk89</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v4.3.0">https://github.com/actions/checkout/compare/v4...v4.3.0</a></p>
<h2>v4.2.2</h2>
<h2>What's Changed</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4.2.1...v4.2.2">https://github.com/actions/checkout/compare/v4.2.1...v4.2.2</a></p>
<h2>v4.2.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Jcambass"><code>@​Jcambass</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1919">actions/checkout#1919</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4.2.0...v4.2.1">https://github.com/actions/checkout/compare/v4.2.0...v4.2.1</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
<li>README: Suggest <code>user.email</code> to be
<code>41898282+github-actions[bot]@users.noreply.github.com</code> by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1707">actions/checkout#1707</a></li>
</ul>
<h2>v4.1.4</h2>
<ul>
<li>Disable <code>extensions.worktreeConfig</code> when disabling
<code>sparse-checkout</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1692">actions/checkout#1692</a></li>
<li>Add dependabot config by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1688">actions/checkout#1688</a></li>
<li>Bump the minor-actions-dependencies group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1693">actions/checkout#1693</a></li>
<li>Bump word-wrap from 1.2.3 to 1.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1643">actions/checkout#1643</a></li>
</ul>
<h2>v4.1.3</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="08c6903cd8"><code>08c6903</code></a>
Prepare v5.0.0 release (<a
href="https://redirect.github.com/actions/checkout/issues/2238">#2238</a>)</li>
<li><a
href="9f265659d3"><code>9f26565</code></a>
Update actions checkout to use node 24 (<a
href="https://redirect.github.com/actions/checkout/issues/2226">#2226</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 11:53:35 +00:00
dependabot[bot]
b81ea5ee9c chore: CI: bump actions/download-artifact from 4 to 5 (#10220)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 4 to 5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/407">actions/download-artifact#407</a></li>
<li>BREAKING fix: inconsistent path behavior for single artifact
downloads by ID by <a
href="https://github.com/GrantBirki"><code>@​GrantBirki</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/416">actions/download-artifact#416</a></li>
</ul>
<h2>v5.0.0</h2>
<h3>🚨 Breaking Change</h3>
<p>This release fixes an inconsistency in path behavior for single
artifact downloads by ID. <strong>If you're downloading single artifacts
by ID, the output path may change.</strong></p>
<h4>What Changed</h4>
<p>Previously, <strong>single artifact downloads</strong> behaved
differently depending on how you specified the artifact:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (direct)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/my-artifact/</code> (nested)</li>
</ul>
<p>Now both methods are consistent:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (unchanged)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/</code> (fixed - now direct)</li>
</ul>
<h4>Migration Guide</h4>
<h5> No Action Needed If:</h5>
<ul>
<li>You download artifacts by <strong>name</strong></li>
<li>You download <strong>multiple</strong> artifacts by ID</li>
<li>You already use <code>merge-multiple: true</code> as a
workaround</li>
</ul>
<h5>⚠️ Action Required If:</h5>
<p>You download <strong>single artifacts by ID</strong> and your
workflows expect the nested directory structure.</p>
<p><strong>Before v5 (nested structure):</strong></p>
<pre lang="yaml"><code>- uses: actions/download-artifact@v4
  with:
    artifact-ids: 12345
    path: dist
# Files were in: dist/my-artifact/
</code></pre>
<blockquote>
<p>Where <code>my-artifact</code> is the name of the artifact you
previously uploaded</p>
</blockquote>
<p><strong>To maintain old behavior (if needed):</strong></p>
<pre lang="yaml"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="634f93cb29"><code>634f93c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/416">#416</a>
from actions/single-artifact-id-download-path</li>
<li><a
href="b19ff43027"><code>b19ff43</code></a>
refactor: resolve download path correctly in artifact download tests
(mainly ...</li>
<li><a
href="e262cbee4a"><code>e262cbe</code></a>
bundle dist</li>
<li><a
href="bff23f9308"><code>bff23f9</code></a>
update docs</li>
<li><a
href="fff8c148a8"><code>fff8c14</code></a>
fix download path logic when downloading a single artifact by id</li>
<li><a
href="448e3f862a"><code>448e3f8</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/407">#407</a>
from actions/nebuk89-patch-1</li>
<li><a
href="47225c44b3"><code>47225c4</code></a>
Update README.md</li>
<li>See full diff in <a
href="https://github.com/actions/download-artifact/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 11:53:09 +00:00
Leonardo de Moura
c75d37f76b fix: no model-based theory combination on instances (#10314)
This PR skips model based theory combination on instances.
2025-09-09 03:30:29 +00:00
Leonardo de Moura
dd87739fc2 feat: grind normalizers for natCast and intCast (#10313)
This PR adds missing `grind` normalization rules for `natCast` and
`intCast` Examples:
```
open Lean.Grind
variable (R : Type) (a b : R)

section CommSemiring
variable [CommSemiring R]

example (m n : Nat) : (m + n) • a = m • a + n • a := by grind
example (m n : Nat) : (m * n) • a = m • (n • a) := by grind

end CommSemiring

section CommRing
variable [CommRing R]

example (m n : Nat) : (m + n) • a = m • a + n • a := by grind
example (m n : Nat) : (m * n) • a = m • (n • a) := by grind
example (m n : Int) : (m * n) • (a * b) = (m • a) * (n • b) := by grind

end CommRing
```
2025-09-09 01:32:09 +00:00
Lean stage0 autoupdater
01e6928da0 chore: update stage0 2025-09-09 01:05:26 +00:00
Leonardo de Moura
e36d1925f1 refactor: grind cutsat as solver extension (#10312)
This PR uses the new solver extension framework to implement `grind
cutsat`. All satellite solvers have been migrated to the new framework.
2025-09-09 00:23:12 +00:00
Kim Morrison
f9b2e550bb feat: grind annotations for basic monad transformers (#10227)
This PR adds `@[grind]` annotations (nearly all `@[grind =]` annotations
parallel to existing `@[simp]`s) for `ReaderT`, `StateT`, `ExceptT`.
2025-09-08 23:51:55 +00:00
Leonardo de Moura
ed99ad63f3 refactor: grind offset as solver extension (#10311)
This PR uses the new solver extension framework to implement `grind
offset`.
2025-09-08 19:53:54 +00:00
Leonardo de Moura
eb337b820f refactor: grind linarith as solver extension (#10310)
This PR uses the new solver extension framework to implement `grind
linarith`.
2025-09-08 18:34:25 +00:00
Lean stage0 autoupdater
1dc72b1880 chore: update stage0 2025-09-08 19:04:07 +00:00
Cameron Zwarich
e86ab1b1db fix: make IO.RealWorld opaque (#9631)
This PR makes `IO.RealWorld` opaque. It also adds a new compiler -only
`lcRealWorld` constant to represent this type within the compiler. By
default, an opaque type definition is treated like `lcAny`, whereas we
want a more efficient representation. At the moment, this isn't a big
difference, but in the future we would like to completely erase
`IO.RealWorld` at runtime.
2025-09-08 18:12:19 +00:00
Leonardo de Moura
c34ea82bc2 refactor: grind ring as solver extension (#10308)
This PR uses the new solver extension framework to implement `grind
ring`.
2025-09-08 15:40:55 +00:00
Joachim Breitner
79051fb5c0 feat: simpler off-diagonal noConfusion construction using ctorIdx (#10300)
This PR offers an alternative `noConfusion` construction for the
off-diagonal use (i.e. for different constructors), based on comparing
the `.ctorIdx`. This should lead to faster type checking, as the kernel
only has to reduce `.ctorIdx` twice, instead of the complicate
`noConfusionType` construction.
2025-09-08 14:34:26 +00:00
Kyle Miller
81fe3b6d05 feat: pretty print sorry in "declaration uses 'sorry'" (#10034)
This PR changes the "declaration uses 'sorry'" error to pretty print an
actual `sorry` expression in the message. The effect is that the `sorry`
is hoverable and, if it's labeled, you can "go to definition" to see
where it came from.

The implementation prefers reporting synthetic sorries. These can appear
even if there are no error messages if a declaration refers to a
declaration that has elaboration errors. Users should focus on
elaboration errors before worrying about user-written `sorry`s.

In the future we could have some more precise logic for sorry reporting.
All the sorries in a declaration should be considered to be reported,
and we should not re-report sorries in later declarations. Some
elaborators use `warn.sorry` to avoid re-reporting sorries in auxiliary
declarations.
2025-09-08 12:14:42 +00:00
Lean stage0 autoupdater
05d6b8648c chore: update stage0 2025-09-08 10:52:50 +00:00
Wojciech Różowski
5c03ab9630 fix: unfolding order on predicates (#10245)
This PR changes the implementation of a function `unfoldPredRel` used in
(co)inductive predicate machinery, that unfolds pointwise order on
predicates to quantifications and implications. Previous implementation
relied on `withDeclsDND` that could not deal with types which depend on
each other. This caused the following example to fail:

```lean4
inductive infSeq_functor1.{u} {α : Type u} (r : α → α → Prop) (call : {α : Type u} → (r : α → α → Prop) → α → Prop) : α → Prop where
  | step : r a b → infSeq_functor1 r call b → infSeq_functor1 r call a

def infSeq1 (r : α → α → Prop) : α → Prop := infSeq_functor1 r (infSeq1)
  coinductive_fixpoint monotonicity by sorry

#check infSeq1.coinduct
```
Closes #10234.
2025-09-08 10:07:15 +00:00
Joachim Breitner
3e24d5dee8 fix: expose ctorIdx and per-constructor elims (#10301)
This PR exposes ctorIdx and per-constructor eliminators. Fixes #10299.
2025-09-08 10:04:19 +00:00
Cameron Zwarich
4a73532fbe chore: remove unnecessary parens (#10298) 2025-09-08 05:52:45 +00:00
Cameron Zwarich
f6cf54fb2f chore: remove lean/run/lcnf1.lean test (#10297)
This test involves re-running the compiler on decls that have already
been compiled, which can cause all sorts of issues. I just hit these
issues on a PR, so it's time to retire this test like others that hit
the same issues.
2025-09-08 05:51:40 +00:00
Leonardo de Moura
058f6008c0 fix: bug at Poly.combine_mul_k (#10296)
This PR fixes a bug in an auxiliary function used to construct proof
terms in `grind cutsat`.
2025-09-08 02:17:11 +00:00
Lean stage0 autoupdater
ab30577acb chore: update stage0 2025-09-08 01:54:53 +00:00
Leonardo de Moura
be1e090833 feat: grind solver extensions (part 2) (#10294)
This PR completes the `grind` solver extension design and ports the
`grind ac` solver to the new framework. Future PRs will document the API
and port the remaining solvers. An additional benefit of the new design
is faster build times.
2025-09-08 01:11:05 +00:00
Cameron Zwarich
6a8d7cc17c chore: remove instWPMonad instance and test that relies upon it (#10293)
The proof of the instWPMonad instance relies on the equality of any two
terms of type `IO.RealWorld`, which is only a side effect of the current
transparent definition. Ignoring the questions around the utility of
proving things about programs in `IO`, the semantic validity of this
instance in the intended model of the IO monad is also unclear.

I tried a few things to axiomatize this instance so it could be put into
the test file to preserve the one test section that relies on it, but I
was unsuccessful; everything I attempted caused errors.
2025-09-07 23:42:52 +00:00
Lean stage0 autoupdater
13795fb3ad chore: update stage0 2025-09-07 18:40:52 +00:00
Leonardo de Moura
612c7588d0 feat: grind solver extensions (#10290)
This PR adds infrastructure for registering new `grind` solvers. `grind`
already includes many solvers, and this PR is the first step toward
modularizing the design and supporting user-defined solvers.
2025-09-07 17:45:50 +00:00
Lean stage0 autoupdater
d70b619500 chore: update stage0 2025-09-07 17:55:11 +00:00
Markus Himmel
9402c307fe chore: reorganize Init imports around strings (#10289)
This PR reorganizes the import hierarchy so that
`Init.Data.String.Basic` can import `Init.Data.UInt.Bitwise` and
`Init.Data.Array.Lemmas`.
2025-09-07 17:09:14 +00:00
Lean stage0 autoupdater
1ab115648d chore: update stage0 2025-09-07 13:40:08 +00:00
Markus Himmel
aa0a31ae7d chore: prepare for untangling strings (#10288)
This PR prepares for a future reorganization of the import hierarchy so
that `Init.Data.String.Basic` can import `Init.Data.UInt.Bitwise` and
`Init.Data.Array.Lemmas`.
2025-09-07 12:58:23 +00:00
Markus Himmel
19bd0254c3 chore: move String.utf8EncodeChar to the prelude (#10264)
This PR moves `String.utf8EncodeChar` to the prelude to prepare for the
imminent redefinition of `String`.

The definition in the prelude uses modulo and division operations on
natural numbers. In `String.Extra`, a `csimp` lemma is provided, showing
that the new definition is equal to the previous one (which is now
called `utf8EncodeCharFast`) which uses bitwise operations on `UInt8`.
2025-09-07 12:42:53 +00:00
Marc Huisinga
0b3550f284 fix: textedit completions (#10286)
This PR fixes `textEdit`-based completions after they were accidentally
broken by the new serialization procedure in #10249.
2025-09-07 09:44:16 +00:00
Leonardo de Moura
5463e10ce4 test: grind ac diagnostics (#10284) 2025-09-07 02:15:56 +00:00
Leonardo de Moura
8fd8821b61 feat: grind ac module diagnostics (#10283)
This PR implements diagnostic information for the `grind ac` module. It
now displays the basis, normalized disequalities, and additional
properties detected for each associative operator.
2025-09-07 01:43:38 +00:00
Leonardo de Moura
975b6e758f feat: improve grind linarith counterexamples for NatModule (#10282)
This PR improves the counterexamples produced by `grind linarith` for
`NatModule`s. `grind` now hides occurrences of the auxiliary function
`Grind.IntModule.OfNatModule.toQ`.
2025-09-07 01:04:01 +00:00
Leonardo de Moura
a31eb94e5a feat: normalize NatModule equations (#10281)
This PR implements `NatModule` normalization when the `AddRightCancel`
instance is not available. Note that in this case, the embedding into
`IntModule` is not injective. Therefore, we use a custom normalizer,
similar to the `CommSemiring` normalizer used in the `grind ring`
module. Example:

```lean
open Lean Grind
example [NatModule α] (a b c : α)
    : 2•a + 2•(b + 2•c) + 3•a = 4•a + c + 2•b + 3•c + a := by
  grind
```
2025-09-07 00:20:10 +00:00
Leonardo de Moura
652868c308 feat: NatModule equation normalization theorem (#10280)
This PR adds the auxiliary theorem `Lean.Grind.Linarith.eq_normN` for
normalizing `NatModule` equations when the instance `AddRightCancel` is
not available.
2025-09-06 23:32:26 +00:00
Mac Malone
0d28e450c2 refactor: lake: mv verLit into the DSL namespace (#10276)
This PR moves the `verLit` syntax into the `Lake.DSL` namespace to be
consistent with other code found in `Lake.DSL`.
2025-09-06 21:14:15 +00:00
Joachim Breitner
a872cec0a7 refactor: use match decEq, not if h : in deriving DecidableEq (#10274)
This PR changes the implementation of the linear `DecidableEq`
implementation to use `match decEq` rather than `if h : ` to compare the
constructor tags. Otherwise, the “smart unfolding” machinery will not
let `rfl` decide that different constructors are different.
2025-09-06 21:00:34 +00:00
Leonardo de Moura
2ff41f43be feat: NatModule inequalities and equalities in grind linarith (#10278)
This PR adds support for `NatModule` equalities and inequalities in
`grind linarith`. Examples:
```lean
open Lean Grind Std

example [NatModule α] [LE α] [LT α] 
  [LawfulOrderLT α] [IsLinearOrder α] [OrderedAdd α] 
  (x y : α) : x ≤ y → 2 • x + y ≤ 3 • y := by
  grind

example [NatModule α] [AddRightCancel α] [LE α] [LT α] 
    [LawfulOrderLT α] [IsLinearOrder α] [OrderedAdd α] 
    (a b c d : α) : a ≤ b → a ≥ c + d → d ≤ 0 → d ≥ 0 → b = c → a = b := by
  grind
```
2025-09-06 20:52:09 +00:00
Leonardo de Moura
52a9fe3b67 feat: missing NatModule instances (#10277)
This PR adds the missing instances `IsPartialOrder`, `IsLinearPreorder`
and `IsLinearOrder` for `OfNatModule.Q α`.
2025-09-06 18:58:02 +00:00
Joachim Breitner
316ff35afd feat: deriving instances: use accessible names (#10271)
This PR changes the naming of the internal functions in deriving
instances like BEq to use accessible names. This is necessary to
reasonably easily prove things about these functions. For example after
`deriving BEq` for a type `T`, the implementation of `instBEqT` is in
`instBEqT.beq`.
2025-09-06 18:12:20 +00:00
Mac Malone
aaa0cf3cf6 refactor: lake: rm public syntax workarounds (#10275) 2025-09-06 17:33:36 +00:00
Joachim Breitner
8b09366c78 fix: casesOnSameCtor: export if not private (#10273)
This PR tries to do the right thing about the visibility of the
same-ctor-match-construct.
2025-09-06 16:32:10 +00:00
Sebastian Ullrich
5f75c55191 fix: do not apply private instances in public scope (#10260) 2025-09-06 15:34:12 +00:00
Sebastian Ullrich
752b53e936 feat: maxErrors option (#10262)
This PR adds a new option `maxErrors` that limits the number of errors
printed from a single `lean` run, defaulting to 100. Processing is
aborted when the limit is reached, but this is tracked only on a
per-command level.

Smaller values can be useful when making changes that break a lot of
files and would otherwise scroll the actual root failures out of the
terminal view.
2025-09-06 14:52:49 +00:00
Eric Wieser
3f671cca92 doc: add docstrings for tracing functions (#10169) 2025-09-06 09:29:24 +00:00
Leonardo de Moura
8735447d44 feat: infrastructure for NatModule in grind linarith (#10267)
This PR implements the infrastructure for supporting `NatModule` in
`grind linarith` and uses it to handle disequalities. Another PR will
add support for equalities and inequalities. Example:
```lean
open Lean Grind
variable (M : Type) [NatModule M] [AddRightCancel M]

example (x y : M) : 2 • x + 3 • y + x = 3 • (x + y) := by
  grind
```
2025-09-06 01:16:03 +00:00
Leonardo de Moura
1861cc6bbc fix: panic in grind ring (#10265)
This PR fixes a panic in `grind ring` exposed by #10242. `grind ring`
should not assume that all normalizations have been applied, because
some subterms cannot be rewritten by `simp` due to typing constraints.
Moreover, `grind` uses `preprocessLight` in a few places, and it skips
the simplifier/normalizer.

Closes #10242
2025-09-05 16:16:25 +00:00
Sebastian Ullrich
974c649e2e fix: meta structure/inductive should create meta ctor (#10263) 2025-09-05 14:00:55 +00:00
Paul Reichert
184f716da1 refactor: improve names in the range API (#10059)
This PR improves the names of definitions and lemmas in the polymorphic
range API. It also introduces a recommended spelling. For example, a
left-closed, right-open range is spelled `Rco` in analogy with Mathlib's
`Ico` intervals.
2025-09-05 13:10:05 +00:00
Lean stage0 autoupdater
3f7f1c87f6 chore: update stage0 2025-09-05 11:21:02 +00:00
Marc Huisinga
7ba0ae1f72 feat: improve auto-completion performance (#10249)
This PR speeds up auto-completion by a factor of ~3.5x through various
performance improvements in the language server. On one machine, with
`import Mathlib`, completing `i` used to take 3200ms and now instead
yields a result in 920ms.

Specifically, the following improvements are made:
- The watchdog process no longer de-serializes and re-serializes most
messages from the file worker before passing them on to the user - a
fast partial de-serialization procedure is now used to determine whether
the message needs to be de-serialized in full or not.
- `escapePart` is optimized to perform better on ASCII strings that do
not need escaping.
- `Json.compress` is optimized to allocate fewer objects.
- A faster JSON compression specifically for completion responses is
implemented that skips allocating `Json` altogether.
- The JSON compression has been moved to the task where we convert a
request response to `Json` so that converting to a string won't block
the output task of the FileWorker and so the `Json` value is not marked
as multi-threaded when we compress is, which drastically increases the
cost of reference-counting.
- The JSON representation of the `data?` field of each completion item
is optimized.
- Both the completion kind and the set of completion tags for each
imported completion item is now cached.
- The filtering of duplicate completion items is optimized.

Other adjustments:
- `LT UInt8` and `LE UInt8` are moved to Prelude so that they can be
used in `Init.Meta` for the name part escaping fast path.
- `Array.usize` is exposed since it was marked as `@[simp]`.
2025-09-05 08:55:49 +00:00
Cameron Zwarich
9923a8d9f8 chore: remove special case for extern constructors (#10257)
This is subsumed by the fix in #10256.
2025-09-05 06:08:45 +00:00
Cameron Zwarich
de38a16fa9 fix: use IR decls in toIR for applications without mono decls (#10256)
This PR corrects a mistake in `toIR` where it could over-apply a
function that has an IR decl but no mono decl.

Fixes #10181.
2025-09-05 05:32:19 +00:00
Cameron Zwarich
c0238e396c refactor: inline tryIrDecl? into its only caller (#10255)
This helper function was actually incorrectly named anyways.
2025-09-05 04:41:34 +00:00
Cameron Zwarich
c7cc398935 refactor: create a mkApplication helper for toIR (#10254) 2025-09-05 01:42:36 +00:00
Mac Malone
849bb770fd refactor: lake: split PackageConfig from Config.Package (#10253)
This PR moves the `PackageConfig` definition from `Lake.Config.Package`
into its own module. This enables a significant reduction in the `meta
import` tree of the `Lake.CLI.Translate` modules.
2025-09-04 23:15:37 +00:00
Leonardo de Moura
6cefbc4bb0 chore: fix typo (#10251) 2025-09-04 16:05:00 +00:00
Paul Reichert
9b6a4a7588 fix: solve two problems with LinearOrderPackage factories (#10250)
This PR fixes a bug in the `LinearOrderPackage.ofOrd` factory. If there
is a `LawfulEqOrd` instance available, it should automatically use it
instead of requiring the user to provide the `eq_of_compare` argument to
the factory. The PR also solves a hygiene-related problem making the
factories fail when `Std` is not open.
2025-09-04 15:27:09 +00:00
Sebastian Ullrich
47787dc1cb perf: rebuild leak on private match (#10246)
This PR prevents downstream rebuilds on changes to private `match`es
under the module system
2025-09-04 12:51:42 +00:00
Lean stage0 autoupdater
25ab3dd93d chore: update stage0 2025-09-04 08:22:20 +00:00
Kim Morrison
bbd45b13f4 chore: move omega internals to a namespace (#10243)
This PR moves some internal implementation details of `omega` out of the
`List` namespace. See [#mathlib4 > Naming: ne_zero vs nonzero @
💬](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Naming.3A.20ne_zero.20vs.20nonzero/near/537424328).
2025-09-04 06:32:02 +00:00
Kim Morrison
85f168bbd0 chore: add test cases for grind on Fin lemmas (#10241)
This PR adds some test cases for `grind` working with `Fin`. There are
many still failing tests in `tests/lean/grind/grind_fin.lean` which I'm
intending to triage and work on.
2025-09-04 04:28:29 +00:00
Marcus Rossel
89aed0931e feat: improve error message when passing local hypotheses to grind (#8891)
This PR improves the error message produced when passing (automatically
redundant) local hypotheses to `grind`.
2025-09-04 03:00:21 +00:00
Sebastian Ullrich
92d24e1c40 fix: Environment.realizeConst to replay realization map (#10238)
This PR fixes an issue with retrieving realized declarations after use
of Aesop uncovered by #10229
2025-09-03 22:16:40 +00:00
Leonardo de Moura
c15ee8a9f0 fix: universe polymorphic E-matching (#10239)
This PR fixes the E-matching procedure for theorems that contain
universe parameters not referenced by any regular parameter. This kind
of theorem seldom happens in practice, but we do have instances in the
standard library. Example:
```
@[simp, grind =] theorem Std.Do.SPred.down_pure {φ : Prop} : (⌜φ⌝ : SPred []).down = φ := rfl
```

closes #10233
2025-09-03 22:14:58 +00:00
Leonardo de Moura
320b02108b fix: grind canonicalizer (#10237)
This PR fixes a missing case in the `grind` canonicalizer. Some types
may include terms or propositions that are internalized later in the
`grind` state.

closes #10232
2025-09-03 18:08:48 +00:00
Rob23oba
80df86dfdd feat: add more MonoBind instances for monad transformers (#10230)
This PR adds `MonoBind` for more monad transformers. This allows using
`partial_fixpoint` for more complicated monads based on `Option` and
`EIO`. Example:
```lean-4
abbrev M := ReaderT String (StateT String.Pos Option)

def parseAll (x : M α) : M (List α) := do
  if (← read).atEnd (← get) then
    return []
  let val ← x
  let list ← parseAll x
  return val :: list
partial_fixpoint
```
2025-09-03 17:15:41 +00:00
Paul Reichert
fef390df08 perf: improve iterator/range benchmarks, use shortcut instances for Int ranges (#10197)
This PR is the result of analyzing the elaborator performance regression
introduced by #10005. It makes the `workspaceSymboldNewRanges` and
`iterators` benchmarks less noisy. It also replaces some range-related
instances for `Nat` with shortcuts to the general-purpose instances.
This is a trade-off between the ergonomics and the synthesis cost of
having general-purpose instances.
2025-09-03 15:47:52 +00:00
Sebastian Ullrich
37be918c50 perf: do not export EqnInfo for non-exposed defs (#10229) 2025-09-03 10:03:52 +00:00
Sebastian Ullrich
2efbe4ac36 feat: support visibility modifiers on syntax abbrevs (#10228)
Closes #10068
2025-09-03 07:53:29 +00:00
Eric Wieser
6d68aab56a feat: generalize universes in monadic operators for collections (#10224)
This PR generalizes the monadic operations for `HashMap`, `TreeMap`, and
`HashSet` to work for `m : Type u → Type v`.

This upstreams [a workaround from
Aesop](66a992130e/Aesop/Util/Basic.lean (L57-L66)),
and seems to continue a pattern already established in other files, such
as:
```lean
Array.forM.{u, v, w} {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Array α) (start : Nat := 0)
  (stop : Nat := as.size) : m PUnit
```
2025-09-03 07:24:14 +00:00
Joachim Breitner
ccb8568756 feat: linear-size DecidableEq instance (#10152)
This PR introduces an alternative construction for `DecidableEq`
instances that avoids the quadratic overhead of the default
construction.

The usual construction uses a `match` statement that looks at each pair
of constructors, and thus is necessarily quadratic in size. For
inductive data type with dozens of constructors or more, this quickly
becomes slow to process.

The new construction first compares the constructor tags (using the
`.ctorIdx` introduced in #9951), and handles the case of a differing
constructor tag quickly. If the constructor tags match, it uses the
per-constructor-eliminators (#9952) to create a linear-size instance. It
does so by creating a custom “matcher” for a parallel match on the data
types and the `h : x1.ctorIdx = x2.ctorIdx` assumption; this behaves
(and delaborates) like a normal `match` statement, but is implemented in
a bespoke way. This same-constructor-matcher will be useful for
implementing other instances as well.

The new construction produces less efficient code at the moment, so we
use it only for inductive types with 10 or more constructors by default.
The option `deriving.decEq.linear_construction_threshold` can be used to
adjust the threshold; set it to 0 to always use the new construction.
2025-09-03 06:31:49 +00:00
Leonardo de Moura
a4f6f391fe feat: equality propagation from AC module to grind core (#10223)
This PR implements equality propagation from the new AC module into the
`grind` core. Examples:

```lean
example {α β : Sort u} (f : α → β) (op : α → α → α) [Std.Associative op] [Std.Commutative op] 
    (a b c d : α) : op a (op b b) = op d c → f (op (op b a) (op b c)) = f (op c (op d c)) := by
  grind only

example (a b c : Nat) : min a (max b (max c 0)) = min (max c b) a := by
  grind -cutsat only

example {α β : Sort u} (bar : α → β) (op : α → α → α) [Std.Associative op] [Std.IdempotentOp op]
    (a b c d e f x y w : α) :
    op d (op x c) = op a b →
    op e (op f (op y w)) = op (op d a) (op b c) →
    bar (op d (op x c)) = bar (op e (op f (op y w))) := by
  grind only
```
2025-09-02 23:02:25 +00:00
Leonardo de Moura
dac61c406f feat: extra critical pairs for associative + idempotent operators in grind ac (#10221)
This PR adds the extra critical pairs to ensure the `grind ac` procedure
is complete when the operator is associative and idempotent, but not
commutative. Example:
```lean
example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.IdempotentOp op] (a b c d e f x y w : α)
    : op d (op x c) = op a b →
      op e (op f (op y w)) = op a (op b c) →
      op d (op x c) = op e (op f (op y w)) := by
  grind only

example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.IdempotentOp op] (a b c d e f x y w : α)
    : op a (op d x) = op b c →
      op e (op f (op y w)) = op a (op b c) →
      op a (op d x) = op e (op f (op y w)) := by
  grind only
```
2025-09-02 15:52:56 +00:00
Henrik Böving
db35f98b26 fix: make csimp equivalence criteria more strict (#10214)
This PR fixes #10213.
2025-09-02 14:36:08 +00:00
Leonardo de Moura
e6f50b0181 perf: EqCnstr.superposeWith (#10218)
This PR adds a small optimization for `EqCnstr.superposeWith`
It also adds a new test unrelated to the optimization.
2025-09-02 13:50:47 +00:00
Dax Fohl
2877196656 doc: fix broken "quickstart" and "supported editors" link (#8785)
The "supported editors" link in
https://github.com/leanprover/lean4/blob/master/doc/dev/index.md is
broken, as `setup.md` no longer exists in the repo. This PR changes the
link to point to the live Lean docs setup page at
https://docs.lean-lang.org/lean4/doc/setup.html#editing.

A similar fix for quickstart is included.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2025-09-02 12:45:04 +00:00
Aaron Liu
f748d1c4ef doc: fix typo in docstring for fieldIdxKind (#8814)
This PR fixes a typo in the docstring for `Lean.fieldIdxKind`, which was
missing a backtick.
2025-09-02 12:30:07 +00:00
Eric Wieser
848832dd61 chore: demote a panic to an exception in saveModuleData (#9127)
This PR makes `saveModuleData` throw an IO.Error instead of panicking,
if given something that cannot be serialized. This doesn't really matter
for saving modules, but is handy when writing tools to save auxiliary
date in olean files via Batteries' `pickle`.

The caller of this C++ function already is guarded in a `try`/`catch`
that promotes from a `lean::exception` to an `IO.userError`.

A simple test of this in the web editor is
```
import Batteries

#eval pickle "/tmp/foo.txt" fun x : Nat => x
```
which crashes before this change.

---------

Co-authored-by: Laurent Sartran <lsartran@google.com>
2025-09-02 12:25:45 +00:00
Henrik Böving
c5f2c192d6 fix: Selectable.one does not panic on empty array (#10216)
This PR fixes #10193.
2025-09-02 11:55:36 +00:00
1845 changed files with 23056 additions and 9952 deletions

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: actionlint
uses: raven-actions/actionlint@v2
with:

View File

@@ -70,7 +70,7 @@ jobs:
if: runner.os == 'macOS'
- name: Checkout
if: (!endsWith(matrix.os, '-with-cache'))
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -8,7 +8,7 @@ jobs:
check-stage0-on-queue:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
filter: blob:none

View File

@@ -54,7 +54,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
# don't schedule nightlies on forks
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
- name: Set Nightly
@@ -363,7 +363,7 @@ jobs:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
path: artifacts
- name: Release
@@ -388,12 +388,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
# needed for tagging
fetch-depth: 0
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
path: artifacts
- name: Prepare Nightly Release

View File

@@ -6,7 +6,7 @@ jobs:
check-lean-files:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Verify .lean files start with a copyright header.
run: |

View File

@@ -395,7 +395,7 @@ jobs:
# Checkout the Batteries repository with all branches
- name: Checkout Batteries repository
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
repository: leanprover-community/batteries
token: ${{ secrets.MATHLIB4_BOT }}
@@ -454,7 +454,7 @@ jobs:
# Checkout the mathlib4 repository with all branches
- name: Checkout mathlib4 repository
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
repository: leanprover-community/mathlib4-nightly-testing
token: ${{ secrets.MATHLIB4_BOT }}
@@ -524,7 +524,7 @@ jobs:
# Checkout the reference manual repository with all branches
- name: Checkout mathlib4 repository
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
repository: leanprover/reference-manual
token: ${{ secrets.MANUAL_PR_BOT }}

View File

@@ -25,7 +25,7 @@ jobs:
# This action should push to an otherwise protected branch, so it
# uses a deploy key with write permissions, as suggested at
# https://stackoverflow.com/a/76135647/946226
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"

View File

@@ -8,7 +8,7 @@ You should not edit the `stage0` directory except using the commands described i
## Development Setup
You can use any of the [supported editors](../setup.md) for editing the Lean source code.
You can use any of the [supported editors](https://lean-lang.org/install/manual/) for editing the Lean source code.
Please see below for specific instructions for VS Code.
### Dev setup using elan
@@ -99,3 +99,19 @@ on to `nightly-with-manual` branch. (It is fine to force push after rebasing.)
CI will generate a branch of the reference manual called `lean-pr-testing-NNNN`
in `leanprover/reference-manual`. This branch uses the toolchain for your PR,
and will report back to the Lean PR with results from Mathlib CI.
### Avoiding rebuilds for downstream projects
If you want to test changes to Lean on downstream projects and would like to avoid rebuilding modules you have already built/fetched using the project's configured Lean toolchain, you can often do so as long as your build of Lean is close enough to that Lean toolchain (compatible .olean format including structure of all relevant environment extensions).
To override the toolchain without rebuilding for a single command, for example `lake build` or `lake lean`, you can use the prefix
```
LEAN_GITHASH=$(lean --githash) lake +lean4 ...
```
Alternatively, use
```
export LEAN_GITHASH=$(lean --githash)
export ELAN_TOOLCHAIN=lean4
```
to persist these changes for the lifetime of the current shell, which will affect any processes spawned from it such as VS Code started via `code .`.
If you use a setup where you cannot directly start your editor from the command line, such as VS Code Remote, you might want to consider using [direnv](https://direnv.net/) together with an editor extension for it instead so that you can put the lines above into `.envrc`.

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](../dev/index.md).
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.
We strongly suggest that new users instead follow the [Installation Instructions](https://lean-lang.org/install/) 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

@@ -19,8 +19,8 @@ variable {ε σ α : Type u}
instance [ToString ε] [ToString α] : ToString (Result ε σ α) where
toString
| Result.ok a _ => "ok: " ++ toString a
| Result.error e _ => "error: " ++ toString e
| Result.ok a _ => String.Internal.append "ok: " (toString a)
| Result.error e _ => String.Internal.append "error: " (toString e)
instance [Repr ε] [Repr α] : Repr (Result ε σ α) where
reprPrec

View File

@@ -22,23 +22,24 @@ open Function
namespace ExceptT
@[ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
@[ext, grind ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
simp [run] at h
assumption
@[simp] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
@[simp, grind =] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
@[simp] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
@[simp, grind =] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
@[simp] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
@[simp, grind =] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
@[simp] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
@[simp, grind =] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
simp [ExceptT.run, ExceptT.lift, bind, ExceptT.bind, ExceptT.mk, ExceptT.bindCont]
@[simp] theorem bind_throw [Monad m] [LawfulMonad m] (f : α ExceptT ε m β) : (throw e >>= f) = throw e := by
@[simp, grind =] theorem bind_throw [Monad m] [LawfulMonad m] (f : α ExceptT ε m β) : (throw e >>= f) = throw e := by
simp [throw, throwThe, MonadExceptOf.throw, bind, ExceptT.bind, ExceptT.bindCont, ExceptT.mk]
theorem run_bind [Monad m] (x : ExceptT ε m α)
@[grind =]
theorem run_bind [Monad m] (x : ExceptT ε m α) (f : α ExceptT ε m β)
: run (x >>= f : ExceptT ε m β)
=
run x >>= fun
@@ -46,10 +47,10 @@ theorem run_bind [Monad m] (x : ExceptT ε m α)
| Except.error e => pure (Except.error e) :=
rfl
@[simp] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
@[simp, grind =] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
simp [ExceptT.lift, pure, ExceptT.pure]
@[simp] theorem run_map [Monad m] [LawfulMonad m] (f : α β) (x : ExceptT ε m α)
@[simp, grind =] theorem run_map [Monad m] [LawfulMonad m] (f : α β) (x : ExceptT ε m α)
: (f <$> x).run = Except.map f <$> x.run := by
simp [Functor.map, ExceptT.map, bind_pure_comp]
apply bind_congr
@@ -113,28 +114,28 @@ instance : LawfulFunctor (Except ε) := inferInstance
namespace ReaderT
@[ext] theorem ext {x y : ReaderT ρ m α} (h : ctx, x.run ctx = y.run ctx) : x = y := by
@[ext, grind 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
@[simp] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
@[simp, grind =] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
@[simp] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α ReaderT ρ m β) (ctx : ρ)
@[simp, grind =] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α ReaderT ρ m β) (ctx : ρ)
: (x >>= f).run ctx = x.run ctx >>= λ a => (f a).run ctx := rfl
@[simp] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
@[simp, grind =] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
: (Functor.mapConst a x).run ctx = Functor.mapConst a (x.run ctx) := rfl
@[simp] theorem run_map [Monad m] (f : α β) (x : ReaderT ρ m α) (ctx : ρ)
@[simp, grind =] theorem run_map [Monad m] (f : α β) (x : ReaderT ρ m α) (ctx : ρ)
: (f <$> x).run ctx = f <$> x.run ctx := rfl
@[simp] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
@[simp, grind =] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
: (monadLift x : ReaderT ρ m α).run ctx = (monadLift x : m α) := rfl
@[simp] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} n β n β) (x : ReaderT ρ m α) (ctx : ρ)
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} n β n β) (x : ReaderT ρ m α) (ctx : ρ)
: (monadMap @f x : ReaderT ρ m α).run ctx = monadMap @f (x.run ctx) := rfl
@[simp] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
@[simp, grind =] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
@[simp] theorem run_seq {α β : Type u} [Monad m] (f : ReaderT ρ m (α β)) (x : ReaderT ρ m α) (ctx : ρ)
: (f <*> x).run ctx = (f.run ctx <*> x.run ctx) := rfl
@@ -175,38 +176,39 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
namespace StateT
@[ext] theorem ext {x y : StateT σ m α} (h : s, x.run s = y.run s) : x = y :=
@[ext, grind 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 :=
@[simp, grind =] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
rfl
@[simp] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
@[simp, grind =] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
@[simp] theorem run_bind [Monad m] (x : StateT σ m α) (f : α StateT σ m β) (s : σ)
@[simp, grind =] theorem run_bind [Monad m] (x : StateT σ m α) (f : α StateT σ m β) (s : σ)
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := by
simp [bind, StateT.bind, run]
@[simp] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
@[simp, grind =] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
simp [Functor.map, StateT.map, run, bind_pure_comp]
@[simp] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
@[simp, grind =] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
@[simp] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (, s') := rfl
@[simp, grind =] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (, s') := rfl
@[simp] theorem run_modify [Monad m] (f : σ σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (, f s) := rfl
@[simp, grind =] theorem run_modify [Monad m] (f : σ σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (, f s) := rfl
@[simp] theorem run_modifyGet [Monad m] (f : σ α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
@[simp, grind =] theorem run_modifyGet [Monad m] (f : σ α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
simp [modifyGet, MonadStateOf.modifyGet, StateT.modifyGet, run]
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
@[simp, grind =] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
@[grind =]
theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
simp [StateT.lift, StateT.run, bind, StateT.bind]
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
@[simp, grind =] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
@[simp] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} n β n β) (x : StateT σ m α) (s : σ) :
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} n β n β) (x : StateT σ m α) (s : σ) :
(monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by

View File

@@ -201,7 +201,7 @@ theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
rcases this with _, _, m, rfl
exact m
@[simp, grind]
@[simp, grind =]
theorem mem_attachWith {xs : Array α} {q : α Prop} (H) (x : {x // q x}) :
x xs.attachWith q H x.1 xs := by
cases xs
@@ -212,12 +212,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
b pmap f xs H (a : _) (h : a xs), f a (H a h) = b := by
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
@[grind]
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {xs H} {a} (h : a xs) :
f a (H a h) pmap f xs H := by
rw [mem_pmap]
exact a, h, rfl
grind_pattern mem_pmap_of_mem => _ pmap f xs H, a xs
@[simp, grind =]
theorem size_pmap {p : α Prop} {f : a, p a β} {xs H} : (pmap f xs H).size = xs.size := by
cases xs; simp
@@ -706,7 +707,7 @@ and simplifies these to the function directly taking the value.
{f : { x // p x } Array β} {g : α Array β} (hf : x h, f x, h = g x) :
(xs.flatMap f) = xs.unattach.flatMap g := by
cases xs
simp only [List.flatMap_toArray, List.unattach_toArray,
simp only [List.flatMap_toArray, List.unattach_toArray,
mk.injEq]
rw [List.flatMap_subtype]
simp [hf]

View File

@@ -10,8 +10,6 @@ public import Init.WFTactics
public import Init.Data.Nat.Basic
public import Init.Data.Fin.Basic
public import Init.Data.UInt.BasicAux
public import Init.Data.Repr
public import Init.Data.ToString.Basic
public import Init.GetElem
public import Init.Data.List.ToArrayImpl
import all Init.Data.List.ToArrayImpl
@@ -42,11 +40,11 @@ namespace Array
/-! ### Preliminary theorems -/
@[simp, grind] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
@[simp, grind =] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
(set xs i v h).size = xs.size :=
List.length_set ..
@[simp, grind] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
@[simp, grind =] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
List.length_concat ..
theorem ext {xs ys : Array α}
@@ -113,10 +111,12 @@ theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
simp [mem_def]
@[simp, grind] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] xs := by
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] xs := by
rw [Array.mem_def, getElem_toList]
apply List.getElem_mem
grind_pattern getElem_mem => xs[i] xs
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
@@ -134,7 +134,7 @@ theorem toList_toArray {as : List α} : as.toArray.toList = as := rfl
@[deprecated toList_toArray (since := "2025-02-17")]
abbrev _root_.Array.toList_toArray := @List.toList_toArray
@[simp, grind] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
@[simp, grind =] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
@[deprecated size_toArray (since := "2025-02-17")]
abbrev _root_.Array.size_toArray := @List.size_toArray
@@ -164,7 +164,7 @@ This is a low-level version of `Array.size` that directly queries the runtime sy
representation of arrays. While this is not provable, `Array.usize` always returns the exact size of
the array since the implementation only supports arrays of size less than `USize.size`.
-/
@[extern "lean_array_size", simp]
@[extern "lean_array_size", simp, expose]
def usize (xs : @& Array α) : USize := xs.size.toUSize
/--
@@ -199,7 +199,7 @@ Examples:
def pop (xs : Array α) : Array α where
toList := xs.toList.dropLast
@[simp, grind] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
@[simp, grind =] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
match xs with
| [] => rfl
| a::as => simp [pop, Nat.succ_sub_succ_eq_sub, size]
@@ -443,7 +443,7 @@ def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
swapAt xs i v
else
have : Inhabited (α × Array α) := (v, xs)
panic! ("index " ++ toString i ++ " out of bounds")
panic! String.Internal.append (String.Internal.append "index " (toString i)) " out of bounds"
/--
Returns the first `n` elements of an array. The resulting array is produced by repeatedly calling
@@ -2169,7 +2169,7 @@ instance {α : Type u} [Repr α] : Repr (Array α) where
reprPrec xs _ := Array.repr xs
instance [ToString α] : ToString (Array α) where
toString xs := "#" ++ toString xs.toList
toString xs := String.Internal.append "#" (toString xs.toList)
end Array

View File

@@ -91,7 +91,7 @@ theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
rcases xs with xs
simpa using List.mem_of_mem_eraseP
@[simp, grind] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a xs.eraseP p a xs := by
@[simp, grind =] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a xs.eraseP p a xs := by
rcases xs with xs
simpa using List.mem_eraseP_of_neg pa
@@ -240,7 +240,7 @@ theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a
rcases xs with xs
simpa using List.mem_of_mem_erase (by simpa using h)
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a b) :
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a b) :
a xs.erase b a xs :=
erase_eq_eraseP b xs mem_eraseP_of_neg (mt eq_of_beq ab.symm)

View File

@@ -27,11 +27,11 @@ open Nat
/-! ### findSome? -/
@[simp, grind] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
@[simp, grind] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
@[simp, grind =] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
@[simp, grind =] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
cases xs; simp [List.findSome?_append]
@[grind]
@[grind =]
theorem findSome?_singleton {a : α} {f : α Option β} : #[a].findSome? f = f a := by
simp
@@ -228,11 +228,12 @@ theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ x
simp at h
simpa using List.mem_of_find?_eq_some h
@[grind]
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h xs := by
cases xs
simp [List.get_find?_mem]
grind_pattern get_find?_mem => (xs.find? p).get h
@[simp, grind =] 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
@@ -395,7 +396,6 @@ theorem findIdx_singleton {a : α} {p : α → Bool} :
#[a].findIdx p = if p a then 0 else 1 := by
simp
@[grind ]
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
rcases xs with xs
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
@@ -728,7 +728,7 @@ theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
cases xs
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
rw [findFinIdx?_congr List.unattach_toArray]
simp only [Option.map_map, Function.comp_def, Fin.cast_trans]
simp only [Option.map_map, Function.comp_def, Fin.cast_cast]
simp [Array.size]
/-! ### idxOf

View File

@@ -15,7 +15,6 @@ public import Init.Data.List.Monadic
public import Init.Data.List.OfFn
public import Init.Data.Array.Mem
public import Init.Data.Array.DecidableEq
public import Init.Data.Array.Lex.Basic
public import Init.Data.Range.Lemmas
public import Init.TacticsExtra
public import Init.Data.List.ToArray
@@ -62,7 +61,7 @@ theorem toArray_eq : List.toArray as = xs ↔ as = xs.toList := by
@[simp] theorem empty_eq {xs : Array α} : #[] = xs xs = #[] := by
cases xs <;> simp
@[grind] theorem size_empty : (#[] : Array α).size = 0 := rfl
@[grind =] theorem size_empty : (#[] : Array α).size = 0 := rfl
/-! ### size -/
@@ -197,7 +196,7 @@ theorem getElem?_push_size {xs : Array α} {x} : (xs.push x)[xs.size]? = some x
theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : #[a][i] = a := by
simp
@[grind]
@[grind =]
theorem getElem?_singleton {a : α} {i : Nat} : #[a][i]? = if i = 0 then some a else none := by
simp [List.getElem?_singleton]
@@ -212,12 +211,12 @@ theorem ext_getElem? {xs ys : Array α} (h : ∀ i : Nat, xs[i]? = ys[i]?) : xs
@[simp] theorem pop_push {xs : Array α} {x : α} : (xs.push x).pop = xs := by simp [pop]
@[simp, grind] theorem getElem_pop {xs : Array α} {i : Nat} (h : i < xs.pop.size) :
@[simp, grind =] theorem getElem_pop {xs : Array α} {i : Nat} (h : i < xs.pop.size) :
xs.pop[i] = xs[i]'(by simp at h; omega) := by
rcases xs with xs
simp [List.getElem_dropLast]
@[grind] theorem getElem?_pop {xs : Array α} {i : Nat} :
@[grind =] theorem getElem?_pop {xs : Array α} {i : Nat} :
xs.pop[i]? = if i < xs.size - 1 then xs[i]? else none := by
rcases xs with xs
simp [List.getElem?_dropLast]
@@ -332,7 +331,7 @@ theorem singleton_inj : #[a] = #[b] ↔ a = b := by
/-! ### replicate -/
@[simp, grind] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
@[simp, grind =] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
List.length_replicate ..
@[deprecated size_replicate (since := "2025-03-18")]
@@ -344,12 +343,12 @@ abbrev size_mkArray := @size_replicate
@[deprecated toList_replicate (since := "2025-03-18")]
abbrev toList_mkArray := @toList_replicate
@[simp, grind] theorem replicate_zero : replicate 0 a = #[] := rfl
@[simp, grind =] theorem replicate_zero : replicate 0 a = #[] := rfl
@[deprecated replicate_zero (since := "2025-03-18")]
abbrev mkArray_zero := @replicate_zero
@[grind]
@[grind =]
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
apply toList_inj.1
simp [List.replicate_succ']
@@ -357,13 +356,13 @@ theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
@[deprecated replicate_succ (since := "2025-03-18")]
abbrev mkArray_succ := @replicate_succ
@[simp, grind] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
@[simp, grind =] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
(replicate n v)[i] = v := by simp [ getElem_toList]
@[deprecated getElem_replicate (since := "2025-03-18")]
abbrev getElem_mkArray := @getElem_replicate
@[grind] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
@[grind =] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
(replicate n v)[i]? = if i < n then some v else none := by
simp [getElem?_def]
@@ -374,14 +373,20 @@ abbrev getElem?_mkArray := @getElem?_replicate
theorem not_mem_empty (a : α) : ¬ a #[] := by simp
@[simp] theorem mem_push {xs : Array α} {x y : α} : x xs.push y x xs x = y := by
@[simp, grind =] theorem mem_push {xs : Array α} {x y : α} : x xs.push y x xs x = y := by
simp only [mem_def]
simp
@[grind] theorem mem_or_eq_of_mem_push {a b : α} {xs : Array α} :
theorem mem_or_eq_of_mem_push {a b : α} {xs : Array α} :
a xs.push b a xs a = b := Array.mem_push.mp
@[grind] theorem mem_push_self {xs : Array α} {x : α} : x xs.push x :=
-- This pattern may be excessively general:
-- it fires anytime we ae thinking about membership of arrays,
-- and constructing a list via `push`, even if the elements are unrelated.
-- Nevertheless in practice it is quite helpful!
grind_pattern mem_or_eq_of_mem_push => xs.push b, a xs
theorem mem_push_self {xs : Array α} {x : α} : x xs.push x :=
mem_push.2 (Or.inr rfl)
theorem eq_push_append_of_mem {xs : Array α} {x : α} (h : x xs) :
@@ -392,7 +397,7 @@ theorem eq_push_append_of_mem {xs : Array α} {x : α} (h : x ∈ xs) :
obtain rfl := h
exact as.toArray, bs.toArray, by simp, by simpa using w
@[grind] theorem mem_push_of_mem {xs : Array α} {x : α} (y : α) (h : x xs) : x xs.push y :=
theorem mem_push_of_mem {xs : Array α} {x : α} (y : α) (h : x xs) : x xs.push y :=
mem_push.2 (Or.inl h)
-- The argument `xs : Array α` is intentionally explicit,
@@ -521,8 +526,8 @@ theorem forall_getElem {xs : Array α} {p : α → Prop} :
/-! ### isEmpty -/
@[grind] theorem isEmpty_empty : (#[] : Array α).isEmpty = true := rfl
@[simp, grind] theorem isEmpty_push {xs : Array α} : (xs.push x).isEmpty = false := by
@[grind =] theorem isEmpty_empty : (#[] : Array α).isEmpty = true := rfl
@[simp, grind =] theorem isEmpty_push {xs : Array α} : (xs.push x).isEmpty = false := by
rcases xs with xs
simp
@@ -729,18 +734,18 @@ theorem all_eq_true_iff_forall_mem {xs : Array α} : xs.all p ↔ ∀ x, x ∈ x
subst h
rw [all_toList]
@[grind] theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
@[grind =] theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
l.toArray.anyM p = l.anyM p := by
rw [ anyM_toList]
@[grind] theorem _root_.List.any_toArray {p : α Bool} {l : List α} : l.toArray.any p = l.any p := by
@[grind =] theorem _root_.List.any_toArray {p : α Bool} {l : List α} : l.toArray.any p = l.any p := by
rw [any_toList]
@[grind] theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
@[grind =] theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α m Bool} {l : List α} :
l.toArray.allM p = l.allM p := by
rw [ allM_toList]
@[grind] theorem _root_.List.all_toArray {p : α Bool} {l : List α} : l.toArray.all p = l.all p := by
@[grind =] theorem _root_.List.all_toArray {p : α Bool} {l : List α} : l.toArray.all p = l.all p := by
rw [all_toList]
/-- Variant of `any_eq_true` in terms of membership rather than an array index. -/
@@ -847,7 +852,7 @@ theorem contains_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : Array α} (
elem a xs = xs.contains a := by
simp [elem]
@[grind] theorem contains_empty [BEq α] : (#[] : Array α).contains a = false := by simp
@[grind =] theorem contains_empty [BEq α] : (#[] : Array α).contains a = false := by simp
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
elem a xs = true a xs := mem_of_contains_eq_true, contains_eq_true_of_mem
@@ -861,14 +866,14 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a ∈ as)
theorem elem_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
elem a xs = decide (a xs) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
xs.contains a = decide (a xs) := by rw [ elem_eq_contains, elem_eq_mem]
@[grind] theorem any_empty [BEq α] {p : α Bool} : (#[] : Array α).any p = false := by simp
@[grind] theorem all_empty [BEq α] {p : α Bool} : (#[] : Array α).all p = true := by simp
@[grind =] theorem any_empty [BEq α] {p : α Bool} : (#[] : Array α).any p = false := by simp
@[grind =] theorem all_empty [BEq α] {p : α Bool} : (#[] : Array α).all p = true := by simp
/-- Variant of `any_push` with a side condition on `stop`. -/
@[simp, grind] theorem any_push' {xs : Array α} {a : α} {p : α Bool} (h : stop = xs.size + 1) :
@[simp, grind =] theorem any_push' {xs : Array α} {a : α} {p : α Bool} (h : stop = xs.size + 1) :
(xs.push a).any p 0 stop = (xs.any p || p a) := by
cases xs
rw [List.push_toArray]
@@ -879,7 +884,7 @@ theorem any_push {xs : Array α} {a : α} {p : α → Bool} :
any_push' (by simp)
/-- Variant of `all_push` with a side condition on `stop`. -/
@[simp, grind] theorem all_push' {xs : Array α} {a : α} {p : α Bool} (h : stop = xs.size + 1) :
@[simp, grind =] theorem all_push' {xs : Array α} {a : α} {p : α Bool} (h : stop = xs.size + 1) :
(xs.push a).all p 0 stop = (xs.all p && p a) := by
cases xs
rw [List.push_toArray]
@@ -912,13 +917,13 @@ theorem all_push {xs : Array α} {a : α} {p : α → Bool} :
(ne : i j) : (xs.set i v)[j]? = xs[j]? := by
by_cases h : j < xs.size <;> simp [ne, h]
@[grind] theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
@[grind =] theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
(h : j < (xs.set i v).size) :
(xs.set i v)[j] = if i = j then v else xs[j]'(by simpa using h) := by
simp at h
by_cases p : i = j <;> simp [p, h]
@[grind] theorem getElem?_set {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} :
@[grind =] theorem getElem?_set {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} :
(xs.set i v)[j]? = if i = j then some v else xs[j]? := by
split <;> simp_all
@@ -984,23 +989,23 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
/-! ### setIfInBounds -/
@[simp, grind] theorem setIfInBounds_empty {i : Nat} {a : α} :
@[simp, grind =] theorem setIfInBounds_empty {i : Nat} {a : α} :
#[].setIfInBounds i a = #[] := rfl
@[simp, grind =] theorem set!_eq_setIfInBounds : set! xs i v = setIfInBounds xs i v := rfl
@[grind]
@[grind =]
theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
xs.setIfInBounds i a = if h : i < xs.size then xs.set i a else xs := rfl
@[simp, grind] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
@[simp, grind =] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
(xs.setIfInBounds i a).size = xs.size := by
if h : i < xs.size then
simp [setIfInBounds, h]
else
simp [setIfInBounds, h]
@[grind] theorem getElem_setIfInBounds {xs : Array α} {i : Nat} {a : α} {j : Nat}
@[grind =] theorem getElem_setIfInBounds {xs : Array α} {i : Nat} {a : α} {j : Nat}
(hj : j < xs.size) :
(xs.setIfInBounds i a)[j]'(by simp [hj]) = if i = j then a else xs[j] := by
simp only [setIfInBounds]
@@ -1019,7 +1024,7 @@ theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
(xs.setIfInBounds i a)[j]'(by simpa using hj) = xs[j] := by
simp [getElem_setIfInBounds, hj, h]
@[grind] theorem getElem?_setIfInBounds {xs : Array α} {i j : Nat} {a : α} :
@[grind =] theorem getElem?_setIfInBounds {xs : Array α} {i j : Nat} {a : α} :
(xs.setIfInBounds i a)[j]? = if i = j then if i < xs.size then some a else none else xs[j]? := by
cases xs
simp [List.getElem?_set]
@@ -1083,11 +1088,11 @@ theorem mem_or_eq_of_mem_setIfInBounds
/-! ### BEq -/
@[simp, grind] theorem beq_empty_eq [BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty := by
@[simp, grind =] theorem beq_empty_eq [BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty := by
cases xs
simp
@[simp, grind] theorem empty_beq_eq [BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty := by
@[simp, grind =] theorem empty_beq_eq [BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty := by
cases xs
simp
@@ -1097,7 +1102,7 @@ abbrev beq_empty_iff := @beq_empty_eq
@[deprecated empty_beq_eq (since := "2025-04-04")]
abbrev empty_beq_iff := @empty_beq_eq
@[simp, grind] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
(xs.push a == ys.push b) = (xs == ys && a == b) := by
cases xs
cases ys
@@ -1157,16 +1162,16 @@ private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] → a ==
/-! ### back -/
@[grind] theorem back_singleton {a : α} : #[a].back = a := by simp
@[grind =] theorem back_singleton {a : α} : #[a].back = a := by simp
@[grind]
@[grind =]
theorem back_eq_getElem {xs : Array α} (h : 0 < xs.size) : xs.back = xs[xs.size - 1] := by
cases xs
simp [List.getLast_eq_getElem]
@[grind] theorem back?_empty : (#[] : Array α).back? = none := by simp
@[grind =] theorem back?_empty : (#[] : Array α).back? = none := by simp
@[grind] theorem back?_eq_getElem? {xs : Array α} : xs.back? = xs[xs.size - 1]? := by
@[grind =] theorem back?_eq_getElem? {xs : Array α} : xs.back? = xs[xs.size - 1]? := by
cases xs
simp [List.getLast?_eq_getElem?]
@@ -1203,17 +1208,17 @@ where
apply ext'
simp
@[simp, grind] theorem size_map {f : α β} {xs : Array α} : (xs.map f).size = xs.size := by
@[simp, grind =] theorem size_map {f : α β} {xs : Array α} : (xs.map f).size = xs.size := by
simp only [ length_toList]
simp
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
@[simp, grind] theorem getElem_map (f : α β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) :
@[simp, grind =] theorem getElem_map (f : α β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) :
(xs.map f)[i] = f (xs[i]'(by simpa using hi)) := by
cases xs
simp
@[simp, grind] theorem getElem?_map {f : α β} {xs : Array α} {i : Nat} :
@[simp, grind =] theorem getElem?_map {f : α β} {xs : Array α} {i : Nat} :
(xs.map f)[i]? = xs[i]?.map f := by
simp [getElem?_def]
@@ -1221,9 +1226,9 @@ where
@[simp] theorem mapM_empty [Monad m] (f : α m β) : mapM f #[] = pure #[] := by
rw [mapM, mapM.map]; rfl
@[grind] theorem map_empty {f : α β} : map f #[] = #[] := by simp
@[grind =] theorem map_empty {f : α β} : map f #[] = #[] := by simp
@[simp, grind] theorem map_push {f : α β} {as : Array α} {x : α} :
@[simp, grind =] theorem map_push {f : α β} {as : Array α} {x : α} :
(as.push x).map f = (as.map f).push (f x) := by
ext
· simp
@@ -1384,7 +1389,7 @@ theorem array₃_induction (P : Array (Array (Array α)) → Prop)
/-! ### filter -/
@[grind] theorem filter_empty {p : α Bool} : #[].filter p = #[] := rfl
@[grind =] theorem filter_empty {p : α Bool} : #[].filter p = #[] := rfl
@[congr]
theorem filter_congr {xs ys : Array α} (h : xs = ys)
@@ -1405,7 +1410,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
induction xs with simp
| cons => split <;> simp [*]
@[grind] theorem toList_filter {p : α Bool} {xs : Array α} :
@[grind =] theorem toList_filter {p : α Bool} {xs : Array α} :
(xs.filter p).toList = xs.toList.filter p := by
simp
@@ -1414,7 +1419,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
apply ext'
simp [h]
@[grind] theorem _root_.List.filter_toArray {p : α Bool} {l : List α} :
@[grind =] theorem _root_.List.filter_toArray {p : α Bool} {l : List α} :
l.toArray.filter p = (l.filter p).toArray := by
simp
@@ -1432,7 +1437,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
rcases xs with xs
simp [h]
@[grind] theorem filter_push {p : α Bool} {a : α} {xs : Array α} :
@[grind =] theorem filter_push {p : α Bool} {a : α} {xs : Array α} :
(xs.push a).filter p = if p a then (xs.filter p).push a else xs.filter p := by
split <;> simp [*]
@@ -1453,7 +1458,7 @@ grind_pattern Array.size_filter_le => (xs.filter p).size
rcases xs with xs
simp
@[simp, grind] theorem mem_filter {p : α Bool} {xs : Array α} {a : α} :
@[simp, grind =] theorem mem_filter {p : α Bool} {xs : Array α} {a : α} :
a xs.filter p a xs p a := by
rcases xs with xs
simp
@@ -1515,7 +1520,7 @@ theorem map_filter_eq_foldl {f : α → β} {p : α → Bool} {xs : Array α} :
simp only [List.filter_cons, List.foldr_cons]
split <;> simp_all
@[simp, grind] theorem filter_append {p : α Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) :
@[simp, grind =] theorem filter_append {p : α Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) :
filter p (xs ++ ys) 0 stop = filter p xs ++ filter p ys := by
subst w
rcases xs with xs
@@ -1569,7 +1574,7 @@ theorem size_filter_lt_size_iff_exists {xs : Array α} {p : α → Bool} :
/-! ### filterMap -/
@[simp, grind] theorem filterMap_empty {f : α Option β} : filterMap f #[] = #[] := rfl
@[simp, grind =] theorem filterMap_empty {f : α Option β} : filterMap f #[] = #[] := rfl
@[congr]
theorem filterMap_congr {as bs : Array α} (h : as = bs)
@@ -1592,7 +1597,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
· simp_all [List.filterMap_cons]
split <;> simp_all
@[grind] theorem toList_filterMap {f : α Option β} {xs : Array α} :
@[grind =] theorem toList_filterMap {f : α Option β} {xs : Array α} :
(xs.filterMap f).toList = xs.toList.filterMap f := by
simp [toList_filterMap']
@@ -1602,7 +1607,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
apply ext'
simp [h]
@[grind] theorem _root_.List.filterMap_toArray {f : α Option β} {l : List α} :
@[grind =] theorem _root_.List.filterMap_toArray {f : α Option β} {l : List α} :
l.toArray.filterMap f = (l.filterMap f).toArray := by
simp
@@ -1620,7 +1625,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
rcases xs with xs
simp [h]
@[grind] theorem filterMap_push {f : α Option β} {a : α} {xs : Array α}
@[grind =] theorem filterMap_push {f : α Option β} {a : α} {xs : Array α}
(w : stop = xs.size + 1) :
filterMap f (xs.push a) 0 stop =
match f a with
@@ -1645,7 +1650,7 @@ theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
cases xs
simp
@[simp, grind] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
@[simp, grind =] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
cases xs
simp
@@ -1673,19 +1678,19 @@ theorem filterMap_eq_filter {p : α → Bool} (w : stop = as.size) :
cases as
simp
@[grind]
@[grind =]
theorem filterMap_filterMap {f : α Option β} {g : β Option γ} {xs : Array α} :
filterMap g (filterMap f xs) = filterMap (fun x => (f x).bind g) xs := by
cases xs
simp [List.filterMap_filterMap]
@[grind]
@[grind =]
theorem map_filterMap {f : α Option β} {g : β γ} {xs : Array α} :
map g (filterMap f xs) = filterMap (fun x => (f x).map g) xs := by
cases xs
simp [List.map_filterMap]
@[simp, grind] theorem filterMap_map {f : α β} {g : β Option γ} {xs : Array α} :
@[simp, grind =] theorem filterMap_map {f : α β} {g : β Option γ} {xs : Array α} :
filterMap g (map f xs) = filterMap (g f) xs := by
cases xs
simp [List.filterMap_map]
@@ -1700,7 +1705,7 @@ theorem filterMap_filter {p : α → Bool} {f : α → Option β} {xs : Array α
cases xs
simp [List.filterMap_filter]
@[simp, grind] theorem mem_filterMap {f : α Option β} {xs : Array α} {b : β} :
@[simp, grind =] theorem mem_filterMap {f : α Option β} {xs : Array α} {b : β} :
b filterMap f xs a, a xs f a = some b := by
simp only [mem_def, toList_filterMap, List.mem_filterMap]
@@ -1712,7 +1717,7 @@ theorem forall_mem_filterMap {f : α → Option β} {xs : Array α} {P : β →
intro a
rw [forall_comm]
@[simp, grind] theorem filterMap_append {α β : Type _} {xs ys : Array α} {f : α Option β}
@[simp, grind =] theorem filterMap_append {α β : Type _} {xs ys : Array α} {f : α Option β}
{stop : Nat} (w : stop = xs.size + ys.size) :
filterMap f (xs ++ ys) 0 stop = filterMap f xs ++ filterMap f ys := by
subst w
@@ -1771,7 +1776,7 @@ theorem size_filterMap_lt_size_iff_exists {xs : Array α} {f : α → Option β}
/-! ### append -/
@[simp, grind] theorem size_append {xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size := by
@[simp, grind =] theorem size_append {xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size := by
simp only [size, toList_append, List.length_append]
@[simp, grind _=_] theorem push_append {a : α} {xs ys : Array α} : (xs ++ ys).push a = xs ++ ys.push a := by
@@ -1808,7 +1813,7 @@ theorem empty_append_fun : ((#[] : Array α) ++ ·) = id := by
funext l
simp
@[simp, grind] theorem mem_append {a : α} {xs ys : Array α} : a xs ++ ys a xs a ys := by
@[simp, grind =] theorem mem_append {a : α} {xs ys : Array α} : a xs ++ ys a xs a ys := by
simp only [mem_def, toList_append, List.mem_append]
theorem mem_append_left {a : α} {xs : Array α} (ys : Array α) (h : a xs) : a xs ++ ys :=
@@ -1836,7 +1841,7 @@ theorem forall_mem_append {p : α → Prop} {xs ys : Array α} :
( (x) (_ : x xs ++ ys), p x) ( (x) (_ : x xs), p x) ( (x) (_ : x ys), p x) := by
simp only [mem_append, or_imp, forall_and]
@[grind] theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
@[grind =] theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
(xs ++ ys)[i] = if h' : i < xs.size then xs[i] else ys[i - xs.size]'(by simp at h; omega) := by
cases xs; cases ys
simp [List.getElem_append]
@@ -1870,7 +1875,7 @@ theorem getElem?_append_right {xs ys : Array α} {i : Nat} (h : xs.size ≤ i) :
simp at h
simp [List.getElem?_append_right, h]
@[grind] theorem getElem?_append {xs ys : Array α} {i : Nat} :
@[grind =] theorem getElem?_append {xs ys : Array α} {i : Nat} :
(xs ++ ys)[i]? = if i < xs.size then xs[i]? else ys[i - xs.size]? := by
split <;> rename_i h
· exact getElem?_append_left h
@@ -1951,7 +1956,6 @@ theorem append_left_inj {xs₁ xs₂ : Array α} (ys) : xs₁ ++ ys = xs₂ ++ y
@[simp] theorem append_eq_empty_iff {xs ys : Array α} : xs ++ ys = #[] xs = #[] ys = #[] := by
cases xs <;> simp
@[grind ]
theorem eq_empty_of_append_eq_empty {xs ys : Array α} (h : xs ++ ys = #[]) : xs = #[] ys = #[] :=
append_eq_empty_iff.mp h
@@ -2013,7 +2017,7 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
· left; exact as.toList, by simp
· right; exact cs.toList, by simp
@[grind] theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
@[grind =] theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
(xs ++ ys).set i x =
if h' : i < xs.size then
xs.set i x ++ ys
@@ -2033,7 +2037,7 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
(xs ++ ys).set i x = xs ++ ys.set (i - xs.size) x (by simp at h'; omega) := by
rw [set_append, dif_neg (by omega)]
@[grind] theorem setIfInBounds_append {xs ys : Array α} {i : Nat} {x : α} :
@[grind =] theorem setIfInBounds_append {xs ys : Array α} {i : Nat} {x : α} :
(xs ++ ys).setIfInBounds i x =
if i < xs.size then
xs.setIfInBounds i x ++ ys
@@ -2070,7 +2074,7 @@ theorem append_eq_filterMap_iff {f : α → Option β} :
as bs, zs = as ++ bs filterMap f as = xs filterMap f bs = ys := by
rw [eq_comm, filterMap_eq_append_iff]
@[simp, grind] theorem map_append {f : α β} {xs ys : Array α} :
@[simp, grind =] theorem map_append {f : α β} {xs ys : Array α} :
map f (xs ++ ys) = map f xs ++ map f ys := by
rcases xs with xs
rcases ys with ys
@@ -2086,9 +2090,9 @@ theorem append_eq_map_iff {f : α → β} :
/-! ### flatten -/
@[simp, grind] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
@[simp, grind =] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
@[simp, grind] theorem toList_flatten {xss : Array (Array α)} :
@[simp, grind =] theorem toList_flatten {xss : Array (Array α)} :
xss.flatten.toList = (xss.toList.map toList).flatten := by
dsimp [flatten]
simp only [ foldl_toList]
@@ -2114,11 +2118,11 @@ theorem flatten_map_toArray {L : List (List α)} :
apply ext'
simp
@[simp, grind] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
@[simp, grind =] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
cases xss using array₂_induction
simp [Function.comp_def]
@[simp, grind] theorem flatten_singleton {xs : Array α} : #[xs].flatten = xs := by simp [flatten]; rfl
@[simp, grind =] theorem flatten_singleton {xs : Array α} : #[xs].flatten = xs := by simp [flatten]; rfl
theorem mem_flatten : {xss : Array (Array α)}, a xss.flatten xs, xs xss a xs := by
simp only [mem_def, toList_flatten, List.mem_flatten, List.mem_map]
@@ -2161,7 +2165,7 @@ theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap
Function.comp_def]
rw [ Function.comp_def, List.map_map, flatten_toArray_map]
@[simp, grind] theorem filterMap_flatten {f : α Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
@[simp, grind =] theorem filterMap_flatten {f : α Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
filterMap f (flatten xss) 0 stop = flatten (map (filterMap f) xss) := by
subst w
induction xss using array₂_induction
@@ -2169,7 +2173,7 @@ theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap
List.filterMap_flatten, List.map_toArray, List.map_map, Function.comp_def]
rw [ Function.comp_def, List.map_map, flatten_toArray_map]
@[simp, grind] theorem filter_flatten {p : α Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
@[simp, grind =] theorem filter_flatten {p : α Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
filter p (flatten xss) 0 stop = flatten (map (filter p) xss) := by
subst w
induction xss using array₂_induction
@@ -2193,7 +2197,7 @@ theorem flatten_filter_ne_empty [DecidablePred fun xs : Array α => xs ≠ #[]]
induction xss₂ using array₂_induction
simp [ List.map_append]
@[grind] theorem flatten_push {xss : Array (Array α)} {xs : Array α} :
@[grind =] theorem flatten_push {xss : Array (Array α)} {xs : Array α} :
flatten (xss.push xs) = flatten xss ++ xs := by
induction xss using array₂_induction
rcases xs with l
@@ -2284,7 +2288,7 @@ theorem flatMap_def {xs : Array α} {f : α → Array β} : xs.flatMap f = flatt
rcases xs with l
simp [flatten_toArray, Function.comp_def, List.flatMap_def]
@[simp, grind] theorem flatMap_empty {β} {f : α Array β} : (#[] : Array α).flatMap f = #[] := rfl
@[simp, grind =] theorem flatMap_empty {β} {f : α Array β} : (#[] : Array α).flatMap f = #[] := rfl
theorem flatMap_toList {xs : Array α} {f : α List β} :
xs.toList.flatMap f = (xs.flatMap (fun a => (f a).toArray)).toList := by
@@ -2320,7 +2324,7 @@ theorem size_flatMap {xs : Array α} {f : α → Array β} :
rcases xs with l
simp
@[simp, grind] theorem mem_flatMap {f : α Array β} {b} {xs : Array α} : b xs.flatMap f a, a xs b f a := by
@[simp, grind =] theorem mem_flatMap {f : α Array β} {b} {xs : Array α} : b xs.flatMap f a, a xs 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₂
@@ -2348,7 +2352,7 @@ theorem flatMap_singleton {f : α → Array β} {x : α} : #[x].flatMap f = f x
rcases xs with xs
simp
@[simp, grind] theorem flatMap_push {xs : Array α} {x : α} {f : α Array β} :
@[simp, grind =] theorem flatMap_push {xs : Array α} {x : α} {f : α Array β} :
(xs.push x).flatMap f = xs.flatMap f ++ f x := by
rcases xs with xs
simp
@@ -2417,7 +2421,7 @@ theorem replicate_succ' : replicate (n + 1) a = #[a] ++ replicate n a := by
@[deprecated replicate_succ' (since := "2025-03-18")]
abbrev mkArray_succ' := @replicate_succ'
@[simp, grind] theorem mem_replicate {a b : α} {n} : b replicate n a n 0 b = a := by
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b replicate n a n 0 b = a := by
unfold replicate
simp only [mem_toArray, List.mem_replicate]
@@ -2533,7 +2537,7 @@ abbrev replicate_eq_mkArray_iff := @replicate_eq_append_iff
@[deprecated map_replicate (since := "2025-03-18")]
abbrev map_mkArray := @map_replicate
@[grind] theorem filter_replicate (w : stop = n) :
@[grind =] theorem filter_replicate (w : stop = n) :
(replicate n a).filter p 0 stop = if p a then replicate n a else #[] := by
apply Array.ext'
simp only [w]
@@ -2632,14 +2636,14 @@ abbrev sum_mkArray_nat := @sum_replicate_nat
/-! ### Preliminaries about `swap` needed for `reverse`. -/
@[grind]
@[grind =]
theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
simp [swap_def, getElem?_set]
/-! ### reverse -/
@[simp, grind] theorem size_reverse {xs : Array α} : xs.reverse.size = xs.size := by
@[simp, grind =] theorem size_reverse {xs : Array α} : xs.reverse.size = xs.size := by
let rec go (as : Array α) (i j) : (reverse.loop as i j).size = as.size := by
rw [reverse.loop]
if h : i < j then
@@ -2648,7 +2652,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
termination_by j - i
simp only [reverse]; split <;> simp [go]
@[simp, grind] theorem reverse_empty : reverse (#[] : Array α) = #[] := rfl
@[simp, grind =] theorem reverse_empty : reverse (#[] : Array α) = #[] := rfl
@[simp] theorem toList_reverse {xs : Array α} : xs.reverse.toList = xs.toList.reverse := by
let rec go (as : Array α) (i j hj)
@@ -2703,7 +2707,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
cases xs
simp
@[simp, grind] theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
@[simp, grind =] theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
(xs.reverse)[i] = xs[xs.size - 1 - i]'(by simp at hi; omega) := by
cases xs
simp
@@ -2732,14 +2736,14 @@ theorem getElem?_reverse' {xs : Array α} {i j} (h : i + j + 1 = xs.size) : xs.r
simp only [List.reverse_toArray, List.getElem?_toArray]
rw [List.getElem?_reverse' h]
@[simp, grind]
@[simp, grind =]
theorem getElem?_reverse {xs : Array α} {i} (h : i < xs.size) :
xs.reverse[i]? = xs[xs.size - 1 - i]? := by
cases xs
simp_all
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
@[simp, grind] theorem reverse_reverse (xs : Array α) : xs.reverse.reverse = xs := by
@[simp, grind =] theorem reverse_reverse (xs : Array α) : xs.reverse.reverse = xs := by
cases xs
simp
@@ -2778,7 +2782,7 @@ theorem reverse_eq_iff {xs ys : Array α} : xs.reverse = ys ↔ xs = ys.reverse
cases xs
simp
@[simp, grind] theorem reverse_append {xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse := by
@[simp, grind =] theorem reverse_append {xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse := by
cases xs
cases ys
simp
@@ -2802,17 +2806,17 @@ theorem flatten_reverse {xss : Array (Array α)} :
cases xss using array₂_induction
simp [flatten_toArray, List.flatten_reverse, Function.comp_def]
@[grind] theorem reverse_flatMap {β} {xs : Array α} {f : α Array β} :
@[grind =] theorem reverse_flatMap {β} {xs : Array α} {f : α Array β} :
(xs.flatMap f).reverse = xs.reverse.flatMap (reverse f) := by
cases xs
simp [List.reverse_flatMap, Function.comp_def]
@[grind] theorem flatMap_reverse {β} {xs : Array α} {f : α Array β} :
@[grind =] theorem flatMap_reverse {β} {xs : Array α} {f : α Array β} :
(xs.reverse.flatMap f) = (xs.flatMap (reverse f)).reverse := by
cases xs
simp [List.flatMap_reverse, Function.comp_def]
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
rw [ toList_inj]
simp
@@ -2973,10 +2977,10 @@ theorem extract_empty_of_size_le_start {xs : Array α} {start stop : Nat} (h : x
simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
rw [Nat.sub_min_sub_right, Nat.sub_eq_zero_of_le h, Nat.min_zero, extract_loop_zero]
@[simp, grind] theorem extract_empty {start stop : Nat} : (#[] : Array α).extract start stop = #[] :=
@[simp, grind =] theorem extract_empty {start stop : Nat} : (#[] : Array α).extract start stop = #[] :=
extract_empty_of_size_le_start (Nat.zero_le _)
@[simp, grind] theorem extract_zero {xs : Array α} : xs.extract start 0 = #[] := by
@[simp, grind =] theorem extract_zero {xs : Array α} : xs.extract start 0 = #[] := by
ext i h₁ h₂
· simp
· simp at h₁
@@ -3170,7 +3174,7 @@ theorem foldlM_append [Monad m] [LawfulMonad m] {f : β → α → m β} {b} {xs
· rfl
· simp at h₂
@[simp, grind] theorem foldrM_empty [Monad m] {f : α β m β} {init : β} {start stop : Nat} :
@[simp, grind =] theorem foldrM_empty [Monad m] {f : α β m β} {init : β} {start stop : Nat} :
foldrM f init #[] start stop = return init := by
simp [foldrM]
@@ -3244,6 +3248,7 @@ rather than `(arr.push a).size` as the argument.
(xs.push a).foldrM f init start = f a init >>= xs.foldrM f := by
simp [ foldrM_push, h]
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem _root_.List.foldrM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α m β} {xs : Array β} :
l.foldrM (fun x xs => xs.push <$> f x) xs = do return xs ++ ( l.reverse.mapM f).toArray := by
induction l with
@@ -3256,15 +3261,16 @@ rather than `(arr.push a).size` as the argument.
funext x
simp
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem _root_.List.foldlM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α m β} {xs : Array β} :
l.foldlM (fun xs x => xs.push <$> f x) xs = do return xs ++ ( l.mapM f).toArray := by
induction l generalizing xs <;> simp [*]
/-! ### foldl / foldr -/
@[grind] theorem foldl_empty {f : β α β} {init : β} : (#[].foldl f init) = init := rfl
@[grind =] theorem foldl_empty {f : β α β} {init : β} : (#[].foldl f init) = init := rfl
@[grind] theorem foldr_empty {f : α β β} {init : β} : (#[].foldr f init) = init := rfl
@[grind =] theorem foldr_empty {f : α β β} {init : β} : (#[].foldr f init) = init := rfl
theorem foldl_induction
{as : Array α} (motive : Nat β Prop) {init : β} (h0 : motive 0 init) {f : β α β}
@@ -3312,7 +3318,7 @@ theorem foldl_push {f : β → α → β} {init : β} {xs : Array α} {a : α} :
foldlM_push ..
/-- Variant of `foldl_push` with a side condition for the `stop` argument. -/
@[simp, grind] theorem foldl_push' {f : β α β} {init : β} {xs : Array α} {a : α} {stop : Nat}
@[simp, grind =] theorem foldl_push' {f : β α β} {init : β} {xs : Array α} {a : α} {stop : Nat}
(h : stop = xs.size + 1) :
(xs.push a).foldl f init 0 stop = f (xs.foldl f init) a := by
subst h
@@ -3325,10 +3331,11 @@ theorem foldr_push {f : α → β → β} {init : β} {xs : Array α} {a : α} :
Variant of `foldr_push` with the `h : start = arr.size + 1`
rather than `(arr.push a).size` as the argument.
-/
@[simp, grind] theorem foldr_push' {f : α β β} {init : β} {xs : Array α} {a : α} {start : Nat}
@[simp, grind =] theorem foldr_push' {f : α β β} {init : β} {xs : Array α} {a : α} {start : Nat}
(h : start = xs.size + 1) : (xs.push a).foldr f init start = xs.foldr f (f a init) :=
foldrM_push' h
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem foldl_push_eq_append {as : Array α} {bs : Array β} {f : α β} (w : stop = as.size) :
as.foldl (fun acc a => acc.push (f a)) bs 0 stop = bs ++ as.map f := by
subst w
@@ -3337,12 +3344,14 @@ rather than `(arr.push a).size` as the argument.
simp only [List.foldl_toArray']
induction as generalizing bs <;> simp [*]
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem foldl_cons_eq_append {as : Array α} {bs : List β} {f : α β} (w : stop = as.size) :
as.foldl (fun acc a => (f a) :: acc) bs 0 stop = (as.map f).reverse.toList ++ bs := by
subst w
rcases as with as
simp
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem foldr_cons_eq_append {as : Array α} {bs : List β} {f : α β} (w : start = as.size) :
as.foldr (fun a acc => (f a) :: acc) bs start 0 = (as.map f).toList ++ bs := by
subst w
@@ -3350,27 +3359,29 @@ rather than `(arr.push a).size` as the argument.
simp
/-- Variant of `foldr_cons_eq_append` specialized to `f = id`. -/
@[simp, grind] theorem foldr_cons_eq_append' {as : Array α} {bs : List α} (w : start = as.size) :
@[simp, grind =] theorem foldr_cons_eq_append' {as : Array α} {bs : List α} (w : start = as.size) :
as.foldr List.cons bs start 0 = as.toList ++ bs := by
subst w
rcases as with as
simp
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem _root_.List.foldr_push_eq_append {l : List α} {f : α β} {xs : Array β} :
l.foldr (fun x xs => xs.push (f x)) xs = xs ++ (l.reverse.map f).toArray := by
induction l <;> simp [*]
/-- Variant of `List.foldr_push_eq_append` specialized to `f = id`. -/
@[simp, grind] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
@[simp, grind =] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
l.foldr (fun x xs => xs.push x) xs = xs ++ l.reverse.toArray := by
induction l <;> simp [*]
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem _root_.List.foldl_push_eq_append {l : List α} {f : α β} {xs : Array β} :
l.foldl (fun xs x => xs.push (f x)) xs = xs ++ (l.map f).toArray := by
induction l generalizing xs <;> simp [*]
/-- Variant of `List.foldl_push_eq_append` specialized to `f = id`. -/
@[simp, grind] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
@[simp, grind =] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
l.foldl (fun xs x => xs.push x) xs = xs ++ l.toArray := by
simpa using List.foldl_push_eq_append (f := id)
@@ -3382,24 +3393,28 @@ theorem _root_.List.foldl_push {l : List α} {as : Array α} : l.foldl Array.pus
theorem _root_.List.foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
rw [List.foldr_eq_foldl_reverse, List.foldl_push_eq_append']
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem foldr_append_eq_append {xs : Array α} {f : α Array β} {ys : Array β} :
xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
rcases xs with xs
rcases ys with ys
induction xs <;> simp_all [Function.comp_def, flatten_toArray]
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem foldl_append_eq_append {xs : Array α} {f : α Array β} {ys : Array β} :
xs.foldl (· ++ f ·) ys = ys ++ (xs.map f).flatten := by
rcases xs with xs
rcases ys with ys
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem foldr_flip_append_eq_append {xs : Array α} {f : α Array β} {ys : Array β} :
xs.foldr (fun x acc => acc ++ f x) ys = ys ++ (xs.map f).reverse.flatten := by
rcases xs with xs
rcases ys with ys
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
@[simp, grind] theorem foldl_flip_append_eq_append {xs : Array α} {f : α Array β} {ys : Array β} :
xs.foldl (fun acc y => f y ++ acc) ys = (xs.map f).reverse.flatten ++ ys:= by
rcases xs with l
@@ -3528,12 +3543,12 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
cases xss using array₂_induction
simp [List.foldr_flatten, List.foldr_map]
@[grind] theorem foldl_flatten {f : β α β} {b} {xss : Array (Array α)} :
@[grind =] theorem foldl_flatten {f : β α β} {b} {xss : Array (Array α)} :
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
cases xss using array₂_induction
simp [List.foldl_flatten, List.foldl_map]
@[grind] theorem foldr_flatten {f : α β β} {b} {xss : Array (Array α)} :
@[grind =] theorem foldr_flatten {f : α β β} {b} {xss : Array (Array α)} :
(flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
cases xss using array₂_induction
simp [List.foldr_flatten, List.foldr_map]
@@ -3550,11 +3565,11 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
xs.reverse.foldr f b start 0 = xs.foldl (fun x y => f y x) b :=
foldrM_reverse' w
@[grind] theorem foldl_reverse {xs : Array α} {f : β α β} {b} :
@[grind =] theorem foldl_reverse {xs : Array α} {f : β α β} {b} :
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
foldlM_reverse
@[grind] theorem foldr_reverse {xs : Array α} {f : α β β} {b} :
@[grind =] theorem foldr_reverse {xs : Array α} {f : α β β} {b} :
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
foldrM_reverse
@@ -3659,7 +3674,7 @@ theorem mem_of_back? {xs : Array α} {a : α} (h : xs.back? = some a) : a ∈ xs
simp only [List.append_toArray, List.back_toArray]
rw [List.getLast_append_of_ne_nil]
@[grind] theorem back_append {xs : Array α} (h : 0 < (xs ++ ys).size) :
@[grind =] theorem back_append {xs : Array α} (h : 0 < (xs ++ ys).size) :
(xs ++ ys).back h =
if h' : ys.isEmpty then
xs.back (by simp_all)
@@ -3690,7 +3705,7 @@ theorem back_append_left {xs ys : Array α} (w : 0 < (xs ++ ys).size) (h : ys.si
rw [List.getLast_append_left]
simpa using h
@[simp, grind] theorem back?_append {xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back? := by
@[simp, grind =] theorem back?_append {xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back? := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.back?_toArray]
@@ -3762,6 +3777,10 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Array α} {a : α} :
rcases xs with xs
simp [List.contains_iff_exists_mem_beq]
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
grind_pattern contains_iff_exists_mem_beq => xs.contains a
@[grind _=_]
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.contains a a xs := by
@@ -4004,10 +4023,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
cases xss using array₂_induction
simp [Function.comp_def]
@[grind] theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
@[grind =] theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
simp
@[grind] theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
@[grind =] theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
simp
/-- Variant of `any_flatMap` with a side condition for the `stop` argument. -/
@@ -4026,11 +4045,11 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
rw [List.flatMap_toArray]
simp [List.all_flatMap]
@[grind] theorem any_flatMap {xs : Array α} {f : α Array β} {p : β Bool} :
@[grind =] theorem any_flatMap {xs : Array α} {f : α Array β} {p : β Bool} :
(xs.flatMap f).any p 0 = xs.any fun a => (f a).any p := by
simp
@[grind] theorem all_flatMap {xs : Array α} {f : α Array β} {p : β Bool} :
@[grind =] theorem all_flatMap {xs : Array α} {f : α Array β} {p : β Bool} :
(xs.flatMap f).all p 0 = xs.all fun a => (f a).all p := by
simp
@@ -4048,10 +4067,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
rw [List.reverse_toArray]
simp [List.all_reverse]
@[grind] theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
@[grind =] theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
simp
@[grind] theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
@[grind =] theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
simp
@[simp] theorem any_replicate {n : Nat} {a : α} :
@@ -4122,7 +4141,7 @@ theorem getElem_swap' {xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs
· simp_all only [getElem_swap_left]
· split <;> simp_all
@[grind]
@[grind =]
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
apply getElem_swap'
@@ -4173,13 +4192,13 @@ theorem swapAt!_def {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
section replace
variable [BEq α]
@[simp, grind] theorem replace_empty : (#[] : Array α).replace a b = #[] := by simp [replace]
@[simp, grind =] theorem replace_empty : (#[] : Array α).replace a b = #[] := by simp [replace]
@[simp, grind] theorem replace_singleton {a b c : α} : #[a].replace b c = #[if a == b then c else a] := by
@[simp, grind =] theorem replace_singleton {a b c : α} : #[a].replace b c = #[if a == b then c else a] := by
simp only [replace, List.finIdxOf?_toArray, List.finIdxOf?]
by_cases h : a == b <;> simp [h]
@[simp, grind] theorem size_replace {xs : Array α} : (xs.replace a b).size = xs.size := by
@[simp, grind =] theorem size_replace {xs : Array α} : (xs.replace a b).size = xs.size := by
simp only [replace]
split <;> simp
@@ -4191,7 +4210,7 @@ variable [LawfulBEq α]
cases xs
simp_all
@[grind] theorem getElem?_replace {xs : Array α} {i : Nat} :
@[grind =] theorem getElem?_replace {xs : Array α} {i : Nat} :
(xs.replace a b)[i]? = if xs[i]? == some a then if a xs.take i then some a else some b else xs[i]? := by
rcases xs with xs
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, take_eq_extract,
@@ -4201,7 +4220,7 @@ theorem getElem?_replace_of_ne {xs : Array α} {i : Nat} (h : xs[i]? ≠ some a)
(xs.replace a b)[i]? = xs[i]? := by
simp_all [getElem?_replace]
@[grind] theorem getElem_replace {xs : Array α} {i : Nat} (h : i < xs.size) :
@[grind =] theorem getElem_replace {xs : Array α} {i : Nat} (h : i < xs.size) :
(xs.replace a b)[i]'(by simpa) = if xs[i] == a then if a xs.take i then a else b else xs[i] := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_replace]
@@ -4212,14 +4231,14 @@ theorem getElem_replace_of_ne {xs : Array α} {i : Nat} {h : i < xs.size} (h' :
rw [getElem_replace h]
simp [h']
@[grind] theorem replace_append {xs ys : Array α} :
@[grind =] theorem replace_append {xs ys : Array α} :
(xs ++ ys).replace a b = if a xs then xs.replace a b ++ ys else xs ++ ys.replace a b := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.replace_toArray, List.replace_append, mem_toArray]
split <;> simp
@[grind] theorem replace_push {xs : Array α} {a b c : α} :
@[grind =] theorem replace_push {xs : Array α} {a b c : α} :
(xs.push a).replace b c = if b xs then (xs.replace b c).push a else xs.push (if b == a then c else a) := by
rcases xs with xs
simp [List.replace_append]
@@ -4370,7 +4389,7 @@ theorem getElem?_range {n : Nat} {i : Nat} : (Array.range n)[i]? = if i < n then
/-! ### sum -/
@[simp, grind] theorem sum_empty [Add α] [Zero α] : (#[] : Array α).sum = 0 := rfl
@[simp, grind =] theorem sum_empty [Add α] [Zero α] : (#[] : Array α).sum = 0 := rfl
-- Without further algebraic hypotheses, there's no useful `sum_push` lemma.
@@ -4443,7 +4462,7 @@ theorem getElem_mem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]
theorem back!_eq_back? [Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD default := by
simp [back!, back?, getElem!_def, Option.getD]; rfl
@[simp, grind] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
@[simp, grind =] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
simp [back?]
@[simp] theorem back!_push [Inhabited α] {xs : Array α} {x : α} : (xs.push x).back! = x := by

View File

@@ -70,8 +70,8 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
rw [cons_lex_cons.forIn'_congr_aux Std.PRange.toList_eq_match rfl (fun _ _ _ => rfl)]
simp only [Std.PRange.SupportsUpperBound.IsSatisfied, bind_pure_comp, map_pure]
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
simp only [Std.PRange.toList_open_eq_toList_closed_of_isSome_succ? (lo := 0) (h := rfl),
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.ClosedOpen.toList_succ_succ,
simp only [Std.PRange.toList_Rox_eq_toList_Rcx_of_isSome_succ? (lo := 0) (h := rfl),
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_Rco_succ_succ,
Option.get_some, List.forIn'_cons, List.size_toArray, List.length_cons, List.length_nil,
Nat.lt_add_one, getElem_append_left, List.getElem_toArray, List.getElem_cons_zero]
cases lt a b

View File

@@ -206,10 +206,13 @@ Converts a bitvector into a fixed-width hexadecimal number with enough digits to
If `n` is `0`, then one digit is returned. Otherwise, `⌊(n + 3) / 4⌋` digits are returned.
-/
-- If we ever want to prove something about this, we can avoid having to use the opaque
-- `Internal` string functions by moving this definition out to a separate file that can live
-- downstream of `Init.Data.String.Basic`.
protected def toHex {n : Nat} (x : BitVec n) : String :=
let s := (Nat.toDigits 16 x.toNat).asString
let t := (List.replicate ((n+3) / 4 - s.length) '0').asString
t ++ s
let t := (List.replicate ((n+3) / 4 - String.Internal.length s) '0').asString
String.Internal.append t s
/-- `BitVec` representation. -/
protected def BitVec.repr (a : BitVec n) : Std.Format :=

View File

@@ -21,13 +21,6 @@ namespace BitVec
section Nat
/--
The bitvector with value `i mod 2^n`.
-/
@[expose, match_pattern]
protected def ofNat (n : Nat) (i : Nat) : BitVec n where
toFin := Fin.ofNat (2^n) i
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
/-- Return the bound in terms of toNat. -/

View File

@@ -19,7 +19,7 @@ theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
@[simp, grind =] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
@[simp, grind] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getLsbD x i = false := by
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getLsbD x i = false := by
let x, x_lt := x
simp only [getLsbD_ofFin]
apply Nat.testBit_lt_two_pow

View File

@@ -37,7 +37,7 @@ namespace BitVec
@[simp] theorem getElem_ofFin (x : Fin (2^n)) (i : Nat) (h : i < n) :
(BitVec.ofFin x)[i] = x.val.testBit i := rfl
@[simp, grind] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getMsbD x i = false := by
@[simp, grind =] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getMsbD x i = false := by
rw [getMsbD]
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
omega
@@ -122,7 +122,7 @@ theorem getElem_of_getLsbD_eq_true {x : BitVec w} {i : Nat} (h : x.getLsbD i = t
This normalized a bitvec using `ofFin` to `ofNat`.
-/
theorem ofFin_eq_ofNat : @BitVec.ofFin w (Fin.mk x lt) = BitVec.ofNat w x := by
simp only [BitVec.ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
simp only [BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
/-- Prove nonequality of bitvectors in terms of nat operations. -/
theorem toNat_ne_iff_ne {n} {x y : BitVec n} : x.toNat y.toNat x y := by
@@ -299,7 +299,7 @@ theorem length_pos_of_ne {x y : BitVec w} (h : x ≠ y) : 0 < w :=
theorem ofFin_ofNat (n : Nat) :
ofFin (no_index (OfNat.ofNat n : Fin (2^w))) = OfNat.ofNat n := by
simp only [OfNat.ofNat, Fin.ofNat, BitVec.ofNat]
simp only [OfNat.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, BitVec.ofNat]
-- We use a `grind_pattern` as `@[grind]` will not use the `no_index` term.
grind_pattern ofFin_ofNat => ofFin (OfNat.ofNat n : Fin (2^w))

View File

@@ -10,7 +10,6 @@ public import Init.NotationExtra
public section
namespace Bool
/--

View File

@@ -7,5 +7,6 @@ module
prelude
public import Init.Data.ByteArray.Basic
public import Init.Data.ByteArray.Extra
public section

View File

@@ -6,7 +6,6 @@ Author: Leonardo de Moura
module
prelude
public import Init.Data.Array.Basic
public import Init.Data.Array.DecidableEq
public import Init.Data.UInt.Basic
public import Init.Data.UInt.BasicAux
@@ -361,27 +360,3 @@ def List.toByteArray (bs : List UInt8) : ByteArray :=
loop bs ByteArray.empty
instance : ToString ByteArray := fun bs => bs.toList.toString
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
assert! bs.size == 8
(bs.get! 7).toUInt64 <<< 0x38 |||
(bs.get! 6).toUInt64 <<< 0x30 |||
(bs.get! 5).toUInt64 <<< 0x28 |||
(bs.get! 4).toUInt64 <<< 0x20 |||
(bs.get! 3).toUInt64 <<< 0x18 |||
(bs.get! 2).toUInt64 <<< 0x10 |||
(bs.get! 1).toUInt64 <<< 0x8 |||
(bs.get! 0).toUInt64
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
assert! bs.size == 8
(bs.get! 0).toUInt64 <<< 0x38 |||
(bs.get! 1).toUInt64 <<< 0x30 |||
(bs.get! 2).toUInt64 <<< 0x28 |||
(bs.get! 3).toUInt64 <<< 0x20 |||
(bs.get! 4).toUInt64 <<< 0x18 |||
(bs.get! 5).toUInt64 <<< 0x10 |||
(bs.get! 6).toUInt64 <<< 0x8 |||
(bs.get! 7).toUInt64

View File

@@ -0,0 +1,34 @@
/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
-/
module
prelude
public import Init.Data.ByteArray.Basic
import Init.Data.String.Basic
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
public def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
assert! bs.size == 8
(bs.get! 7).toUInt64 <<< 0x38 |||
(bs.get! 6).toUInt64 <<< 0x30 |||
(bs.get! 5).toUInt64 <<< 0x28 |||
(bs.get! 4).toUInt64 <<< 0x20 |||
(bs.get! 3).toUInt64 <<< 0x18 |||
(bs.get! 2).toUInt64 <<< 0x10 |||
(bs.get! 1).toUInt64 <<< 0x8 |||
(bs.get! 0).toUInt64
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
public def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
assert! bs.size == 8
(bs.get! 0).toUInt64 <<< 0x38 |||
(bs.get! 1).toUInt64 <<< 0x30 |||
(bs.get! 2).toUInt64 <<< 0x28 |||
(bs.get! 3).toUInt64 <<< 0x20 |||
(bs.get! 4).toUInt64 <<< 0x18 |||
(bs.get! 5).toUInt64 <<< 0x10 |||
(bs.get! 6).toUInt64 <<< 0x8 |||
(bs.get! 7).toUInt64

View File

@@ -66,11 +66,6 @@ instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
def notLTTotal : Std.Total (¬ · < · : Char Char Prop) where
total := fun x y => by simpa using Char.le_total y x
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 c.utf8Size = 2 c.utf8Size = 3 c.utf8Size = 4 := by
have := c.utf8Size_pos
have := c.utf8Size_le_four
omega
@[simp] theorem ofNat_toNat (c : Char) : Char.ofNat c.toNat = c := by
rw [Char.ofNat, dif_pos]
rfl

View File

@@ -51,6 +51,11 @@ The assumption `NeZero n` ensures that `Fin n` is nonempty.
@[expose] protected def ofNat (n : Nat) [NeZero n] (a : Nat) : Fin n :=
a % n, Nat.mod_lt _ (pos_of_neZero n)
@[simp]
theorem Internal.ofNat_eq_ofNat {n : Nat} {hn} {a : Nat} :
letI : NeZero n := Nat.pos_iff_ne_zero.1 hn
Fin.Internal.ofNat n hn a = Fin.ofNat n a := rfl
@[deprecated Fin.ofNat (since := "2025-05-28")]
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
Fin.ofNat n a

View File

@@ -25,12 +25,12 @@ namespace Fin
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a.val % m.val) (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.pos) := rfl
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a.val * b.val) % 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.pos) := rfl
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b.val) + a.val) % n) (Nat.mod_lt _ a.pos) := rfl
theorem pos' : [Nonempty (Fin n)], 0 < n | i => i.pos
@@ -81,7 +81,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
@[deprecated ofNat_self (since := "2025-05-28")] abbrev ofNat'_self := @ofNat_self
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x) = x := by
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x.val) = x := by
ext
rw [val_ofNat, Nat.mod_eq_of_lt]
exact x.2
@@ -121,8 +121,6 @@ Non-trivial loops lead to undesirable and counterintuitive elaboration behavior.
For example, for `x : Fin k` and `n : Nat`,
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
silently introducing wraparound arithmetic.
Note: as of 2025-06-03, Mathlib has such a coercion for `Fin n` anyway!
-/
@[expose]
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
@@ -265,7 +263,7 @@ instance : LawfulOrderLT (Fin n) where
lt_iff := by
simp [ Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
@[simp, grind =] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
@[simp, grind =] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
rw [val_rev, val_rev, Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
@@ -500,9 +498,11 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
ext
simp
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
@[simp, grind =] theorem cast_cast {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
@[deprecated cast_cast (since := "2025-09-03")] abbrev cast_trans := @cast_cast
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
@@ -531,7 +531,7 @@ theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
(i.castAdd m').cast h = i.castAdd m := rfl
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := 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. -/

View File

@@ -8,7 +8,7 @@ module
prelude
public import Init.Control.State
public import Init.Data.Int.Basic
public import Init.Data.String.Basic
public import Init.Data.String.Bootstrap
public section
@@ -168,8 +168,8 @@ private def spaceUptoLine : Format → Bool → Int → Nat → SpaceResult
else
{ foundLine := true }
| text s, flatten, _, _ =>
let p := s.posOf '\n'
let off := s.offsetOfPos p
let p := String.Internal.posOf s '\n'
let off := String.Internal.offsetOfPos s p
{ foundLine := p != s.endPos, foundFlattenedHardLine := flatten && p != s.endPos, space := off }
| append f₁ f₂, flatten, m, w => merge w (spaceUptoLine f₁ flatten m w) (spaceUptoLine f₂ flatten m)
| nest n f, flatten, m, w => spaceUptoLine f flatten (m - n) w
@@ -263,15 +263,15 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
| append f₁ f₂ => be w (gs' ({ i with f := f₁, activeTags := 0 }::{ i with f := f₂ }::is))
| nest n f => be w (gs' ({ i with f, indent := i.indent + n }::is))
| text s =>
let p := s.posOf '\n'
let p := String.Internal.posOf s '\n'
if p == s.endPos then
pushOutput s
endTags i.activeTags
be w (gs' is)
else
pushOutput (s.extract {} p)
pushOutput (String.Internal.extract s {} p)
pushNewline i.indent.toNat
let is := { i with f := text (s.extract (s.next p) s.endPos) }::is
let is := { i with f := text (String.Internal.extract s (String.Internal.next s p) s.endPos) }::is
-- after a hard line break, re-evaluate whether to flatten the remaining group
-- note that we shouldn't start flattening after a hard break outside a group
if g.fla == .disallow then
@@ -298,7 +298,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
pushGroup FlattenBehavior.fill is gs w >>= be w
-- if preceding fill item fit in a single line, try to fit next one too
if g.fla.shouldFlatten then
let gs'@(g'::_) pushGroup FlattenBehavior.fill is gs (w - " ".length)
let gs'@(g'::_) pushGroup FlattenBehavior.fill is gs (w - String.Internal.length " ")
| panic "unreachable"
if g'.fla.shouldFlatten then
pushOutput " "
@@ -316,7 +316,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
else
let k currColumn
if k < i.indent then
pushOutput ("".pushn ' ' (i.indent - k).toNat)
pushOutput (String.Internal.pushn "" ' ' (i.indent - k).toNat)
endTags i.activeTags
be w (gs' is)
else
@@ -350,7 +350,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
The group's `FlattenBehavior` is `allOrNone`; for `fill` use `Std.Format.bracketFill`.
-/
@[inline] def bracket (l : String) (f : Format) (r : String) : Format :=
group (nest l.length $ l ++ f ++ r)
group (nest (String.Internal.length l) $ l ++ f ++ r)
/--
Creates the format `"(" ++ f ++ ")"` with a flattening group, nesting by one space.
@@ -372,7 +372,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
The group's `FlattenBehavior` is `fill`; for `allOrNone` use `Std.Format.bracketFill`.
-/
@[inline] def bracketFill (l : String) (f : Format) (r : String) : Format :=
fill (nest l.length $ l ++ f ++ r)
fill (nest (String.Internal.length l) $ l ++ f ++ r)
/-- The default indentation level, which is two spaces. -/
def defIndent := 2
@@ -397,8 +397,8 @@ private structure State where
private instance : MonadPrettyFormat (StateM State) where
-- We avoid a structure instance update, and write these functions using pattern matching because of issue #316
pushOutput s := modify fun out, col => out ++ s, col + s.length
pushNewline indent := modify fun out, _ => out ++ "\n".pushn ' ' indent, indent
pushOutput s := modify fun out, col => String.Internal.append out s, col + (String.Internal.length s)
pushNewline indent := modify fun out, _ => String.Internal.append out (String.Internal.pushn "\n" ' ' indent), indent
currColumn := return ( get).column
startTag _ := return ()
endTags _ := return ()

View File

@@ -9,6 +9,7 @@ prelude
public import Init.Data.Format.Basic
public import Init.Data.Array.Basic
public import Init.Data.ToString.Basic
import Init.Data.String.Basic
public section

View File

@@ -9,6 +9,8 @@ prelude
public import Init.Data.Format.Macro
public import Init.Data.Format.Instances
public import Init.Meta
import Init.Data.String.Basic
import Init.Data.ToString.Name
public section

View File

@@ -34,20 +34,104 @@ Examples:
@[inline, expose]
def uncurry : (α β φ) α × β φ := fun f a => f a.1 a.2
@[simp, grind]
@[simp, grind =]
theorem curry_uncurry (f : α β φ) : curry (uncurry f) = f :=
rfl
@[simp, grind]
@[simp, grind =]
theorem uncurry_curry (f : α × β φ) : uncurry (curry f) = f :=
funext fun _a, _b => rfl
@[simp, grind]
@[simp, grind =]
theorem uncurry_apply_pair {α β γ} (f : α β γ) (x : α) (y : β) : uncurry f (x, y) = f x y :=
rfl
@[simp, grind]
@[simp, grind =]
theorem curry_apply {α β γ} (f : α × β γ) (x : α) (y : β) : curry f x y = f (x, y) :=
rfl
/-- A function `f : α → β` is called injective if `f x = f y` implies `x = y`. -/
def Injective (f : α β) : Prop :=
a₁ a₂, f a₁ = f a₂ a₁ = a₂
theorem Injective.comp {g : β φ} {f : α β} (hg : Injective g) (hf : Injective f) :
Injective (g f) := fun _a₁ _a₂ => fun h => hf (hg h)
/-- A function `f : α → β` is called surjective if every `b : β` is equal to `f a`
for some `a : α`. -/
def Surjective (f : α β) : Prop :=
b, Exists fun a => f a = b
theorem Surjective.comp {g : β φ} {f : α β} (hg : Surjective g) (hf : Surjective f) :
Surjective (g f) := fun c : φ =>
Exists.elim (hg c) fun b hb =>
Exists.elim (hf b) fun a ha =>
Exists.intro a (show g (f a) = c from Eq.trans (congrArg g ha) hb)
/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/
@[grind]
def LeftInverse (g : β α) (f : α β) : Prop :=
x, g (f x) = x
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
def HasLeftInverse (f : α β) : Prop :=
Exists fun finv : β α => LeftInverse finv f
/-- `RightInverse g f` means that `g` is a right inverse to `f`. That is, `f ∘ g = id`. -/
@[grind]
def RightInverse (g : β α) (f : α β) : Prop :=
LeftInverse f g
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
def HasRightInverse (f : α β) : Prop :=
Exists fun finv : β α => RightInverse finv f
theorem LeftInverse.injective {g : β α} {f : α β} : LeftInverse g f Injective f :=
fun h a b faeqfb => ((h a).symm.trans (congrArg g faeqfb)).trans (h b)
theorem HasLeftInverse.injective {f : α β} : HasLeftInverse f Injective f := fun h =>
Exists.elim h fun _finv inv => inv.injective
theorem rightInverse_of_injective_of_leftInverse {f : α β} {g : β α} (injf : Injective f)
(lfg : LeftInverse f g) : RightInverse f g := fun x =>
have h : f (g (f x)) = f x := lfg (f x)
injf h
theorem RightInverse.surjective {f : α β} {g : β α} (h : RightInverse g f) : Surjective f :=
fun y => g y, h y
theorem HasRightInverse.surjective {f : α β} : HasRightInverse f Surjective f
| _finv, inv => inv.surjective
theorem leftInverse_of_surjective_of_rightInverse {f : α β} {g : β α} (surjf : Surjective f)
(rfg : RightInverse f g) : LeftInverse f g := fun y =>
Exists.elim (surjf y) fun x hx => ((hx rfl : f (g y) = f (g (f x))).trans (Eq.symm (rfg x) rfl)).trans hx
theorem injective_id : Injective (@id α) := fun _a₁ _a₂ h => h
theorem surjective_id : Surjective (@id α) := fun a => a, rfl
variable {f : α β}
theorem Injective.eq_iff (I : Injective f) {a b : α} : f a = f b a = b :=
@I _ _, congrArg f
theorem Injective.eq_iff' (I : Injective f) {a b : α} {c : β} (h : f b = c) : f a = c a = b :=
h I.eq_iff
theorem Injective.ne (hf : Injective f) {a₁ a₂ : α} : a₁ a₂ f a₁ f a₂ :=
mt fun h hf h
theorem Injective.ne_iff (hf : Injective f) {x y : α} : f x f y x y :=
mt <| congrArg f, hf.ne
theorem Injective.ne_iff' (hf : Injective f) {x y : α} {z : β} (h : f y = z) : f x z x y :=
h hf.ne_iff
protected theorem LeftInverse.id {g : β α} {f : α β} (h : LeftInverse g f) : g f = id :=
funext h
protected theorem RightInverse.id {g : β α} {f : α β} (h : RightInverse g f) : f g = id :=
funext h
end Function

View File

@@ -379,8 +379,11 @@ def Poly.mul (p : Poly) (k : Int) : Poly :=
p₁)
fuel
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) : Poly Poly Poly :=
combine_mul_k' hugeFuel a b
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) (p₁ p₂ : Poly) : Poly :=
Bool.rec
(Bool.rec (combine_mul_k' hugeFuel a b p₁ p₂) (p₁.mul_k a) (Int.beq' b 0))
(p₂.mul_k b)
(Int.beq' a 0)
@[simp] theorem Poly.denote_mul (ctx : Context) (p : Poly) (k : Int) : (p.mul k).denote ctx = k * p.denote ctx := by
simp [mul]
@@ -424,34 +427,36 @@ theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p
theorem Poly.denote_combine_mul_k (ctx : Context) (a b : Int) (p₁ p₂ : Poly) : (p₁.combine_mul_k a b p₂).denote ctx = a * p₁.denote ctx + b * p₂.denote ctx := by
unfold combine_mul_k
cases h₁ : Int.beq' a 0 <;> simp at h₁ <;> simp [*]
cases h₂ : Int.beq' b 0 <;> simp at h₂ <;> simp [*]
generalize hugeFuel = fuel
induction fuel generalizing p₁ p₂
next => show ((p₁.mul a).append (p₂.mul b)).denote ctx = _; simp
next fuel ih =>
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
next k₁ k₂ v₂ p₂ =>
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
simp [ih, Int.mul_assoc]
next k₁ v₁ p₁ k₂ =>
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
simp [ih, Int.mul_assoc]
next k₁ v₁ p₁ k₂ v₂ p₂ =>
cases h₁ : Nat.beq v₁ v₂ <;> simp
next =>
cases h₂ : Nat.blt v₂ v₁ <;> simp
next =>
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
simp [ih, Int.mul_assoc]
next =>
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
simp [ih, Int.mul_assoc]
next =>
simp at h₁; subst v₂
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
next =>
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
next k₁ k₂ v₂ p₂ =>
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
simp [ih, Int.mul_assoc]
next k₁ v₁ p₁ k₂ =>
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
simp [ih, Int.mul_assoc]
next k₁ v₁ p₁ k₂ v₂ p₂ =>
cases h₁ : Nat.beq v₁ v₂ <;> simp
next =>
cases h₂ : Nat.blt v₂ v₁ <;> simp
next =>
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
simp [ih, Int.mul_assoc]
next =>
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
simp [ih, Int.mul_assoc]
next =>
simp at h₁; subst v₂
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
next =>
show a * k₁ * v₁.denote ctx + (b * k₂ * v₁.denote ctx + (combine_mul_k' fuel a b p₁ p₂).denote ctx) = _
simp [ih, Int.mul_assoc]
next =>
next =>
simp at h₂
show (combine_mul_k' fuel a b p₁ p₂).denote ctx = _
simp [ih, Int.mul_assoc, Int.add_mul, h₂]

View File

@@ -174,7 +174,7 @@ theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
rcases this with _, _, m, rfl
exact m
@[simp, grind]
@[simp, grind =]
theorem mem_attachWith {l : List α} {q : α Prop} (H) (x : {x // q x}) :
x l.attachWith q H x.1 l := by
induction l with
@@ -192,12 +192,13 @@ 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]
@[grind]
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
grind_pattern mem_pmap_of_mem => _ pmap f l H, a l
@[simp, grind =]
theorem length_pmap {p : α Prop} {f : a, p a β} {l H} : (pmap f l H).length = l.length := by
induction l
@@ -370,13 +371,13 @@ theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
xs.attach.tail = xs.tail.attach.map (fun x, h => x, mem_of_mem_tail h) := by
cases xs <;> simp
@[grind]
@[grind =]
theorem foldl_pmap {l : List α} {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]
@[grind]
@[grind =]
theorem foldr_pmap {l : List α} {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

View File

@@ -80,17 +80,17 @@ namespace List
/-! ### length -/
@[simp, grind] theorem length_nil : length ([] : List α) = 0 :=
@[simp, grind =] theorem length_nil : length ([] : List α) = 0 :=
rfl
@[simp] theorem length_singleton {a : α} : length [a] = 1 := rfl
@[simp, grind] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
@[simp, grind =] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
rfl
/-! ### set -/
@[simp, grind] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
@[simp, grind =] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
induction as generalizing i with
| nil => rfl
| cons x xs ih =>
@@ -101,8 +101,8 @@ namespace List
/-! ### foldl -/
-- As `List.foldl` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
@[simp, grind] theorem foldl_nil : [].foldl f b = b := rfl
@[simp, grind] theorem foldl_cons {l : List α} {f : β α β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
@[simp, grind =] theorem foldl_nil : [].foldl f b = b := rfl
@[simp, grind =] theorem foldl_cons {l : List α} {f : β α β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
/-! ### concat -/
@@ -332,7 +332,7 @@ def getLast? : List α → Option α
| [] => none
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
@[simp, grind] theorem getLast?_nil : @getLast? α [] = none := rfl
@[simp, grind =] theorem getLast?_nil : @getLast? α [] = none := rfl
/-! ### getLastD -/
@@ -365,7 +365,7 @@ Returns the first element of a non-empty list.
def head : (as : List α) as [] α
| a::_, _ => a
@[simp, grind] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
@[simp, grind =] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
/-! ### head? -/
@@ -383,8 +383,8 @@ def head? : List α → Option α
| [] => none
| a::_ => some a
@[simp, grind] theorem head?_nil : head? ([] : List α) = none := rfl
@[simp, grind] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
@[simp, grind =] theorem head?_nil : head? ([] : List α) = none := rfl
@[simp, grind =] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
/-! ### headD -/
@@ -420,8 +420,8 @@ def tail : List α → List α
| [] => []
| _::as => as
@[simp, grind] theorem tail_nil : tail ([] : List α) = [] := rfl
@[simp, grind] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
@[simp, grind =] theorem tail_nil : tail ([] : List α) = [] := rfl
@[simp, grind =] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
/-! ### tail? -/
@@ -441,8 +441,8 @@ def tail? : List α → Option (List α)
| [] => none
| _::as => some as
@[simp, grind] theorem tail?_nil : tail? ([] : List α) = none := rfl
@[simp, grind] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
@[simp, grind =] theorem tail?_nil : tail? ([] : List α) = none := rfl
@[simp, grind =] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
/-! ### tailD -/
@@ -490,8 +490,8 @@ Examples:
| [] => []
| a::as => f a :: map f as
@[simp, grind] theorem map_nil {f : α β} : map f [] = [] := rfl
@[simp, grind] theorem map_cons {f : α β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
@[simp, grind =] theorem map_nil {f : α β} : map f [] = [] := rfl
@[simp, grind =] theorem map_cons {f : α β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
/-! ### filter -/
@@ -511,7 +511,7 @@ def filter (p : α → Bool) : (l : List α) → List α
| true => a :: filter p as
| false => filter p as
@[simp, grind] theorem filter_nil {p : α Bool} : filter p [] = [] := rfl
@[simp, grind =] theorem filter_nil {p : α Bool} : filter p [] = [] := rfl
/-! ### filterMap -/
@@ -537,8 +537,8 @@ Example:
| none => filterMap f as
| some b => b :: filterMap f as
@[simp, grind] theorem filterMap_nil {f : α Option β} : filterMap f [] = [] := rfl
@[grind] theorem filterMap_cons {f : α Option β} {a : α} {l : List α} :
@[simp, grind =] theorem filterMap_nil {f : α Option β} : filterMap f [] = [] := rfl
@[grind =] theorem filterMap_cons {f : α Option β} {a : α} {l : List α} :
filterMap f (a :: l) =
match f a with
| none => filterMap f l
@@ -561,8 +561,8 @@ Examples:
| [] => init
| a :: l => f a (foldr f init l)
@[simp, grind] theorem foldr_nil : [].foldr f b = b := rfl
@[simp, grind] theorem foldr_cons {a} {l : List α} {f : α β β} {b} :
@[simp, grind =] theorem foldr_nil : [].foldr f b = b := rfl
@[simp, grind =] theorem foldr_cons {a} {l : List α} {f : α β β} {b} :
(a :: l).foldr f b = f a (l.foldr f b) := rfl
/-! ### reverse -/
@@ -591,7 +591,7 @@ Examples:
@[expose] def reverse (as : List α) : List α :=
reverseAux as []
@[simp, grind] theorem reverse_nil : reverse ([] : List α) = [] := rfl
@[simp, grind =] theorem reverse_nil : reverse ([] : List α) = [] := rfl
theorem reverseAux_reverseAux {as bs cs : List α} :
reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs) := by
@@ -645,10 +645,10 @@ instance : Append (List α) := ⟨List.append⟩
@[simp] theorem append_eq {as bs : List α} : List.append as bs = as ++ bs := rfl
@[simp, grind] theorem nil_append (as : List α) : [] ++ as = as := rfl
@[simp, grind =] theorem nil_append (as : List α) : [] ++ as = as := rfl
@[simp, grind _=_] theorem cons_append {a : α} {as bs : List α} : (a::as) ++ bs = a::(as ++ bs) := rfl
@[simp, grind] theorem append_nil (as : List α) : as ++ [] = as := by
@[simp, grind =] theorem append_nil (as : List α) : as ++ [] = as := by
induction as with
| nil => rfl
| cons a as ih =>
@@ -658,7 +658,7 @@ instance : Std.LawfulIdentity (α := List α) (· ++ ·) [] where
left_id := nil_append
right_id := append_nil
@[simp, grind] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
@[simp, grind =] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
induction as with
| nil => simp
| cons _ as ih => simp [ih, Nat.succ_add]
@@ -685,7 +685,7 @@ theorem reverseAux_eq_append {as bs : List α} : reverseAux as bs = reverseAux a
rw [ih (bs := a :: bs), ih (bs := [a]), append_assoc]
rfl
@[simp, grind] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
@[simp, grind =] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
simp [reverse, reverseAux]
rw [ reverseAux_eq_append]
@@ -704,8 +704,8 @@ def flatten : List (List α) → List α
| [] => []
| l :: L => l ++ flatten L
@[simp, grind] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
@[simp, grind] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
@[simp, grind =] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
@[simp, grind =] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
/-! ### singleton -/
@@ -731,8 +731,8 @@ Examples:
-/
@[inline] def flatMap {α : Type u} {β : Type v} (b : α List β) (as : List α) : List β := flatten (map b as)
@[simp, grind] theorem flatMap_nil {f : α List β} : List.flatMap f [] = [] := by simp [List.flatMap]
@[simp, grind] theorem flatMap_cons {x : α} {xs : List α} {f : α List β} :
@[simp, grind =] theorem flatMap_nil {f : α List β} : List.flatMap f [] = [] := by simp [List.flatMap]
@[simp, grind =] theorem flatMap_cons {x : α} {xs : List α} {f : α List β} :
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
/-! ### replicate -/
@@ -748,10 +748,10 @@ def replicate : (n : Nat) → (a : α) → List α
| 0, _ => []
| n+1, a => a :: replicate n a
@[simp, grind] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
@[grind] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
@[simp, grind =] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
@[grind =] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
@[simp, grind] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
@[simp, grind =] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
induction n with
| zero => simp
| succ n ih => simp only [ih, replicate_succ, length_cons]
@@ -819,8 +819,8 @@ def isEmpty : List α → Bool
| [] => true
| _ :: _ => false
@[simp, grind] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
@[simp, grind] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
@[simp, grind =] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
@[simp, grind =] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
/-! ### elem -/
@@ -842,7 +842,7 @@ def elem [BEq α] (a : α) : (l : List α) → Bool
| true => true
| false => elem a bs
@[simp, grind] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
@[simp, grind =] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
theorem elem_cons [BEq α] {a : α} :
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
@@ -958,9 +958,9 @@ def take : (n : Nat) → (xs : List α) → List α
| _+1, [] => []
| n+1, a::as => a :: take n as
@[simp, grind] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
@[simp, grind] theorem take_zero {l : List α} : l.take 0 = [] := rfl
@[simp, grind] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
@[simp, grind =] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
@[simp, grind =] theorem take_zero {l : List α} : l.take 0 = [] := rfl
@[simp, grind =] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
/-! ### drop -/
@@ -980,10 +980,10 @@ def drop : (n : Nat) → (xs : List α) → List α
| _+1, [] => []
| n+1, _::as => drop n as
@[simp, grind] theorem drop_nil : ([] : List α).drop i = [] := by
@[simp, grind =] theorem drop_nil : ([] : List α).drop i = [] := by
cases i <;> rfl
@[simp, grind] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
@[simp, grind] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
@[simp, grind =] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
@[simp, grind =] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
theorem drop_eq_nil_of_le {as : List α} {i : Nat} (h : as.length i) : as.drop i = [] := by
match as, i with
@@ -1094,13 +1094,13 @@ def dropLast {α} : List α → List α
| [_] => []
| a::as => a :: dropLast as
@[simp, grind] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
@[simp, grind] theorem dropLast_singleton : [x].dropLast = [] := rfl
@[simp, grind =] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
@[simp, grind =] theorem dropLast_singleton : [x].dropLast = [] := rfl
@[deprecated dropLast_singleton (since := "2025-04-16")]
theorem dropLast_single : [x].dropLast = [] := dropLast_singleton
@[simp, grind] theorem dropLast_cons₂ :
@[simp, grind =] theorem dropLast_cons₂ :
(x::y::zs).dropLast = x :: (y::zs).dropLast := rfl
-- Later this can be proved by `simp` via `[List.length_dropLast, List.length_cons, Nat.add_sub_cancel]`,
@@ -1439,8 +1439,8 @@ def replace [BEq α] : (l : List α) → (a : α) → (b : α) → List α
| true => c::as
| false => a :: replace as b c
@[simp, grind] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
@[grind] theorem replace_cons [BEq α] {a : α} :
@[simp, grind =] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
@[grind =] theorem replace_cons [BEq α] {a : α} :
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
rfl
@@ -1648,8 +1648,8 @@ def findSome? (f : α → Option β) : List α → Option β
| some b => some b
| none => findSome? f as
@[simp, grind] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
@[grind] theorem findSome?_cons {f : α Option β} :
@[simp, grind =] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
@[grind =] theorem findSome?_cons {f : α Option β} :
(a::as).findSome? f = match f a with | some b => some b | none => as.findSome? f :=
rfl
@@ -1906,8 +1906,8 @@ def any : (l : List α) → (p : α → Bool) → Bool
| [], _ => false
| h :: t, p => p h || any t p
@[simp, grind] theorem any_nil : [].any f = false := rfl
@[simp, grind] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
@[simp, grind =] theorem any_nil : [].any f = false := rfl
@[simp, grind =] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
/-! ### all -/
@@ -1925,8 +1925,8 @@ def all : List α → (α → Bool) → Bool
| [], _ => true
| h :: t, p => p h && all t p
@[simp, grind] theorem all_nil : [].all f = true := rfl
@[simp, grind] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
@[simp, grind =] theorem all_nil : [].all f = true := rfl
@[simp, grind =] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
/-! ### or -/
@@ -2066,8 +2066,8 @@ Examples:
def sum {α} [Add α] [Zero α] : List α α :=
foldr (· + ·) 0
@[simp, grind] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
@[simp, grind] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
@[simp, grind =] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
@[simp, grind =] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
/-! ### range -/

View File

@@ -223,7 +223,7 @@ variable [BEq α]
@[simp, grind =] theorem count_nil {a : α} : count a [] = 0 := rfl
@[grind]
@[grind =]
theorem count_cons {a b : α} {l : List α} :
count a (b :: l) = count a l + if b == a then 1 else 0 := by
simp [count, countP_cons]
@@ -237,7 +237,7 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
theorem count_eq_length_filter {a : α} {l : List α} : count a l = (filter (· == a) l).length := by
simp [count, countP_eq_length_filter]
@[grind]
@[grind =]
theorem count_tail : {l : List α} {a : α},
l.tail.count a = l.count a - if l.head? == some a then 1 else 0
| [], a => by simp
@@ -380,7 +380,7 @@ theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {l : List
theorem count_flatMap {α} [BEq β] {l : List α} {f : α List β} {x : β} :
count x (l.flatMap f) = sum (map (count x f) l) := countP_flatMap
@[grind]
@[grind =]
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

@@ -130,7 +130,7 @@ theorem le_length_eraseP {l : List α} : l.length - 1 ≤ (l.eraseP p).length :=
@[grind ]
theorem mem_of_mem_eraseP {l : List α} : a l.eraseP p a l := (eraseP_subset ·)
@[simp, grind] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a l.eraseP p a l := by
@[simp, grind =] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a l.eraseP p a l := by
refine mem_of_mem_eraseP, fun al => ?_
match exists_or_eq_self_of_eraseP p l with
| .inl h => rw [h]; assumption
@@ -265,14 +265,18 @@ theorem eraseP_eq_iff {p} {l : List α} :
subst p
simp_all
@[grind ]
theorem Pairwise.eraseP (q) : Pairwise p l Pairwise p (l.eraseP q) :=
Pairwise.sublist <| eraseP_sublist
@[grind ]
grind_pattern Pairwise.eraseP => Pairwise p (l.eraseP q)
grind_pattern Pairwise.eraseP => Pairwise p l, l.eraseP q
theorem Nodup.eraseP (p) : Nodup l Nodup (l.eraseP p) :=
Pairwise.eraseP p
grind_pattern Nodup.eraseP => Nodup (l.eraseP p)
grind_pattern Nodup.eraseP => Nodup l, l.eraseP p
@[grind =]
theorem eraseP_comm {l : List α} (h : a l, ¬ p a ¬ q a) :
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
@@ -393,7 +397,7 @@ theorem le_length_erase [LawfulBEq α] {a : α} {l : List α} : l.length - 1 ≤
@[grind ]
theorem mem_of_mem_erase {a b : α} {l : List α} (h : a l.erase b) : a l := erase_subset h
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a b) :
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a b) :
a l.erase b a l :=
erase_eq_eraseP b l mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@@ -508,10 +512,12 @@ theorem Nodup.not_mem_erase [LawfulBEq α] {a : α} (h : Nodup l) : a ∉ l.eras
-- Only activate `not_mem_erase` when `l.Nodup` is already available.
grind_pattern List.Nodup.not_mem_erase => a l.erase a, l.Nodup
@[grind]
theorem Nodup.erase [LawfulBEq α] (a : α) : Nodup l Nodup (l.erase a) :=
Pairwise.erase a
grind_pattern Nodup.erase => Nodup (l.erase a)
grind_pattern Nodup.erase => Nodup l, l.erase a
theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h xs :=
erase_sublist.head_mem h
@@ -578,21 +584,21 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
| [a]
| a::b::l => simp
@[grind]
theorem eraseIdx_sublist : (l : List α) (k : Nat), eraseIdx l k <+ l
| [], _ => by simp
| a::l, 0 => by simp
| a::l, k + 1 => by simp [eraseIdx_sublist]
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ <+ l
theorem mem_of_mem_eraseIdx {l : List α} {i : Nat} {a : α} (h : a l.eraseIdx i) : a l :=
(eraseIdx_sublist _ _).mem h
@[grind]
theorem eraseIdx_subset {l : List α} {k : Nat} : eraseIdx l k l :=
(eraseIdx_sublist _ _).subset
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ l
@[simp]
theorem eraseIdx_eq_self : {l : List α} {k : Nat}, eraseIdx l k = l length l k
| [], _ => by simp
@@ -649,15 +655,18 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
exact m.2
· rw [eraseIdx_of_length_le (by simpa using h)]
@[grind ]
theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l Pairwise p (l.eraseIdx k) :=
Pairwise.sublist <| eraseIdx_sublist _ _
@[grind ]
grind_pattern Pairwise.eraseIdx => Pairwise p (l.eraseIdx k)
grind_pattern Pairwise.eraseIdx => Pairwise p l, l.eraseIdx k
theorem Nodup.eraseIdx {l : List α} (k) : Nodup l Nodup (l.eraseIdx k) :=
Pairwise.eraseIdx k
@[grind ]
grind_pattern Nodup.eraseIdx => Nodup (l.eraseIdx k)
grind_pattern Nodup.eraseIdx => Nodup l, l.eraseIdx k
protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
eraseIdx l k <+: eraseIdx l' k := by
rcases h with t, rfl
@@ -667,6 +676,10 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
rw [Nat.not_lt] at hkl
simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl]
grind_pattern IsPrefix.eraseIdx => eraseIdx l k <+: eraseIdx l' k
grind_pattern IsPrefix.eraseIdx => eraseIdx l k, l <+: l'
grind_pattern IsPrefix.eraseIdx => eraseIdx l' k, l <+: l'
-- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in
-- `Init/Data/List/Nat/Basic.lean`.
@@ -686,6 +699,4 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
rw [eq_comm, eraseIdx_eq_self]
exact Nat.le_of_eq (idxOf_eq_length h).symm
end List

View File

@@ -293,7 +293,6 @@ theorem mem_of_find?_eq_some : ∀ {l}, find? p l = some a → a ∈ l
· exact H .head _
· exact .tail _ (mem_of_find?_eq_some H)
@[grind]
theorem get_find?_mem {xs : List α} {p : α Bool} (h) : (xs.find? p).get h xs := by
induction xs with
| nil => simp at h
@@ -305,6 +304,8 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
right
apply ih
grind_pattern get_find?_mem => (xs.find? p).get h
@[simp, grind =] theorem find?_filter {xs : List α} {p : α Bool} {q : α Bool} :
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
induction xs with
@@ -558,7 +559,6 @@ where
@[simp] theorem findIdx_singleton {a : α} {p : α Bool} : [a].findIdx p = if p a then 0 else 1 := by
simp [findIdx_cons, findIdx_nil]
@[grind ]
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
induction xs with
| nil => simp_all

View File

@@ -306,7 +306,7 @@ theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
match i, h with
| 0, _ => rfl
@[grind]
@[grind =]
theorem getElem?_singleton {a : α} {i : Nat} : [a][i]? = if i = 0 then some a else none := by
simp [getElem?_cons]
@@ -382,14 +382,20 @@ theorem get!_eq_getElem! [Inhabited α] (l : List α) (i) : l.get! i = l[i]! :=
@[simp] theorem not_mem_nil {a : α} : ¬ a [] := nofun
@[simp] theorem mem_cons : a b :: l a = b a l :=
@[simp, grind =] theorem mem_cons : a b :: l a = b a l :=
fun h => by cases h <;> simp [Membership.mem, *],
fun | Or.inl rfl => by constructor | Or.inr h => by constructor; assumption
@[grind] theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
a b :: l a = b a l := List.mem_cons.mp
@[grind] theorem mem_cons_self {a : α} {l : List α} : a a :: l := .head ..
-- This pattern may be excessively general:
-- it fires anytime we ae thinking about membership of lists,
-- and constructing a list via `cons`, even if the elements are unrelated.
-- Nevertheless in practice it is quite helpful!
grind_pattern eq_or_mem_of_mem_cons => b :: l, a l
theorem mem_cons_self {a : α} {l : List α} : a a :: l := .head ..
theorem mem_concat_self {xs : List α} {a : α} : a xs ++ [a] :=
mem_append_right xs mem_cons_self
@@ -411,7 +417,7 @@ theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
· obtain as, bs, rfl, h := ih h
exact x :: as, bs, rfl, by simp_all
@[grind] theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a l a y :: l := .tail _
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a l a y :: l := .tail _
-- The argument `l : List α` is intentionally explicit,
-- as a tactic may generate `h` without determining `l`.
@@ -547,10 +553,10 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
elem a as = decide (a as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
as.contains a = decide (a as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
@[simp, grind] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
@[simp, grind =] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
(a :: l).contains b = (b == a || l.contains b) := by
simp only [contains, elem_cons]
split <;> simp_all
@@ -605,7 +611,7 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
@[simp] theorem all_eq_false {l : List α} : l.all p = false x, x l ¬p x := by
simp [all_eq]
@[grind] theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
induction l <;> simp_all [contains_cons]
/-- Variant of `any_beq` with `==` reversed. -/
@@ -613,7 +619,7 @@ theorem any_beq' [BEq α] [PartialEquivBEq α] {l : List α} :
(l.any fun x => x == a) = l.contains a := by
simp only [BEq.comm, any_beq]
@[grind] theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
induction l <;> simp_all [bne]
/-- Variant of `all_bne` with `!=` reversed. -/
@@ -624,10 +630,10 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
/-! ### set -/
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
@[simp, grind] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
@[simp, grind] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
@[simp, grind =] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
@[simp, grind =] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
(x :: xs).set 0 a = a :: xs := rfl
@[simp, grind] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
@[simp, grind =] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
(x :: xs).set (i + 1) a = x :: xs.set i a := rfl
@[simp] theorem getElem_set_self {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
@@ -670,14 +676,14 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
simp_all
· rw [getElem?_eq_none (by simp_all), getElem?_eq_none (by simp_all)]
@[grind] theorem getElem_set {l : List α} {i j} {a} (h) :
@[grind =] theorem getElem_set {l : List α} {i j} {a} (h) :
(set l i a)[j]'h = if i = j then a else l[j]'(length_set .. h) := by
if h : i = j then
subst h; simp only [getElem_set_self, reduceIte]
else
simp [h]
@[grind] theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
@[grind =] 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
subst h
@@ -747,10 +753,10 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {i : Nat} {a b : α}, a ∈ l.s
/-! ### BEq -/
@[simp, grind] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
@[simp, grind =] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
cases l <;> rfl
@[simp, grind] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
@[simp, grind =] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
cases l <;> rfl
@[deprecated beq_nil_eq (since := "2025-04-04")]
@@ -759,7 +765,7 @@ abbrev beq_nil_iff := @beq_nil_eq
@[deprecated nil_beq_eq (since := "2025-04-04")]
abbrev nil_beq_iff := @nil_beq_eq
@[simp, grind] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
@[simp, grind =] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
@[simp] theorem concat_beq_concat [BEq α] {a b : α} {l₁ l₂ : List α} :
@@ -825,7 +831,7 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
/-! ### getLast -/
@[grind]
@[grind =]
theorem getLast_eq_getElem : {l : List α} (h : l []),
getLast l h = l[l.length - 1]'(by
match l with
@@ -839,7 +845,7 @@ theorem getElem_length_sub_one_eq_getLast {l : List α} (h : l.length - 1 < l.le
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
rw [ getLast_eq_getElem]
@[simp, grind] theorem getLast_cons_cons {a : α} {l : List α} :
@[simp, grind =] theorem getLast_cons_cons {a : α} {l : List α} :
getLast (a :: b :: l) (by simp) = getLast (b :: l) (by simp) :=
rfl
@@ -852,10 +858,10 @@ theorem getLast_cons {a : α} {l : List α} : ∀ (h : l ≠ nil),
theorem getLast_eq_getLastD {a l} (h) : @getLast α (a::l) h = getLastD l a := by
cases l <;> rfl
@[simp, grind] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
@[simp, grind =] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
cases l <;> rfl
@[simp, grind] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
@[simp, grind =] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
simp [getLast!, getLast_eq_getLastD]
@@ -888,7 +894,7 @@ theorem getLast?_eq_getLast : ∀ {l : List α} h, l.getLast? = some (l.getLast
| [], h => nomatch h rfl
| _ :: _, _ => rfl
@[grind] theorem getLast?_eq_getElem? : {l : List α}, l.getLast? = l[l.length - 1]?
@[grind =] theorem getLast?_eq_getElem? : {l : List α}, l.getLast? = l[l.length - 1]?
| [] => rfl
| a::l => by
rw [getLast?_eq_getLast (l := a :: l) nofun, getLast_eq_getElem, getElem?_eq_getElem]
@@ -901,14 +907,14 @@ theorem getLast_eq_iff_getLast?_eq_some {xs : List α} (h) :
-- `getLast?_eq_none_iff`, `getLast?_eq_some_iff`, `getLast?_isSome`, and `getLast_mem`
-- are proved later once more `reverse` theorems are available.
@[grind]
@[grind =]
theorem getLast?_cons {a : α} : (a::l).getLast? = some (l.getLast?.getD a) := by
cases l <;> simp [getLast?, getLast]
@[simp] theorem getLast?_cons_cons : (a :: b :: l).getLast? = (b :: l).getLast? := by
simp [getLast?_cons]
@[grind]
@[grind =]
theorem getLast?_concat {l : List α} {a : α} : (l ++ [a]).getLast? = some a := by
simp [getLast?_eq_getElem?, Nat.succ_sub_succ]
@@ -927,7 +933,7 @@ theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
theorem getLast!_of_getLast? [Inhabited α] : {l : List α}, getLast? l = some a getLast! l = a
| _ :: _, rfl => rfl
@[grind]
@[grind =]
theorem getLast!_eq_getElem! [Inhabited α] {l : List α} : l.getLast! = l[l.length - 1]! := by
cases l with
| nil => simp
@@ -955,7 +961,7 @@ theorem head?_eq_getElem? : ∀ {l : List α}, l.head? = l[0]?
theorem head_singleton {a : α} : head [a] (by simp) = a := by simp
@[grind]
@[grind =]
theorem head_eq_getElem {l : List α} (h : l []) : head l h = l[0]'(length_pos_iff.mpr h) := by
cases l with
| nil => simp at h
@@ -1017,18 +1023,18 @@ theorem head_of_mem_head? {l : List α} {x} (hx : x ∈ l.head?) :
/-! ### headD -/
/-- `simp` unfolds `headD` in terms of `head?` and `Option.getD`. -/
@[simp, grind] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
@[simp, grind =] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
cases l <;> simp [headD]
/-! ### tailD -/
/-- `simp` unfolds `tailD` in terms of `tail?` and `Option.getD`. -/
@[simp, grind] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
@[simp, grind =] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
cases l <;> rfl
/-! ### tail -/
@[simp, grind] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
@[simp, grind =] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
theorem tail_eq_tailD {l : List α} : l.tail = tailD l [] := by cases l <;> rfl
@@ -1040,13 +1046,13 @@ theorem mem_of_mem_tail {a : α} {l : List α} (h : a ∈ tail l) : a ∈ l := b
theorem ne_nil_of_tail_ne_nil {l : List α} : l.tail [] l [] := by
cases l <;> simp
@[simp, grind] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
@[simp, grind =] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
(tail l)[i] = l[i + 1]'(add_lt_of_lt_sub (by simpa using h)) := by
cases l with
| nil => simp at h
| cons _ l => simp
@[simp, grind] theorem getElem?_tail {l : List α} {i : Nat} :
@[simp, grind =] theorem getElem?_tail {l : List α} {i : Nat} :
(tail l)[i]? = l[i + 1]? := by
cases l <;> simp
@@ -1070,7 +1076,7 @@ theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.l
@[simp] theorem head?_tail {l : List α} : (tail l).head? = l[1]? := by
simp [head?_eq_getElem?]
@[simp, grind] theorem getLast_tail {l : List α} (h : l.tail []) :
@[simp, grind =] theorem getLast_tail {l : List α} (h : l.tail []) :
(tail l).getLast h = l.getLast (ne_nil_of_tail_ne_nil h) := by
simp only [getLast_eq_getElem, length_tail, getElem_tail]
congr
@@ -1096,7 +1102,7 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
/-! ### map -/
@[simp, grind] theorem length_map {as : List α} (f : α β) : (as.map f).length = as.length := by
@[simp, grind =] theorem length_map {as : List α} (f : α β) : (as.map f).length = as.length := by
induction as with
| nil => simp [List.map]
| cons _ as ih => simp [List.map, ih]
@@ -1104,13 +1110,13 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
@[simp] theorem isEmpty_map {l : List α} {f : α β} : (l.map f).isEmpty = l.isEmpty := by
cases l <;> simp
@[simp, grind] theorem getElem?_map {f : α β} : {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
@[simp, grind =] theorem getElem?_map {f : α β} : {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
| [], _ => rfl
| _ :: _, 0 => by simp
| _ :: l, i+1 => by simp [getElem?_map]
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
@[simp, grind] theorem getElem_map (f : α β) {l} {i : Nat} {h : i < (map f l).length} :
@[simp, grind =] theorem getElem_map (f : α β) {l} {i : Nat} {h : i < (map f l).length} :
(map f l)[i] = f (l[i]'(length_map f h)) :=
Option.some.inj <| by rw [ getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
@@ -1276,7 +1282,7 @@ theorem getLastD_map {f : α → β} {l : List α} {a : α} : (map f l).getLastD
@[simp] theorem filter_cons_of_neg {p : α Bool} {a : α} {l} (pa : ¬ p a) :
filter p (a :: l) = filter p l := by rw [filter, eq_false_of_ne_true pa]
@[grind] theorem filter_cons :
@[grind =] theorem filter_cons :
(x :: xs : List α).filter p = if p x then x :: (xs.filter p) else xs.filter p := by
split <;> simp [*]
@@ -1315,7 +1321,7 @@ theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length ↔ ∀
@[deprecated length_filter_eq_length_iff (since := "2025-04-04")]
abbrev filter_length_eq_length := @length_filter_eq_length_iff
@[simp, grind] theorem mem_filter : x filter p as x as p x := by
@[simp, grind =] theorem mem_filter : x filter p as x as p x := by
induction as with
| nil => simp
| cons a as ih =>
@@ -1330,10 +1336,12 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
( (i) (_ : i l.filter p), P i) (j) (_ : j l), p j P j := by
simp
@[grind] theorem getElem_filter {xs : List α} {p : α Bool} {i : Nat} (h : i < (xs.filter p).length) :
theorem getElem_filter {xs : List α} {p : α Bool} {i : Nat} (h : i < (xs.filter p).length) :
p (xs.filter p)[i] :=
(mem_filter.mp (getElem_mem h)).2
grind_pattern getElem_filter => (xs.filter p)[i]
theorem getElem?_filter {xs : List α} {p : α Bool} {i : Nat} (h : i < (xs.filter p).length)
(w : (xs.filter p)[i]? = some a) : p a := by
rw [getElem?_eq_getElem] at w
@@ -1377,7 +1385,7 @@ theorem map_filter_eq_foldr {f : α → β} {p : α → Bool} {as : List α} :
simp only [foldr]
cases hp : p head <;> simp [filter, *]
@[simp, grind] theorem filter_append {p : α Bool} :
@[simp, grind =] theorem filter_append {p : α Bool} :
(l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂
| [], _ => rfl
| a :: l₁, l₂ => by simp only [cons_append, filter]; split <;> simp [filter_append l₁]
@@ -1442,7 +1450,7 @@ theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
erw [filterMap_eq_map]
simp
@[simp, grind] theorem filterMap_some {l : List α} : filterMap some l = l := by
@[simp, grind =] theorem filterMap_some {l : List α} : filterMap some l = l := by
rw [filterMap_some_fun, id]
theorem map_filterMap_some_eq_filter_map_isSome {f : α Option β} {l : List α} :
@@ -1477,19 +1485,19 @@ theorem filterMap_eq_filter {p : α → Bool} :
| nil => rfl
| cons a l IH => by_cases pa : p a <;> simp [Option.guard, pa, IH]
@[grind]
@[grind =]
theorem filterMap_filterMap {f : α Option β} {g : β Option γ} {l : List α} :
filterMap g (filterMap f l) = filterMap (fun x => (f x).bind g) l := by
induction l with
| nil => rfl
| cons a l IH => cases h : f a <;> simp [filterMap_cons, *]
@[grind]
@[grind =]
theorem map_filterMap {f : α Option β} {g : β γ} {l : List α} :
map g (filterMap f l) = filterMap (fun x => (f x).map g) l := by
simp only [ filterMap_eq_map, filterMap_filterMap, Option.map_eq_bind]
@[simp, grind]
@[simp, grind =]
theorem filterMap_map {f : α β} {g : β Option γ} {l : List α} :
filterMap g (map f l) = filterMap (g f) l := by
rw [ filterMap_eq_map, filterMap_filterMap]; rfl
@@ -1504,7 +1512,7 @@ theorem filterMap_filter {p : α → Bool} {f : α → Option β} {l : List α}
rw [ filterMap_eq_filter, filterMap_filterMap]
congr; funext x; by_cases h : p x <;> simp [Option.guard, h]
@[simp, grind] theorem mem_filterMap {f : α Option β} {l : List α} {b : β} :
@[simp, grind =] theorem mem_filterMap {f : α Option β} {l : List α} {b : β} :
b filterMap f l a, a l f a = some b := by
induction l <;> simp [filterMap_cons]; split <;> simp [*, eq_comm]
@@ -1516,7 +1524,7 @@ theorem forall_mem_filterMap {f : α → Option β} {l : List α} {P : β → Pr
intro a
rw [forall_comm]
@[simp, grind] theorem filterMap_append {l l' : List α} {f : α Option β} :
@[simp, grind =] theorem filterMap_append {l l' : List α} {f : α Option β} :
filterMap f (l ++ l') = filterMap f l ++ filterMap f l' := by
induction l <;> simp [filterMap_cons]; split <;> simp [*]
@@ -1588,7 +1596,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
@[simp, grind] theorem mem_append {a : α} {s t : List α} : a s ++ t a s a t := by
@[simp, grind =] theorem mem_append {a : α} {s t : List α} : a s ++ t a s a t := by
induction s <;> simp_all [or_assoc]
theorem not_mem_append {a : α} {s t : List α} (h₁ : a s) (h₂ : a t) : a s ++ t :=
@@ -1611,7 +1619,7 @@ theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} :
( (x) (_ : x l₁ ++ l₂), p x) ( (x) (_ : x l₁), p x) ( (x) (_ : x l₂), p x) := by
simp only [mem_append, or_imp, forall_and]
@[grind] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
@[grind =] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
(l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - 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']
@@ -1630,7 +1638,7 @@ theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length
rw [cons_append]
simp [Nat.succ_sub_succ_eq_sub, getElem?_append_right (Nat.lt_succ.1 h₁)]
@[grind] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
@[grind =] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
(l₁ ++ l₂)[i]? = if i < l₁.length then l₁[i]? else l₂[i - l₁.length]? := by
split <;> rename_i h
· exact getElem?_append_left h
@@ -1709,7 +1717,6 @@ theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp
theorem nil_eq_append_iff : [] = a ++ b a = [] b = [] := by
simp
@[grind ]
theorem eq_nil_of_append_eq_nil {l₁ l₂ : List α} (h : l₁ ++ l₂ = []) : l₁ = [] l₂ = [] :=
append_eq_nil_iff.mp h
@@ -1739,12 +1746,12 @@ theorem append_eq_append_iff {ws xs ys zs : List α} :
| nil => simp_all
| cons a as ih => cases ys <;> simp [eq_comm, and_assoc, ih, and_or_left]
@[simp, grind] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
@[simp, grind =] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
head (l ++ l') w₁ = head l w₂ := by
match l, w₂ with
| a :: l, _ => rfl
@[grind] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ []) :
@[grind =] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ []) :
head (l₁ ++ l₂) w =
if h : l₁.isEmpty then
head l₂ (by simp_all [isEmpty_iff])
@@ -1765,28 +1772,28 @@ theorem head_append_right {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) (h : l
head (l₁ ++ l₂) w = head l₂ (by simp_all) := by
rw [head_append, dif_pos (by simp_all)]
@[simp, grind] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
@[simp, grind =] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
cases l <;> simp
-- Note:
-- `getLast_append_of_ne_nil`, `getLast_append` and `getLast?_append`
-- are stated and proved later in the `reverse` section.
@[grind] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
@[grind =] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
cases l <;> simp
theorem tail?_append_of_ne_nil {l l' : List α} (_ : l []) : (l ++ l').tail? = some (l.tail ++ l') :=
match l with
| _ :: _ => by simp
@[grind] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
@[grind =] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
cases l <;> simp
@[simp] theorem tail_append_of_ne_nil {xs ys : List α} (h : xs []) :
(xs ++ ys).tail = xs.tail ++ ys := by
simp_all [tail_append]
@[grind] theorem set_append {s t : List α} :
@[grind =] theorem set_append {s t : List α} :
(s ++ t).set i x = if i < s.length then s.set i x ++ t else s ++ t.set (i - s.length) x := by
induction s generalizing i with
| nil => simp
@@ -1844,7 +1851,7 @@ theorem append_eq_filter_iff {p : α → Bool} :
L₁ ++ L₂ = filter p l l₁ l₂, l = l₁ ++ l₂ filter p l₁ = L₁ filter p l₂ = L₂ := by
rw [eq_comm, filter_eq_append_iff]
@[simp, grind] theorem map_append {f : α β} : {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
@[simp, grind =] theorem map_append {f : α β} : {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
intro l₁; induction l₁ <;> intros <;> simp_all
theorem map_eq_append_iff {f : α β} :
@@ -1917,7 +1924,7 @@ theorem eq_nil_or_concat : ∀ l : List α, l = [] ∃ l' b, l = concat l' b
| cons =>
simp [flatten, length_append, *]
@[grind] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
@[grind =] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
@[simp] theorem mem_flatten : {L : List (List α)}, a L.flatten l, l L a l
| [] => by simp
@@ -2092,7 +2099,7 @@ theorem length_flatMap {l : List α} {f : α → List β} :
length (l.flatMap f) = sum (map (fun a => (f a).length) l) := by
rw [List.flatMap, length_flatten, map_map, Function.comp_def]
@[simp, grind] theorem mem_flatMap {f : α List β} {b} {l : List α} : b l.flatMap f a, a l b f a := by
@[simp, grind =] 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₂
@@ -2119,7 +2126,7 @@ theorem flatMap_singleton (f : α → List β) (x : α) : [x].flatMap f = f x :=
@[simp] theorem flatMap_singleton' (l : List α) : (l.flatMap fun x => [x]) = l := by
induction l <;> simp [*]
@[grind] theorem head?_flatMap {l : List α} {f : α List β} :
@[grind =] theorem head?_flatMap {l : List α} {f : α List β} :
(l.flatMap f).head? = l.findSome? fun a => (f a).head? := by
induction l with
| nil => rfl
@@ -2172,7 +2179,7 @@ theorem flatMap_eq_foldl {f : α → List β} {l : List α} :
theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
induction n <;> simp_all [replicate_succ, cons_append]
@[simp, grind] theorem mem_replicate {a b : α} : {n}, b replicate n a n 0 b = a
@[simp, grind =] theorem mem_replicate {a b : α} : {n}, b replicate n a n 0 b = a
| 0 => by simp
| n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
@@ -2197,11 +2204,11 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[simp] theorem replicate_eq_nil_iff {n : Nat} (a : α) : replicate n a = [] n = 0 := by
cases n <;> simp
@[simp, grind] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
@[simp, grind =] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
(replicate n a)[i] = a :=
eq_of_mem_replicate (getElem_mem _)
@[grind] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
@[grind =] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
by_cases h : i < n
· rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
· rw [getElem?_eq_none (by simpa using h), if_neg h]
@@ -2209,7 +2216,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
simp [h]
@[grind] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
@[grind =] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
cases n <;> simp [replicate_succ]
@[simp] theorem head_replicate (w : replicate n a []) : (replicate n a).head w = a := by
@@ -2298,7 +2305,7 @@ theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
simp only [getElem?_map, getElem?_replicate]
split <;> simp
@[grind] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
@[grind =] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
cases n with
| zero => simp
| succ n =>
@@ -2401,7 +2408,7 @@ termination_by l.length
/-! ### reverse -/
@[simp, grind] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
@[simp, grind =] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
induction as with
| nil => rfl
| cons a as ih => simp [ih]
@@ -2410,7 +2417,7 @@ theorem mem_reverseAux {x : α} : ∀ {as bs}, x ∈ reverseAux as bs ↔ x ∈
| [], _ => .inr, fun | .inr h => h
| a :: _, _ => by rw [reverseAux, mem_cons, or_assoc, or_left_comm, mem_reverseAux, mem_cons]
@[simp, grind] theorem mem_reverse {x : α} {as : List α} : x reverse as x as := by
@[simp, grind =] theorem mem_reverse {x : α} {as : List α} : x reverse as x as := by
simp [reverse, mem_reverseAux]
@[simp] theorem reverse_eq_nil_iff {xs : List α} : xs.reverse = [] xs = [] := by
@@ -2434,14 +2441,14 @@ theorem getElem?_reverse' : ∀ {l : List α} {i j}, i + j + 1 = length l →
rw [getElem?_append_left, getElem?_reverse' this]
rw [length_reverse, this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)
@[simp, grind]
@[simp, grind =]
theorem getElem?_reverse {l : List α} {i} (h : i < length l) :
l.reverse[i]? = l[l.length - 1 - i]? :=
getElem?_reverse' <| by
rw [Nat.add_sub_of_le (Nat.le_sub_one_of_lt h),
Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) h)]
@[simp, grind]
@[simp, grind =]
theorem getElem_reverse {l : List α} {i} (h : i < l.reverse.length) :
l.reverse[i] = l[l.length - 1 - i]'(Nat.sub_one_sub_lt_of_lt (by simpa using h)) := by
apply Option.some.inj
@@ -2454,7 +2461,7 @@ theorem reverseAux_reverseAux_nil {as bs : List α} : reverseAux (reverseAux as
| cons a as ih => simp [reverseAux, ih]
-- The argument `as : List α` is explicit to allow rewriting from right to left.
@[simp, grind] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
@[simp, grind =] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
simp only [reverse]; rw [reverseAux_reverseAux_nil]; rfl
theorem reverse_eq_iff {as bs : List α} : as.reverse = bs as = bs.reverse := by
@@ -2467,10 +2474,10 @@ theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse :
xs.reverse = a :: ys xs = ys.reverse ++ [a] := by
rw [reverse_eq_iff, reverse_cons]
@[simp, grind] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
@[simp, grind =] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
cases l <;> simp [getLast?_concat]
@[simp, grind] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
@[simp, grind =] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
rw [ getLast?_reverse, reverse_reverse]
theorem getLast?_eq_head?_reverse {xs : List α} : xs.getLast? = xs.reverse.head? := by
@@ -2534,16 +2541,16 @@ theorem flatten_reverse {L : List (List α)} :
L.reverse.flatten = (L.map reverse).flatten.reverse := by
induction L <;> simp_all
@[grind] theorem reverse_flatMap {β} {l : List α} {f : α List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse f) := by
@[grind =] theorem reverse_flatMap {β} {l : List α} {f : α List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse f) := by
induction l <;> simp_all
@[grind] theorem flatMap_reverse {β} {l : List α} {f : α List β} : (l.reverse.flatMap f) = (l.flatMap (reverse f)).reverse := by
@[grind =] theorem flatMap_reverse {β} {l : List α} {f : α List β} : (l.reverse.flatMap f) = (l.flatMap (reverse f)).reverse := by
induction l <;> simp_all
@[simp] theorem reverseAux_eq {as bs : List α} : reverseAux as bs = reverse as ++ bs :=
reverseAux_eq_append ..
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
eq_replicate_iff.2
by rw [length_reverse, length_replicate],
fun _ h => eq_of_mem_replicate (mem_reverse.1 h)
@@ -2555,7 +2562,7 @@ theorem flatten_reverse {L : List (List α)} :
(l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f := by
induction l generalizing b <;> simp [*]
@[simp, grind] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α β m β} {b : β} :
@[simp, grind =] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α β m β} {b : β} :
(a :: l).foldrM f b = l.foldrM f b >>= f a := by
simp only [foldrM]
induction l <;> simp_all
@@ -2599,37 +2606,37 @@ theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
/-! ### foldl and foldr -/
@[simp, grind] theorem foldr_cons_eq_append {l : List α} {f : α β} {l' : List β} :
@[simp] theorem foldr_cons_eq_append {l : List α} {f : α β} {l' : List β} :
l.foldr (fun x ys => f x :: ys) l' = l.map f ++ l' := by
induction l <;> simp [*]
/-- Variant of `foldr_cons_eq_append` specalized to `f = id`. -/
@[simp, grind] theorem foldr_cons_eq_append' {l l' : List β} :
@[simp, grind =] theorem foldr_cons_eq_append' {l l' : List β} :
l.foldr cons l' = l ++ l' := by
induction l <;> simp [*]
@[simp, grind] theorem foldl_flip_cons_eq_append {l : List α} {f : α β} {l' : List β} :
@[simp] theorem foldl_flip_cons_eq_append {l : List α} {f : α β} {l' : List β} :
l.foldl (fun xs y => f y :: xs) l' = (l.map f).reverse ++ l' := by
induction l generalizing l' <;> simp [*]
/-- Variant of `foldl_flip_cons_eq_append` specalized to `f = id`. -/
@[grind] theorem foldl_flip_cons_eq_append' {l l' : List α} :
theorem foldl_flip_cons_eq_append' {l l' : List α} :
l.foldl (fun xs y => y :: xs) l' = l.reverse ++ l' := by
simp
@[simp, grind] theorem foldr_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp] theorem foldr_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldr (f · ++ ·) l' = (l.map f).flatten ++ l' := by
induction l <;> simp [*]
@[simp, grind] theorem foldl_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp] theorem foldl_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldl (· ++ f ·) l' = l' ++ (l.map f).flatten := by
induction l generalizing l'<;> simp [*]
@[simp, grind] theorem foldr_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp] theorem foldr_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldr (fun x ys => ys ++ f x) l' = l' ++ (l.map f).reverse.flatten := by
induction l generalizing l' <;> simp [*]
@[simp, grind] theorem foldl_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp] theorem foldl_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldl (fun xs y => f y ++ xs) l' = (l.map f).reverse.flatten ++ l' := by
induction l generalizing l' <;> simp [*]
@@ -2683,19 +2690,19 @@ theorem foldr_map_hom {g : α → β} {f : ααα} {f' : β → β →
@[simp, grind _=_] theorem foldr_append {f : α β β} {b : β} {l l' : List α} :
(l ++ l').foldr f b = l.foldr f (l'.foldr f b) := by simp [foldr_eq_foldrM, -foldrM_pure]
@[grind] theorem foldl_flatten {f : β α β} {b : β} {L : List (List α)} :
@[grind =] theorem foldl_flatten {f : β α β} {b : β} {L : List (List α)} :
(flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b := by
induction L generalizing b <;> simp_all
@[grind] theorem foldr_flatten {f : α β β} {b : β} {L : List (List α)} :
@[grind =] theorem foldr_flatten {f : α β β} {b : β} {L : List (List α)} :
(flatten L).foldr f b = L.foldr (fun l b => l.foldr f b) b := by
induction L <;> simp_all
@[simp, grind] theorem foldl_reverse {l : List α} {f : β α β} {b : β} :
@[simp, grind =] theorem foldl_reverse {l : List α} {f : β α β} {b : β} :
l.reverse.foldl f b = l.foldr (fun x y => f y x) b := by
simp [foldl_eq_foldlM, foldr_eq_foldrM, -foldrM_pure]
@[simp, grind] theorem foldr_reverse {l : List α} {f : α β β} {b : β} :
@[simp, grind =] theorem foldr_reverse {l : List α} {f : α β β} {b : β} :
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
(foldl_reverse ..).symm.trans <| by simp
@@ -2849,7 +2856,7 @@ theorem foldr_rel {l : List α} {f : α → β → β} {g : αγγ} {a
/-! #### Further results about `getLast` and `getLast?` -/
@[simp, grind] theorem head_reverse {l : List α} (h : l.reverse []) :
@[simp, grind =] theorem head_reverse {l : List α} (h : l.reverse []) :
l.reverse.head h = getLast l (by simp_all) := by
induction l with
| nil => contradiction
@@ -2879,7 +2886,7 @@ theorem getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔
rw [getLast?_eq_head?_reverse, isSome_head?]
simp
@[simp, grind] theorem getLast_reverse {l : List α} (h : l.reverse []) :
@[simp, grind =] theorem getLast_reverse {l : List α} (h : l.reverse []) :
l.reverse.getLast h = l.head (by simp_all) := by
simp [getLast_eq_head_reverse]
@@ -2892,7 +2899,7 @@ theorem head_eq_getLast_reverse {l : List α} (h : l ≠ []) :
simp only [getLast_eq_head_reverse, reverse_append]
rw [head_append_of_ne_nil]
@[grind] theorem getLast_append {l : List α} (h : l ++ l' []) :
@[grind =] theorem getLast_append {l : List α} (h : l ++ l' []) :
(l ++ l').getLast h =
if h' : l'.isEmpty then
l.getLast (by simp_all [isEmpty_iff])
@@ -2913,7 +2920,7 @@ theorem getLast_append_left {l : List α} (w : l ++ l' ≠ []) (h : l' = []) :
(l ++ l').getLast w = l.getLast (by simp_all) := by
rw [getLast_append, dif_pos (by simp_all)]
@[simp, grind] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
@[simp, grind =] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
simp [ head?_reverse]
theorem getLast_filter_of_pos {p : α Bool} {l : List α} (w : l []) (h : p (getLast l w) = true) :
@@ -2949,7 +2956,7 @@ theorem getLast?_replicate {a : α} {n : Nat} : (replicate n a).getLast? = if n
/-! ### leftpad -/
-- We unfold `leftpad` and `rightpad` for verification purposes.
attribute [simp, grind] leftpad rightpad
attribute [simp, grind =] leftpad rightpad
-- `length_leftpad` and `length_rightpad` are in `Init.Data.List.Nat.Basic`.
@@ -2978,17 +2985,21 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
l.contains a a' l, a == a' := by
induction l <;> simp_all
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
grind_pattern contains_iff_exists_mem_beq => l.contains a
@[grind _=_]
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
l.contains a a l := by
simp
@[simp, grind]
@[simp, grind =]
theorem contains_map [BEq β] {l : List α} {x : β} {f : α β} :
(l.map f).contains x = l.any (fun a => x == f a) := by
induction l with simp_all
@[simp, grind]
@[simp, grind =]
theorem contains_filter [BEq α] {l : List α} {x : α} {p : α Bool} :
(l.filter p).contains x = l.any (fun a => x == a && p a) := by
induction l with
@@ -2997,7 +3008,7 @@ theorem contains_filter [BEq α] {l : List α} {x : α} {p : α → Bool} :
simp only [filter_cons, any_cons]
split <;> simp_all
@[simp, grind]
@[simp, grind =]
theorem contains_filterMap [BEq β] {l : List α} {x : β} {f : α Option β} :
(l.filterMap f).contains x = l.any (fun a => (f a).any fun b => x == b) := by
induction l with
@@ -3013,21 +3024,21 @@ theorem contains_append [BEq α] {l₁ l₂ : List α} {x : α} :
| nil => simp
| cons a l ih => simp [ih, Bool.or_assoc]
@[simp, grind]
@[simp, grind =]
theorem contains_flatten [BEq α] {l : List (List α)} {x : α} :
l.flatten.contains x = l.any fun l => l.contains x := by
induction l with
| nil => simp
| cons _ l ih => simp [ih]
@[simp, grind]
@[simp, grind =]
theorem contains_reverse [BEq α] {l : List α} {x : α} :
(l.reverse).contains x = l.contains x := by
induction l with
| nil => simp
| cons a l ih => simp [ih, Bool.or_comm]
@[simp, grind]
@[simp, grind =]
theorem contains_flatMap [BEq β] {l : List α} {f : α List β} {x : β} :
(l.flatMap f).contains x = l.any fun a => (f a).contains x := by
induction l with
@@ -3042,7 +3053,7 @@ Because we immediately simplify `partition` into two `filter`s for verification
we do not separately develop much theory about it.
-/
@[simp, grind] theorem partition_eq_filter_filter {p : α Bool} {l : List α} :
@[simp, grind =] theorem partition_eq_filter_filter {p : α Bool} {l : List α} :
partition p l = (filter p l, filter (not p) l) := by simp [partition, aux]
where
aux : l {as bs}, partition.loop p l (as, bs) =
@@ -3062,16 +3073,16 @@ grind_pattern mem_partition => a ∈ (partition p l).2
are often used for theorems about `Array.pop`.
-/
@[simp, grind] theorem length_dropLast : {xs : List α}, xs.dropLast.length = xs.length - 1
@[simp, grind =] theorem length_dropLast : {xs : List α}, xs.dropLast.length = xs.length - 1
| [] => rfl
| x::xs => by simp
@[simp, grind] theorem getElem_dropLast : {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
@[simp, grind =] 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
| _ :: _ :: _, _ + 1, h => getElem_dropLast (Nat.add_one_lt_add_one_iff.mp h)
@[grind] theorem getElem?_dropLast {xs : List α} {i : Nat} :
@[grind =] theorem getElem?_dropLast {xs : List α} {i : Nat} :
xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none := by
split
· rw [getElem?_eq_getElem, getElem?_eq_getElem, getElem_dropLast]
@@ -3269,24 +3280,24 @@ theorem all_eq_not_any_not {l : List α} {p : α → Bool} : l.all p = !l.any (!
| nil => rfl
| cons h t ih => simp_all [Bool.and_assoc]
@[simp, grind] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
@[simp, grind =] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
induction l <;> simp_all
@[simp, grind] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
@[simp, grind =] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
induction l <;> simp_all
@[simp, grind] theorem any_flatMap {l : List α} {f : α List β} :
@[simp, grind =] theorem any_flatMap {l : List α} {f : α List β} :
(l.flatMap f).any p = l.any fun a => (f a).any p := by
induction l <;> simp_all
@[simp, grind] theorem all_flatMap {l : List α} {f : α List β} :
@[simp, grind =] theorem all_flatMap {l : List α} {f : α List β} :
(l.flatMap f).all p = l.all fun a => (f a).all p := by
induction l <;> simp_all
@[simp, grind] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
@[simp, grind =] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
induction l <;> simp_all [Bool.or_comm]
@[simp, grind] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
@[simp, grind =] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
induction l <;> simp_all [Bool.and_comm]
@[simp] theorem any_replicate {n : Nat} {a : α} :
@@ -3336,14 +3347,14 @@ variable [BEq α]
simp only [replace_cons]
split <;> simp_all
@[simp, grind] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
@[simp, grind =] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
induction l with
| nil => simp
| cons x l ih =>
simp only [replace_cons]
split <;> simp_all
@[grind] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
@[grind =] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
(l.replace a b)[i]? = if l[i]? == some a then if a l.take i then some a else some b else l[i]? := by
induction l generalizing i with
| nil => cases i <;> simp
@@ -3356,7 +3367,7 @@ theorem getElem?_replace_of_ne [LawfulBEq α] {l : List α} {i : Nat} (h : l[i]?
(l.replace a b)[i]? = l[i]? := by
simp_all [getElem?_replace]
@[grind] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
@[grind =] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
(l.replace a b)[i]'(by simpa) = if l[i] == a then if a l.take i then a else b else l[i] := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_replace]
@@ -3386,7 +3397,7 @@ theorem head_replace {l : List α} {a b : α} (w) :
apply Option.some.inj
rw [ head?_eq_head, head?_replace, head?_eq_head]
@[grind] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
@[grind =] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
(l₁ ++ l₂).replace a b = if a l₁ then l₁.replace a b ++ l₂ else l₁ ++ l₂.replace a b := by
induction l₁ with
| nil => simp
@@ -3430,9 +3441,9 @@ end replace
section insert
variable [BEq α]
@[simp, grind] theorem insert_nil (a : α) : [].insert a = [a] := rfl
@[simp, grind =] theorem insert_nil (a : α) : [].insert a = [a] := rfl
@[simp, grind] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
@[simp, grind =] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
(l.insert a).contains x = (x == a || l.contains x) := by
simp only [List.insert]
split <;> rename_i h
@@ -3449,7 +3460,7 @@ variable [LawfulBEq α]
@[simp] theorem insert_of_not_mem {l : List α} (h : a l) : l.insert a = a :: l := by
simp [List.insert, h]
@[simp, grind] theorem mem_insert_iff {l : List α} : a l.insert b a = b a l := by
@[simp, grind =] theorem mem_insert_iff {l : List α} : a l.insert b a = b a l := by
if h : b l then
rw [insert_of_mem h]
constructor; {apply Or.inr}
@@ -3473,7 +3484,7 @@ theorem eq_or_mem_of_mem_insert {l : List α} (h : a ∈ l.insert b) : a = b
@[simp] theorem length_insert_of_not_mem {l : List α} (h : a l) :
length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl
@[grind] theorem length_insert {l : List α} :
@[grind =] theorem length_insert {l : List α} :
(l.insert a).length = l.length + if a l then 0 else 1 := by
split <;> simp_all
@@ -3508,13 +3519,13 @@ theorem getElem?_insert_succ {l : List α} {a : α} {i : Nat} :
simp only [insert_eq]
split <;> simp
@[grind] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
@[grind =] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
(l.insert a)[i]? = if a l then l[i]? else if i = 0 then some a else l[i-1]? := by
cases i
· simp [getElem?_insert_zero]
· simp [getElem?_insert_succ]
@[grind] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
@[grind =] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
(l.insert a)[i]'(Nat.lt_of_lt_of_le h length_le_length_insert) =
if a l then l[i] else if i = 0 then a else l[i-1]'(Nat.lt_of_le_of_lt (Nat.pred_le _) h) := by
apply Option.some.inj
@@ -3538,7 +3549,7 @@ theorem head_insert {l : List α} {a : α} (w) :
apply Option.some.inj
rw [ head?_eq_head, head?_insert]
@[grind] theorem insert_append {l₁ l₂ : List α} {a : α} :
@[grind =] theorem insert_append {l₁ l₂ : List α} {a : α} :
(l₁ ++ l₂).insert a = if a l₂ then l₁ ++ l₂ else l₁.insert a ++ l₂ := by
simp only [insert_eq, mem_append]
(repeat split) <;> simp_all
@@ -3551,7 +3562,7 @@ theorem insert_append_of_not_mem_left {l₁ l₂ : List α} (h : ¬ a ∈ l₂)
(l₁ ++ l₂).insert a = l₁.insert a ++ l₂ := by
simp [insert_append, h]
@[simp, grind] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
@[simp, grind =] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
cases n <;> simp_all
@[simp] theorem insert_replicate_ne {a b : α} (h : !b == a) :

View File

@@ -248,11 +248,10 @@ theorem pairwise_le_range {n : Nat} : Pairwise (· ≤ ·) (range n) :=
theorem nodup_range {n : Nat} : Nodup (range n) := by
simp +decide only [range_eq_range', nodup_range']
@[simp, grind] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
(range n).find? p = some i p i i range n j, j < i !p j := by
simp [range_eq_range']
@[grind]
theorem find?_range_eq_none {n : Nat} {p : Nat Bool} :
(range n).find? p = none i, i < n !p i := by
simp

View File

@@ -43,7 +43,7 @@ theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l →
(pairwise_cons.1 p).2
set_option linter.unusedVariables false in
@[grind] theorem Pairwise.tail : {l : List α} (h : Pairwise R l), Pairwise R l.tail
@[grind ] theorem Pairwise.tail : {l : List α} (h : Pairwise R l), Pairwise R l.tail
| [], h => h
| _ :: _, h => h.of_cons
@@ -103,7 +103,7 @@ theorem Pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : Pa
· exact h₃.1 _ hx
· exact ih (fun x hx => h₁ _ <| mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy
@[grind] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
@[grind ] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
@[grind =] theorem pairwise_pair {a b : α} : Pairwise R [a, b] R a b := by simp
@@ -117,7 +117,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
(p : Pairwise S (map f l)) : Pairwise R l :=
(pairwise_map.1 p).imp (H _ _)
@[grind] theorem Pairwise.map {S : β β Prop} (f : α β) (H : a b : α, R a b S (f a) (f b))
@[grind <=] theorem Pairwise.map {S : β β Prop} (f : α β) (H : a b : α, R a b S (f a) (f b))
(p : Pairwise R l) : Pairwise S (map f l) :=
pairwise_map.2 <| p.imp (H _ _)
@@ -136,7 +136,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
simpa [IH, e] using fun _ =>
fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab
@[grind] theorem Pairwise.filterMap {S : β β Prop} (f : α Option β)
@[grind <=] theorem Pairwise.filterMap {S : β β Prop} (f : α Option β)
(H : a a' : α, R a a' b, f a = some b b', f a' = some b' S b b') {l : List α} (p : Pairwise R l) :
Pairwise S (filterMap f l) :=
pairwise_filterMap.2 <| p.imp (H _ _)
@@ -146,7 +146,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
rw [ filterMap_eq_filter, pairwise_filterMap]
simp
@[grind] theorem Pairwise.filter (p : α Bool) : Pairwise R l Pairwise R (filter p l) :=
@[grind ] theorem Pairwise.filter (p : α Bool) : Pairwise R l Pairwise R (filter p l) :=
Pairwise.sublist filter_sublist
@[grind =] theorem pairwise_append {l₁ l₂ : List α} :
@@ -207,10 +207,10 @@ theorem pairwise_append_comm {R : αα → Prop} (s : ∀ {x y}, R x y →
simp
· exact fun _ => h, Or.inr h
@[grind] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
@[grind ] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
h.sublist (drop_sublist _ _)
@[grind] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
@[grind ] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
h.sublist (take_sublist _ _)
-- This theorem is not annotated with `grind` because it leads to a loop of instantiations with `Pairwise.sublist`.
@@ -266,7 +266,7 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : αα → Prop} (h :
rintro H _ b hb rfl
exact H b hb _ _
@[grind] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α Prop} {f : a, p a β}
@[grind <=] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α Prop} {f : a, p a β}
(h : x l, p x) {S : β β Prop}
(hS : x (hx : p x) y (hy : p y), R x y S (f x hx) (f y hy)) :
Pairwise S (l.pmap f h) := by
@@ -277,10 +277,12 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : αα → Prop} (h :
@[grind =] theorem nodup_iff_pairwise_ne : List.Nodup l List.Pairwise (· ·) l := Iff.rfl
@[simp, grind]
@[simp]
theorem nodup_nil : @Nodup α [] :=
Pairwise.nil
grind_pattern nodup_nil => @Nodup α []
@[simp, grind =]
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) a l Nodup l := by
simp only [Nodup, pairwise_cons, forall_mem_ne]

View File

@@ -202,12 +202,18 @@ theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l
protected theorem Sublist.mem (hx : a l₁) (hl : l₁ <+ l₂) : a l₂ :=
hl.subset hx
@[grind] theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h xs :=
theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h xs :=
s.mem (List.head_mem h)
@[grind] theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h xs :=
grind_pattern Sublist.head_mem => ys <+ xs, ys.head h
grind_pattern Sublist.head_mem => ys.head h xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h xs :=
s.mem (List.getLast_mem h)
grind_pattern Sublist.getLast_mem => ys <+ xs, ys.getLast h
grind_pattern Sublist.getLast_mem => ys.getLast h xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
instance : Trans (@Sublist α) Subset Subset :=
fun h₁ h₂ => trans h₁.subset h₂
@@ -248,12 +254,13 @@ theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l
theorem Sublist.length_eq (s : l₁ <+ l₂) : length l₁ = length l₂ l₁ = l₂ :=
s.eq_of_length, congrArg _
@[grind]
theorem tail_sublist : l : List α, tail l <+ l
| [] => .slnil
| a::l => sublist_cons_self a l
@[grind]
grind_pattern tail_sublist => tail l <+ _
@[grind ]
protected theorem Sublist.tail : {l₁ l₂ : List α}, l₁ <+ l₂ tail l₁ <+ tail l₂
| _, _, slnil => .slnil
| _, _, Sublist.cons _ h => (tail_sublist _).trans h
@@ -263,7 +270,7 @@ protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tai
theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ :=
h.tail
@[grind]
@[grind ]
protected theorem Sublist.map (f : α β) {l₁ l₂} (s : l₁ <+ l₂) : map f l₁ <+ map f l₂ := by
induction s with
| slnil => simp
@@ -275,7 +282,7 @@ protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : m
grind_pattern Sublist.map => l₁ <+ l₂, map f l₁
grind_pattern Sublist.map => l₁ <+ l₂, map f l₂
@[grind]
@[grind ]
protected theorem Sublist.filterMap (f : α Option β) (s : l₁ <+ l₂) :
filterMap f l₁ <+ filterMap f l₂ := by
induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons]
@@ -283,7 +290,7 @@ protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₁
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₂
@[grind]
@[grind ]
protected theorem Sublist.filter (p : α Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by
rw [ filterMap_eq_filter]; apply s.filterMap
@@ -481,7 +488,7 @@ theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h :
exact fun x m => w x (mem_append_left l₂' m) (h₁.mem m)
simp_all
@[grind]
@[grind ]
theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l₁ ++ a :: l₂ := by
rw [sublist_append_iff] at h
obtain l₁', l₂', rfl, h₁, h₂ := h
@@ -624,22 +631,28 @@ theorem flatten_sublist_iff {L : List (List α)} {l} :
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist
@[grind]
@[grind ]
protected theorem Sublist.drop : {l₁ l₂ : List α}, l₁ <+ l₂ i, l₁.drop i <+ l₂.drop i
| _, _, h, 0 => h
| _, _, h, i + 1 => by rw [ drop_tail, drop_tail]; exact h.tail.drop i
/-! ### IsPrefix / IsSuffix / IsInfix -/
@[simp, grind] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := l₂, rfl
@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := l₂, rfl
@[simp, grind] theorem suffix_append (l₁ l₂ : List α) : l <:+ l₁ ++ l₂ := l₁, rfl
grind_pattern prefix_append => l <+: l₁ ++ l₂
@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := l₁, rfl
grind_pattern suffix_append => l₂ <:+ l₁ ++ l₂
theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := l₁, l₃, rfl
@[simp, grind] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
rw [ List.append_assoc]; apply infix_append
grind_pattern infix_append' => l₂ <:+: l₁ ++ (l₂ ++ l₃)
theorem infix_append_left : l₁ <:+: l₁ ++ l₂ := [], l₂, rfl
theorem infix_append_right : l₂ <:+: l₁ ++ l₂ := l₁, [], by simp
@@ -666,7 +679,9 @@ theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
@[simp, grind] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
@[simp, grind] theorem suffix_cons (a : α) : l, l <:+ a :: l := suffix_append [a]
@[simp] theorem suffix_cons (a : α) : l, l <:+ a :: l := suffix_append [a]
grind_pattern suffix_cons => _ <:+ a :: l
theorem infix_cons : l₁ <:+: l₂ l₁ <:+: a :: l₂ := fun l₁', l₂', h => a :: l₁', l₂', h rfl
@@ -1108,24 +1123,36 @@ theorem infix_of_mem_flatten : ∀ {L : List (List α)}, l ∈ L → l <:+: flat
theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ l₁ <+: l₂ :=
prefix_append_right_inj [a]
@[grind] theorem take_prefix (i) (l : List α) : take i l <+: l :=
theorem take_prefix (i) (l : List α) : take i l <+: l :=
_, take_append_drop _ _
@[grind] theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
grind_pattern take_prefix => take i l <+: _
theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
_, take_append_drop _ _
@[grind] theorem take_sublist (i) (l : List α) : take i l <+ l :=
grind_pattern drop_suffix => drop i l <+: _
theorem take_sublist (i) (l : List α) : take i l <+ l :=
(take_prefix i l).sublist
@[grind] theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
grind_pattern take_sublist => take i l <+ l
theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
(drop_suffix i l).sublist
grind_pattern drop_sublist => drop i l <+ l
theorem take_subset (i) (l : List α) : take i l l :=
(take_sublist i l).subset
grind_pattern take_subset => take i l l
theorem drop_subset (i) (l : List α) : drop i l l :=
(drop_sublist i l).subset
grind_pattern drop_subset => drop i l l
theorem mem_of_mem_take {l : List α} (h : a l.take i) : a l :=
take_subset _ _ h
@@ -1138,64 +1165,84 @@ theorem drop_suffix_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l
-- See `Init.Data.List.Nat.TakeDrop` for `take_prefix_take_left`.
@[grind] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l <+ drop i l :=
@[grind ] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l <+ drop i l :=
(drop_suffix_drop_left l h).sublist
@[grind] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l drop i l :=
@[grind ] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l drop i l :=
(drop_sublist_drop_left l h).subset
@[grind] theorem takeWhile_prefix (p : α Bool) : l.takeWhile p <+: l :=
theorem takeWhile_prefix (p : α Bool) : l.takeWhile p <+: l :=
l.dropWhile p, takeWhile_append_dropWhile
@[grind] theorem dropWhile_suffix (p : α Bool) : l.dropWhile p <:+ l :=
grind_pattern takeWhile_prefix => l.takeWhile p <+: _
theorem dropWhile_suffix (p : α Bool) : l.dropWhile p <:+ l :=
l.takeWhile p, takeWhile_append_dropWhile
@[grind] theorem takeWhile_sublist (p : α Bool) : l.takeWhile p <+ l :=
grind_pattern dropWhile_suffix => l.dropWhile p <+: _
theorem takeWhile_sublist (p : α Bool) : l.takeWhile p <+ l :=
(takeWhile_prefix p).sublist
@[grind] theorem dropWhile_sublist (p : α Bool) : l.dropWhile p <+ l :=
grind_pattern takeWhile_sublist => l.takeWhile p <+ _
theorem dropWhile_sublist (p : α Bool) : l.dropWhile p <+ l :=
(dropWhile_suffix p).sublist
grind_pattern dropWhile_sublist => l.dropWhile p <+ _
theorem takeWhile_subset {l : List α} (p : α Bool) : l.takeWhile p l :=
(takeWhile_sublist p).subset
grind_pattern takeWhile_subset => l.takeWhile p _
theorem dropWhile_subset {l : List α} (p : α Bool) : l.dropWhile p l :=
(dropWhile_sublist p).subset
@[grind] theorem dropLast_prefix : l : List α, l.dropLast <+: l
grind_pattern dropWhile_subset => l.dropWhile p _
theorem dropLast_prefix : l : List α, l.dropLast <+: l
| [] => nil, by rw [dropLast, List.append_nil]
| a :: l => _, dropLast_concat_getLast (cons_ne_nil a l)
@[grind] theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
grind_pattern dropLast_prefix => l.dropLast <+: _
theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
(dropLast_prefix l).sublist
grind_pattern dropLast_sublist => l.dropLast <+ _
theorem dropLast_subset (l : List α) : l.dropLast l :=
(dropLast_sublist l).subset
@[grind] theorem tail_suffix (l : List α) : tail l <:+ l := by rw [ drop_one]; apply drop_suffix
grind_pattern dropLast_subset => l.dropLast _
@[grind] theorem IsPrefix.map {β} (f : α β) l₁ l₂ : List α (h : l <+: l) : l₁.map f <+: l₂.map f := by
theorem tail_suffix (l : List α) : tail l <:+ l := by rw [ drop_one]; apply drop_suffix
grind_pattern tail_suffix => tail l <+: _
@[grind ] theorem IsPrefix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
obtain r, rfl := h
rw [map_append]; apply prefix_append
grind_pattern IsPrefix.map => l₁ <+: l₂, l₁.map f
grind_pattern IsPrefix.map => l₁ <+: l₂, l₂.map f
@[grind] theorem IsSuffix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
@[grind ] theorem IsSuffix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
obtain r, rfl := h
rw [map_append]; apply suffix_append
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₁.map f
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₂.map f
@[grind] theorem IsInfix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
@[grind ] theorem IsInfix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
obtain r₁, r₂, rfl := h
rw [map_append, map_append]; apply infix_append
grind_pattern IsInfix.map => l₁ <:+: l₂, l₁.map f
grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
@[grind] theorem IsPrefix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <+: l₂) :
@[grind ] theorem IsPrefix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <+: l₂) :
l₁.filter p <+: l₂.filter p := by
obtain xs, rfl := h
rw [filter_append]; apply prefix_append
@@ -1203,7 +1250,7 @@ grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₁.filter p
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
@[grind] theorem IsSuffix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+ l₂) :
@[grind ] theorem IsSuffix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+ l₂) :
l₁.filter p <:+ l₂.filter p := by
obtain xs, rfl := h
rw [filter_append]; apply suffix_append
@@ -1211,7 +1258,7 @@ grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₁.filter p
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
@[grind] theorem IsInfix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+: l₂) :
@[grind ] theorem IsInfix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+: l₂) :
l₁.filter p <:+: l₂.filter p := by
obtain xs, ys, rfl := h
rw [filter_append, filter_append]; apply infix_append _
@@ -1219,7 +1266,7 @@ grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₁.filter p
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
@[grind] theorem IsPrefix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <+: l₂) :
@[grind ] theorem IsPrefix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <+: l₂) :
filterMap f l₁ <+: filterMap f l₂ := by
obtain xs, rfl := h
rw [filterMap_append]; apply prefix_append
@@ -1227,7 +1274,7 @@ grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₁
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
@[grind] theorem IsSuffix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+ l₂) :
@[grind ] theorem IsSuffix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+ l₂) :
filterMap f l₁ <:+ filterMap f l₂ := by
obtain xs, rfl := h
rw [filterMap_append]; apply suffix_append
@@ -1235,7 +1282,7 @@ grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₁
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₂
@[grind] theorem IsInfix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+: l₂) :
@[grind ] theorem IsInfix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+: l₂) :
filterMap f l₁ <:+: filterMap f l₂ := by
obtain xs, ys, rfl := h
rw [filterMap_append, filterMap_append]; apply infix_append

View File

@@ -12,7 +12,6 @@ public import Init.Data.List.Impl
public import Init.Data.List.Nat.Erase
public import Init.Data.List.Monadic
public import Init.Data.List.Nat.InsertIdx
public import Init.Data.Array.Lex.Basic
public import Init.Data.Array.Basic
import all Init.Data.Array.Basic
public import Init.Data.Array.Set

View File

@@ -257,8 +257,6 @@ attribute [simp] Nat.le_refl
theorem succ_lt_succ {n m : Nat} : n < m succ n < succ m := succ_le_succ
theorem lt_succ_of_le {n m : Nat} : n m n < succ m := succ_le_succ
theorem le_of_lt_add_one {n m : Nat} : n < m + 1 n m := le_of_succ_le_succ
theorem lt_add_one_of_le {n m : Nat} : n m n < m + 1 := succ_le_succ
@@ -271,37 +269,15 @@ theorem not_add_one_le_self : (n : Nat) → ¬ n + 1 ≤ n := Nat.not_succ_le_se
theorem add_one_pos (n : Nat) : 0 < n + 1 := Nat.zero_lt_succ n
theorem succ_sub_succ_eq_sub (n m : Nat) : succ n - succ m = n - m := by
induction m with
| zero => exact rfl
| succ m ih => apply congrArg pred ih
theorem pred_le : (n : Nat), pred n n
| zero => Nat.le.refl
| succ _ => le_succ _
theorem pred_lt : {n : Nat}, n 0 pred n < n
| zero, h => absurd rfl h
| succ _, _ => lt_succ_of_le (Nat.le_refl _)
theorem sub_one_lt : {n : Nat}, n 0 n - 1 < n := pred_lt
@[simp] theorem sub_le (n m : Nat) : n - m n := by
induction m with
| zero => exact Nat.le_refl (n - 0)
| succ m ih => apply Nat.le_trans (pred_le (n - m)) ih
theorem sub_lt_of_lt {a b c : Nat} (h : a < c) : a - b < c :=
Nat.lt_of_le_of_lt (Nat.sub_le _ _) h
theorem sub_lt : {n m : Nat}, 0 < n 0 < m n - m < n
| 0, _, h1, _ => absurd h1 (Nat.lt_irrefl 0)
| _+1, 0, _, h2 => absurd h2 (Nat.lt_irrefl 0)
| n+1, m+1, _, _ =>
Eq.symm (succ_sub_succ_eq_sub n m)
show n - m < succ n from
lt_succ_of_le (sub_le n m)
theorem sub_succ (n m : Nat) : n - succ m = pred (n - m) := rfl
theorem succ_sub_succ (n m : Nat) : succ n - succ m = n - m :=
@@ -316,9 +292,6 @@ theorem sub_add_eq (a b c : Nat) : a - (b + c) = a - b - c := by
| zero => simp
| succ c ih => simp only [Nat.add_succ, Nat.sub_succ, ih]
protected theorem lt_of_lt_of_le {n m k : Nat} : n < m m k n < k :=
Nat.le_trans
protected theorem lt_of_lt_of_eq {n m k : Nat} : n < m m = k n < k :=
fun h₁ h₂ => h₂ h₁
@@ -356,12 +329,10 @@ protected theorem pos_of_ne_zero {n : Nat} : n ≠ 0 → 0 < n := (eq_zero_or_po
theorem pos_of_neZero (n : Nat) [NeZero n] : 0 < n := Nat.pos_of_ne_zero (NeZero.ne _)
attribute [simp] Nat.lt_add_one
theorem lt.base (n : Nat) : n < succ n := Nat.le_refl (succ n)
theorem lt_succ_self (n : Nat) : n < succ n := lt.base n
@[simp] protected theorem lt_add_one (n : Nat) : n < n + 1 := lt.base n
protected theorem le_total (m n : Nat) : m n n m :=
match Nat.lt_or_ge m n with
| Or.inl h => Or.inl (Nat.le_of_lt h)
@@ -457,7 +428,6 @@ protected theorem le_lt_asymm : ∀{a b : Nat}, a ≤ b → ¬(b < a) := flip Na
theorem gt_of_not_le {n m : Nat} (h : ¬ n m) : n > m := (Nat.lt_or_ge m n).resolve_right h
protected theorem lt_of_not_ge : {a b : Nat}, ¬(b a) b < a := Nat.gt_of_not_le
protected theorem lt_of_not_le : {a b : Nat}, ¬(a b) b < a := Nat.gt_of_not_le
theorem ge_of_not_lt {n m : Nat} (h : ¬ n < m) : n m := (Nat.lt_or_ge n m).resolve_left h
protected theorem le_of_not_gt : {a b : Nat}, ¬(b > a) b a := Nat.ge_of_not_lt
@@ -770,10 +740,6 @@ protected theorem mul_lt_mul_of_pos_left {n m k : Nat} (h : n < m) (hk : k > 0)
protected theorem mul_lt_mul_of_pos_right {n m k : Nat} (h : n < m) (hk : k > 0) : n * k < m * k :=
Nat.mul_comm k m Nat.mul_comm k n Nat.mul_lt_mul_of_pos_left h hk
protected theorem mul_pos {n m : Nat} (ha : n > 0) (hb : m > 0) : n * m > 0 :=
have h : 0 * m < n * m := Nat.mul_lt_mul_of_pos_right ha hb
Nat.zero_mul m h
protected theorem le_of_mul_le_mul_left {a b c : Nat} (h : c * a c * b) (hc : 0 < c) : a b :=
Nat.ge_of_not_lt fun hlt : b < a =>
have h' : c * b < c * a := Nat.mul_lt_mul_of_pos_left hlt hc
@@ -833,11 +799,6 @@ set_option linter.missingDocs false in
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
protected theorem pow_pos (h : 0 < a) : 0 < a^n :=
match n with
| 0 => Nat.zero_lt_one
| _ + 1 => Nat.mul_pos (Nat.pow_pos h) h
set_option linter.missingDocs false in
@[deprecated Nat.pow_pos (since := "2025-02-17")]
abbrev pos_pow_of_pos := @Nat.pow_pos
@@ -1199,6 +1160,8 @@ protected theorem sub_eq_iff_eq_add {c : Nat} (h : b ≤ a) : a - b = c ↔ a =
protected theorem sub_eq_iff_eq_add' {c : Nat} (h : b a) : a - b = c a = b + c := by
rw [Nat.add_comm, Nat.sub_eq_iff_eq_add h]
attribute [simp] sub_le
protected theorem sub_one_sub_lt_of_lt (h : a < b) : b - 1 - a < b := by
rw [ Nat.sub_add_eq]
exact sub_lt (zero_lt_of_lt h) (Nat.lt_add_right a Nat.one_pos)

View File

@@ -24,47 +24,6 @@ there is some `c` such that `b = a * c`.
instance : Dvd Nat where
dvd a b := Exists (fun c => b = a * c)
theorem div_rec_lemma {x y : Nat} : 0 < y y x x - y < x :=
fun ypos, ylex => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
theorem div_rec_fuel_lemma {x y fuel : Nat} (hy : 0 < y) (hle : y x) (hfuel : x < fuel + 1) :
x - y < fuel :=
Nat.lt_of_lt_of_le (div_rec_lemma hy, hle) (Nat.le_of_lt_succ hfuel)
/--
Division of natural numbers, discarding the remainder. Division by `0` returns `0`. Usually accessed
via the `/` operator.
This operation is sometimes called “floor division.”
This function is overridden at runtime with an efficient implementation. This definition is
the logical model.
Examples:
* `21 / 3 = 7`
* `21 / 5 = 4`
* `0 / 22 = 0`
* `5 / 0 = 0`
-/
@[extern "lean_nat_div", irreducible]
protected def div (x y : @& Nat) : Nat :=
if hy : 0 < y then
let rec
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
match fuel with
| 0 => by contradiction
| succ fuel =>
if h : y x then
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel) + 1
else
0
termination_by structural fuel
go (x + 1) x (Nat.lt_succ_self _)
else
0
instance instDiv : Div Nat := Nat.div
private theorem div.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
Nat.div.go y hy fuel1 x h1 = Nat.div.go y hy fuel2 x h2 := by
match fuel1, fuel2 with
@@ -154,36 +113,6 @@ protected def divExact (x y : @& Nat) (h : y x) : Nat :=
@[simp]
theorem divExact_eq_div {x y : Nat} (h : y x) : x.divExact y h = x / y := rfl
/--
The modulo operator, which computes the remainder when dividing one natural number by another.
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
than an error.
This is the core implementation of `Nat.mod`. It computes the correct result for any two closed
natural numbers, but it does not have some convenient [definitional
reductions](lean-manual://section/type-system) when the `Nat`s contain free variables. The wrapper
`Nat.mod` handles those cases specially and then calls `Nat.modCore`.
This function is overridden at runtime with an efficient implementation. This definition is the
logical model.
-/
@[extern "lean_nat_mod", irreducible]
protected noncomputable def modCore (x y : Nat) : Nat :=
if hy : 0 < y then
let rec
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
match fuel with
| 0 => by contradiction
| succ fuel =>
if h : y x then
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel)
else
x
termination_by structural fuel
go (x + 1) x (Nat.lt_succ_self _)
else
x
private theorem modCore.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
Nat.modCore.go y hy fuel1 x h1 = Nat.modCore.go y hy fuel2 x h2 := by
match fuel1, fuel2 with
@@ -214,51 +143,6 @@ protected theorem modCore_eq (x y : Nat) : Nat.modCore x y =
next =>
simp only [false_and, reduceIte, *]
/--
The modulo operator, which computes the remainder when dividing one natural number by another.
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
than an error.
`Nat.mod` is a wrapper around `Nat.modCore` that special-cases two situations, giving better
definitional reductions:
* `Nat.mod 0 m` should reduce to `m`, for all terms `m : Nat`.
* `Nat.mod n (m + n + 1)` should reduce to `n` for concrete `Nat` literals `n`.
These reductions help `Fin n` literals work well, because the `OfNat` instance for `Fin` uses
`Nat.mod`. In particular, `(0 : Fin (n + 1)).val` should reduce definitionally to `0`. `Nat.modCore`
can handle all numbers, but its definitional reductions are not as convenient.
This function is overridden at runtime with an efficient implementation. This definition is the
logical model.
Examples:
* `7 % 2 = 1`
* `9 % 3 = 0`
* `5 % 7 = 5`
* `5 % 0 = 5`
* `show ∀ (n : Nat), 0 % n = 0 from fun _ => rfl`
* `show ∀ (m : Nat), 5 % (m + 6) = 5 from fun _ => rfl`
-/
@[extern "lean_nat_mod"]
protected def mod : @& Nat @& Nat Nat
/-
Nat.modCore is defined with fuel and thus does not reduce with open terms very well.
Nevertheless it is desirable for trivial `Nat.mod` calculations, namely
* `Nat.mod 0 m` for all `m`
* `Nat.mod n (m + n + 1)` for concrete literals `n`,
to reduce definitionally.
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
definition.
-/
| 0, _ => 0
| n@(_ + 1), m =>
if m n -- NB: if n < m does not reduce as well as `m ≤ n`!
then Nat.modCore n m
else n
instance instMod : Mod Nat := Nat.mod
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
change Nat.modCore n m = Nat.mod n m
match n, m with
@@ -315,24 +199,6 @@ theorem mod_eq_sub_mod {a b : Nat} (h : a ≥ b) : a % b = (a - b) % b :=
| Or.inl h₁ => h₁.symm (Nat.sub_zero a).symm rfl
| Or.inr h₁ => (mod_eq a b).symm if_pos h₁, h
theorem mod_lt (x : Nat) {y : Nat} : y > 0 x % y < y := by
induction x, y using mod.inductionOn with
| base x y h₁ =>
intro h₂
have h₁ : ¬ 0 < y ¬ y x := Decidable.not_and_iff_or_not.mp h₁
match h₁ with
| Or.inl h₁ => exact absurd h₂ h₁
| Or.inr h₁ =>
have hgt : y > x := gt_of_not_le h₁
have heq : x % y = x := mod_eq_of_lt hgt
rw [ heq] at hgt
exact hgt
| ind x y h h₂ =>
intro h₃
have _, h₁ := h
rw [mod_eq_sub_mod h₁]
exact h₂ h₃
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
rw [Nat.sub_add_cancel]
cases a with

View File

@@ -264,9 +264,6 @@ protected theorem pos_of_lt_add_left : n < k + n → 0 < k := by
protected theorem add_pos_left (h : 0 < m) (n) : 0 < m + n :=
Nat.lt_of_lt_of_le h (Nat.le_add_right ..)
protected theorem add_pos_right (m) (h : 0 < n) : 0 < m + n :=
Nat.lt_of_lt_of_le h (Nat.le_add_left ..)
protected theorem add_self_ne_one : n, n + n 1
| n+1, h => by rw [Nat.succ_add, Nat.succ.injEq] at h; contradiction

View File

@@ -15,30 +15,30 @@ public section
namespace Option
@[simp, grind] theorem mem_toArray {a : α} {o : Option α} : a o.toArray o = some a := by
@[simp, grind =] theorem mem_toArray {a : α} {o : Option α} : a o.toArray o = some a := by
cases o <;> simp [eq_comm]
@[simp, grind] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toArray β m (ForInStep β)) :
@[simp, grind =] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toArray β m (ForInStep β)) :
forIn' o.toArray b f = forIn' o b fun a m b => f a (by simpa using m) b := by
cases o <;> simp <;> rfl
@[simp, grind] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind =] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
forIn o.toArray b f = forIn o b f := by
cases o <;> simp <;> rfl
@[simp, grind] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
@[simp, grind =] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
o.toArray.foldlM f a = o.elim (pure a) (fun b => f a b) := by
cases o <;> simp
@[simp, grind] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
@[simp, grind =] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
o.toArray.foldrM f a = o.elim (pure a) (fun b => f b a) := by
cases o <;> simp
@[simp, grind] theorem foldl_toArray (o : Option β) (a : α) (f : α β α) :
@[simp, grind =] theorem foldl_toArray (o : Option β) (a : α) (f : α β α) :
o.toArray.foldl f a = o.elim a (fun b => f a b) := by
cases o <;> simp
@[simp, grind] theorem foldr_toArray (o : Option β) (a : α) (f : β α α) :
@[simp, grind =] theorem foldr_toArray (o : Option β) (a : α) (f : β α α) :
o.toArray.foldr f a = o.elim a (fun b => f b a) := by
cases o <;> simp

View File

@@ -97,7 +97,7 @@ theorem attach_eq_some : ∀ (o : Option α) (x : {x // o = some x}), o.attach =
| none, x, h => by simp at h
| some a, x, h => by simpa using h
@[grind]
@[grind ]
theorem mem_attach : (o : Option α) (x : {x // o = some x}), x o.attach :=
attach_eq_some

View File

@@ -18,27 +18,27 @@ namespace Option
deriving instance DecidableEq for Option
deriving instance BEq for Option
@[simp, grind] theorem getD_none : getD none a = a := rfl
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind =] theorem getD_none : getD none a = a := rfl
@[simp, grind =] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind] theorem map_none (f : α β) : none.map f = none := rfl
@[simp, grind] theorem map_some (a) (f : α β) : (some a).map f = some (f a) := rfl
@[simp, grind =] theorem map_none (f : α β) : none.map f = none := rfl
@[simp, grind =] theorem map_some (a) (f : α β) : (some a).map f = some (f a) := rfl
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
def getM [Alternative m] : Option α m α
| none => failure
| some a => pure a
@[simp, grind] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
@[simp, grind] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
@[simp, grind =] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
@[simp, grind =] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
/-- Returns `true` on `some x` and `false` on `none`. -/
@[inline] def isSome : Option α Bool
| some _ => true
| none => false
@[simp, grind] theorem isSome_none : @isSome α none = false := rfl
@[simp, grind] theorem isSome_some : isSome (some a) = true := rfl
@[simp, grind =] theorem isSome_none : @isSome α none = false := rfl
@[simp, grind =] theorem isSome_some : isSome (some a) = true := rfl
/--
Returns `true` on `none` and `false` on `some x`.
@@ -53,8 +53,8 @@ Examples:
| some _ => false
| none => true
@[simp, grind] theorem isNone_none : @isNone α none = true := rfl
@[simp, grind] theorem isNone_some : isNone (some a) = false := rfl
@[simp, grind =] theorem isNone_none : @isNone α none = true := rfl
@[simp, grind =] theorem isNone_some : isNone (some a) = false := rfl
/--
Checks whether an optional value is both present and equal to some other value.
@@ -89,8 +89,8 @@ Examples:
| none, _ => none
| some a, f => f a
@[simp, grind] theorem bind_none (f : α Option β) : none.bind f = none := rfl
@[simp, grind] theorem bind_some (a) (f : α Option β) : (some a).bind f = f a := rfl
@[simp, grind =] theorem bind_none (f : α Option β) : none.bind f = none := rfl
@[simp, grind =] theorem bind_some (a) (f : α Option β) : (some a).bind f = f a := rfl
@[deprecated bind_none (since := "2025-05-03")]
abbrev none_bind := @bind_none
@@ -125,8 +125,8 @@ This function only requires `m` to be an applicative functor. An alias `Option.m
| none => pure none
| some x => some <$> f x
@[simp, grind] theorem mapM_none [Applicative m] (f : α m β) : none.mapM f = pure none := rfl
@[simp, grind] theorem mapM_some [Applicative m] (x) (f : α m β) : (some x).mapM f = some <$> f x := rfl
@[simp, grind =] theorem mapM_none [Applicative m] (f : α m β) : none.mapM f = pure none := rfl
@[simp, grind =] theorem mapM_some [Applicative m] (x) (f : α m β) : (some x).mapM f = some <$> f x := rfl
/--
Applies a function in some applicative functor to an optional value, returning `none` with no
@@ -138,9 +138,9 @@ This is an alias for `Option.mapM`, which already works for applicative functors
Option.mapM f
/-- For verification purposes, we replace `mapA` with `mapM`. -/
@[simp, grind] theorem mapA_eq_mapM [Applicative m] {f : α m β} : Option.mapA f o = Option.mapM f o := rfl
@[simp, grind =] theorem mapA_eq_mapM [Applicative m] {f : α m β} : Option.mapA f o = Option.mapM f o := rfl
@[simp, grind]
@[simp, grind =]
theorem map_id : (Option.map id : Option α Option α) = id :=
funext (fun o => match o with | none => rfl | some _ => rfl)
@@ -182,8 +182,8 @@ Examples:
| some a => p a
| none => true
@[simp, grind] theorem all_none : Option.all p none = true := rfl
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
@[simp, grind =] theorem all_none : Option.all p none = true := rfl
@[simp, grind =] theorem all_some : Option.all p (some x) = p x := rfl
/--
Checks whether an optional value is not `none` and satisfies a Boolean predicate.
@@ -197,8 +197,8 @@ Examples:
| some a => p a
| none => false
@[simp, grind] theorem any_none : Option.any p none = false := rfl
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
@[simp, grind =] theorem any_none : Option.any p none = false := rfl
@[simp, grind =] theorem any_some : Option.any p (some x) = p x := rfl
/--
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
@@ -210,8 +210,8 @@ See also `or` for a version that is strict in the second argument.
| some a, _ => some a
| none, b => b ()
@[simp, grind] theorem orElse_some : (some a).orElse b = some a := rfl
@[simp, grind] theorem orElse_none : none.orElse b = b () := rfl
@[simp, grind =] theorem orElse_some : (some a).orElse b = some a := rfl
@[simp, grind =] theorem orElse_none : none.orElse b = b () := rfl
instance : OrElse (Option α) where
orElse := Option.orElse
@@ -351,9 +351,9 @@ Extracts the value from an option that can be proven to be `some`.
@[inline] def get {α : Type u} : (o : Option α) isSome o α
| some x, _ => x
@[simp, grind] theorem some_get : {x : Option α} (h : isSome x), some (x.get h) = x
@[simp, grind =] theorem some_get : {x : Option α} (h : isSome x), some (x.get h) = x
| some _, _ => rfl
@[simp, grind] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
@[simp, grind =] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
/--
Returns `none` if a value doesn't satisfy a Boolean predicate, or the value itself otherwise.
@@ -431,8 +431,8 @@ Examples:
-/
@[inline] def join (x : Option (Option α)) : Option α := x.bind id
@[simp, grind] theorem join_none : (none : Option (Option α)).join = none := rfl
@[simp, grind] theorem join_some : (some o).join = o := rfl
@[simp, grind =] theorem join_none : (none : Option (Option α)).join = none := rfl
@[simp, grind =] theorem join_some : (some o).join = o := rfl
/--
Converts an optional monadic computation into a monadic computation of an optional value.
@@ -457,8 +457,8 @@ some "world"
| none => pure none
| some f => some <$> f
@[simp, grind] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
@[simp, grind] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
@[simp, grind =] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
@[simp, grind =] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
/--
A monadic case analysis function for `Option`.
@@ -483,8 +483,8 @@ This is the monadic analogue of `Option.getD`.
| some a => pure a
| none => y
@[simp, grind] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
@[simp, grind] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
@[simp, grind =] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
@[simp, grind =] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
rfl {x} := private
@@ -520,10 +520,10 @@ protected def min [Min α] : Option α → Option α → Option α
instance [Min α] : Min (Option α) where min := Option.min
@[simp, grind] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp, grind] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
@[simp, grind =] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp, grind =] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
cases o <;> rfl
@[simp, grind] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
@[simp, grind =] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
cases o <;> rfl
@[deprecated min_none_right (since := "2025-05-12")]
@@ -553,10 +553,10 @@ protected def max [Max α] : Option α → Option α → Option α
instance [Max α] : Max (Option α) where max := Option.max
@[simp, grind] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp, grind] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
@[simp, grind =] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp, grind =] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
cases o <;> rfl
@[simp, grind] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
@[simp, grind =] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
cases o <;> rfl
@[deprecated max_none_right (since := "2025-05-12")]

View File

@@ -24,7 +24,7 @@ namespace Option
@[deprecated mem_def (since := "2025-04-07")]
theorem mem_iff {a : α} {b : Option α} : a b b = some a := .rfl
@[grind] theorem mem_some {a b : α} : a some b b = a := by simp
@[grind =] theorem mem_some {a b : α} : a some b b = a := by simp
theorem mem_some_iff {a b : α} : a some b b = a := mem_some

View File

@@ -16,30 +16,30 @@ public section
namespace Option
@[simp, grind] theorem mem_toList {a : α} {o : Option α} : a o.toList o = some a := by
@[simp, grind =] theorem mem_toList {a : α} {o : Option α} : a o.toList o = some a := by
cases o <;> simp [eq_comm]
@[simp, grind] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toList β m (ForInStep β)) :
@[simp, grind =] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toList β m (ForInStep β)) :
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
cases o <;> rfl
@[simp, grind] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind =] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
forIn o.toList b f = forIn o b f := by
cases o <;> rfl
@[simp, grind] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
@[simp, grind =] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
cases o <;> simp
@[simp, grind] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
@[simp, grind =] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
cases o <;> simp
@[simp, grind] theorem foldl_toList (o : Option β) (a : α) (f : α β α) :
@[simp, grind =] theorem foldl_toList (o : Option β) (a : α) (f : α β α) :
o.toList.foldl f a = o.elim a (fun b => f a b) := by
cases o <;> simp
@[simp, grind] theorem foldr_toList (o : Option β) (a : α) (f : β α α) :
@[simp, grind =] theorem foldr_toList (o : Option β) (a : α) (f : β α α) :
o.toList.foldr f a = o.elim a (fun b => f b a) := by
cases o <;> simp
@@ -47,7 +47,7 @@ namespace Option
theorem pairwise_toList {P : α α Prop} {o : Option α} : o.toList.Pairwise P := by
cases o <;> simp
@[simp, grind]
@[simp, grind =]
theorem head?_toList {o : Option α} : o.toList.head? = o := by
cases o <;> simp

View File

@@ -16,20 +16,20 @@ public section
namespace Option
@[simp, grind] theorem bindM_none [Pure m] (f : α m (Option β)) : none.bindM f = pure none := rfl
@[simp, grind] theorem bindM_some [Pure m] (a) (f : α m (Option β)) : (some a).bindM f = f a := by
@[simp, grind =] theorem bindM_none [Pure m] (f : α m (Option β)) : none.bindM f = pure none := rfl
@[simp, grind =] theorem bindM_some [Pure m] (a) (f : α m (Option β)) : (some a).bindM f = f a := by
simp [Option.bindM]
-- We simplify `Option.forM` to `forM`.
@[simp] theorem forM_eq_forM [Monad m] : @Option.forM m α _ = forM := rfl
@[simp, grind] theorem forM_none [Monad m] (f : α m PUnit) :
@[simp, grind =] theorem forM_none [Monad m] (f : α m PUnit) :
forM none f = pure .unit := rfl
@[simp, grind] theorem forM_some [Monad m] (f : α m PUnit) (a : α) :
@[simp, grind =] theorem forM_some [Monad m] (f : α m PUnit) (a : α) :
forM (some a) f = f a := rfl
@[simp, grind] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α β) (f : β m PUnit) :
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α β) (f : β m PUnit) :
forM (o.map g) f = forM o (fun a => f (g a)) := by
cases o <;> simp
@@ -37,11 +37,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α
forM o.join f = forM o (forM · f) := by
cases o <;> simp
@[simp, grind] theorem forIn'_none [Monad m] (b : β) (f : (a : α) a none β m (ForInStep β)) :
@[simp, grind =] theorem forIn'_none [Monad m] (b : β) (f : (a : α) a none β m (ForInStep β)) :
forIn' none b f = pure b := by
rfl
@[simp, grind] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
@[simp, grind =] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn', bind_pure_comp]
rw [map_eq_pure_bind]
@@ -49,11 +49,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α
funext x
split <;> simp
@[simp, grind] theorem forIn_none [Monad m] (b : β) (f : α β m (ForInStep β)) :
@[simp, grind =] theorem forIn_none [Monad m] (b : β) (f : α β m (ForInStep β)) :
forIn none b f = pure b := by
rfl
@[simp, grind] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind =] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn, forIn', bind_pure_comp]
rw [map_eq_pure_bind]
@@ -106,7 +106,7 @@ theorem forIn'_id_yield_eq_pelim
o.pelim b (fun a h => f a h b) :=
forIn'_pure_yield_eq_pelim _ _ _
@[simp, grind] theorem forIn'_map [Monad m] [LawfulMonad m]
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : (b : β) b o.map g γ m (ForInStep γ)) :
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases o <;> simp
@@ -149,7 +149,7 @@ theorem forIn_id_yield_eq_elim
o.elim b (fun a => f a b) :=
forIn_pure_yield_eq_elim _ _ _
@[simp, grind] theorem forIn_map [Monad m] [LawfulMonad m]
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
cases o <;> simp

View File

@@ -349,13 +349,13 @@ theorem LawfulEqCmp.compare_beq_iff_eq {a b : α} : cmp a b == .eq ↔ a = b :=
beq_iff_eq.trans compare_eq_iff_eq
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_eq_iff_eq` -/
@[simp, grind]
@[simp, grind =]
theorem LawfulEqOrd.compare_eq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
compare a b = .eq a = b :=
LawfulEqCmp.compare_eq_iff_eq
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_beq_iff_eq` -/
@[grind]
@[grind =]
theorem LawfulEqOrd.compare_beq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
compare a b == .eq a = b :=
LawfulEqCmp.compare_beq_iff_eq

View File

@@ -67,20 +67,20 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
extract_lets
first
| infer_instance
| exact Classical.Order.instLT
| exact _root_.Classical.Order.instLT
beq :
let := le; let := decidableLE
BEq α := by
extract_lets
first
| infer_instance
| exact FactoryInstances.beqOfDecidableLE
| exact _root_.Std.FactoryInstances.beqOfDecidableLE
lt_iff :
let := le; let := lt
a b : α, a < b a b ¬ b a := by
extract_lets
first
| exact LawfulOrderLT.lt_iff
| exact _root_.Std.LawfulOrderLT.lt_iff
| fail "Failed to automatically prove that the `LE` and `LT` instances are compatible. \
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
manually provide the field `lt_iff`."
@@ -89,10 +89,10 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
have := lt_iff
DecidableLT α := by
extract_lets
haveI := @LawfulOrderLT.mk (lt_iff := by assumption) ..
haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..
first
| infer_instance
| exact FactoryInstances.decidableLTOfLE
| exact _root_.Std.FactoryInstances.decidableLTOfLE
| fail "Failed to automatically derive that `LT` is decidable. \
Please ensure that a `DecidableLT` instance can be synthesized or \
manually provide the field `decidableLT`."
@@ -101,7 +101,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
a b : α, a == b a b b a := by
extract_lets
first
| exact LawfulOrderBEq.beq_iff_le_and_ge
| exact _root_.Std.LawfulOrderBEq.beq_iff_le_and_ge
| fail "Failed to automatically prove that the `LE` and `BEq` instances are compatible. \
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
manually provide the field `beq_iff_le_and_ge`."
@@ -110,7 +110,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
a : α, a a := by
extract_lets
first
| exact Std.Refl.refl (r := (· ·))
| exact _root_.Std.Refl.refl (r := (· ·))
| fail "Failed to automatically prove that the `LE` instance is reflexive. \
Please ensure that a `Refl` instance can be synthesized or \
manually provide the field `le_refl`."
@@ -119,7 +119,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
a b c : α, a b b c a c := by
extract_lets
first
| exact fun _ _ _ hab hbc => Trans.trans (r := (· ·)) (s := (· ·)) (t := (· ·)) hab hbc
| exact fun _ _ _ hab hbc => _root_.Trans.trans (r := (· ·)) (s := (· ·)) (t := (· ·)) hab hbc
| fail "Failed to automatically prove that the `LE` instance is transitive. \
Please ensure that a `Trans` instance can be synthesized or \
manually provide the field `le_trans`."
@@ -202,7 +202,7 @@ public structure Packages.PartialOrderOfLEArgs (α : Type u) extends Packages.Pr
a b : α, a b b a a = b := by
extract_lets
first
| exact Antisymm.antisymm
| exact _root_.Std.Antisymm.antisymm
| fail "Failed to automatically prove that the `LE` instance is antisymmetric. \
Please ensure that a `Antisymm` instance can be synthesized or \
manually provide the field `le_antisymm`."
@@ -310,11 +310,11 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
extract_lets
first
| infer_instance
| exact FactoryInstances.instOrdOfDecidableLE
| exact _root_.Std.FactoryInstances.instOrdOfDecidableLE
le_total :
a b : α, a b b a := by
first
| exact Total.total
| exact _root_.Std.Total.total
| fail "Failed to automatically prove that the `LE` instance is total. \
Please ensure that a `Total` instance can be synthesized or \
manually provide the field `le_total`."
@@ -324,7 +324,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
a b : α, (compare a b).isLE a b := by
extract_lets
first
| exact LawfulOrderOrd.isLE_compare
| exact _root_.Std.LawfulOrderOrd.isLE_compare
| fail "Failed to automatically prove that `(compare a b).isLE` is equivalent to `a ≤ b`. \
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
manually provide the field `isLE_compare`."
@@ -333,7 +333,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
a b : α, (compare a b).isGE b a := by
extract_lets
first
| exact LawfulOrderOrd.isGE_compare
| exact _root_.Std.LawfulOrderOrd.isGE_compare
| fail "Failed to automatically prove that `(compare a b).isGE` is equivalent to `b ≤ a`. \
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
manually provide the field `isGE_compare`."
@@ -411,20 +411,20 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
extract_lets
first
| infer_instance
| exact Min.leftLeaningOfLE _
| exact _root_.Min.leftLeaningOfLE _
max :
let := le; let := decidableLE
Max α := by
extract_lets
first
| infer_instance
| exact Max.leftLeaningOfLE _
| exact _root_.Max.leftLeaningOfLE _
min_eq :
let := le; let := decidableLE; let := min
a b : α, Min.min a b = if a b then a else b := by
extract_lets
first
| exact fun a b => Std.min_eq_if (a := a) (b := b)
| exact fun a b => _root_.Std.min_eq_if (a := a) (b := b)
| fail "Failed to automatically prove that `min` is left-leaning. \
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
manually provide the field `min_eq`."
@@ -433,7 +433,7 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
a b : α, Max.max a b = if b a then a else b := by
extract_lets
first
| exact fun a b => Std.max_eq_if (a := a) (b := b)
| exact fun a b => _root_.Std.max_eq_if (a := a) (b := b)
| fail "Failed to automatically prove that `max` is left-leaning. \
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
manually provide the field `max_eq`."
@@ -538,7 +538,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
extract_lets
first
| infer_instance
| exact LE.ofOrd _
| exact _root_.LE.ofOrd _
lawfulOrderOrd :
let := ord; let := transOrd; let := le
LawfulOrderOrd α := by
@@ -554,7 +554,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
extract_lets
first
| infer_instance
| exact DecidableLE.ofOrd _
| exact _root_.DecidableLE.ofOrd _
| fail "Failed to automatically derive that `LE` is decidable.\
Please ensure that a `DecidableLE` instance can be synthesized or \
manually provide the field `decidableLE`."
@@ -570,7 +570,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
a b : α, a < b compare a b = .lt := by
extract_lets
first
| exact fun _ _ => Std.compare_eq_lt.symm
| exact fun _ _ => _root_.Std.compare_eq_lt.symm
| fail "Failed to automatically derive that `LT` and `Ord` are compatible. \
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
manually provide the field `lt_iff`."
@@ -580,7 +580,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
extract_lets
first
| infer_instance
| exact DecidableLT.ofOrd _
| exact _root_DecidableLT.ofOrd _
| fail "Failed to automatically derive that `LT` is decidable. \
Please ensure that a `DecidableLT` instance can be synthesized or \
manually provide the field `decidableLT`."
@@ -589,7 +589,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
extract_lets
first
| infer_instance
| exact BEq.ofOrd _
| exact _root_.BEq.ofOrd _
beq_iff :
let := ord; let := le; have := lawfulOrderOrd; let := beq
a b : α, a == b compare a b = .eq := by
@@ -708,7 +708,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
a b : α, compare a b = .eq a = b := by
extract_lets
first
| exact LawfulEqOrd.eq_of_compare
| exact fun _ _ => _root_.Std.LawfulEqOrd.eq_of_compare
| fail "Failed to derive a `LawfulEqOrd` instance. \
Please make sure that it can be synthesized or \
manually provide the field `eq_of_compare`."
@@ -718,20 +718,20 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
extract_lets
first
| infer_instance
| exact FactoryInstances.instMinOfOrd
| exact _root_.Std.FactoryInstances.instMinOfOrd
max :
let := ord
Max α := by
extract_lets
first
| infer_instance
| exact FactoryInstances.instMaxOfOrd
| exact _root_.Std.FactoryInstances.instMaxOfOrd
min_eq :
let := ord; let := le; let := min; have := lawfulOrderOrd
a b : α, Min.min a b = if (compare a b).isLE then a else b := by
extract_lets
first
| exact fun a b => Std.min_eq_if_isLE_compare (a := a) (b := b)
| exact fun a b => _root_.Std.min_eq_if_isLE_compare (a := a) (b := b)
| fail "Failed to automatically prove that `min` is left-leaning. \
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
manually provide the field `min_eq`."
@@ -740,7 +740,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
a b : α, Max.max a b = if (compare a b).isGE then a else b := by
extract_lets
first
| exact fun a b => Std.max_eq_if_isGE_compare (a := a) (b := b)
| exact fun a b => _root_.Std.max_eq_if_isGE_compare (a := a) (b := b)
| fail "Failed to automatically prove that `max` is left-leaning. \
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
manually provide the field `max_eq`."

View File

@@ -7,6 +7,7 @@ module
prelude
public import Init.System.IO
import Init.Data.ByteArray.Extra
public section
universe u

View File

@@ -24,14 +24,14 @@ namespace Std.PRange
instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLE α] [LawfulOrderLT α] : LawfulUpwardEnumerableLT α where
lt_iff a b := by
simp only [LawfulOrderLT.lt_iff, LawfulUpwardEnumerableLE.le_iff]
simp only [LawfulOrderLT.lt_iff, UpwardEnumerable.le_iff]
constructor
· intro h
obtain n, hn := h.1
cases n
· apply h.2.elim
refine 0, ?_
simpa [UpwardEnumerable.succMany?_zero] using hn.symm
simpa [succMany?_zero] using hn.symm
exact _, hn
· intro h
constructor
@@ -41,63 +41,60 @@ instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α] :
LawfulUpwardEnumerableLowerBound .closed α where
isSatisfied_iff a l := by
simp [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
LawfulUpwardEnumerableLE.le_iff]
simp [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.le_iff]
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α]
[Trans (α := α) (· ·) (· ·) (· ·)]:
LawfulUpwardEnumerableUpperBound .closed α where
isSatisfied_of_le u a b hub hab := by
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLE.le_iff] at hub hab
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.le_iff] at hub hab
exact Trans.trans hab hub
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLT α] :
LawfulUpwardEnumerableLowerBound .open α where
isSatisfied_iff a l := by
simp only [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
LawfulUpwardEnumerableLT.lt_iff]
simp only [SupportsLowerBound.IsSatisfied, init?, UpwardEnumerable.lt_iff]
constructor
· rintro n, hn
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
cases h : UpwardEnumerable.succ? l
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
cases h : succ? l
· simp [h] at hn
· exact _, rfl, n, by simpa [h] using hn
· rintro init, hi, n, hn
exact n, by simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hi] using hn
exact n, by simpa [succMany?_succ?_eq_succ?_bind_succMany?, hi] using hn
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLT α] :
LawfulUpwardEnumerableUpperBound .open α where
isSatisfied_of_le u a b hub hab := by
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at hub
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at hub
exact UpwardEnumerable.lt_of_le_of_lt hab hub
instance [UpwardEnumerable α] [Least? α] [LawfulUpwardEnumerableLeast? α] :
LawfulUpwardEnumerableLowerBound .unbounded α where
isSatisfied_iff a l := by
simpa [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?] using
LawfulUpwardEnumerableLeast?.eq_succMany?_least? a
simpa [SupportsLowerBound.IsSatisfied, init?] using UpwardEnumerable.least?_le
instance [LE α] [Total (α := α) (· ·)] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLE α] :
LinearlyUpwardEnumerable α where
eq_of_succ?_eq a b hab := by
cases Total.total (α := α) (r := (· ·)) a b <;> rename_i h <;>
simp only [LawfulUpwardEnumerableLE.le_iff] at h
simp only [UpwardEnumerable.le_iff] at h
· obtain n, hn := h
cases n
· simpa [UpwardEnumerable.succMany?_zero] using hn
· simpa [succMany?_zero] using hn
· exfalso
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab,
LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab,
succMany?_succ?_eq_succ?_bind_succMany?] at hn
exact UpwardEnumerable.lt_irrefl _, hn
· obtain n, hn := h
cases n
· simpa [UpwardEnumerable.succMany?_zero] using hn.symm
· simpa [succMany?_zero] using hn.symm
· exfalso
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab.symm,
LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
rw [succMany?_succ?_eq_succ?_bind_succMany?, hab.symm,
succMany?_succ?_eq_succ?_bind_succMany?] at hn
exact UpwardEnumerable.lt_irrefl _, hn
instance [UpwardEnumerable α] : LawfulUpwardEnumerableUpperBound .unbounded α where
@@ -122,24 +119,24 @@ instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [Decidable
simp only [SupportsUpperBound.IsSatisfied] at h
simp only [RangeSize.size]
by_cases h' : a bound
· match hs : UpwardEnumerable.succ? a with
· match hs : succ? a with
| none => rw [LawfulRangeSize.size_eq_one_of_succ?_eq_none (h := h') (h' := by omega)]
| some b =>
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := h') (h' := hs)]
have : ¬ b bound := by
intro hb
have : a < b := by
rw [LawfulUpwardEnumerableLT.lt_iff]
exact 0, by simpa [UpwardEnumerable.succMany?_one] using hs
rw [UpwardEnumerable.lt_iff]
exact 0, by simpa [succMany?_one] using hs
exact h (lt_of_lt_of_le this hb)
rw [LawfulRangeSize.size_eq_zero_of_not_isSatisfied (h := this)]
· suffices RangeSize.size (shape := .closed) bound a = 0 by omega
exact LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
size_eq_one_of_succ?_eq_none bound a h h' := by
exfalso
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at h
simp only [SupportsUpperBound.IsSatisfied, UpwardEnumerable.lt_iff] at h
obtain n, hn := h
simp [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] at hn
simp [succMany?_succ?_eq_succ?_bind_succMany?, h'] at hn
size_eq_succ_of_succ?_eq_some bound a a' h h' := by
simp only [SupportsUpperBound.IsSatisfied] at h
simp only [RangeSize.size, Nat.pred_eq_succ_iff]
@@ -148,10 +145,10 @@ instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [Decidable
· omega
· simp only [Nat.succ_le_iff, LawfulRangeSize.size_pos_iff_isSatisfied,
SupportsUpperBound.IsSatisfied]
rw [LawfulUpwardEnumerableLE.le_iff]
rw [LawfulUpwardEnumerableLT.lt_iff] at h
rw [UpwardEnumerable.le_iff]
rw [UpwardEnumerable.lt_iff] at h
refine h.choose, ?_
simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] using h.choose_spec
simpa [succMany?_succ?_eq_succ?_bind_succMany?, h'] using h.choose_spec
instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[RangeSize su α] [SupportsUpperBound su α] [LawfulRangeSize su α] : HasFiniteRanges su α where
@@ -161,11 +158,11 @@ instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpward
induction n generalizing init with
| zero =>
simp only [LawfulRangeSize.size_eq_zero_iff_not_isSatisfied] at hn
simp [UpwardEnumerable.succMany?_zero, hn]
simp [succMany?_zero, hn]
| succ =>
rename_i n ih
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?]
match hs : UpwardEnumerable.succ? init with
rw [succMany?_succ?_eq_succ?_bind_succMany?]
match hs : succ? init with
| none => simp
| some a =>
simp only [Option.bind_some]

View File

@@ -7,7 +7,7 @@ module
prelude
public import Init.Data.Iterators
public import Init.Data.Iterators.Lemmas.Consumers.Collect
import Init.Data.Iterators.Lemmas.Consumers.Collect
public import Init.Data.Range.Polymorphic.Basic
import all Init.Data.Range.Polymorphic.Basic
public import Init.Data.Range.Polymorphic.RangeIterator
@@ -30,13 +30,13 @@ open Std.Iterators
variable {shape : RangeShape} {α : Type u}
private theorem Internal.iter_open_eq_iter_closed_of_isSome_succ? {su} [UpwardEnumerable α]
private theorem Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
Internal.iter (PRange.mk (shape := .open, su) lo hi) =
Internal.iter (PRange.mk (shape := .closed, su) (UpwardEnumerable.succ? lo |>.get h) hi) := by
simp [Internal.iter, BoundedUpwardEnumerable.init?]
simp [Internal.iter, init?]
private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
[BoundedUpwardEnumerable sl α] [SupportsUpperBound su α] [HasFiniteRanges su α]
@@ -44,7 +44,7 @@ private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
r.toList = (Internal.iter r).toList := by
rfl
theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
{it : Iter (α := RangeIterator su α) α} :
@@ -61,11 +61,11 @@ theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
· simp [*]
· split <;> rename_i heq' <;> simp [*]
theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
{r : PRange sl, su α} :
r.toList = match BoundedUpwardEnumerable.init? r.lower with
r.toList = match init? r.lower with
| none => []
| some a => if SupportsUpperBound.IsSatisfied r.upper a then
a :: (PRange.mk (shape := .open, su) a r.upper).toList
@@ -73,26 +73,35 @@ theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable s
[] := by
rw [Internal.toList_eq_toList_iter, RangeIterator.toList_eq_match]; rfl
theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
public theorem toList_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
(PRange.mk (shape := .open, su) lo hi).toList =
(PRange.mk (shape := .closed, su) (UpwardEnumerable.succ? lo |>.get h) hi).toList := by
simp [Internal.toList_eq_toList_iter, Internal.iter_open_eq_iter_closed_of_isSome_succ?, h]
simp [Internal.toList_eq_toList_iter, Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ?, h]
theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
@[deprecated toList_Rox_eq_toList_Rcx_of_isSome_succ? (since := "2025-08-22")]
public theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
(PRange.mk (shape := .open, su) lo hi).toList =
(PRange.mk (shape := .closed, su) (UpwardEnumerable.succ? lo |>.get h) hi).toList :=
toList_Rox_eq_toList_Rcx_of_isSome_succ? h
public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
[LawfulUpwardEnumerable α]
{r : PRange sl, su α} :
r.toList = []
¬ ( a, BoundedUpwardEnumerable.init? r.lower = some a SupportsUpperBound.IsSatisfied r.upper a) := by
¬ ( a, init? r.lower = some a SupportsUpperBound.IsSatisfied r.upper a) := by
rw [Internal.toList_eq_toList_iter]
rw [RangeIterator.toList_eq_match, Internal.iter]
simp only
split <;> rename_i heq <;> simp [heq]
theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -101,17 +110,24 @@ theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
rw [Internal.toList_eq_toList_iter, Iter.mem_toList_iff_isPlausibleIndirectOutput,
Internal.isPlausibleIndirectOutput_iter_iff]
theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
public theorem BoundedUpwardEnumerable.init?_succ?_closed [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
(h : UpwardEnumerable.succ? lower = some lower') :
BoundedUpwardEnumerable.init? lower' = (BoundedUpwardEnumerable.init? lower).bind UpwardEnumerable.succ? := by
init? lower' = (init? lower).bind UpwardEnumerable.succ? := by
cases h : init? lower <;> rename_i ilower <;> cases h' : init? lower' <;> rename_i ilower'
· simp
· simp [init?] at h
· simp [init?] at h'
· simp_all [init?]
theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
@[deprecated BoundedUpwardEnumerable.init?_succ?_closed (since := "2025-08-22")]
public theorem BoundedUpwardEnumerable.Closed.init?_succ [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
(h : UpwardEnumerable.succ? lower = some lower') :
init? lower' = (init? lower).bind UpwardEnumerable.succ? :=
init?_succ?_closed h
public theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -130,14 +146,14 @@ theorem pairwise_toList_upwardEnumerableLt {sl su} [UpwardEnumerable α]
simp only at ha
have : UpwardEnumerable.LT a ha.choose := by
refine 0, ?_
simp only [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero,
simp only [succMany?_succ?, succMany?_zero,
Option.bind_some]
exact ha.choose_spec.1
exact UpwardEnumerable.lt_of_lt_of_le this ha.choose_spec.2
· apply ihy (out := a)
simp_all [RangeIterator.isPlausibleStep_iff, RangeIterator.step]
theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
public theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -145,7 +161,7 @@ theorem pairwise_toList_ne {sl su} [UpwardEnumerable α]
r.toList.Pairwise (fun a b => a b) :=
List.Pairwise.imp (fun hlt => UpwardEnumerable.ne_of_lt hlt) pairwise_toList_upwardEnumerableLt
theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
public theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLT α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -154,7 +170,7 @@ theorem pairwise_toList_lt {sl su} [LT α] [UpwardEnumerable α]
List.Pairwise.imp
(fun hlt => (LawfulUpwardEnumerableLT.lt_iff ..).mpr hlt) pairwise_toList_upwardEnumerableLt
theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
public theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -162,38 +178,44 @@ theorem pairwise_toList_le {sl su} [LE α] [UpwardEnumerable α]
r.toList.Pairwise (fun a b => a b) :=
pairwise_toList_upwardEnumerableLt
|> List.Pairwise.imp UpwardEnumerable.le_of_lt
|> List.Pairwise.imp (fun hle => (LawfulUpwardEnumerableLE.le_iff ..).mpr hle)
|> List.Pairwise.imp (fun hle => (UpwardEnumerable.le_iff ..).mpr hle)
theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
public theorem mem_Rco_succ_succ_iff [UpwardEnumerable α]
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
a PRange.mk (shape := .closed, .open) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper)
a', a = UpwardEnumerable.succ a' a' PRange.mk (shape := .closed, .open) lower upper := by
(a (succ lower)...(succ upper)) a', a = succ a' a' lower...upper := by
simp [Membership.mem, LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
BoundedUpwardEnumerable.init?, LawfulOpenUpperBound.isSatisfied_iff_le]
init?, LawfulOpenUpperBound.isSatisfied_iff_le]
rw [ Option.some_get (InfinitelyUpwardEnumerable.isSome_succ? _)]
simp only [Option.some.injEq, UpwardEnumerable.succ.eq_def]
simp
constructor
· rintro n, hn, h
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany, UpwardEnumerable.succMany_one,
UpwardEnumerable.succMany_add, Nat.add_comm, UpwardEnumerable.succMany_add,
UpwardEnumerable.succMany_one] at hn
rw [succMany?_eq_some_iff_succMany, succMany_one, succMany_add, Nat.add_comm, succMany_add,
succMany_one] at hn
rw [ hn]
refine UpwardEnumerable.succMany n lower, rfl, ?_, ?_
· exact n, by simp [UpwardEnumerable.succMany_eq_get]
refine succMany n lower, rfl, ?_, ?_
· exact n, by simp [succMany_eq_get]
· obtain m, hm := h
refine m, ?_
rw [UpwardEnumerable.succMany?_eq_some_iff_succMany] at hm
rwa [ hn, UpwardEnumerable.succMany_one, UpwardEnumerable.succMany_add, Nat.add_comm,
UpwardEnumerable.succMany_add, UpwardEnumerable.succMany_one,
UpwardEnumerable.succ_eq_succ_iff] at hm
rw [succMany?_eq_some_iff_succMany] at hm
rwa [ hn, succMany_one, succMany_add, Nat.add_comm, succMany_add, succMany_one,
succ_eq_succ_iff] at hm
· rintro a', rfl, hl, hu
simp [UpwardEnumerable.succ_le_succ_iff, UpwardEnumerable.succ_lt_succ_iff]
exact hl, hu
@[deprecated mem_Rco_succ_succ_iff (since := "2025-08-22")]
public theorem ClosedOpen.mem_succ_iff [UpwardEnumerable α]
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
[SupportsLowerBound .closed α] [LawfulUpwardEnumerableLowerBound .closed α]
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
{lower : Bound .closed α} {upper : Bound .open α} {a : α} :
(a (succ lower)...(succ upper)) a', a = succ a' a' lower...upper :=
mem_Rco_succ_succ_iff
private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α α Prop} [asymm : Asymm lt]
{l l' : List α} (hl : l.Pairwise lt) (hl' : l'.Pairwise lt)
(h : a, a l a l') : l = l' := by
@@ -246,13 +268,13 @@ private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : αα → Prop} [asym
have hgt := hl.1 y _
cases Asymm.asymm _ _ hlt hgt
theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
public theorem toList_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
{lower : Bound .closed α} {upper : Bound .open α} :
(PRange.mk (shape := .closed, .open) (UpwardEnumerable.succ lower) (UpwardEnumerable.succ upper)).toList =
(PRange.mk (shape := .closed, .open) lower upper).toList.map UpwardEnumerable.succ := by
((succ lower)...(succ upper)).toList =
(lower...upper).toList.map succ := by
apply eq_of_pairwise_lt_of_mem_iff_mem (lt := UpwardEnumerable.LT) (asymm := ?_)
· apply pairwise_toList_upwardEnumerableLt
· apply List.Pairwise.map (R := UpwardEnumerable.LT) (S := UpwardEnumerable.LT)
@@ -261,7 +283,7 @@ theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
· apply pairwise_toList_upwardEnumerableLt
· simp only [List.mem_map, mem_toList_iff_mem]
intro a
rw [mem_succ_iff]
rw [mem_Rco_succ_succ_iff]
constructor
· rintro a, rfl, h
exact a, h, rfl
@@ -269,6 +291,16 @@ theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerB
exact _, h'.symm, h
· exact fun _ _ => UpwardEnumerable.not_gt_of_lt
@[deprecated toList_Rco_succ_succ_eq_map (since := "2025-08-22")]
public theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
{lower : Bound .closed α} {upper : Bound .open α} :
((succ lower)...(succ upper)).toList =
(lower...upper).toList.map succ :=
toList_Rco_succ_succ_eq_map
private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
@@ -280,7 +312,7 @@ private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
ForIn'.forIn' (Internal.iter r) init (fun a ha acc => f a (Internal.isPlausibleIndirectOutput_iter_iff.mp ha) acc) := by
rfl
theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -292,7 +324,7 @@ theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
simp [Internal.forIn'_eq_forIn'_iter, Internal.toList_eq_toList_iter,
Iter.forIn'_eq_forIn'_toList]
theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -303,7 +335,7 @@ theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
ForIn'.forIn' r init (fun a ha acc => f a (mem_toList_iff_mem.mpr ha) acc) := by
simp [forIn'_eq_forIn'_toList]
theorem mem_of_mem_open [UpwardEnumerable α]
public theorem mem_of_mem_open [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -314,22 +346,21 @@ theorem mem_of_mem_open [UpwardEnumerable α]
a r := by
refine ?_, hmem.2
have := hmem.1
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff,
BoundedUpwardEnumerable.init?] at this hrb
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff, init?] at this hrb
obtain init, hi := hrb
obtain b', hb' := this
refine init, hi.1, UpwardEnumerable.le_trans hi.2 (UpwardEnumerable.le_trans ?_ hb'.2)
exact UpwardEnumerable.le_of_succ?_eq hb'.1
theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
public theorem SupportsLowerBound.isSatisfied_init? {sl} [UpwardEnumerable α]
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α]
{bound : Bound sl α} {a : α} (h : BoundedUpwardEnumerable.init? bound = some a) :
{bound : Bound sl α} {a : α} (h : init? bound = some a) :
SupportsLowerBound.IsSatisfied bound a := by
simp only [LawfulUpwardEnumerableLowerBound.isSatisfied_iff]
exact a, h, UpwardEnumerable.le_refl _
theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
public theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -337,7 +368,7 @@ theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
{r : PRange sl, su α}
{γ : Type u} {init : γ} {m : Type u Type w} [Monad m] [LawfulMonad m]
{f : (a : α) _ γ m (ForInStep γ)} :
ForIn'.forIn' r init f = match hi : BoundedUpwardEnumerable.init? r.lower with
ForIn'.forIn' r init f = match hi : init? r.lower with
| none => pure init
| some a => if hu : SupportsUpperBound.IsSatisfied r.upper a then do
match f a SupportsLowerBound.isSatisfied_init? hi, hu init with
@@ -362,7 +393,7 @@ theorem forIn'_eq_match {sl su} [UpwardEnumerable α]
· simp
· simp
instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] [LawfulRangeSize su α] :
LawfulIteratorSize (RangeIterator su α) where
size_eq_size_toArray {it} := by
@@ -400,7 +431,7 @@ instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
simp [*] at this
theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[BoundedUpwardEnumerable sl α] [SupportsLowerBound sl α] [SupportsUpperBound su α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
{r : PRange sl, su α} :
@@ -422,6 +453,6 @@ theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEn
intro hu
have hl := SupportsLowerBound.isSatisfied_init? (bound := r.lower)
(Option.some_get hi).symm
exact h ((BoundedUpwardEnumerable.init? r.lower).get hi) hl, hu
exact h ((init? r.lower).get hi) hl, hu
end Std.PRange

View File

@@ -6,8 +6,11 @@ Authors: Paul Reichert
module
prelude
public import Init.Data.Nat.Lemmas
public import Init.Data.Range.Polymorphic.Basic
import Init.Data.Nat.Lemmas
public import Init.Data.Nat.Order
public import Init.Data.Range.Polymorphic.Instances
public import Init.Data.Order.Classes
import Init.Data.Order.Lemmas
public section
@@ -20,6 +23,10 @@ instance : UpwardEnumerable Nat where
instance : Least? Nat where
least? := some 0
instance : LawfulUpwardEnumerableLeast? Nat where
least?_le a := by
simpa [Least?.least?] using a, by simp [UpwardEnumerable.succMany?]
instance : LawfulUpwardEnumerableLE Nat where
le_iff a b := by
constructor
@@ -30,98 +37,29 @@ instance : LawfulUpwardEnumerableLE Nat where
rw [ hn]
exact Nat.le_add_right _ _
instance : LawfulUpwardEnumerableLT Nat where
lt_iff a b := by
constructor
· intro h
refine b - a - 1, ?_
simp [UpwardEnumerable.succMany?]
rw [Nat.sub_add_cancel, Nat.add_sub_cancel']
· exact Nat.le_of_lt h
· rwa [Nat.lt_iff_add_one_le, Nat.le_sub_iff_add_le'] at h
exact Nat.le_trans (Nat.le_succ _) h
· rintro n, hn
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
rw [ hn]
apply Nat.lt_add_of_pos_right
apply Nat.zero_lt_succ
instance : LawfulUpwardEnumerable Nat where
succMany?_zero := by simp [UpwardEnumerable.succMany?]
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
ne_of_lt a b hlt := by
rw [ LawfulUpwardEnumerableLT.lt_iff] at hlt
exact Nat.ne_of_lt hlt
have hn := hlt.choose_spec
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
omega
instance : LawfulUpwardEnumerableLowerBound .closed Nat where
isSatisfied_iff a l := by
simp [ LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
SupportsLowerBound.IsSatisfied]
instance : LawfulUpwardEnumerableUpperBound .closed Nat where
isSatisfied_of_le u a b hub hab := by
rw [ LawfulUpwardEnumerableLE.le_iff] at hab
exact Nat.le_trans hab hub
instance : LawfulUpwardEnumerableLowerBound .open Nat where
isSatisfied_iff a l := by
simp [ LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
SupportsLowerBound.IsSatisfied, UpwardEnumerable.succ?, Nat.lt_iff_add_one_le]
instance : LawfulUpwardEnumerableUpperBound .open Nat where
isSatisfied_of_le u a b hub hab := by
rw [ LawfulUpwardEnumerableLE.le_iff] at hab
exact Nat.lt_of_le_of_lt hab hub
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat where
isSatisfied_iff a l := by
simp [ LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
SupportsLowerBound.IsSatisfied, Least?.least?]
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat where
isSatisfied_of_le _ _ _ _ _ := .intro
instance : LinearlyUpwardEnumerable Nat where
eq_of_succ?_eq a b := by simp [UpwardEnumerable.succ?]
instance : LawfulUpwardEnumerableLT Nat := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed Nat := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed Nat := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open Nat := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open Nat := inferInstance
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat := inferInstance
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat := inferInstance
instance : InfinitelyUpwardEnumerable Nat where
isSome_succ? a := by simp [UpwardEnumerable.succ?]
private def rangeRev (k : Nat) :=
match k with
| 0 => []
| k + 1 => k :: rangeRev k
private theorem mem_rangeRev {k l : Nat} (h : l < k) : l rangeRev k := by
induction k
case zero => cases h
case succ k ih =>
rw [rangeRev]
by_cases hl : l = k
· simp [hl]
· apply List.mem_cons_of_mem
exact ih (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ h) hl)
@[no_expose]
instance : HasFiniteRanges .closed Nat where
finite init u := by
refine u - init + 1, ?_
simp only [UpwardEnumerable.succMany?, SupportsUpperBound.IsSatisfied, Nat.not_le,
Option.elim_some]
omega
@[no_expose]
instance : HasFiniteRanges .open Nat where
finite init u := by
refine u - init, ?_
simp only [UpwardEnumerable.succMany?, SupportsUpperBound.IsSatisfied, Option.elim_some]
omega
instance : RangeSize .closed Nat where
size bound a := bound + 1 - a
instance : RangeSize .open Nat where
size bound a := bound - a
instance : RangeSize .open Nat := .openOfClosed
instance : LawfulRangeSize .closed Nat where
size_eq_zero_of_not_isSatisfied upperBound init hu := by
@@ -135,17 +73,16 @@ instance : LawfulRangeSize .closed Nat where
Option.some.injEq] at hu h
omega
instance : LawfulRangeSize .open Nat where
size_eq_zero_of_not_isSatisfied upperBound init hu := by
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size] at hu
omega
size_eq_one_of_succ?_eq_none upperBound init hu h := by
simp only [UpwardEnumerable.succ?] at h
cases h
size_eq_succ_of_succ?_eq_some upperBound init hu h := by
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size, UpwardEnumerable.succ?,
Option.some.injEq] at hu h
omega
instance : LawfulRangeSize .open Nat := inferInstance
instance : HasFiniteRanges .closed Nat := inferInstance
instance : HasFiniteRanges .open Nat := inferInstance
instance : LinearlyUpwardEnumerable Nat := by
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
/-!
The following instances are used for the implementation of array slices a.k.a. `Subarray`.
See also `Init.Data.Slice.Array`.
-/
instance : ClosedOpenIntersection .open, .open Nat where
intersection r s := PRange.mk (max (r.lower + 1) s.lower) (min r.upper s.upper)

View File

@@ -13,13 +13,16 @@ public section
namespace Std.PRange.Nat
theorem succ_eq {n : Nat} : UpwardEnumerable.succ n = n + 1 :=
theorem succ_eq {n : Nat} : succ n = n + 1 :=
rfl
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
((m+1)...(n+1)).toList =
(m...n).toList.map (· + 1) := by
theorem toList_Rco_succ_succ {m n : Nat} :
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := by
simp only [ succ_eq]
rw [Std.PRange.ClosedOpen.toList_succ_succ_eq_map]
rw [Std.PRange.toList_Rco_succ_succ_eq_map]
@[deprecated toList_Rco_succ_succ (since := "2025-08-22")]
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := toList_Rco_succ_succ
end Std.PRange.Nat

View File

@@ -53,14 +53,16 @@ A range of elements of some type `α`. It is characterized by its upper and lowe
may be inclusive, exclusive or absent.
* `a...=b` is the range of elements greater than or equal to `a` and less than or equal to `b`.
* `a<...=b` is the range of elements greater than `a` and less than or equal to `b`.
* `a...b` or `a...<b` is the range of elements greater than or equal to `a` and less than `b`.
* `a...*` is the range of elements greater than or equal to `a`.
* `a<...=b` is the range of elements greater than `a` and less than or equal to `b`.
* `a<...b` or `a<...<b` is the range of elements greater than `a` and less than `b`.
* `a<...*` is the range of elements greater than `a`.
* `*...=b` is the range of elements less than or equal to `b`.
* `*...b` or `*...<b` is the range of elements less than `b`.
* `a...*` is the range of elements greater than or equal to `a`.
* `a<...*` is the range of elements greater than `a`.
* `*...*` contains all elements of `α`.
The recommended spelling for these ranges can be found in the `PRange.mk` constructor's docstring.
-/
structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
/-- The lower bound of the range. -/
@@ -68,6 +70,14 @@ structure _root_.Std.PRange (shape : RangeShape) (α : Type u) where
/-- The upper bound of the range. -/
upper : Bound shape.upper α
/--
Creates a new range. For more information about ranges, see `Std.PRange`.
The implicit `shape` parameter specifies the shape of the explicitly given
lower and upper bounds.
-/
add_decl_doc _root_.Std.PRange.mk
/-- `a...*` is the range of elements greater than or equal to `a`. See also `Std.PRange`. -/
syntax:max (term "...*") : term
/-- `*...*` is the range that is unbounded in both directions. See also `Std.PRange`. -/
@@ -125,6 +135,27 @@ macro_rules
| `($a<...<$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
| `($a<...$b) => ``(PRange.mk (shape := RangeShape.mk BoundShape.open BoundShape.open) $a $b)
recommended_spelling "Rcc" for "a...=b" in [PRange.mk, «term_...=_»]
recommended_spelling "Rco" for "a...b" in [PRange.mk, «term_..._», «term_...<_»]
recommended_spelling "Rco" for "a...<b" in [«term_...<_»]
recommended_spelling "Rci" for "a...*" in [PRange.mk, «term_...*»]
recommended_spelling "Roc" for "a<...=b" in [PRange.mk, «term_<...=_»]
recommended_spelling "Roo" for "a<...b" in [PRange.mk, «term_<..._», «term_<...<_»]
recommended_spelling "Roo" for "a<...<b" in [«term_<...<_»]
recommended_spelling "Roi" for "a<...*" in [PRange.mk, «term_<...*»]
recommended_spelling "Ric" for "*...=b" in [PRange.mk, «term*...=_»]
recommended_spelling "Rio" for "*...b" in [PRange.mk, «term*..._», «term*...<_»]
recommended_spelling "Rio" for "*...<b" in [«term*...<_»]
recommended_spelling "Rii" for "*...*" in [PRange.mk, «term*...*»]
recommended_spelling "Rcx" for "PRange.mk .closed ub" in [PRange.mk]
recommended_spelling "Rox" for "PRange.mk .open ub" in [PRange.mk]
recommended_spelling "Rix" for "PRange.mk .unbounded ub" in [PRange.mk]
recommended_spelling "Rxc" for "PRange.mk lb .closed" in [PRange.mk]
recommended_spelling "Rxo" for "PRange.mk lb .open" in [PRange.mk]
recommended_spelling "Rxi" for "PRange.mk lb .unbounded" in [PRange.mk]
recommended_spelling "Rxx" for "PRange.mk lb ub" in [PRange.mk]
/--
This typeclass provides decidable lower bound checks of the given shape.
@@ -138,6 +169,8 @@ class SupportsLowerBound (shape : BoundShape) (α : Type u) where
IsSatisfied : Bound shape α α Prop
decidableSatisfiesLowerBound : DecidableRel IsSatisfied := by infer_instance
attribute [simp] SupportsLowerBound.IsSatisfied
instance : SupportsLowerBound .unbounded α where
IsSatisfied _ _ := True
@@ -154,6 +187,8 @@ class SupportsUpperBound (shape : BoundShape) (α : Type u) where
IsSatisfied : Bound shape α α Prop
decidableSatisfiesUpperBound : DecidableRel IsSatisfied := by infer_instance
attribute [simp] SupportsUpperBound.IsSatisfied
instance {α} : SupportsUpperBound .unbounded α where
IsSatisfied _ _ := True
@@ -192,6 +227,9 @@ Instances are automatically generated in the following cases:
class BoundedUpwardEnumerable (lowerBoundShape : BoundShape) (α : Type u) where
init? : Bound lowerBoundShape α Option α
attribute [simp] BoundedUpwardEnumerable.init?
export BoundedUpwardEnumerable (init?)
/--
This typeclass ensures that the lower bound predicate from `SupportsLowerBound sl α`
can be characterized in terms of `UpwardEnumerable α` and `BoundedUpwardEnumerable sl α`.
@@ -200,11 +238,10 @@ class LawfulUpwardEnumerableLowerBound (sl α) [UpwardEnumerable α]
[SupportsLowerBound sl α] [BoundedUpwardEnumerable sl α] where
/--
An element `a` satisfies the lower bound `l` if and only if it is
`BoundedUpwardEnumerable.init? l` or one of its transitive successors.
`init? l` or one of its transitive successors.
-/
isSatisfied_iff (a : α) (l : Bound sl α) :
SupportsLowerBound.IsSatisfied l a
init, BoundedUpwardEnumerable.init? l = some init UpwardEnumerable.LE init a
SupportsLowerBound.IsSatisfied l a init, init? l = some init UpwardEnumerable.LE init a
/--
This typeclass ensures that if `b` is a transitive successor of `a` and `b` satisfies an upper bound

View File

@@ -251,14 +251,14 @@ private def RangeIterator.instFinitenessRelation [UpwardEnumerable α] [Supports
obtain n, hn := HasFiniteRanges.finite init bound
induction n generalizing init with
| zero =>
simp only [UpwardEnumerable.succMany?_zero, Option.elim_some] at hn
simp only [succMany?_zero, Option.elim_some] at hn
constructor
simp [hn, IterStep.successor]
| succ n ih =>
constructor
rintro it'
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
match hs : UpwardEnumerable.succ? init with
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at hn
match hs : succ? init with
| none =>
simp only [hs]
intro h
@@ -316,7 +316,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
· split <;> rename_i heq
· apply IterM.IsPlausibleNthOutputStep.done
simp only [Monadic.isPlausibleStep_iff, Monadic.step]
simp only [Option.bind_eq_none_iff, UpwardEnumerable.succMany?_zero, reduceCtorEq,
simp only [Option.bind_eq_none_iff, succMany?_zero, reduceCtorEq,
imp_false] at heq
cases heq' : it.internalState.next
· simp
@@ -325,7 +325,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
exact heq _ rfl
· cases heq' : it.internalState.next
· simp [heq'] at heq
simp only [heq', Option.bind_some, UpwardEnumerable.succMany?_zero, Option.some.injEq] at heq
simp only [heq', Option.bind_some, succMany?_zero, Option.some.injEq] at heq
cases heq
split <;> rename_i heq''
· apply IterM.IsPlausibleNthOutputStep.zero_yield
@@ -338,7 +338,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
· apply IterM.IsPlausibleNthOutputStep.done
simp only [Monadic.isPlausibleStep_iff, Monadic.step, heq']
· rename_i out
simp only [heq', Option.bind_some, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
simp only [heq', Option.bind_some, succMany?_succ?_eq_succ?_bind_succMany?] at heq
specialize ih UpwardEnumerable.succ? out, it.internalState.upperBound
simp only [heq] at ih
by_cases heq'' : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
@@ -354,7 +354,7 @@ instance RangeIterator.instIteratorAccess {su} [UpwardEnumerable α] [SupportsUp
rename_i out
simp only [heq', Option.bind_some] at heq
have hle : UpwardEnumerable.LE out _ := n + 1, heq
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at heq
simp only [succMany?_succ?_eq_succ?_bind_succMany?] at heq
specialize ih UpwardEnumerable.succ? out, it.internalState.upperBound
simp only [heq] at ih
by_cases hout : SupportsUpperBound.IsSatisfied it.internalState.upperBound out
@@ -378,7 +378,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
{it : IterM (α := RangeIterator su α) Id α} {out : α} :
it.IsPlausibleIndirectOutput out
n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out
n, it.internalState.next.bind (succMany? n ·) = some out
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
constructor
· intro h
@@ -391,7 +391,7 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
obtain n, hn := ih
obtain a, ha, h₁, h₂, h₃ := h
refine n + 1, ?_
simp [ha, h₃, hn.2, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h₂, hn]
simp [ha, h₃, hn.2, succMany?_succ?_eq_succ?_bind_succMany?, h₂, hn]
· rintro n, hn, hu
induction n generalizing it
case zero =>
@@ -404,8 +404,8 @@ theorem RangeIterator.Monadic.isPlausibleIndirectOutput_iff {su α}
rename_i a
simp only [hn', Option.bind_some] at hn
have hle : UpwardEnumerable.LE a out := _, hn
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
cases hn' : UpwardEnumerable.succ? a
rw [succMany?_succ?_eq_succ?_bind_succMany?] at hn
cases hn' : succ? a
· simp only [hn', Option.bind_none, reduceCtorEq] at hn
rename_i a'
simp only [hn', Option.bind_some] at hn
@@ -422,7 +422,7 @@ theorem RangeIterator.isPlausibleIndirectOutput_iff {su α}
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
{it : Iter (α := RangeIterator su α) α} {out : α} :
it.IsPlausibleIndirectOutput out
n, it.internalState.next.bind (UpwardEnumerable.succMany? n ·) = some out
n, it.internalState.next.bind (succMany? n ·) = some out
SupportsUpperBound.IsSatisfied it.internalState.upperBound out := by
simp only [Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM,
Monadic.isPlausibleIndirectOutput_iff, Iter.toIterM]
@@ -476,7 +476,7 @@ instance RangeIterator.instIteratorLoop {su} [UpwardEnumerable α] [SupportsUppe
exact UpwardEnumerable.le_refl _
case hle' =>
refine UpwardEnumerable.le_trans hl 1, ?_
simp [UpwardEnumerable.succMany?_one, hs]
simp [succMany?_one, hs]
partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
@@ -496,7 +496,7 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
(next : α) (hl : UpwardEnumerable.LE least next) (hu : SupportsUpperBound.IsSatisfied upperBound next) : n γ := do
match f next hl hu acc with
| .yield acc' =>
match hs : UpwardEnumerable.succ? next with
match hs : succ? next with
| some next' =>
if hu : SupportsUpperBound.IsSatisfied upperBound next' then
loop γ upperBound least acc' f next' ?hle' hu
@@ -513,10 +513,10 @@ partial instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable
exact UpwardEnumerable.le_refl _
case hle' =>
refine UpwardEnumerable.le_trans hl 1, ?_
simp [UpwardEnumerable.succMany?_one, hs]
simp [succMany?_one, hs]
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α] [SupportsUpperBound su α]
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableUpperBound su α]
{n : Type u Type w} [Monad n] [LawfulMonad n] {γ : Type u}
{lift} [Internal.LawfulMonadLiftBindFunction lift]
{PlausibleForInStep} {upperBound} {next} {hl} {hu} {f} {acc} {wf} :
@@ -524,16 +524,18 @@ theorem RangeIterator.instIteratorLoop.loop_eq {su} [UpwardEnumerable α] [Suppo
(do
match f next hl hu acc with
| .yield c, _ =>
letI it' : IterM (α := RangeIterator su α) Id α := UpwardEnumerable.succ? next, upperBound
letI it' : IterM (α := RangeIterator su α) Id α := succ? next, upperBound
IterM.DefaultConsumers.forIn' (m := Id) lift γ
PlausibleForInStep wf it' c it'.IsPlausibleIndirectOutput (fun _ => id)
(fun b h c => f b
(by
refine UpwardEnumerable.le_trans hl ?_
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it',
LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at h
succMany?_succ?_eq_succ?_bind_succMany?] at h
exact h.choose + 1, h.choose_spec.1)
(by simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h; exact h.choose_spec.2) c)
(by
simp only [RangeIterator.Monadic.isPlausibleIndirectOutput_iff, it'] at h
exact h.choose_spec.2) c)
| .done c, _ => return c) := by
rw [loop]
apply bind_congr

View File

@@ -40,13 +40,16 @@ class UpwardEnumerable (α : Type u) where
-/
succMany? (n : Nat) (a : α) : Option α := Nat.repeat (· >>= succ?) n (some a)
attribute [simp] UpwardEnumerable.succ? UpwardEnumerable.succMany?
export UpwardEnumerable (succ? succMany?)
/--
According to `UpwardEnumerable.LE`, `a` is less than or equal to `b` if `b` is `a` or a transitive
successor of `a`.
-/
@[expose]
def UpwardEnumerable.LE {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
n, UpwardEnumerable.succMany? n a = some b
protected def UpwardEnumerable.LE {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
n, succMany? n a = some b
/--
According to `UpwardEnumerable.LT`, `a` is less than `b` if `b` is a proper transitive successor of
@@ -55,10 +58,10 @@ According to `UpwardEnumerable.LT`, `a` is less than `b` if `b` is a proper tran
Given `LawfulUpwardEnumerable α`, no element of `α` is less than itself.
-/
@[expose]
def UpwardEnumerable.LT {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
n, UpwardEnumerable.succMany? (n + 1) a = some b
protected def UpwardEnumerable.LT {α : Type u} [UpwardEnumerable α] (a b : α) : Prop :=
n, succMany? (n + 1) a = some b
theorem UpwardEnumerable.le_of_lt {α : Type u} [UpwardEnumerable α] {a b : α}
protected theorem UpwardEnumerable.le_of_lt {α : Type u} [UpwardEnumerable α] {a b : α}
(h : UpwardEnumerable.LT a b) : UpwardEnumerable.LE a b :=
h.choose + 1, h.choose_spec
@@ -77,6 +80,9 @@ class Least? (α : Type u) where
-/
least? : Option α
attribute [simp] Least?.least?
export Least? (least?)
/--
This typeclass ensures that an `UpwardEnumerable α` instance is well-behaved.
-/
@@ -84,99 +90,110 @@ class LawfulUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
/-- There is no cyclic chain of successors. -/
ne_of_lt (a b : α) : UpwardEnumerable.LT a b a b
/-- The `0`-th successor of `a` is `a` itself. -/
succMany?_zero (a : α) : UpwardEnumerable.succMany? 0 a = some a
succMany?_zero (a : α) : succMany? 0 a = some a
/--
The `n + 1`-th successor of `a` is the successor of the `n`-th successor, given that said
successors actually exist.
-/
succMany?_succ (n : Nat) (a : α) :
UpwardEnumerable.succMany? (n + 1) a = (UpwardEnumerable.succMany? n a).bind UpwardEnumerable.succ?
succMany? (n + 1) a = (succMany? n a).bind succ?
theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
UpwardEnumerable.succMany? 0 a = some a :=
succMany? 0 a = some a :=
LawfulUpwardEnumerable.succMany?_zero a
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]
theorem UpwardEnumerable.succMany?_succ? [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{n : Nat} {a : α} :
UpwardEnumerable.succMany? (n + 1) a =
(UpwardEnumerable.succMany? n a).bind UpwardEnumerable.succ? :=
succMany? (n + 1) a = (succMany? n a).bind succ? :=
LawfulUpwardEnumerable.succMany?_succ n a
@[deprecated succMany?_succ? (since := "2025-09-03")]
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{n : Nat} {a : α} :
succMany? (n + 1) a = (succMany? n a).bind succ? :=
succMany?_succ?
theorem UpwardEnumerable.succMany?_one [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
UpwardEnumerable.succMany? 1 a = UpwardEnumerable.succ? a := by
simp [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero]
succMany? 1 a = succ? a := by
simp [succMany?_succ?, succMany?_zero]
theorem UpwardEnumerable.succMany?_add [UpwardEnumerable α] [LawfulUpwardEnumerable α]
(m n : Nat) (a : α) :
UpwardEnumerable.succMany? (m + n) a =
(UpwardEnumerable.succMany? m a).bind (UpwardEnumerable.succMany? n ·) := by
{m n : Nat} {a : α} :
succMany? (m + n) a = (succMany? m a).bind (succMany? n ·) := by
induction n
case zero => simp [LawfulUpwardEnumerable.succMany?_zero]
case zero => simp [succMany?_zero]
case succ n ih =>
rw [ Nat.add_assoc, LawfulUpwardEnumerable.succMany?_succ, ih, Option.bind_assoc]
simp only [LawfulUpwardEnumerable.succMany?_succ]
rw [ Nat.add_assoc, succMany?_succ?, ih, Option.bind_assoc]
simp [succMany?_succ?]
theorem UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?
[UpwardEnumerable α] [LawfulUpwardEnumerable α]
{n : Nat} {a : α} :
succMany? (n + 1) a = (succ? a).bind (succMany? n ·) := by
rw [Nat.add_comm]
simp [succMany?_add, succMany?_succ?, succMany?_zero]
@[deprecated UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany? (since := "2025-09-03")]
theorem LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?
[UpwardEnumerable α] [LawfulUpwardEnumerable α]
(n : Nat) (a : α) :
UpwardEnumerable.succMany? (n + 1) a =
(UpwardEnumerable.succ? a).bind (UpwardEnumerable.succMany? n ·) := by
rw [Nat.add_comm]
simp [UpwardEnumerable.succMany?_add, LawfulUpwardEnumerable.succMany?_succ,
LawfulUpwardEnumerable.succMany?_zero]
succMany? (n + 1) a = (succ? a).bind (succMany? n ·) :=
UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?
theorem UpwardEnumerable.le_refl {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
(a : α) : UpwardEnumerable.LE a a :=
0, LawfulUpwardEnumerable.succMany?_zero a
export UpwardEnumerable (succMany?_zero succMany?_succ? succMany?_one succMany?_add
succMany?_succ?_eq_succ?_bind_succMany?)
theorem UpwardEnumerable.lt_irrefl {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a : α} : ¬ UpwardEnumerable.LT a a :=
protected theorem UpwardEnumerable.le_refl {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] (a : α) : UpwardEnumerable.LE a a :=
0, succMany?_zero
protected theorem UpwardEnumerable.lt_irrefl {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a : α} : ¬ UpwardEnumerable.LT a a :=
fun h => LawfulUpwardEnumerable.ne_of_lt a a h rfl
theorem UpwardEnumerable.le_trans {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LE b c) :
UpwardEnumerable.LE a c := by
protected theorem UpwardEnumerable.ne_of_lt {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a b : α} (h : UpwardEnumerable.LT a b) : a b :=
LawfulUpwardEnumerable.ne_of_lt a b h
protected theorem UpwardEnumerable.le_trans {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LE a b)
(hbc : UpwardEnumerable.LE b c) : UpwardEnumerable.LE a c := by
refine hab.choose + hbc.choose, ?_
simp [succMany?_add, hab.choose_spec, hbc.choose_spec]
theorem UpwardEnumerable.le_of_succ?_eq {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b : α} (hab : UpwardEnumerable.succ? a = some b) : UpwardEnumerable.LE a b :=
1, by simp [UpwardEnumerable.succMany?_one, hab]
1, by simp [succMany?_one, hab]
theorem UpwardEnumerable.lt_of_lt_of_le {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b c : α} (hab : UpwardEnumerable.LT a b) (hbc : UpwardEnumerable.LE b c) :
UpwardEnumerable.LT a c := by
protected theorem UpwardEnumerable.lt_of_lt_of_le {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LT a b)
(hbc : UpwardEnumerable.LE b c) : UpwardEnumerable.LT a c := by
refine hab.choose + hbc.choose, ?_
rw [Nat.add_right_comm, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
theorem UpwardEnumerable.lt_of_le_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LT b c) :
UpwardEnumerable.LT a c := by
protected theorem UpwardEnumerable.lt_of_le_of_lt {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a b c : α} (hab : UpwardEnumerable.LE a b)
(hbc : UpwardEnumerable.LT b c) : UpwardEnumerable.LT a c := by
refine hab.choose + hbc.choose, ?_
rw [Nat.add_assoc, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b : α} :
protected theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a b : α} :
UpwardEnumerable.LE a b ¬ UpwardEnumerable.LT b a := by
rintro n, hle m, hgt
have : UpwardEnumerable.LT a a := by
refine n + m, ?_
rw [Nat.add_assoc, UpwardEnumerable.succMany?_add, hle, Option.bind_some, hgt]
exact LawfulUpwardEnumerable.ne_of_lt _ _ this rfl
rw [Nat.add_assoc, succMany?_add, hle, Option.bind_some, hgt]
exact UpwardEnumerable.ne_of_lt this rfl
theorem UpwardEnumerable.not_ge_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b : α} :
protected theorem UpwardEnumerable.not_ge_of_lt {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a b : α} :
UpwardEnumerable.LT a b ¬ UpwardEnumerable.LE b a :=
flip not_gt_of_le
flip UpwardEnumerable.not_gt_of_le
theorem UpwardEnumerable.not_gt_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b : α} (h : UpwardEnumerable.LT a b) : ¬ UpwardEnumerable.LT b a :=
not_gt_of_le (le_of_lt h)
theorem UpwardEnumerable.ne_of_lt {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{a b : α} :
UpwardEnumerable.LT a b a b :=
LawfulUpwardEnumerable.ne_of_lt a b
protected theorem UpwardEnumerable.not_gt_of_lt {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {a b : α} (h : UpwardEnumerable.LT a b) : ¬ UpwardEnumerable.LT b a :=
UpwardEnumerable.not_gt_of_le (UpwardEnumerable.le_of_lt h)
/--
This propositional typeclass ensures that `UpwardEnumerable.succ?` will never return `none`.
@@ -192,15 +209,23 @@ class LinearlyUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
eq_of_succ?_eq : a b : α, UpwardEnumerable.succ? a = UpwardEnumerable.succ? b a = b
theorem UpwardEnumerable.isSome_succ? {α : Type u} [UpwardEnumerable α]
[InfinitelyUpwardEnumerable α] {a : α} :
(succ? a).isSome :=
[InfinitelyUpwardEnumerable α] {a : α} : (succ? a).isSome :=
InfinitelyUpwardEnumerable.isSome_succ? a
theorem UpwardEnumerable.eq_of_succ?_eq {α : Type u} [UpwardEnumerable α]
[LinearlyUpwardEnumerable α] {a b : α} (h : succ? a = succ? b) :
theorem UpwardEnumerable.succ?_inj {α : Type u} [UpwardEnumerable α] [LinearlyUpwardEnumerable α]
{a b : α} (h : succ? a = succ? b) :
a = b :=
LinearlyUpwardEnumerable.eq_of_succ?_eq a b h
@[deprecated succ?_inj (since := "2025-09-03")]
theorem UpwardEnumerable.eq_of_succ?_eq {α : Type u} [UpwardEnumerable α] [LinearlyUpwardEnumerable α]
{a b : α} (h : succ? a = succ? b) :
a = b :=
succ?_inj h
/--
Maps elements of `α` to their immediate successor.
-/
@[always_inline, inline]
abbrev UpwardEnumerable.succ {α : Type u} [UpwardEnumerable α] [InfinitelyUpwardEnumerable α]
(a : α) : α :=
@@ -216,17 +241,23 @@ theorem UpwardEnumerable.succ?_eq_some {α : Type u} [UpwardEnumerable α]
succ? a = some (succ a) := by
simp
theorem UpwardEnumerable.eq_of_succ_eq {α : Type u} [UpwardEnumerable α]
theorem UpwardEnumerable.succ_inj {α : Type u} [UpwardEnumerable α]
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α}
(h : succ a = succ b) : a = b := by
rw [succ, succ, Option.some.injEq, Option.some_get, Option.some_get] at h
exact eq_of_succ?_eq h
exact succ?_inj h
@[deprecated succ_inj (since := "2025-09-03")]
theorem UpwardEnumerable.eq_of_succ_eq {α : Type u} [UpwardEnumerable α]
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α}
(h : succ a = succ b) : a = b :=
succ_inj h
theorem UpwardEnumerable.succ_eq_succ_iff {α : Type u} [UpwardEnumerable α]
[InfinitelyUpwardEnumerable α] [LinearlyUpwardEnumerable α] {a b : α} :
succ a = succ b a = b := by
constructor
· apply eq_of_succ_eq
· apply succ_inj
· exact congrArg succ
theorem UpwardEnumerable.isSome_succMany? {α : Type u} [UpwardEnumerable α]
@@ -235,10 +266,19 @@ theorem UpwardEnumerable.isSome_succMany? {α : Type u} [UpwardEnumerable α]
induction n
· simp [succMany?_zero]
· rename_i ih
simp only [succMany?_succ]
simp only [succMany?_succ?]
rw [ Option.some_get ih, Option.bind_some]
apply InfinitelyUpwardEnumerable.isSome_succ?
/--
Maps elements of `α` to their `n`-th successor. This should semantically behave like repeatedly
applying `succ`, but it might be more efficient.
This function uses an `UpwardEnumerable α` instance.
`LawfulUpwardEnumerable α` ensures the compatibility with `succ` and `succ?`.
If no other implementation is provided in UpwardEnumerable instance, succMany? repeatedly applies succ?.
-/
@[always_inline, inline]
def UpwardEnumerable.succMany {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
@@ -260,6 +300,11 @@ theorem UpwardEnumerable.succMany?_eq_some_iff_succMany {α : Type u} [UpwardEnu
succMany? n a = some b succMany n a = b := by
simp [succMany?_eq_some]
theorem UpwardEnumerable.succMany_zero {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a : α} :
succMany 0 a = a := by
simp [succMany, succMany?_zero]
theorem UpwardEnumerable.succMany_one {α : Type u} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a : α} :
succMany 1 a = succ a := by
@@ -270,43 +315,49 @@ theorem UpwardEnumerable.succMany_add {α : Type u} [UpwardEnumerable α]
{m n : Nat} {a : α} : succMany (m + n) a = succMany n (succMany m a) := by
simp [succMany, succMany?_add]
theorem UpwardEnumerable.succ_le_succ_iff {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a b : α} :
UpwardEnumerable.LE (UpwardEnumerable.succ a) (UpwardEnumerable.succ b)
export UpwardEnumerable (isSome_succ? succ?_inj succ succ_eq_get succ?_eq_some succ_inj
succ_eq_succ_iff isSome_succMany? succMany succMany_eq_get
succMany?_eq_some succMany?_eq_some_iff_succMany succMany_one succMany_zero
succMany_add)
theorem UpwardEnumerable.succ_le_succ_iff {α : Type w} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
{a b : α} : UpwardEnumerable.LE (succ a) (succ b)
UpwardEnumerable.LE a b := by
constructor
· rintro n, hn
simp only [succ] at hn
refine n, ?_
simp [succMany?_eq_some]
apply eq_of_succ?_eq
apply succ?_inj
rw [ Option.bind_some (f := succMany? n), Option.some_get,
LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, Option.some_get] at hn
rw [ Option.bind_some (f := succ?), succMany?_eq_some, succMany?_succ, hn]
succMany?_succ?_eq_succ?_bind_succMany?, Option.some_get] at hn
rw [ Option.bind_some (f := succ?), succMany?_eq_some, succMany?_succ?, hn]
· rintro n, hn
refine n, ?_
rw [succ_eq_get, succ_eq_get, Option.bind_some (f := succMany? n), Option.some_get,
Option.some_get, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?,
succMany?_succ, hn, Option.bind_some]
Option.some_get, succMany?_succ?_eq_succ?_bind_succMany?,
succMany?_succ?, hn, Option.bind_some]
theorem UpwardEnumerable.succ_lt_succ_iff {α : Type w} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] {a b : α} :
UpwardEnumerable.LT (UpwardEnumerable.succ a) (UpwardEnumerable.succ b)
theorem UpwardEnumerable.succ_lt_succ_iff {α : Type w} [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α]
{a b : α} :
UpwardEnumerable.LT (succ a) (succ b)
UpwardEnumerable.LT a b := by
constructor
· rintro n, hn
simp only [succ] at hn
refine n, ?_
rw [succMany?_eq_some_iff_succMany]
apply eq_of_succ?_eq
apply succ?_inj
rw [ Option.bind_some (f := succMany? _), Option.some_get,
LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, Option.some_get] at hn
rw [ Option.bind_some (f := succ?), succMany?_eq_some, succMany?_succ, hn]
succMany?_succ?_eq_succ?_bind_succMany?, Option.some_get] at hn
rw [ Option.bind_some (f := succ?), succMany?_eq_some, succMany?_succ?, hn]
· rintro n, hn
refine n, ?_
rw [succ_eq_get, succ_eq_get, Option.bind_some (f := succMany? _), Option.some_get,
Option.some_get, LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?,
succMany?_succ, hn, Option.bind_some]
Option.some_get, succMany?_succ?_eq_succ?_bind_succMany?, succMany?_succ?, hn,
Option.bind_some]
/--
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with `≤`.
@@ -317,7 +368,11 @@ class LawfulUpwardEnumerableLE (α : Type u) [UpwardEnumerable α] [LE α] where
`a` is less than or equal to `b` if and only if `b` is either `a` or a transitive successor
of `a`.
-/
le_iff (a b : α) : a b UpwardEnumerable.LE a b
protected le_iff (a b : α) : a b UpwardEnumerable.LE a b
protected theorem UpwardEnumerable.le_iff {α : Type u} [LE α] [UpwardEnumerable α]
[LawfulUpwardEnumerableLE α] {a b : α} : a b UpwardEnumerable.LE a b :=
LawfulUpwardEnumerableLE.le_iff a b
/--
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with `<`.
@@ -329,6 +384,10 @@ class LawfulUpwardEnumerableLT (α : Type u) [UpwardEnumerable α] [LT α] where
-/
lt_iff (a b : α) : a < b UpwardEnumerable.LT a b
protected theorem UpwardEnumerable.lt_iff {α : Type u} [LT α] [UpwardEnumerable α]
[LawfulUpwardEnumerableLT α] {a b : α} : a < b UpwardEnumerable.LT a b :=
LawfulUpwardEnumerableLT.lt_iff a b
/--
This typeclass ensures that an `UpwardEnumerable α` instance is compatible with a `Least? α`
instance. For nonempty `α`, it ensures that `least?` has a value and that every other value is
@@ -336,6 +395,11 @@ a transitive successor of it.
-/
class LawfulUpwardEnumerableLeast? (α : Type u) [UpwardEnumerable α] [Least? α] where
/-- For nonempty `α`, `least?` has a value and every other value is a transitive successor of it. -/
eq_succMany?_least? (a : α) : init, Least?.least? = some init UpwardEnumerable.LE init a
least?_le (a : α) : init, Least?.least? = some init UpwardEnumerable.LE init a
theorem UpwardEnumerable.least?_le {α : Type u} [UpwardEnumerable α] [Least? α]
[LawfulUpwardEnumerableLeast? α] {a : α} :
init, least? = some init UpwardEnumerable.LE init a :=
LawfulUpwardEnumerableLeast?.least?_le a
end Std.PRange

View File

@@ -356,7 +356,7 @@ Returns the decimal string representation of an integer.
-/
protected def Int.repr : Int String
| ofNat m => Nat.repr m
| negSucc m => "-" ++ Nat.repr (succ m)
| negSucc m => String.Internal.append "-" (Nat.repr (succ m))
instance : Repr Int where
reprPrec i prec := if i < 0 then Repr.addAppParen i.repr prec else i.repr
@@ -370,14 +370,14 @@ def Char.quoteCore (c : Char) (inString : Bool := false) : String :=
else if c = '\\' then "\\\\"
else if c = '\"' then "\\\""
else if !inString && c = '\'' then "\\\'"
else if c.toNat <= 31 c = '\x7f' then "\\x" ++ smallCharToHex c
else if c.toNat <= 31 c = '\x7f' then String.Internal.append "\\x" (smallCharToHex c)
else String.singleton c
where
smallCharToHex (c : Char) : String :=
let n := Char.toNat c;
let d2 := n / 16;
let d1 := n % 16;
hexDigitRepr d2 ++ hexDigitRepr d1
String.Internal.append (hexDigitRepr d2) (hexDigitRepr d1)
/--
Quotes the character to its representation as a character literal, surrounded by single quotes and
@@ -388,7 +388,7 @@ Examples:
* `'"'.quote = "'\\\"'"`
-/
def Char.quote (c : Char) : String :=
"'" ++ Char.quoteCore c ++ "'"
String.Internal.append (String.Internal.append "'" (Char.quoteCore c)) "'"
instance : Repr Char where
reprPrec c _ := c.quote
@@ -405,8 +405,8 @@ Examples:
* `"\"".quote = "\"\\\"\""`
-/
def String.quote (s : String) : String :=
if s.isEmpty then "\"\""
else s.foldl (fun s c => s ++ c.quoteCore (inString := true)) "\"" ++ "\""
if String.Internal.isEmpty s then "\"\""
else String.Internal.append (String.Internal.foldl (fun s c => String.Internal.append s (c.quoteCore (inString := true))) "\"" s) "\""
instance : Repr String where
reprPrec s _ := s.quote
@@ -415,10 +415,7 @@ instance : Repr String.Pos where
reprPrec p _ := "{ byteIdx := " ++ repr p.byteIdx ++ " }"
instance : Repr Substring where
reprPrec s _ := Format.text <| String.quote s.toString ++ ".toSubstring"
instance : Repr String.Iterator where
reprPrec | s, pos, prec => Repr.addAppParen ("String.Iterator.mk " ++ reprArg s ++ " " ++ reprArg pos) prec
reprPrec s _ := Format.text <| String.Internal.append (String.quote (Substring.Internal.toString s)) ".toSubstring"
instance (n : Nat) : Repr (Fin n) where
reprPrec f _ := repr f.val

View File

@@ -8,6 +8,7 @@ module
prelude
public import Init.Data.Range
public import Init.Data.Array.Subarray
public import Init.Data.String.Basic
import Init.Data.Slice.Array.Basic

View File

@@ -7,7 +7,10 @@ module
prelude
public import Init.Data.String.Basic
public import Init.Data.String.Bootstrap
public import Init.Data.String.Extra
public import Init.Data.String.Lemmas
public import Init.Data.String.Repr
public import Init.Data.String.Bootstrap
public section

View File

@@ -8,22 +8,12 @@ module
prelude
public import Init.Data.List.Basic
public import Init.Data.Char.Basic
public import Init.Data.String.Bootstrap
public section
universe u
/--
Creates a string that contains the characters in a list, in order.
Examples:
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
* `[].asString = ""`
* `['a', 'a', 'a'].asString = "aaa"`
-/
def List.asString (s : List Char) : String :=
s
namespace String
instance : HAdd String.Pos String.Pos String.Pos where
@@ -32,6 +22,10 @@ instance : HAdd String.Pos String.Pos String.Pos where
instance : HSub String.Pos String.Pos String.Pos where
hSub p₁ p₂ := { byteIdx := p₁.byteIdx - p₂.byteIdx }
@[export lean_string_pos_sub]
def Pos.Internal.subImpl : String.Pos String.Pos String.Pos :=
(· - ·)
instance : HAdd String.Pos Char String.Pos where
hAdd p c := { byteIdx := p.byteIdx + c.utf8Size }
@@ -53,9 +47,6 @@ instance (p₁ p₂ : String.Pos) : Decidable (LT.lt p₁ p₂) :=
instance : Min String.Pos := minOfLe
instance : Max String.Pos := maxOfLe
instance : OfNat String.Pos (nat_lit 0) where
ofNat := {}
instance : LT String :=
fun s₁ s₂ => s₁.data < s₂.data
@@ -90,20 +81,6 @@ Examples:
def length : (@& String) Nat
| s => s.length
/--
Adds a character to the end of a string.
The internal implementation uses dynamic arrays and will perform destructive updates
if the string is not shared.
Examples:
* `"abc".push 'd' = "abcd"`
* `"".push 'a' = "a"`
-/
@[extern "lean_string_push", expose]
def push : String Char String
| s, c => s ++ [c]
/--
Appends two strings. Usually accessed via the `++` operator.
@@ -305,6 +282,10 @@ Examples:
@[inline] def front (s : String) : Char :=
get s 0
@[export lean_string_front]
def Internal.frontImpl (s : String) : Char :=
String.front s
/--
Returns the last character in `s`. If `s = ""`, returns `(default : Char)`.
@@ -385,6 +366,10 @@ theorem _root_.Char.utf8Size_pos (c : Char) : 0 < c.utf8Size := by
theorem _root_.Char.utf8Size_le_four (c : Char) : c.utf8Size 4 := by
repeat first | apply iteInduction (motive := (· 4)) <;> intros | decide
theorem _root_.Char.utf8Size_eq (c : Char) : c.utf8Size = 1 c.utf8Size = 2 c.utf8Size = 3 c.utf8Size = 4 := by
match c.utf8Size, c.utf8Size_pos, c.utf8Size_le_four with
| 1, _, _ | 2, _, _ | 3, _, _ | 4, _, _ => simp
@[deprecated Char.utf8Size_pos (since := "2026-06-04")] abbrev one_le_csize := Char.utf8Size_pos
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
@@ -430,6 +415,10 @@ Examples:
@[inline] def posOf (s : String) (c : Char) : Pos :=
posOfAux s c s.endPos 0
@[export lean_string_posof]
def Internal.posOfImpl (s : String) (c : Char) : Pos :=
String.posOf s c
def revPosOfAux (s : String) (c : Char) (pos : Pos) : Option Pos :=
if h : pos = 0 then none
else
@@ -500,6 +489,10 @@ Returns either `p₁` or `p₂`, whichever has the least byte index.
abbrev Pos.min (p₁ p₂ : Pos) : Pos :=
{ byteIdx := p₁.byteIdx.min p₂.byteIdx }
@[export lean_string_pos_min]
def Pos.Internal.minImpl (p₁ p₂ : Pos) : Pos :=
Pos.min p₁ p₂
/--
Returns the first position where the two strings differ.
@@ -660,6 +653,10 @@ Examples:
@[inline] def pushn (s : String) (c : Char) (n : Nat) : String :=
n.repeat (fun s => s.push c) s
@[export lean_string_pushn]
def Internal.pushnImpl (s : String) (c : Char) (n : Nat) : String :=
String.pushn s c n
/--
Checks whether a string is empty.
@@ -673,6 +670,10 @@ Examples:
@[inline] def isEmpty (s : String) : Bool :=
s.endPos == 0
@[export lean_string_isempty]
def Internal.isEmptyImpl (s : String) : Bool :=
String.isEmpty s
/--
Appends all the strings in a list of strings, in order.
@@ -686,20 +687,6 @@ Examples:
@[inline] def join (l : List String) : String :=
l.foldl (fun r s => r ++ s) ""
/--
Returns a new string that contains only the character `c`.
Because strings are encoded in UTF-8, the resulting string may take multiple bytes.
Examples:
* `String.singleton 'L' = "L"`
* `String.singleton ' ' = " "`
* `String.singleton '"' = "\""`
* `String.singleton '𝒫' = "𝒫"`
-/
@[inline,expose] def singleton (c : Char) : String :=
"".push c
/--
Appends the strings in a list of strings, placing the separator `s` between each pair.
@@ -715,6 +702,10 @@ where go (acc : String) (s : String) : List String → String
| a :: as => go (acc ++ s ++ a) s as
| [] => acc
@[export lean_string_intercalate]
def Internal.intercalateImpl (s : String) : List String String :=
String.intercalate s
/--
An iterator over the characters (Unicode code points) in a `String`. Typically created by
`String.iter`.
@@ -926,6 +917,10 @@ Examples:
@[inline] def offsetOfPos (s : String) (pos : Pos) : Nat :=
offsetOfPosAux s pos 0 0
@[export lean_string_offsetofpos]
def Internal.offsetOfPosImpl (s : String) (pos : Pos) : Nat :=
String.offsetOfPos s pos
@[specialize] def foldlAux {α : Type u} (f : α Char α) (s : String) (stopPos : Pos) (i : Pos) (a : α) : α :=
if h : i < stopPos then
have := Nat.sub_lt_sub_left h (lt_next s i)
@@ -945,6 +940,10 @@ Examples:
@[inline] def foldl {α : Type u} (f : α Char α) (init : α) (s : String) : α :=
foldlAux f s s.endPos 0 init
@[export lean_string_foldl]
def Internal.foldlImpl (f : String Char String) (init : String) (s : String) : String :=
String.foldl f init s
@[specialize] def foldrAux {α : Type u} (f : Char α α) (a : α) (s : String) (i begPos : Pos) : α :=
if h : begPos < i then
have := String.prev_lt_of_pos s i <| mt (congrArg String.Pos.byteIdx) <|
@@ -990,6 +989,10 @@ Examples:
@[inline] def any (s : String) (p : Char Bool) : Bool :=
anyAux s s.endPos p 0
@[export lean_string_any]
def Internal.anyImpl (s : String) (p : Char Bool) :=
String.any s p
/--
Checks whether the Boolean predicate `p` returns `true` for every character in a string.
@@ -1012,7 +1015,11 @@ Examples:
* `"".contains 'x' = false`
-/
@[inline] def contains (s : String) (c : Char) : Bool :=
s.any (fun a => a == c)
s.any (fun a => a == c)
@[export lean_string_contains]
def Internal.containsImpl (s : String) (c : Char) : Bool :=
String.contains s c
theorem utf8SetAux_of_gt (c' : Char) : (cs : List Char) {i p : Pos}, i > p utf8SetAux c' cs i p = cs
| [], _, _, _ => rfl
@@ -1155,6 +1162,10 @@ Examples:
def isPrefixOf (p : String) (s : String) : Bool :=
substrEq p 0 s 0 p.endPos.byteIdx
@[export lean_string_isprefixof]
def Internal.isPrefixOfImpl (p : String) (s : String) : Bool :=
String.isPrefixOf p s
/--
In the string `s`, replaces all occurrences of `pattern` with `replacement`.
@@ -1204,12 +1215,20 @@ A substring is empty if its start and end positions are the same.
@[inline] def isEmpty (ss : Substring) : Bool :=
ss.bsize == 0
@[export lean_substring_isempty]
def Internal.isEmptyImpl (ss : Substring) : Bool :=
Substring.isEmpty ss
/--
Copies the region of the underlying string pointed to by a substring into a fresh string.
-/
@[inline] def toString : Substring String
| s, b, e => s.extract b e
@[export lean_substring_tostring]
def Internal.toStringImpl : Substring String :=
Substring.toString
/--
Returns an iterator into the underlying string, at the substring's starting position. The ending
position is discarded, so the iterator alone cannot be used to determine whether its current
@@ -1229,6 +1248,10 @@ returned. Does not panic.
@[inline] def get : Substring String.Pos Char
| s, b, _, p => s.get (b+p)
@[export lean_substring_get]
def Internal.getImpl : Substring String.Pos Char :=
Substring.get
/--
Returns the next position in a substring after the given position. If the position is at the end of
the substring, it is returned unmodified.
@@ -1262,6 +1285,10 @@ position, not the underlying string.
let absP := b+p
if absP = b then p else { byteIdx := (s.prev absP).byteIdx - b.byteIdx }
@[export lean_substring_prev]
def Internal.prevImpl : Substring String.Pos String.Pos :=
Substring.prev
/--
Returns the position that's the specified number of characters forward from the given position in a
substring. If the end position of the substring is reached, it is returned.
@@ -1295,6 +1322,10 @@ returned. Does not panic.
@[inline] def front (s : Substring) : Char :=
s.get 0
@[export lean_substring_front]
def Internal.frontImpl : Substring Char :=
Substring.front
/--
Returns the substring-relative position of the first occurrence of `c` in `s`, or `s.bsize` if `c`
doesn't occur.
@@ -1312,6 +1343,10 @@ If the substring's end position is reached, the start position is not advanced p
@[inline] def drop : Substring Nat Substring
| ss@s, b, e, n => s, b + ss.nextn n 0, e
@[export lean_substring_drop]
def Internal.dropImpl : Substring Nat Substring :=
Substring.drop
/--
Removes the specified number of characters (Unicode code points) from the end of a substring
by moving its end position towards its start position.
@@ -1360,6 +1395,10 @@ positions adjusted.
@[inline] def extract : Substring String.Pos String.Pos Substring
| s, b, e, b', e' => if b' e' then "", 0, 0 else s, e.min (b+b'), e.min (b+e')
@[export lean_substring_extract]
def Internal.extractImpl : Substring String.Pos String.Pos Substring :=
Substring.extract
/--
Splits a substring `s` on occurrences of the separator string `sep`. The default separator is `" "`.
@@ -1426,6 +1465,10 @@ Short-circuits at the first character for which `p` returns `false`.
@[inline] def all (s : Substring) (p : Char Bool) : Bool :=
!s.any (fun c => !p c)
@[export lean_substring_all]
def Internal.allImpl (s : Substring) (p : Char Bool) : Bool :=
Substring.all s p
/--
Checks whether a substring contains the specified character.
-/
@@ -1450,6 +1493,10 @@ characters by moving the substring's end position towards its start position.
let e := takeWhileAux s e p b;
s, b, e
@[export lean_substring_takewhile]
def Internal.takeWhileImpl : Substring (Char Bool) Substring :=
Substring.takeWhile
/--
Removes the longest prefix of a substring in which a Boolean predicate returns `true` for all
characters by moving the substring's start position. The start position is moved to the position of
@@ -1567,6 +1614,10 @@ instead, they are equal if they contain the same sequence of characters.
def beq (ss1 ss2 : Substring) : Bool :=
ss1.bsize == ss2.bsize && ss1.str.substrEq ss1.startPos ss2.str ss2.startPos ss1.bsize
@[export lean_substring_beq]
def Internal.beqImpl (ss1 ss2 : Substring) : Bool :=
Substring.beq ss1 ss2
instance hasBeq : BEq Substring := beq
/--
@@ -1664,6 +1715,10 @@ Examples:
@[inline] def drop (s : String) (n : Nat) : String :=
(s.toSubstring.drop n).toString
@[export lean_string_drop]
def Internal.dropImpl (s : String) (n : Nat) : String :=
String.drop s n
/--
Removes the specified number of characters (Unicode code points) from the end of the string.
@@ -1677,6 +1732,10 @@ Examples:
@[inline] def dropRight (s : String) (n : Nat) : String :=
(s.toSubstring.dropRight n).toString
@[export lean_string_dropright]
def Internal.dropRightImpl (s : String) (n : Nat) : String :=
String.dropRight s n
/--
Creates a new string that contains the first `n` characters (Unicode code points) of `s`.
@@ -1828,6 +1887,10 @@ Examples:
@[inline] def trim (s : String) : String :=
s.toSubstring.trim.toString
@[export lean_string_trim]
def Internal.trimImpl (s : String) : String :=
String.trim s
/--
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
returns `true` for the character at the position. Stops incrementing at the end of the string or
@@ -1841,6 +1904,10 @@ Examples:
@[inline] def nextWhile (s : String) (p : Char Bool) (i : String.Pos) : String.Pos :=
Substring.takeWhileAux s s.endPos p i
@[export lean_string_nextwhile]
def Internal.nextWhileImpl (s : String) (p : Char Bool) (i : String.Pos) : String.Pos :=
String.nextWhile s p i
/--
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
returns `false` for the character at the position. Stops incrementing at the end of the string or
@@ -1890,9 +1957,13 @@ Examples:
* `"ORANGE".capitalize = "ORANGE"`
* `"".capitalize = ""`
-/
@[inline] def capitalize (s : String) :=
@[inline] def capitalize (s : String) : String :=
s.set 0 <| s.get 0 |>.toUpper
@[export lean_string_capitalize]
def Internal.capitalizeImpl (s : String) : String :=
String.capitalize s
/--
Replaces the first character in `s` with the result of applying `Char.toLower` to it. Returns the
empty string if the string is empty.
@@ -1975,16 +2046,6 @@ end String
namespace Char
/--
Constructs a singleton string that contains only the provided character.
Examples:
* `'L'.toString = "L"`
* `'"'.toString = "\""`
-/
@[inline, expose] protected def toString (c : Char) : String :=
String.singleton c
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := rfl
end Char

View File

@@ -0,0 +1,186 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura, Mario Carneiro
-/
module
prelude
public import Init.Data.List.Basic
public import Init.Data.Char.Basic
public section
namespace String
instance : OfNat String.Pos (nat_lit 0) where
ofNat := {}
instance : Inhabited String where
default := ""
/--
Adds a character to the end of a string.
The internal implementation uses dynamic arrays and will perform destructive updates
if the string is not shared.
Examples:
* `"abc".push 'd' = "abcd"`
* `"".push 'a' = "a"`
-/
@[extern "lean_string_push", expose]
def push : String Char String
| s, c => s ++ [c]
/--
Returns a new string that contains only the character `c`.
Because strings are encoded in UTF-8, the resulting string may take multiple bytes.
Examples:
* `String.singleton 'L' = "L"`
* `String.singleton ' ' = " "`
* `String.singleton '"' = "\""`
* `String.singleton '𝒫' = "𝒫"`
-/
@[inline, expose] def singleton (c : Char) : String :=
"".push c
end String
namespace String.Internal
@[extern "lean_string_posof"]
opaque posOf (s : String) (c : Char) : Pos
@[extern "lean_string_offsetofpos"]
opaque offsetOfPos (s : String) (pos : Pos) : Nat
@[extern "lean_string_utf8_extract"]
opaque extract : (@& String) (@& Pos) (@& Pos) String
@[extern "lean_string_length"]
opaque length : (@& String) Nat
@[extern "lean_string_pushn"]
opaque pushn (s : String) (c : Char) (n : Nat) : String
@[extern "lean_string_append"]
opaque append : String (@& String) String
@[extern "lean_string_utf8_next"]
opaque next (s : @& String) (p : @& Pos) : Pos
@[extern "lean_string_isempty"]
opaque isEmpty (s : String) : Bool
@[extern "lean_string_foldl"]
opaque foldl (f : String Char String) (init : String) (s : String) : String
@[extern "lean_string_isprefixof"]
opaque isPrefixOf (p : String) (s : String) : Bool
@[extern "lean_string_any"]
opaque any (s : String) (p : Char Bool) : Bool
@[extern "lean_string_contains"]
opaque contains (s : String) (c : Char) : Bool
@[extern "lean_string_utf8_get"]
opaque get (s : @& String) (p : @& Pos) : Char
@[extern "lean_string_capitalize"]
opaque capitalize (s : String) : String
@[extern "lean_string_utf8_at_end"]
opaque atEnd : (@& String) (@& Pos) Bool
@[extern "lean_string_nextwhile"]
opaque nextWhile (s : String) (p : Char Bool) (i : String.Pos) : String.Pos
@[extern "lean_string_trim"]
opaque trim (s : String) : String
@[extern "lean_string_intercalate"]
opaque intercalate (s : String) : List String String
@[extern "lean_string_front"]
opaque front (s : String) : Char
@[extern "lean_string_drop"]
opaque drop (s : String) (n : Nat) : String
@[extern "lean_string_dropright"]
opaque dropRight (s : String) (n : Nat) : String
end String.Internal
/--
Creates a string that contains the characters in a list, in order.
Examples:
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
* `[].asString = ""`
* `['a', 'a', 'a'].asString = "aaa"`
-/
def List.asString (s : List Char) : String :=
s
namespace Substring.Internal
@[extern "lean_substring_tostring"]
opaque toString : Substring String
@[extern "lean_substring_drop"]
opaque drop : Substring Nat Substring
@[extern "lean_substring_front"]
opaque front (s : Substring) : Char
@[extern "lean_substring_takewhile"]
opaque takeWhile : Substring (Char Bool) Substring
@[extern "lean_substring_extract"]
opaque extract : Substring String.Pos String.Pos Substring
@[extern "lean_substring_all"]
opaque all (s : Substring) (p : Char Bool) : Bool
@[extern "lean_substring_beq"]
opaque beq (ss1 ss2 : Substring) : Bool
@[extern "lean_substring_isempty"]
opaque isEmpty (ss : Substring) : Bool
@[extern "lean_substring_get"]
opaque get : Substring String.Pos Char
@[extern "lean_substring_prev"]
opaque prev : Substring String.Pos String.Pos
end Substring.Internal
namespace String.Pos.Internal
@[extern "lean_string_pos_sub"]
opaque sub : String.Pos String.Pos String.Pos
@[extern "lean_string_pos_min"]
opaque min (p₁ p₂ : Pos) : Pos
end String.Pos.Internal
namespace Char
/--
Constructs a singleton string that contains only the provided character.
Examples:
* `'L'.toString = "L"`
* `'"'.toString = "\""`
-/
@[inline, expose] protected def toString (c : Char) : String :=
String.singleton c
end Char

View File

@@ -11,6 +11,7 @@ import all Init.Data.ByteArray.Basic
public import Init.Data.String.Basic
import all Init.Data.String.Basic
import Init.Data.UInt.Lemmas
import Init.Data.UInt.Bitwise
public section
@@ -135,7 +136,7 @@ the corresponding string, or panics if the array is not a valid UTF-8 encoding o
/--
Returns the sequence of bytes in a character's UTF-8 encoding.
-/
def utf8EncodeChar (c : Char) : List UInt8 :=
def utf8EncodeCharFast (c : Char) : List UInt8 :=
let v := c.val
if v 0x7f then
[v.toUInt8]
@@ -152,8 +153,58 @@ def utf8EncodeChar (c : Char) : List UInt8 :=
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
v.toUInt8 &&& 0x3f ||| 0x80]
private theorem Nat.add_two_pow_eq_or_of_lt {b : Nat} (i : Nat) (b_lt : b < 2 ^ i) (a : Nat) :
b + 2 ^ i * a = b ||| 2 ^ i * a := by
rw [Nat.add_comm, Nat.or_comm, Nat.two_pow_add_eq_or_of_lt b_lt]
@[csimp]
theorem utf8EncodeChar_eq_utf8EncodeCharFast : @utf8EncodeChar = @utf8EncodeCharFast := by
funext c
simp only [utf8EncodeChar, utf8EncodeCharFast, UInt8.ofNat_uInt32ToNat, UInt8.ofNat_add,
UInt8.reduceOfNat, UInt32.le_iff_toNat_le, UInt32.reduceToNat]
split
· rfl
· split
· simp only [List.cons.injEq, UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
refine ?_, ?_
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 5 (by omega) 6,
Nat.and_two_pow_sub_one_eq_mod _ 5, Nat.shiftRight_eq_div_pow,
Nat.mod_eq_of_lt (b := 256) (by omega)]
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd _ (by decide)]
· split
· simp only [List.cons.injEq, UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
refine ?_, ?_, ?_
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 4 (by omega) 14,
Nat.and_two_pow_sub_one_eq_mod _ 4, Nat.shiftRight_eq_div_pow,
Nat.mod_eq_of_lt (b := 256) (by omega)]
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
· simp only [List.cons.injEq, UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
refine ?_, ?_, ?_, ?_
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 3 (by omega) 30,
Nat.and_two_pow_sub_one_eq_mod _ 3, Nat.shiftRight_eq_div_pow,
Nat.mod_mod_of_dvd _ (by decide)]
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 12) (by decide)]
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = c.utf8Size := by
simp [Char.utf8Size, utf8EncodeChar]
simp [Char.utf8Size, utf8EncodeChar_eq_utf8EncodeCharFast, utf8EncodeCharFast]
cases Decidable.em (c.val 0x7f) <;> simp [*]
cases Decidable.em (c.val 0x7ff) <;> simp [*]
cases Decidable.em (c.val 0xffff) <;> simp [*]

View File

@@ -10,6 +10,7 @@ public import Init.Data.Char.Order
public import Init.Data.Char.Lemmas
public import Init.Data.List.Lex
import Init.Data.Order.Lemmas
public import Init.Data.String.Basic
public section

View File

@@ -0,0 +1,95 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura, Mario Carneiro
-/
module
prelude
public import Init.Data.String.Basic
public import Init.Data.ToString.Basic
public section
instance : Repr String.Iterator where
reprPrec | s, pos, prec => Repr.addAppParen ("String.Iterator.mk " ++ reprArg s ++ " " ++ reprArg pos) prec
instance : ToString String.Iterator :=
fun it => it.remainingToString
/--
Interprets a string as the decimal representation of an integer, returning it. Returns `none` if
the string does not contain a decimal integer.
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
and optionally `-` in front. Leading `+` characters are not allowed.
Use `String.isInt` to check whether `String.toInt?` would return `some`. `String.toInt!` is an
alternative that panics instead of returning `none` when the string is not an integer.
Examples:
* `"".toInt? = none`
* `"-".toInt? = none`
* `"0".toInt? = some 0`
* `"5".toInt? = some 5`
* `"-5".toInt? = some (-5)`
* `"587".toInt? = some 587`
* `"-587".toInt? = some (-587)`
* `" 5".toInt? = none`
* `"2-3".toInt? = none`
* `"0xff".toInt? = none`
-/
def String.toInt? (s : String) : Option Int := do
if s.get 0 = '-' then do
let v (s.toSubstring.drop 1).toNat?;
pure <| - Int.ofNat v
else
Int.ofNat <$> s.toNat?
/--
Checks whether the string can be interpreted as the decimal representation of an integer.
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
and optionally `-` in front. Leading `+` characters are not allowed.
Use `String.toInt?` or `String.toInt!` to convert such a string to an integer.
Examples:
* `"".isInt = false`
* `"-".isInt = false`
* `"0".isInt = true`
* `"-0".isInt = true`
* `"5".isInt = true`
* `"587".isInt = true`
* `"-587".isInt = true`
* `"+587".isInt = false`
* `" 5".isInt = false`
* `"2-3".isInt = false`
* `"0xff".isInt = false`
-/
def String.isInt (s : String) : Bool :=
if s.get 0 = '-' then
(s.toSubstring.drop 1).isNat
else
s.isNat
/--
Interprets a string as the decimal representation of an integer, returning it. Panics if the string
does not contain a decimal integer.
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
and optionally `-` in front. Leading `+` characters are not allowed.
Use `String.isInt` to check whether `String.toInt!` would return a value. `String.toInt?` is a safer
alternative that returns `none` instead of panicking when the string is not an integer.
Examples:
* `"0".toInt! = 0`
* `"5".toInt! = 5`
* `"587".toInt! = 587`
* `"-587".toInt! = -587`
-/
def String.toInt! (s : String) : Int :=
match s.toInt? with
| some v => v
| none => panic "Int expected"

View File

@@ -8,5 +8,6 @@ module
prelude
public import Init.Data.ToString.Basic
public import Init.Data.ToString.Macro
public meta import Init.Data.ToString.Name
public section

View File

@@ -38,10 +38,10 @@ instance : ToString String :=
fun s => s
instance : ToString Substring :=
fun s => s.toString
fun s => Substring.Internal.toString s
instance : ToString String.Iterator :=
fun it => it.remainingToString
instance : ToString Char :=
fun c => Char.toString c
instance : ToString Bool :=
fun b => cond b "true" "false"
@@ -67,8 +67,9 @@ Examples:
-/
protected def List.toString [ToString α] : List α String
| [] => "[]"
| [x] => "[" ++ toString x ++ "]"
| x::xs => xs.foldl (· ++ ", " ++ toString ·) ("[" ++ toString x) |>.push ']'
| [x] => String.Internal.append (String.Internal.append "[" (toString x)) "]"
| x::xs => String.push (xs.foldl (fun l r => String.Internal.append (String.Internal.append l ", ") (toString r))
(String.Internal.append "[" (toString x))) ']'
instance {α : Type u} [ToString α] : ToString (List α) :=
List.toString
@@ -91,10 +92,7 @@ instance : ToString String.Pos :=
instance : ToString Int where
toString
| Int.ofNat m => toString m
| Int.negSucc m => "-" ++ toString (succ m)
instance : ToString Char :=
fun c => c.toString
| Int.negSucc m => String.Internal.append "-" (toString (succ m))
instance (n : Nat) : ToString (Fin n) :=
fun f => toString (Fin.val f)
@@ -118,108 +116,43 @@ instance : ToString Format where
toString f := f.pretty
def addParenHeuristic (s : String) : String :=
if "(".isPrefixOf s || "[".isPrefixOf s || "{".isPrefixOf s || "#[".isPrefixOf s then s
else if !s.any Char.isWhitespace then s
else "(" ++ s ++ ")"
if String.Internal.isPrefixOf "(" s || String.Internal.isPrefixOf "[" s || String.Internal.isPrefixOf "{" s || String.Internal.isPrefixOf "#[" s then s
else if !(String.Internal.any s Char.isWhitespace) then s
else String.Internal.append (String.Internal.append "(" s) ")"
instance {α : Type u} [ToString α] : ToString (Option α) := fun
| none => "none"
| (some a) => "(some " ++ addParenHeuristic (toString a) ++ ")"
| (some a) => String.Internal.append (String.Internal.append "(some " (addParenHeuristic (toString a))) ")"
instance {α : Type u} {β : Type v} [ToString α] [ToString β] : ToString (Sum α β) := fun
| (inl a) => "(inl " ++ addParenHeuristic (toString a) ++ ")"
| (inr b) => "(inr " ++ addParenHeuristic (toString b) ++ ")"
| (inl a) => String.Internal.append (String.Internal.append "(inl " (addParenHeuristic (toString a))) ")"
| (inr b) => String.Internal.append (String.Internal.append "(inr " (addParenHeuristic (toString b))) ")"
instance {α : Type u} {β : Type v} [ToString α] [ToString β] : ToString (α × β) := fun (a, b) =>
"(" ++ toString a ++ ", " ++ toString b ++ ")"
String.Internal.append
(String.Internal.append
(String.Internal.append
(String.Internal.append "(" (toString a))
", ")
(toString b))
")"
instance {α : Type u} {β : α Type v} [ToString α] [ x, ToString (β x)] : ToString (Sigma β) := fun a, b =>
"" ++ toString a ++ ", " ++ toString b ++ ""
String.Internal.append
(String.Internal.append
(String.Internal.append
(String.Internal.append "" (toString a))
", ")
(toString b))
""
instance {α : Type u} {p : α Prop} [ToString α] : ToString (Subtype p) := fun s =>
toString (val s)
/--
Interprets a string as the decimal representation of an integer, returning it. Returns `none` if
the string does not contain a decimal integer.
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
and optionally `-` in front. Leading `+` characters are not allowed.
Use `String.isInt` to check whether `String.toInt?` would return `some`. `String.toInt!` is an
alternative that panics instead of returning `none` when the string is not an integer.
Examples:
* `"".toInt? = none`
* `"-".toInt? = none`
* `"0".toInt? = some 0`
* `"5".toInt? = some 5`
* `"-5".toInt? = some (-5)`
* `"587".toInt? = some 587`
* `"-587".toInt? = some (-587)`
* `" 5".toInt? = none`
* `"2-3".toInt? = none`
* `"0xff".toInt? = none`
-/
def String.toInt? (s : String) : Option Int := do
if s.get 0 = '-' then do
let v (s.toSubstring.drop 1).toNat?;
pure <| - Int.ofNat v
else
Int.ofNat <$> s.toNat?
/--
Checks whether the string can be interpreted as the decimal representation of an integer.
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
and optionally `-` in front. Leading `+` characters are not allowed.
Use `String.toInt?` or `String.toInt!` to convert such a string to an integer.
Examples:
* `"".isInt = false`
* `"-".isInt = false`
* `"0".isInt = true`
* `"-0".isInt = true`
* `"5".isInt = true`
* `"587".isInt = true`
* `"-587".isInt = true`
* `"+587".isInt = false`
* `" 5".isInt = false`
* `"2-3".isInt = false`
* `"0xff".isInt = false`
-/
def String.isInt (s : String) : Bool :=
if s.get 0 = '-' then
(s.toSubstring.drop 1).isNat
else
s.isNat
/--
Interprets a string as the decimal representation of an integer, returning it. Panics if the string
does not contain a decimal integer.
A string can be interpreted as a decimal integer if it only consists of at least one decimal digit
and optionally `-` in front. Leading `+` characters are not allowed.
Use `String.isInt` to check whether `String.toInt!` would return a value. `String.toInt?` is a safer
alternative that returns `none` instead of panicking when the string is not an integer.
Examples:
* `"0".toInt! = 0`
* `"5".toInt! = 5`
* `"587".toInt! = 587`
* `"-587".toInt! = -587`
-/
def String.toInt! (s : String) : Int :=
match s.toInt? with
| some v => v
| none => panic "Int expected"
instance [ToString ε] [ToString α] : ToString (Except ε α) where
toString
| Except.error e => "error: " ++ toString e
| Except.ok a => "ok: " ++ toString a
| Except.error e => String.Internal.append "error: " (toString e)
| Except.ok a => String.Internal.append "ok: " (toString a)
instance [Repr ε] [Repr α] : Repr (Except ε α) where
reprPrec

View File

@@ -0,0 +1,128 @@
/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura and Sebastian Ullrich
-/
module
prelude
public import Init.Meta
import Init.Data.String.Extra
/-!
Here we give the. implementation of `Name.toString`. There is also a private implementation in
`Init.Meta`, which we cannot import this implementation due to import hierarchy limitations.
The difference between the two versions is that the one in `Init.Meta` uses the `String.Internal.*`
functions, while the one here uses the public String functions. These differ in
that the latter versions have better inferred borrowing annotations, which is significant for an
inner-loop function like `Name.toString`.
-/
public section
namespace Lean.Name
-- If you change this, also change the corresponding function in `Init.Meta`.
private partial def needsNoEscapeAsciiRest (s : String) (i : Nat) : Bool :=
if h : i < s.utf8ByteSize then
let c := s.getUtf8Byte i h
isIdRestAscii c && needsNoEscapeAsciiRest s (i + 1)
else
true
-- If you change this, also change the corresponding function in `Init.Meta`.
@[inline] private def needsNoEscapeAscii (s : String) (h : s.utf8ByteSize > 0) : Bool :=
let c := s.getUtf8Byte 0 h
isIdFirstAscii c && needsNoEscapeAsciiRest s 1
-- If you change this, also change the corresponding function in `Init.Meta`.
@[inline] private def needsNoEscape (s : String) (h : s.utf8ByteSize > 0) : Bool :=
needsNoEscapeAscii s h || isIdFirst (s.get 0) && (s.toSubstring.drop 1).all isIdRest
-- If you change this, also change the corresponding function in `Init.Meta`.
@[inline] private def escape (s : String) : String :=
idBeginEscape.toString ++ s ++ idEndEscape.toString
/--
Creates a round-trippable string name component if possible, otherwise returns `none`.
Names that are valid identifiers are not escaped, and otherwise, if they do not contain `»`, they are escaped.
- If `force` is `true`, then even valid identifiers are escaped.
-/
-- If you change this, also change the corresponding function in `Init.Meta`.
@[inline]
def escapePart (s : String) (force : Bool := false) : Option String :=
if h : s.utf8ByteSize > 0 then
if !force && needsNoEscape s h then
some s
else if s.any isIdEndEscape then
none
else
some <| escape s
else
some <| escape s
variable (sep : String) (escape : Bool) in
/--
Uses the separator `sep` (usually `"."`) to combine the components of the `Name` into a string.
See the documentation for `Name.toStringWithToken` for an explanation of `escape` and `isToken`.
-/
-- If you change this, also change the corresponding function in `Init.Meta`.
@[specialize isToken] -- explicit annotation because isToken is overridden in recursive call
def toStringWithSep (n : Name) (isToken : String Bool := fun _ => false) : String :=
match n with
| anonymous => "[anonymous]"
| str anonymous s => maybeEscape s (isToken s)
| num anonymous v => toString v
| str n s =>
-- Escape the last component if the identifier would otherwise be a token
let r := toStringWithSep n isToken
let r' := r ++ sep ++ (maybeEscape s false)
if escape && isToken r' then r ++ sep ++ (maybeEscape s true) else r'
| num n v => toStringWithSep n (isToken := fun _ => false) ++ sep ++ Nat.repr v
where
maybeEscape s force := if escape then escapePart s force |>.getD s else s
/--
Converts a name to a string.
- If `escape` is `true`, then escapes name components using `«` and `»` to ensure that
those names that can appear in source files round trip.
Names with number components, anonymous names, and names containing `»` might not round trip.
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
- The optional `isToken` function is used when `escape` is `true` to determine whether more
escaping is necessary to avoid parser tokens.
The insertion algorithm works so long as parser tokens do not themselves contain `«` or `»`.
-/
-- If you change this, also change the corresponding function in `Init.Meta`.
@[specialize]
def toStringWithToken (n : Name) (escape := true) (isToken : String Bool) : String :=
-- never escape "prettified" inaccessible names or macro scopes or pseudo-syntax introduced by the delaborator
toStringWithSep "." (escape && !n.isInaccessibleUserName && !n.hasMacroScopes && !maybePseudoSyntax) n isToken
where
maybePseudoSyntax :=
if n == `_ then
-- output hole as is
true
else if let .str _ s := n.getRoot then
-- could be pseudo-syntax for loose bvar or universe mvar, output as is
"#".isPrefixOf s || "?".isPrefixOf s
else
false
/--
Converts a name to a string.
- If `escape` is `true`, then escapes name components using `«` and `»` to ensure that
those names that can appear in source files round trip.
Names with number components, anonymous names, and names containing `»` might not round trip.
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
-/
-- If you change this, also change the corresponding function in `Init.Meta`.
protected def toString (n : Name) (escape := true) : String :=
Name.toStringWithToken n escape (fun _ => false)
instance : ToString Name where
toString n := n.toString
end Lean.Name

View File

@@ -139,16 +139,6 @@ This function is overridden at runtime with an efficient implementation.
-/
@[extern "lean_uint8_shift_right"]
protected def UInt8.shiftRight (a b : UInt8) : UInt8 := a.toBitVec >>> (UInt8.mod b 8).toBitVec
/--
Strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
natural numbers. Usually accessed via the `<` operator.
-/
protected def UInt8.lt (a b : UInt8) : Prop := a.toBitVec < b.toBitVec
/--
Non-strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
natural numbers. Usually accessed via the `≤` operator.
-/
protected def UInt8.le (a b : UInt8) : Prop := a.toBitVec b.toBitVec
instance : Add UInt8 := UInt8.add
instance : Sub UInt8 := UInt8.sub
@@ -160,8 +150,6 @@ set_option linter.deprecated false in
instance : HMod UInt8 Nat UInt8 := UInt8.modn
instance : Div UInt8 := UInt8.div
instance : LT UInt8 := UInt8.lt
instance : LE UInt8 := UInt8.le
/--
Bitwise complement, also known as bitwise negation, for 8-bit unsigned integers. Usually accessed
@@ -197,39 +185,6 @@ Converts `true` to `1` and `false` to `0`.
@[extern "lean_bool_to_uint8"]
def Bool.toUInt8 (b : Bool) : UInt8 := if b then 1 else 0
/--
Decides whether one 8-bit unsigned integer is strictly less than another. Usually accessed via the
`DecidableLT UInt8` instance.
This function is overridden at runtime with an efficient implementation.
Examples:
* `(if (6 : UInt8) < 7 then "yes" else "no") = "yes"`
* `(if (5 : UInt8) < 5 then "yes" else "no") = "no"`
* `show ¬((7 : UInt8) < 7) by decide`
-/
@[extern "lean_uint8_dec_lt"]
def UInt8.decLt (a b : UInt8) : Decidable (a < b) :=
inferInstanceAs (Decidable (a.toBitVec < b.toBitVec))
/--
Decides whether one 8-bit unsigned integer is less than or equal to another. Usually accessed via the
`DecidableLE UInt8` instance.
This function is overridden at runtime with an efficient implementation.
Examples:
* `(if (15 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
* `(if (15 : UInt8) ≤ 5 then "yes" else "no") = "no"`
* `(if (5 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
* `show (7 : UInt8) ≤ 7 by decide`
-/
@[extern "lean_uint8_dec_le"]
def UInt8.decLe (a b : UInt8) : Decidable (a b) :=
inferInstanceAs (Decidable (a.toBitVec b.toBitVec))
attribute [instance] UInt8.decLt UInt8.decLe
instance : Max UInt8 := maxOfLe
instance : Min UInt8 := minOfLe

View File

@@ -29,21 +29,6 @@ def UInt8.toFin (x : UInt8) : Fin UInt8.size := x.toBitVec.toFin
@[deprecated UInt8.toFin (since := "2025-02-12"), inherit_doc UInt8.toFin]
def UInt8.val (x : UInt8) : Fin UInt8.size := x.toFin
/--
Converts a natural number to an 8-bit unsigned integer, wrapping on overflow.
This function is overridden at runtime with an efficient implementation.
Examples:
* `UInt8.ofNat 5 = 5`
* `UInt8.ofNat 255 = 255`
* `UInt8.ofNat 256 = 0`
* `UInt8.ofNat 259 = 3`
* `UInt8.ofNat 32770 = 2`
-/
@[extern "lean_uint8_of_nat"]
def UInt8.ofNat (n : @& Nat) : UInt8 := BitVec.ofNat 8 n
/--
Converts a natural number to an 8-bit unsigned integer, returning the largest representable value if
the number is too large.
@@ -222,8 +207,8 @@ instance UInt32.instOfNat : OfNat UInt32 n := ⟨UInt32.ofNat n⟩
theorem UInt32.ofNatLT_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
n < m UInt32.ofNatLT n h1 < UInt32.ofNat m := by
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.ofNat,
Nat.mod_eq_of_lt h2, imp_self]
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat,
Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
@[deprecated UInt32.ofNatLT_lt_of_lt (since := "2025-02-13")]
theorem UInt32.ofNat'_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
@@ -231,8 +216,8 @@ theorem UInt32.ofNat'_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt
theorem UInt32.lt_ofNatLT_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
m < n UInt32.ofNat m < UInt32.ofNatLT n h1 := by
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.ofNat,
Nat.mod_eq_of_lt h2, imp_self]
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat,
Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
@[deprecated UInt32.lt_ofNatLT_of_lt (since := "2025-02-13")]
theorem UInt32.lt_ofNat'_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :

View File

@@ -200,7 +200,7 @@ theorem mem_attach (xs : Vector α n) : ∀ x, x ∈ xs.attach
rcases this with _, _, m, rfl
exact m
@[simp, grind]
@[simp, grind =]
theorem mem_attachWith {xs : Vector α n} {q : α Prop} (H) (x : {x // q x}) :
x xs.attachWith q H x.1 xs := by
rcases xs with xs, rfl
@@ -211,12 +211,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs : Vector α n} {H
b pmap f xs H (a : _) (h : a xs), f a (H a h) = b := by
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
@[grind]
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {xs : Vector α n} {H} {a} (h : a xs) :
f a (H a h) pmap f xs H := by
rw [mem_pmap]
exact a, h, rfl
grind_pattern mem_pmap_of_mem => _ pmap f xs H, a xs
theorem pmap_eq_self {xs : Vector α n} {p : α Prop} {hp : (a : α), a xs p a}
{f : (a : α) p a α} : xs.pmap f hp = xs a (h : a xs), f a (hp a h) = a := by
rcases xs with xs, rfl

View File

@@ -36,7 +36,7 @@ structure Vector (α : Type u) (n : Nat) where
size_toArray : toArray.size = n
deriving Repr, DecidableEq
attribute [simp, grind] Vector.size_toArray
attribute [simp, grind =] Vector.size_toArray
/--
Converts an array to a vector. The resulting vector's size is the array's size.

View File

@@ -32,11 +32,11 @@ open Nat
/-! ### findSome? -/
@[simp, grind] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
@[simp, grind] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
@[simp, grind =] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
@[simp, grind =] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
cases xs; simp
@[grind]
@[grind =]
theorem findSome?_singleton {a : α} {f : α Option β} : #v[a].findSome? f = f a := by
simp
@@ -228,11 +228,12 @@ theorem mem_of_find?_eq_some {xs : Vector α n} (h : find? p xs = some a) : a
simp at h
simpa using Array.mem_of_find?_eq_some h
@[grind]
theorem get_find?_mem {xs : Vector α n} (h) : (xs.find? p).get h xs := by
cases xs
simp [Array.get_find?_mem]
grind_pattern get_find?_mem => (xs.find? p).get h
@[simp, grind =] theorem find?_map {f : β α} {xs : Vector β n} :
find? p (xs.map f) = (xs.find? (p f)).map f := by
cases xs; simp

View File

@@ -266,12 +266,12 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
/-! ### toArray lemmas -/
@[simp, grind] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
@[simp, grind =] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := by
cases xs
simp
@[simp, grind] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
@[simp, grind =] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
xs.toArray[i]? = xs[i]? := by
cases xs
simp
@@ -280,45 +280,45 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
(xs ++ ys).toArray = xs.toArray ++ ys.toArray := rfl
set_option linter.indexVariables false in
@[simp, grind] theorem toArray_drop {xs : Vector α n} {i} :
@[simp, grind =] theorem toArray_drop {xs : Vector α n} {i} :
(xs.drop i).toArray = xs.toArray.extract i n := by
simp [drop]
@[simp, grind =] theorem toArray_empty : (#v[] : Vector α 0).toArray = #[] := rfl
@[simp, grind] theorem toArray_emptyWithCapacity {cap} :
@[simp, grind =] theorem toArray_emptyWithCapacity {cap} :
(Vector.emptyWithCapacity (α := α) cap).toArray = Array.emptyWithCapacity cap := rfl
@[deprecated toArray_emptyWithCapacity (since := "2025-03-12")]
abbrev toArray_mkEmpty := @toArray_emptyWithCapacity
@[simp, grind] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
@[simp, grind =] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
(xs.eraseIdx i h).toArray = xs.toArray.eraseIdx i (by simp [h]) := rfl
@[simp, grind] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
@[simp, grind =] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
(xs.eraseIdx! i).toArray = xs.toArray.eraseIdx! i := by
cases xs; simp_all [Array.eraseIdx!]
@[simp, grind] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
@[simp, grind =] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
(xs.insertIdx i x h).toArray = xs.toArray.insertIdx i x (by simp [h]) := rfl
@[simp, grind] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i n) :
@[simp, grind =] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i n) :
(xs.insertIdx! i x).toArray = xs.toArray.insertIdx! i x := by
cases xs; simp_all [Array.insertIdx!]
@[simp, grind] theorem toArray_cast {xs : Vector α n} (h : n = m) :
@[simp, grind =] theorem toArray_cast {xs : Vector α n} (h : n = m) :
(xs.cast h).toArray = xs.toArray := rfl
@[simp, grind] theorem toArray_extract {xs : Vector α n} {start stop} :
@[simp, grind =] theorem toArray_extract {xs : Vector α n} {start stop} :
(xs.extract start stop).toArray = xs.toArray.extract start stop := rfl
@[simp, grind] theorem toArray_map {f : α β} {xs : Vector α n} :
@[simp, grind =] theorem toArray_map {f : α β} {xs : Vector α n} :
(xs.map f).toArray = xs.toArray.map f := rfl
@[simp, grind] theorem toArray_mapIdx {f : Nat α β} {xs : Vector α n} :
@[simp, grind =] theorem toArray_mapIdx {f : Nat α β} {xs : Vector α n} :
(xs.mapIdx f).toArray = xs.toArray.mapIdx f := rfl
@[simp, grind] theorem toArray_mapFinIdx {f : (i : Nat) α (h : i < n) β} {xs : Vector α n} :
@[simp, grind =] theorem toArray_mapFinIdx {f : (i : Nat) α (h : i < n) β} {xs : Vector α n} :
(xs.mapFinIdx f).toArray =
xs.toArray.mapFinIdx (fun i a h => f i a (by simpa [xs.size_toArray] using h)) :=
rfl
@@ -336,42 +336,42 @@ private theorem toArray_mapM_go [Monad m] [LawfulMonad m] {f : α → m β} {xs
rfl
· simp
@[simp, grind] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α m β} {xs : Vector α n} :
@[simp, grind =] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α m β} {xs : Vector α n} :
toArray <$> xs.mapM f = xs.toArray.mapM f := by
rcases xs with xs, rfl
unfold mapM
rw [toArray_mapM_go]
rfl
@[simp, grind] theorem toArray_ofFn {f : Fin n α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
@[simp, grind =] theorem toArray_ofFn {f : Fin n α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
@[simp, grind] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
@[simp, grind =] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
@[simp, grind] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
@[simp, grind =] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
@[simp, grind] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
@[simp, grind =] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
(xs.toArray == ys.toArray) = (xs == ys) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, xs.2, ys.2]
@[simp, grind] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
@[simp, grind =] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
@[simp, grind] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
@[simp, grind =] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
@[simp, grind] theorem toArray_set {xs : Vector α n} {i x} (h) :
@[simp, grind =] theorem toArray_set {xs : Vector α n} {i x} (h) :
(xs.set i x).toArray = xs.toArray.set i x (by simpa using h):= rfl
@[simp, grind] theorem toArray_set! {xs : Vector α n} {i x} :
@[simp, grind =] theorem toArray_set! {xs : Vector α n} {i x} :
(xs.set! i x).toArray = xs.toArray.set! i x := rfl
@[simp, grind] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
@[simp, grind =] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
(xs.setIfInBounds i x).toArray = xs.toArray.setIfInBounds i x := rfl
@[simp, grind] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
@[simp, grind =] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
@[simp, grind] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
@[simp, grind =] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
xs.toArray.swap i j (by simp [hj]) (by simp [hi]) := rfl
@[simp, grind] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
@[simp, grind =] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
(xs.swapIfInBounds i j).toArray = xs.toArray.swapIfInBounds i j := rfl
theorem toArray_swapAt {xs : Vector α n} {i x} (h) :
@@ -383,98 +383,98 @@ theorem toArray_swapAt! {xs : Vector α n} {i x} :
((xs.swapAt! i x).fst, (xs.swapAt! i x).snd.toArray) =
((xs.toArray.swapAt! i x).fst, (xs.toArray.swapAt! i x).snd) := rfl
@[simp, grind] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
@[simp, grind =] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
@[simp, grind] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
@[simp, grind =] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
(xs.zipIdx k).toArray = xs.toArray.zipIdx k := rfl
@[simp, grind] theorem toArray_zipWith {f : α β γ} {as : Vector α n} {bs : Vector β n} :
@[simp, grind =] theorem toArray_zipWith {f : α β γ} {as : Vector α n} {bs : Vector β n} :
(Vector.zipWith f as bs).toArray = Array.zipWith f as.toArray bs.toArray := rfl
@[simp, grind] theorem anyM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind =] theorem anyM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.anyM p = xs.anyM p := by
cases xs
simp
@[simp, grind] theorem allM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind =] theorem allM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.allM p = xs.allM p := by
cases xs
simp
@[simp, grind] theorem any_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind =] theorem any_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.any p = xs.any p := by
cases xs
simp
@[simp, grind] theorem all_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind =] theorem all_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.all p = xs.all p := by
cases xs
simp
@[simp, grind] theorem countP_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind =] theorem countP_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.countP p = xs.countP p := by
cases xs
simp
@[simp, grind] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
@[simp, grind =] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
xs.toArray.count a = xs.count a := by
cases xs
simp
@[simp, grind] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
@[simp, grind =] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
xs.toArray.replace a b = (xs.replace a b).toArray := rfl
@[simp, grind] theorem find?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind =] theorem find?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.find? p = xs.find? p := by
cases xs
simp
@[simp, grind] theorem findSome?_toArray {f : α Option β} {xs : Vector α n} :
@[simp, grind =] theorem findSome?_toArray {f : α Option β} {xs : Vector α n} :
xs.toArray.findSome? f = xs.findSome? f := by
cases xs
simp
@[simp, grind] theorem findRev?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind =] theorem findRev?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.findRev? p = xs.findRev? p := by
cases xs
simp
@[simp, grind] theorem findSomeRev?_toArray {f : α Option β} {xs : Vector α n} :
@[simp, grind =] theorem findSomeRev?_toArray {f : α Option β} {xs : Vector α n} :
xs.toArray.findSomeRev? f = xs.findSomeRev? f := by
cases xs
simp
@[simp, grind] theorem findM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind =] theorem findM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.findM? p = xs.findM? p := by
cases xs
simp
@[simp, grind] theorem findSomeM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
@[simp, grind =] theorem findSomeM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
xs.toArray.findSomeM? f = xs.findSomeM? f := by
cases xs
simp
@[simp, grind] theorem findRevM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind =] theorem findRevM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.findRevM? p = xs.findRevM? p := by
rcases xs with xs, rfl
simp
@[simp, grind] theorem findSomeRevM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
@[simp, grind =] theorem findSomeRevM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
xs.toArray.findSomeRevM? f = xs.findSomeRevM? f := by
rcases xs with xs, rfl
simp
@[simp, grind] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
@[simp, grind =] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
xs.toArray.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast xs.size_toArray.symm) := by
rcases xs with xs, rfl
simp
@[simp, grind] theorem findFinIdx?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind =] theorem findFinIdx?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast xs.size_toArray.symm) := by
rcases xs with xs, rfl
simp
@[simp, grind] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
@[simp, grind =] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
@[deprecated toArray_replicate (since := "2025-03-18")]
abbrev toArray_mkVector := @toArray_replicate
@@ -503,13 +503,13 @@ protected theorem ext {xs ys : Vector α n} (h : (i : Nat) → (_ : i < n) → x
/-! ### toList -/
@[simp, grind] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
@[simp, grind =] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
rcases xs with xs, rfl
simp [toList]
@[grind =_] theorem toList_toArray {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl
@[simp, grind] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
@[simp, grind =] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
@[simp] theorem getElem_toList {xs : Vector α n} {i : Nat} (h : i < xs.toList.length) :
xs.toList[i] = xs[i]'(by simpa using h) := by
@@ -784,12 +784,12 @@ theorem singleton_inj : #v[a] = #v[b] ↔ a = b := by
/-! ### replicate -/
@[simp, grind] theorem replicate_zero : replicate 0 a = #v[] := rfl
@[simp, grind =] theorem replicate_zero : replicate 0 a = #v[] := rfl
@[deprecated replicate_zero (since := "2025-03-18")]
abbrev replicate_mkVector := @replicate_zero
@[grind]
@[grind =]
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
simp [replicate, Array.replicate_succ]
@@ -895,26 +895,35 @@ theorem getElem?_push_size {xs : Vector α n} {x : α} : (xs.push x)[n]? = some
theorem getElem_singleton {a : α} (h : i < 1) : #v[a][i] = a := by
simp
@[grind]
@[grind =]
theorem getElem?_singleton {a : α} {i : Nat} : #v[a][i]? = if i = 0 then some a else none := by
simp [List.getElem?_singleton]
/-! ### mem -/
@[simp, grind] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] xs := by
@[simp] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] xs := by
rcases xs with xs, rfl
simp
grind_pattern getElem_mem => xs[i] xs
theorem not_mem_empty (a : α) : ¬ a #v[] := nofun
@[simp] theorem mem_push {xs : Vector α n} {x y : α} : x xs.push y x xs x = y := by
@[simp, grind =] theorem mem_push {xs : Vector α n} {x y : α} : x xs.push y x xs x = y := by
rcases xs with xs, rfl
simp
@[grind] theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
a xs.push b a xs a = b := Vector.mem_push.mp
@[grind] theorem mem_push_self {xs : Vector α n} {x : α} : x xs.push x :=
-- This pattern may be excessively general:
-- it fires anytime we ae thinking about membership of vectors,
-- and constructing a list via `push`, even if the elements are unrelated.
-- Nevertheless in practice it is quite helpful!
grind_pattern mem_or_eq_of_mem_push => xs.push b, a xs
theorem mem_push_self {xs : Vector α n} {x : α} : x xs.push x :=
mem_push.2 (Or.inr rfl)
theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x xs) :
@@ -926,7 +935,7 @@ theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x ∈ xs) :
obtain rfl := h
exact _, _, as.toVector, bs.toVector, by simp, by simp, by simpa using w
@[grind] theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x xs) : x xs.push y :=
theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x xs) : x xs.push y :=
mem_push.2 (Or.inl h)
theorem exists_mem_of_size_pos {xs : Vector α n} (h : 0 < n) : x, x xs := by
@@ -1213,9 +1222,9 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a as) :=
decidable_of_decidable_of_iff contains_iff
@[grind] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
@[grind =] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = decide (a as) := by
rw [Bool.eq_iff_iff, contains_iff, decide_eq_true_iff]
@@ -1236,7 +1245,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
/-! ### set -/
@[grind] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
@[grind =] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
(xs.set i x hi)[j] = if i = j then x else xs[j] := by
cases xs
split <;> simp_all
@@ -1249,7 +1258,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
@[simp] theorem getElem_set_ne {xs : Vector α n} {x : α} (hi : i < n) (hj : j < n) (h : i j) :
(xs.set i x hi)[j] = xs[j] := by simp [getElem_set, h]
@[grind] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
@[grind =] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
(xs.set i x hi)[j]? = if i = j then some x else xs[j]? := by
cases xs
split <;> simp_all
@@ -1294,10 +1303,10 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
/-! ### setIfInBounds -/
@[simp, grind] theorem setIfInBounds_empty {i : Nat} {a : α} :
@[simp, grind =] theorem setIfInBounds_empty {i : Nat} {a : α} :
#v[].setIfInBounds i a = #v[] := rfl
@[grind] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
@[grind =] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
(xs.setIfInBounds i x)[j] = if i = j then x else xs[j] := by
cases xs
split <;> simp_all
@@ -1310,7 +1319,7 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
@[simp] theorem getElem_setIfInBounds_ne {xs : Vector α n} {x : α} (hj : j < n) (h : i j) :
(xs.setIfInBounds i x)[j] = xs[j] := by simp [getElem_setIfInBounds, h]
@[grind] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
@[grind =] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
(xs.setIfInBounds i x)[j]? = if i = j then if i < n then some x else none else xs[j]? := by
rcases xs with xs, rfl
simp [Array.getElem?_setIfInBounds]
@@ -1347,7 +1356,7 @@ theorem mem_setIfInBounds {xs : Vector α n} {a : α} (hi : i < n) :
/-! ### BEq -/
@[simp, grind] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
(xs.push a == ys.push b) = (xs == ys && a == b) := by
cases xs
cases ys
@@ -1410,16 +1419,16 @@ abbrev mkVector_beq_mkVector := @replicate_beq_replicate
/-! ### back -/
@[grind] theorem back_singleton {a : α} : #v[a].back = a := by simp
@[grind =] theorem back_singleton {a : α} : #v[a].back = a := by simp
@[grind]
@[grind =]
theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by have := NeZero.ne n; omega) := by
rcases xs with xs, rfl
simp [Array.back_eq_getElem]
@[grind] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
@[grind =] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
@[grind] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
@[grind =] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
rcases xs with xs, rfl
simp [Array.back?_eq_getElem?]
@@ -1430,22 +1439,22 @@ theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by
/-! ### map -/
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
@[simp, grind] theorem getElem_map (f : α β) {xs : Vector α n} (hi : i < n) :
@[simp, grind =] theorem getElem_map (f : α β) {xs : Vector α n} (hi : i < n) :
(xs.map f)[i] = f xs[i] := by
cases xs
simp
@[simp, grind] theorem getElem?_map {f : α β} {xs : Vector α n} {i : Nat}:
@[simp, grind =] theorem getElem?_map {f : α β} {xs : Vector α n} {i : Nat}:
(xs.map f)[i]? = xs[i]?.map f := by
cases xs
simp
/-- The empty vector maps to the empty vector. -/
@[grind]
@[grind =]
theorem map_empty {f : α β} : map f #v[] = #v[] := by
simp
@[simp, grind] theorem map_push {f : α β} {as : Vector α n} {x : α} :
@[simp, grind =] theorem map_push {f : α β} {as : Vector α n} {x : α} :
(as.push x).map f = (as.map f).push (f x) := by
cases as
simp
@@ -1620,7 +1629,7 @@ theorem append_push {as : Vector α n} {bs : Vector α m} {a : α} :
theorem singleton_eq_toVector_singleton {a : α} : #v[a] = #[a].toVector := rfl
@[simp, grind] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
@[simp, grind =] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
a xs ++ ys a xs a ys := by
cases xs
cases ys
@@ -1656,16 +1665,16 @@ theorem forall_mem_append {p : α → Prop} {xs : Vector α n} {ys : Vector α m
( (x) (_ : x xs ++ ys), p x) ( (x) (_ : x xs), p x) ( (x) (_ : x ys), p x) := by
simp only [mem_append, or_imp, forall_and]
@[simp, grind]
@[simp, grind =]
theorem empty_append {xs : Vector α n} : (#v[] : Vector α 0) ++ xs = xs.cast (by omega) := by
rcases xs with as, rfl
simp
@[simp, grind]
@[simp, grind =]
theorem append_empty {xs : Vector α n} : xs ++ (#v[] : Vector α 0) = xs := by
rw [ toArray_inj, toArray_append, Array.append_empty]
@[grind]
@[grind =]
theorem getElem_append {xs : Vector α n} {ys : Vector α m} (hi : i < n + m) :
(xs ++ ys)[i] = if h : i < n then xs[i] else ys[i - n] := by
rcases xs with xs, rfl
@@ -1692,7 +1701,7 @@ theorem getElem?_append_right {xs : Vector α n} {ys : Vector α m} (h : n ≤ i
rcases ys with ys, rfl
simp [Array.getElem?_append_right, h]
@[grind]
@[grind =]
theorem getElem?_append {xs : Vector α n} {ys : Vector α m} {i : Nat} :
(xs ++ ys)[i]? = if i < n then xs[i]? else ys[i - n]? := by
split <;> rename_i h
@@ -1771,7 +1780,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
right
refine cs.toArray, ha, rfl
@[simp, grind] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
@[simp, grind =] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
(xs ++ ys) ++ zs = (xs ++ (ys ++ zs)).cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
@@ -1779,14 +1788,14 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
simp [Array.append_assoc]
-- Variant for rewriting the other direction: we can't use `append_assoc` as it has a `cast` on the right-hand side.
@[grind] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
@[grind =] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
xs ++ (ys ++ zs) = ((xs ++ ys) ++ zs).cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
rcases zs with zs, rfl
simp [Array.append_assoc]
@[grind] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
@[grind =] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
(xs ++ ys).set i x =
if h' : i < n then
xs.set i x ++ ys
@@ -1806,7 +1815,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
(xs ++ ys).set i x = xs ++ ys.set (i - n) x := by
rw [set_append, dif_neg (by omega)]
@[grind] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
@[grind =] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
(xs ++ ys).setIfInBounds i x =
if i < n then
xs.setIfInBounds i x ++ ys
@@ -1826,7 +1835,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
(xs ++ ys).setIfInBounds i x = xs ++ ys.setIfInBounds (i - n) x := by
rw [setIfInBounds_append, if_neg (by omega)]
@[simp, grind] theorem map_append {f : α β} {xs : Vector α n} {ys : Vector α m} :
@[simp, grind =] theorem map_append {f : α β} {xs : Vector α n} {ys : Vector α m} :
map f (xs ++ ys) = map f xs ++ map f ys := by
rcases xs with xs, rfl
rcases ys with ys, rfl
@@ -1895,7 +1904,7 @@ theorem getElem?_flatten {xss : Vector (Vector β m) n} {i : Nat} :
none := by
simp [getElem?_def]
@[simp, grind] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
@[simp, grind =] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
simp [flatten]
set_option linter.listVariables false in
@@ -1922,17 +1931,17 @@ theorem forall_mem_flatten {p : α → Prop} {xss : Vector (Vector α n) m} :
induction xss using vector₂_induction with
| of xss h₁ h₂ => simp
@[simp, grind] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
@[simp, grind =] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
flatten (xss₁ ++ xss₂) = (flatten xss₁ ++ flatten xss₂).cast (by simp [Nat.add_mul]) := by
induction xss₁ using vector₂_induction
induction xss₂ using vector₂_induction
simp
@[grind] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
@[grind =] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
flatten xss₁ ++ flatten xss₂ = (flatten (xss₁ ++ xss₂)).cast (by simp [Nat.add_mul]) := by
simp
@[grind] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
@[grind =] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
flatten (xss.push xs) = (flatten xss ++ xs).cast (by simp [Nat.add_mul]) := by
induction xss using vector₂_induction
rcases xs with xs
@@ -1982,10 +1991,10 @@ theorem flatMap_def {xs : Vector α n} {f : α → Vector β m} : xs.flatMap f =
rcases xs with xs, rfl
simp [Array.flatMap_def, Function.comp_def]
@[simp, grind] theorem flatMap_empty {f : α Vector β m} :
@[simp, grind =] theorem flatMap_empty {f : α Vector β m} :
(#v[] : Vector α 0).flatMap f = #v[].cast (by simp) := rfl
@[simp, grind] theorem flatMap_push {xs : Vector α n} {x : α} {f : α Vector β m} :
@[simp, grind =] theorem flatMap_push {xs : Vector α n} {x : α} {f : α Vector β m} :
(xs.push x).flatMap f = (xs.flatMap f ++ f x).cast (by simp [Nat.add_mul]) := by
rcases xs with xs, rfl
simp
@@ -2011,7 +2020,7 @@ theorem getElem?_flatMap {xs : Vector α n} {f : α → Vector β m} {i : Nat} :
@[simp] theorem flatMap_id' {xss : Vector (Vector α m) n} : xss.flatMap (fun xs => xs) = xss.flatten := by simp [flatMap_def]
@[simp, grind] theorem mem_flatMap {f : α Vector β m} {b} {xs : Vector α n} : b xs.flatMap f a, a xs b f a := by
@[simp, grind =] theorem mem_flatMap {f : α Vector β m} {b} {xs : Vector α n} : b xs.flatMap f a, a xs 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₂
@@ -2074,7 +2083,7 @@ theorem replicate_succ' : replicate (n + 1) a = (#v[a] ++ replicate n a).cast (b
@[deprecated replicate_succ' (since := "2025-03-18")]
abbrev mkVector_succ' := @replicate_succ'
@[simp, grind] theorem mem_replicate {a b : α} {n} : b replicate n a n 0 b = a := by
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b replicate n a n 0 b = a := by
unfold replicate
simp only [mem_mk]
simp
@@ -2094,14 +2103,14 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[deprecated forall_mem_replicate (since := "2025-03-18")]
abbrev forall_mem_mkVector := @forall_mem_replicate
@[simp, grind] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
@[simp, grind =] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
rw [replicate_eq_mk_replicate, getElem_mk]
simp
@[deprecated getElem_replicate (since := "2025-03-18")]
abbrev getElem_mkVector := @getElem_replicate
@[grind] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
@[grind =] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
simp [getElem?_def]
@[deprecated getElem?_replicate (since := "2025-03-18")]
@@ -2227,16 +2236,16 @@ abbrev sum_mkVector := @sum_replicate_nat
theorem reverse_empty : reverse (#v[] : Vector α 0) = #v[] := rfl
@[simp, grind] theorem reverse_push {as : Vector α n} {a : α} :
@[simp, grind =] theorem reverse_push {as : Vector α n} {a : α} :
(as.push a).reverse = (#v[a] ++ as.reverse).cast (by omega) := by
rcases as with as, rfl
simp [Array.reverse_push]
@[simp, grind] theorem mem_reverse {x : α} {as : Vector α n} : x as.reverse x as := by
@[simp, grind =] theorem mem_reverse {x : α} {as : Vector α n} : x as.reverse x as := by
cases as
simp
@[simp, grind] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
@[simp, grind =] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
(xs.reverse)[i] = xs[n - 1 - i] := by
rcases xs with xs, rfl
simp
@@ -2252,14 +2261,14 @@ theorem getElem?_reverse' {xs : Vector α n} {i j : Nat} (h : i + j + 1 = n) : x
rcases xs with xs, rfl
simpa using Array.getElem?_reverse' h
@[simp, grind]
@[simp, grind =]
theorem getElem?_reverse {xs : Vector α n} {i} (h : i < n) :
xs.reverse[i]? = xs[n - 1 - i]? := by
cases xs
simp_all
-- The argument `xs : Vector α n` is explicit so we can rewrite from right to left.
@[simp, grind] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
@[simp, grind =] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
rcases xs with xs, rfl
simp [Array.reverse_reverse]
@@ -2279,13 +2288,13 @@ theorem reverse_eq_iff {xs ys : Vector α n} : xs.reverse = ys ↔ xs = ys.rever
rcases xs with xs, rfl
simp [Array.map_reverse]
@[simp, grind] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
@[simp, grind =] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
(xs ++ ys).reverse = (ys.reverse ++ xs.reverse).cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
simp [Array.reverse_append]
@[grind] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
@[grind =] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
ys.reverse ++ xs.reverse = (xs ++ ys).reverse.cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
@@ -2320,7 +2329,7 @@ theorem flatMap_reverse {xs : Vector α n} {f : α → Vector β m} :
rcases xs with xs, rfl
simp [Array.flatMap_reverse, Function.comp_def]
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
rw [ toArray_inj]
simp
@@ -2345,7 +2354,7 @@ set_option linter.indexVariables false in
rcases as with as, rfl
simp
@[grind] theorem extract_empty {start stop : Nat} :
@[grind =] theorem extract_empty {start stop : Nat} :
(#v[] : Vector α 0).extract start stop = #v[].cast (by simp) := by
simp
@@ -2361,11 +2370,11 @@ theorem foldlM_empty [Monad m] {f : β → α → m β} {init : β} :
foldlM f init #v[] = return init := by
simp
@[grind] theorem foldrM_empty [Monad m] {f : α β m β} {init : β} :
@[grind =] theorem foldrM_empty [Monad m] {f : α β m β} {init : β} :
foldrM f init #v[] = return init := by
simp
@[simp, grind] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β α m β} {b} :
@[simp, grind =] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β α m β} {b} :
(xs.push a).foldlM f b = xs.foldlM f b >>= fun b => f b a := by
rcases xs with xs, rfl
simp
@@ -2410,16 +2419,16 @@ theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Vector α n} :
rcases xs with xs, rfl
simp
@[simp, grind] theorem foldrM_push [Monad m] {f : α β m β} {init : β} {xs : Vector α n} {a : α} :
@[simp, grind =] theorem foldrM_push [Monad m] {f : α β m β} {init : β} {xs : Vector α n} {a : α} :
(xs.push a).foldrM f init = f a init >>= xs.foldrM f := by
rcases xs with xs, rfl
simp
/-! ### foldl / foldr -/
@[grind] theorem foldl_empty {f : β α β} {init : β} : (#v[].foldl f init) = init := rfl
@[grind =] theorem foldl_empty {f : β α β} {init : β} : (#v[].foldl f init) = init := rfl
@[grind] theorem foldr_empty {f : α β β} {init : β} : (#v[].foldr f init) = init := rfl
@[grind =] theorem foldr_empty {f : α β β} {init : β} : (#v[].foldr f init) = init := rfl
@[congr]
theorem foldl_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : β α β} (h₁ : f = g)
@@ -2433,12 +2442,12 @@ theorem foldr_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : α → β →
xs.foldr f a = ys.foldr g b := by
congr
@[simp, grind] theorem foldl_push {f : β α β} {init : β} {xs : Vector α n} {a : α} :
@[simp, grind =] theorem foldl_push {f : β α β} {init : β} {xs : Vector α n} {a : α} :
(xs.push a).foldl f init = f (xs.foldl f init) a := by
rcases xs with xs, rfl
simp
@[simp, grind] theorem foldr_push {f : α β β} {init : β} {xs : Vector α n} {a : α} :
@[simp, grind =] theorem foldr_push {f : α β β} {init : β} {xs : Vector α n} {a : α} :
(xs.push a).foldr f init = xs.foldr f (f a init) := by
rcases xs with xs, rfl
simp
@@ -2490,21 +2499,21 @@ theorem foldr_map_hom {g : α → β} {f : ααα} {f' : β → β →
@[simp, grind _=_] theorem foldr_append {f : α β β} {b} {xs : Vector α n} {ys : Vector α k} :
(xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b) := foldrM_append
@[simp, grind] theorem foldl_flatten {f : β α β} {b} {xss : Vector (Vector α m) n} :
@[simp, grind =] theorem foldl_flatten {f : β α β} {b} {xss : Vector (Vector α m) n} :
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
cases xss using vector₂_induction
simp [Array.foldl_flatten', Array.foldl_map']
@[simp, grind] theorem foldr_flatten {f : α β β} {b} {xss : Vector (Vector α m) n} :
@[simp, grind =] theorem foldr_flatten {f : α β β} {b} {xss : Vector (Vector α m) n} :
(flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
cases xss using vector₂_induction
simp [Array.foldr_flatten', Array.foldr_map']
@[simp, grind] theorem foldl_reverse {xs : Vector α n} {f : β α β} {b} :
@[simp, grind =] theorem foldl_reverse {xs : Vector α n} {f : β α β} {b} :
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
foldlM_reverse
@[simp, grind] theorem foldr_reverse {xs : Vector α n} {f : α β β} {b} :
@[simp, grind =] theorem foldr_reverse {xs : Vector α n} {f : α β β} {b} :
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
(foldl_reverse ..).symm.trans <| by simp
@@ -2598,7 +2607,7 @@ theorem back?_eq_some_iff {xs : Vector α n} {a : α} :
simp only [mk_append_mk, back_mk]
rw [Array.back_append_of_size_pos]
@[grind] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
@[grind =] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
(xs ++ ys).back =
if h' : m = 0 then
have : NeZero n := by subst h'; simp_all
@@ -2629,7 +2638,7 @@ theorem back_append_left {xs : Vector α n} {ys : Vector α 0} [NeZero n] :
simp only [mk_append_mk, back_mk]
rw [Array.back_append_left _ h]
@[simp, grind] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
@[simp, grind =] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
rcases xs with xs, rfl
rcases ys with ys, rfl
simp
@@ -2681,24 +2690,28 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Vector α n} {a : α} :
rcases xs with xs, rfl
simp [Array.contains_iff_exists_mem_beq]
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
grind_pattern contains_iff_exists_mem_beq => xs.contains a
@[grind _=_]
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Vector α n} {a : α} :
xs.contains a a xs := by
simp
@[simp, grind]
@[simp, grind =]
theorem contains_toList [BEq α] {xs : Vector α n} {x : α} :
xs.toList.contains x = xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind]
@[simp, grind =]
theorem contains_toArray [BEq α] {xs : Vector α n} {x : α} :
xs.toArray.contains x = xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind]
@[simp, grind =]
theorem contains_map [BEq β] {xs : Vector α n} {x : β} {f : α β} :
(xs.map f).contains x = xs.any (fun a => x == f a) := by
rcases xs with xs
@@ -2723,19 +2736,19 @@ theorem contains_append [BEq α] {xs : Vector α n} {ys : Vector α m} {x : α}
rcases ys with ys, rfl
simp
@[simp, grind]
@[simp, grind =]
theorem contains_flatten [BEq α] {xs : Vector (Vector α n) m} {x : α} :
(xs.flatten).contains x = xs.any fun xs => xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind]
@[simp, grind =]
theorem contains_reverse [BEq α] {xs : Vector α n} {x : α} :
(xs.reverse).contains x = xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind]
@[simp, grind =]
theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α Vector β m} {x : β} :
(xs.flatMap f).contains x = xs.any fun a => (f a).contains x := by
rcases xs with xs, rfl
@@ -2747,7 +2760,7 @@ theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α → Vector β m} {x
@[simp] theorem pop_push {xs : Vector α n} {x : α} : (xs.push x).pop = xs := by simp [pop]
@[simp, grind] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
@[simp, grind =] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
xs.pop[i] = xs[i] := by
rcases xs with xs, rfl
simp
@@ -2760,7 +2773,7 @@ defeq issues in the implicit size argument.
@getElem (Vector α n) Nat α (fun _ i => i < n) instGetElemNatLt xs.pop i h = xs[i] :=
getElem_pop h
@[grind] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
@[grind =] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
xs.pop[i]? = if i < n - 1 then xs[i]? else none := by
rcases xs with xs, rfl
simp [Array.getElem?_pop]
@@ -2908,15 +2921,15 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
unfold all
apply allM_congr w h
@[simp, grind] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
@[simp, grind =] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
cases xss using vector₂_induction
simp
@[simp, grind] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
@[simp, grind =] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
cases xss using vector₂_induction
simp
@[simp, grind] theorem any_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
@[simp, grind =] theorem any_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
(xs.flatMap f).any p = xs.any fun a => (f a).any p := by
rcases xs with xs
simp only [flatMap_mk, any_mk, Array.size_flatMap, size_toArray, Array.any_flatMap']
@@ -2925,7 +2938,7 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
congr
simp [Vector.size_toArray]
@[simp, grind] theorem all_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
@[simp, grind =] theorem all_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
(xs.flatMap f).all p = xs.all fun a => (f a).all p := by
rcases xs with xs
simp only [flatMap_mk, all_mk, Array.size_flatMap, size_toArray, Array.all_flatMap']
@@ -2934,11 +2947,11 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
congr
simp [Vector.size_toArray]
@[simp, grind] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
@[simp, grind =] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
rcases xs with xs, rfl
simp
@[simp, grind] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
@[simp, grind =] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
rcases xs with xs, rfl
simp
@@ -2974,9 +2987,9 @@ variable [BEq α]
rcases xs with xs, rfl
simp
@[simp, grind] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
@[simp, grind =] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
@[grind] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
@[grind =] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
simp
-- This hypothesis could probably be dropped from some of the lemmas below,
@@ -2987,7 +3000,7 @@ variable [LawfulBEq α]
rcases xs with xs, rfl
simp_all
@[grind] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
@[grind =] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
(xs.replace a b)[i]? = if xs[i]? == some a then if a xs.take i then some a else some b else xs[i]? := by
rcases xs with xs, rfl
simp [Array.getElem?_replace, -beq_iff_eq]
@@ -2996,7 +3009,7 @@ theorem getElem?_replace_of_ne {xs : Vector α n} {i : Nat} (h : xs[i]? ≠ some
(xs.replace a b)[i]? = xs[i]? := by
simp_all [getElem?_replace]
@[grind] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
@[grind =] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
(xs.replace a b)[i] = if xs[i] == a then if a xs.take i then a else b else xs[i] := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_replace]
@@ -3007,7 +3020,7 @@ theorem getElem_replace_of_ne {xs : Vector α n} {i : Nat} {h : i < n} (h' : xs[
rw [getElem_replace h]
simp [h']
@[grind] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
@[grind =] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
(xs ++ ys).replace a b = if a xs then xs.replace a b ++ ys else xs ++ ys.replace a b := by
rcases xs with xs, rfl
rcases ys with ys, rfl
@@ -3022,7 +3035,7 @@ theorem replace_append_right {xs : Vector α n} {ys : Vector α m} (h : ¬ a ∈
(xs ++ ys).replace a b = xs ++ ys.replace a b := by
simp [replace_append, h]
@[grind] theorem replace_push {xs : Vector α n} {a b c : α} :
@[grind =] theorem replace_push {xs : Vector α n} {a b c : α} :
(xs.push a).replace b c = if b xs then (xs.replace b c).push a else xs.push (if b == a then c else a) := by
rcases xs with xs, rfl
simp only [push_mk, replace_mk, Array.replace_push, mem_mk]
@@ -3091,7 +3104,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
/-! ### swap -/
@[grind] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
@[grind =] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
cases xs
simp_all [Array.getElem_swap]
@@ -3108,7 +3121,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
(hi' : k i) (hj' : k j) : (xs.swap i j hi hj)[k] = xs[k] := by
simp_all [getElem_swap]
@[grind]
@[grind =]
theorem getElem?_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
rcases xs with xs, rfl

View File

@@ -166,25 +166,25 @@ export LawfulGetElem (getElem?_def getElem!_def)
instance (priority := low) [GetElem coll idx elem valid] [ xs i, Decidable (valid xs i)] :
LawfulGetElem coll idx elem valid where
@[simp, grind] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind =] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
(c : cont) (i : idx) (h : dom c i) : c[i]? = some (c[i]'h) := by
have : Decidable (dom c i) := .isTrue h
rw [getElem?_def]
exact dif_pos h
@[simp, grind] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind =] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
(c : cont) (i : idx) (h : ¬dom c i) : c[i]? = none := by
have : Decidable (dom c i) := .isFalse h
rw [getElem?_def]
exact dif_neg h
@[simp, grind] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind =] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
[Inhabited elem] (c : cont) (i : idx) (h : dom c i) :
c[i]! = c[i]'h := by
have : Decidable (dom c i) := .isTrue h
simp [getElem!_def, h]
@[simp, grind] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind =] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
[Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) : c[i]! = default := by
have : Decidable (dom c i) := .isFalse h
simp [getElem!_def, h]
@@ -291,18 +291,20 @@ namespace List
instance : GetElem (List α) Nat α fun as i => i < as.length where
getElem as i h := as.get i, h
@[simp, grind]
@[simp, grind =]
theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) :
getElem (a :: as) 0 h = a := rfl
@[simp, grind]
@[simp, grind =]
theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) :=
rfl
@[simp, grind] theorem getElem_mem : {l : List α} {n} (h : n < l.length), l[n]'h l
@[simp] theorem getElem_mem : {l : List α} {n} (h : n < l.length), l[n]'h l
| _ :: _, 0, _ => .head ..
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
grind_pattern getElem_mem => l[n]'h l
theorem getElem_cons_drop_succ_eq_drop {as : List α} {i : Nat} (h : i < as.length) :
as[i] :: as.drop (i+1) = as.drop i :=
match as, i with

View File

@@ -518,7 +518,7 @@ theorem Seq.contains_k_cons (y x : Var) (s : Seq) : Seq.contains_k (.cons y s) x
attribute [local simp] Seq.contains_k_var Seq.contains_k_cons
theorem Seq.denote_insert_of_contains {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.Commutative ctx.op} {inst₃ : Std.IdempotentOp ctx.op}
theorem Seq.denote_insert_of_contains {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.Commutative ctx.op] [inst₃ : Std.IdempotentOp ctx.op]
(s : Seq) (x : Var) : s.contains_k x (s.insert x).denote ctx = s.denote ctx := by
induction s
next => simp; intro; subst x; rw [Std.IdempotentOp.idempotent (self := inst₃)]
@@ -544,7 +544,68 @@ theorem superpose_ac_idempotent {α} (ctx : Context α) {inst₁ : Std.Associati
simp [superpose_ac_idempotent_cert]; intro h₁ _ h₂; subst rhs
replace h₂ : Seq.denote ctx (lhs₁.insert x) = Seq.denote ctx (rhs₁.insert x) := by
simp [h₂]
rw [ h₂, Seq.denote_insert_of_contains ctx lhs₁ x h₁] <;> assumption
rw [ h₂, Seq.denote_insert_of_contains ctx lhs₁ x h₁]
noncomputable def Seq.startsWithVar_k (s : Seq) (x : Var) : Bool :=
Seq.rec (fun y => Nat.beq x y) (fun y _ _ => Nat.beq x y) s
theorem Seq.startsWithVar_k_var (y x : Var) : Seq.startsWithVar_k (.var y) x = (x == y) := by
simp [startsWithVar_k]; rw [Bool.eq_iff_iff]; simp
theorem Seq.startsWithVar_k_cons (y x : Var) (s : Seq) : Seq.startsWithVar_k (.cons y s) x = (x == y) := by
simp [startsWithVar_k]; rw [Bool.eq_iff_iff]; simp
attribute [local simp] Seq.startsWithVar_k_var Seq.startsWithVar_k_cons
theorem Seq.denote_concat_of_startsWithVar {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.IdempotentOp ctx.op]
(s : Seq) (x : Var) : s.startsWithVar_k x (concat_k (.var x) s).denote ctx = s.denote ctx := by
cases s <;> simp <;> intro <;> subst x
next => rw [Std.IdempotentOp.idempotent (self := inst₂)]
next => rw [ Std.Associative.assoc (self := inst₁), Std.IdempotentOp.idempotent (self := inst₂)]
noncomputable def superpose_head_idempotent_cert (x : Var) (lhs₁ rhs₁ rhs : Seq) : Bool :=
lhs₁.startsWithVar_k x |>.and' (rhs.beq' (Seq.concat (.var x) rhs₁))
/--
`superpose_ac_idempotent` for the non-commutative case. This is the "head"-case
-/
theorem superpose_head_idempotent {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.IdempotentOp ctx.op}
(x : Var) (lhs₁ rhs₁ rhs : Seq) : superpose_head_idempotent_cert x lhs₁ rhs₁ rhs lhs₁.denote ctx = rhs₁.denote ctx lhs₁.denote ctx = rhs.denote ctx := by
simp [superpose_head_idempotent_cert]; intro h₁ _ h₂; subst rhs
replace h₂ : Seq.denote ctx (Seq.concat (.var x) lhs₁) = Seq.denote ctx (Seq.concat (.var x) rhs₁) := by
simp [h₂]
rw [ h₂, Seq.concat_k_eq_concat, Seq.denote_concat_of_startsWithVar ctx lhs₁ x h₁]
noncomputable def Seq.endsWithVar_k (s : Seq) (x : Var) : Bool :=
Seq.rec (fun y => Nat.beq x y) (fun _ _ ih => ih) s
theorem Seq.endsWithVar_k_var (y x : Var) : Seq.endsWithVar_k (.var y) x = (x == y) := by
simp [Seq.endsWithVar_k]; rw [Bool.eq_iff_iff]; simp
theorem Seq.endsWithVar_k_cons (y x : Var) (s : Seq) : Seq.endsWithVar_k (.cons y s) x = s.endsWithVar_k x := rfl
attribute [local simp] Seq.endsWithVar_k_var Seq.endsWithVar_k_cons
theorem Seq.denote_concat_of_endsWithVar {α} (ctx : Context α) [inst₁ : Std.Associative ctx.op] [inst₂ : Std.IdempotentOp ctx.op]
(s : Seq) (x : Var) : s.endsWithVar_k x (s.concat_k (.var x)).denote ctx = s.denote ctx := by
induction s
next => simp; intro; subst x; rw [Std.IdempotentOp.idempotent (self := inst₂)]
next ih =>
simp; intro h; replace ih := ih h
simp at ih; rw [Std.Associative.assoc (self := inst₁), ih]
noncomputable def superpose_tail_idempotent_cert (x : Var) (lhs₁ rhs₁ rhs : Seq) : Bool :=
lhs₁.endsWithVar_k x |>.and' (rhs.beq' (Seq.concat rhs₁ (.var x)))
/--
`superpose_ac_idempotent` for the non-commutative case. It is similar to `superpose_head_idempotent` but for the "tail"-case
-/
theorem superpose_tail_idempotent {α} (ctx : Context α) {inst₁ : Std.Associative ctx.op} {inst₂ : Std.IdempotentOp ctx.op}
(x : Var) (lhs₁ rhs₁ rhs : Seq) : superpose_tail_idempotent_cert x lhs₁ rhs₁ rhs lhs₁.denote ctx = rhs₁.denote ctx lhs₁.denote ctx = rhs.denote ctx := by
simp [superpose_tail_idempotent_cert]; intro h₁ _ h₂; subst rhs
replace h₂ : Seq.denote ctx (Seq.concat lhs₁ (.var x) ) = Seq.denote ctx (Seq.concat rhs₁ (.var x) ) := by
simp [h₂]
rw [ h₂, Seq.concat_k_eq_concat, Seq.denote_concat_of_endsWithVar ctx lhs₁ x h₁]
noncomputable def eq_norm_a_cert (lhs rhs : Expr) (lhs' rhs' : Seq) : Bool :=
lhs.toSeq.beq' lhs' |>.and' (rhs.toSeq.beq' rhs')
@@ -618,4 +679,37 @@ noncomputable def diseq_unsat_cert (lhs rhs : Seq) : Bool :=
theorem diseq_unsat {α} (ctx : Context α) (lhs rhs : Seq) : diseq_unsat_cert lhs rhs lhs.denote ctx rhs.denote ctx False := by
simp [diseq_unsat_cert]; intro; subst lhs; simp
theorem norm_a {α} (ctx : Context α) {_ : Std.Associative ctx.op} (e : Expr) (s : Seq)
: e.toSeq.beq' s e.denote ctx = s.denote ctx := by
simp; intro _; subst s; simp
theorem norm_ac {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.Commutative ctx.op} (e : Expr) (s : Seq)
: e.toSeq.sort.beq' s e.denote ctx = s.denote ctx := by
simp; intro _; subst s; simp
theorem norm_ai {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
(e : Expr) (s : Seq) : e.toSeq.erase0.beq' s e.denote ctx = s.denote ctx := by
simp; intro _; subst s; simp
theorem norm_aci {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.Commutative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
(e : Expr) (s : Seq) : e.toSeq.erase0.sort.beq' s e.denote ctx = s.denote ctx := by
simp; intro _ ; subst s; simp
theorem eq_erase0_rhs {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.LawfulIdentity ctx.op (Var.denote ctx 0)}
(lhs rhs rhs' : Seq) : rhs.erase0.beq' rhs' lhs.denote ctx = rhs.denote ctx lhs.denote ctx = rhs'.denote ctx := by
simp; intro _ _; subst rhs'; simp [*]
theorem eq_erase_dup_rhs {α} (ctx : Context α) {_ : Std.Associative ctx.op} {_ : Std.IdempotentOp ctx.op}
(lhs rhs rhs' : Seq) : rhs.eraseDup.beq' rhs' lhs.denote ctx = rhs.denote ctx lhs.denote ctx = rhs'.denote ctx := by
simp; intro _ _; subst rhs'; simp [*]
theorem eq_expr_seq_seq {α} (ctx : Context α) (e : Expr) (s₁ s₂ : Seq) : e.denote ctx = s₁.denote ctx s₁.denote ctx = s₂.denote ctx e.denote ctx = s₂.denote ctx := by
apply Eq.trans
theorem imp_eq {α} (ctx : Context α) (lhs rhs : Expr) (s : Seq)
: lhs.denote ctx = s.denote ctx rhs.denote ctx = s.denote ctx lhs.denote ctx = rhs.denote ctx := by
simp_all
theorem refl {α} (ctx : Context α) (s : Seq) : s.denote ctx = s.denote ctx := (rfl)
end Lean.Grind.AC

View File

@@ -95,7 +95,7 @@ Ordinarily, the grind attribute does not consider the `=` symbol when generating
-/
syntax grindEqBwd := patternIgnore(atomic("" "=") <|> atomic("<-" "="))
/--
The `` modifier instructs `grind` to select a multi-pattern from the conclusion of theorem.
The `` modifier instructs `grind` to select a multi-pattern from the conclusion of theorem.
In other words, `grind` will use the theorem for backwards reasoning.
This may fail if not all of the arguments to the theorem appear in the conclusion.
-/

View File

@@ -4,10 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
module
prelude
public import Init.Grind.Module.Basic
public import Init.Grind.Module.Envelope
public import Init.Grind.Module.OfNatModule
public import Init.Grind.Module.NatModuleNorm
public section

View File

@@ -227,7 +227,7 @@ theorem toQ_add (a b : α) : toQ (a + b) = toQ a + toQ b := by
theorem toQ_zero : toQ (0 : α) = 0 := by
simp; apply Quot.sound; simp
theorem toQ_smul (n : Nat) (a : α) : toQ (n a) = (n : Int) toQ a := by
theorem toQ_smul (n : Nat) (a : α) : toQ (n a) = n toQ a := by
simp; apply Quot.sound; simp
/-!
@@ -318,6 +318,29 @@ instance [LE α] [IsPreorder α] [OrderedAdd α] : IsPreorder (OfNatModule.Q α)
rw [this]; clear this
exact OrderedAdd.add_le_add h₁ h₂
instance [LE α] [IsPartialOrder α] [OrderedAdd α] : IsPartialOrder (OfNatModule.Q α) where
le_antisymm a b h₁ h₂ := by
induction a using Q.ind with | _ a
induction b using Q.ind with | _ b
rcases a with a₁, a₂; rcases b with b₁, b₂
simp only [mk_le_mk] at h₁ h₂
rw [AddCommMonoid.add_comm b₁ a₂, AddCommMonoid.add_comm b₂ a₁] at h₂
have := IsPartialOrder.le_antisymm _ _ h₁ h₂
apply Quot.sound
simp; exists 0
rw [this]
instance [LE α] [IsLinearPreorder α] [OrderedAdd α] : IsLinearPreorder (OfNatModule.Q α) where
le_total a b := by
induction a using Q.ind with | _ a
induction b using Q.ind with | _ b
rcases a with a₁, a₂; rcases b with b₁, b₂
simp only [mk_le_mk]
rw [AddCommMonoid.add_comm b₁ a₂, AddCommMonoid.add_comm b₂ a₁]
apply le_total
instance [LE α] [IsLinearOrder α] [OrderedAdd α] : IsLinearOrder (OfNatModule.Q α) where
attribute [-simp] Q.mk
@[local simp] private theorem mk_lt_mk

View File

@@ -0,0 +1,199 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module
prelude
public import Init.Grind.Module.Envelope
public import Init.Grind.Ordered.Linarith
@[expose] public section
namespace Lean.Grind.Linarith
open Std
def Expr.denoteN {α} [NatModule α] (ctx : Context α) : Expr α
| .sub .. | .neg .. | .intMul ..
| zero => 0
| .var v => v.denote ctx
| .add a b => denoteN ctx a + denoteN ctx b
| .natMul k a => k denoteN ctx a
inductive Poly.NonnegCoeffs : Poly Prop
| nil : NonnegCoeffs .nil
| add (a : Int) (x : Var) (p : Poly) : a 0 NonnegCoeffs p NonnegCoeffs (.add a x p)
def Poly.denoteN {α} [NatModule α] (ctx : Context α) (p : Poly) : α :=
match p with
| .nil => 0
| .add k v p =>
bif k < 0 then
0
else
k.natAbs v.denote ctx + denoteN ctx p
def Poly.denoteN_nil {α} [NatModule α] (ctx : Context α) : Poly.denoteN ctx .nil = 0 := rfl
def Poly.denoteN_add {α} [NatModule α] (ctx : Context α) (k : Int) (x : Var) (p : Poly)
: k 0 Poly.denoteN ctx (.add k x p) = k.toNat x.denote ctx + p.denoteN ctx := by
intro h; simp [denoteN, cond_eq_if]; split
next => omega
next =>
have : (k.natAbs : Int) = k.toNat := by
rw [Int.toNat_of_nonneg h, Int.natAbs_of_nonneg h]
rw [Int.ofNat_inj.mp this]
attribute [local simp] Poly.denoteN_nil Poly.denoteN_add
open AddCommMonoid AddCommGroup NatModule IntModule
-- Helper instance for `ac_rfl`
local instance {α} [NatModule α] : Std.Associative (· + · : α α α) where
assoc := AddCommMonoid.add_assoc
-- Helper instance for `ac_rfl`
local instance {α} [NatModule α] : Std.Commutative (· + · : α α α) where
comm := AddCommMonoid.add_comm
theorem Poly.denoteN_insert {α} [NatModule α] (ctx : Context α) (k : Int) (x : Var) (p : Poly)
: k 0 p.NonnegCoeffs (insert k x p).denoteN ctx = k.toNat x.denote ctx + p.denoteN ctx := by
fun_induction insert
next => intros; simp [*]
next => intro h₁ h₂; cases h₂; simp [*]
next h₁ h₂ h₃ =>
intro h₄ h₅; cases h₅; simp [*]
simp at h₃; simp at h₂; subst h₂
rw [ add_assoc, add_nsmul, Int.toNat_add, h₃, Int.toNat_zero, zero_nsmul, zero_add] <;> assumption
next h _ =>
intro h₁ h₂; cases h₂; rw [denoteN_add] <;> simp <;> try omega
next h₂ _ =>
simp at h; subst h;
rw [Int.toNat_add h₁ h₂, add_nsmul]; simp [*]; ac_rfl
next ih =>
intro h₁ h₂; cases h₂; simp [*]; ac_rfl
attribute [local simp] Poly.denoteN_insert
theorem Poly.denoteN_append {α} [NatModule α] (ctx : Context α) (p₁ p₂ : Poly)
: p₁.NonnegCoeffs p₂.NonnegCoeffs (append p₁ p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
fun_induction append <;> intro h₁ h₂; simp [*]
next => rw [zero_add]
next ih => cases h₁; next hn₁ hn₂ => simp [ih hn₂ h₂, *]; ac_rfl
attribute [local simp] Poly.denoteN_append
theorem Poly.denoteN_combine' {α} [NatModule α] (ctx : Context α) (fuel : Nat) (p₁ p₂ : Poly)
: p₁.NonnegCoeffs p₂.NonnegCoeffs (p₁.combine' fuel p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
fun_induction p₁.combine' fuel p₂ <;> intro h₁ h₂ <;> try simp [*, zero_add, add_zero]
next hx _ h ih =>
simp at hx
simp +zetaDelta at h
cases h₁; cases h₂
next h₁ _ h₂ =>
simp [ih h₁ h₂, *]
rw [add_left_comm, add_assoc, add_assoc, add_nsmul, Int.toNat_add, Int.add_comm, h,
Int.toNat_zero, zero_nsmul, zero_add] <;> assumption
next hx _ h ih =>
simp at hx
cases h₁; cases h₂
next hp₁ h₁ hp₂ h₂ =>
simp +zetaDelta [*]
rw [denoteN_add, ih h₁ h₂, Int.toNat_add hp₁ hp₂, add_nsmul]; ac_rfl; omega
next ih =>
cases h₁; next h₁ =>
simp [ih h₁ h₂, *]; ac_rfl
next ih =>
cases h₂; next h₂ =>
simp [ih h₁ h₂, *]; ac_rfl
theorem Poly.denoteN_combine {α} [NatModule α] (ctx : Context α) (p₁ p₂ : Poly)
: p₁.NonnegCoeffs p₂.NonnegCoeffs (p₁.combine p₂).denoteN ctx = p₁.denoteN ctx + p₂.denoteN ctx := by
intros; simp [combine, denoteN_combine', *]
theorem Poly.denoteN_mul' {α} [NatModule α] (ctx : Context α) (p : Poly) (k : Nat) : p.NonnegCoeffs (p.mul' k).denoteN ctx = k p.denoteN ctx := by
induction p <;> simp [mul', *, nsmul_zero]
next ih =>
intro h; cases h; next hp h =>
have hk : (k : Int) 0 := by simp
simp [*]
rw [denoteN_add, Int.toNat_mul, mul_nsmul, Int.toNat_natCast, nsmul_add, ih h]
assumption; assumption;
exact Int.mul_nonneg hk hp
theorem Poly.denoteN_mul {α} [NatModule α] (ctx : Context α) (p : Poly) (k : Nat) : p.NonnegCoeffs (p.mul k).denoteN ctx = k p.denoteN ctx := by
simp [mul]; intro h
split
next => simp [*, zero_nsmul]
next => simp [denoteN_mul', *]
def Expr.toPolyN : Expr Poly
| .sub .. | .neg .. | .intMul ..
| zero => .nil
| .var v => .add 1 v .nil
| .add a b => a.toPolyN.combine b.toPolyN
| .natMul k a => a.toPolyN.mul k
theorem Poly.mul'_Nonneg (p : Poly) (k : Nat) : p.NonnegCoeffs (p.mul' k).NonnegCoeffs := by
induction p
next => intro; simp [mul']; assumption
next ih =>
have hk : (k : Int) 0 := by simp
intro h; cases h; next hp h =>
simp [mul']
constructor
next => exact Int.mul_nonneg hk hp
next => exact ih h
theorem Poly.mul_Nonneg (p : Poly) (k : Nat) : p.NonnegCoeffs (p.mul k).NonnegCoeffs := by
simp [mul]; intro h
split
next => constructor
next => simp [Poly.mul'_Nonneg, *]
theorem Poly.append_Nonneg (p₁ p₂ : Poly) : p₁.NonnegCoeffs p₂.NonnegCoeffs (p₁.append p₂).NonnegCoeffs := by
fun_induction append <;> intro h₁ h₂; simp [*]
next ih => cases h₁; constructor; assumption; apply ih <;> assumption
theorem Poly.combine'_Nonneg (fuel : Nat) (p₁ p₂ : Poly) : p₁.NonnegCoeffs p₂.NonnegCoeffs (p₁.combine' fuel p₂).NonnegCoeffs := by
fun_induction Poly.combine'
next => apply Poly.append_Nonneg
next => intros; assumption
next => intros; assumption
next ih =>
intro h₁ h₂; cases h₁; cases h₂
apply ih <;> assumption
next h ih =>
intro h₁ h₂; cases h₁; cases h₂
constructor; simp +zetaDelta; omega
apply ih <;> assumption
next ih =>
intro h₁ h₂; cases h₁; cases h₂
constructor; simp +zetaDelta; omega
apply ih; assumption; constructor; assumption; assumption
next ih =>
intro h₁ h₂; cases h₁; cases h₂
constructor; assumption
apply ih; constructor; assumption; assumption; assumption
theorem Poly.combine_Nonneg (p₁ p₂ : Poly) : p₁.NonnegCoeffs p₂.NonnegCoeffs (p₁.combine p₂).NonnegCoeffs := by
simp [combine]; apply Poly.combine'_Nonneg
theorem Expr.toPolyN_Nonneg (e : Expr) : e.toPolyN.NonnegCoeffs := by
fun_induction toPolyN <;> try constructor <;> simp
next => constructor; simp; constructor
next => apply Poly.combine_Nonneg <;> assumption
next => apply Poly.mul_Nonneg; assumption
theorem Expr.denoteN_toPolyN {α} [NatModule α] (ctx : Context α) (e : Expr) : e.toPolyN.denoteN ctx = e.denoteN ctx := by
fun_induction toPolyN <;> simp [denoteN, add_zero, one_nsmul]
next => rw [Poly.denoteN_combine]; simp [*]; apply toPolyN_Nonneg; apply toPolyN_Nonneg
next => rw [Poly.denoteN_mul]; simp [*]; apply toPolyN_Nonneg
def eq_normN_cert (lhs rhs : Expr) : Bool :=
lhs.toPolyN == rhs.toPolyN
theorem eq_normN {α} [NatModule α] (ctx : Context α) (lhs rhs : Expr)
: eq_normN_cert lhs rhs lhs.denoteN ctx = rhs.denoteN ctx := by
simp [eq_normN_cert]; intro h
replace h := congrArg (Poly.denoteN ctx) h
simp [Expr.denoteN_toPolyN, *] at h
assumption
end Lean.Grind.Linarith

View File

@@ -4,13 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module
prelude
import Init.Grind.Module.Envelope
open Std
public import Init.Grind.Module.Envelope
public section
namespace Lean.Grind.IntModule.OfNatModule
open Std
/-!
Support for `NatModule` in the `grind` linear arithmetic module.
@@ -44,8 +42,7 @@ theorem add_congr {α} [NatModule α] {a b : α} {a' b' : Q α}
(h₁ : toQ a = a') (h₂ : toQ b = b') : toQ (a + b) = a' + b' := by
rw [toQ_add, h₁, h₂]
theorem smul_congr {α} [NatModule α] (n : Nat) (a : α) (i : Int) (a' : Q α)
(h₁ : n == i) (h₂ : toQ a = a') : toQ (n a) = i a' := by
simp at h₁; rw [ h₁, h₂, toQ_smul]
theorem smul_congr {α} [NatModule α] (n : Nat) (a : α) (a' : Q α) (h : toQ a = a') : toQ (n a) = n a' := by
rw [ h, toQ_smul]
end Lean.Grind.IntModule.OfNatModule

View File

@@ -205,5 +205,13 @@ init_grind_norm
Field.inv_zero Field.inv_inv Field.inv_one Field.inv_neg
-- SMul normalizer
smul_int_eq_mul smul_nat_eq_mul
-- NatCast & IntCast for algebraic structures
Semiring.natCast_add
Semiring.natCast_pow
Semiring.natCast_mul
Ring.intCast_add
Ring.intCast_mul
Ring.intCast_pow
Ring.intCast_sub
end Lean.Grind

View File

@@ -7,6 +7,7 @@ module
prelude
public import Init.NotationExtra
meta import Init.Data.String.Basic
public section

View File

@@ -169,7 +169,8 @@ theorem zpow_add {a : α} (h : a ≠ 0) (m n : Int) : a ^ (m + n) = a ^ m * a ^
| zero => simp [Int.add_neg_one, zpow_sub_one h, zpow_neg_one]
| succ n ih => rw [Int.natCast_add_one, Int.neg_add, Int.add_neg_one, Int.add_sub_assoc, zpow_sub_one h, zpow_sub_one h, ih, Semiring.mul_assoc]
instance [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
-- This is expensive as an instance. Let's see what breaks without it.
def noNatZeroDivisors.ofIsCharPZero [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
intro a b h w
have := IsCharP.natCast_eq_zero_iff (α := α) 0 a
simp only [Nat.mod_zero, h, iff_false] at this

View File

@@ -126,6 +126,52 @@ structure Config where
abstractProof := true
deriving Inhabited, BEq
/--
A minimal configuration, with ematching and splitting disabled, and all solver modules turned off.
`grind` will not do anything in this configuration,
which can be used a starting point for minimal configurations.
-/
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
structure NoopConfig extends Config where
-- Disable splitting
splits := 0
-- We don't override the various `splitMatch` / `splitIte` settings separately.
-- Disable e-matching
ematch := 0
-- We don't override `matchEqs` separately.
-- Disable extensionality
ext := false
extAll := false
etaStruct := false
funext := false
-- Disable all solver modules
ring := false
linarith := false
cutsat := false
ac := false
/--
A `grind` configuration that only uses `cutsat` and splitting.
Note: `cutsat` benefits from some amount of instantiation, e.g. `Nat.max_def`.
We don't currently have a mechanism to enable only a small set of lemmas.
-/
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
structure CutsatConfig extends NoopConfig where
cutsat := true
-- Allow the default number of splits.
splits := ({} : Config).splits
/--
A `grind` configuration that only uses `ring`.
-/
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
structure GrobnerConfig extends NoopConfig where
ring := true
end Lean.Grind
namespace Lean.Parser.Tactic
@@ -420,6 +466,23 @@ syntax (name := grindTrace)
(" [" withoutPosition(grindParam,*) "]")?
(&" on_failure " term)? : tactic
/--
`cutsat` solves linear integer arithmetic goals.
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `cutsat` solver.
Please use `grind` instead if you need additional capabilities.
-/
syntax (name := cutsat) "cutsat" optConfig : tactic
/--
`grobner` solves goals that can be phrased as polynomial equations (with further polynomial equations as hypotheses)
over commutative (semi)rings, using the Grobner basis algorithm.
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `grobner` solver.
Please use `grind` instead if you need additional capabilities.
-/
syntax (name := grobner) "grobner" optConfig : tactic
/-!
Sets symbol priorities for the E-matching pattern inference procedure used in `grind`
-/

View File

@@ -40,7 +40,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt8) = OfNat.of
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
erw [Int.toNat_natCast]
rw [Int.toNat_pow_of_nonneg (by decide)]
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
Nat.mod_mod_of_dvd, instOfNat]
end UInt8
@@ -70,7 +70,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt16) = OfNat.o
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
erw [Int.toNat_natCast]
rw [Int.toNat_pow_of_nonneg (by decide)]
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
Nat.mod_mod_of_dvd, instOfNat]
end UInt16
@@ -100,7 +100,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt32) = OfNat.o
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
erw [Int.toNat_natCast]
rw [Int.toNat_pow_of_nonneg (by decide)]
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
Nat.mod_mod_of_dvd, instOfNat]
end UInt32
@@ -130,7 +130,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt64) = OfNat.o
rw [Int.toNat_emod (Int.zero_le_ofNat x) (by decide)]
erw [Int.toNat_natCast]
rw [Int.toNat_pow_of_nonneg (by decide)]
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
Nat.mod_mod_of_dvd, instOfNat]
end UInt64
@@ -157,7 +157,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : USize) = OfNat.of
rw [Int.toNat_emod (Int.zero_le_ofNat x)]
· erw [Int.toNat_natCast]
rw [Int.toNat_pow_of_nonneg (by decide)]
simp only [ofNat, BitVec.ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
simp only [ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Int.reduceToNat, Nat.dvd_refl,
Nat.mod_mod_of_dvd, instOfNat]
· obtain _ | _ := System.Platform.numBits_eq <;> simp_all

View File

@@ -10,7 +10,13 @@ prelude
public import Init.ByCases
public import Init.RCases
public import Init.Control.Except -- for `MonoBind` instance
public import Init.Control.StateRef -- for `MonoBind` instance
public import Init.Control.Option -- for `MonoBind` instance
public import Init.System.IO -- for `MonoBind` instance
import all Init.Control.Except -- for `MonoBind` instance
import all Init.Control.StateRef -- for `MonoBind` instance
import all Init.Control.Option -- for `MonoBind` instance
import all Init.System.IO -- for `MonoBind` instance
public section
@@ -790,14 +796,14 @@ on `m` is monotone in both arguments with regard to that order.
This is intended to be used in the construction of `partial_fixpoint`, and not meant to be used otherwise.
-/
class MonoBind (m : Type u Type v) [Bind m] [ α, PartialOrder (m α)] where
bind_mono_left {a₁ a₂ : m α} {f : α m b} (h : a₁ a₂) : a₁ >>= f a₂ >>= f
bind_mono_right {a : m α} {f₁ f₂ : α m b} (h : x, f₁ x f₂ x) : a >>= f₁ a >>= f₂
bind_mono_left {a₁ a₂ : m α} {f : α m β} (h : a₁ a₂) : a₁ >>= f a₂ >>= f
bind_mono_right {a : m α} {f₁ f₂ : α m β} (h : x, f₁ x f₂ x) : a >>= f₁ a >>= f₂
@[partial_fixpoint_monotone]
theorem monotone_bind
(m : Type u Type v) [Bind m] [ α, PartialOrder (m α)] [MonoBind m]
{α β : Type u}
{γ : Type w} [PartialOrder γ]
{γ : Sort w} [PartialOrder γ]
(f : γ m α) (g : γ α m β)
(hmono₁ : monotone f)
(hmono₂ : monotone g) :
@@ -823,9 +829,9 @@ theorem Option.admissible_eq_some (P : Prop) (y : α) :
admissible (fun (x : Option α) => x = some y P) := by
apply admissible_flatOrder; simp
instance [Monad m] [inst : α, PartialOrder (m α)] : PartialOrder (ExceptT ε m α) := inst _
instance [Monad m] [ α, PartialOrder (m α)] [inst : α, CCPO (m α)] : CCPO (ExceptT ε m α) := inst _
instance [Monad m] [ α, PartialOrder (m α)] [ α, CCPO (m α)] [MonoBind m] : MonoBind (ExceptT ε m) where
instance [inst : α, PartialOrder (m α)] : PartialOrder (ExceptT ε m α) := inst _
instance [inst : α, CCPO (m α)] : CCPO (ExceptT ε m α) := inst _
instance [Monad m] [ α, PartialOrder (m α)] [MonoBind m] : MonoBind (ExceptT ε m) where
bind_mono_left h₁₂ := by
apply MonoBind.bind_mono_left (m := m)
exact h₁₂
@@ -836,6 +842,112 @@ instance [Monad m] [∀ α, PartialOrder (m α)] [∀ α, CCPO (m α)] [MonoBind
· apply PartialOrder.rel_refl
· apply h₁₂
@[partial_fixpoint_monotone]
theorem monotone_exceptTRun [PartialOrder γ]
[Monad m] [ α, PartialOrder (m α)]
(f : γ ExceptT ε m α) (hmono : monotone f) :
monotone (fun (x : γ) => ExceptT.run (f x)) :=
hmono
instance [inst : α, PartialOrder (m α)] : PartialOrder (OptionT m α) := inst _
instance [inst : α, CCPO (m α)] : CCPO (OptionT m α) := inst _
instance [Monad m] [ α, PartialOrder (m α)] [MonoBind m] : MonoBind (OptionT m) where
bind_mono_left h₁₂ := by
apply MonoBind.bind_mono_left (m := m)
exact h₁₂
bind_mono_right h₁₂ := by
apply MonoBind.bind_mono_right (m := m)
intro x
cases x
· apply PartialOrder.rel_refl
· apply h₁₂
@[partial_fixpoint_monotone]
theorem monotone_optionTRun [PartialOrder γ]
[Monad m] [ α, PartialOrder (m α)]
(f : γ OptionT m α) (hmono : monotone f) :
monotone (fun (x : γ) => OptionT.run (f x)) :=
hmono
instance [inst : PartialOrder (m α)] : PartialOrder (ReaderT ρ m α) := instOrderPi
instance [inst : CCPO (m α)] : CCPO (ReaderT ρ m α) := instCCPOPi
instance [Monad m] [ α, PartialOrder (m α)] [MonoBind m] : MonoBind (ReaderT ρ m) where
bind_mono_left h₁₂ := by
intro x
apply MonoBind.bind_mono_left (m := m)
exact h₁₂ x
bind_mono_right h₁₂ := by
intro x
apply MonoBind.bind_mono_right (m := m)
intro y
apply h₁₂
@[partial_fixpoint_monotone]
theorem monotone_readerTRun [PartialOrder γ]
[Monad m] [PartialOrder (m α)]
(f : γ ReaderT σ m α) (hmono : monotone f) (s : σ) :
monotone (fun (x : γ) => ReaderT.run (f x) s) :=
monotone_apply s _ hmono
instance [inst : PartialOrder (m α)] : PartialOrder (StateRefT' ω σ m α) := instOrderPi
instance [inst : CCPO (m α)] : CCPO (StateRefT' ω σ m α) := instCCPOPi
instance [Monad m] [ α, PartialOrder (m α)] [MonoBind m] : MonoBind (StateRefT' ω σ m) :=
inferInstanceAs (MonoBind (ReaderT _ _))
@[partial_fixpoint_monotone]
theorem monotone_stateRefT'Run [PartialOrder γ]
[Monad m] [MonadLiftT (ST ω) m] [ α, PartialOrder (m α)] [MonoBind m]
(f : γ StateRefT' ω σ m α) (hmono : monotone f) (s : σ) :
monotone (fun (x : γ) => StateRefT'.run (f x) s) := by
apply monotone_bind
· apply monotone_const
· refine monotone_of_monotone_apply _ fun ref => ?_
apply monotone_bind
· exact monotone_apply _ _ hmono
· apply monotone_const
instance [inst : α, PartialOrder (m α)] : PartialOrder (StateT σ m α) := instOrderPi
instance [inst : α, CCPO (m α)] : CCPO (StateT σ m α) := instCCPOPi
instance [Monad m] [ α, PartialOrder (m α)] [MonoBind m] : MonoBind (StateT ρ m) where
bind_mono_left h₁₂ := by
intro x
apply MonoBind.bind_mono_left (m := m)
exact h₁₂ x
bind_mono_right h₁₂ := by
intro x
apply MonoBind.bind_mono_right (m := m)
intro y
apply h₁₂
@[partial_fixpoint_monotone]
theorem monotone_stateTRun [PartialOrder γ]
[Monad m] [ α, PartialOrder (m α)]
(f : γ StateT σ m α) (hmono : monotone f) (s : σ) :
monotone (fun (x : γ) => StateT.run (f x) s) :=
monotone_apply s _ hmono
-- TODO: axiomatize these instances (ideally without `Nonempty ε`) when EIO is opaque
noncomputable instance [Nonempty ε] : CCPO (EIO ε α) :=
inferInstanceAs (CCPO ((s : _) FlatOrder (.error Classical.ofNonempty (Classical.choice s))))
noncomputable instance [Nonempty ε] : MonoBind (EIO ε) where
bind_mono_left {_ _ a₁ a₂ f} h₁₂ := by
intro s
specialize h₁₂ s
change FlatOrder.rel (a₁.bind f s) (a₂.bind f s)
simp only [EStateM.bind]
generalize a₁ s = a₁ at h₁₂; generalize a₂ s = a₂ at h₁₂
cases h₁₂
· exact .bot
· exact .refl
bind_mono_right {_ _ a f₁ f₂} h₁₂ := by
intro w
change FlatOrder.rel (a.bind f₁ w) (a.bind f₂ w)
simp only [EStateM.bind]
split
· apply h₁₂
· exact .refl
end mono_bind
section implication_order

View File

@@ -8,8 +8,8 @@ Additional goodies for writing macros
module
prelude
public import Init.Prelude -- for unfolding `Name.beq`
import all Init.Prelude -- for unfolding `Name.beq`
public import Init.Prelude
import all Init.Prelude -- for unfolding `Name.beq`
public import Init.MetaTypes
public import Init.Syntax
public import Init.Data.Array.GetLit
@@ -47,15 +47,21 @@ opaque version.getSpecialDesc (u : Unit) : String
def version.specialDesc : String := version.getSpecialDesc ()
def versionStringCore :=
toString version.major ++ "." ++ toString version.minor ++ "." ++ toString version.patch
String.Internal.append
(String.Internal.append
(String.Internal.append
(String.Internal.append (toString version.major) ".")
(toString version.minor))
".")
(toString version.patch)
def versionString :=
if version.specialDesc "" then
versionStringCore ++ "-" ++ version.specialDesc
String.Internal.append (String.Internal.append versionStringCore "-") version.specialDesc
else if version.isRelease then
versionStringCore
else
versionStringCore ++ ", commit " ++ githash
(String.Internal.append (String.Internal.append versionStringCore ", commit ") githash)
def origin :=
"leanprover/lean4"
@@ -63,11 +69,17 @@ def origin :=
def toolchain :=
if version.specialDesc "" then
if version.isRelease then
origin ++ ":" ++ versionStringCore ++ "-" ++ version.specialDesc
String.Internal.append
(String.Internal.append
(String.Internal.append
(String.Internal.append origin ":")
versionStringCore)
"-")
version.specialDesc
else
origin ++ ":" ++ version.specialDesc
String.Internal.append (String.Internal.append origin ":") version.specialDesc
else if version.isRelease then
origin ++ ":" ++ versionStringCore
String.Internal.append (String.Internal.append origin ":") versionStringCore
else
""
@@ -109,9 +121,22 @@ def isSubScriptAlnum (c : Char) : Bool :=
@[inline] def isIdFirst (c : Char) : Bool :=
c.isAlpha || c = '_' || isLetterLike c
@[inline] private def isAlphaAscii (c : UInt8) : Bool :=
'a'.toUInt8 c && c 'z'.toUInt8
|| 'A'.toUInt8 c && c 'Z'.toUInt8
@[inline] def isIdFirstAscii (c : UInt8) : Bool :=
isAlphaAscii c || c = '_'.toUInt8
@[inline] private def isAlphanumAscii (c : UInt8) : Bool :=
isAlphaAscii c || '0'.toUInt8 c && c '9'.toUInt8
@[inline] def isIdRest (c : Char) : Bool :=
c.isAlphanum || c = '_' || c = '\'' || c == '!' || c == '?' || isLetterLike c || isSubScriptAlnum c
@[inline] def isIdRestAscii (c : UInt8) : Bool :=
isAlphanumAscii c || c = '_'.toUInt8 || c = '\''.toUInt8 || c == '!'.toUInt8 || c == '?'.toUInt8
def idBeginEscape := '«'
def idEndEscape := '»'
@[inline] def isIdBeginEscape (c : Char) : Bool := c = idBeginEscape
@@ -127,7 +152,7 @@ def getRoot : Name → Name
@[export lean_is_inaccessible_user_name]
def isInaccessibleUserName : Name Bool
| Name.str _ s => s.contains '' || s == "_inaccessible"
| Name.str _ s => (String.Internal.contains s '') || s == "_inaccessible"
| Name.num p _ => isInaccessibleUserName p
| _ => false
@@ -137,24 +162,65 @@ def isInaccessibleUserName : Name → Bool
@[extern "lean_string_get_byte_fast"]
private opaque getUtf8Byte' (s : @& String) (n : Nat) (h : n < s.utf8ByteSize) : UInt8
section ToString
/-!
Here we give a private implementation of `Name.toString`. The real implementation is in
`Init.Data.ToString.Name`, which we cannot import here due to import hierarchy limitations.
The difference between the two versions is that this one uses the `String.Internal.*` functions,
while the one in `Init.Data.ToString.Name` uses the public String functions. These differ in
that the latter versions have better inferred borrowing annotations, which is significant for an
inner-loop function like `Name.toString`.
-/
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
private partial def needsNoEscapeAsciiRest (s : String) (i : Nat) : Bool :=
if h : i < s.utf8ByteSize then
let c := getUtf8Byte' s i h
isIdRestAscii c && needsNoEscapeAsciiRest s (i + 1)
else
true
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
@[inline] private def needsNoEscapeAscii (s : String) (h : s.utf8ByteSize > 0) : Bool :=
let c := getUtf8Byte' s 0 h
isIdFirstAscii c && needsNoEscapeAsciiRest s 1
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
@[inline] private def needsNoEscape (s : String) (h : s.utf8ByteSize > 0) : Bool :=
needsNoEscapeAscii s h || isIdFirst (String.Internal.get s 0) && Substring.Internal.all (Substring.Internal.drop s.toSubstring 1) isIdRest
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
@[inline] private def escape (s : String) : String :=
String.Internal.append (String.Internal.append idBeginEscape.toString s) idEndEscape.toString
/--
Creates a round-trippable string name component if possible, otherwise returns `none`.
Names that are valid identifiers are not escaped, and otherwise, if they do not contain `»`, they are escaped.
- If `force` is `true`, then even valid identifiers are escaped.
-/
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
@[inline]
def escapePart (s : String) (force : Bool := false) : Option String :=
if s.length > 0 && !force && isIdFirst (s.get 0) && (s.toSubstring.drop 1).all isIdRest then some s
else if s.any isIdEndEscape then none
else some <| idBeginEscape.toString ++ s ++ idEndEscape.toString
private def Internal.Meta.escapePart (s : String) (force : Bool := false) : Option String :=
if h : s.utf8ByteSize > 0 then
if !force && needsNoEscape s h then
some s
else if String.Internal.any s isIdEndEscape then
none
else
some <| escape s
else
some <| escape s
variable (sep : String) (escape : Bool) in
/--
Uses the separator `sep` (usually `"."`) to combine the components of the `Name` into a string.
See the documentation for `Name.toStringWithToken` for an explanation of `escape` and `isToken`.
-/
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
@[specialize isToken] -- explicit annotation because isToken is overridden in recursive call
def toStringWithSep (n : Name) (isToken : String Bool := fun _ => false) : String :=
private def Internal.Meta.toStringWithSep (n : Name) (isToken : String Bool := fun _ => false) : String :=
match n with
| anonymous => "[anonymous]"
| str anonymous s => maybeEscape s (isToken s)
@@ -162,9 +228,9 @@ def toStringWithSep (n : Name) (isToken : String → Bool := fun _ => false) : S
| str n s =>
-- Escape the last component if the identifier would otherwise be a token
let r := toStringWithSep n isToken
let r' := r ++ sep ++ maybeEscape s false
if escape && isToken r' then r ++ sep ++ maybeEscape s true else r'
| num n v => toStringWithSep n (isToken := fun _ => false) ++ sep ++ Nat.repr v
let r' := String.Internal.append (String.Internal.append r sep) (maybeEscape s false)
if escape && isToken r' then String.Internal.append (String.Internal.append r sep) (maybeEscape s true) else r'
| num n v => String.Internal.append (String.Internal.append (toStringWithSep n (isToken := fun _ => false)) sep) (Nat.repr v)
where
maybeEscape s force := if escape then escapePart s force |>.getD s else s
@@ -180,7 +246,8 @@ Converts a name to a string.
The insertion algorithm works so long as parser tokens do not themselves contain `«` or `»`.
-/
@[specialize]
def toStringWithToken (n : Name) (escape := true) (isToken : String Bool) : String :=
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
private def Internal.Meta.toStringWithToken (n : Name) (escape := true) (isToken : String Bool) : String :=
-- never escape "prettified" inaccessible names or macro scopes or pseudo-syntax introduced by the delaborator
toStringWithSep "." (escape && !n.isInaccessibleUserName && !n.hasMacroScopes && !maybePseudoSyntax) n isToken
where
@@ -190,7 +257,7 @@ where
true
else if let .str _ s := n.getRoot then
-- could be pseudo-syntax for loose bvar or universe mvar, output as is
"#".isPrefixOf s || "?".isPrefixOf s
String.Internal.isPrefixOf "#" s || String.Internal.isPrefixOf "?" s
else
false
@@ -202,11 +269,11 @@ Converts a name to a string.
Names with number components, anonymous names, and names containing `»` might not round trip.
Furthermore, "pseudo-syntax" produced by the delaborator, such as `_`, `#0` or `?u`, is not escaped.
-/
protected def toString (n : Name) (escape := true) : String :=
Name.toStringWithToken n escape (fun _ => false)
-- If you change this, also change the corresponding function in `Init.Data.ToString.Name`.
private def Internal.Meta.toString (n : Name) (escape := true) : String :=
toStringWithToken n escape (fun _ => false)
instance : ToString Name where
toString n := n.toString
end ToString
private def hasNum : Name Bool
| anonymous => false
@@ -221,13 +288,13 @@ protected def reprPrec (n : Name) (prec : Nat) : Std.Format :=
if p.hasNum then
Repr.addAppParen ("Lean.Name.mkStr " ++ Name.reprPrec p max_prec ++ " " ++ repr s) prec
else
Std.Format.text "`" ++ n.toString
Std.Format.text "`" ++ Internal.Meta.toString n
instance : Repr Name where
reprPrec := Name.reprPrec
def capitalize : Name Name
| .str p s => .str p s.capitalize
| .str p s => .str p (String.Internal.capitalize s)
| n => n
def replacePrefix : Name Name Name Name
@@ -256,20 +323,20 @@ def eraseSuffix? : Name → Name → Option Name
@[export lean_name_append_after]
def appendAfter (n : Name) (suffix : String) : Name :=
n.modifyBase fun
| str p s => Name.mkStr p (s ++ suffix)
| str p s => Name.mkStr p (String.Internal.append s suffix)
| n => Name.mkStr n suffix
@[export lean_name_append_index_after]
def appendIndexAfter (n : Name) (idx : Nat) : Name :=
n.modifyBase fun
| str p s => Name.mkStr p (s ++ "_" ++ toString idx)
| n => Name.mkStr n ("_" ++ toString idx)
| str p s => Name.mkStr p (String.Internal.append (String.Internal.append s "_") (toString idx))
| n => Name.mkStr n (String.Internal.append "_" (toString idx))
@[export lean_name_append_before]
def appendBefore (n : Name) (pre : String) : Name :=
n.modifyBase fun
| anonymous => Name.mkStr anonymous pre
| str p s => Name.mkStr p (pre ++ s)
| str p s => Name.mkStr p (String.Internal.append pre s)
| num p n => Name.mkNum (Name.mkStr p pre) n
protected theorem beq_iff_eq {m n : Name} : m == n m = n := by
@@ -446,7 +513,7 @@ partial def structEq : Syntax → Syntax → Bool
| Syntax.missing, Syntax.missing => true
| Syntax.node _ k args, Syntax.node _ k' args' => k == k' && args.isEqv args' structEq
| Syntax.atom _ val, Syntax.atom _ val' => val == val'
| Syntax.ident _ rawVal val preresolved, Syntax.ident _ rawVal' val' preresolved' => rawVal == rawVal' && val == val' && preresolved == preresolved'
| Syntax.ident _ rawVal val preresolved, Syntax.ident _ rawVal' val' preresolved' => Substring.Internal.beq rawVal rawVal' && val == val' && preresolved == preresolved'
| _, _ => false
instance : BEq Lean.Syntax := structEq
@@ -641,7 +708,7 @@ partial def expandMacros (stx : Syntax) (p : SyntaxNodeKind → Bool := fun k =>
Create an identifier copying the position from `src`.
To refer to a specific constant, use `mkCIdentFrom` instead. -/
def mkIdentFrom (src : Syntax) (val : Name) (canonical := false) : Ident :=
Syntax.ident (SourceInfo.fromRef src canonical) (toString val).toSubstring val []
Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString val).toSubstring val []
def mkIdentFromRef [Monad m] [MonadRef m] (val : Name) (canonical := false) : m Ident := do
return mkIdentFrom ( getRef) val canonical
@@ -653,7 +720,7 @@ def mkIdentFromRef [Monad m] [MonadRef m] (val : Name) (canonical := false) : m
def mkCIdentFrom (src : Syntax) (c : Name) (canonical := false) : Ident :=
-- Remark: We use the reserved macro scope to make sure there are no accidental collision with our frontend
let id := addMacroScope `_internal c reservedMacroScope
Syntax.ident (SourceInfo.fromRef src canonical) (toString id).toSubstring id [.decl c []]
Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString id).toSubstring id [.decl c []]
def mkCIdentFromRef [Monad m] [MonadRef m] (c : Name) (canonical := false) : m Syntax := do
return mkCIdentFrom ( getRef) c canonical
@@ -663,7 +730,7 @@ def mkCIdent (c : Name) : Ident :=
@[export lean_mk_syntax_ident]
def mkIdent (val : Name) : Ident :=
Syntax.ident SourceInfo.none (toString val).toSubstring val []
Syntax.ident SourceInfo.none (Name.Internal.Meta.toString val).toSubstring val []
@[inline] def mkGroupNode (args : Array Syntax := #[]) : Syntax :=
mkNode groupKind args
@@ -693,11 +760,11 @@ def mkSep (a : Array Syntax) (sep : Syntax) : Syntax :=
mkNullNode <| mkSepArray a sep
def SepArray.ofElems {sep} (elems : Array Syntax) : SepArray sep :=
mkSepArray elems (if sep.isEmpty then mkNullNode else mkAtom sep)
mkSepArray elems (if String.Internal.isEmpty sep then mkNullNode else mkAtom sep)
def SepArray.ofElemsUsingRef [Monad m] [MonadRef m] {sep} (elems : Array Syntax) : m (SepArray sep) := do
let ref getRef;
return mkSepArray elems (if sep.isEmpty then mkNullNode else mkAtomFrom ref sep)
return mkSepArray elems (if String.Internal.isEmpty sep then mkNullNode else mkAtomFrom ref sep)
instance : Coe (Array Syntax) (SepArray sep) where
coe := SepArray.ofElems
@@ -752,55 +819,55 @@ def mkNameLit (val : String) (info := SourceInfo.none) : NameLit :=
for Syntax objects representing these numerals. -/
private partial def decodeBinLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
if s.atEnd i then some val
if String.Internal.atEnd s i then some val
else
let c := s.get i
if c == '0' then decodeBinLitAux s (s.next i) (2*val)
else if c == '1' then decodeBinLitAux s (s.next i) (2*val + 1)
else if c == '_' then decodeBinLitAux s (s.next i) val
let c := String.Internal.get s i
if c == '0' then decodeBinLitAux s (String.Internal.next s i) (2*val)
else if c == '1' then decodeBinLitAux s (String.Internal.next s i) (2*val + 1)
else if c == '_' then decodeBinLitAux s (String.Internal.next s i) val
else none
private partial def decodeOctalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
if s.atEnd i then some val
if String.Internal.atEnd s i then some val
else
let c := s.get i
if '0' c && c '7' then decodeOctalLitAux s (s.next i) (8*val + c.toNat - '0'.toNat)
else if c == '_' then decodeOctalLitAux s (s.next i) val
let c := String.Internal.get s i
if '0' c && c '7' then decodeOctalLitAux s (String.Internal.next s i) (8*val + c.toNat - '0'.toNat)
else if c == '_' then decodeOctalLitAux s (String.Internal.next s i) val
else none
private def decodeHexDigit (s : String) (i : String.Pos) : Option (Nat × String.Pos) :=
let c := s.get i
let i := s.next i
let c := String.Internal.get s i
let i := String.Internal.next s i
if '0' c && c '9' then some (c.toNat - '0'.toNat, i)
else if 'a' c && c 'f' then some (10 + c.toNat - 'a'.toNat, i)
else if 'A' c && c 'F' then some (10 + c.toNat - 'A'.toNat, i)
else none
private partial def decodeHexLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
if s.atEnd i then some val
if String.Internal.atEnd s i then some val
else match decodeHexDigit s i with
| some (d, i) => decodeHexLitAux s i (16*val + d)
| none =>
if s.get i == '_' then decodeHexLitAux s (s.next i) val
if String.Internal.get s i == '_' then decodeHexLitAux s (String.Internal.next s i) val
else none
private partial def decodeDecimalLitAux (s : String) (i : String.Pos) (val : Nat) : Option Nat :=
if s.atEnd i then some val
if String.Internal.atEnd s i then some val
else
let c := s.get i
if '0' c && c '9' then decodeDecimalLitAux s (s.next i) (10*val + c.toNat - '0'.toNat)
else if c == '_' then decodeDecimalLitAux s (s.next i) val
let c := String.Internal.get s i
if '0' c && c '9' then decodeDecimalLitAux s (String.Internal.next s i) (10*val + c.toNat - '0'.toNat)
else if c == '_' then decodeDecimalLitAux s (String.Internal.next s i) val
else none
def decodeNatLitVal? (s : String) : Option Nat :=
let len := s.length
let len := String.Internal.length s
if len == 0 then none
else
let c := s.get 0
let c := String.Internal.get s 0
if c == '0' then
if len == 1 then some 0
else
let c := s.get 1
let c := String.Internal.get s 1
if c == 'x' || c == 'X' then decodeHexLitAux s 2 0
else if c == 'b' || c == 'B' then decodeBinLitAux s 2 0
else if c == 'o' || c == 'O' then decodeOctalLitAux s 2 0
@@ -836,16 +903,16 @@ def isFieldIdx? (s : Syntax) : Option Nat :=
`n * 10^-e` if `sign` else `n * 10^e`.
-/
partial def decodeScientificLitVal? (s : String) : Option (Nat × Bool × Nat) :=
let len := s.length
let len := String.Internal.length s
if len == 0 then none
else
let c := s.get 0
let c := String.Internal.get s 0
if c.isDigit then
decode 0 0
else none
where
decodeAfterExp (i : String.Pos) (val : Nat) (e : Nat) (sign : Bool) (exp : Nat) : Option (Nat × Bool × Nat) :=
if s.atEnd i then
if String.Internal.atEnd s i then
if sign then
some (val, sign, exp + e)
else if exp >= e then
@@ -853,51 +920,51 @@ where
else
some (val, true, e - exp)
else
let c := s.get i
let c := String.Internal.get s i
if '0' c && c '9' then
decodeAfterExp (s.next i) val e sign (10*exp + c.toNat - '0'.toNat)
decodeAfterExp (String.Internal.next s i) val e sign (10*exp + c.toNat - '0'.toNat)
else if c == '_' then
decodeAfterExp (s.next i) val e sign exp
decodeAfterExp (String.Internal.next s i) val e sign exp
else
none
decodeExp (i : String.Pos) (val : Nat) (e : Nat) : Option (Nat × Bool × Nat) :=
if s.atEnd i then none else
let c := s.get i
if String.Internal.atEnd s i then none else
let c := String.Internal.get s i
if c == '-' then
decodeAfterExp (s.next i) val e true 0
decodeAfterExp (String.Internal.next s i) val e true 0
else if c == '+' then
decodeAfterExp (s.next i) val e false 0
decodeAfterExp (String.Internal.next s i) val e false 0
else
decodeAfterExp i val e false 0
decodeAfterDot (i : String.Pos) (val : Nat) (e : Nat) : Option (Nat × Bool × Nat) :=
if s.atEnd i then
if String.Internal.atEnd s i then
some (val, true, e)
else
let c := s.get i
let c := String.Internal.get s i
if '0' c && c '9' then
decodeAfterDot (s.next i) (10*val + c.toNat - '0'.toNat) (e+1)
decodeAfterDot (String.Internal.next s i) (10*val + c.toNat - '0'.toNat) (e+1)
else if c == '_' then
decodeAfterDot (s.next i) val e
decodeAfterDot (String.Internal.next s i) val e
else if c == 'e' || c == 'E' then
decodeExp (s.next i) val e
decodeExp (String.Internal.next s i) val e
else
none
decode (i : String.Pos) (val : Nat) : Option (Nat × Bool × Nat) :=
if s.atEnd i then
if String.Internal.atEnd s i then
none
else
let c := s.get i
let c := String.Internal.get s i
if '0' c && c '9' then
decode (s.next i) (10*val + c.toNat - '0'.toNat)
decode (String.Internal.next s i) (10*val + c.toNat - '0'.toNat)
else if c == '_' then
decode (s.next i) val
decode (String.Internal.next s i) val
else if c == '.' then
decodeAfterDot (s.next i) val 0
decodeAfterDot (String.Internal.next s i) val 0
else if c == 'e' || c == 'E' then
decodeExp (s.next i) val 0
decodeExp (String.Internal.next s i) val 0
else
none
@@ -908,7 +975,7 @@ def isScientificLit? (stx : Syntax) : Option (Nat × Bool × Nat) :=
def isIdOrAtom? : Syntax Option String
| Syntax.atom _ val => some val
| Syntax.ident _ rawVal _ _ => some rawVal.toString
| Syntax.ident _ rawVal _ _ => some (Substring.Internal.toString rawVal)
| _ => none
def toNat (stx : Syntax) : Nat :=
@@ -917,8 +984,8 @@ def toNat (stx : Syntax) : Nat :=
| none => 0
def decodeQuotedChar (s : String) (i : String.Pos) : Option (Char × String.Pos) := do
let c := s.get i
let i := s.next i
let c := String.Internal.get s i
let i := String.Internal.next s i
if c == '\\' then pure ('\\', i)
else if c = '\"' then pure ('\"', i)
else if c = '\'' then pure ('\'', i)
@@ -945,25 +1012,25 @@ the more restrictive `"\" newline whitespace*` since this simplifies the impleme
Justification: this does not overlap with any other sequences beginning with `\`.
-/
def decodeStringGap (s : String) (i : String.Pos) : Option String.Pos := do
guard <| (s.get i).isWhitespace
some <| s.nextWhile Char.isWhitespace (s.next i)
guard <| (String.Internal.get s i).isWhitespace
some <| String.Internal.nextWhile s Char.isWhitespace (String.Internal.next s i)
partial def decodeStrLitAux (s : String) (i : String.Pos) (acc : String) : Option String := do
let c := s.get i
let i := s.next i
let c := String.Internal.get s i
let i := String.Internal.next s i
if c == '\"' then
pure acc
else if s.atEnd i then
else if String.Internal.atEnd s i then
none
else if c == '\\' then do
if let some (c, i) := decodeQuotedChar s i then
decodeStrLitAux s i (acc.push c)
decodeStrLitAux s i (String.push acc c)
else if let some i := decodeStringGap s i then
decodeStrLitAux s i acc
else
none
else
decodeStrLitAux s i (acc.push c)
decodeStrLitAux s i (String.push acc c)
/--
Takes a raw string literal, counts the number of `#`'s after the `r`, and interprets it as a string.
@@ -972,12 +1039,12 @@ The algorithm is simple: we are given `r##...#"...string..."##...#` with zero or
By counting the number of leading `#`'s, we can extract the `...string...`.
-/
partial def decodeRawStrLitAux (s : String) (i : String.Pos) (num : Nat) : String :=
let c := s.get i
let i := s.next i
let c := String.Internal.get s i
let i := String.Internal.next s i
if c == '#' then
decodeRawStrLitAux s i (num + 1)
else
s.extract i ⟨s.utf8ByteSize - (num + 1)⟩
String.Internal.extract s i ⟨s.utf8ByteSize - (num + 1)⟩
/--
Takes the string literal lexical syntax parsed by the parser and interprets it as a string.
@@ -988,7 +1055,7 @@ If it returns `none` then the string literal is ill-formed, which indicates a bu
The function is not required to return `none` if the string literal is ill-formed.
-/
def decodeStrLit (s : String) : Option String :=
if s.get 0 == 'r' then
if String.Internal.get s 0 == 'r' then
some <| decodeRawStrLitAux s ⟨1⟩ 0
else
decodeStrLitAux s ⟨1⟩ ""
@@ -1005,7 +1072,7 @@ def isStrLit? (stx : Syntax) : Option String :=
| _ => none
def decodeCharLit (s : String) : Option Char := do
let c := s.get ⟨1⟩
let c := String.Internal.get s ⟨1⟩
if c == '\\' then do
let (c, _) ← decodeQuotedChar s ⟨2⟩
pure c
@@ -1019,26 +1086,26 @@ def isCharLit? (stx : Syntax) : Option Char :=
private partial def splitNameLitAux (ss : Substring) (acc : List Substring) : List Substring :=
let splitRest (ss : Substring) (acc : List Substring) : List Substring :=
if ss.front == '.' then
splitNameLitAux (ss.drop 1) acc
else if ss.isEmpty then
if Substring.Internal.front ss == '.' then
splitNameLitAux (Substring.Internal.drop ss 1) acc
else if Substring.Internal.isEmpty ss then
acc
else
[]
if ss.isEmpty then []
if Substring.Internal.isEmpty ss then []
else
let curr := ss.front
let curr := Substring.Internal.front ss
if isIdBeginEscape curr then
let escapedPart := ss.takeWhile (!isIdEndEscape ·)
let escapedPart := { escapedPart with stopPos := ss.stopPos.min (escapedPart.str.next escapedPart.stopPos) }
if !isIdEndEscape (escapedPart.get <| escapedPart.prev ⟨escapedPart.bsize⟩) then []
else splitRest (ss.extract ⟨escapedPart.bsize⟩ ⟨ss.bsize⟩) (escapedPart :: acc)
let escapedPart := Substring.Internal.takeWhile ss (!isIdEndEscape ·)
let escapedPart := { escapedPart with stopPos := String.Pos.Internal.min ss.stopPos (String.Internal.next escapedPart.str escapedPart.stopPos) }
if !isIdEndEscape (Substring.Internal.get escapedPart <| Substring.Internal.prev escapedPart ⟨escapedPart.bsize⟩) then []
else splitRest (Substring.Internal.extract ss ⟨escapedPart.bsize⟩ ⟨ss.bsize⟩) (escapedPart :: acc)
else if isIdFirst curr then
let idPart := ss.takeWhile isIdRest
splitRest (ss.extract ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
let idPart := Substring.Internal.takeWhile ss isIdRest
splitRest (Substring.Internal.extract ss ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
else if curr.isDigit then
let idPart := ss.takeWhile Char.isDigit
splitRest (ss.extract ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
let idPart := Substring.Internal.takeWhile ss Char.isDigit
splitRest (Substring.Internal.extract ss ⟨idPart.bsize⟩ ⟨ss.bsize⟩) (idPart :: acc)
else
[]
@@ -1059,10 +1126,10 @@ def _root_.Substring.toName (s : Substring) : Name :=
| [] => .anonymous
| comps => comps.foldr (init := Name.anonymous)
fun comp n =>
let comp := comp.toString
if isIdBeginEscape comp.front then
Name.mkStr n (comp.drop 1 |>.dropRight 1)
else if comp.front.isDigit then
let comp := Substring.Internal.toString comp
if isIdBeginEscape (String.Internal.front comp) then
Name.mkStr n (String.Internal.dropRight (String.Internal.drop comp 1) 1)
else if (String.Internal.front comp).isDigit then
if let some k := decodeNatLitVal? comp then
Name.mkNum n k
else
@@ -1080,8 +1147,8 @@ def _root_.String.toName (s : String) : Name :=
s.toSubstring.toName
def decodeNameLit (s : String) : Option Name :=
if s.get 0 == '`' then
match (s.toSubstring.drop 1).toName with
if String.Internal.get s 0 == '`' then
match (Substring.Internal.drop s.toSubstring 1).toName with
| .anonymous => none
| name => some name
else
@@ -1101,7 +1168,7 @@ def isAtom : Syntax → Bool
| _ => false
def isToken (token : String) : Syntax → Bool
| atom _ val => val.trim == token.trim
| atom _ val => String.Internal.trim val == String.Internal.trim token
| _ => false
def isNone (stx : Syntax) : Bool :=
@@ -1199,7 +1266,7 @@ end TSyntax
def HygieneInfo.mkIdent (s : HygieneInfo) (val : Name) (canonical := false) : Ident :=
let src := s.raw[0]
let id := { extractMacroScopes src.getId with name := val.eraseMacroScopes }.review
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString val).toSubstring id []⟩
⟨Syntax.ident (SourceInfo.fromRef src canonical) (Name.Internal.Meta.toString val).toSubstring id []⟩
/-- Reflect a runtime datum back to surface syntax (best-effort). -/
class Quote (α : Type) (k : SyntaxNodeKind := `term) where
@@ -1215,13 +1282,13 @@ instance : Quote Bool := ⟨fun | true => mkCIdent ``Bool.true | false => mkCIde
instance : Quote Char charLitKind := ⟨Syntax.mkCharLit⟩
instance : Quote String strLitKind := ⟨Syntax.mkStrLit⟩
instance : Quote Nat numLitKind := ⟨fun n => Syntax.mkNumLit <| toString n⟩
instance : Quote Substring := ⟨fun s => Syntax.mkCApp ``String.toSubstring' #[quote s.toString]⟩
instance : Quote Substring := ⟨fun s => Syntax.mkCApp ``String.toSubstring' #[quote (Substring.Internal.toString s)]⟩
-- in contrast to `Name.toString`, we can, and want to be, precise here
private def getEscapedNameParts? (acc : List String) : Name → Option (List String)
| Name.anonymous => if acc.isEmpty then none else some acc
| Name.str n s => do
let s ← Name.escapePart s
let s ← Name.Internal.Meta.escapePart s false
getEscapedNameParts? (s::acc) n
| Name.num _ _ => none
@@ -1233,7 +1300,7 @@ def quoteNameMk : Name → Term
instance : Quote Name `term where
quote n := private
match getEscapedNameParts? [] n with
| some ss => ⟨mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ ".".intercalate ss)]⟩
| some ss => ⟨mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit (String.Internal.append "`" (String.Internal.intercalate "." ss))]⟩
| none => ⟨quoteNameMk n⟩
instance [Quote α `term] [Quote β `term] : Quote (α × β) `term where
@@ -1257,7 +1324,7 @@ where
if h : i < xs.size then
go (i+1) (args.push (quote xs[i]))
else
Syntax.mkCApp (Name.mkStr2 "Array" ("mkArray" ++ toString xs.size)) args
Syntax.mkCApp (Name.mkStr2 "Array" (String.Internal.append "mkArray" (toString xs.size))) args
termination_by xs.size - i
decreasing_by decreasing_trivial_pre_omega
@@ -1415,28 +1482,28 @@ private def decodeInterpStrQuotedChar (s : String) (i : String.Pos) : Option (Ch
match decodeQuotedChar s i with
| some r => some r
| none =>
let c := s.get i
let i := s.next i
let c := String.Internal.get s i
let i := String.Internal.next s i
if c == '{' then pure ('{', i)
else none
private partial def decodeInterpStrLit (s : String) : Option String :=
let rec loop (i : String.Pos) (acc : String) : Option String :=
let c := s.get i
let i := s.next i
let c := String.Internal.get s i
let i := String.Internal.next s i
if c == '\"' || c == '{' then
pure acc
else if s.atEnd i then
else if String.Internal.atEnd s i then
none
else if c == '\\' then do
if let some (c, i) := decodeInterpStrQuotedChar s i then
loop i (acc.push c)
loop i (String.push acc c)
else if let some i := decodeStringGap s i then
loop i acc
else
none
else
loop i (acc.push c)
loop i (String.push acc c)
loop ⟨1⟩ ""
partial def isInterpolatedStrLit? (stx : Syntax) : Option String :=
@@ -1451,28 +1518,38 @@ end Syntax
namespace TSyntax
def expandInterpolatedStrChunks (chunks : Array Syntax) (mkAppend : Syntax → Syntax → MacroM Syntax) (mkElem : Syntax → MacroM Syntax) : MacroM Syntax := do
let mut i := 0
def expandInterpolatedStrChunks (chunks : Array Syntax) (mkAppend : Syntax → Syntax → MacroM Syntax)
(mkElem : Syntax → MacroM Syntax) (mkLit : String → MacroM Syntax) : MacroM Syntax := do
let mut result := Syntax.missing
for elem in chunks do
let elem ← withRef elem <| match elem.isInterpolatedStrLit? with
| none => mkElem elem
| some str => mkElem (Syntax.mkStrLit str)
if i == 0 then
let elem ← match elem.isInterpolatedStrLit? with
| none => withRef elem <| mkElem elem
| some str =>
if String.Internal.isEmpty str then continue
else withRef elem <| mkLit str
if result.isMissing then
result := elem
else
result ← mkAppend result elem
i := i+1
return result
if result.isMissing then
mkLit ""
else
return result
open TSyntax.Compat in
def expandInterpolatedStr (interpStr : TSyntax interpolatedStrKind) (type : Term) (toTypeFn : Term) : MacroM Term := do
let r ← expandInterpolatedStrChunks interpStr.raw.getArgs (fun a b => `($a ++ $b)) (fun a => `($toTypeFn $a))
/-- Expand `interpStr` into a term of type `type` (which supports ` ++ `),
calling `ofInterpFn` on terms within `{}`,
and `ofLitFn` on the literals between the interpolations. -/
def expandInterpolatedStr (interpStr : TSyntax interpolatedStrKind) (type : Term) (ofInterpFn : Term) (ofLitFn : Term := ofInterpFn) : MacroM Term := do
let r ← expandInterpolatedStrChunks interpStr.raw.getArgs
(fun a b => `($a ++ $b))
(fun a => `($ofInterpFn $a))
(fun s => `($ofLitFn $(Syntax.mkStrLit s)))
`(($r : $type))
def getDocString (stx : TSyntax `Lean.Parser.Command.docComment) : String :=
match stx.raw[1] with
| Syntax.atom _ val => val.extract 0 (val.endPos - ⟨2⟩)
| Syntax.atom _ val => String.Internal.extract val 0 (String.Pos.Internal.sub val.endPos ⟨2⟩)
| _ => ""
end TSyntax
@@ -1646,8 +1723,8 @@ macro (name := declareSimpLikeTactic) doc?:(docComment)?
return s)
/-- `simp!` is shorthand for `simp` with `autoUnfold := true`.
This will rewrite with all equation lemmas, which can be used to
partially evaluate many definitions. -/
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
This can be used to partially evaluate many definitions. -/
declare_simp_like_tactic simpAutoUnfold "simp! " (autoUnfold := true)
/--
@@ -1663,8 +1740,8 @@ Note that `+decide` is not needed for reducing arithmetic terms since simprocs h
syntax (name := simpArithBang) "simp_arith! " optConfig (discharger)? (&" only")? (" [" (simpStar <|> simpErase <|> simpLemma),* "]")? (location)? : tactic
/-- `simp_all!` is shorthand for `simp_all` with `autoUnfold := true`.
This will rewrite with all equation lemmas, which can be used to
partially evaluate many definitions. -/
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
This can be used to partially evaluate many definitions. -/
declare_simp_like_tactic (all := true) simpAllAutoUnfold "simp_all! " (autoUnfold := true)
/--
@@ -1681,8 +1758,8 @@ syntax (name := simpAllArithBang) "simp_all_arith!" optConfig (discharger)? (&"
/-- `dsimp!` is shorthand for `dsimp` with `autoUnfold := true`.
This will rewrite with all equation lemmas, which can be used to
partially evaluate many definitions. -/
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
This can be used to partially evaluate many definitions. -/
declare_simp_like_tactic (dsimp := true) dsimpAutoUnfold "dsimp! " (autoUnfold := true)
end Tactic

View File

@@ -94,7 +94,7 @@ structure Config where
-/
decide : Bool := false
/--
When `true` (default: `false`), unfolds definitions.
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
This can be enabled using the `simp!` syntax.
-/
autoUnfold : Bool := false
@@ -208,7 +208,7 @@ structure Config where
/-- When `true` (default: `false`), simplifies simple arithmetic expressions. -/
arith : Bool := false
/--
When `true` (default: `false`), unfolds definitions.
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
This can be enabled using the `simp!` syntax.
-/
autoUnfold : Bool := false

View File

@@ -44,8 +44,11 @@ deriving BEq, DecidableEq, Repr
namespace Constraint
private local instance : Append String where
append := String.Internal.append
instance : ToString Constraint where
toString := fun
toString := private fun
| none, none => "(-∞, ∞)"
| none, some y => s!"(-∞, {y}]"
| some x, none => s!"[{x}, ∞)"

View File

@@ -33,9 +33,15 @@ deriving DecidableEq, Repr
namespace LinearCombo
private def join (l : List String) : String :=
l.foldl (init := "") (fun sofar next => String.Internal.append sofar next)
private local instance : Append String where
append := String.Internal.append
instance : ToString LinearCombo where
toString lc :=
s!"{lc.const}{String.join <| lc.coeffs.toList.zipIdx.map fun ⟨c, i⟩ => s!" + {c} * x{i+1}"}"
toString lc := private
s!"{lc.const}{join <| lc.coeffs.toList.zipIdx.map fun ⟨c, i⟩ => s!" + {c} * x{i+1}"}"
instance : Inhabited LinearCombo := {const := 1}

View File

@@ -141,6 +141,9 @@ unsafe axiom lcErased : Type
/-- Marker for type dependency that has been erased by the code generator. -/
unsafe axiom lcAny : Type
/-- Internal representation of `IO.RealWorld` in the compiler. -/
unsafe axiom lcRealWorld : Type
/--
Auxiliary unsafe constant used by the Compiler when erasing proofs from code.
@@ -1778,6 +1781,20 @@ theorem Nat.ne_of_beq_eq_false : {n m : Nat} → Eq (beq n m) false → Not (Eq
have : Eq (beq n m) false := h₁
Nat.noConfusion h₂ (fun h₂ => absurd h₂ (ne_of_beq_eq_false this))
private theorem noConfusion_of_Nat.aux : (a : Nat) (Nat.beq a a).rec False True
| Nat.zero => True.intro
| Nat.succ n => noConfusion_of_Nat.aux n
/--
A helper theorem to deduce `False` from `a = b` when `f a ≠ f b` for some function `f : α → Nat`
(typically `.ctorIdx`). Used as a simpler alternative to the no-confusion theorems.
-/
theorem noConfusion_of_Nat {α : Sort u} (f : α Nat) {a b : α} (h : Eq a b) :
(Nat.beq (f a) (f b)).rec False True :=
congrArg f h noConfusion_of_Nat.aux (f a)
/--
A decision procedure for equality of natural numbers, usually accessed via the `DecidableEq Nat`
instance.
@@ -1865,6 +1882,9 @@ protected theorem Nat.le_trans {n m k : Nat} : LE.le n m → LE.le m k → LE.le
| h, Nat.le.refl => h
| h₁, Nat.le.step h₂ => Nat.le.step (Nat.le_trans h₁ h₂)
protected theorem Nat.lt_of_lt_of_le {n m k : Nat} : LT.lt n m LE.le m k LT.lt n k :=
Nat.le_trans
protected theorem Nat.lt_trans {n m k : Nat} (h₁ : LT.lt n m) : LT.lt m k LT.lt n k :=
Nat.le_trans (le_step h₁)
@@ -1968,6 +1988,27 @@ theorem Nat.ble_eq_true_of_le (h : LE.le n m) : Eq (Nat.ble n m) true :=
theorem Nat.not_le_of_not_ble_eq_true (h : Not (Eq (Nat.ble n m) true)) : Not (LE.le n m) :=
fun h' => absurd (Nat.ble_eq_true_of_le h') h
theorem Nat.lt_succ_of_le {n m : Nat} : LE.le n m LT.lt n (succ m) := succ_le_succ
protected theorem Nat.lt_add_one (n : Nat) : LT.lt n (HAdd.hAdd n 1) := Nat.le_refl (succ n)
theorem Nat.lt_succ_self (n : Nat) : LT.lt n (succ n) := Nat.lt_add_one _
protected theorem Nat.lt_of_not_le {a b : Nat} (h : Not (LE.le a b)) : LT.lt b a :=
(Nat.lt_or_ge b a).resolve_right h
protected theorem Nat.add_pos_right :
{b : Nat} (a : Nat) (hb : LT.lt 0 b) LT.lt 0 (HAdd.hAdd a b)
| succ _, _, _ => Nat.zero_lt_succ _
protected theorem Nat.mul_pos :
{n m : Nat} (hn : LT.lt 0 n) (hm : LT.lt 0 m) LT.lt 0 (HMul.hMul n m)
| _, succ _, ha, _ => Nat.add_pos_right _ ha
protected theorem Nat.pow_pos {a : Nat} : {n : Nat} (h : LT.lt 0 a) LT.lt 0 (HPow.hPow a n)
| zero, _ => Nat.zero_lt_succ _
| succ _, h => Nat.mul_pos (Nat.pow_pos h) h
/--
A decision procedure for non-strict inequality of natural numbers, usually accessed via the
`DecidableLE Nat` instance.
@@ -2021,6 +2062,160 @@ protected def Nat.sub : (@& Nat) → (@& Nat) → Nat
instance instSubNat : Sub Nat where
sub := Nat.sub
theorem Nat.succ_sub_succ_eq_sub (n m : Nat) : Eq (HSub.hSub (succ n) (succ m)) (HSub.hSub n m) :=
m.rec rfl (fun _ ih => congrArg pred ih)
theorem Nat.pred_le : (n : Nat), LE.le (Nat.pred n) n
| zero => Nat.le.refl
| succ _ => le_succ _
theorem Nat.sub_le (n m : Nat) : LE.le (HSub.hSub n m) n :=
m.rec (Nat.le_refl _) (fun _ ih => Nat.le_trans (pred_le _) ih)
theorem Nat.sub_lt : {n m : Nat}, LT.lt 0 n LT.lt 0 m LT.lt (HSub.hSub n m) n
| 0, _, h1, _ => absurd h1 (Nat.lt_irrefl 0)
| Nat.succ _, 0, _, h2 => absurd h2 (Nat.lt_irrefl 0)
| Nat.succ n, Nat.succ m, _, _ =>
Eq.symm (succ_sub_succ_eq_sub n m)
show LT.lt (HSub.hSub n m) (succ n) from
lt_succ_of_le (sub_le n m)
theorem Nat.div_rec_lemma {x y : Nat} :
(And (LT.lt 0 y) (LE.le y x)) LT.lt (HSub.hSub x y) x :=
fun ypos, ylex => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
theorem Nat.div_rec_fuel_lemma {x y fuel : Nat} (hy : LT.lt 0 y) (hle : LE.le y x)
(hfuel : LT.lt x (HAdd.hAdd fuel 1)) : LT.lt (HSub.hSub x y) fuel :=
Nat.lt_of_lt_of_le (div_rec_lemma hy, hle) (Nat.le_of_lt_succ hfuel)
set_option bootstrap.genMatcherCode false in
/--
Division of natural numbers, discarding the remainder. Division by `0` returns `0`. Usually accessed
via the `/` operator.
This operation is sometimes called “floor division.”
This function is overridden at runtime with an efficient implementation. This definition is
the logical model.
Examples:
* `21 / 3 = 7`
* `21 / 5 = 4`
* `0 / 22 = 0`
* `5 / 0 = 0`
-/
@[extern "lean_nat_div", irreducible]
protected def Nat.div (x y : @& Nat) : Nat :=
dite (LT.lt 0 y) (fun hy =>
let rec
go (fuel : Nat) (x : Nat) (hfuel : LT.lt x fuel) : Nat :=
match fuel with
| succ fuel =>
dite (LE.le y x)
(fun h => HAdd.hAdd (go fuel (HSub.hSub x y) (div_rec_fuel_lemma hy h hfuel)) 1)
(fun _ => 0)
termination_by structural fuel
go (succ x) x (Nat.lt_succ_self _))
(fun _ => 0)
instance Nat.instDiv : Div Nat := Nat.div
set_option bootstrap.genMatcherCode false in
/--
The modulo operator, which computes the remainder when dividing one natural number by another.
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
than an error.
This is the core implementation of `Nat.mod`. It computes the correct result for any two closed
natural numbers, but it does not have some convenient [definitional
reductions](lean-manual://section/type-system) when the `Nat`s contain free variables. The wrapper
`Nat.mod` handles those cases specially and then calls `Nat.modCore`.
This function is overridden at runtime with an efficient implementation. This definition is the
logical model.
-/
@[extern "lean_nat_mod"]
protected noncomputable def Nat.modCore (x y : Nat) : Nat :=
dite (LT.lt 0 y)
(fun hy =>
let rec
go (fuel : Nat) (x : Nat) (hfuel : LT.lt x fuel) : Nat :=
match fuel with
| succ fuel =>
dite (LE.le y x)
(fun h => go fuel (HSub.hSub x y) (div_rec_fuel_lemma hy h hfuel))
(fun _ => x)
termination_by structural fuel
go (succ x) x (Nat.lt_succ_self _))
(fun _ => x)
theorem Nat.modCoreGo_lt {fuel y : Nat} (hy : LT.lt 0 y) : (x : Nat) (hfuel : LT.lt x fuel)
LT.lt (Nat.modCore.go y hy fuel x hfuel) y :=
fuel.rec (fun _ h => absurd h (Nat.not_lt_zero _))
(fun _ ih x _ =>
show LT.lt (dite _ _ _) _ from
match Nat.decLe y x with
| .isTrue _ => ih _ _
| .isFalse h => Nat.lt_of_not_le h)
theorem Nat.modCore_lt {x y : Nat} (hy : LT.lt 0 y) : LT.lt (Nat.modCore x y) y :=
show LT.lt (dite _ _ _) y from
match Nat.decLt 0 y with
| .isTrue _ => Nat.modCoreGo_lt hy x (Nat.lt_succ_self _)
| .isFalse h => absurd hy h
attribute [irreducible] Nat.modCore
set_option bootstrap.genMatcherCode false in
/--
The modulo operator, which computes the remainder when dividing one natural number by another.
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
than an error.
`Nat.mod` is a wrapper around `Nat.modCore` that special-cases two situations, giving better
definitional reductions:
* `Nat.mod 0 m` should reduce to `m`, for all terms `m : Nat`.
* `Nat.mod n (m + n + 1)` should reduce to `n` for concrete `Nat` literals `n`.
These reductions help `Fin n` literals work well, because the `OfNat` instance for `Fin` uses
`Nat.mod`. In particular, `(0 : Fin (n + 1)).val` should reduce definitionally to `0`. `Nat.modCore`
can handle all numbers, but its definitional reductions are not as convenient.
This function is overridden at runtime with an efficient implementation. This definition is the
logical model.
Examples:
* `7 % 2 = 1`
* `9 % 3 = 0`
* `5 % 7 = 5`
* `5 % 0 = 5`
* `show ∀ (n : Nat), 0 % n = 0 from fun _ => rfl`
* `show ∀ (m : Nat), 5 % (m + 6) = 5 from fun _ => rfl`
-/
@[extern "lean_nat_mod"]
protected def Nat.mod : @& Nat @& Nat Nat
/-
Nat.modCore is defined with fuel and thus does not reduce with open terms very well.
Nevertheless it is desirable for trivial `Nat.mod` calculations, namely
* `Nat.mod 0 m` for all `m`
* `Nat.mod n (m + n + 1)` for concrete literals `n`,
to reduce definitionally.
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
definition.
-/
| 0, _ => 0
| n@(succ _), m => ite (LE.le m n) (Nat.modCore n m) n
instance Nat.instMod : Mod Nat := Nat.mod
theorem Nat.mod_lt : (x : Nat) {y : Nat} (hy : LT.lt 0 y) LT.lt (HMod.hMod x y) y
| 0, succ _, _ => Nat.zero_lt_succ _
| succ n, m, hm =>
show LT.lt (ite (LE.le m (succ n)) (Nat.modCore (succ n) m) (succ n)) _ from
match Nat.decLe m (succ n) with
| .isTrue _ => Nat.modCore_lt hm
| .isFalse h => Nat.lt_of_not_le h
attribute [gen_constructor_elims] Nat
/--
@@ -2090,6 +2285,14 @@ instance {n} : LE (Fin n) where
instance Fin.decLt {n} (a b : Fin n) : Decidable (LT.lt a b) := Nat.decLt ..
instance Fin.decLe {n} (a b : Fin n) : Decidable (LE.le a b) := Nat.decLe ..
/--
Returns `a` modulo `n` as a `Fin n`.
This function exists for bootstrapping purposes. Use `Fin.ofNat` instead.
-/
@[expose] protected def Fin.Internal.ofNat (n : Nat) (hn : LT.lt 0 n) (a : Nat) : Fin n :=
HMod.hMod a n, Nat.mod_lt _ hn
/--
A bitvector of the specified width.
@@ -2126,6 +2329,13 @@ instance : DecidableEq (BitVec w) := BitVec.decEq
protected def BitVec.ofNatLT {w : Nat} (i : Nat) (p : LT.lt i (hPow 2 w)) : BitVec w where
toFin := i, p
/--
The bitvector with value `i mod 2^n`.
-/
@[expose, match_pattern]
protected def BitVec.ofNat (n : Nat) (i : Nat) : BitVec n where
toFin := Fin.Internal.ofNat (HPow.hPow 2 n) (Nat.pow_pos (Nat.zero_lt_succ _)) i
/--
Return the underlying `Nat` that represents a bitvector.
@@ -2174,6 +2384,21 @@ This function is overridden at runtime with an efficient implementation.
def UInt8.ofNatLT (n : @& Nat) (h : LT.lt n UInt8.size) : UInt8 where
toBitVec := BitVec.ofNatLT n h
/--
Converts a natural number to an 8-bit unsigned integer, wrapping on overflow.
This function is overridden at runtime with an efficient implementation.
Examples:
* `UInt8.ofNat 5 = 5`
* `UInt8.ofNat 255 = 255`
* `UInt8.ofNat 256 = 0`
* `UInt8.ofNat 259 = 3`
* `UInt8.ofNat 32770 = 2`
-/
@[extern "lean_uint8_of_nat"]
def UInt8.ofNat (n : @& Nat) : UInt8 := BitVec.ofNat 8 n
set_option bootstrap.genMatcherCode false in
/--
Decides whether two 8-bit unsigned integers are equal. Usually accessed via the `DecidableEq UInt8`
@@ -2199,6 +2424,52 @@ instance : DecidableEq UInt8 := UInt8.decEq
instance : Inhabited UInt8 where
default := UInt8.ofNatLT 0 (of_decide_eq_true rfl)
/--
Strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
natural numbers. Usually accessed via the `<` operator.
-/
protected def UInt8.lt (a b : UInt8) : Prop := LT.lt a.toBitVec b.toBitVec
/--
Non-strict inequality of 8-bit unsigned integers, defined as inequality of the corresponding
natural numbers. Usually accessed via the `≤` operator.
-/
protected def UInt8.le (a b : UInt8) : Prop := LE.le a.toBitVec b.toBitVec
instance : LT UInt8 := UInt8.lt
instance : LE UInt8 := UInt8.le
/--
Decides whether one 8-bit unsigned integer is strictly less than another. Usually accessed via the
`DecidableLT UInt8` instance.
This function is overridden at runtime with an efficient implementation.
Examples:
* `(if (6 : UInt8) < 7 then "yes" else "no") = "yes"`
* `(if (5 : UInt8) < 5 then "yes" else "no") = "no"`
* `show ¬((7 : UInt8) < 7) by decide`
-/
@[extern "lean_uint8_dec_lt"]
def UInt8.decLt (a b : UInt8) : Decidable (LT.lt a b) :=
inferInstanceAs (Decidable (LT.lt a.toBitVec b.toBitVec))
/--
Decides whether one 8-bit unsigned integer is less than or equal to another. Usually accessed via the
`DecidableLE UInt8` instance.
This function is overridden at runtime with an efficient implementation.
Examples:
* `(if (15 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
* `(if (15 : UInt8) ≤ 5 then "yes" else "no") = "no"`
* `(if (5 : UInt8) ≤ 15 then "yes" else "no") = "yes"`
* `show (7 : UInt8) ≤ 7 by decide`
-/
@[extern "lean_uint8_dec_le"]
def UInt8.decLe (a b : UInt8) : Decidable (LE.le a b) :=
inferInstanceAs (Decidable (LE.le a.toBitVec b.toBitVec))
attribute [instance] UInt8.decLt UInt8.decLe
/-- The number of distinct values representable by `UInt16`, that is, `2^16 = 65536`. -/
abbrev UInt16.size : Nat := 65536
@@ -2738,6 +3009,37 @@ def List.concat {α : Type u} : List αα → List α
| nil, b => cons b nil
| cons a as, b => cons a (concat as b)
/--
Returns the sequence of bytes in a character's UTF-8 encoding.
-/
def String.utf8EncodeChar (c : Char) : List UInt8 :=
let v := c.val.toNat
ite (LE.le v 0x7f)
(List.cons (UInt8.ofNat v) List.nil)
(ite (LE.le v 0x7ff)
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x20) 0xc0))
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
List.nil))
(ite (LE.le v 0xffff)
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x10) 0xe0))
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
List.nil)))
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 262144) 0x08) 0xf0))
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x40) 0x80))
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
(List.cons
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
List.nil))))))
/--
A string is a sequence of Unicode code points.
@@ -4545,7 +4847,7 @@ abbrev scientificLitKind : SyntaxNodeKind := `scientific
/-- `` `name `` is the node kind of name literals like `` `foo ``. -/
abbrev nameLitKind : SyntaxNodeKind := `name
/-- `` `fieldIdx ` is the node kind of projection indices like the `2` in `x.2`. -/
/-- `` `fieldIdx `` is the node kind of projection indices like the `2` in `x.2`. -/
abbrev fieldIdxKind : SyntaxNodeKind := `fieldIdx
/--

View File

@@ -7,6 +7,7 @@ module
prelude
public import Init.NotationExtra
import Init.Data.ToString.Name
public section

View File

@@ -8,6 +8,7 @@ module
prelude
public import Init.System.Platform
public import Init.Data.ToString.Basic
public import Init.Data.String.Basic
public section

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