Compare commits

...

199 Commits

Author SHA1 Message Date
Sofia Rodrigues
bb2954d8d7 fix: remove async from notify and test 2025-09-24 00:02:41 -03:00
Sofia Rodrigues
07f39d40dc feat: add notify 2025-09-24 00:02:41 -03:00
Sofia Rodrigues
7b3b323525 fix: stream can only return one type 2025-09-24 00:02:41 -03:00
Sofia Rodrigues
40a807527a fix: remove useless function 2025-09-24 00:02:41 -03:00
Sofia Rodrigues
5e40283a07 feat: remove outparams 2025-09-24 00:02:41 -03:00
Sofia Rodrigues
9837e4ccea feat: async type classes 2025-09-24 00:02:40 -03:00
Sofia Rodrigues
94e5b66dfe feat: add AsyncStream, AsyncWrite and AsyncRead type classes (#10370)
This PR adds async type classes for streams.
2025-09-23 23:30:33 +00:00
Joachim Breitner
8443600762 chore: assert hasLooseBVar before shifting (#10528)
This assumptions seems to be violated in #10353, so maybe worth
asserting it here to more quickly stumble over it.
2025-09-23 20:49:04 +00:00
Garmelon
8b64425033 chore: set temci tags for the radar bench script (#10527)
The radar bench scripts at
https://github.com/leanprover/radar-bench-lean4/ split up the benchmarks
between the two runners based on the tags: One runner filters by the tag
`stdlib` while the other filters by the tag `other`. Only benchmarks
using one of these tags will be run, and any benchmark tagged with both
will waste electricity.

As far as I know, the tags are unused otherwise, so I just replaced all
the old tags.
2025-09-23 19:51:10 +00:00
David Thrane Christiansen
d96fd949ff fix: invalid docstring suggestions for attributes (#10522)
This also exposed an issue with `#guard_msgs` in Verso mode where the
docstring would log parse errors as if it contained Verso, even though
it actually worked. This has been fixed, and error messages improved as
well.
2025-09-23 16:18:21 +00:00
Sebastian Ullrich
d33aece210 feat: list definitions in defeq problems that could not be unfolded for lack of @[expose] (#10158)
This PR adds information about definitions blocked from unfolding via
the module system to type defeq errors.
2025-09-23 16:13:39 +00:00
Sebastian Graf
9a7bab5f90 chore: add documentation for mvcgen related definitions (#10525) 2025-09-23 15:59:58 +00:00
Kim Morrison
e2f87ed215 chore: lemma for unfolding eraseIdxIfInBounds (#10520) 2025-09-23 13:08:41 +00:00
Tom Levy
e42892cfb6 doc: fix comment about String.fromUTF8 replacing invalid chars (#10240)
Hi, the doc of `String.fromUTF8` previously said invalid characters are
replaced with 'A'. But the parameter `h : validateUTF8 a` guarantees
there are no invalid characters, so that explanation doesn't make sense
to me. This PR deletes that explanation (and fixes some unrelated
typos).

I also have a patch that uses `h` to prove each of the characters is
valid, eliminating the need for a default character
([pr/chore-String-fromUTF8-prove-valid](27f1ff36b2)),
would you be interested in merging that?

<details>
<summary>Notes on invalid characters from unchecked C++</summary>
I don't know if this function may be called from unchecked C++ with
invalid characters. If it may, I'm not sure what would happen with my
patched function... I'm not familiar with Lean's safety model, but it
seems like a bad idea to have a Lean function that takes a proof of a
proposition but is expected to operate in a certain way even if the
proposition is false. I think the safe approach is to have two functions
-- one that takes a proof and is only called from Lean, and another that
doesn't take a proof and replaces invalid chars (for use from C++, not
sure whether it's useful from Lean); I'd prefer to go even further and
report an error instead of silently replacing invalid characters (I'm
not sure if there is any easy way to report errors/panic in Lean code
called from C++).
</details>
2025-09-23 10:19:20 +00:00
Sebastian Ullrich
cc5c070328 fix: inline/specialize may only refer to publicly imported decls for now (#10494)
This PR resolves a potential bad interaction between the compiler and
the module system where references to declarations not imported are
brought into scope by inlining or specializing. We now proactively check
that declarations to be inlined/specialized only reference public
imports. The intention is to later resolve this limitation by moving out
compilation into a separate build step with its own import/incremental
system.
2025-09-23 09:58:14 +00:00
David Thrane Christiansen
f122454ef6 chore: cleanup and better docs for #10479 (#10504)
This PR cleans up a half-reverted refactor and adds documentation to
#10479.
2025-09-23 09:02:07 +00:00
Sebastian Graf
02f482129a fix: Use @[tactic_alt] for bv_decide, mvcgen and similar tactics (#10506)
This PR annotates the shadowing main definitions of `bv_decide`,
`mvcgen` and similar tactics in `Std` with the semantically richer
`tactic_alt` attribute so that `verso` will not warn about overloads.

This fixes leanprover/verso#535.
2025-09-23 07:40:02 +00:00
Kim Morrison
0807f73171 feat: basic premise selection algorithm based on MePo (#7844)
This PR adds a simple implementation of MePo, from "Lightweight
relevance filtering for machine-generated resolution problems" by Meng
and Paulson.

This needs tuning, but is already useful as a baseline or test case.

---------

Co-authored-by: Thomas Zhu <thomas.zhu.sh@hotmail.com>
2025-09-23 06:40:22 +00:00
Lean stage0 autoupdater
27fa5b0bb5 chore: update stage0 2025-09-23 06:22:49 +00:00
Alex Meiburg
8f9966ba74 doc: fix to new name for "Associative" in ac_rfl / ac_nf docstring (#10458)
This PR fixes the docstring for ac_rfl and ac_nf to correctly refer to
`Std.Associative` instead of the old name `Associative`; ditto
`Commutative`.
2025-09-23 05:52:05 +00:00
Sofia Rodrigues
eabd7309b7 feat: add vectored write and fix rc issue in tcp and udp cancel function (#10487)
This PR adds vectored write and fix rc issues in tcp and udp cancel
functions.
2025-09-22 17:02:57 +00:00
Sebastian Graf
795d13ddce feat: account for tactic_alt in missing docs linter (#10507)
This PR makes the missing docs linter aware of `tactic_alt`.
2025-09-22 16:23:24 +00:00
Kim Morrison
2b23afdfab chore: remove >6 month old deprecations (#10446) 2025-09-22 12:47:11 +00:00
Kim Morrison
20b0bd0a20 chore: upstream rangeOfStx? from Batteries (#10490)
This PR upstreams a helper function that is used in ProofWidgets.

---------

Co-authored-by: Marc Huisinga <mhuisi@protonmail.com>
2025-09-22 12:21:14 +00:00
Kim Morrison
979c2b4af0 chore: add grind annotations for List.not_mem_nil (#10493) 2025-09-22 12:18:03 +00:00
Kim Morrison
b3cd5999e7 chore: normalize empty ByteArrays to .empty (#10501) 2025-09-22 12:06:29 +00:00
Kim Morrison
a4dcb25f69 chore: add limited public API for builtinRpcProcedures (#10499)
This is not a complete public API, just enough to avoid an `open
private` in ProofWidgets.
2025-09-22 11:20:25 +00:00
Henrik Böving
85ce814689 fix: constant folding for UIntX (#10495)
This PR fixes constant folding for UIntX in the code generator. This
optimization was previously simply dead code due to the way that uint
literals are encoded.
2025-09-22 10:06:24 +00:00
Leonardo de Moura
9fc18b8ab4 doc: extra grind docstrings (#10486)
This PR adds and expands `grind` related docstrings.
2025-09-22 03:27:48 +00:00
Leonardo de Moura
852a3db447 chore: improve grind imports (#10491) 2025-09-22 01:25:41 +00:00
Lean stage0 autoupdater
d0d5d4ca39 chore: update stage0 2025-09-21 11:13:12 +00:00
Sebastian Ullrich
b32f3e8930 chore: revert "feat: add vectored write and fix rc issue in tcp and udp cancel functions" (#10485)
Reverts leanprover/lean4#10367 due to Windows build failure
2025-09-21 10:43:46 +00:00
David Thrane Christiansen
34f5fba54d chore: remove bootstrapping workaround (#10484)
This PR removes temporary bootstrapping workarounds introduced in PR
#10479.
2025-09-21 07:36:49 +00:00
Leonardo de Moura
4c9601e60f feat: support for injective functions in grind (#10483)
This PR completes support for injective functions in grind. See
examples:
```lean

/-! Add some injectivity theorems. -/

def double (x : Nat) := 2*x

@[grind inj] theorem double_inj : Function.Injective double := by
  grind [Function.Injective, double]

structure InjFn (α : Type) (β : Type) where
  f : α → β
  h : Function.Injective f

instance : CoeFun (InjFn α β) (fun _ => α → β) where
  coe s := s.f

@[grind inj] theorem fn_inj (F : InjFn α β) : Function.Injective (F : α → β) := by
  grind [Function.Injective, cases InjFn]

def toList (a : α) : List α := [a]

@[grind inj] theorem toList_inj : Function.Injective (toList : α → List α) := by
  grind [Function.Injective, toList]

/-! Examples -/

example (x y : Nat) : toList (double x) = toList (double y) → x = y := by
  grind

example (f : InjFn (List Nat) α) (x y z : Nat)
    : f (toList (double x)) = f (toList y) →
      y = double z →
      x = z := by
  grind
```
2025-09-21 06:31:46 +00:00
Leonardo de Moura
42be7bb5c7 fix: [grind inj] attribute (#10482)
This PR fixes symbol collection for the `@[grind inj]` attribute.
2025-09-21 04:14:17 +00:00
Leonardo de Moura
5f68c1662d refactor: generalize theorem activation in grind (#10481)
This PR generalizes the theorem activation function used in `grind`. 
The goal is to reuse it to implement the injective function module.
2025-09-21 02:50:55 +00:00
Leonardo de Moura
2d14d51935 fix: equality resolution in grind (#10480)
This PR fixes a bug in the equality resolution frontend used in `grind`.
2025-09-21 02:40:38 +00:00
Lean stage0 autoupdater
7cbeb14e46 chore: update stage0 2025-09-20 22:47:35 +00:00
David Thrane Christiansen
cee2886154 feat: improvements to Verso docstrings (#10479)
This PR implements module docstrings in Verso syntax, as well as adding
a number of improvements and fixes to Verso docstrings in general. In
particular, they now have language server support and are parsed at
parse time rather than elaboration time, so the snapshot's syntax tree
includes the parsed documentation.
2025-09-20 22:05:57 +00:00
Leonardo de Moura
35764213fc fix: grind sort internalization (#10477)
This PR ensures sorts are internalized by `grind`.
2025-09-20 18:31:20 +00:00
Sofia Rodrigues
6b92cbdfa4 feat: add vectored write and fix rc issue in tcp and udp cancel functions (#10367)
This PR adds vectored write for TCP and UDP (that helps a lot with not
copying the arrays over and over) and fix a RC issue in TCP and UDP
cancel functions with the line `lean_dec((lean_object*)udp_socket);` and
a similar one that tries to decrement the object inside of the `socket`.
2025-09-20 17:01:20 +00:00
Leonardo de Moura
72bb7cf364 fix: infer_let in the kernel (#10476)
This PR fixes the dead `let` elimination code in the kernel's
`infer_let` function.

Closes #10475
2025-09-20 16:26:46 +00:00
Sofia Rodrigues
4881c3042e refactor: replace Task with Async and minor changes to some basic Async functions (#10366)
This PR refactors the Async module to use the `Async` type in all of the
`Async` files.
2025-09-20 16:23:06 +00:00
Leonardo de Moura
ec7add0b48 doc: ! modifier in grind parameters (#10474)
This PR adds a doc string for the `!` parameter modifier in `grind`.
2025-09-20 08:06:05 +00:00
Leonardo de Moura
9b842b7554 fix: message context in grind code actions (#10473)
This PR ensures the code action messages produced by `grind` include the
full context
2025-09-20 08:02:12 +00:00
Leonardo de Moura
fc718eac88 feat: code action for grind parameters (#10472)
This PR adds a code action for `grind` parameters. We need to use
`set_option grind.param.codeAction true` to enable the option. The PR
also adds a modifier to instruct `grind` to use the "default" pattern
inference strategy.
2025-09-20 07:30:39 +00:00
Michał Dobranowski
8b3c82cce2 fix: lake: GH action template condition (#10459)
This PR fixes a conditional check in a GitHub Action template generated
by Lake.

Closes #10420.
2025-09-20 06:33:42 +00:00
Mac Malone
0d1b7e6c88 chore: lake: fix tests/lean (#10470)
The ordering of the `--setup` JSON object changed at some point,
breaking this test. This PR fixes it by avoiding the potential for such
breakages.
2025-09-20 02:11:50 +00:00
Leonardo de Moura
d898c9ed17 fix: grind canonicalizer (#10469)
This PR fixes an incorrect optimization in the `grind` canonicalizer.
See the new test for an example that exposes the problem.
2025-09-20 01:24:54 +00:00
Leonardo de Moura
c6abc3c036 feat: improve grind diagnostics (#10466)
This PR reduces noise in the 'Equivalence classes' section of the
`grind` diagnostics. It now uses a notion of *support expressions*.
Right now, it is hard-coded, but we will probably make it extensible in
the future. The current definition is

- `match`, `ite` and `dite`-applications. They have builtin support in
`grind`.
- Cast-like applications used by `grind`: `toQ`, `toInt`, `Nat.cast`,
`Int.cast`, and `cast`
- `grind` gadget applications (e.g., `Grind.nestedDecidable`)
- Projections of constructors (e.g., `{ x := 1, y := 2}.x`)
- Auxiliary arithmetic terms constructed by solvers such as `cutsat` and
`ring`.

If an equivalence class contains at most one non-support term, it goes
into the “others” bucket. Otherwise, we display the non-support elements
and place the support terms in a child node.

**BEFORE**:
<img width="1397" height="1558" alt="image"
src="https://github.com/user-attachments/assets/4fd4de31-7300-4158-908b-247024381243"
/>

**AFTER**:
<img width="840" height="340" alt="image"
src="https://github.com/user-attachments/assets/05020f34-4ade-49bf-8ccc-9eb0ba53c861"
/>

**Remark**: No information is lost; it is just grouped differently."
2025-09-19 23:44:30 +00:00
Leonardo de Moura
d07862db2a chore: skip cast-like operations in grind mbtc (#10465)
This PR skips cast-like helper `grind` functions during `grind mbtc`
2025-09-19 21:12:25 +00:00
Leonardo de Moura
8a79ef3633 chore: missing grind normalization (#10463)
This PR adds `Nat.sub_zero` as a `grind` normalization rule.
2025-09-19 18:50:39 +00:00
Leonardo de Moura
b1c82f776b chore: mbtc in grind cutsat (#10462)
Minor improvement to `grind mbtc` in `cutsat`.
2025-09-19 18:47:10 +00:00
Leonardo de Moura
f278f31469 fix: unnecessary case-splits in grind mbtc (#10461)
This PR fixes unnecessary case splits generated by the `grind mbtc`
module. Here, `mbtc` stands for model-based theory combination.
2025-09-19 17:24:57 +00:00
Joachim Breitner
38b4062edb feat: linear-size Ord instance (#10270)
This PR adds an alternative implementation of `Deriving Ord` based on
comparing `.ctorIdx` and using a dedicated matcher for comparing same
constructors (added in #10152). The new option
`deriving.ord.linear_construction_threshold` sets the constructor count
threshold (10 by default) for using the new construction.

It also (unconditionally) changes the implementation for enumeration
types to simply compare the `ctorIdx`.
2025-09-19 14:13:57 +00:00
Sebastian Graf
ae8dc414c3 feat: mvcgen invariants? to scaffold initial invariants (#10456)
This PR implements `mvcgen invariants?` for providing initial invariant
skeletons for the user to flesh out. When the loop body has an early
return, it will helpfully suggest `Invariant.withEarlyReturn ...` as a
skeleton.

```lean
def mySum (l : List Nat) : Nat := Id.run do
  let mut acc := 0
  for x in l do
    acc := acc + x
  return acc

/--
info: Try this:
  invariants
    · ⇓⟨xs, acc⟩ => _
-/
#guard_msgs (info) in
theorem mySum_suggest_invariant (l : List Nat) : mySum l = l.sum := by
  generalize h : mySum l = r
  apply Id.of_wp_run_eq h
  mvcgen invariants?
  all_goals admit

def nodup (l : List Int) : Bool := Id.run do
  let mut seen : HashSet Int := ∅
  for x in l do
    if x ∈ seen then
      return false
    seen := seen.insert x
  return true

/--
info: Try this:
  invariants
    · Invariant.withEarlyReturn (onReturn := fun r acc => _) (onContinue := fun xs acc => _)
-/
#guard_msgs (info) in
theorem nodup_suggest_invariant (l : List Int) : nodup l ↔ l.Nodup := by
  generalize h : nodup l = r
  apply Id.of_wp_run_eq h
  mvcgen invariants?
  all_goals admit
```
2025-09-19 14:05:24 +00:00
Sebastian Ullrich
7822ee4500 fix: check that compiler does not infer inconsistent types between modules (#10418)
This PR fixes a potential miscompilation when using non-exposed type
definitions using the module system by turning it into a static error. A
future revision may lift the restriction by making the compiler metadata
independent of the current module.
2025-09-19 12:36:47 +00:00
Joachim Breitner
8f22c56420 refactor: less public section in Eqns.lean files (#10454) 2025-09-19 11:52:56 +00:00
Joachim Breitner
0e122870be perf: mkNoConfusionCtors: cheaper inferType (#10455)
This PR changes `mkNoConfusionCtors` so that its use of `inferType` does
not have to reduce `noConfusionType`, to make #10315 really effective.
2025-09-19 10:51:17 +00:00
Sebastian Graf
13c23877d4 fix: reduce through lets in mvcgen main loop (#10453)
This PR makes `mvcgen` reduce through `let`s, so that it progresses over
`(have t := 42; fun _ => foo t) 23` by reduction to `have t := 42; foo
t` and then introducing `t`.
2025-09-19 08:21:04 +00:00
Kim Morrison
7fba12f8f7 chore: add test for website primes example (#10451)
(This test is currently failing. We either need to change the failing
line to `grind [!factorial_pos]`, or again change the behaviour of
grind.)
2025-09-19 04:56:28 +00:00
Kim Morrison
abb487a0c0 chore: include lean-lang.org in release checklist (#10450) 2025-09-19 03:46:32 +00:00
Leonardo de Moura
1091053824 chore: reportIssue! at grind ematch (#10449)
This PR ensures that issues reported by the E-matching module are
displayed only when `set_option grind.debug true` is enabled. Users
reported that these messages are too distracting and not very useful.
They are more valuable for library developers when annotating their
libraries.
2025-09-19 02:43:03 +00:00
Leonardo de Moura
545bd8a96c feat: add [grind inj] attribute (#10447)
This PR adds the `[grind inj]` attribute for marking injectivity
theorems for `grind`.
2025-09-19 00:49:05 +00:00
Sebastian Ullrich
2f9618f76b chore: make def used by proofwidgets public again (#10437) 2025-09-18 21:30:23 +00:00
Joachim Breitner
fa36fcd448 feat: linear-size BEq instance (#10268)
This PR adds an alternative implementation of `DerivingBEq` based on
comparing `.ctorIdx` and using a dedicated matcher for comparing same
constructors (added in #10152), to avoid the quadratic overhead of the
default match implementation. The new option
`deriving.beq.linear_construction_threshold` sets the constructor count
threshold (10 by default) for using the new construction. Such instances
also allow `deriving ReflBEq, LawfulBeq`, although these proofs for
these properties are still quadratic.
2025-09-18 21:27:25 +00:00
Henrik Böving
9a3b4b2716 fix: overeager inc insertion for large uint constants (#10444)
This PR fixes an overeager insertion of `inc` operations for large uint
constants.


Closes: #10443
2025-09-18 20:54:19 +00:00
Leonardo de Moura
9fb5ab8450 feat: helper definitions for injective function support in grind (#10445)
This PR adds helper definitions in preparation for the upcoming
injective function support in `grind`.
2025-09-18 19:42:15 +00:00
Leonardo de Moura
a62c0bce77 chore: missing grind modifier (#10441) 2025-09-18 14:44:57 +00:00
Lean stage0 autoupdater
3ce554abd7 chore: update stage0 2025-09-18 13:48:00 +00:00
Joachim Breitner
257c347f9f feat: reduceCtorIdx simproc (#10440)
This PR adds the `reduceCtorIdx` simproc which recognizes and reduces
`ctorIdx` applications. This is not on by default yet because it does
not use the discrimination tree (yet).
2025-09-18 13:05:14 +00:00
Sebastian Ullrich
ca1315e3ba fix: backtracking kernel errors under Elab.async (#10438)
This PR fixes an issue where notations and other overloadings would
signal kernel errors even though there exists a successful
interpretation.
2025-09-18 12:33:57 +00:00
Markus Himmel
197bc6cb66 feat: redefine String, part one (#10304)
This PR redefines `String` to be the type of byte arrays `b` for which
`b.IsValidUtf8`.

This moves the data model of strings much closer to the actual data
representation at runtime.

In the near future, we will

- provide variants of `String.Pos` and `Substring` that only allow for
valid positions
- redefine all `String` functions to be much closer to their C++
implementations

In the near-to-medium future we will then provide comprehensive
verification of `String` based on these refactors.
2025-09-18 11:36:52 +00:00
Luisa Cicolini
02ca710872 feat: add BitVec.ctz to bv_decide (#9298)
This PR adds support the Count Trailing Zeros operation `BitVec.ctz` to
the bitvector library and to `bv_decide`, relying on the existing `clz`
circuit. We also build some theory around `BitVec.ctz` (analogous to the
theory existing for `BitVec.clz`) and introduce lemmas
`BitVec.[ctz_eq_reverse_clz, clz_eq_reverse_ctz, ctz_lt_iff_ne_zero,
getLsbD_false_of_lt_ctz, getLsbD_true_ctz_of_ne_zero,
two_pow_ctz_le_toNat_of_ne_zero, reverse_reverse_eq,
reverse_eq_zero_iff]`.

`ctz` operation is common in numerous compiler intrinsics (see
[here](https://clang.llvm.org/docs/LanguageExtensions.html#intrinsics-support-within-constant-expressions))
and architectures (see
[here](https://en.wikipedia.org/wiki/Find_first_set)).

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
2025-09-18 08:38:07 +00:00
Kim Morrison
3fbf080d72 chore: update script/release_notes.py for changelog-tactics (#10436) 2025-09-18 07:22:53 +00:00
Kim Morrison
4379002d05 feat: add reprove command for re-proving theorems with a specified tactic (#10434)
This PR adds `reprove N by T`, which effectively elaborates `example
type_of% N := by T`. It supports multiple identifiers. This is useful
for testing tactics.


🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-18 06:29:53 +00:00
Lean stage0 autoupdater
5d50ec90f9 chore: update stage0 2025-09-18 04:56:02 +00:00
Leonardo de Moura
6ca699b1ff feat: enable new E-matching pattern inference procedure in grind (#10432)
This PR enables the new E-matching pattern inference heuristic for
`grind`, implemented in PR #10422.
**Important**: Users can still use the old pattern inference heuristic
by setting:

```lean
set_option backward.grind.inferPattern true
```

In PR #10422, we introduced the new modifier `@[grind!]` for enabling
the minimal indexable subexpression condition. This option can now also
be set in `grind` parameters. Example:

```lean
opaque f : Nat → Nat
opaque fInv : Nat → Nat 
axiom fInv_f : fInv (f x) = x

/-- trace: [grind.ematch.pattern] fInv_f: [f #0] -/
#guard_msgs in 
set_option trace.grind.ematch.pattern true in
example {x y} : f x = f y → x = y := by
  /-
  The modifier `!` instructs `grind` to use the minimal indexable subexpression 
  (i.e., `f x` in this case).   
  -/
  grind [!fInv_f] 
```
2025-09-18 04:13:54 +00:00
Kim Morrison
c2d56fa031 chore: custom steps in release checklist for CSLib (#10433) 2025-09-18 01:12:00 +00:00
Lean stage0 autoupdater
b6d590ccc3 chore: update stage0 2025-09-17 21:44:32 +00:00
Sebastian Ullrich
719765ec5c feat: overhaul meta system (#10362)
This PR refines and clarifies the `meta` phase distinction in the module
system.

* `meta import A` without `public` now has the clarified meaning of
"enable compile-time evaluation of declarations in or above `A` in the
current module, but not downstream". This is now checked statically by
enforcing that public meta defs, which therefore may be referenced from
outside, can only use public meta imports, and that global evaluating
attributes such as `@[term_parser]` can only be applied to public meta
defs.
* `meta def`s may no longer reference non-meta defs even when in the
same module. This clarifies the meta distinction as well as improves
locality of (new) error messages.
* parser references in `syntax` are now also properly tracked as meta
references.
* A `meta import` of an `import` now properly loads only the `.ir` of
the nested module for the purposes of execution instead of also making
its declarations available for general elaboration.
* `initialize` is now no longer being run on import under the module
system, which is now covered by `meta initialize`.
2025-09-17 21:04:29 +00:00
Lean stage0 autoupdater
11b0e7d89c chore: update stage0 2025-09-17 18:46:58 +00:00
Leonardo de Moura
37f3f0e1e2 feat: minimal indexable subexpressions in grind parameters (#10430)
This PR ensures users can select the "minimal indexable subexpression"
condition in `grind` parameters. Example, they can now write `grind [!
-> thmName]`. `grind?` will include the `!` modifier whenever users had
used `@[grind!]`. This PR also fixes a missing case in the new pattern
inference procedure.
It also adjusts some `grind` annotations and tests in preparation for
setting the new pattern inference heuristic as the new default.
2025-09-17 18:04:05 +00:00
Henrik Böving
85645958f9 fix: overeager specialisation reuse in codegen (#10429)
This PR fixes and overeager reuse of specialisation in the code
generator.

The issue was originally discovered in
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Miscompilation.20.28incorrect.20code.29.20in.20new.20compiler/near/540037917
and occurs because the specialisation cache didnt't take the name of
alternatives in pattern matches
into account.
2025-09-17 17:35:40 +00:00
Leonardo de Moura
a80169165e chore: missing grind modifiers and local grind theorems config (#10428)
This PR makes explicit missing `grind` modifiers, and ensures `grind`
uses "minIndexable" for local theorems.
2025-09-17 16:15:16 +00:00
Robert J. Simmons
8dca311ba5 doc: update URLs that are currently pointing to redirects (#10397)
This PR updates several URLs that are currently pointing to redirects on
lean-lang.org, most importantly a few in the top-level README
2025-09-17 15:50:07 +00:00
Lean stage0 autoupdater
e6dfde1ad6 chore: update stage0 2025-09-17 14:32:29 +00:00
Joachim Breitner
e532ce95ce refactor: change how equations for structural recursion are proved (#10415)
This PR changes the order of steps tried when proving equational
theorems for structural recursion. In order to avoid goals that `split`
cannot handle, avoid unfolding the LHS of the equation to `.brecOn` and
`.rec` until after the RHS has been split into its final cases.

Fixes: #10195
2025-09-17 13:46:45 +00:00
Joachim Breitner
e74b81169d feat: split to generalize proof discriminants (#10425)
This PR lets the `split` tactic generalize discriminants that are not
free variables and proofs using `generalize`. If the only
non-fvar-discriminants are proofs, then this avoids the more elaborate
generalization strategy of `split`, which can fail with dependent
motives, thus mitigating issue #10424.
2025-09-17 12:18:30 +00:00
Markus Himmel
cf8ffc28d3 chore: kernel changes ahead of String redefinition (#10330)
This PR changes the defeq algorithm to perform `whnf` on the `String.mk`
expression it creates for string literals.

This is currently a no-op, but will no longer be one once `String` is
redefined so that `String.mk` is a regular function instead of a
constructor.
2025-09-17 09:12:07 +00:00
Marc Huisinga
d625aaa96f feat: server-side for trace search (#10365)
This PR implements the server-side for a new trace search mechanism in
the InfoView.

Demo:
![Search
demo](https://github.com/user-attachments/assets/f8f1cdfd-a4f2-4258-8cb8-360f64ea06e9)
2025-09-17 08:58:56 +00:00
Lean stage0 autoupdater
89e4f9815f chore: update stage0 2025-09-17 09:11:32 +00:00
Sebastian Ullrich
9002cc8761 fix: elaborate private inductive ctor in the private scope (#10423) 2025-09-17 08:39:27 +00:00
Lean stage0 autoupdater
5a7d663624 chore: update stage0 2025-09-17 03:26:25 +00:00
Leonardo de Moura
efb398b040 feat: new grind pattern inference heuristic and code action (#10422)
This PR implements the new E-matching pattern inference heuristic for
`grind`. It is not enabled yet. You can activate the new behavior using
`set_option backward.grind.inferPattern false`. Here is a summary of the
new behavior.

* `[grind =]`, `[grind =_]`, `[grind _=_]`, `[grind <-=]`: no changes;
we keep the current behavior.
  
* `[grind ->]`, `[grind <-]`, `[grind =>]`, `[grind <=]`: we stop using
the *minimal indexable subexpression* and instead use the first
indexable one.

* `[grind! <mod>]`: behaves like `[grind <mod>]` but uses the minimal
indexable subexpression restriction. We generate an error if the user
writes `[grind! =]`, `[grind! =_]`, `[grind! _=_]`, or `[grind! <-=]`,
since there is no pattern search in these cases.
  
* `[grind]`: it tries `=`, `=_`, `<-`, `->`, `<=`, `=>` with and without
the minimal indexable subexpression restriction. For the ones that work,
we generate a code action to encourage users to select the one they
prefer.

* `[grind!]`: it tries `<-`, `->`, `<=`, `=>` using the minimal
indexable subexpression restriction. For the ones that work, we generate
a code action to encourage users to select the one they prefer.

* `[grind? <mod>]`: where `<mod>` is one of the modifiers above, it
behaves like `[grind <mod>]` but also displays the pattern.
  
Example:
```lean
/--
info: Try these:
  • [grind =] for pattern: [f (g #0)]
  • [grind =_] for pattern: [r #0 #0]
  • [grind! ←] for pattern: [g #0]
-/
#guard_msgs in
@[grind] axiom fg₇ : f (g x) = r x x
```
2025-09-17 02:44:11 +00:00
Leonardo de Moura
4cbd1a439a feat: non-commutative semiring normalizer in grind (#10421)
This PR adds a normalizer for non-commutative semirings to `grind`.
Examples:
```lean
open Lean.Grind
variable (R : Type u) [Semiring R]

example (a b c : R) : a * (b + c) = a * c + a * b := by grind
example (a b : R) : (a + 2 * b)^2 = a^2 + 2 * a * b + 2 * b * a + 4 * b^2 := by grind
example (a b : R) : b^2 + (a + 2 * b)^2 = a^2 + 2 * a * b + b * (1+1) * a * 1 + 5 * b^2 := by grind
example (a b : R) : a^3 + a^2*b + a*b*a + b*a^2 + a*b^2 + b*a*b + b^2*a + b^3 = (a+b)^3 := by grind
```
2025-09-16 20:15:38 +00:00
Leonardo de Moura
20873d5d72 feat: helper theorem for normalizing non-commutative semirings (#10419)
This PR adds the helper theorem `eq_normS_nc` for normalizing
non-commutative semirings. We will use this theorem to justify
normalization steps in the `grind ring` module.
2025-09-16 18:09:34 +00:00
Leonardo de Moura
4c1830e5ae refactor: semiring support in grind ring (#10403)
This PR reduces a bit of redundancy in the `grind ring`.
2025-09-16 17:37:55 +00:00
Joachim Breitner
7b75db7c6e refactor: use deriving LawfulBEq in Init (#10411)
This PR starts using `deriving LawfulBEq` in `Init`, removing some hairy
hand-rolled proofs.
2025-09-16 16:26:32 +00:00
Joachim Breitner
8d418201a6 fix: use with_reducible in deriving_LawfulEq_tactic_step (#10417)
This PR changes the automation in `deriving_LawfulEq_tactic_step` to use
`with_reducible` when asserting the shape of the goal using `change`, so
that we do not accidentally unfold `x == x'` calls here. Fixes #10416.
2025-09-16 16:07:42 +00:00
Lean stage0 autoupdater
850a4c897f chore: update stage0 2025-09-16 13:43:34 +00:00
Joachim Breitner
186f5a6960 feat: deriving ReflBEq and LawfulBEq (#10351)
This PR adds the ability to do `deriving ReflBEq, LawfulBEq`. Both
classes have to listed in the `deriving` clause. For `ReflBEq`, a simple
`simp`-based proof is used. For `LawfulBEq`, a dedicated,
syntax-directed tactic is used that should work for derived `BEq`
instances. This is meant to work with `deriving BEq` (but you can try to
use it on hand-rolled `@[methods_specs] instance : BEq…` instances).
Does not support mutual or nested inductives.
2025-09-16 12:58:01 +00:00
Lean stage0 autoupdater
917715c862 chore: update stage0 2025-09-16 11:06:37 +00:00
Joachim Breitner
50435417ac chore: remove comment from src/stdlib_flags.h (#10409)
This PR removes an update-stage0-comment from
`src/stdlib_flags.h`. Again. Sorry for that.
2025-09-16 10:39:27 +00:00
Joachim Breitner
9deff2751f refactor: use reduceBEq in Init (#10398)
This PR uses the `reduceBEq` simproc in Init, but mostly only for
testing, because afer #10351 this code will be derived.
2025-09-16 10:35:46 +00:00
Joachim Breitner
f3d93970dc feat: @[method_specs_simp] in Init (#10407)
This PR adds `@[method_specs_simp]` in `Init` for type classes like
`HAppend`.
2025-09-16 10:27:33 +00:00
Lean stage0 autoupdater
d1577fda7a chore: update stage0 2025-09-16 09:49:47 +00:00
Joachim Breitner
ca10fd7c4f fix: method spec theorems to be private when appropriate (#10406)
This PR improves upon #10302 to properly make the method spec theorems
private if the implementation function is not exposed.
2025-09-16 09:20:04 +00:00
Kim Morrison
a1cd945e82 chore: remove deprecated Xor (#10404) 2025-09-16 03:41:20 +00:00
Kim Morrison
9c372b9bc2 chore: begin development cycle for v4.25.0 (#10402) 2025-09-16 00:25:06 +00:00
Kim Morrison
38214ac121 chore: fix to release scripts (#10401) 2025-09-16 00:23:55 +00:00
Lean stage0 autoupdater
6d30aeefe5 chore: update stage0 2025-09-15 17:51:09 +00:00
Kyle Miller
112fa51e08 fix: keep abstract nested proofs procedure from hiding sorry warning (#10388)
This PR fixes a bug where definitions with nested proofs that contain
`sorry` might not report "warning: declaration uses 'sorry'" if the
proof has the same type as another nested proof from a previous
declaration. The bug only affected log messages; `#print axioms` would
still correctly report uses of `sorryAx`.

The fix is that now the abstract nested proofs procedure does not
consult the aux lemma cache if the proof contains a `sorry`.

Closes #10196
2025-09-15 17:07:49 +00:00
David Thrane Christiansen
9b53e39804 feat: activate Verso docstring builtins (#10386)
This PR activates the builtin expanders for Verso docstrings.
2025-09-15 17:07:33 +00:00
Kyle Miller
ede1acfb44 fix: let anonymous constructor notation elaborate with insufficient arguments (#10391)
This PR gives anonymous constructor notation (`⟨x,y⟩`) an error recovery
mechanism where if there are not enough arguments then synthetic sorries
are inserted for the missing arguments and an error is logged, rather
than outright failing.

Closes #9591.
2025-09-15 16:44:34 +00:00
Kyle Miller
0799e5c4e9 fix: make sure error ranges for if tactic are correct (#10392)
This PR fixes an issue with the `if` tactic where errors were not placed
at the correct source ranges. It also adds some error recovery to avoid
additional errors about unsolved goals on the `if` token when the tactic
has incomplete syntax.

Closes #7972
2025-09-15 16:40:11 +00:00
Lean stage0 autoupdater
32a4c88986 chore: update stage0 2025-09-15 17:07:15 +00:00
Joachim Breitner
4cf3c0ae67 feat: reduceBEq and reduceOrd simprocs (#10394)
This PR adds the `reduceBEq` and `reduceOrd` simprocs. They rewrite
occurrences of `_ == _` resp. `Ord.compare _ _` if both arguments are
constructors and the corresponding instance has been marked with
`@[method_specs]` (introduced in #10302), which now by default is the
case for derived instances.
2025-09-15 16:24:44 +00:00
Lean stage0 autoupdater
06ba748221 chore: update stage0 2025-09-15 15:31:41 +00:00
Joachim Breitner
d2d32f13c0 chore: remove comment from src/stdlib_flags.h (#10396)
This PR removes an update-stage0-comment from
`src/stdlib_flags.h`; these comments should be added to
`stage0/src/stdlib_flags.h`.
2025-09-15 15:03:12 +00:00
Joachim Breitner
9aa6448fa9 feat: use @[method_specs] when deriving BEq and Ord (#10346)
This PR lets `deriving BEq` and `deriving Ord` use `@[method_specs]`
from #10302 when applicable (i.e. when not using `partial`).
2025-09-15 14:58:00 +00:00
Sofia Rodrigues
3bea7e209e feat: add signal handling support using libuv (#9258)
This PR adds support for signal handlers to the Lean standard library.

---------

Co-authored-by: Markus Himmel <markus@lean-fro.org>
2025-09-15 13:09:50 +00:00
Joachim Breitner
88fa4212d7 feat: @[method_specs] to generate specification theorems from class instances (#10302)
This PR introduces the `@[specs]` attribute. It can be applied to
(certain) type class instances and define “specification theorems” for
the class’ operations, by taking the equational theorems of the
implementation function mentioned in the type class instance and
rephrasing them in terms of the overloaded operations. Fixes #5295.

Example:

```
inductive L α where
  | nil  : L α
  | cons : α → L α → L α

def L.beqImpl [BEq α] : L α → L α → Bool
  | nil, nil           => true
  | cons x xs, cons y ys => x == y && L.beqImpl xs ys
  | _, _               => false

@[method_specs] instance [BEq α] : BEq (L α) := ⟨L.beqImpl⟩

/--
info: theorem instBEqL.beq_spec_2.{u_1} : ∀ {α : Type u_1} [inst : BEq α] (x_2 : α) (xs : L α) (y : α) (ys : L α),
  (L.cons x_2 xs == L.cons y ys) = (x_2 == y && xs == ys)
-/
#guard_msgs(pass trace, all) in
#print sig instBEqL.beq_spec_2
```

It also introduces the `method_specs_norm` simpset to allow registering
further normalization of the theorems. The intended use of this is to
rewrite, say, `Append.append` to the `HAppend.hAppend` (i.e. `++`) that
the user wants to see. Library annotations to follow in a separate PR.
2025-09-15 11:17:06 +00:00
David Thrane Christiansen
97464c9d7f fix: trailing whitespace setting for string literals was ignored (#10389)
This PR fixes a bug where string literal parsing ignored its trailing
whitespace setting.
2025-09-15 09:51:56 +00:00
Sebastian Ullrich
8df968de01 feat: have example default to the private scope (#10168) 2025-09-15 09:10:56 +00:00
Lean stage0 autoupdater
d869c38e7b chore: update stage0 2025-09-15 05:12:36 +00:00
Kim Morrison
4d8d502754 chore: remove bad grind annotation on List.eq_nil_of_map_eq_nil (#10356) 2025-09-15 04:33:16 +00:00
David Thrane Christiansen
8e1df86939 feat: improvements to Verso docstrings (#10382)
This PR makes the builtin Verso docstring elaborators bootstrap
correctly, adds the ability to postpone checks (which is necessary for
resolving forward references and bootstrapping issues), and fixes a
minor parser bug.
2025-09-15 04:28:29 +00:00
Kim Morrison
4ff33eaef5 feat: updates to release process for cslib (#10385)
This PR updates the release checklist scripts to handle a corner case in
Cslib.
2025-09-15 01:41:17 +00:00
Kim Morrison
22a4cab8c7 feat: updates to release process for v4.23.0 (#10383)
This PR includes some improvements to the release process, making the
updating of `stable` branches more robust, and including `cslib` in the
release checklist.
2025-09-14 23:52:19 +00:00
Lean stage0 autoupdater
1e12cdddc0 chore: update stage0 2025-09-14 22:54:32 +00:00
Kyle Miller
cab33ac1da feat: syntax name heuristic for unicode(...) (#10381)
This PR sets the `syntax` naming heuristic for `unicode(" → ", " -> ")`
to use `→` rather than `→->`.

Continuation of #10373.
2025-09-14 21:53:48 +00:00
Leonardo de Moura
6b97e41650 feat: sanity check for instances in grind ring (#10380)
This PR implements sanity checks in the `grind ring` module to ensure
the instances synthesized by type class resolution are definitionally
equal to the corresponding ones in the `grind` core classes. The
definitional equality test is performed with reduction restricted to
reducible definitions and instances.
2025-09-14 21:04:40 +00:00
Lean stage0 autoupdater
c2521e94e1 chore: update stage0 2025-09-14 21:03:42 +00:00
Kyle Miller
f771dea78b fix: make sure app elaborator eta feature does not result in capturable variables (#10377)
This PR fixes an issue where the "eta feature" in the app elaborator,
which is invoked when positional arguments are skipped due to named
arguments, results in variables that can be captured by those named
arguments. Now the temporary local variables that implement this feature
get fresh names. The names used for the closed lambda expression still
use the original parameter names.

Closes #6373
2025-09-14 20:19:50 +00:00
Kyle Miller
02a4713875 feat: enable notationItem in "mixfix" notation commands (#10378)
This PR enables using `notation` items in
`infix`/`infixl`/`infixr`/`prefix`/`postfix`. The motivation for this is
to enable being able to use `pp.unicode`-aware parsers. A followup PR
can combine core parsers as such:
```lean
infixr:30 unicode(" ∨ ", " \\/ ") => Or
```

Continuation of #10373.
2025-09-14 18:54:36 +00:00
Kyle Miller
7407534eb8 feat: include := in the atomic part of tactic configuration items (#10379)
This PR modifies the syntax for tactic configurations. Previously just
`(ident` would commit to tactic configuration item parsing, but now it
needs to be `(ident :=`. This enables reliably using tactic
configurations before the `term` category. For example, given `syntax
"my_tac" optConfig term : tactic`, it used to be that `my_tac (x + y)`
would have an error on `+` with "expected `:=`", but now it parses the
term.

An additional rationale is that these are like named arguments; (1)
terms can't begin with named arguments so now there is no parsing
ambiguity and (2) `Parser.Term.namedArgument` indeed already includes
`:=` in the atomic part.
2025-09-14 18:53:47 +00:00
Kyle Miller
3f80e530d3 feat: suppress safe shadowing within fun binders (#10376)
This PR modifies pretty printing of `fun` binders, suppressing the safe
shadowing feature among the binders in the same `fun`. For example,
rather than pretty printing as `fun x x => 0`, we now see `fun x x_1 =>
0`. The calculation is done per `fun`, so for example `fun x => id fun x
=> 0` pretty prints as-is, taking advantage of safe shadowing.

The motivation for this change is that many users have reported that
safe shadowing within the same `fun` is confusing.
2025-09-14 15:54:59 +00:00
Lean stage0 autoupdater
3146f6c651 chore: update stage0 2025-09-14 08:05:12 +00:00
Leonardo de Moura
22aab5c3bb feat: non-commutative ring normalizer in grind (#10375)
This PR adds support for non-commutative ring normalization in `grind`.
The new normalizer also accounts for the `IsCharP` type class. Examples:
```lean
open Lean Grind

variable (R : Type u) [Ring R]
example (a b : R) : (a + 2 * b)^2 = a^2 + 2 * a * b + 2 * b * a + 4 * b^2 := by grind
example (a b : R) : (a + 2 * b)^2 = a^2 + 2 * a * b + -b * (-4) * a - 2*b*a + 4 * b^2 := by grind

variable [IsCharP R 4]
example (a b : R) : (a - b)^2 = a^2 - a * b - b * 5 * a + b^2 := by grind
example (a b : R) : (a - b)^2 = 13*a^2 - a * b - b * 5 * a + b*3*b*3 := by grind
```
2025-09-14 07:35:08 +00:00
Kyle Miller
7e9ea00ac0 feat: add option pp.piBinderNames (#10374)
This PR adds the options `pp.piBinderNames` and
`pp.piBinderNames.hygienic`. Enabling `pp.piBinderNames` causes
non-dependent pi binder names to be pretty printed, rather than be
omitted. When `pp.piBinderNames.hygienic` is false (the default) then
only non-hygienic such biner names are pretty printed. Setting `pp.all`
enables `pp.piBinderNames` if it is not otherwise explicitly set.

Implementation note: this is exposing the secret pretty printer option
`pp.piBinderNames` that was being used within the signature pretty
printer.

Closes #1134.
2025-09-14 05:15:04 +00:00
Kyle Miller
409cbe1da9 fix: make rw collect only new goals, occurs check (#10306)
This PR fixes a few bugs in the `rw` tactic: it could "steal" goals
because they appear in the type of the rewrite, it did not do an occurs
check, and new proof goals would not be synthetic opaque. This PR also
lets the `rfl` tactic assign synthetic opaque metavariables so that it
is equivalent to `exact rfl`.

Implementation note: filtering old vs new is not sufficient. This PR
partially addresses the bug where the rw tactic creates natural
metavariables for each of the goals; now new proof goals are synthetic
opaque.

Metaprogramming API: Instead of `Lean.MVarId.rewrite` prefer
`Lean.Elab.Tactic.elabRewrite` for elaborating rewrite theorems and
applying rewrites to expressions.

Closes #10172
2025-09-14 04:44:55 +00:00
Kyle Miller
3e4fa12c72 feat: add unicode(...) parser syntax and pp.unicode option (#10373)
This PR adds a `pp.unicode` option and a `unicode("→", "->")` syntax
description alias for the lower-level `unicodeSymbol "→" "->"` parser.
The syntax is added to the `notation` command as well. When `pp.unicode`
is true (the default) then the first form is used when pretty printing,
and otherwise the second ASCII form is used. A variant, `unicode("→",
"->", preserveForPP)` causes the `->` form to be preferred; delaborators
can insert `→` directly into the syntax, which will be pretty printed
as-is; this allows notations like `fun` to use custom options such as
`pp.unicode.fun` to opt into the unicode form when pretty printing.

Additionally:
- Adds more documentation for the `symbol` and `nonReservedSymbol`
parser descriptions.
- Adds documentation for the
`infix`/`infixr`/`infixl`/`prefix`/`postfix` commands.
- The parenthesizers for symbols are improved to backtrack if the atom
doesn't match.
- Fixes a bug where `&"..."` symbols aren't validated.

This is partial progress for issue #1056. What remains is enabling
`unicode(...)` for mixfix commands and then making use of it for core
notation.
2025-09-14 04:40:03 +00:00
Mac Malone
ed5dc328d9 refactor: import Lake.Util.* from Lake (#10371)
This PR explicitly imports `Lake.Util` submodules in `Lake`, ensuring
Lake utilities are consistently available by default in configuration
files.

It also simplifies the Lake globs for the core build to ensure all Lake
submodules are built (even if they are not imported).
2025-09-13 13:56:54 +00:00
Anne Baanen
2bbf5db04f fix: add infotree context to classical tactic (#10332)
This PR ensures that the infotree recognizes `Classical.propDecidable`
as an instance, when below a `classical` tactic.

The `classical` tactic modifies the environment that the subsequent
sequence of tactics runs in (by making `Classical.propDecidable` an
instance). However, it does not add a corresponding `InfoTree.context`
node, so its effects are not visible when we want to replay a tactic
sequence (for example when running a tactic in the tactic analysis
framework). We should add a call to `Lean.Elab.withSafeInfoContext` to
remedy this issue.

There are two potential places to add this class: in the meta-level
`Lean.Elab.Tactic.classical` wrapper, or the tactic-level
`evalClassical` tactic elaborator. I chose the latter since meta-level
does not have access to info tree operations (unless we add many
parameters to `Lean.Elab.Tactic.classical`: `[MonadNameGenerator m]
[MonadOptions m] [MonadMCtx m] [MonadResolveName m] [MonadFileMap m]`).

A testcase that uses the tactic analysis framework is available here:
https://github.com/leanprover-community/mathlib4/pull/29501
2025-09-12 16:30:44 +00:00
Sebastian Ullrich
116b708269 chore: CI: ensure cache reuse in update-stage0 (#10359) 2025-09-12 14:56:32 +00:00
Lean stage0 autoupdater
4b6eab762f chore: update stage0 2025-09-12 13:30:23 +00:00
Sebastian Ullrich
9d6f391414 fix: missing docs linter under the module system (#10361) 2025-09-12 12:41:06 +00:00
Sebastian Ullrich
245ede65b5 feat: meta initialize (#10360)
This PR adds syntax for defining compile-time initializers under the
module system, with other initializers to be restricted from running at
compile time in a follow-up PR.
2025-09-12 12:39:06 +00:00
Lean stage0 autoupdater
2422b9db87 chore: update stage0 2025-09-12 11:43:21 +00:00
Sebastian Ullrich
3f9f8f094d chore: split Std.Do.SPred.Notation in preparation for meta semantics restrictions (#10358) 2025-09-12 11:09:26 +00:00
Joachim Breitner
cf18337157 perf: use per-constructor noConfusion in mkNoConfusion (#10318)
This PR uses the per-constructor `noConfusion` principles (from #10315)
in the `mkNoConfusion` app builder, if possible. This means they are
used by `injection`, `grind`, `simp` and other places. This brings
notable performance improvements when dealing with inductives with a
large number of constructors.
2025-09-12 08:42:24 +00:00
Joachim Breitner
3cf7fdcbe0 feat: per-constructor noConfusion constructions (#10315)
This PR adds `T.ctor.noConfusion` declarations, which are
specializations of `T.noConfusion` to equalities between `T.ctor`. The
point is to avoid reducing the `T.noConfusionType` construction every
time we use `injection` or a similar tactic.

```lean
Vec.cons.noConfusion.{u_1, u} {α : Type u} (P : Sort u_1) {n : Nat}
  (x : α) (xs : Vec α n) (x' : α) (xs' : Vec α n)
  (h : Vec.cons x xs = Vec.cons x' xs')
  (k : n = n → x = x' → xs ≍ xs' → P) : P
```

The constructions are not as powerful as `T.noConfusion` when the
indices of the inductive type are not just constructor parameters (or
constructor applications of these parameters), so the full
`T.noConfusion` construction is still needed as a fallback.

It may seem costly to generate these eagerly, but given that we eagerly
generate injectivity theorems already, and we will use them there, it
seems reasonable for now.

To further reduce the cost, we only generate them for constructors with
fields (for others, the `T.noConfusion` theorem doesn't provide any
information), and we use `macro_inline` to prevent the compiler from
creating code for these, given that the compiler has special support for
`T.noConfusion` that we want it to use).

An earlier version of this PR also removed trivial equations and
un-HEq-ed others, leading to
```
 (k : x = x' → xs = xs' → P) 
```
in the example above. I backed out of that change, as it makes it harder
for tactics like `injectivity` to know how often to `intro`, so better
to keep things uniform.
2025-09-12 08:00:12 +00:00
Paul Reichert
caa0eacea8 feat: ranges in UInt* (#10303)
This PR adds range support to`BitVec` and the `UInt*` types. This means
that it is now possible to write, for example, `for i in (1 : UInt8)...5
do`, in order to loop over the values 1, 2, 3 and 4 of type `UInt8`.
2025-09-12 07:52:45 +00:00
David Thrane Christiansen
b8e584a054 fix: restore monad-polymorphism to some docstring functions (#10357)
This PR makes the Markdown docstring functions monad-polymorphic again,
and improves documentation for the internal docstring API.
2025-09-12 07:41:47 +00:00
Paul Reichert
ae682ed225 feat: more iterator/range lemmas about toList and toArray (#10244)
This PR adds more lemmas about the `toList` and `toArray` functions on
ranges and iterators. It also renames `Array.mem_toArray` into
`List.mem_toArray`.
2025-09-12 07:14:28 +00:00
Cameron Zwarich
b64111d5a8 fix: convert .proj on builtin types to use projection functions (#10355)
This PR changes `toLCNF` to convert `.proj` for builtin types to use
projection functions instead.

Fixes #10078.
2025-09-12 00:19:45 +00:00
Kim Morrison
72cc6c85eb chore: correct order of implicit arguments for Injective/Surjective API (#10354) 2025-09-11 23:30:19 +00:00
Sofia Rodrigues
a966ce64ca feat: add useful functions in Parsec, add error variant and Std.Data.ByteSlice (#9599)
This PR adds the type `Std.Internal.Parsec.Error`, which contains the
constructors `.eof` (useful for checking if parsing failed due to not
having enough input and then retrying when more input arrives that is
useful in the HTTP server) and `.other`, which describes other errors.
It also adds documentation to many functions, along with some new
functions to the `ByteArray` Parsec, such as `peekWhen?`, `octDigit`,
`takeWhile`, `takeUntil`, `skipWhile`, and `skipUntil`.
2025-09-11 14:53:41 +00:00
Lean stage0 autoupdater
5c88a2bf56 chore: update stage0 2025-09-11 13:47:30 +00:00
Sebastian Ullrich
73c85b177e refactor: split Init.Meta in preparation for meta semantics restrictions (#10343) 2025-09-11 13:01:03 +00:00
Kim Morrison
5c06c79c15 chore: fix remainining discrepancies for change in grind pattern heuristics (#10347)
This PR is followup to the change in grind pattern heuristics from
#10342, typically resolving the discrepancy by writing out an explicit
`grind_pattern` for the intended pattern. The new behaviour is more
aggressive, because it selects smaller patterns.
2025-09-11 12:48:52 +00:00
Lean stage0 autoupdater
c8117a34c1 chore: update stage0 2025-09-11 12:27:01 +00:00
Sebastian Ullrich
a5f5d793d7 perf: implement jumping to native [export] decls in the interpreter (#10345)
This PR allows the interpreter to jump to native code of `[export]`
declarations, which can increase performance as well as the
effectiveness of `interpreter.prefer_native=true` during bootstrapping.
2025-09-11 11:41:16 +00:00
David Thrane Christiansen
61c46fd5f8 fix: mark doc parser tests as eol=lf (#10344)
This PR sets the eol Git attribute on docstring parser tests. This is to
stop them from failing on Windows due to line ending translation.
2025-09-11 11:19:01 +00: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
2028 changed files with 33766 additions and 10968 deletions

6
.gitattributes vendored
View File

@@ -4,3 +4,9 @@ RELEASES.md merge=union
stage0/** binary linguist-generated
# The following file is often manually edited, so do show it in diffs
stage0/src/stdlib_flags.h -binary -linguist-generated
# These files should not have line endings translated on Windows, because
# it throws off parser tests. Later lines override earlier ones, so the
# runner code is still treated as ordinary text.
tests/lean/docparse/* eol=lf
tests/lean/docparse/*.lean eol=auto
tests/lean/docparse/*.sh eol=auto

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

@@ -21,11 +21,13 @@ jobs:
runs-on: nscloud-ubuntu-22.04-amd64-8x16
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_COMPRESS: true
CCACHE_MAXSIZE: 400M
steps:
# 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"
@@ -72,10 +74,14 @@ jobs:
restore-keys: |
Linux Lake-build-v3
- if: env.should_update_stage0 == 'yes'
run: cmake --preset release
# sync options with `Linux Lake` to ensure cache reuse
run: |
mkdir -p build
cmake --preset release -B build -DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true
shell: 'nix develop -c bash -euxo pipefail {0}'
- if: env.should_update_stage0 == 'yes'
run: make -j$NPROC -C build/release update-stage0-commit
run: |
make -j$NPROC -C build update-stage0-commit
shell: 'nix develop -c bash -euxo pipefail {0}'
- if: env.should_update_stage0 == 'yes'
run: git show --stat

View File

@@ -2,19 +2,19 @@ This is the repository for **Lean 4**.
# About
- [Quickstart](https://lean-lang.org/documentation/setup/)
- [Quickstart](https://lean-lang.org/install/)
- [Homepage](https://lean-lang.org)
- [Theorem Proving Tutorial](https://lean-lang.org/theorem_proving_in_lean4/)
- [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/)
- [Documentation Overview](https://lean-lang.org/documentation/)
- [Documentation Overview](https://lean-lang.org/learn/)
- [Language Reference](https://lean-lang.org/doc/reference/latest/)
- [Release notes](RELEASES.md) starting at v4.0.0-m3
- [Examples](https://lean-lang.org/lean4/doc/examples.html)
- [Examples](https://lean-lang.org/examples/)
- [External Contribution Guidelines](CONTRIBUTING.md)
# Installation
See [Setting Up Lean](https://lean-lang.org/documentation/setup/).
See [Install Lean](https://lean-lang.org/install/).
# Contributing

View File

@@ -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

@@ -37,6 +37,15 @@
"isDefault": true
}
},
{
"label": "build-old",
"type": "shell",
"command": "make -C build/release -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) LAKE_EXTRA_ARGS=--old",
"problemMatcher": [],
"group": {
"kind": "build"
}
},
{
"label": "test",
"type": "shell",

View File

@@ -5,6 +5,7 @@ Merge a tag into a branch on a GitHub repository.
This script checks if a specified tag can be merged cleanly into a branch and performs
the merge if possible. If the merge cannot be done cleanly, it prints a helpful message.
Merge conflicts in the lean-toolchain file are automatically resolved by accepting the incoming changes.
Usage:
python3 merge_remote.py <org/repo> <branch> <tag>
@@ -58,6 +59,32 @@ def clone_repo(repo, temp_dir):
return True
def get_conflicted_files():
"""Get list of files with merge conflicts."""
result = run_command("git diff --name-only --diff-filter=U", check=False)
if result.returncode == 0:
return result.stdout.strip().split('\n') if result.stdout.strip() else []
return []
def resolve_lean_toolchain_conflict(tag):
"""Resolve lean-toolchain conflict by accepting incoming (tag) changes."""
print("Resolving lean-toolchain conflict by accepting incoming changes...")
# Accept theirs (incoming) version for lean-toolchain
result = run_command(f"git checkout --theirs lean-toolchain", check=False)
if result.returncode != 0:
print("Failed to resolve lean-toolchain conflict")
return False
# Add the resolved file
add_result = run_command("git add lean-toolchain", check=False)
if add_result.returncode != 0:
print("Failed to stage resolved lean-toolchain")
return False
return True
def check_and_merge(repo, branch, tag, temp_dir):
"""Check if tag can be merged into branch and perform the merge if possible."""
# Change to the temporary directory
@@ -98,12 +125,37 @@ def check_and_merge(repo, branch, tag, temp_dir):
# Try merging the tag directly
print(f"Merging {tag} into {branch}...")
merge_result = run_command(f"git merge {tag} --no-edit", check=False)
if merge_result.returncode != 0:
print(f"Cannot merge {tag} cleanly into {branch}.")
print("Merge conflicts would occur. Aborting merge.")
run_command("git merge --abort")
return False
# Check which files have conflicts
conflicted_files = get_conflicted_files()
if conflicted_files == ['lean-toolchain']:
# Only lean-toolchain has conflicts, resolve it
print("Merge conflict detected only in lean-toolchain.")
if resolve_lean_toolchain_conflict(tag):
# Continue the merge with the resolved conflict
print("Continuing merge with resolved lean-toolchain...")
continue_result = run_command(f"git commit --no-edit", check=False)
if continue_result.returncode != 0:
print("Failed to complete merge after resolving lean-toolchain")
run_command("git merge --abort")
return False
else:
print("Failed to resolve lean-toolchain conflict")
run_command("git merge --abort")
return False
else:
# Other files have conflicts, or unable to determine
if conflicted_files:
print(f"Cannot merge {tag} cleanly into {branch}.")
print(f"Merge conflicts in: {', '.join(conflicted_files)}")
else:
print(f"Cannot merge {tag} cleanly into {branch}.")
print("Merge conflicts would occur.")
print("Aborting merge.")
run_command("git merge --abort")
return False
print(f"Pushing changes to remote...")
push_result = run_command(f"git push origin {branch}")

View File

@@ -52,6 +52,7 @@ def sort_sections_order():
return [
"Language",
"Library",
"Tactics",
"Compiler",
"Pretty Printing",
"Documentation",

View File

@@ -1,4 +1,11 @@
repositories:
- name: lean4-cli
url: https://github.com/leanprover/lean4-cli
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: batteries
url: https://github.com/leanprover-community/batteries
toolchain-tag: true
@@ -7,6 +14,13 @@ repositories:
bump-branch: true
dependencies: []
- name: verso
url: https://github.com/leanprover/verso
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: lean4checker
url: https://github.com/leanprover/lean4checker
toolchain-tag: true
@@ -21,20 +35,6 @@ repositories:
branch: master
dependencies: []
- name: lean4-cli
url: https://github.com/leanprover/lean4-cli
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: verso
url: https://github.com/leanprover/verso
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: plausible
url: https://github.com/leanprover-community/plausible
toolchain-tag: true
@@ -96,6 +96,15 @@ repositories:
- import-graph
- plausible
- name: cslib
url: https://github.com/leanprover/cslib
toolchain-tag: true
stable-branch: true
branch: main
bump-branch: true
dependencies:
- mathlib4
- name: repl
url: https://github.com/leanprover-community/repl
toolchain-tag: true
@@ -103,3 +112,11 @@ repositories:
branch: master
dependencies:
- mathlib4
- name: lean-fro.org
url: https://github.com/leanprover/lean-fro.org
toolchain-tag: false
stable-branch: false
branch: master
dependencies:
- verso

View File

@@ -377,6 +377,33 @@ def execute_release_steps(repo, version, config):
except subprocess.CalledProcessError as e:
print(red("Tests failed, but continuing with PR creation..."))
print(red(f"Test error: {e}"))
elif repo_name == "lean-fro.org":
# Update lean-toolchain in examples/hero
print(blue("Updating examples/hero/lean-toolchain..."))
docs_toolchain = repo_path / "examples" / "hero" / "lean-toolchain"
with open(docs_toolchain, "w") as f:
f.write(f"leanprover/lean4:{version}\n")
print(green(f"Updated examples/hero/lean-toolchain to leanprover/lean4:{version}"))
print(blue("Running `lake update`..."))
run_command("lake update", cwd=repo_path, stream_output=True)
print(blue("Running `lake update` in examples/hero..."))
run_command("lake update", cwd=repo_path / "examples" / "hero", stream_output=True)
elif repo_name == "cslib":
print(blue("Updating lakefile.toml..."))
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
print(blue("Updating docs/lakefile.toml..."))
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path / "docs")
# Update lean-toolchain in docs
print(blue("Updating docs/lean-toolchain..."))
docs_toolchain = repo_path / "docs" / "lean-toolchain"
with open(docs_toolchain, "w") as f:
f.write(f"leanprover/lean4:{version}\n")
print(green(f"Updated docs/lean-toolchain to leanprover/lean4:{version}"))
run_command("lake update", cwd=repo_path, stream_output=True)
elif dependencies:
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
run_command("lake update", cwd=repo_path, stream_output=True)

View File

@@ -10,7 +10,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 24)
set(LEAN_VERSION_MINOR 25)
set(LEAN_VERSION_PATCH 0)
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")

View File

@@ -42,5 +42,8 @@ public import Init.While
public import Init.Syntax
public import Init.Internal
public import Init.Try
public meta import Init.Try -- make sure `Try.Config` can be evaluated anywhere
public import Init.BinderNameHint
public import Init.Task
public import Init.MethodSpecsSimp
public import Init.LawfulBEqTactics

View File

@@ -147,7 +147,7 @@ class LawfulMonad (m : Type u → Type v) [Monad m] : Prop extends LawfulApplica
export LawfulMonad (bind_pure_comp bind_map pure_bind bind_assoc)
attribute [simp] pure_bind bind_assoc bind_pure_comp
attribute [grind] pure_bind
attribute [grind <=] pure_bind
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
change x >>= (fun a => pure (id a)) = x

View File

@@ -1580,6 +1580,7 @@ instance {p q : Prop} [d : Decidable (p ↔ q)] : Decidable (p = q) :=
gen_injective_theorems% Array
gen_injective_theorems% BitVec
gen_injective_theorems% ByteArray
gen_injective_theorems% Char
gen_injective_theorems% DoResultBC
gen_injective_theorems% DoResultPR
@@ -2546,7 +2547,3 @@ class Irrefl (r : αα → Prop) : Prop where
irrefl : a, ¬r a a
end Std
/-- Deprecated alias for `XorOp`. -/
@[deprecated XorOp (since := "2025-07-30")]
abbrev Xor := XorOp

View File

@@ -121,7 +121,7 @@ theorem pmap_eq_map {p : α → Prop} {f : α → β} {xs : Array α} (H) :
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (xs : Array α) {H₁ H₂}
(h : a xs, (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
cases xs
simp only [mem_toArray] at h
simp only [List.mem_toArray] at h
simp only [List.pmap_toArray, mk.injEq]
rw [List.pmap_congr_left _ h]
@@ -176,9 +176,6 @@ theorem attach_map_val (xs : Array α) (f : α → β) :
cases xs
simp
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
theorem attach_map_subtype_val (xs : Array α) : xs.attach.map Subtype.val = xs := by
cases xs; simp
@@ -187,21 +184,18 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {xs : Array α} (H
((xs.attachWith p H).map fun (i : { i // p i}) => f i) = xs.map f := by
cases xs; simp
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
theorem attachWith_map_subtype_val {p : α Prop} {xs : Array α} (H : a xs, p a) :
(xs.attachWith p H).map Subtype.val = xs := by
cases xs; simp
@[simp, grind]
@[simp, grind ]
theorem mem_attach (xs : Array α) : x, x xs.attach
| a, h => by
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
rcases this with _, _, m, rfl
exact m
@[simp, 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 +206,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
@@ -345,7 +340,7 @@ theorem foldl_attach {xs : Array α} {f : β → α → β} {b : β} :
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.foldl_toArray', mem_toArray, List.foldl_subtype]
List.foldl_toArray', List.mem_toArray, List.foldl_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
@@ -364,7 +359,7 @@ theorem foldr_attach {xs : Array α} {f : α → β → β} {b : β} :
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.foldr_toArray', mem_toArray, List.foldr_subtype]
List.foldr_toArray', List.mem_toArray, List.foldr_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
@@ -400,9 +395,6 @@ theorem map_attach_eq_pmap {xs : Array α} {f : { x // x ∈ xs } → β} :
cases xs
ext <;> simp
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
abbrev map_attach := @map_attach_eq_pmap
@[grind =]
theorem attach_filterMap {xs : Array α} {f : α Option β} :
(xs.filterMap f).attach = xs.attach.filterMap
@@ -706,7 +698,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

@@ -40,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 α}
@@ -108,13 +108,19 @@ instance : Membership α (Array α) where
theorem mem_def {a : α} {as : Array α} : a as a as.toList :=
fun | .mk h => h, Array.Mem.mk
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
@[simp, grind =] theorem _root_.List.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
@[deprecated List.mem_toArray (since := "2025-09-04")]
theorem mem_toArray {a : α} {l : List α} : a l.toArray a l :=
List.mem_toArray
@[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
@@ -123,19 +129,10 @@ end Array
namespace List
@[deprecated Array.toArray_toList (since := "2025-02-17")]
abbrev toArray_toList := @Array.toArray_toList
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
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]
@[deprecated size_toArray (since := "2025-02-17")]
abbrev _root_.Array.size_toArray := @List.size_toArray
@[simp, grind =] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
@[simp, grind =] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := rfl
@@ -197,7 +194,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]
@@ -406,10 +403,6 @@ that requires a proof the array is non-empty.
def back? (xs : Array α) : Option α :=
xs[xs.size - 1]?
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), expose]
def get? (xs : Array α) (i : Nat) : Option α :=
if h : i < xs.size then some xs[i] else none
/--
Swaps a new element with the element at the given index.
@@ -1806,7 +1799,6 @@ Examples:
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 3 = #["apple", "pear", "orange"]`
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 5 = #["apple", "pear", "orange"]`
-/
@[grind]
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
if h : i < xs.size then xs.eraseIdx i h else xs

View File

@@ -24,29 +24,6 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
namespace Array
/--
Use the indexing notation `a[i]` instead.
Access an element from an array without needing a runtime bounds checks,
using a `Nat` index and a proof that it is in bounds.
This function does not use `get_elem_tactic` to automatically find the proof that
the index is in bounds. This is because the tactic itself needs to look up values in
arrays.
-/
@[deprecated "Use indexing notation `as[i]` instead" (since := "2025-02-17")]
def get {α : Type u} (xs : @& Array α) (i : @& Nat) (h : LT.lt i xs.size) : α :=
xs.toList.get i, h
/--
Use the indexing notation `a[i]!` instead.
Access an element from an array, or panic if the index is out of bounds.
-/
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17"), expose]
def get! {α : Type u} [Inhabited α] (xs : @& Array α) (i : @& Nat) : α :=
Array.getD xs i default
theorem foldlM_toList.aux [Monad m]
{f : β α m β} {xs : Array α} {i j} (H : xs.size i + j) {b} :
foldlM.loop f xs xs.size (Nat.le_refl _) i j b = (xs.toList.drop j).foldlM f b := by
@@ -108,9 +85,6 @@ abbrev push_toList := @toList_push
@[simp, grind =] theorem toList_pop {xs : Array α} : xs.pop.toList = xs.toList.dropLast := rfl
@[deprecated toList_pop (since := "2025-02-17")]
abbrev pop_toList := @Array.toList_pop
@[simp] theorem append_eq_append {xs ys : Array α} : xs.append ys = xs ++ ys := rfl
@[simp, grind =] theorem toList_append {xs ys : 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)
@@ -271,7 +271,7 @@ theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
(xs ++ ys).erase a = if a xs then xs.erase a ++ ys else xs ++ ys.erase a := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
simp only [List.append_toArray, List.erase_toArray, List.erase_append, List.mem_toArray]
split <;> simp
@[grind =]
@@ -324,6 +324,13 @@ abbrev erase_mkArray_ne := @erase_replicate_ne
end erase
/-! ### eraseIdxIfInBounds -/
@[grind =]
theorem eraseIdxIfInBounds_eq {xs : Array α} {i : Nat} :
xs.eraseIdxIfInBounds i = if h : i < xs.size then xs.eraseIdx i else xs := by
simp [eraseIdxIfInBounds]
/-! ### eraseIdx -/
theorem eraseIdx_eq_eraseIdxIfInBounds {xs : Array α} {i : Nat} (h : i < xs.size) :

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
@@ -277,9 +278,6 @@ theorem find?_flatten_eq_none_iff {xss : Array (Array α)} {p : α → Bool} :
xss.flatten.find? p = none ys xss, x ys, !p x := by
simp
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
/--
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
@@ -305,9 +303,6 @@ theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α → Bool} {a
zs.toList, bs.toList.map Array.toList, by simpa using h,
by simpa using h₁, by simpa using h₂
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
@[simp, grind =] theorem find?_flatMap {xs : Array α} {f : α Array β} {p : β Bool} :
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
cases xs
@@ -317,17 +312,11 @@ theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α → Array β} {p : β
(xs.flatMap f).find? p = none x xs, y f x, !p y := by
simp
@[deprecated find?_flatMap_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
@[grind =]
theorem find?_replicate :
find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
simp [ List.toArray_replicate, List.find?_replicate]
@[deprecated find?_replicate (since := "2025-03-18")]
abbrev find?_mkArray := @find?_replicate
@[simp] theorem find?_replicate_of_size_pos (h : 0 < n) :
find? p (replicate n a) = if p a then some a else none := by
simp [find?_replicate, Nat.ne_of_gt h]
@@ -345,34 +334,19 @@ abbrev find?_mkArray_of_pos := @find?_replicate_of_pos
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
simp [find?_replicate, h]
@[deprecated find?_replicate_of_neg (since := "2025-03-18")]
abbrev find?_mkArray_of_neg := @find?_replicate_of_neg
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α Bool} :
(replicate n a).find? p = none n = 0 !p a := by
simp [ List.toArray_replicate, Classical.or_iff_not_imp_left]
@[deprecated find?_replicate_eq_none_iff (since := "2025-03-18")]
abbrev find?_mkArray_eq_none_iff := @find?_replicate_eq_none_iff
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α Bool} :
(replicate n a).find? p = some b n 0 p a a = b := by
simp [ List.toArray_replicate]
@[deprecated find?_replicate_eq_some_iff (since := "2025-03-18")]
abbrev find?_mkArray_eq_some_iff := @find?_replicate_eq_some_iff
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
abbrev find?_mkArray_eq_some := @find?_replicate_eq_some_iff
@[simp] theorem get_find?_replicate {n : Nat} {a : α} {p : α Bool} (h) :
((replicate n a).find? p).get h = a := by
simp [ List.toArray_replicate]
@[deprecated get_find?_replicate (since := "2025-03-18")]
abbrev get_find?_mkArray := @get_find?_replicate
@[grind =]
theorem find?_pmap {P : α Prop} {f : (a : α) P a β} {xs : Array α}
(H : (a : α), a xs P a) {p : β Bool} :
@@ -395,7 +369,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)

File diff suppressed because it is too large Load Diff

View File

@@ -9,8 +9,8 @@ prelude
public import Init.Core
import Init.Data.Array.Basic
import Init.Data.Nat.Lemmas
import Init.Data.Range.Polymorphic.Iterators
import Init.Data.Range.Polymorphic.Nat
public import Init.Data.Range.Polymorphic.Iterators
public import Init.Data.Range.Polymorphic.Nat
import Init.Data.Iterators.Consumers
public section

View File

@@ -167,7 +167,7 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
forIn' as b f = forIn' bs b' g := by
cases as <;> cases bs
simp only [mk.injEq, mem_toArray, List.forIn'_toArray] at w h
simp only [mk.injEq, List.mem_toArray, List.forIn'_toArray] at w h
exact List.forIn'_congr w hb h
/--

View File

@@ -116,7 +116,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat Bool} :
(range' s n).find? p = some i p i i range' s n j, s j j < i !p j := by
rw [ List.toArray_range']
simp only [List.find?_toArray, mem_toArray]
simp only [List.find?_toArray, List.mem_toArray]
simp [List.find?_range'_eq_some]
@[simp] theorem find?_range'_eq_none {s n : Nat} {p : Nat Bool} :

View File

@@ -7,6 +7,7 @@ module
prelude
public import Init.GetElem
public import Init.Data.Array.Basic
import Init.Data.Array.GetLit
public import Init.Data.Slice.Basic

View File

@@ -29,10 +29,6 @@ set_option linter.missingDocs true
namespace BitVec
@[inline, deprecated BitVec.ofNatLT (since := "2025-02-13"), inherit_doc BitVec.ofNatLT]
protected def ofNatLt {n : Nat} (i : Nat) (p : i < 2 ^ n) : BitVec n :=
BitVec.ofNatLT i p
section Nat
/--
@@ -874,4 +870,7 @@ def clzAuxRec {w : Nat} (x : BitVec w) (n : Nat) : BitVec w :=
/-- Count the number of leading zeros. -/
def clz (x : BitVec w) : BitVec w := clzAuxRec x (w - 1)
/-- Count the number of trailing zeros. -/
def ctz (x : BitVec w) : BitVec w := (x.reverse).clz
end BitVec

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
@@ -74,10 +74,6 @@ theorem some_eq_getElem?_iff {l : BitVec w} : some a = l[n]? ↔ ∃ h : n < w,
theorem getElem_of_getElem? {l : BitVec w} : l[n]? = some a h : n < w, l[n] = a :=
getElem?_eq_some_iff.mp
set_option linter.missingDocs false in
@[deprecated getElem?_eq_some_iff (since := "2025-02-17")]
abbrev getElem?_eq_some := @getElem?_eq_some_iff
theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none w n := by
simp
@@ -350,25 +346,14 @@ theorem ofBool_eq_iff_eq : ∀ {b b' : Bool}, BitVec.ofBool b = BitVec.ofBool b'
@[simp] theorem ofBool_xor_ofBool : ofBool b ^^^ ofBool b' = ofBool (b ^^ b') := by
cases b <;> cases b' <;> rfl
@[deprecated toNat_ofNatLT (since := "2025-02-13")]
theorem toNat_ofNatLt (x : Nat) (p : x < 2^w) : (x#'p).toNat = x := rfl
@[simp, grind =] theorem getLsbD_ofNatLT {n : Nat} (x : Nat) (lt : x < 2^n) (i : Nat) :
getLsbD (x#'lt) i = x.testBit i := by
simp [getLsbD, BitVec.ofNatLT]
@[deprecated getLsbD_ofNatLT (since := "2025-02-13")]
theorem getLsbD_ofNatLt {n : Nat} (x : Nat) (lt : x < 2^n) (i : Nat) :
getLsbD (x#'lt) i = x.testBit i := getLsbD_ofNatLT x lt i
@[simp, grind =] theorem getMsbD_ofNatLT {n x i : Nat} (h : x < 2^n) :
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := by
simp [getMsbD, getLsbD]
@[deprecated getMsbD_ofNatLT (since := "2025-02-13")]
theorem getMsbD_ofNatLt {n x i : Nat} (h : x < 2^n) :
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := getMsbD_ofNatLT h
@[grind =]
theorem ofNatLT_eq_ofNat {w : Nat} {n : Nat} (hn) : BitVec.ofNatLT n hn = BitVec.ofNat w n :=
eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt hn])
@@ -1100,6 +1085,10 @@ theorem toInt_setWidth' {m n : Nat} (p : m ≤ n) {x : BitVec m} :
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.coe_castLE, val_toFin,
Nat.mod_eq_of_lt (by apply BitVec.toNat_lt_twoPow_of_le p)]
theorem toNat_setWidth_of_le {w w' : Nat} {b : BitVec w} (h : w w') : (b.setWidth w').toNat = b.toNat := by
rw [BitVec.toNat_setWidth, Nat.mod_eq_of_lt]
exact BitVec.toNat_lt_twoPow_of_le h
/-! ## extractLsb -/
@[simp, grind =]
@@ -1287,6 +1276,17 @@ theorem extractLsb'_eq_zero {x : BitVec w} {start : Nat} :
ext i hi
omega
theorem extractLsb'_setWidth_of_le {b : BitVec w} {start len w' : Nat} (h : start + len w') :
(b.setWidth w').extractLsb' start len = b.extractLsb' start len := by
ext i h_i
simp
omega
theorem setWidth_extractLsb'_of_le {c : BitVec w} (h : len₁ len₂) :
(c.extractLsb' start len₂).setWidth len₁ = c.extractLsb' start len₁ := by
ext i hi
simp [show i < len₂ by omega]
/-! ### allOnes -/
@[simp, grind =] theorem toNat_allOnes : (allOnes v).toNat = 2^v - 1 := by
@@ -1530,6 +1530,12 @@ theorem extractLsb_and {x : BitVec w} {hi lo : Nat} :
@[simp, grind =] theorem ofNat_and {x y : Nat} : BitVec.ofNat w (x &&& y) = BitVec.ofNat w x &&& BitVec.ofNat w y :=
eq_of_toNat_eq (by simp [Nat.and_mod_two_pow])
theorem and_or_distrib_left {x y z : BitVec w} : x &&& (y ||| z) = (x &&& y) ||| (x &&& z) :=
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_left])
theorem and_or_distrib_right {x y z : BitVec w} : (x ||| y) &&& z = (x &&& z) ||| (y &&& z) :=
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_right])
/-! ### xor -/
@[simp, grind =] theorem toNat_xor (x y : BitVec v) :
@@ -2180,6 +2186,10 @@ theorem msb_ushiftRight {x : BitVec w} {n : Nat} :
have := lt_of_getLsbD ha
omega
theorem setWidth_ushiftRight_eq_extractLsb {b : BitVec w} : (b >>> w').setWidth w'' = b.extractLsb' w' w'' := by
ext i hi
simp
/-! ### ushiftRight reductions from BitVec to Nat -/
@[simp, grind =]
@@ -2970,10 +2980,9 @@ theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
/-- Combine adjacent `extractLsb'` operations into a single `extractLsb'`. -/
theorem extractLsb'_append_extractLsb'_eq_extractLsb' {x : BitVec w} (h : start₂ = start₁ + len₁) :
((x.extractLsb' start₂ len₂) ++ (x.extractLsb' start₁ len₁)) =
(x.extractLsb' start₁ (len + len)).cast (by omega) := by
x.extractLsb' start₁ (len + len) := by
ext i h
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, getElem_cast, ite_eq_left_iff,
Nat.not_lt]
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, ite_eq_left_iff, Nat.not_lt]
intro hi
congr 1
omega
@@ -3085,6 +3094,51 @@ theorem extractLsb'_append_eq_of_le {v w} {xhi : BitVec v} {xlo : BitVec w}
extractLsb' start len (xhi ++ xlo) = extractLsb' (start - w) len xhi := by
simp [extractLsb'_append_eq_ite, show ¬ start < w by omega]
theorem extractLsb'_append_eq_left {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' w' w = a := by
simp [BitVec.extractLsb'_append_eq_of_le]
theorem extractLsb'_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' 0 w' = b := by
simp [BitVec.extractLsb'_append_eq_of_add_le]
theorem setWidth_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).setWidth w' = b := by
ext i hi
simp [getLsbD_append, hi]
theorem append_left_inj {s₁ s₂ : BitVec w} (t : BitVec w') : s₁ ++ t = s₂ ++ t s₁ = s₂ := by
refine fun h => ?_, fun h => h rfl
ext i hi
simpa [getElem_append, dif_neg] using congrArg (·[i + w']'(by omega)) h
theorem append_right_inj (s : BitVec w) {t₁ t₂ : BitVec w'} : s ++ t₁ = s ++ t₂ t₁ = t₂ := by
refine fun h => ?_, fun h => h rfl
ext i hi
simpa [getElem_append, hi] using congrArg (·[i]) h
theorem setWidth_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} :
(b ++ b').setWidth w'' = (b.setWidth w'' <<< w') ||| b'.setWidth w'' := by
ext i hi
simp only [getElem_setWidth, getElem_or, getElem_shiftLeft]
rw [getLsbD_append]
split <;> simp_all
theorem setWidth_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} :
(b ++ b' ++ b'').setWidth w''' = (b.setWidth w''' <<< (w' + w'')) ||| (b'.setWidth w''' <<< w'') ||| b''.setWidth w''' := by
rw [BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
theorem setWidth_append_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} {b''' : BitVec w'''} :
(b ++ b' ++ b'' ++ b''').setWidth w'''' = (b.setWidth w'''' <<< (w' + w'' + w''')) ||| (b'.setWidth w'''' <<< (w'' + w''')) |||
(b''.setWidth w'''' <<< w''') ||| b'''.setWidth w'''' := by
simp only [BitVec.setWidth_append_eq_shiftLeft_setWidth_or, BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
theorem and_setWidth_allOnes (w' w : Nat) (b : BitVec (w' + w)) :
b &&& (BitVec.allOnes w).setWidth (w' + w) = 0#w' ++ b.setWidth w := by
ext i hi
simp only [getElem_and, getElem_setWidth, getLsbD_allOnes]
rw [BitVec.getElem_append]
split <;> simp_all
/-! ### rev -/
@[grind =]
@@ -4041,6 +4095,9 @@ instance instLawfulOrderLT : LawfulOrderLT (BitVec n) := by
apply LawfulOrderLT.of_le
simpa using fun _ _ => BitVec.lt_asymm
theorem length_pos_of_lt {b b' : BitVec w} (h : b < b') : 0 < w :=
length_pos_of_ne (BitVec.ne_of_lt h)
protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y x % y < y := by
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
apply Nat.mod_lt
@@ -4112,6 +4169,14 @@ theorem lt_of_msb_false_of_msb_true {x y : BitVec w} (hx : x.msb = false) (hy :
simp
omega
theorem lt_add_one {b : BitVec w} (h : b allOnes w) : b < b + 1 := by
simp only [ne_eq, toNat_inj, toNat_allOnes] at h
simp only [BitVec.lt_def, ofNat_eq_ofNat, toNat_add, toNat_ofNat, Nat.add_mod_mod]
rw [Nat.mod_eq_of_lt]
· exact Nat.lt_add_one _
· have := b.toNat_lt_twoPow_of_le (Nat.le_refl _)
omega
/-! ### udiv -/
theorem udiv_def {x y : BitVec n} : x / y = BitVec.ofNat n (x.toNat / y.toNat) := by
@@ -5257,7 +5322,7 @@ theorem replicate_succ' {x : BitVec w} :
(replicate n x ++ x).cast (by rw [Nat.mul_succ]) := by
simp [replicate_append_self]
theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
theorem setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
apply BitVec.eq_of_toNat_eq
rw [toNat_setWidth]
simp only [toNat_setWidth, toNat_add, toNat_umod, Nat.add_mod_mod, Nat.mod_add_mod, toNat_twoPow]
@@ -5266,6 +5331,14 @@ theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y)
· have hk : 2 ^ w < 2 ^ i := Nat.pow_lt_pow_of_lt (by decide) (Nat.lt_of_not_le h)
rw [Nat.mod_eq_of_lt hk, Nat.mod_mod_eq_mod_mod_of_dvd (Nat.pow_dvd_pow _ (Nat.le_of_not_le h))]
theorem setWidth_setWidth_eq_self {a : BitVec w} {w' : Nat} (h : a < BitVec.twoPow w w') : (a.setWidth w').setWidth w = a := by
by_cases hw : w' < w
· simp only [toNat_eq, toNat_setWidth]
rw [Nat.mod_mod_of_dvd' (Nat.pow_dvd_pow _ (Nat.le_of_lt hw)), Nat.mod_eq_of_lt]
rwa [BitVec.lt_def, BitVec.toNat_twoPow_of_lt hw] at h
· rw [BitVec.lt_def, BitVec.toNat_twoPow_of_le (by omega)] at h
simp at h
/-! ### intMin -/
@[grind =]
@@ -5779,6 +5852,25 @@ theorem msb_replicate {n w : Nat} {x : BitVec w} :
simp only [BitVec.msb, getMsbD_replicate, Nat.zero_mod]
cases n <;> cases w <;> simp
@[simp]
theorem reverse_eq_zero_iff {x : BitVec w} :
x.reverse = 0#w x = 0#w := by
constructor
· intro hrev
ext i hi
rw [ getLsbD_eq_getElem, getLsbD_eq_getMsbD, getLsbD_reverse]
simp [hrev]
· intro hzero
ext i hi
rw [ getLsbD_eq_getElem, getLsbD_eq_getMsbD, getMsbD_reverse]
simp [hi, hzero]
@[simp]
theorem reverse_reverse_eq {x : BitVec w} :
x.reverse.reverse = x := by
ext k hk
rw [getElem_reverse, getMsbD_reverse, getLsbD_eq_getElem]
/-! ### Inequalities (le / lt) -/
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
@@ -5909,6 +6001,12 @@ theorem getElem_eq_true_of_lt_of_le {x : BitVec w} (hk' : k < w) (hlt: x.toNat <
omega
· simp [show w k + k' by omega] at hk'
theorem not_lt_iff {b : BitVec w} : ~~~b < b 0 < w b.msb = true := by
refine fun h => ?_, fun hw, hb => ?_
· have := length_pos_of_lt h
exact this, by rwa [ ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)] at h
· rwa [ ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)]
/-! ### Count leading zeros -/
theorem clzAuxRec_zero (x : BitVec w) :
@@ -6182,16 +6280,70 @@ theorem toNat_lt_two_pow_sub_clz {x : BitVec w} :
· simp [show w + 1 i by omega]
· simp; omega
theorem clz_eq_reverse_ctz {x : BitVec w} :
x.clz = (x.reverse).ctz := by
simp [ctz]
/-! ### Deprecations -/
/-! ### Count trailing zeros -/
set_option linter.missingDocs false
@[deprecated toFin_uShiftRight (since := "2025-02-18")]
abbrev toFin_uShiftRight := @toFin_ushiftRight
theorem ctz_eq_reverse_clz {x : BitVec w} :
x.ctz = (x.reverse).clz := by
simp [ctz]
/-- The number of trailing zeroes is strictly less than the bitwidth iff the bitvector is nonzero. -/
@[simp]
theorem ctz_lt_iff_ne_zero {x : BitVec w} :
ctz x < w x 0#w := by
simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq]
rw [show BitVec.ofNat w w = w by simp, reverse_eq_zero_iff (x := x)]
apply clz_lt_iff_ne_zero (x := x.reverse)
/-- If a bitvec is different than zero the bits at indexes lower than `ctz x` are false. -/
theorem getLsbD_false_of_lt_ctz {x : BitVec w} (hi : i < x.ctz.toNat) :
x.getLsbD i = false := by
rw [getLsbD_eq_getMsbD, getLsbD_reverse]
have hiff := ctz_lt_iff_ne_zero (x := x)
by_cases hzero : x = 0#w
· simp [hzero, getLsbD_reverse]
· simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq, hzero, not_false_eq_true,
iff_true] at hiff
simp only [ctz] at hi
have hi' : i < w := by simp [BitVec.lt_def] at hiff; omega
simp only [hi', decide_true, Bool.true_and]
have : (x.reverse.clzAuxRec (w - 1)).toNat w := by
rw [show ((x.reverse.clzAuxRec (w - 1)).toNat w) =
((x.reverse.clzAuxRec (w - 1)).toNat (BitVec.ofNat w w).toNat) by simp, le_def]
apply clzAuxRec_le (x := x.reverse) (n := w - 1)
let j := (x.reverse.clzAuxRec (w - 1)).toNat - 1 - i
rw [show w - 1 - i = w - (x.reverse.clzAuxRec (w - 1)).toNat + j by
subst j
rw [Nat.sub_sub (n := (x.reverse.clzAuxRec (w - 1)).toNat),
Nat.add_sub_assoc (by exact Nat.one_add_le_iff.mpr hi)]
omega]
have hfalse : (i : Nat), w - 1 < i x.reverse.getLsbD i = false := by
intros i hj
simp [show w i by omega]
exact getLsbD_false_of_clzAuxRec (x := x.reverse) (n := w - 1) hfalse (j := j)
/-- If a bitvec is different than zero, the bit at index `ctz x`, i.e., the first bit after the
trailing zeros, is true. -/
theorem getLsbD_true_ctz_of_ne_zero {x : BitVec w} (hx : x 0#w) :
x.getLsbD (ctz x).toNat = true := by
simp only [ctz_eq_reverse_clz, clz]
rw [getLsbD_eq_getMsbD, getLsbD_reverse]
have := ctz_lt_iff_ne_zero (x := x)
simp only [ctz_eq_reverse_clz, clz, natCast_eq_ofNat, lt_def, toNat_ofNat, Nat.mod_two_pow_self,
ne_eq] at this
simp only [this, hx, not_false_eq_true, decide_true, Bool.true_and]
have hnotrev : ¬x.reverse = 0#w := by simp [reverse_eq_zero_iff, hx]
apply getLsbD_true_of_eq_clzAuxRec_of_ne_zero (x := x.reverse) (n := w - 1) hnotrev
intro i hi
simp [show w i by omega]
/-- A nonzero bitvector is lower-bounded by its trailing zeroes. -/
theorem two_pow_ctz_le_toNat_of_ne_zero {x : BitVec w} (hx : x 0#w) :
2 ^ (ctz x).toNat x.toNat := by
have hclz := getLsbD_true_ctz_of_ne_zero (x := x) hx
exact Nat.ge_two_pow_of_testBit hclz
end BitVec

View File

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

View File

@@ -11,16 +11,11 @@ public import Init.Data.UInt.Basic
public import Init.Data.UInt.BasicAux
import all Init.Data.UInt.BasicAux
public import Init.Data.Option.Basic
public import Init.Data.Array.Extract
@[expose] public section
universe u
structure ByteArray where
data : Array UInt8
attribute [extern "lean_byte_array_mk"] ByteArray.mk
attribute [extern "lean_byte_array_data"] ByteArray.data
namespace ByteArray
deriving instance BEq for ByteArray
@@ -30,29 +25,15 @@ attribute [ext] ByteArray
instance : DecidableEq ByteArray :=
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
@[extern "lean_mk_empty_byte_array"]
def emptyWithCapacity (c : @& Nat) : ByteArray :=
{ data := #[] }
@[deprecated emptyWithCapacity (since := "2025-03-12")]
abbrev mkEmpty := emptyWithCapacity
def empty : ByteArray := emptyWithCapacity 0
instance : Inhabited ByteArray where
default := empty
instance : EmptyCollection ByteArray where
emptyCollection := ByteArray.empty
@[extern "lean_byte_array_push"]
def push : ByteArray UInt8 ByteArray
| bs, b => bs.push b
@[extern "lean_byte_array_size"]
def size : (@& ByteArray) Nat
| bs => bs.size
@[extern "lean_sarray_size", simp]
def usize (a : @& ByteArray) : USize :=
a.size.toUSize
@@ -106,11 +87,31 @@ def copySlice (src : @& ByteArray) (srcOff : Nat) (dest : ByteArray) (destOff le
def extract (a : ByteArray) (b e : Nat) : ByteArray :=
a.copySlice b empty 0 (e - b)
protected def append (a : ByteArray) (b : ByteArray) : ByteArray :=
protected def fastAppend (a : ByteArray) (b : ByteArray) : ByteArray :=
-- we assume that `append`s may be repeated, so use asymptotic growing; use `copySlice` directly to customize
b.copySlice 0 a a.size b.size false
instance : Append ByteArray := ByteArray.append
@[simp]
theorem size_data {a : ByteArray} :
a.data.size = a.size := rfl
@[csimp]
theorem append_eq_fastAppend : @ByteArray.append = @ByteArray.fastAppend := by
funext a b
ext1
apply Array.ext'
simp [ByteArray.fastAppend, copySlice, size_data, - Array.append_assoc]
-- Needs to come after the `csimp` lemma
instance : Append ByteArray where
append := ByteArray.append
@[simp]
theorem append_eq {a b : ByteArray} : a.append b = a ++ b := rfl
@[simp]
theorem fastAppend_eq {a b : ByteArray} : a.fastAppend b = a ++ b := by
simp [ append_eq_fastAppend]
def toList (bs : ByteArray) : List UInt8 :=
let rec loop (i : Nat) (r : List UInt8) :=
@@ -350,13 +351,4 @@ def prevn : Iterator → Nat → Iterator
end Iterator
end ByteArray
/--
Converts a list of bytes into a `ByteArray`.
-/
def List.toByteArray (bs : List UInt8) : ByteArray :=
let rec loop
| [], r => r
| b::bs, r => loop bs (r.push b)
loop bs ByteArray.empty
instance : ToString ByteArray := fun bs => bs.toList.toString

View File

@@ -0,0 +1,53 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Markus Himmel
-/
module
prelude
public import Init.Prelude
public import Init.Data.List.Basic
public section
namespace ByteArray
@[simp]
theorem data_push {a : ByteArray} {b : UInt8} : (a.push b).data = a.data.push b := rfl
@[expose]
protected def append (a b : ByteArray) : ByteArray :=
a.data.toList ++ b.data.toList
@[simp]
theorem toList_data_append' {a b : ByteArray} :
(a.append b).data.toList = a.data.toList ++ b.data.toList := by
have a := a
have b := b
rfl
theorem ext : {x y : ByteArray} x.data = y.data x = y
| _, _, rfl => rfl
end ByteArray
@[simp]
theorem List.toList_data_toByteArray {l : List UInt8} :
l.toByteArray.data.toList = l := by
rw [List.toByteArray]
suffices a b, (List.toByteArray.loop a b).data.toList = b.data.toList ++ a by
simpa using this l ByteArray.empty
intro a b
fun_induction List.toByteArray.loop a b with simp_all [toList_push]
where
toList_push {xs : Array UInt8} {x : UInt8} : (xs.push x).toList = xs.toList ++ [x] := by
have xs := xs
simp [Array.push, List.concat_eq_append]
theorem List.toByteArray_append' {l l' : List UInt8} :
(l ++ l').toByteArray = l.toByteArray.append l'.toByteArray :=
ByteArray.ext (ext (by simp))
where
ext : {x y : Array UInt8} x.toList = y.toList x = y
| _, _, rfl => rfl

View File

@@ -0,0 +1,259 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Markus Himmel
-/
module
prelude
public import Init.Data.ByteArray.Basic
public import Init.Data.Array.Extract
public section
-- At present the preferred normal form for empty byte arrays is `ByteArray.empty`
@[simp]
theorem emptyc_eq_empty : ( : ByteArray) = ByteArray.empty := rfl
@[simp]
theorem emptyWithCapacity_eq_empty : ByteArray.emptyWithCapacity 0 = ByteArray.empty := rfl
@[simp]
theorem ByteArray.data_empty : ByteArray.empty.data = #[] := rfl
@[simp]
theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
(a.extract b e).data = a.data.extract b e := by
simp [extract, copySlice]
by_cases b e
· rw [(by omega : b + (e - b) = e)]
· rw [Array.extract_eq_empty_of_le (by omega), Array.extract_eq_empty_of_le (by omega)]
@[simp]
theorem ByteArray.extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
ext1
simp
@[simp]
theorem ByteArray.extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
ext1
simp [Nat.min_le_left]
theorem ByteArray.fastAppend_eq_copySlice {a b : ByteArray} :
a.fastAppend b = b.copySlice 0 a a.size b.size false := rfl
@[simp]
theorem List.toByteArray_append {l l' : List UInt8} :
(l ++ l').toByteArray = l.toByteArray ++ l'.toByteArray := by
simp [List.toByteArray_append']
@[simp]
theorem ByteArray.toList_data_append {l l' : ByteArray} :
(l ++ l').data.toList = l.data.toList ++ l'.data.toList := by
simp [ append_eq]
@[simp]
theorem ByteArray.data_append {l l' : ByteArray} :
(l ++ l').data = l.data ++ l'.data := by
simp [ Array.toList_inj]
@[simp]
theorem ByteArray.size_empty : ByteArray.empty.size = 0 := by
simp [ ByteArray.size_data]
@[simp]
theorem List.data_toByteArray {l : List UInt8} :
l.toByteArray.data = l.toArray := by
rw [List.toByteArray]
suffices a b, (List.toByteArray.loop a b).data = b.data ++ a.toArray by
simpa using this l ByteArray.empty
intro a b
fun_induction List.toByteArray.loop a b with simp_all
@[simp]
theorem List.size_toByteArray {l : List UInt8} :
l.toByteArray.size = l.length := by
simp [ ByteArray.size_data]
@[simp]
theorem List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
@[simp]
theorem ByteArray.empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
ext1
simp
@[simp]
theorem ByteArray.append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
ext1
simp
@[simp, grind =]
theorem ByteArray.size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
simp [ size_data]
@[simp]
theorem ByteArray.size_eq_zero_iff {a : ByteArray} : a.size = 0 a = ByteArray.empty := by
refine fun h => ?_, fun h => h ByteArray.size_empty
ext1
simp [ Array.size_eq_zero_iff, h]
theorem ByteArray.getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
a[i] = a.data[i]'(by simpa [ size_data]) := rfl
@[simp]
theorem ByteArray.getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
(hlt : i < a.size) : (a ++ b)[i] = a[i] := by
simp only [getElem_eq_getElem_data, data_append]
rw [Array.getElem_append_left (by simpa)]
theorem ByteArray.getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
(hle : a.size i) : (a ++ b)[i] = b[i - a.size]'(by simp_all; omega) := by
simp only [getElem_eq_getElem_data, data_append]
rw [Array.getElem_append_right (by simpa)]
simp
@[simp]
theorem List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
l.toByteArray[i]'h = l[i]'(by simp_all) := by
simp [ByteArray.getElem_eq_getElem_data]
theorem List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
l[i]'h = l.toByteArray[i]'(by simp_all) := by
simp
@[simp]
theorem ByteArray.size_extract {a : ByteArray} {b e : Nat} :
(a.extract b e).size = min e a.size - b := by
simp [ size_data]
@[simp]
theorem ByteArray.extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty min j b.size i := by
rw [ size_eq_zero_iff, size_extract]
omega
@[simp]
theorem ByteArray.extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
simp only [extract_eq_empty_iff]
exact Nat.le_trans (Nat.min_le_left _ _) (by simp)
@[simp]
theorem ByteArray.append_eq_empty_iff {a b : ByteArray} :
a ++ b = ByteArray.empty a = ByteArray.empty b = ByteArray.empty := by
simp [ size_eq_zero_iff, size_append]
@[simp]
theorem List.toByteArray_eq_empty {l : List UInt8} :
l.toByteArray = ByteArray.empty l = [] := by
simp [ ByteArray.size_eq_zero_iff]
theorem ByteArray.append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
xs ++ ys₁ = xs ++ ys₂ ys₁ = ys₂ := by
simp [ByteArray.ext_iff, Array.append_right_inj]
@[simp]
theorem ByteArray.extract_append_extract {a : ByteArray} {i j k : Nat} :
a.extract i j ++ a.extract j k = a.extract (min i j) (max j k) := by
ext1
simp
theorem ByteArray.extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
(hi : i j) (hk : j k) :
a.extract i k = a.extract i j ++ a.extract j k := by
simp
rw [Nat.min_eq_left hi, Nat.max_eq_right hk]
theorem ByteArray.append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
simp only [ByteArray.ext_iff, ByteArray.size_data, ByteArray.data_append] at *
exact Array.append_inj_left h hl
theorem ByteArray.extract_append_eq_right {a b : ByteArray} {i : Nat} (hi : i = a.size) :
(a ++ b).extract i (a ++ b).size = b := by
subst hi
ext1
simp [ size_data]
theorem ByteArray.extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
(a ++ b).extract 0 i = a := by
subst hi
ext1
simp
theorem ByteArray.extract_append_size_left {a b : ByteArray} {i : Nat} :
(a ++ b).extract i a.size = a.extract i a.size := by
ext1
simp
theorem ByteArray.extract_append_size_add {a b : ByteArray} {i j : Nat} :
(a ++ b).extract (a.size + i) (a.size + j) = b.extract i j := by
ext1
simp
theorem ByteArray.extract_append {as bs : ByteArray} {i j : Nat} :
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
ext1
simp
theorem ByteArray.extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
(a ++ b).extract (k + i) (k + j) = b.extract i j := by
cases h
rw [extract_append_size_add]
theorem ByteArray.extract_extract {a : ByteArray} {i j k l : Nat} :
(a.extract i j).extract k l = a.extract (i + k) (min (i + l) j) := by
ext1
simp
theorem ByteArray.getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
start + i < xs.size := by
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
apply Nat.sub_le_sub_right; apply Nat.min_le_right
theorem ByteArray.getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
(h) : (b.extract start stop)[i]'h = b[start + i]'(getElem_extract_aux h) := by
simp [getElem_eq_getElem_data]
theorem ByteArray.extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
a.extract i j = a.extract i' j min j a.size - i = min j a.size - i' := by
simp [ByteArray.ext_iff, Array.extract_eq_extract_left]
theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 a.size) :
a.extract i (i + 1) = [a[i]].toByteArray := by
ext
· simp
omega
· rename_i j hj hj'
obtain rfl : j = 0 := by simpa using hj'
simp [ByteArray.getElem_eq_getElem_data]
theorem ByteArray.extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 a.size) :
a.extract i (i + 2) = [a[i], a[i + 1]].toByteArray := by
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
extract_add_one (by omega), extract_add_one (by omega)]
simp [ List.toByteArray_append]
theorem ByteArray.extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 a.size) :
a.extract i (i + 3) = [a[i], a[i + 1], a[i + 2]].toByteArray := by
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
extract_add_one (by omega), extract_add_two (by omega)]
simp [ List.toByteArray_append]
theorem ByteArray.extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 a.size) :
a.extract i (i + 4) = [a[i], a[i + 1], a[i + 2], a[i + 3]].toByteArray := by
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
extract_add_one (by omega), extract_add_three (by omega)]
simp [ List.toByteArray_append]
theorem ByteArray.append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
ext1
simp
@[simp]
theorem ByteArray.toList_empty : ByteArray.empty.toList = [] := by
simp [ByteArray.toList, ByteArray.toList.loop]
theorem ByteArray.copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
ByteArray.copySlice src srcOff dest destOff len exact =
dest.extract 0 destOff ++ src.extract srcOff (srcOff +len) ++ dest.extract (destOff + min len (src.data.size - srcOff)) dest.data.size := by
ext1
simp [copySlice]

View File

@@ -122,7 +122,7 @@ private theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i
rw [foldlM_loop_lt _ _ h', foldlM_loop]; rfl
else
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
rw [foldlM_loop_lt]
rw [foldlM_loop_lt _ _ h]
congr; funext
rw [foldlM_loop_eq, foldlM_loop_eq]
termination_by n - i

View File

@@ -3,15 +3,11 @@ Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
module
prelude
public import Init.Core
public import Init.Grind.Tactics
public section
namespace Function
/--
@@ -34,20 +30,108 @@ 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`. -/
@[expose]
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 : α`. -/
@[expose]
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`. -/
@[expose, grind]
def LeftInverse {α β} (g : β α) (f : α β) : Prop :=
x, g (f x) = x
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
@[expose]
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`. -/
@[expose, grind]
def RightInverse {α β} (g : β α) (f : α β) : Prop :=
LeftInverse f g
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
@[expose]
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

@@ -206,9 +206,6 @@ theorem ediv_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : 0 ≤ a / b ↔ 0 ≤ a
| Int.ofNat (b+1), _ =>
rcases a with a <;> simp [Int.ediv, -natCast_ediv]
@[deprecated ediv_nonneg_iff_of_pos (since := "2025-02-28")]
abbrev div_nonneg_iff_of_pos := @ediv_nonneg_iff_of_pos
/-! ### emod -/
theorem emod_nonneg : (a : Int) {b : Int}, b 0 0 a % b

View File

@@ -17,6 +17,7 @@ import all Init.Data.Int.Gcd
public import Init.Data.RArray
public import Init.Data.AC
import all Init.Data.AC
import Init.LawfulBEqTactics
public section
@@ -54,7 +55,7 @@ def Expr.denote (ctx : Context) : Expr → Int
inductive Poly where
| num (k : Int)
| add (k : Int) (v : Var) (p : Poly)
deriving @[expose] BEq
deriving @[expose] BEq, ReflBEq, LawfulBEq
@[expose]
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly Bool :=
@@ -525,18 +526,6 @@ theorem Expr.denote_norm (ctx : Context) (e : Expr) : e.norm.denote ctx = e.deno
simp [norm, toPoly', Expr.denote_toPoly'_go]
attribute [local simp] Expr.denote_norm
instance : LawfulBEq Poly where
eq_of_beq {a} := by
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
next ih =>
intro _ _ h
exact ih h
rfl := by
intro a
induction a <;> simp! [BEq.beq]
assumption
attribute [local simp] Poly.denote'_eq_denote
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm.beq' p) : e.denote ctx = p.denote' ctx := by

View File

@@ -1347,8 +1347,6 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
| 0 => Int.mul_zero _
| -[_+1] => Int.mul_neg_one _
@[deprecated mul_sign_self (since := "2025-02-24")] abbrev mul_sign := @mul_sign_self
@[simp] theorem sign_mul_self (i : Int) : sign i * i = natAbs i := by
rw [Int.mul_comm, mul_sign_self]

View File

@@ -50,14 +50,9 @@ protected theorem pow_ne_zero {n : Int} {m : Nat} : n ≠ 0 → n ^ m ≠ 0 := b
instance {n : Int} {m : Nat} [NeZero n] : NeZero (n ^ m) := Int.pow_ne_zero (NeZero.ne _)
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
-- This can't be removed until the next update-stage0
@[deprecated Nat.pow_pos (since := "2025-02-17")]
abbrev pos_pow_of_pos := @Nat.pow_pos
abbrev _root_.Nat.pos_pow_of_pos := @Nat.pow_pos
@[simp, norm_cast]
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by

View File

@@ -19,6 +19,7 @@ universe v u v' u'
section ULiftT
/-- `ULiftT.{v, u}` shrinks a monad on `Type max u v` to a monad on `Type u`. -/
@[expose] -- for codegen
def ULiftT (n : Type max u v Type v') (α : Type u) := n (ULift.{v} α)
/-- Returns the underlying `n`-monadic representation of a `ULiftT n α` value. -/

View File

@@ -139,7 +139,7 @@ def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
@[always_inline, inline, inherit_doc IterM.size]
@[always_inline, inline, expose, inherit_doc IterM.size]
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
(it : Iter (α := α) β) : Nat :=
(IteratorSize.size it.toIterM).run.down

View File

@@ -57,6 +57,6 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
[LawfulMonad m] [LawfulIteratorCollect α m m] :
(·.map Subtype.val) <$> (it.attachWith P hP).toArray = it.toArray := by
rw [ toArray_toList, toArray_toList, map_unattach_toList_attachWith (it := it) (hP := hP)]
simp [-map_unattach_toList_attachWith]
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
end Std.Iterators

View File

@@ -53,6 +53,6 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
[LawfulIteratorCollect α Id Id] :
it.uLift.toArray = it.toArray.map ULift.up := by
rw [ toArray_toList, toArray_toList, toList_uLift]
simp
simp [-toArray_toList]
end Std.Iterators

View File

@@ -44,11 +44,13 @@ theorem IterM.toListRev_toIter {α β} [Iterator α Id β] [Finite α Id]
it.toIter.toListRev = it.toListRev.run :=
(rfl)
@[simp]
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
it.toArray.toList = it.toList := by
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, IterM.toList_toArray]
@[simp]
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
it.toList.toArray = it.toArray := by

View File

@@ -14,6 +14,7 @@ public import Init.Data.Iterators.Consumers.Loop
import all Init.Data.Iterators.Consumers.Loop
public import Init.Data.Iterators.Consumers.Monadic.Collect
import all Init.Data.Iterators.Consumers.Monadic.Collect
import Init.Data.Array.Monadic
public section
@@ -43,6 +44,20 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
f out acc) := by
simp [ForIn.forIn, forIn'_eq, -forIn'_eq_forIn]
@[congr] theorem Iter.forIn'_congr {α β : Type w}
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
{ita itb : Iter (α := α) β} (w : ita = itb)
{b b' : γ} (hb : b = b')
{f : (a' : β) _ γ Id (ForInStep γ)}
{g : (a' : β) _ γ Id (ForInStep γ)}
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
letI : ForIn' Id (Iter (α := α) β) β _ := Iter.instForIn'
forIn' ita b f = forIn' itb b' g := by
subst_eqs
simp only [ funext_iff] at h
rw [ h]
rfl
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w Type w''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -188,6 +203,13 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
obtain step, h₁, rfl := h₁
simp [heq, IterStep.successor] at h₁
theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
[IteratorCollect α Id Id] [Finite α Id]
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
{it : Iter (α := α) β} {out : β} :
out it.toArray it.IsPlausibleIndirectOutput out := by
rw [ Iter.toArray_toList, List.mem_toArray, mem_toList_iff_isPlausibleIndirectOutput]
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -222,6 +244,17 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
simp only [ihs h (f := fun out h acc => f out (this h) acc)]
· simp
theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) _ γ m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it.toArray init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mpr h) acc) := by
simp only [ Iter.toArray_toList (it := it), List.forIn'_toArray, Iter.forIn'_toList]
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -234,6 +267,18 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
simp only [forIn'_toList]
congr
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) _ γ m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it init f = ForIn'.forIn' it.toArray init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mp h) acc) := by
simp only [forIn'_toArray]
congr
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -260,6 +305,15 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
rw [ihs h]
· simp
theorem Iter.forIn_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : β γ m (ForInStep γ)} :
ForIn.forIn it.toArray init f = ForIn.forIn it init f := by
simp only [ Iter.toArray_toList, List.forIn_toArray, forIn_toList]
theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x Type x'} [Monad m] [IteratorLoop α Id m] {f : γ β m γ}
{init : γ} {it : Iter (α := α) β} :
@@ -301,6 +355,14 @@ theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [F
rw [Iter.foldM_eq_forIn, Iter.forIn_toList]
simp only [List.forIn_yield_eq_foldlM, id_map']
theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{f : γ β m γ} {init : γ} {it : Iter (α := α) β} :
it.toArray.foldlM (init := init) f = it.foldM (init := init) f := by
rw [Iter.foldM_eq_forIn, Iter.forIn_toArray]
simp only [Array.forIn_yield_eq_foldlM, id_map']
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -324,6 +386,12 @@ theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
simp [foldM_eq_forIn, fold_eq_forIn]
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{f : γ β γ} {init : γ} {it : Iter (α := α) β} :
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
@[simp]
theorem Iter.forIn_pure_yield_eq_fold {α β : Type w} {γ : Type x} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : β γ γ} {init : γ}
@@ -344,6 +412,38 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
generalize it.step = step
cases step using PlausibleIterStep.casesOn <;> simp
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
theorem Iter.fold_hom [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β}
(f : γ₁ γ₂) {g₁ : γ₁ β γ₁} {g₂ : γ₂ β γ₂} {init : γ₁}
(H : x y, g₂ (f x) y = f (g₁ x y)) :
it.fold g₂ (f init) = f (it.fold g₁ init) := by
-- We cannot reduce to `IterM.fold_hom` because `IterM.fold` is necessarily more restrictive
-- w.r.t. the universe of the output.
induction it using Iter.inductSteps generalizing init with | step it ihy ihs =>
rw [fold_eq_match_step, fold_eq_match_step]
split
· rw [H, ihy _]
· rw [ihs _]
· simp
theorem Iter.toList_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{it : Iter (α := α) β} :
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
rw [Iter.toList_eq_toList_toIterM, IterM.toList_eq_fold, Iter.fold_eq_fold_toIterM]
theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{it : Iter (α := α) β} :
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
simp only [ toArray_toList, toList_eq_fold]
rw [ fold_hom (List.toArray)]
simp
@[simp]
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
@@ -352,6 +452,14 @@ theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Fi
it.toList.foldl (init := init) f = it.fold (init := init) f := by
rw [fold_eq_foldM, List.foldl_eq_foldlM, Iter.foldlM_toList]
@[simp]
theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{f : γ β γ} {init : γ} {it : Iter (α := α) β} :
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
rw [fold_eq_foldM, Array.foldl_eq_foldlM, Iter.foldlM_toArray]
@[simp]
theorem Iter.size_toArray_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]

View File

@@ -67,15 +67,17 @@ theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
simp [bind_pure_comp, pure_bind]
@[simp]
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
{it : IterM (α := α) m β} :
Array.toList <$> it.toArray = it.toList := by
simp [IterM.toList]
@[simp]
theorem IterM.toArray_toList [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
[IteratorCollect α m m] {it : IterM (α := α) m β} :
List.toArray <$> it.toList = it.toArray := by
simp [IterM.toList]
simp [IterM.toList, -toList_toArray]
theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
@@ -153,6 +155,6 @@ theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'
[hl : LawfulIteratorCollect α m m]
{it : IterM (α := α) m β} :
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
simp [IterM.toList, toArray_eq]
simp [IterM.toList, toArray_eq, -IterM.toList_toArray]
end Std.Iterators

View File

@@ -60,6 +60,20 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) (fun out _ acc => (·, .intro) <$> f out acc) := by
simp only [ForIn.forIn, forIn'_eq]
@[congr] theorem IterM.forIn'_congr {α β : Type w} {m : Type w Type w'} [Monad m]
[Iterator α m β] [Finite α m] [IteratorLoop α m m]
{ita itb : IterM (α := α) m β} (w : ita = itb)
{b b' : γ} (hb : b = b')
{f : (a' : β) _ γ m (ForInStep γ)}
{g : (a' : β) _ γ m (ForInStep γ)}
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
letI : ForIn' m (IterM (α := α) m β) β _ := IterM.instForIn'
forIn' ita b f = forIn' itb b' g := by
subst_eqs
simp only [ funext_iff] at h
rw [ h]
rfl
theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] {n : Type w Type w''} [Monad m] [Monad n] [LawfulMonad n]
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
@@ -200,6 +214,23 @@ theorem IterM.fold_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [I
intro step
cases step using PlausibleIterStep.casesOn <;> simp
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
theorem IterM.fold_hom {m : Type w Type w'} [Iterator α m β] [Finite α m]
[Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β}
(f : γ₁ γ₂) {g₁ : γ₁ β γ₁} {g₂ : γ₂ β γ₂} {init : γ₁}
(H : x y, g₂ (f x) y = f (g₁ x y)) :
it.fold g₂ (f init) = f <$> (it.fold g₁ init) := by
induction it using IterM.inductSteps generalizing init with | step it ihy ihs =>
rw [fold_eq_match_step, fold_eq_match_step, map_eq_pure_bind, bind_assoc]
apply bind_congr
intro step
rw [bind_pure_comp]
split
· rw [H, ihy _]
· rw [ihs _]
· simp
theorem IterM.toList_eq_fold {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
@@ -223,6 +254,15 @@ theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator
simp [ihs h]
· simp
theorem IterM.toArray_eq_fold {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
{it : IterM (α := α) m β} :
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
simp only [ toArray_toList, toList_eq_fold]
rw [ fold_hom]
simp
theorem IterM.drain_eq_fold {α β : Type w} {m : Type w Type w'} [Iterator α m β] [Finite α m]
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
it.drain = it.fold (init := PUnit.unit) (fun _ _ => .unit) :=

View File

@@ -149,9 +149,6 @@ theorem attach_map_val {l : List α} {f : α → β} :
(l.attach.map fun (i : {i // i l}) => f i) = l.map f := by
rw [attach, attachWith, map_pmap]; exact pmap_eq_map _
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
-- The argument `l : List α` is explicit to allow rewriting from right to left.
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
attach_map_val.trans (List.map_id _)
@@ -160,21 +157,18 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {l : List α} (H :
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
rw [attachWith, map_pmap]; exact pmap_eq_map _
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
theorem attachWith_map_subtype_val {p : α Prop} {l : List α} (H : a l, p a) :
(l.attachWith p H).map Subtype.val = l :=
(attachWith_map_val _).trans (List.map_id _)
@[simp, grind]
@[simp, grind ]
theorem mem_attach (l : List α) : x, x l.attach
| a, h => by
have := mem_map.1 (by rw [attach_map_subtype_val]; exact h)
rcases this with _, _, m, rfl
exact m
@[simp, 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 +186,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
@@ -253,13 +248,6 @@ theorem getElem?_pmap {p : α → Prop} {f : ∀ a, p a → β} {l : List α} (h
· simp
· simp only [pmap, getElem?_cons_succ, hl]
set_option linter.deprecated false in
@[deprecated List.getElem?_pmap (since := "2025-02-12")]
theorem get?_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) (n : Nat) :
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (mem_of_get? H) := by
simp only [get?_eq_getElem?]
simp [getElem?_pmap]
-- The argument `f` is explicit to allow rewriting from right to left.
@[simp, grind =]
theorem getElem_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) {i : Nat}
@@ -276,15 +264,6 @@ theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h
· simp
· simp [hl]
@[deprecated getElem_pmap (since := "2025-02-13")]
theorem get_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) {n : Nat}
(hn : n < (pmap f l h).length) :
get (pmap f l h) n, hn =
f (get l n, @length_pmap _ _ p f l h hn)
(h _ (getElem_mem (@length_pmap _ _ p f l h hn))) := by
simp only [get_eq_getElem]
simp [getElem_pmap]
@[simp, grind =]
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α Prop} {H : a xs, P a} :
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
@@ -370,13 +349,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
@@ -465,9 +444,6 @@ theorem map_attach_eq_pmap {l : List α} {f : { x // x ∈ l } → β} :
apply pmap_congr_left
simp
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
abbrev map_attach := @map_attach_eq_pmap
@[grind =]
theorem attach_filterMap {l : List α} {f : α Option β} :
(l.filterMap f).attach = l.attach.filterMap

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 -/
@@ -289,16 +289,6 @@ theorem cons_lex_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false :
@[simp] theorem lex_nil [BEq α] {as : List α} : lex as [] lt = false := by
cases as <;> simp [nil_lex_nil, cons_lex_nil]
@[deprecated nil_lex_nil (since := "2025-02-10")]
theorem lex_nil_nil [BEq α] : lex ([] : List α) [] lt = false := rfl
@[deprecated nil_lex_cons (since := "2025-02-10")]
theorem lex_nil_cons [BEq α] {b} {bs : List α} : lex [] (b :: bs) lt = true := rfl
@[deprecated cons_lex_nil (since := "2025-02-10")]
theorem lex_cons_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false := rfl
@[deprecated cons_lex_cons (since := "2025-02-10")]
theorem lex_cons_cons [BEq α] {a b} {as bs : List α} :
lex (a :: as) (b :: bs) lt = (lt a b || (a == b && lex as bs lt)) := rfl
/-! ## Alternative getters -/
/-! ### getLast -/
@@ -332,7 +322,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 +355,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 +373,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 +410,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 +431,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 -/
@@ -475,23 +465,8 @@ We define the basic functional programming operations on `List`:
/-! ### map -/
/--
Applies a function to each element of the list, returning the resulting list of values.
`O(|l|)`.
Examples:
* `[a, b, c].map f = [f a, f b, f c]`
* `[].map Nat.succ = []`
* `["one", "two", "three"].map (·.length) = [3, 3, 5]`
* `["one", "two", "three"].map (·.reverse) = ["eno", "owt", "eerht"]`
-/
@[specialize] def map (f : α β) : (l : List α) List β
| [] => []
| 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 +486,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 +512,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 +536,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 +566,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
@@ -606,20 +581,6 @@ Appends two lists. Normally used via the `++` operator.
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
Examples:
* `[1, 2, 3] ++ [4, 5] = [1, 2, 3, 4, 5]`.
* `[] ++ [4, 5] = [4, 5]`.
* `[1, 2, 3] ++ [] = [1, 2, 3]`.
-/
protected def append : (xs ys : List α) List α
| [], bs => bs
| a::as, bs => a :: List.append as bs
/--
Appends two lists. Normally used via the `++` operator.
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
This is a tail-recursive version of `List.append`.
Examples:
@@ -645,10 +606,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 +619,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,27 +646,15 @@ 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]
/-! ### flatten -/
/--
Concatenates a list of lists into a single list, preserving the order of the elements.
`O(|flatten L|)`.
Examples:
* `[["a"], ["b", "c"]].flatten = ["a", "b", "c"]`
* `[["a"], [], ["b", "c"], ["d", "e", "f"]].flatten = ["a", "b", "c", "d", "e", "f"]`
-/
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 -/
@@ -721,20 +670,14 @@ Examples:
/-! ### flatMap -/
/--
Applies a function that returns a list to each element of a list, and concatenates the resulting
lists.
Examples:
* `[2, 3, 2].flatMap List.range = [0, 1, 0, 1, 2, 0, 1]`
* `["red", "blue"].flatMap String.toList = ['r', 'e', 'd', 'b', 'l', 'u', 'e']`
-/
@[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]
@[simp, grind _=_] theorem flatMap_append {xs ys : List α} {f : α List β} :
(xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
induction xs; {rfl}; simp_all [flatMap_cons, append_assoc]
/-! ### replicate -/
/--
@@ -748,10 +691,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 +762,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 +785,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 +901,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 +923,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 +1037,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 +1382,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 +1591,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 +1849,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 +1868,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 +2009,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

@@ -21,65 +21,6 @@ namespace List
/-! ## Alternative getters -/
/-! ### get? -/
/--
Returns the `i`-th element in the list (zero-based).
If the index is out of bounds (`i ≥ as.length`), this function returns `none`.
Also see `get`, `getD` and `get!`.
-/
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), expose]
def get? : (as : List α) (i : Nat) Option α
| a::_, 0 => some a
| _::as, n+1 => get? as n
| _, _ => none
set_option linter.deprecated false in
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
theorem get?_nil : @get? α [] n = none := rfl
set_option linter.deprecated false in
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
theorem get?_cons_zero : @get? α (a::l) 0 = some a := rfl
set_option linter.deprecated false in
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
theorem get?_cons_succ : @get? α (a::l) (n+1) = get? l n := rfl
set_option linter.deprecated false in
@[deprecated "Use `List.ext_getElem?`." (since := "2025-02-12")]
theorem ext_get? : {l₁ l₂ : List α}, ( n, l₁.get? n = l₂.get? n) l₁ = l₂
| [], [], _ => rfl
| _ :: _, [], h => nomatch h 0
| [], _ :: _, h => nomatch h 0
| a :: l₁, a' :: l₂, h => by
have h0 : some a = some a' := h 0
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
/-! ### get! -/
/--
Returns the `i`-th element in the list (zero-based).
If the index is out of bounds (`i ≥ as.length`), this function panics when executed, and returns
`default`. See `get?` and `getD` for safer alternatives.
-/
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12"), expose]
def get! [Inhabited α] : (as : List α) (i : Nat) α
| a::_, 0 => a
| _::as, n+1 => get! as n
| _, _ => panic! "invalid index"
set_option linter.deprecated false in
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
theorem get!_nil [Inhabited α] (n : Nat) : [].get! n = (default : α) := rfl
set_option linter.deprecated false in
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
theorem get!_cons_succ [Inhabited α] (l : List α) (a : α) (n : Nat) :
(a::l).get! (n+1) = get! l n := rfl
set_option linter.deprecated false in
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
theorem get!_cons_zero [Inhabited α] (l : List α) (a : α) : (a::l).get! 0 = a := rfl
/-! ### getD -/
/--
@@ -281,17 +222,6 @@ theorem getElem_append_right {as bs : List α} {i : Nat} (h₁ : as.length ≤ i
cases i with simp [Nat.succ_sub_succ] <;> simp at h₁
| succ i => apply ih; simp [h₁]
@[deprecated "Deprecated without replacement." (since := "2025-02-13")]
theorem get_last {as : List α} {i : Fin (length (as ++ [a]))} (h : ¬ i.1 < as.length) : (as ++ [a] : List _).get i = a := by
cases i; rename_i i h'
induction as generalizing i with
| nil => cases i with
| zero => simp [List.get]
| succ => simp +arith at h'
| cons a as ih =>
cases i with simp at h
| succ i => apply ih; simp [h]
theorem sizeOf_lt_of_mem [SizeOf α] {as : List α} (h : a as) : sizeOf a < sizeOf as := by
induction h with
| head => simp +arith

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
@@ -359,9 +360,6 @@ theorem find?_flatten_eq_none_iff {xs : List (List α)} {p : α → Bool} :
xs.flatten.find? p = none ys xs, x ys, !p x := by
simp
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
/--
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
some list in `xs` contains `a`, and no earlier element of that list satisfies `p`.
@@ -402,9 +400,6 @@ theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α → Bool} {a :
· exact h₁ l ml a m
· exact h₂ a m
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
@[simp, grind =] theorem find?_flatMap {xs : List α} {f : α List β} {p : β Bool} :
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
simp [flatMap_def, findSome?_map]; rfl
@@ -433,16 +428,10 @@ theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
(replicate n a).find? p = none n = 0 !p a := by
simp [Classical.or_iff_not_imp_left]
@[deprecated find?_replicate_eq_none_iff (since := "2025-02-03")]
abbrev find?_replicate_eq_none := @find?_replicate_eq_none_iff
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α Bool} :
(replicate n a).find? p = some b n 0 p a a = b := by
cases n <;> simp
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
abbrev find?_replicate_eq_some := @find?_replicate_eq_some_iff
@[simp] theorem get_find?_replicate {n : Nat} {a : α} {p : α Bool} (h) : ((replicate n a).find? p).get h = a := by
cases n with
| zero => simp at h
@@ -558,7 +547,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
@@ -836,9 +824,6 @@ theorem of_findIdx?_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p
simp_all only [findIdx?_cons]
split at w <;> cases i <;> simp_all
@[deprecated of_findIdx?_eq_some (since := "2025-02-02")]
abbrev findIdx?_of_eq_some := @of_findIdx?_eq_some
theorem of_findIdx?_eq_none {xs : List α} {p : α Bool} (w : xs.findIdx? p = none) :
i : Nat, match xs[i]? with | some a => ¬ p a | none => true := by
intro i
@@ -854,9 +839,6 @@ theorem of_findIdx?_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p
apply ih
split at w <;> simp_all
@[deprecated of_findIdx?_eq_none (since := "2025-02-02")]
abbrev findIdx?_of_eq_none := @of_findIdx?_eq_none
@[simp, grind _=_] theorem findIdx?_map {f : β α} {l : List β} : findIdx? p (l.map f) = l.findIdx? (p f) := by
induction l with
| nil => simp

File diff suppressed because it is too large Load Diff

View File

@@ -105,9 +105,6 @@ theorem length_leftpad {n : Nat} {a : α} {l : List α} :
(leftpad n a l).length = max n l.length := by
simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max]
@[deprecated length_leftpad (since := "2025-02-24")]
abbrev leftpad_length := @length_leftpad
theorem length_rightpad {n : Nat} {a : α} {l : List α} :
(rightpad n a l).length = max n l.length := by
simp [rightpad]

View File

@@ -196,9 +196,6 @@ theorem getElem_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (hn : i < j)
| zero => omega
| succ j => simp
@[deprecated getElem_insertIdx_of_gt (since := "2025-02-04")]
abbrev getElem_insertIdx_of_ge := @getElem_insertIdx_of_gt
@[grind =]
theorem getElem_insertIdx {l : List α} {x : α} {i j : Nat} (h : j < (l.insertIdx i x).length) :
(l.insertIdx i x)[j] =
@@ -261,9 +258,6 @@ theorem getElem?_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (h : i < j)
(l.insertIdx i x)[j]? = l[j - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
@[deprecated getElem?_insertIdx_of_gt (since := "2025-02-04")]
abbrev getElem?_insertIdx_of_ge := @getElem?_insertIdx_of_gt
end InsertIdx
end List

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

@@ -117,9 +117,6 @@ theorem take_set_of_le {a : α} {i j : Nat} {l : List α} (h : j ≤ i) :
next h' => rw [getElem?_set_ne (by omega)]
· rfl
@[deprecated take_set_of_le (since := "2025-02-04")]
abbrev take_set_of_lt := @take_set_of_le
@[simp, grind =] theorem take_replicate {a : α} : {i n : Nat}, take i (replicate n a) = replicate (min i n) a
| n, 0 => by simp
| 0, m => by simp
@@ -165,9 +162,6 @@ theorem take_eq_take_iff :
| x :: xs, 0, j + 1 => by simp [succ_min_succ]
| x :: xs, i + 1, j + 1 => by simp [succ_min_succ, take_eq_take_iff]
@[deprecated take_eq_take_iff (since := "2025-02-16")]
abbrev take_eq_take := @take_eq_take_iff
@[grind =]
theorem take_add {l : List α} {i j : Nat} : l.take (i + j) = l.take i ++ (l.drop i).take j := by
suffices take (i + j) (take i l ++ drop i l) = take i l ++ take j (drop i l) by
@@ -567,9 +561,10 @@ theorem getElem_zipWith {f : α → β → γ} {l : List α} {l' : List β}
f (l[i]'(lt_length_left_of_zipWith h))
(l'[i]'(lt_length_right_of_zipWith h)) := by
rw [ Option.some_inj, getElem?_eq_getElem, getElem?_zipWith_eq_some]
have := lt_length_right_of_zipWith h
exact
l[i]'(lt_length_left_of_zipWith h), l'[i]'(lt_length_right_of_zipWith h),
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem]; exact rfl, rfl
l[i]'(lt_length_left_of_zipWith h), l'[i],
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem this]; exact rfl, rfl
theorem zipWith_eq_zipWith_take_min : {l₁ : List α} {l₂ : List β},
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))

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 α} :
@@ -171,7 +171,7 @@ theorem pairwise_append_comm {R : αα → Prop} (s : ∀ {x y}, R x y →
induction L with
| nil => simp
| cons l L IH =>
simp only [flatten, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
simp only [flatten_cons, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
pairwise_cons, and_assoc, and_congr_right_iff]
rw [and_comm, and_congr_left_iff]
intros; exact fun h l' b c d e => h c d e l' b, fun h c d e l' b => h l' b c d e
@@ -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

@@ -151,11 +151,11 @@ theorem subset_replicate {n : Nat} {a : α} {l : List α} (h : n ≠ 0) : l ⊆
/-! ### Sublist and isSublist -/
@[simp, grind] theorem nil_sublist : l : List α, [] <+ l
@[simp, grind ] theorem nil_sublist : l : List α, [] <+ l
| [] => .slnil
| a :: l => (nil_sublist l).cons a
@[simp, grind] theorem Sublist.refl : l : List α, l <+ l
@[simp, grind ] theorem Sublist.refl : l : List α, l <+ l
| [] => .slnil
| a :: l => (Sublist.refl l).cons₂ a
@@ -172,7 +172,7 @@ theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l
instance : Trans (@Sublist α) Sublist Sublist := Sublist.trans
attribute [simp, grind] Sublist.cons
attribute [simp, grind ] Sublist.cons
theorem sublist_cons_self (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _
@@ -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
@@ -651,22 +664,24 @@ theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ =>
grind_pattern IsSuffix.isInfix => l₁ <:+ l₂, IsInfix
@[simp, grind] theorem nil_prefix {l : List α} : [] <+: l := l, rfl
@[simp, grind ] theorem nil_prefix {l : List α} : [] <+: l := l, rfl
@[simp, grind] theorem nil_suffix {l : List α} : [] <:+ l := l, append_nil _
@[simp, grind ] theorem nil_suffix {l : List α} : [] <:+ l := l, append_nil _
@[simp, grind] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
@[simp, grind ] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
theorem prefix_refl (l : List α) : l <+: l := [], append_nil _
@[simp, grind] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
@[simp, grind ] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
theorem suffix_refl (l : List α) : l <:+ l := [], rfl
@[simp, grind] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
@[simp, grind ] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
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 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

@@ -165,9 +165,6 @@ theorem take_set {l : List α} {i j : Nat} {a : α} :
| nil => simp
| cons hd tl => cases j <;> simp_all
@[deprecated take_set (since := "2025-02-17")]
abbrev set_take := @take_set
theorem drop_set {l : List α} {i j : Nat} {a : α} :
(l.set j a).drop i = if j < i then l.drop i else (l.drop i).set (j - i) a := by
induction i generalizing l j with

View File

@@ -791,18 +791,6 @@ protected theorem pow_le_pow_right {n : Nat} (hx : n > 0) {i : Nat} : ∀ {j}, i
| Or.inr h =>
h.symm Nat.le_refl _
set_option linter.missingDocs false in
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
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
set_option linter.missingDocs false in
@[deprecated Nat.pow_pos (since := "2025-02-17")]
abbrev pos_pow_of_pos := @Nat.pow_pos
@[simp] theorem zero_pow_of_pos (n : Nat) (h : 0 < n) : 0 ^ n = 0 := by
cases n with
| zero => cases h
@@ -882,9 +870,6 @@ protected theorem ne_zero_of_lt (h : b < a) : a ≠ 0 := by
exact absurd h (Nat.not_lt_zero _)
apply Nat.noConfusion
@[deprecated Nat.ne_zero_of_lt (since := "2025-02-06")]
theorem not_eq_zero_of_lt (h : b < a) : a 0 := Nat.ne_zero_of_lt h
theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
pred_lt (Nat.ne_zero_of_lt h)

View File

@@ -9,6 +9,7 @@ prelude
public import Init.ByCases
public import Init.Data.Prod
public import Init.Data.RArray
import Init.LawfulBEqTactics
public section
@@ -138,21 +139,7 @@ structure PolyCnstr where
eq : Bool
lhs : Poly
rhs : Poly
deriving BEq
-- TODO: implement LawfulBEq generator companion for BEq
instance : LawfulBEq PolyCnstr where
eq_of_beq {a b} h := by
cases a; rename_i eq₁ lhs₁ rhs₁
cases b; rename_i eq₂ lhs₂ rhs₂
have h : eq₁ == eq₂ && (lhs₁ == lhs₂ && rhs₁ == rhs₂) := h
simp at h
have h₁, h₂, h₃ := h
rw [h₁, h₂, h₃]
rfl {a} := by
cases a; rename_i eq lhs rhs
change (eq == eq && (lhs == lhs && rhs == rhs)) = true
simp
deriving BEq, ReflBEq, LawfulBEq
structure ExprCnstr where
eq : Bool

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

@@ -75,9 +75,6 @@ theorem attach_map_val (o : Option α) (f : α → β) :
(o.attach.map fun (i : {i // o = some i}) => f i) = o.map f := by
cases o <;> simp
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
@[simp, grind =]theorem attach_map_subtype_val (o : Option α) :
o.attach.map Subtype.val = o :=
(attach_map_val _ _).trans (congrFun Option.map_id _)
@@ -86,9 +83,6 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (o : Option α) (H
((o.attachWith p H).map fun (i : { i // p i}) => f i.val) = o.map f := by
cases o <;> simp
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
@[simp, grind =] theorem attachWith_map_subtype_val {p : α Prop} (o : Option α) (H : a, o = some a p a) :
(o.attachWith p H).map Subtype.val = o :=
(attachWith_map_val _ _ _).trans (congrFun Option.map_id _)
@@ -97,7 +91,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
@@ -187,9 +181,6 @@ theorem toArray_attachWith {p : α → Prop} {o : Option α} {h} :
o.attach.map f = o.pmap (fun a (h : o = some a) => f a, h) (fun _ h => h) := by
cases o <;> simp
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
abbrev map_attach := @map_attach_eq_pmap
@[simp, grind =] theorem map_attachWith {l : Option α} {P : α Prop} {H : (a : α), l = some a P a}
(f : { x // P x } β) :
(l.attachWith P H).map f = l.attach.map fun x, h => f x, H _ h := by

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
@@ -52,7 +52,7 @@ theorem get_of_mem : ∀ {o : Option α} (h : isSome o), a ∈ o → o.get h = a
theorem get_of_eq_some : {o : Option α} (h : isSome o), o = some a o.get h = a
| _, _, rfl => rfl
@[simp, grind] theorem not_mem_none (a : α) : a (none : Option α) := nofun
@[simp, grind ] theorem not_mem_none (a : α) : a (none : Option α) := nofun
theorem getD_of_ne_none {x : Option α} (hx : x none) (y : α) : some (x.getD y) = x := by
cases x; {contradiction}; rw [getD_some]

View File

@@ -16,38 +16,38 @@ 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
@[simp, grind]
@[simp, grind ]
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

@@ -12,6 +12,8 @@ public import Init.Data.Range.Polymorphic.Stream
public import Init.Data.Range.Polymorphic.Lemmas
public import Init.Data.Range.Polymorphic.Nat
public import Init.Data.Range.Polymorphic.Int
public import Init.Data.Range.Polymorphic.BitVec
public import Init.Data.Range.Polymorphic.UInt
public import Init.Data.Range.Polymorphic.NatLemmas
public import Init.Data.Range.Polymorphic.GetElemTactic

View File

@@ -0,0 +1,88 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Range.Polymorphic.Instances
public import Init.Data.Order.Lemmas
public import Init.Data.UInt
import Init.Omega
public section
open Std Std.PRange
namespace BitVec
variable {n : Nat}
instance : UpwardEnumerable (BitVec n) where
succ? i := if i + 1 = 0 then none else some (i + 1)
succMany? m i := if h : i.toNat + m < 2 ^ n then some (.ofNatLT _ h) else none
instance : LawfulUpwardEnumerable (BitVec n) where
ne_of_lt := by
simp +contextual [UpwardEnumerable.LT, BitVec.toNat_inj, succMany?] at
omega
succMany?_zero := by simp [UpwardEnumerable.succMany?, BitVec.toNat_lt_twoPow_of_le]
succMany?_succ? a b := by
simp +contextual [ BitVec.toNat_inj, succMany?, succ?]
split <;> split
· rename_i h
simp [ BitVec.toNat_inj, Nat.mod_eq_of_lt (a := b.toNat + a + 1) _]
all_goals omega
· omega
· have : b.toNat + a + 1 = 2 ^ n := by omega
simp [this]
· simp
instance : LawfulUpwardEnumerableLE (BitVec n) where
le_iff x y := by
simp [UpwardEnumerable.LE, UpwardEnumerable.succMany?, BitVec.le_def]
apply Iff.intro
· intro hle
refine y.toNat - x.toNat, ?_
apply Exists.intro <;> simp [Nat.add_sub_cancel' hle, BitVec.toNat_lt_twoPow_of_le]
· rintro n, hn, rfl
simp [BitVec.ofNatLT]
instance : LawfulOrderLT (BitVec n) := inferInstance
instance : LawfulUpwardEnumerableLT (BitVec n) := inferInstance
instance : LawfulUpwardEnumerableLT (BitVec n) := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed (BitVec n) := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed (BitVec n) := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open (BitVec n) := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open (BitVec n) := inferInstance
instance : RangeSize .closed (BitVec n) where
size bound a := bound.toNat + 1 - a.toNat
instance : RangeSize .open (BitVec n) := RangeSize.openOfClosed
instance : LawfulRangeSize .closed (BitVec n) where
size_eq_zero_of_not_isSatisfied bound x := by
simp [SupportsUpperBound.IsSatisfied, BitVec.not_le, RangeSize.size, BitVec.lt_def]
omega
size_eq_one_of_succ?_eq_none bound x := by
have := BitVec.toNat_lt_twoPow_of_le (Nat.le_refl _) (x := bound)
have (h : (x.toNat + 1) % 2 ^ n = 0) : x.toNat = 2 ^ n - 1 := by
apply Classical.not_not.mp
intro _
simp [Nat.mod_eq_of_lt (a := x.toNat + 1) (b := 2 ^ n) (by omega)] at h
simp [RangeSize.size, BitVec.le_def, BitVec.toNat_inj, succ?]
omega
size_eq_succ_of_succ?_eq_some bound init x := by
have (h : ¬ (init.toNat + 1) % 2 ^ n = 0) : ¬ (init.toNat + 1 2 ^ n) := by
intro _
have : init.toNat + 1 = 2 ^ n := by omega
simp_all
simp_all +contextual [RangeSize.size, BitVec.le_def, BitVec.toNat_inj,
Nat.mod_eq_of_lt (a := init.toNat + 1) (b := 2 ^ n), succ?]
omega
instance : LawfulRangeSize .open (BitVec n) := inferInstance
end BitVec

View File

@@ -8,6 +8,7 @@ module
prelude
public import Init.Data.Range.Polymorphic.Instances
public import Init.Data.Order.Classes
public import Init.Data.Int.Order
import Init.Omega
public section
@@ -23,7 +24,7 @@ instance : LawfulUpwardEnumerable Int where
simp only [UpwardEnumerable.LT, UpwardEnumerable.succMany?, Option.some.injEq]
omega
succMany?_zero := by simp [UpwardEnumerable.succMany?]
succMany?_succ := by
succMany?_succ? := by
simp only [UpwardEnumerable.succMany?, UpwardEnumerable.succ?,
Option.bind_some, Option.some.injEq]
omega
@@ -36,6 +37,14 @@ instance : LawfulUpwardEnumerableLE Int where
simp [UpwardEnumerable.LE, UpwardEnumerable.succMany?, Int.le_def, Int.nonneg_def,
Int.sub_eq_iff_eq_add', eq_comm (a := y)]
instance : LawfulOrderLT Int := inferInstance
instance : LawfulUpwardEnumerableLT Int := inferInstance
instance : LawfulUpwardEnumerableLT Int := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed Int := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed Int := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open Int := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open Int := inferInstance
instance : RangeSize .closed Int where
size bound a := (bound + 1 - a).toNat

View File

@@ -27,7 +27,7 @@ def Internal.iter {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl
/--
Returns the elements of the given range as a list in ascending order, given that ranges of the given
type and shape support this function and the range is finite.
type and shape are finite and support this function.
-/
@[always_inline, inline, expose]
def toList {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
@@ -37,6 +37,18 @@ def toList {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[IteratorCollect (RangeIterator su α) Id Id] : List α :=
PRange.Internal.iter r |>.toList
/--
Returns the elements of the given range as an array in ascending order, given that ranges of the
given type and shape are finite and support this function.
-/
@[always_inline, inline, expose]
def toArray {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[SupportsUpperBound su α]
(r : PRange sl, su α)
[Iterator (RangeIterator su α) Id α] [Finite (RangeIterator su α) Id]
[IteratorCollect (RangeIterator su α) Id Id] : Array α :=
PRange.Internal.iter r |>.toArray
/--
Iterators for ranges implementing `RangeSize` support the `size` function.
-/

View File

@@ -16,6 +16,7 @@ public import Init.Data.Range.Polymorphic.Iterators
import all Init.Data.Range.Polymorphic.Iterators
public import Init.Data.Iterators.Consumers.Loop
import all Init.Data.Iterators.Consumers.Loop
import Init.Data.Array.Monadic
public section
@@ -44,6 +45,12 @@ private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
r.toList = (Internal.iter r).toList := by
rfl
private theorem Internal.toArray_eq_toArray_iter {sl su} [UpwardEnumerable α]
[BoundedUpwardEnumerable sl α] [SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α] {r : PRange sl, su α} :
r.toArray = (Internal.iter r).toArray := by
rfl
public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
@@ -61,6 +68,35 @@ public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
· simp [*]
· split <;> rename_i heq' <;> simp [*]
public theorem RangeIterator.toArray_eq_match {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
{it : Iter (α := RangeIterator su α) α} :
it.toArray = match it.internalState.next with
| none => #[]
| some a => if SupportsUpperBound.IsSatisfied it.internalState.upperBound a then
#[a] ++ (UpwardEnumerable.succ? a, it.internalState.upperBound : Iter (α := RangeIterator su α) α).toArray
else
#[] := by
rw [ Iter.toArray_toList, toList_eq_match]
split
· rfl
· split <;> simp
@[simp]
public theorem toList_toArray {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerable α]
{r : PRange sl, su α} :
r.toArray.toList = r.toList := by
simp [Internal.toArray_eq_toArray_iter, Internal.toList_eq_toList_iter]
@[simp]
public theorem toArray_toList {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerable α]
{r : PRange sl, su α} :
r.toList.toArray = r.toArray := by
simp [Internal.toArray_eq_toArray_iter, Internal.toList_eq_toList_iter]
public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
@@ -73,6 +109,18 @@ public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnume
[] := by
rw [Internal.toList_eq_toList_iter, RangeIterator.toList_eq_match]; rfl
public theorem toArray_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
{r : PRange sl, su α} :
r.toArray = match init? r.lower with
| none => #[]
| some a => if SupportsUpperBound.IsSatisfied r.upper a then
#[a] ++ (PRange.mk (shape := .open, su) a r.upper).toArray
else
#[] := by
rw [Internal.toArray_eq_toArray_iter, RangeIterator.toArray_eq_match]; rfl
public theorem toList_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α]
[LawfulUpwardEnumerable α]
@@ -90,6 +138,14 @@ public theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerab
(PRange.mk (shape := .closed, su) (UpwardEnumerable.succ? lo |>.get h) hi).toList :=
toList_Rox_eq_toList_Rcx_of_isSome_succ? h
public theorem toArray_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).toArray =
(PRange.mk (shape := .closed, su) (UpwardEnumerable.succ? lo |>.get h) hi).toArray := by
simp [Internal.toArray_eq_toArray_iter, Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ?, h]
public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
[LawfulUpwardEnumerable α]
@@ -101,6 +157,14 @@ public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
simp only
split <;> rename_i heq <;> simp [heq]
public theorem toArray_eq_empty_iff {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
[LawfulUpwardEnumerable α]
{r : PRange sl, su α} :
r.toArray = #[]
¬ ( a, init? r.lower = some a SupportsUpperBound.IsSatisfied r.upper a) := by
rw [ toArray_toList, List.toArray_eq_iff, Array.toList_empty, toList_eq_nil_iff]
public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
@@ -110,6 +174,15 @@ public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
rw [Internal.toList_eq_toList_iter, Iter.mem_toList_iff_isPlausibleIndirectOutput,
Internal.isPlausibleIndirectOutput_iter_iff]
public theorem mem_toArray_iff_mem {sl su} [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
{r : PRange sl, su α}
{a : α} : a r.toArray a r := by
rw [Internal.toArray_eq_toArray_iter, Iter.mem_toArray_iff_isPlausibleIndirectOutput,
Internal.isPlausibleIndirectOutput_iter_iff]
public theorem BoundedUpwardEnumerable.init?_succ?_closed [UpwardEnumerable α]
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
(h : UpwardEnumerable.succ? lower = some lower') :
@@ -301,6 +374,17 @@ public theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [Support
(lower...upper).toList.map succ :=
toList_Rco_succ_succ_eq_map
public theorem toArray_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 α} :
((succ lower)...(succ upper)).toArray =
(lower...upper).toArray.map succ := by
simp only [ toArray_toList]
rw [toList_Rco_succ_succ_eq_map]
simp only [List.map_toArray]
private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
@@ -324,6 +408,18 @@ public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
simp [Internal.forIn'_eq_forIn'_iter, Internal.toList_eq_toList_iter,
Iter.forIn'_eq_forIn'_toList]
public theorem forIn'_eq_forIn'_toArray [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
{r : PRange sl, su α}
{γ : Type u} {init : γ} {m : Type u Type w} [Monad m] [LawfulMonad m]
{f : (a : α) a r γ m (ForInStep γ)} :
ForIn'.forIn' r init f =
ForIn'.forIn' r.toArray init (fun a ha acc => f a (mem_toArray_iff_mem.mp ha) acc) := by
simp [Internal.forIn'_eq_forIn'_iter, Internal.toArray_eq_toArray_iter,
Iter.forIn'_eq_forIn'_toArray]
public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
@@ -335,6 +431,17 @@ public 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]
public theorem forIn'_toArray_eq_forIn' [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
{r : PRange sl, su α}
{γ : Type u} {init : γ} {m : Type u Type w} [Monad m] [LawfulMonad m]
{f : (a : α) _ γ m (ForInStep γ)} :
ForIn'.forIn' r.toArray init f =
ForIn'.forIn' r init (fun a ha acc => f a (mem_toArray_iff_mem.mpr ha) acc) := by
simp [forIn'_eq_forIn'_toArray]
public theorem mem_of_mem_open [UpwardEnumerable α]
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
@@ -431,6 +538,20 @@ public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
simp [*] at this
public theorem length_toList {sl su} [UpwardEnumerable α] [SupportsUpperBound su α]
[RangeSize su α] [LawfulUpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[HasFiniteRanges su α] [LawfulRangeSize su α]
{r : PRange sl, su α} :
r.toList.length = r.size := by
simp [PRange.toList, PRange.size]
public theorem size_toArray {sl su} [UpwardEnumerable α] [SupportsUpperBound su α]
[RangeSize su α] [LawfulUpwardEnumerable α] [BoundedUpwardEnumerable sl α]
[HasFiniteRanges su α] [LawfulRangeSize su α]
{r : PRange sl, su α} :
r.toArray.size = r.size := by
simp [PRange.toArray, PRange.size]
public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[BoundedUpwardEnumerable sl α] [SupportsLowerBound sl α] [SupportsUpperBound su α]
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
@@ -455,4 +576,94 @@ public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulU
(Option.some_get hi).symm
exact h ((init? r.lower).get hi) hl, hu
theorem Std.PRange.getElem?_toList_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
{r : PRange .closed, su α} {i} :
r.toList[i]? = (UpwardEnumerable.succMany? i r.lower).filter (SupportsUpperBound.IsSatisfied r.upper) := by
induction i generalizing r
· rw [PRange.toList_eq_match, UpwardEnumerable.succMany?_zero]
simp only [Option.filter_some, decide_eq_true_eq]
split <;> simp
· rename_i n ih
rw [PRange.toList_eq_match]
simp only
split
· simp [UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?]
cases hs : UpwardEnumerable.succ? r.lower
· rw [PRange.toList_eq_match]
simp [BoundedUpwardEnumerable.init?, hs]
· rw [toList_Rox_eq_toList_Rcx_of_isSome_succ? (by simp [hs])]
rw [ih]
simp [hs]
· simp only [List.length_nil, Nat.not_lt_zero, not_false_eq_true, getElem?_neg]
cases hs : UpwardEnumerable.succMany? (n + 1) r.lower
· simp
· rename_i hl a
simp only [Option.filter_some, decide_eq_true_eq, right_eq_ite_iff]
have : UpwardEnumerable.LE r.lower a := n + 1, hs
intro ha
exact hl.elim <| LawfulUpwardEnumerableUpperBound.isSatisfied_of_le r.upper _ _ ha this (α := α)
theorem Std.PRange.getElem?_toArray_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
{r : PRange .closed, su α} {i} :
r.toArray[i]? = (UpwardEnumerable.succMany? i r.lower).filter (SupportsUpperBound.IsSatisfied r.upper) := by
rw [ toArray_toList, List.getElem?_toArray, getElem?_toList_Rcx_eq]
theorem Std.PRange.isSome_succMany?_of_lt_length_toList_Rcx [LE α] [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
{r : PRange .closed, su α} {i} (h : i < r.toList.length) :
(UpwardEnumerable.succMany? i r.lower).isSome := by
have : r.toList[i]?.isSome := by simp [h]
simp only [getElem?_toList_Rcx_eq, Option.isSome_filter] at this
exact Option.isSome_of_any this
theorem Std.PRange.isSome_succMany?_of_lt_size_toArray_Rcx [LE α] [UpwardEnumerable α]
[LawfulUpwardEnumerable α] [SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
{r : PRange .closed, su α} {i} (h : i < r.toArray.size) :
(UpwardEnumerable.succMany? i r.lower).isSome := by
have : r.toArray[i]?.isSome := by simp [h]
simp only [getElem?_toArray_Rcx_eq, Option.isSome_filter] at this
exact Option.isSome_of_any this
theorem Std.PRange.getElem_toList_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
{r : PRange .closed, su α} {i h} :
r.toList[i]'h = (UpwardEnumerable.succMany? i r.lower).get
(isSome_succMany?_of_lt_length_toList_Rcx h) := by
simp [List.getElem_eq_getElem?_get, getElem?_toList_Rcx_eq]
theorem Std.PRange.getElem_toArray_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
{r : PRange .closed, su α} {i h} :
r.toArray[i]'h = (UpwardEnumerable.succMany? i r.lower).get
(isSome_succMany?_of_lt_size_toArray_Rcx h) := by
simp [Array.getElem_eq_getElem?_get, getElem?_toArray_Rcx_eq]
theorem Std.PRange.eq_succMany?_of_toList_Rcx_eq_append_cons [LE α]
[UpwardEnumerable α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerableUpperBound su α]
{r : PRange .closed, su α} {pref suff : List α} {cur : α} (h : r.toList = pref ++ cur :: suff) :
cur = (UpwardEnumerable.succMany? pref.length r.lower).get
(isSome_succMany?_of_lt_length_toList_Rcx (by simp [h])) := by
have : cur = (pref ++ cur :: suff)[pref.length] := by simp
simp only [ h] at this
simp [this, getElem_toList_Rcx_eq]
theorem Std.PRange.eq_succMany?_of_toArray_Rcx_eq_append_append [LE α]
[UpwardEnumerable α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerableUpperBound su α]
{r : PRange .closed, su α} {pref suff : Array α} {cur : α} (h : r.toArray = pref ++ #[cur] ++ suff) :
cur = (UpwardEnumerable.succMany? pref.size r.lower).get
(isSome_succMany?_of_lt_size_toArray_Rcx (by simp [h, Nat.add_assoc, Nat.add_comm 1])) := by
have : cur = (pref ++ #[cur] ++ suff)[pref.size] := by simp
simp only [ h] at this
simp [this, getElem_toArray_Rcx_eq]
end Std.PRange

View File

@@ -10,10 +10,12 @@ 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 import Init.Data.Order.Lemmas
public section
open Std PRange
namespace Std.PRange
instance : UpwardEnumerable Nat where
@@ -39,7 +41,7 @@ instance : LawfulUpwardEnumerableLE Nat where
instance : LawfulUpwardEnumerable Nat where
succMany?_zero := by simp [UpwardEnumerable.succMany?]
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
succMany?_succ? := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
ne_of_lt a b hlt := by
have hn := hlt.choose_spec
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
@@ -76,8 +78,7 @@ instance : LawfulRangeSize .closed Nat where
instance : LawfulRangeSize .open Nat := inferInstance
instance : HasFiniteRanges .closed Nat := inferInstance
instance : HasFiniteRanges .open Nat := inferInstance
instance : LinearlyUpwardEnumerable Nat := by
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
instance : LinearlyUpwardEnumerable Nat := inferInstance
/-!
The following instances are used for the implementation of array slices a.k.a. `Subarray`.

View File

@@ -25,4 +25,17 @@ theorem toList_Rco_succ_succ {m n : Nat} :
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := toList_Rco_succ_succ
@[simp]
theorem Nat.size_Rco {a b : Nat} :
(a...b).size = b - a := by
simp only [size, Iterators.Iter.size, Iterators.IteratorSize.size, Iterators.Iter.toIterM,
Internal.iter, init?, RangeSize.size, Id.run_pure]
omega
@[simp]
theorem Nat.size_Rcc {a b : Nat} :
(a...=b).size = b + 1- a := by
simp [Std.PRange.size, Std.Iterators.Iter.size, Std.Iterators.IteratorSize.size,
Std.PRange.Internal.iter, Std.Iterators.Iter.toIterM, Std.PRange.RangeSize.size]
end Std.PRange.Nat

View File

@@ -0,0 +1,382 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Range.Polymorphic.Instances
public import Init.Data.Order.Lemmas
public import Init.Data.UInt
import Init.Omega
public import Init.Data.Range.Polymorphic.BitVec
public section
open Std Std.PRange
namespace UInt8
instance : UpwardEnumerable UInt8 where
succ? i := if i + 1 = 0 then none else some (i + 1)
succMany? n i := if h : i.toNat + n < UInt8.size then some (.ofNatLT _ h) else none
theorem succ?_ofBitVec {x : BitVec 8} :
UpwardEnumerable.succ? (UInt8.ofBitVec x) = UInt8.ofBitVec <$> UpwardEnumerable.succ? x := by
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, UInt8.toBitVec_inj]
split <;> simp_all
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 8} :
UpwardEnumerable.succMany? k (UInt8.ofBitVec x) = UInt8.ofBitVec <$> UpwardEnumerable.succMany? k x := by
simp [succMany?]
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 8} :
UpwardEnumerable.LE (UInt8.ofBitVec x) (UInt8.ofBitVec y) UpwardEnumerable.LE x y := by
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 8} :
UpwardEnumerable.LT (UInt8.ofBitVec x) (UInt8.ofBitVec y) UpwardEnumerable.LT x y := by
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
instance : LawfulUpwardEnumerable UInt8 where
ne_of_lt x y := by
cases x; cases y
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
succMany?_zero x := by
cases x
simpa [succMany?_ofBitVec] using succMany?_zero
succMany?_succ? n x := by
cases x
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
succ?_ofBitVec]
instance : LawfulUpwardEnumerableLE UInt8 where
le_iff x y := by
cases x; cases y
simpa [upwardEnumerableLE_ofBitVec, UInt8.le_iff_toBitVec_le] using
LawfulUpwardEnumerableLE.le_iff _ _
instance : LawfulOrderLT UInt8 := inferInstance
instance : LawfulUpwardEnumerableLT UInt8 := inferInstance
instance : LawfulUpwardEnumerableLT UInt8 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed UInt8 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed UInt8 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open UInt8 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open UInt8 := inferInstance
instance : RangeSize .closed UInt8 where
size bound a := bound.toNat + 1 - a.toNat
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt8} {x : BitVec 8} :
RangeSize.size bound (UInt8.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
simp [RangeSize.size]
instance : LawfulRangeSize .closed UInt8 where
size_eq_zero_of_not_isSatisfied bound x := by
simpa [rangeSizeSize_eq_toBitVec, UInt8.lt_iff_toBitVec_lt] using
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 8) _ _
size_eq_one_of_succ?_eq_none bound x := by
cases x
simpa [rangeSizeSize_eq_toBitVec, UInt8.le_iff_toBitVec_le, succ?_ofBitVec] using
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 8) _ _
size_eq_succ_of_succ?_eq_some bound init x := by
simpa [rangeSizeSize_eq_toBitVec, UInt8.le_iff_toBitVec_le, UInt8.toBitVec_inj, succ?] using
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 8) _ _ _
instance : RangeSize .open UInt8 := RangeSize.openOfClosed
instance : LawfulRangeSize .open UInt8 := inferInstance
end UInt8
namespace UInt16
instance : UpwardEnumerable UInt16 where
succ? i := if i + 1 = 0 then none else some (i + 1)
succMany? n i := if h : i.toNat + n < UInt16.size then some (.ofNatLT _ h) else none
theorem succ?_ofBitVec {x : BitVec 16} :
UpwardEnumerable.succ? (UInt16.ofBitVec x) = UInt16.ofBitVec <$> UpwardEnumerable.succ? x := by
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, UInt16.toBitVec_inj]
split <;> simp_all
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 16} :
UpwardEnumerable.succMany? k (UInt16.ofBitVec x) = UInt16.ofBitVec <$> UpwardEnumerable.succMany? k x := by
simp [succMany?]
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 16} :
UpwardEnumerable.LE (UInt16.ofBitVec x) (UInt16.ofBitVec y) UpwardEnumerable.LE x y := by
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 16} :
UpwardEnumerable.LT (UInt16.ofBitVec x) (UInt16.ofBitVec y) UpwardEnumerable.LT x y := by
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
instance : LawfulUpwardEnumerable UInt16 where
ne_of_lt x y := by
cases x; cases y
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
succMany?_zero x := by
cases x
simpa [succMany?_ofBitVec] using succMany?_zero
succMany?_succ? n x := by
cases x
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
succ?_ofBitVec]
instance : LawfulUpwardEnumerableLE UInt16 where
le_iff x y := by
cases x; cases y
simpa [upwardEnumerableLE_ofBitVec, UInt16.le_iff_toBitVec_le] using
LawfulUpwardEnumerableLE.le_iff _ _
instance : LawfulOrderLT UInt16 := inferInstance
instance : LawfulUpwardEnumerableLT UInt16 := inferInstance
instance : LawfulUpwardEnumerableLT UInt16 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed UInt16 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed UInt16 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open UInt16 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open UInt16 := inferInstance
instance : RangeSize .closed UInt16 where
size bound a := bound.toNat + 1 - a.toNat
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt16} {x : BitVec 16} :
RangeSize.size bound (UInt16.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
simp [RangeSize.size]
instance : LawfulRangeSize .closed UInt16 where
size_eq_zero_of_not_isSatisfied bound x := by
simpa [rangeSizeSize_eq_toBitVec, UInt16.lt_iff_toBitVec_lt] using
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 16) _ _
size_eq_one_of_succ?_eq_none bound x := by
cases x
simpa [rangeSizeSize_eq_toBitVec, UInt16.le_iff_toBitVec_le, succ?_ofBitVec] using
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 16) _ _
size_eq_succ_of_succ?_eq_some bound init x := by
simpa [rangeSizeSize_eq_toBitVec, UInt16.le_iff_toBitVec_le, UInt16.toBitVec_inj, succ?] using
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 16) _ _ _
instance : RangeSize .open UInt16 := RangeSize.openOfClosed
instance : LawfulRangeSize .open UInt16 := inferInstance
end UInt16
namespace UInt32
instance : UpwardEnumerable UInt32 where
succ? i := if i + 1 = 0 then none else some (i + 1)
succMany? n i := if h : i.toNat + n < UInt32.size then some (.ofNatLT _ h) else none
theorem succ?_ofBitVec {x : BitVec 32} :
UpwardEnumerable.succ? (UInt32.ofBitVec x) = UInt32.ofBitVec <$> UpwardEnumerable.succ? x := by
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, UInt32.toBitVec_inj]
split <;> simp_all
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 32} :
UpwardEnumerable.succMany? k (UInt32.ofBitVec x) = UInt32.ofBitVec <$> UpwardEnumerable.succMany? k x := by
simp [succMany?]
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 32} :
UpwardEnumerable.LE (UInt32.ofBitVec x) (UInt32.ofBitVec y) UpwardEnumerable.LE x y := by
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 32} :
UpwardEnumerable.LT (UInt32.ofBitVec x) (UInt32.ofBitVec y) UpwardEnumerable.LT x y := by
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
instance : LawfulUpwardEnumerable UInt32 where
ne_of_lt x y := by
cases x; cases y
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
succMany?_zero x := by
cases x
simpa [succMany?_ofBitVec] using succMany?_zero
succMany?_succ? n x := by
cases x
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
succ?_ofBitVec]
instance : LawfulUpwardEnumerableLE UInt32 where
le_iff x y := by
cases x; cases y
simpa [upwardEnumerableLE_ofBitVec, UInt32.le_iff_toBitVec_le] using
LawfulUpwardEnumerableLE.le_iff _ _
instance : LawfulOrderLT UInt32 := inferInstance
instance : LawfulUpwardEnumerableLT UInt32 := inferInstance
instance : LawfulUpwardEnumerableLT UInt32 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed UInt32 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed UInt32 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open UInt32 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open UInt32 := inferInstance
instance : RangeSize .closed UInt32 where
size bound a := bound.toNat + 1 - a.toNat
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt32} {x : BitVec 32} :
RangeSize.size bound (UInt32.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
simp [RangeSize.size]
instance : LawfulRangeSize .closed UInt32 where
size_eq_zero_of_not_isSatisfied bound x := by
simpa [rangeSizeSize_eq_toBitVec, UInt32.lt_iff_toBitVec_lt] using
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 32) _ _
size_eq_one_of_succ?_eq_none bound x := by
cases x
simpa [rangeSizeSize_eq_toBitVec, UInt32.le_iff_toBitVec_le, succ?_ofBitVec] using
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 32) _ _
size_eq_succ_of_succ?_eq_some bound init x := by
simpa [rangeSizeSize_eq_toBitVec, UInt32.le_iff_toBitVec_le, UInt32.toBitVec_inj, succ?] using
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 32) _ _ _
instance : RangeSize .open UInt32 := RangeSize.openOfClosed
instance : LawfulRangeSize .open UInt32 := inferInstance
end UInt32
namespace UInt64
instance : UpwardEnumerable UInt64 where
succ? i := if i + 1 = 0 then none else some (i + 1)
succMany? n i := if h : i.toNat + n < UInt64.size then some (.ofNatLT _ h) else none
theorem succ?_ofBitVec {x : BitVec 64} :
UpwardEnumerable.succ? (UInt64.ofBitVec x) = UInt64.ofBitVec <$> UpwardEnumerable.succ? x := by
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, UInt64.toBitVec_inj]
split <;> simp_all
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 64} :
UpwardEnumerable.succMany? k (UInt64.ofBitVec x) = UInt64.ofBitVec <$> UpwardEnumerable.succMany? k x := by
simp [succMany?]
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 64} :
UpwardEnumerable.LE (UInt64.ofBitVec x) (UInt64.ofBitVec y) UpwardEnumerable.LE x y := by
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 64} :
UpwardEnumerable.LT (UInt64.ofBitVec x) (UInt64.ofBitVec y) UpwardEnumerable.LT x y := by
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
instance : LawfulUpwardEnumerable UInt64 where
ne_of_lt x y := by
cases x; cases y
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
succMany?_zero x := by
cases x
simpa [succMany?_ofBitVec] using succMany?_zero
succMany?_succ? n x := by
cases x
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
succ?_ofBitVec]
instance : LawfulUpwardEnumerableLE UInt64 where
le_iff x y := by
cases x; cases y
simpa [upwardEnumerableLE_ofBitVec, UInt64.le_iff_toBitVec_le] using
LawfulUpwardEnumerableLE.le_iff _ _
instance : LawfulOrderLT UInt64 := inferInstance
instance : LawfulUpwardEnumerableLT UInt64 := inferInstance
instance : LawfulUpwardEnumerableLT UInt64 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed UInt64 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed UInt64 := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open UInt64 := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open UInt64 := inferInstance
instance : RangeSize .closed UInt64 where
size bound a := bound.toNat + 1 - a.toNat
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt64} {x : BitVec 64} :
RangeSize.size bound (UInt64.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
simp [RangeSize.size]
instance : LawfulRangeSize .closed UInt64 where
size_eq_zero_of_not_isSatisfied bound x := by
simpa [rangeSizeSize_eq_toBitVec, UInt64.lt_iff_toBitVec_lt] using
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 64) _ _
size_eq_one_of_succ?_eq_none bound x := by
cases x
simpa [rangeSizeSize_eq_toBitVec, UInt64.le_iff_toBitVec_le, succ?_ofBitVec] using
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 64) _ _
size_eq_succ_of_succ?_eq_some bound init x := by
simpa [rangeSizeSize_eq_toBitVec, UInt64.le_iff_toBitVec_le, UInt64.toBitVec_inj, succ?] using
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 64) _ _ _
instance : RangeSize .open UInt64 := RangeSize.openOfClosed
instance : LawfulRangeSize .open UInt64 := inferInstance
end UInt64
namespace USize
instance : UpwardEnumerable USize where
succ? i := if i + 1 = 0 then none else some (i + 1)
succMany? n i := if h : i.toNat + n < USize.size then some (.ofNatLT _ h) else none
theorem succ?_ofBitVec {x : BitVec System.Platform.numBits} :
UpwardEnumerable.succ? (USize.ofBitVec x) = USize.ofBitVec <$> UpwardEnumerable.succ? x := by
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, USize.toBitVec_inj]
split <;> simp_all
theorem succMany?_ofBitVec {k : Nat} {x : BitVec System.Platform.numBits} :
UpwardEnumerable.succMany? k (USize.ofBitVec x) = USize.ofBitVec <$> UpwardEnumerable.succMany? k x := by
simp [succMany?]
theorem upwardEnumerableLE_ofBitVec {x y : BitVec System.Platform.numBits} :
UpwardEnumerable.LE (USize.ofBitVec x) (USize.ofBitVec y) UpwardEnumerable.LE x y := by
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
theorem upwardEnumerableLT_ofBitVec {x y : BitVec System.Platform.numBits} :
UpwardEnumerable.LT (USize.ofBitVec x) (USize.ofBitVec y) UpwardEnumerable.LT x y := by
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
instance : LawfulUpwardEnumerable USize where
ne_of_lt x y := by
cases x; cases y
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
succMany?_zero x := by
cases x
simpa [succMany?_ofBitVec] using succMany?_zero
succMany?_succ? n x := by
cases x
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
succ?_ofBitVec]
instance : LawfulUpwardEnumerableLE USize where
le_iff x y := by
cases x; cases y
simpa [upwardEnumerableLE_ofBitVec, USize.le_iff_toBitVec_le] using
LawfulUpwardEnumerableLE.le_iff _ _
instance : LawfulOrderLT USize := inferInstance
instance : LawfulUpwardEnumerableLT USize := inferInstance
instance : LawfulUpwardEnumerableLT USize := inferInstance
instance : LawfulUpwardEnumerableLowerBound .closed USize := inferInstance
instance : LawfulUpwardEnumerableUpperBound .closed USize := inferInstance
instance : LawfulUpwardEnumerableLowerBound .open USize := inferInstance
instance : LawfulUpwardEnumerableUpperBound .open USize := inferInstance
instance : RangeSize .closed USize where
size bound a := bound.toNat + 1 - a.toNat
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed USize} {x : BitVec System.Platform.numBits} :
RangeSize.size bound (USize.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
simp [RangeSize.size]
instance : LawfulRangeSize .closed USize where
size_eq_zero_of_not_isSatisfied bound x := by
simpa [rangeSizeSize_eq_toBitVec, USize.lt_iff_toBitVec_lt] using
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec System.Platform.numBits) _ _
size_eq_one_of_succ?_eq_none bound x := by
cases x
simpa [rangeSizeSize_eq_toBitVec, USize.le_iff_toBitVec_le, succ?_ofBitVec] using
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec System.Platform.numBits) _ _
size_eq_succ_of_succ?_eq_some bound init x := by
simpa [rangeSizeSize_eq_toBitVec, USize.le_iff_toBitVec_le, USize.toBitVec_inj, succ?] using
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec System.Platform.numBits) _ _ _
instance : RangeSize .open USize := RangeSize.openOfClosed
instance : LawfulRangeSize .open USize := inferInstance
end USize

View File

@@ -40,7 +40,6 @@ 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?)
/--
@@ -80,7 +79,6 @@ class Least? (α : Type u) where
-/
least? : Option α
attribute [simp] Least?.least?
export Least? (least?)
/--
@@ -95,7 +93,7 @@ class LawfulUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
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 : α) :
succMany?_succ? (n : Nat) (a : α) :
succMany? (n + 1) a = (succMany? n a).bind succ?
theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
@@ -105,7 +103,7 @@ theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnume
theorem UpwardEnumerable.succMany?_succ? [UpwardEnumerable α] [LawfulUpwardEnumerable α]
{n : Nat} {a : α} :
succMany? (n + 1) a = (succMany? n a).bind succ? :=
LawfulUpwardEnumerable.succMany?_succ n a
LawfulUpwardEnumerable.succMany?_succ? n a
@[deprecated succMany?_succ? (since := "2025-09-03")]
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]

View File

@@ -96,8 +96,7 @@ theorem Int8.toBitVec.inj : {x y : Int8} → x.toBitVec = y.toBitVec → x = y
/-- Obtains the `Int8` that is 2's complement equivalent to the `UInt8`. -/
@[inline] def UInt8.toInt8 (i : UInt8) : Int8 := Int8.ofUInt8 i
@[inline, deprecated UInt8.toInt8 (since := "2025-02-13"), inherit_doc UInt8.toInt8]
def Int8.mk (i : UInt8) : Int8 := UInt8.toInt8 i
/--
Converts an arbitrary-precision integer to an 8-bit integer, wrapping on overflow or underflow.
@@ -159,8 +158,7 @@ Converts an 8-bit signed integer to a natural number, mapping all negative numbe
Use `Int8.toBitVec` to obtain the two's complement representation.
-/
@[inline] def Int8.toNatClampNeg (i : Int8) : Nat := i.toInt.toNat
@[inline, deprecated Int8.toNatClampNeg (since := "2025-02-13"), inherit_doc Int8.toNatClampNeg]
def Int8.toNat (i : Int8) : Nat := i.toInt.toNat
/-- Obtains the `Int8` whose 2's complement representation is the given `BitVec 8`. -/
@[inline] def Int8.ofBitVec (b : BitVec 8) : Int8 := b
/--
@@ -449,8 +447,7 @@ theorem Int16.toBitVec.inj : {x y : Int16} → x.toBitVec = y.toBitVec → x = y
/-- Obtains the `Int16` that is 2's complement equivalent to the `UInt16`. -/
@[inline] def UInt16.toInt16 (i : UInt16) : Int16 := Int16.ofUInt16 i
@[inline, deprecated UInt16.toInt16 (since := "2025-02-13"), inherit_doc UInt16.toInt16]
def Int16.mk (i : UInt16) : Int16 := UInt16.toInt16 i
/--
Converts an arbitrary-precision integer to a 16-bit signed integer, wrapping on overflow or underflow.
@@ -514,8 +511,7 @@ Converts a 16-bit signed integer to a natural number, mapping all negative numbe
Use `Int16.toBitVec` to obtain the two's complement representation.
-/
@[inline] def Int16.toNatClampNeg (i : Int16) : Nat := i.toInt.toNat
@[inline, deprecated Int16.toNatClampNeg (since := "2025-02-13"), inherit_doc Int16.toNatClampNeg]
def Int16.toNat (i : Int16) : Nat := i.toInt.toNat
/-- Obtains the `Int16` whose 2's complement representation is the given `BitVec 16`. -/
@[inline] def Int16.ofBitVec (b : BitVec 16) : Int16 := b
/--
@@ -820,8 +816,7 @@ theorem Int32.toBitVec.inj : {x y : Int32} → x.toBitVec = y.toBitVec → x = y
/-- Obtains the `Int32` that is 2's complement equivalent to the `UInt32`. -/
@[inline] def UInt32.toInt32 (i : UInt32) : Int32 := Int32.ofUInt32 i
@[inline, deprecated UInt32.toInt32 (since := "2025-02-13"), inherit_doc UInt32.toInt32]
def Int32.mk (i : UInt32) : Int32 := UInt32.toInt32 i
/--
Converts an arbitrary-precision integer to a 32-bit integer, wrapping on overflow or underflow.
@@ -886,8 +881,7 @@ Converts a 32-bit signed integer to a natural number, mapping all negative numbe
Use `Int32.toBitVec` to obtain the two's complement representation.
-/
@[inline] def Int32.toNatClampNeg (i : Int32) : Nat := i.toInt.toNat
@[inline, deprecated Int32.toNatClampNeg (since := "2025-02-13"), inherit_doc Int32.toNatClampNeg]
def Int32.toNat (i : Int32) : Nat := i.toInt.toNat
/-- Obtains the `Int32` whose 2's complement representation is the given `BitVec 32`. -/
@[inline] def Int32.ofBitVec (b : BitVec 32) : Int32 := b
/--
@@ -1207,8 +1201,7 @@ theorem Int64.toBitVec.inj : {x y : Int64} → x.toBitVec = y.toBitVec → x = y
/-- Obtains the `Int64` that is 2's complement equivalent to the `UInt64`. -/
@[inline] def UInt64.toInt64 (i : UInt64) : Int64 := Int64.ofUInt64 i
@[inline, deprecated UInt64.toInt64 (since := "2025-02-13"), inherit_doc UInt64.toInt64]
def Int64.mk (i : UInt64) : Int64 := UInt64.toInt64 i
/--
Converts an arbitrary-precision integer to a 64-bit integer, wrapping on overflow or underflow.
@@ -1278,8 +1271,7 @@ Converts a 64-bit signed integer to a natural number, mapping all negative numbe
Use `Int64.toBitVec` to obtain the two's complement representation.
-/
@[inline] def Int64.toNatClampNeg (i : Int64) : Nat := i.toInt.toNat
@[inline, deprecated Int64.toNatClampNeg (since := "2025-02-13"), inherit_doc Int64.toNatClampNeg]
def Int64.toNat (i : Int64) : Nat := i.toInt.toNat
/-- Obtains the `Int64` whose 2's complement representation is the given `BitVec 64`. -/
@[inline] def Int64.ofBitVec (b : BitVec 64) : Int64 := b
/--
@@ -1613,8 +1605,7 @@ theorem ISize.toBitVec.inj : {x y : ISize} → x.toBitVec = y.toBitVec → x = y
/-- Obtains the `ISize` that is 2's complement equivalent to the `USize`. -/
@[inline] def USize.toISize (i : USize) : ISize := ISize.ofUSize i
@[inline, deprecated USize.toISize (since := "2025-02-13"), inherit_doc USize.toISize]
def ISize.mk (i : USize) : ISize := USize.toISize i
/--
Converts an arbitrary-precision integer to a word-sized signed integer, wrapping around on over- or
underflow.
@@ -1647,8 +1638,7 @@ Converts a word-sized signed integer to a natural number, mapping all negative n
Use `ISize.toBitVec` to obtain the two's complement representation.
-/
@[inline] def ISize.toNatClampNeg (i : ISize) : Nat := i.toInt.toNat
@[inline, deprecated ISize.toNatClampNeg (since := "2025-02-13"), inherit_doc ISize.toNatClampNeg]
def ISize.toNat (i : ISize) : Nat := i.toInt.toNat
/-- Obtains the `ISize` whose 2's complement representation is the given `BitVec`. -/
@[inline] def ISize.ofBitVec (b : BitVec System.Platform.numBits) : ISize := b
/--

View File

@@ -10,7 +10,7 @@ public import Init.Core
public import Init.Data.Slice.Array.Basic
import Init.Data.Iterators.Combinators.Attach
import Init.Data.Iterators.Combinators.FilterMap
import Init.Data.Iterators.Combinators.ULift
public import Init.Data.Iterators.Combinators.ULift
public import Init.Data.Iterators.Consumers.Collect
public import Init.Data.Iterators.Consumers.Loop
public import Init.Data.Range.Polymorphic.Basic
@@ -31,7 +31,6 @@ open Std Slice PRange Iterators
variable {shape : RangeShape} {α : Type u}
@[no_expose]
instance {s : Subarray α} : ToIterator s Id α :=
.of _
(PRange.Internal.iter (s.internalRepresentation.start...<s.internalRepresentation.stop)

View File

@@ -8,6 +8,7 @@ module
prelude
public import Init.Data.String.Basic
public import Init.Data.String.Bootstrap
public import Init.Data.String.Decode
public import Init.Data.String.Extra
public import Init.Data.String.Lemmas
public import Init.Data.String.Repr

View File

@@ -9,11 +9,370 @@ prelude
public import Init.Data.List.Basic
public import Init.Data.Char.Basic
public import Init.Data.String.Bootstrap
public import Init.Data.ByteArray.Basic
public import Init.Data.String.Decode
import Init.Data.ByteArray.Lemmas
public section
universe u
section
@[simp]
theorem List.utf8Encode_nil : List.utf8Encode [] = ByteArray.empty := by simp [utf8Encode]
theorem List.utf8Encode_singleton {c : Char} : [c].utf8Encode = (String.utf8EncodeChar c).toByteArray := by
simp [utf8Encode]
@[simp]
theorem List.utf8Encode_append {l l' : List Char} :
(l ++ l').utf8Encode = l.utf8Encode ++ l'.utf8Encode := by
simp [utf8Encode]
theorem List.utf8Encode_cons {c : Char} {l : List Char} : (c :: l).utf8Encode = [c].utf8Encode ++ l.utf8Encode := by
rw [ singleton_append, List.utf8Encode_append]
@[simp]
theorem String.utf8EncodeChar_ne_nil {c : Char} : String.utf8EncodeChar c [] := by
fun_cases String.utf8EncodeChar with simp
@[simp]
theorem List.utf8Encode_eq_empty {l : List Char} : l.utf8Encode = ByteArray.empty l = [] := by
simp [utf8Encode, List.eq_nil_iff_forall_not_mem]
theorem ByteArray.isValidUtf8_utf8Encode {l : List Char} : IsValidUtf8 l.utf8Encode :=
.intro l rfl
@[simp]
theorem ByteArray.isValidUtf8_empty : IsValidUtf8 ByteArray.empty :=
.intro [] (by simp)
theorem Char.isValidUtf8_toByteArray_utf8EncodeChar {c : Char} :
ByteArray.IsValidUtf8 (String.utf8EncodeChar c).toByteArray :=
.intro [c] (by simp [List.utf8Encode_singleton])
theorem ByteArray.IsValidUtf8.append {b b' : ByteArray} (h : IsValidUtf8 b) (h' : IsValidUtf8 b') :
IsValidUtf8 (b ++ b') := by
rcases h with m, rfl
rcases h' with m', rfl
exact .intro (m ++ m') (by simp)
theorem ByteArray.isValidUtf8_utf8Encode_singleton_append_iff {b : ByteArray} {c : Char} :
IsValidUtf8 ([c].utf8Encode ++ b) IsValidUtf8 b := by
refine ?_, fun h => IsValidUtf8.append isValidUtf8_utf8Encode h
rintro l, hl
match l with
| [] => simp at hl
| d::l =>
obtain rfl : c = d := by
replace hl := congrArg (fun l => utf8DecodeChar? l 0) hl
simpa [List.utf8DecodeChar?_utf8Encode_singleton_append,
List.utf8DecodeChar?_utf8Encode_cons] using hl
rw [ List.singleton_append (l := l), List.utf8Encode_append,
ByteArray.append_right_inj] at hl
exact hl isValidUtf8_utf8Encode
@[expose]
def ByteArray.utf8Decode? (b : ByteArray) : Option (Array Char) :=
go (b.size + 1) 0 #[] (by simp) (by simp)
where
go (fuel : Nat) (i : Nat) (acc : Array Char) (hi : i b.size) (hf : b.size - i < fuel) : Option (Array Char) :=
match fuel, hf with
| fuel + 1, _ =>
if i = b.size then
some acc
else
match h : utf8DecodeChar? b i with
| none => none
| some c => go fuel (i + c.utf8Size) (acc.push c)
(le_size_of_utf8DecodeChar?_eq_some h)
(have := c.utf8Size_pos; have := le_size_of_utf8DecodeChar?_eq_some h; by omega)
termination_by structural fuel
theorem ByteArray.utf8Decode?.go.congr {b b' : ByteArray} {fuel fuel' i i' : Nat} {acc acc' : Array Char} {hi hi' hf hf'}
(hbb' : b = b') (hii' : i = i') (hacc : acc = acc') :
ByteArray.utf8Decode?.go b fuel i acc hi hf = ByteArray.utf8Decode?.go b' fuel' i' acc' hi' hf' := by
subst hbb' hii' hacc
fun_induction ByteArray.utf8Decode?.go b fuel i acc hi hf generalizing fuel' with
| case1 =>
rw [go.eq_def]
split
simp
| case2 =>
rw [go.eq_def]
split <;> split
· simp_all
· split <;> simp_all
| case3 =>
conv => rhs; rw [go.eq_def]
split <;> split
· simp_all
· split
· simp_all
· rename_i c₁ hc₁ ih _ _ _ _ _ c₂ hc₂
obtain rfl : c₁ = c₂ := by rw [ Option.some_inj, hc₁, hc₂]
apply ih
@[simp]
theorem ByteArray.utf8Decode?_empty : ByteArray.empty.utf8Decode? = some #[] := by
simp [utf8Decode?, utf8Decode?.go]
private theorem ByteArray.isSome_utf8Decode?go_iff {b : ByteArray} {fuel i : Nat} {hi : i b.size} {hf} {acc : Array Char} :
(ByteArray.utf8Decode?.go b fuel i acc hi hf).isSome IsValidUtf8 (b.extract i b.size) := by
fun_induction ByteArray.utf8Decode?.go with
| case1 => simp
| case2 fuel i hi hf acc h₁ h₂ =>
simp only [Option.isSome_none, Bool.false_eq_true, false_iff]
rintro l, hl
have : l [] := by
rintro rfl
simp at hl
omega
rw [ l.cons_head_tail this] at hl
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract, hl, List.utf8DecodeChar?_utf8Encode_cons] at h₂
simp at h₂
| case3 i acc hi fuel hf h₁ c h₂ ih =>
rw [ih]
have h₂' := h₂
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂'
obtain l, hl := exists_of_utf8DecodeChar?_eq_some h₂'
rw [ByteArray.extract_eq_extract_append_extract (i := i) (i + c.utf8Size) (by omega)
(le_size_of_utf8DecodeChar?_eq_some h₂)] at hl
rw [ByteArray.append_inj_left hl (by have := le_size_of_utf8DecodeChar?_eq_some h₂; simp; omega),
List.utf8Encode_singleton, isValidUtf8_utf8Encode_singleton_append_iff]
theorem ByteArray.isSome_utf8Decode?_iff {b : ByteArray} :
b.utf8Decode?.isSome IsValidUtf8 b := by
rw [utf8Decode?, isSome_utf8Decode?go_iff, extract_zero_size]
@[simp]
theorem String.bytes_empty : "".bytes = ByteArray.empty := (rfl)
/--
Appends two strings. Usually accessed via the `++` operator.
The internal implementation will perform destructive updates if the string is not shared.
Examples:
* `"abc".append "def" = "abcdef"`
* `"abc" ++ "def" = "abcdef"`
* `"" ++ "" = ""`
-/
@[extern "lean_string_append", expose]
def String.append (s t : String) : String where
bytes := s.bytes ++ t.bytes
isValidUtf8 := s.isValidUtf8.append t.isValidUtf8
instance : Append String where
append s t := s.append t
@[simp]
theorem String.bytes_append {s t : String} : (s ++ t).bytes = s.bytes ++ t.bytes := (rfl)
theorem String.bytes_inj {s t : String} : s.bytes = t.bytes s = t := by
refine fun h => ?_, (· rfl)
rcases s with s
rcases t with t
subst h
rfl
@[simp]
theorem String.empty_append {s : String} : "" ++ s = s := by
simp [ String.bytes_inj]
@[simp]
theorem String.append_empty {s : String} : s ++ "" = s := by
simp [ String.bytes_inj]
@[simp] theorem List.bytes_asString {l : List Char} : l.asString.bytes = l.utf8Encode := by
simp [List.asString, String.mk]
@[simp]
theorem List.asString_nil : List.asString [] = "" := by
simp [ String.bytes_inj]
@[simp]
theorem List.asString_append {l₁ l₂ : List Char} : (l₁ ++ l₂).asString = l₁.asString ++ l₂.asString := by
simp [ String.bytes_inj]
@[expose]
def String.Internal.toArray (b : String) : Array Char :=
b.bytes.utf8Decode?.get (b.bytes.isSome_utf8Decode?_iff.2 b.isValidUtf8)
@[simp]
theorem String.Internal.toArray_empty : String.Internal.toArray "" = #[] := by
simp [toArray]
@[extern "lean_string_data", expose]
def String.data (b : String) : List Char :=
(String.Internal.toArray b).toList
@[simp]
theorem String.data_empty : "".data = [] := by
simp [data]
/--
Returns the length of a string in Unicode code points.
Examples:
* `"".length = 0`
* `"abc".length = 3`
* `"L∃∀N".length = 4`
-/
@[extern "lean_string_length"]
def String.length (b : String) : Nat :=
b.data.length
@[simp]
theorem String.Internal.size_toArray {b : String} : (String.Internal.toArray b).size = b.length :=
(rfl)
@[simp]
theorem String.length_data {b : String} : b.data.length = b.length := (rfl)
theorem String.exists_eq_asString (s : String) :
l : List Char, s = l.asString := by
rcases s with _, l, rfl
refine l, by simp [ String.bytes_inj]
private theorem ByteArray.utf8Decode?go_eq_utf8Decode?go_extract {b : ByteArray} {fuel i : Nat} {hi : i b.size} {hf} {acc : Array Char} :
utf8Decode?.go b fuel i acc hi hf = (utf8Decode?.go (b.extract i b.size) fuel 0 #[] (by simp) (by simp [hf])).map (acc ++ ·) := by
fun_cases utf8Decode?.go b fuel i acc hi hf with
| case1 =>
rw [utf8Decode?.go]
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
List.nil_append]
rw [if_pos (by omega)]
simp
| case2 fuel hf₁ h₁ h₂ hf₂ =>
rw [utf8Decode?.go]
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
List.nil_append]
rw [if_neg (by omega)]
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂
split <;> simp_all
| case3 fuel hf₁ h₁ c h₂ hf₂ =>
conv => rhs; rw [utf8Decode?.go]
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
List.nil_append]
rw [if_neg (by omega)]
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂
split
· simp_all
· rename_i c' hc'
obtain rfl : c = c' := by
rw [ Option.some_inj, h₂, hc']
have := c.utf8Size_pos
conv => lhs; rw [ByteArray.utf8Decode?go_eq_utf8Decode?go_extract]
conv => rhs; rw [ByteArray.utf8Decode?go_eq_utf8Decode?go_extract]
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Option.map_map, ByteArray.extract_extract]
have : (fun x => acc ++ x) (fun x => #[c] ++ x) = fun x => acc.push c ++ x := by funext; simp
simp [(by omega : i + (b.size - i) = b.size), this]
theorem ByteArray.utf8Decode?_utf8Encode_singleton_append {l : ByteArray} {c : Char} :
([c].utf8Encode ++ l).utf8Decode? = l.utf8Decode?.map (#[c] ++ ·) := by
rw [utf8Decode?, utf8Decode?.go,
if_neg (by simp [List.utf8Encode_singleton]; have := c.utf8Size_pos; omega)]
split
· simp_all [List.utf8DecodeChar?_utf8Encode_singleton_append]
· rename_i d h
obtain rfl : c = d := by simpa [List.utf8DecodeChar?_utf8Encode_singleton_append] using h
rw [utf8Decode?go_eq_utf8Decode?go_extract, utf8Decode?]
simp only [List.push_toArray, List.nil_append, Nat.zero_add]
congr 1
apply ByteArray.utf8Decode?.go.congr _ rfl rfl
apply extract_append_eq_right
simp [List.utf8Encode_singleton]
@[simp]
theorem List.utf8Decode?_utf8Encode {l : List Char} :
l.utf8Encode.utf8Decode? = some l.toArray := by
induction l with
| nil => simp
| cons c l ih =>
rw [ List.singleton_append, List.utf8Encode_append]
simp only [ByteArray.utf8Decode?_utf8Encode_singleton_append, cons_append, nil_append,
Option.map_eq_some_iff, Array.append_eq_toArray_iff, cons.injEq, true_and]
refine l.toArray, ih, by simp
@[simp]
theorem ByteArray.utf8Encode_get_utf8Decode? {b : ByteArray} {h} :
(b.utf8Decode?.get h).toList.utf8Encode = b := by
obtain l, rfl := isSome_utf8Decode?_iff.1 h
simp
@[simp]
theorem List.data_asString {l : List Char} : l.asString.data = l := by
simp [String.data, String.Internal.toArray]
@[simp]
theorem String.asString_data {b : String} : b.data.asString = b := by
obtain l, rfl := String.exists_eq_asString b
rw [List.data_asString]
theorem List.asString_injective {l₁ l₂ : List Char} (h : l₁.asString = l₂.asString) : l₁ = l₂ := by
simpa using congrArg String.data h
theorem List.asString_inj {l₁ l₂ : List Char} : l₁.asString = l₂.asString l₁ = l₂ :=
asString_injective, (· rfl)
theorem String.data_injective {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ := by
simpa using congrArg List.asString h
theorem String.data_inj {s₁ s₂ : String} : s₁.data = s₂.data s₁ = s₂ :=
data_injective, (· rfl)
@[simp]
theorem String.data_append {l₁ l₂ : String} : (l₁ ++ l₂).data = l₁.data ++ l₂.data := by
apply List.asString_injective
simp
@[simp]
theorem String.utf8encode_data {b : String} : b.data.utf8Encode = b.bytes := by
have := congrArg String.bytes (String.asString_data (b := b))
rwa [ List.bytes_asString]
@[simp]
theorem String.utf8ByteSize_empty : "".utf8ByteSize = 0 := (rfl)
@[simp]
theorem String.utf8ByteSize_append {s t : String} :
(s ++ t).utf8ByteSize = s.utf8ByteSize + t.utf8ByteSize := by
simp [utf8ByteSize]
@[simp]
theorem String.size_bytes {s : String} : s.bytes.size = s.utf8ByteSize := rfl
@[simp]
theorem String.bytes_push {s : String} {c : Char} : (s.push c).bytes = s.bytes ++ [c].utf8Encode := by
simp [push]
-- This is just to keep the proof of `set_next_add` below from breaking; if that lemma goes away
-- or the proof is rewritten, it can be removed.
private noncomputable def String.utf8ByteSize' : String Nat
| s => go s.data
where
go : List Char Nat
| [] => 0
| c::cs => go cs + c.utf8Size
private theorem String.utf8ByteSize'_eq (s : String) : s.utf8ByteSize' = s.utf8ByteSize := by
suffices l, utf8ByteSize'.go l = l.asString.utf8ByteSize by
obtain m, rfl := s.exists_eq_asString
rw [utf8ByteSize', this, asString_data]
intro l
induction l with
| nil => simp [utf8ByteSize'.go]
| cons c cs ih =>
rw [utf8ByteSize'.go, ih, List.singleton_append, List.asString_append,
utf8ByteSize_append, Nat.add_comm]
congr
rw [ size_bytes, List.bytes_asString, List.utf8Encode_singleton,
List.size_toByteArray, length_utf8EncodeChar]
end
namespace String
instance : HAdd String.Pos String.Pos String.Pos where
@@ -54,8 +413,6 @@ instance : LT String :=
instance decidableLT (s₁ s₂ : @& String) : Decidable (s₁ < s₂) :=
List.decidableLT s₁.data s₂.data
/--
Non-strict inequality on strings, typically used via the `≤` operator.
@@ -69,32 +426,6 @@ instance : LE String :=
instance decLE (s₁ s₂ : String) : Decidable (s₁ s₂) :=
inferInstanceAs (Decidable (Not _))
/--
Returns the length of a string in Unicode code points.
Examples:
* `"".length = 0`
* `"abc".length = 3`
* `"L∃∀N".length = 4`
-/
@[extern "lean_string_length", expose]
def length : (@& String) Nat
| s => s.length
/--
Appends two strings. Usually accessed via the `++` operator.
The internal implementation will perform destructive updates if the string is not shared.
Examples:
* `"abc".append "def" = "abcdef"`
* `"abc" ++ "def" = "abcdef"`
* `"" ++ "" = ""`
-/
@[extern "lean_string_append", expose]
def append : String (@& String) String
| a, b => a ++ b
/--
Converts a string to a list of characters.
@@ -153,8 +484,7 @@ Examples:
-/
@[extern "lean_string_utf8_get", expose]
def get (s : @& String) (p : @& Pos) : Char :=
match s with
| s => utf8GetAux s 0 p
utf8GetAux s.data 0 p
def utf8GetAux? : List Char Pos Pos Option Char
| [], _, _ => none
@@ -175,7 +505,7 @@ Examples:
-/
@[extern "lean_string_utf8_get_opt"]
def get? : (@& String) (@& Pos) Option Char
| s, p => utf8GetAux? s 0 p
| s, p => utf8GetAux? s.data 0 p
/--
Returns the character at position `p` of a string. Panics if `p` is not a valid position.
@@ -191,7 +521,7 @@ Examples
@[extern "lean_string_utf8_get_bang", expose]
def get! (s : @& String) (p : @& Pos) : Char :=
match s with
| s => utf8GetAux s 0 p
| s => utf8GetAux s.data 0 p
def utf8SetAux (c' : Char) : List Char Pos Pos List Char
| [], _, _ => []
@@ -214,7 +544,7 @@ Examples:
-/
@[extern "lean_string_utf8_set"]
def set : String (@& Pos) Char String
| s, i, c => utf8SetAux c s 0 i
| s, i, c => (utf8SetAux c s.data 0 i).asString
/--
Replaces the character at position `p` in the string `s` with the result of applying `f` to that
@@ -270,7 +600,7 @@ Examples:
-/
@[extern "lean_string_utf8_prev", expose]
def prev : (@& String) (@& Pos) Pos
| s, p => utf8PrevAux s 0 p
| s, p => utf8PrevAux s.data 0 p
/--
Returns the first character in `s`. If `s = ""`, returns `(default : Char)`.
@@ -336,7 +666,7 @@ Examples:
@[extern "lean_string_utf8_get_fast", expose]
def get' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Char :=
match s with
| s => utf8GetAux s 0 p
| s => utf8GetAux s.data 0 p
/--
Returns the next position in a string after position `p`. The result is unspecified if `p` is not a
@@ -360,16 +690,6 @@ def next' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Pos :=
let c := get s p
p + c
theorem _root_.Char.utf8Size_pos (c : Char) : 0 < c.utf8Size := by
repeat first | apply iteInduction (motive := (0 < ·)) <;> intros | decide
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
@@ -534,7 +854,7 @@ Examples:
-/
@[extern "lean_string_utf8_extract", expose]
def extract : (@& String) (@& Pos) (@& Pos) String
| s, b, e => if b.byteIdx e.byteIdx then "" else go₁ s 0 b e
| s, b, e => if b.byteIdx e.byteIdx then "" else (go₁ s.data 0 b e).asString
where
go₁ : List Char Pos Pos Pos List Char
| [], _, _, _ => []
@@ -1030,37 +1350,31 @@ theorem utf8SetAux_of_gt (c' : Char) : ∀ (cs : List Char) {i p : Pos}, i > p
theorem set_next_add (s : String) (i : Pos) (c : Char) (b₁ b₂)
(h : (s.next i).1 + b₁ = s.endPos.1 + b₂) :
((s.set i c).next i).1 + b₁ = (s.set i c).endPos.1 + b₂ := by
simp [next, get, set, endPos, utf8ByteSize] at h
simp [next, get, set, endPos, utf8ByteSize'_eq, utf8ByteSize'] at h
rw [Nat.add_comm i.1, Nat.add_assoc] at h
let rec foo : cs a b₁ b₂,
(utf8GetAux cs a i).utf8Size + b₁ = utf8ByteSize.go cs + b₂
(utf8GetAux (utf8SetAux c cs a i) a i).utf8Size + b₁ = utf8ByteSize.go (utf8SetAux c cs a i) + b₂
(utf8GetAux cs a i).utf8Size + b₁ = utf8ByteSize'.go cs + b₂
(utf8GetAux (utf8SetAux c cs a i) a i).utf8Size + b₁ = utf8ByteSize'.go (utf8SetAux c cs a i) + b₂
| [], _, _, _, h => h
| c'::cs, a, b₁, b₂, h => by
unfold utf8SetAux
apply iteInduction (motive := fun p => (utf8GetAux p a i).utf8Size + b₁ = utf8ByteSize.go p + b₂) <;>
intro h' <;> simp [utf8GetAux, h', utf8ByteSize.go] at h
apply iteInduction (motive := fun p => (utf8GetAux p a i).utf8Size + b₁ = utf8ByteSize'.go p + b₂) <;>
intro h' <;> simp [utf8GetAux, h', utf8ByteSize'.go] at h
next =>
rw [Nat.add_assoc, Nat.add_left_comm] at h ; rw [Nat.add_left_cancel h]
next =>
rw [Nat.add_assoc] at h
refine foo cs (a + c') b₁ (c'.utf8Size + b₂) h
exact foo s.1 0 _ _ h
exact foo s.data 0 _ _ h
theorem mapAux_lemma (s : String) (i : Pos) (c : Char) (h : ¬s.atEnd i) :
(s.set i c).endPos.1 - ((s.set i c).next i).1 < s.endPos.1 - i.1 :=
(s.set i c).endPos.1 - ((s.set i c).next i).1 < s.endPos.1 - i.1 := by
suffices (s.set i c).endPos.1 - ((s.set i c).next i).1 = s.endPos.1 - (s.next i).1 by
rw [this]
apply Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next ..)
Nat.sub.elim (motive := (_ = ·)) _ _
(fun _ k e =>
have := set_next_add _ _ _ k 0 e.symm
Nat.sub_eq_of_eq_add <| this.symm.trans <| Nat.add_comm ..)
(fun h => by
have k, e := Nat.le.dest h
rw [Nat.succ_add] at e
have : ((s.set i c).next i).1 = _ := set_next_add _ _ c 0 k.succ e.symm
exact Nat.sub_eq_zero_of_le (this Nat.le_add_right ..))
have := set_next_add s i c (s.endPos.byteIdx - (s.next i).byteIdx) 0
have := set_next_add s i c 0 ((s.next i).byteIdx - s.endPos.byteIdx)
omega
@[specialize] def mapAux (f : Char Char) (i : Pos) (s : String) : String :=
if h : s.atEnd i then s
@@ -2044,40 +2358,51 @@ def stripSuffix (s : String) (suff : String) : String :=
end String
namespace Char
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := rfl
end Char
namespace String
@[ext]
theorem ext {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ :=
show s₁.data = (s₂.data : String) from h rfl
theorem ext_iff {s₁ s₂ : String} : s₁ = s₂ s₁.data = s₂.data := fun h => h rfl, ext
data_injective h
@[simp] theorem default_eq : default = "" := rfl
@[simp] theorem length_mk (s : List Char) : (String.mk s).length = s.length := rfl
@[simp]
theorem String.mk_eq_asString (s : List Char) : String.mk s = List.asString s := rfl
@[simp] theorem length_empty : "".length = 0 := rfl
@[simp]
theorem _root_.List.length_asString (s : List Char) : (List.asString s).length = s.length := by
rw [ length_data, List.data_asString]
@[simp] theorem length_singleton (c : Char) : (String.singleton c).length = 1 := rfl
@[simp] theorem length_empty : "".length = 0 := by simp [ length_data, data_empty]
@[simp]
theorem bytes_singleton {c : Char} : (String.singleton c).bytes = [c].utf8Encode := by
simp [singleton]
theorem singleton_eq {c : Char} : String.singleton c = [c].asString := by
simp [ bytes_inj]
@[simp] theorem data_singleton (c : Char) : (String.singleton c).data = [c] := by
simp [singleton_eq]
@[simp]
theorem length_singleton {c : Char} : (String.singleton c).length = 1 := by
simp [ length_data]
theorem push_eq_append (c : Char) : String.push s c = s ++ singleton c := by
simp [ bytes_inj]
@[simp] theorem data_push (c : Char) : (String.push s c).data = s.data ++ [c] := by
simp [push_eq_append]
@[simp] theorem length_push (c : Char) : (String.push s c).length = s.length + 1 := by
rw [push, length_mk, List.length_append, List.length_singleton, Nat.succ.injEq]
rfl
simp [ length_data]
@[simp] theorem length_pushn (c : Char) (n : Nat) : (pushn s c n).length = s.length + n := by
unfold pushn; induction n <;> simp [Nat.repeat, Nat.add_assoc, *]
@[simp] theorem length_append (s t : String) : (s ++ t).length = s.length + t.length := by
simp only [length, append, List.length_append]
@[simp] theorem data_push (s : String) (c : Char) : (s.push c).data = s.data ++ [c] := rfl
@[simp] theorem data_append (s t : String) : (s ++ t).data = s.data ++ t.data := rfl
simp [ length_data]
attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas
@@ -2161,10 +2486,8 @@ end Pos
theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next ..
@[simp] theorem prev_zero (s : String) : prev s 0 = 0 := by
cases s with | mk cs
cases cs
next => rfl
next => simp [prev, utf8PrevAux, Pos.le_iff]
rw [prev]
cases s.data <;> simp [utf8PrevAux, Pos.le_iff]
@[simp] theorem get'_eq (s : String) (p : Pos) (h) : get' s p h = get s p := rfl
@@ -2174,19 +2497,20 @@ theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next ..
-- so for proving can be unfolded.
attribute [simp] toSubstring'
theorem singleton_eq (c : Char) : singleton c = [c] := rfl
@[simp] theorem data_singleton (c : Char) : (singleton c).data = [c] := rfl
@[simp] theorem append_empty (s : String) : s ++ "" = s := ext (List.append_nil _)
@[simp] theorem empty_append (s : String) : "" ++ s = s := rfl
theorem append_assoc (s₁ s₂ s₃ : String) : (s₁ ++ s₂) ++ s₃ = s₁ ++ (s₂ ++ s₃) :=
ext (List.append_assoc ..)
ext (by simp [data_append])
end String
namespace Char
theorem toString_eq_singleton {c : Char} : c.toString = String.singleton c := rfl
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := by
simp [toString_eq_singleton]
end Char
open String
namespace Substring

View File

@@ -8,6 +8,7 @@ module
prelude
public import Init.Data.List.Basic
public import Init.Data.Char.Basic
public import Init.Data.ByteArray.Bootstrap
public section
@@ -31,7 +32,11 @@ Examples:
-/
@[extern "lean_string_push", expose]
def push : String Char String
| s, c => s ++ [c]
| b, h, c => b.append (List.utf8Encode [c]), ?pf
where finally
have m, hm := h
cases hm
exact .intro (m ++ [c]) (by simp [List.utf8Encode, List.toByteArray_append'])
/--
Returns a new string that contains only the character `c`.
@@ -124,8 +129,21 @@ Examples:
* `[].asString = ""`
* `['a', 'a', 'a'].asString = "aaa"`
-/
@[extern "lean_string_mk", expose]
def String.mk (data : List Char) : String :=
List.utf8Encode data,.intro data rfl
/--
Creates a string that contains the characters in a list, in order.
Examples:
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
* `[].asString = ""`
* `['a', 'a', 'a'].asString = "aaa"`
-/
@[expose]
def List.asString (s : List Char) : String :=
s
String.mk s
namespace Substring.Internal

File diff suppressed because it is too large Load Diff

View File

@@ -104,8 +104,7 @@ where
/--
Decodes an array of bytes that encode a string as [UTF-8](https://en.wikipedia.org/wiki/UTF-8) into
the corresponding string. Invalid UTF-8 characters in the byte array result in `(default : Char)`,
or `'A'`, in the string.
the corresponding string.
-/
@[extern "lean_string_from_utf8_unchecked"]
def fromUTF8 (a : @& ByteArray) (h : validateUTF8 a) : String :=
@@ -133,92 +132,15 @@ the corresponding string, or panics if the array is not a valid UTF-8 encoding o
@[inline] def fromUTF8! (a : ByteArray) : String :=
if h : validateUTF8 a then fromUTF8 a h else panic! "invalid UTF-8 string"
/--
Returns the sequence of bytes in a character's UTF-8 encoding.
-/
def utf8EncodeCharFast (c : Char) : List UInt8 :=
let v := c.val
if v 0x7f then
[v.toUInt8]
else if v 0x7ff then
[(v >>> 6).toUInt8 &&& 0x1f ||| 0xc0,
v.toUInt8 &&& 0x3f ||| 0x80]
else if v 0xffff then
[(v >>> 12).toUInt8 &&& 0x0f ||| 0xe0,
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
v.toUInt8 &&& 0x3f ||| 0x80]
else
[(v >>> 18).toUInt8 &&& 0x07 ||| 0xf0,
(v >>> 12).toUInt8 &&& 0x3f ||| 0x80,
(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_eq_utf8EncodeCharFast, utf8EncodeCharFast]
cases Decidable.em (c.val 0x7f) <;> simp [*]
cases Decidable.em (c.val 0x7ff) <;> simp [*]
cases Decidable.em (c.val 0xffff) <;> simp [*]
/--
Encodes a string in UTF-8 as an array of bytes.
-/
@[extern "lean_string_to_utf8"]
def toUTF8 (a : @& String) : ByteArray :=
a.data.flatMap utf8EncodeChar
a.bytes
@[simp] theorem size_toUTF8 (s : String) : s.toUTF8.size = s.utf8ByteSize := by
simp [toUTF8, ByteArray.size, Array.size, utf8ByteSize, List.flatMap]
induction s.data <;> simp [List.map, utf8ByteSize.go, Nat.add_comm, *]
rfl
/--
Accesses the indicated byte in the UTF-8 encoding of a string.

View File

@@ -142,9 +142,9 @@ inductive LiftRel (r : αγ → Prop) (s : β → δ → Prop) : α ⊕ β
@[simp, grind =] theorem liftRel_inl_inl : LiftRel r s (inl a) (inl c) r a c :=
fun h => by cases h; assumption, LiftRel.inl
@[simp, grind] theorem not_liftRel_inl_inr : ¬LiftRel r s (inl a) (inr d) := nofun
@[simp, grind ] theorem not_liftRel_inl_inr : ¬LiftRel r s (inl a) (inr d) := nofun
@[simp, grind] theorem not_liftRel_inr_inl : ¬LiftRel r s (inr b) (inl c) := nofun
@[simp, grind ] theorem not_liftRel_inr_inl : ¬LiftRel r s (inr b) (inl c) := nofun
@[simp, grind =] theorem liftRel_inr_inr : LiftRel r s (inr b) (inr d) s b d :=
fun h => by cases h; assumption, LiftRel.inr
@@ -179,7 +179,7 @@ attribute [simp] Lex.sep
@[simp, grind =] theorem lex_inr_inr : Lex r s (inr b₁) (inr b₂) s b₁ b₂ :=
fun h => by cases h; assumption, Lex.inr
@[simp, grind] theorem lex_inr_inl : ¬Lex r s (inr b) (inl a) := nofun
@[simp, grind ] theorem lex_inr_inl : ¬Lex r s (inr b) (inl a) := nofun
instance instDecidableRelSumLex [DecidableRel r] [DecidableRel s] : DecidableRel (Lex r s)
| inl _, inl _ => decidable_of_iff' _ lex_inl_inl

View File

@@ -7,7 +7,7 @@ module
prelude
public import Init.Meta
import Init.Data.String.Extra
public import Init.Data.String.Extra
/-!
Here we give the. implementation of `Name.toString`. There is also a private implementation in

View File

@@ -21,12 +21,7 @@ open Nat
/-- Converts a `Fin UInt8.size` into the corresponding `UInt8`. -/
@[inline] def UInt8.ofFin (a : Fin UInt8.size) : UInt8 := a
@[deprecated UInt8.ofBitVec (since := "2025-02-12"), inherit_doc UInt8.ofBitVec]
def UInt8.mk (bitVec : BitVec 8) : UInt8 :=
UInt8.ofBitVec bitVec
@[inline, deprecated UInt8.ofNatLT (since := "2025-02-13"), inherit_doc UInt8.ofNatLT]
def UInt8.ofNatCore (n : Nat) (h : n < UInt8.size) : UInt8 :=
UInt8.ofNatLT n h
/-- Converts an `Int` to a `UInt8` by taking the (non-negative remainder of the division by `2 ^ 8`. -/
def UInt8.ofInt (x : Int) : UInt8 := ofNat (x % 2 ^ 8).toNat
@@ -190,12 +185,6 @@ instance : Min UInt8 := minOfLe
/-- Converts a `Fin UInt16.size` into the corresponding `UInt16`. -/
@[inline] def UInt16.ofFin (a : Fin UInt16.size) : UInt16 := a
@[deprecated UInt16.ofBitVec (since := "2025-02-12"), inherit_doc UInt16.ofBitVec]
def UInt16.mk (bitVec : BitVec 16) : UInt16 :=
UInt16.ofBitVec bitVec
@[inline, deprecated UInt16.ofNatLT (since := "2025-02-13"), inherit_doc UInt16.ofNatLT]
def UInt16.ofNatCore (n : Nat) (h : n < UInt16.size) : UInt16 :=
UInt16.ofNatLT n h
/-- Converts an `Int` to a `UInt16` by taking the (non-negative remainder of the division by `2 ^ 16`. -/
def UInt16.ofInt (x : Int) : UInt16 := ofNat (x % 2 ^ 16).toNat
@@ -406,12 +395,6 @@ instance : Min UInt16 := minOfLe
/-- Converts a `Fin UInt32.size` into the corresponding `UInt32`. -/
@[inline] def UInt32.ofFin (a : Fin UInt32.size) : UInt32 := a
@[deprecated UInt32.ofBitVec (since := "2025-02-12"), inherit_doc UInt32.ofBitVec]
def UInt32.mk (bitVec : BitVec 32) : UInt32 :=
UInt32.ofBitVec bitVec
@[inline, deprecated UInt32.ofNatLT (since := "2025-02-13"), inherit_doc UInt32.ofNatLT]
def UInt32.ofNatCore (n : Nat) (h : n < UInt32.size) : UInt32 :=
UInt32.ofNatLT n h
/-- Converts an `Int` to a `UInt32` by taking the (non-negative remainder of the division by `2 ^ 32`. -/
def UInt32.ofInt (x : Int) : UInt32 := ofNat (x % 2 ^ 32).toNat
@@ -585,12 +568,6 @@ def Bool.toUInt32 (b : Bool) : UInt32 := if b then 1 else 0
/-- Converts a `Fin UInt64.size` into the corresponding `UInt64`. -/
@[inline] def UInt64.ofFin (a : Fin UInt64.size) : UInt64 := a
@[deprecated UInt64.ofBitVec (since := "2025-02-12"), inherit_doc UInt64.ofBitVec]
def UInt64.mk (bitVec : BitVec 64) : UInt64 :=
UInt64.ofBitVec bitVec
@[inline, deprecated UInt64.ofNatLT (since := "2025-02-13"), inherit_doc UInt64.ofNatLT]
def UInt64.ofNatCore (n : Nat) (h : n < UInt64.size) : UInt64 :=
UInt64.ofNatLT n h
/-- Converts an `Int` to a `UInt64` by taking the (non-negative remainder of the division by `2 ^ 64`. -/
def UInt64.ofInt (x : Int) : UInt64 := ofNat (x % 2 ^ 64).toNat
@@ -799,12 +776,6 @@ instance : Min UInt64 := minOfLe
/-- Converts a `Fin USize.size` into the corresponding `USize`. -/
@[inline] def USize.ofFin (a : Fin USize.size) : USize := a
@[deprecated USize.ofBitVec (since := "2025-02-12"), inherit_doc USize.ofBitVec]
def USize.mk (bitVec : BitVec System.Platform.numBits) : USize :=
USize.ofBitVec bitVec
@[inline, deprecated USize.ofNatLT (since := "2025-02-13"), inherit_doc USize.ofNatLT]
def USize.ofNatCore (n : Nat) (h : n < USize.size) : USize :=
USize.ofNatLT n h
/-- Converts an `Int` to a `USize` by taking the (non-negative remainder of the division by `2 ^ numBits`. -/
def USize.ofInt (x : Int) : USize := ofNat (x % 2 ^ System.Platform.numBits).toNat
@@ -812,14 +783,6 @@ def USize.ofInt (x : Int) : USize := ofNat (x % 2 ^ System.Platform.numBits).toN
@[simp] theorem USize.le_size : 2 ^ 32 USize.size := by cases USize.size_eq <;> simp_all
@[simp] theorem USize.size_le : USize.size 2 ^ 64 := by cases USize.size_eq <;> simp_all
@[deprecated USize.size_le (since := "2025-02-24")]
theorem usize_size_le : USize.size 18446744073709551616 :=
USize.size_le
@[deprecated USize.le_size (since := "2025-02-24")]
theorem le_usize_size : 4294967296 USize.size :=
USize.le_size
/--
Multiplies two word-sized unsigned integers, wrapping around on overflow. Usually accessed via the
`*` operator.

View File

@@ -26,8 +26,6 @@ open Nat
/-- Converts a `UInt8` into the corresponding `Fin UInt8.size`. -/
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, returning the largest representable value if
@@ -67,8 +65,6 @@ instance UInt8.instOfNat : OfNat UInt8 n := ⟨UInt8.ofNat n⟩
/-- Converts a `UInt16` into the corresponding `Fin UInt16.size`. -/
def UInt16.toFin (x : UInt16) : Fin UInt16.size := x.toBitVec.toFin
@[deprecated UInt16.toFin (since := "2025-02-12"), inherit_doc UInt16.toFin]
def UInt16.val (x : UInt16) : Fin UInt16.size := x.toFin
/--
Converts a natural number to a 16-bit unsigned integer, wrapping on overflow.
@@ -134,8 +130,6 @@ instance UInt16.instOfNat : OfNat UInt16 n := ⟨UInt16.ofNat n⟩
/-- Converts a `UInt32` into the corresponding `Fin UInt32.size`. -/
def UInt32.toFin (x : UInt32) : Fin UInt32.size := x.toBitVec.toFin
@[deprecated UInt32.toFin (since := "2025-02-12"), inherit_doc UInt32.toFin]
def UInt32.val (x : UInt32) : Fin UInt32.size := x.toFin
/--
Converts a natural number to a 32-bit unsigned integer, wrapping on overflow.
@@ -149,8 +143,7 @@ Examples:
-/
@[extern "lean_uint32_of_nat"]
def UInt32.ofNat (n : @& Nat) : UInt32 := BitVec.ofNat 32 n
@[inline, deprecated UInt32.ofNatLT (since := "2025-02-13"), inherit_doc UInt32.ofNatLT]
def UInt32.ofNat' (n : Nat) (h : n < UInt32.size) : UInt32 := UInt32.ofNatLT n h
/--
Converts a natural number to a 32-bit unsigned integer, returning the largest representable value if
the number is too large.
@@ -210,23 +203,14 @@ theorem UInt32.ofNatLT_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UIn
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) :
n < m UInt32.ofNatLT n h1 < UInt32.ofNat m := UInt32.ofNatLT_lt_of_lt h1 h2
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.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) :
m < n UInt32.ofNat m < UInt32.ofNatLT n h1 := UInt32.lt_ofNatLT_of_lt h1 h2
/-- Converts a `UInt64` into the corresponding `Fin UInt64.size`. -/
def UInt64.toFin (x : UInt64) : Fin UInt64.size := x.toBitVec.toFin
@[deprecated UInt64.toFin (since := "2025-02-12"), inherit_doc UInt64.toFin]
def UInt64.val (x : UInt64) : Fin UInt64.size := x.toFin
/--
Converts a natural number to a 64-bit unsigned integer, wrapping on overflow.
@@ -315,18 +299,9 @@ def UInt32.toUInt64 (a : UInt32) : UInt64 := ⟨⟨a.toNat, Nat.lt_trans a.toBit
instance UInt64.instOfNat : OfNat UInt64 n := UInt64.ofNat n
@[deprecated USize.size_eq (since := "2025-02-24")]
theorem usize_size_eq : USize.size = 4294967296 USize.size = 18446744073709551616 :=
USize.size_eq
@[deprecated USize.size_pos (since := "2025-02-24")]
theorem usize_size_pos : 0 < USize.size :=
USize.size_pos
/-- Converts a `USize` into the corresponding `Fin USize.size`. -/
def USize.toFin (x : USize) : Fin USize.size := x.toBitVec.toFin
@[deprecated USize.toFin (since := "2025-02-12"), inherit_doc USize.toFin]
def USize.val (x : USize) : Fin USize.size := x.toFin
/--
Converts an arbitrary-precision natural number to an unsigned word-sized integer, wrapping around on
overflow.

View File

@@ -1327,3 +1327,14 @@ theorem UInt64.right_le_or {a b : UInt64} : b ≤ a ||| b := by
simpa [UInt64.le_iff_toNat_le] using Nat.right_le_or
theorem USize.right_le_or {a b : USize} : b a ||| b := by
simpa [USize.le_iff_toNat_le] using Nat.right_le_or
theorem UInt8.and_lt_add_one {b c : UInt8} (h : c -1) : b &&& c < c + 1 :=
UInt8.lt_of_le_of_lt UInt8.and_le_right (UInt8.lt_add_one h)
theorem UInt16.and_lt_add_one {b c : UInt16} (h : c -1) : b &&& c < c + 1 :=
UInt16.lt_of_le_of_lt UInt16.and_le_right (UInt16.lt_add_one h)
theorem UInt32.and_lt_add_one {b c : UInt32} (h : c -1) : b &&& c < c + 1 :=
UInt32.lt_of_le_of_lt UInt32.and_le_right (UInt32.lt_add_one h)
theorem UInt64.and_lt_add_one {b c : UInt64} (h : c -1) : b &&& c < c + 1 :=
UInt64.lt_of_le_of_lt UInt64.and_le_right (UInt64.lt_add_one h)
theorem USize.and_lt_add_one {b c : USize} (h : c -1) : b &&& c < c + 1 :=
USize.lt_of_le_of_lt USize.and_le_right (USize.lt_add_one h)

View File

@@ -42,9 +42,6 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
@[simp] theorem toNat_ofBitVec : (ofBitVec a).toNat = a.toNat := (rfl)
@[deprecated toNat_ofBitVec (since := "2025-02-12")]
theorem toNat_mk : (ofBitVec a).toNat = a.toNat := (rfl)
@[simp] theorem toNat_ofNat' {n : Nat} : (ofNat n).toNat = n % 2 ^ $bits := BitVec.toNat_ofNat ..
-- Not `simp` because we have simprocs which will avoid the modulo.
@@ -52,34 +49,14 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
@[simp] theorem toNat_ofNatLT {n : Nat} {h : n < size} : (ofNatLT n h).toNat = n := BitVec.toNat_ofNatLT ..
@[deprecated toNat_ofNatLT (since := "2025-02-13")]
theorem toNat_ofNatCore {n : Nat} {h : n < size} : (ofNatLT n h).toNat = n := BitVec.toNat_ofNatLT ..
@[simp] theorem toFin_val (x : $typeName) : x.toFin.val = x.toNat := (rfl)
@[deprecated toFin_val (since := "2025-02-12")]
theorem val_val_eq_toNat (x : $typeName) : x.toFin.val = x.toNat := (rfl)
@[simp] theorem toNat_toBitVec (x : $typeName) : x.toBitVec.toNat = x.toNat := (rfl)
@[simp] theorem toFin_toBitVec (x : $typeName) : x.toBitVec.toFin = x.toFin := (rfl)
@[deprecated toNat_toBitVec (since := "2025-02-21")]
theorem toNat_toBitVec_eq_toNat (x : $typeName) : x.toBitVec.toNat = x.toNat := (rfl)
@[simp] theorem ofBitVec_toBitVec : (a : $typeName), ofBitVec a.toBitVec = a
| _, _ => rfl
@[deprecated ofBitVec_toBitVec (since := "2025-02-21")]
theorem ofBitVec_toBitVec_eq : (a : $typeName), ofBitVec a.toBitVec = a :=
ofBitVec_toBitVec
@[deprecated ofBitVec_toBitVec_eq (since := "2025-02-12")]
theorem mk_toBitVec_eq : (a : $typeName), ofBitVec a.toBitVec = a
| _, _ => rfl
@[deprecated "Use `toNat_toBitVec` and `toNat_ofNat_of_lt`." (since := "2025-03-05")]
theorem toBitVec_eq_of_lt {a : Nat} : a < size (ofNat a).toBitVec.toNat = a :=
Nat.mod_eq_of_lt
theorem toBitVec_ofNat' (n : Nat) : (ofNat n).toBitVec = BitVec.ofNat _ n := (rfl)
theorem toNat_ofNat_of_lt' {n : Nat} (h : n < size) : (ofNat n).toNat = n := by
@@ -140,17 +117,10 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
protected theorem eq_of_toFin_eq {a b : $typeName} (h : a.toFin = b.toFin) : a = b := by
rcases a with _; rcases b with _; simp_all [toFin]
open $typeName (eq_of_toFin_eq) in
@[deprecated eq_of_toFin_eq (since := "2025-02-12")]
protected theorem eq_of_val_eq {a b : $typeName} (h : a.toFin = b.toFin) : a = b :=
eq_of_toFin_eq h
open $typeName (eq_of_toFin_eq) in
protected theorem toFin_inj {a b : $typeName} : a.toFin = b.toFin a = b :=
Iff.intro eq_of_toFin_eq (congrArg toFin)
open $typeName (toFin_inj) in
@[deprecated toFin_inj (since := "2025-02-12")]
protected theorem val_inj {a b : $typeName} : a.toFin = b.toFin a = b :=
toFin_inj
open $typeName (eq_of_toBitVec_eq) in
protected theorem toBitVec_ne_of_ne {a b : $typeName} (h : a b) : a.toBitVec b.toBitVec :=
@@ -236,8 +206,6 @@ instance : LawfulOrderLT $typeName where
@[simp]
theorem toFin_ofNat (n : Nat) : toFin (no_index (OfNat.ofNat n)) = OfNat.ofNat n := (rfl)
@[deprecated toFin_ofNat (since := "2025-02-12")]
theorem val_ofNat (n : Nat) : toFin (no_index (OfNat.ofNat n)) = OfNat.ofNat n := (rfl)
@[simp, int_toBitVec]
theorem toBitVec_ofNat (n : Nat) : toBitVec (no_index (OfNat.ofNat n)) = BitVec.ofNat _ n := (rfl)
@@ -245,9 +213,6 @@ instance : LawfulOrderLT $typeName where
@[simp]
theorem ofBitVec_ofNat (n : Nat) : ofBitVec (BitVec.ofNat _ n) = OfNat.ofNat n := (rfl)
@[deprecated ofBitVec_ofNat (since := "2025-02-12")]
theorem mk_ofNat (n : Nat) : ofBitVec (BitVec.ofNat _ n) = OfNat.ofNat n := (rfl)
@[simp, int_toBitVec] protected theorem toBitVec_add {a b : $typeName} : (a + b).toBitVec = a.toBitVec + b.toBitVec := (rfl)
@[simp, int_toBitVec] protected theorem toBitVec_sub {a b : $typeName} : (a - b).toBitVec = a.toBitVec - b.toBitVec := (rfl)
@[simp, int_toBitVec] protected theorem toBitVec_mul {a b : $typeName} : (a * b).toBitVec = a.toBitVec * b.toBitVec := (rfl)
@@ -311,6 +276,13 @@ theorem UInt64.ofNat_mod_size : ofNat (x % 2 ^ 64) = ofNat x := by
theorem USize.ofNat_mod_size : ofNat (x % 2 ^ System.Platform.numBits) = ofNat x := by
simp [ofNat, BitVec.ofNat, Fin.ofNat]
theorem UInt8.ofNat_size : ofNat size = 0 := by decide
theorem UInt16.ofNat_size : ofNat size = 0 := by decide
theorem UInt32.ofNat_size : ofNat size = 0 := by decide
theorem UInt64.ofNat_size : ofNat size = 0 := by decide
theorem USize.ofNat_size : ofNat size = 0 := by
simp [ofNat, BitVec.ofNat, USize.eq_iff_toBitVec_eq]
theorem UInt8.lt_ofNat_iff {n : UInt8} {m : Nat} (h : m < size) : n < ofNat m n.toNat < m := by
rw [lt_iff_toNat_lt, toNat_ofNat_of_lt' h]
theorem UInt8.ofNat_lt_iff {n : UInt8} {m : Nat} (h : m < size) : ofNat m < n m < n.toNat := by
@@ -3156,3 +3128,15 @@ protected theorem USize.sub_lt {a b : USize} (hb : 0 < b) (hab : b ≤ a) : a -
rw [lt_iff_toNat_lt, USize.toNat_sub_of_le _ _ hab]
refine Nat.sub_lt ?_ (USize.lt_iff_toNat_lt.1 hb)
exact USize.lt_iff_toNat_lt.1 (USize.lt_of_lt_of_le hb hab)
theorem UInt8.lt_add_one {c : UInt8} (h : c -1) : c < c + 1 :=
UInt8.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [ UInt8.toBitVec_inj] using h))
theorem UInt16.lt_add_one {c : UInt16} (h : c -1) : c < c + 1 :=
UInt16.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [ UInt16.toBitVec_inj] using h))
theorem UInt32.lt_add_one {c : UInt32} (h : c -1) : c < c + 1 :=
UInt32.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [ UInt32.toBitVec_inj] using h))
theorem UInt64.lt_add_one {c : UInt64} (h : c -1) : c < c + 1 :=
UInt64.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [ UInt64.toBitVec_inj] using h))
theorem USize.lt_add_one {c : USize} (h : c -1) : c < c + 1 :=
USize.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one
(by simpa [ USize.toBitVec_inj, BitVec.neg_one_eq_allOnes] using h))

View File

@@ -172,9 +172,6 @@ theorem attach_map_val (xs : Vector α n) (f : α → β) :
rcases xs with xs, rfl
simp
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
-- The argument `xs : Vector α n` is explicit to allow rewriting from right to left.
theorem attach_map_subtype_val (xs : Vector α n) : xs.attach.map Subtype.val = xs := by
rcases xs with xs, rfl
@@ -185,22 +182,19 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {xs : Vector α n}
rcases xs with xs, rfl
simp
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
theorem attachWith_map_subtype_val {p : α Prop} {xs : Vector α n} (H : a xs, p a) :
(xs.attachWith p H).map Subtype.val = xs := by
rcases xs with xs, rfl
simp
@[simp, grind]
@[simp, grind ]
theorem mem_attach (xs : Vector α n) : x, x xs.attach
| a, h => by
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
rcases this with _, _, m, rfl
exact m
@[simp, 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 +205,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
@@ -344,9 +339,6 @@ theorem map_attach_eq_pmap {xs : Vector α n} {f : { x // x ∈ xs } → β} :
rcases xs with xs, rfl
ext <;> simp
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
abbrev map_attach := @map_attach_eq_pmap
@[grind =]
theorem pmap_pmap {p : α Prop} {q : β Prop} {g : a, p a β} {f : b, q b γ} {xs : Vector α n} (H₁ H₂) :
pmap f (pmap g xs H₁) H₂ =

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,37 @@ 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
@[grind ]
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 +937,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 +1224,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 +1247,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 +1260,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 +1305,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 +1321,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 +1358,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 +1421,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 +1441,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 +1631,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 +1667,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 +1703,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 +1782,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 +1790,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 +1817,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 +1837,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 +1906,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 +1933,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 +1993,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 +2022,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 +2085,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 +2105,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 +2238,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 +2263,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 +2290,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 +2331,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 +2356,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 +2372,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 +2421,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 +2444,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 +2501,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 +2609,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 +2640,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 +2692,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 +2738,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 +2762,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 +2775,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 +2923,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 +2940,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 +2949,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 +2989,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 +3002,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 +3011,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 +3022,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 +3037,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 +3106,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 +3123,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

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