Compare commits

...

6 Commits

Author SHA1 Message Date
Paul Reichert
39b412a7ed poke 2026-01-28 15:16:05 +01:00
Paul Reichert
89a59534f4 fixes 2026-01-28 14:55:06 +01:00
Paul Reichert
d28873ec2d fixes 2026-01-28 13:33:20 +01:00
Paul Reichert
f8d5e7b9c5 update IteratorAccess 2026-01-28 13:23:08 +01:00
Paul Reichert
603da45a12 more deprecations/updates 2026-01-28 12:24:06 +01:00
Paul Reichert
4f902078ed update Std.Iter docstring 2026-01-28 12:16:32 +01:00
16 changed files with 180 additions and 107 deletions

View File

@@ -94,8 +94,9 @@ By convention, the monadic iterator associated with an object can be obtained vi
For example, `List.iterM IO` creates an iterator over a list in the monad `IO`.
See `Init.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
convert a provably finite iterator `it` into a list and `it.allowNontermination.toList` will
do so even if finiteness cannot be proved. It is also always possible to manually iterate using
convert an iterator `it` into a list and `it.ensureTermination.toList` guarantees that this
operation will terminate, given a proof that the iterator is finite.
It is also always possible to manually iterate using
`it.step`, relying on the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
See `Iter` for a more convenient interface in case that no monadic effects are needed (`m = Id`).
@@ -139,8 +140,9 @@ By convention, the monadic iterator associated with an object can be obtained vi
For example, `List.iterM IO` creates an iterator over a list in the monad `IO`.
See `Init.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
convert a provably finite iterator `it` into a list and `it.allowNontermination.toList` will
do so even if finiteness cannot be proved. It is also always possible to manually iterate using
convert an iterator `it` into a list and `it.ensureTermination.toList` guarantees that this
operation will terminate, given a proof that the iterator is finite.
It is also always possible to manually iterate using
`it.step`, relying on the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
See `IterM` for iterators that operate in a monad.
@@ -754,8 +756,8 @@ def IterM.finitelyManySteps {α : Type w} {m : Type w → Type w'} {β : Type w}
it
/--
Termination measure to be used in well-founded recursive functions recursing over a finite iterator
(see also `Finite`).
Termination measure to be used in recursive functions built with `WellFounded.extrinsicFix`
recursing over a finite iterator without requiring a proof of finiteness (see also `Finite`).
-/
@[expose]
def IterM.finitelyManySteps! {α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β]
@@ -796,6 +798,11 @@ def Iter.finitelyManySteps {α : Type w} {β : Type w} [Iterator α Id β] [Iter
(it : Iter (α := α) β) : IterM.TerminationMeasures.Finite α Id :=
it.toIterM.finitelyManySteps
@[inherit_doc IterM.finitelyManySteps!, expose]
def Iter.finitelyManySteps! {α : Type w} {β : Type w} [Iterator α Id β]
(it : Iter (α := α) β) : IterM.TerminationMeasures.Finite α Id :=
it.toIterM.finitelyManySteps!
/--
This theorem is used by a `decreasing_trivial` extension. It powers automatic termination proofs
with `IterM.finitelyManySteps`.
@@ -902,6 +909,16 @@ def IterM.finitelyManySkips {α : Type w} {m : Type w → Type w'} {β : Type w}
[Iterators.Productive α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Productive α m :=
it
/--
Termination measure to be used in recursive functions built with `WellFounded.extrinsicFix`
recursing over a productive iterator without requiring a proof of productiveness
(see also `Productive`).
-/
@[expose]
def IterM.finitelyManySkips! {α : Type w} {m : Type w Type w'} {β : Type w} [Iterator α m β]
(it : IterM (α := α) m β) : IterM.TerminationMeasures.Productive α m :=
it
/--
This theorem is used by a `decreasing_trivial` extension. It powers automatic termination proofs
with `IterM.finitelyManySkips`.
@@ -922,6 +939,11 @@ def Iter.finitelyManySkips {α : Type w} {β : Type w} [Iterator α Id β] [Iter
(it : Iter (α := α) β) : IterM.TerminationMeasures.Productive α Id :=
it.toIterM.finitelyManySkips
@[inherit_doc IterM.finitelyManySkips!, expose]
def Iter.finitelyManySkips! {α : Type w} {β : Type w} [Iterator α Id β]
(it : Iter (α := α) β) : IterM.TerminationMeasures.Productive α Id :=
it.toIterM.finitelyManySkips!
/--
This theorem is used by a `decreasing_trivial` extension. It powers automatic termination proofs
with `Iter.finitelyManySkips`.

View File

@@ -21,21 +21,70 @@ If possible, takes `n` steps with the iterator `it` and
returns the `n`-th emitted value, or `none` if `it` finished
before emitting `n` values.
This function requires a `Productive` instance proving that the iterator will always emit a value
after a finite number of skips. If the iterator is not productive or such an instance is not
available, consider using `it.allowNontermination.atIdxSlow?` instead of `it.atIdxSlow?`. However,
it is not possible to formally verify the behavior of the partial variant.
If the iterator is not productive, this function might run forever in an endless loop of iterator
steps. The variant `it.ensureTermination.atIdxSlow?` is guaranteed to terminate after finitely many
steps.
-/
@[specialize]
def Iter.atIdxSlow? {α β} [Iterator α Id β] [Productive α Id]
def Iter.atIdxSlow? {α β} [Iterator α Id β]
(n : Nat) (it : Iter (α := α) β) : Option β :=
match it.step with
| .yield it' out _ =>
match n with
| 0 => some out
| k + 1 => it'.atIdxSlow? k
| .skip it' _ => it'.atIdxSlow? n
| .done _ => none
WellFounded.extrinsicFix₂ (C₂ := fun _ _ => Option β) (α := Iter (α := α) β) (β := fun _ => Nat)
(InvImage
(Prod.Lex WellFoundedRelation.rel IterM.TerminationMeasures.Productive.Rel)
(fun p => (p.2, p.1.finitelyManySkips!)))
(fun it n recur =>
match it.step with
| .yield it' out _ =>
match n with
| 0 => some out
| k + 1 => recur it' k (by decreasing_tactic)
| .skip it' _ => recur it' n (by decreasing_tactic)
| .done _ => none) it n
-- We provide the functional induction principle by hand because `atIdxSlow?` is implemented using
-- `extrinsicFix₂` and not using well-founded recursion.
/-
An induction principle for `Iter.atIdxSlow?`.
This lemma provides a functional induction principle for reasoning about `Iter.atIdxSlow? n it`.
The induction follows the structure of iterator steps.
- base case: when we reach the desired index (`n = 0`) and get a `.yield` step
- inductive case: when we have a `.yield` step but need to continue (`n > 0`)
- skip case: when we encounter a `.skip` step and continue with the same index
- done case: when the iterator is exhausted and we return `none`
-/
theorem Iter.atIdxSlow?.induct_unfolding {α β : Type u} [Iterator α Id β] [Productive α Id]
(motive : Nat Iter β Option β Prop)
-- Base case: we have reached index 0 and found a value
(yield_zero : (it it' : Iter (α := α) β) (out : β) (property : it.IsPlausibleStep (IterStep.yield it' out)),
it.step = IterStep.yield it' out, property motive 0 it (some out))
-- Inductive case: we have a yield but need to continue to a higher index
(yield_succ : (it it' : Iter (α := α) β) (out : β) (property : it.IsPlausibleStep (IterStep.yield it' out)),
it.step = IterStep.yield it' out, property
(k : Nat), motive k it' (Iter.atIdxSlow? k it') motive k.succ it (Iter.atIdxSlow? k it'))
-- Skip case: we encounter a skip and continue with the same index
(skip_case : (n : Nat) (it it' : Iter β) (property : it.IsPlausibleStep (IterStep.skip it')),
it.step = IterStep.skip it', property
motive n it' (Iter.atIdxSlow? n it') motive n it (Iter.atIdxSlow? n it'))
-- Done case: the iterator is exhausted, return none
(done_case : (n : Nat) (it : Iter β) (property : it.IsPlausibleStep IterStep.done),
it.step = IterStep.done, property motive n it none)
-- The conclusion: the property holds for all indices and iterators
(n : Nat) (it : Iter β) : motive n it (Iter.atIdxSlow? n it) := by
simp only [atIdxSlow?] at *
rw [WellFounded.extrinsicFix₂_eq_apply]
· split
· split
· apply yield_zero <;> assumption
· apply yield_succ
all_goals try assumption
apply Iter.atIdxSlow?.induct_unfolding <;> assumption
· apply skip_case
all_goals try assumption
apply Iter.atIdxSlow?.induct_unfolding <;> assumption
· apply done_case <;> assumption
· exact InvImage.wf _ WellFoundedRelation.wf
termination_by (n, it.finitelyManySkips)
/--
@@ -43,22 +92,21 @@ If possible, takes `n` steps with the iterator `it` and
returns the `n`-th emitted value, or `none` if `it` finished
before emitting `n` values.
This is a partial, potentially nonterminating, function. It is not possible to formally verify
its behavior. If the iterator has a `Productive` instance, consider using `Iter.atIdxSlow?` instead.
This variant terminates after finitely many steps and requires a proof that the iterator is
productive. If such a proof is not available, consider using `Iter.toArray`.
-/
@[specialize]
partial def Iter.Partial.atIdxSlow? {α β} [Iterator α Id β] [Monad Id]
(n : Nat) (it : Iter.Partial (α := α) β) : Option β := do
match it.it.step with
| .yield it' out _ =>
match n with
| 0 => some out
| k + 1 => (it' : Iter.Partial (α := α) β).atIdxSlow? k
| .skip it' _ => (it' : Iter.Partial (α := α) β).atIdxSlow? n
| .done _ => none
@[inline]
def Iter.Total.atIdxSlow? {α β} [Iterator α Id β] [Productive α Id]
(n : Nat) (it : Iter.Total (α := α) β) : Option β :=
it.it.atIdxSlow? n
@[inline, inherit_doc Iter.atIdxSlow?, deprecated Iter.atIdxSlow? (since := "2026-01-28")]
def Iter.Partial.atIdxSlow? {α β} [Iterator α Id β]
(n : Nat) (it : Iter.Partial (α := α) β) : Option β :=
it.it.atIdxSlow? n
@[always_inline, inline, inherit_doc IterM.atIdx?]
def Iter.atIdx? {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess α Id]
def Iter.atIdx? {α β} [Iterator α Id β] [IteratorAccess α Id]
(n : Nat) (it : Iter (α := α) β) : Option β :=
match (IteratorAccess.nextAtIdx? it.toIterM n).run.val with
| .yield _ out => some out

View File

@@ -29,7 +29,7 @@ consumers such as `toList`. They can be used without any proof of termination su
or `Productive`, but as they are implemented with the `partial` declaration modifier, they are
opaque for the kernel and it is impossible to prove anything about them.
-/
@[always_inline, inline]
@[always_inline, inline, deprecated "The consumers on iterators do not require proofs of termination anymore. For example, use `it.toList` instead of `it.allowNontermination.toList`." (since := "2026-01-28")]
def IterM.allowNontermination {α : Type w} {m : Type w Type w'} {β : Type w}
(it : IterM (α := α) m β) : IterM.Partial (α := α) m β :=
it

View File

@@ -29,7 +29,7 @@ consumers such as `toList`. They can be used without any proof of termination su
or `Productive`, but as they are implemented with the `partial` declaration modifier, they are
opaque for the kernel and it is impossible to prove anything about them.
-/
@[always_inline, inline]
@[always_inline, inline, deprecated "The consumers on iterators do not require proofs of termination anymore. For example, use `it.toList` instead of `it.allowNontermination.toList`." (since := "2026-01-28")]
def Iter.allowNontermination {α : Type w} {β : Type w}
(it : Iter (α := α) β) : Iter.Partial (α := α) β :=
it

View File

@@ -47,18 +47,18 @@ theorem Iter.atIdxSlow?_take {α β}
[Iterator α Id β] [Productive α Id] {k l : Nat}
{it : Iter (α := α) β} :
(it.take k).atIdxSlow? l = if l < k then it.atIdxSlow? l else none := by
fun_induction it.atIdxSlow? l generalizing k
case case1 it it' out h h' =>
simp only [atIdxSlow?.eq_def (it := it.take k), step_take, h']
induction l, it using Iter.atIdxSlow?.induct_unfolding generalizing k
case yield_zero it it' out h h' =>
simp only [atIdxSlow?_eq_match (it := it.take k), step_take, h']
cases k <;> simp
case case2 it it' out h h' l ih =>
simp only [Nat.succ_eq_add_one, atIdxSlow?.eq_def (it := it.take k), step_take, h']
case yield_succ it it' out h h' l ih =>
simp only [Nat.succ_eq_add_one, atIdxSlow?_eq_match (it := it.take k), step_take, h']
cases k <;> cases l <;> simp [ih]
case case3 l it it' h h' ih =>
simp only [atIdxSlow?.eq_def (it := it.take k), step_take, h']
case skip_case l it it' h h' ih =>
simp only [atIdxSlow?_eq_match (it := it.take k), step_take, h']
cases k <;> cases l <;> simp [ih]
case case4 l it h h' =>
simp only [atIdxSlow?.eq_def (it := it.take k), step_take, h']
case done_case l it h h' =>
simp only [atIdxSlow?_eq_match (it := it.take k), step_take, h']
cases k <;> cases l <;> simp
@[simp]

View File

@@ -7,6 +7,7 @@ module
prelude
public import Init.Data.Iterators.Consumers.Access
import Init.Data.Iterators.Lemmas.Basic
namespace Std.Iter
open Std.Iterators
@@ -21,6 +22,6 @@ public theorem atIdxSlow?_eq_match [Iterator α Id β] [Productive α Id]
| n + 1 => it'.atIdxSlow? n
| .skip it' => it'.atIdxSlow? n
| .done => none) := by
fun_induction it.atIdxSlow? n <;> simp_all
induction n, it using Iter.atIdxSlow?.induct_unfolding <;> simp_all
end Std.Iter

View File

@@ -163,12 +163,14 @@ theorem Iter.getElem?_toList_eq_atIdxSlow? {α β}
{it : Iter (α := α) β} {k : Nat} :
it.toList[k]? = it.atIdxSlow? k := by
induction it using Iter.inductSteps generalizing k with | step it ihy ihs
rw [toList_eq_match_step, atIdxSlow?]
obtain step, h := it.step
cases step
· cases k <;> simp [ihy h]
· simp [ihs h]
· simp
rw [toList_eq_match_step, atIdxSlow?, WellFounded.extrinsicFix₂_eq_apply]
· obtain step, h := it.step
cases step
· cases k <;> simp [ihy h, atIdxSlow?]
· simp [ihs h, atIdxSlow?]
· simp
· apply InvImage.wf
exact WellFoundedRelation.wf
theorem Iter.toList_eq_of_atIdxSlow?_eq {α₁ α₂ β}
[Iterator α₁ Id β] [Finite α₁ Id]

View File

@@ -58,7 +58,7 @@ This allows you to observe state changes (like logged messages, modified metavar
as tasks complete, unlike `par`/`par'` which restore the initial state after collecting all results.
Iterators do not have `Finite` instances, as we cannot prove termination from the available
information. For consumers that require `Finite` (like `.toList`), use `.allowNontermination.toList`.
information.
-/
public section
@@ -245,7 +245,7 @@ If `cancel := true` (the default), cancels all remaining tasks after the first s
-/
def parFirst {α : Type} (jobs : List (CoreM α)) (cancel : Bool := true) : CoreM α := do
let (cancelHook, iter) parIterGreedyWithCancel jobs
for result in iter.allowNontermination do
for result in iter do
match result with
| .ok value =>
if cancel then cancelHook
@@ -380,7 +380,7 @@ If `cancel := true` (the default), cancels all remaining tasks after the first s
-/
def parFirst {α : Type} (jobs : List (MetaM α)) (cancel : Bool := true) : MetaM α := do
let (cancelHook, iter) parIterGreedyWithCancel jobs
for result in iter.allowNontermination do
for result in iter do
match result with
| .ok value =>
if cancel then cancelHook
@@ -517,7 +517,7 @@ If `cancel := true` (the default), cancels all remaining tasks after the first s
-/
def parFirst {α : Type} (jobs : List (TermElabM α)) (cancel : Bool := true) : TermElabM α := do
let (cancelHook, iter) parIterGreedyWithCancel jobs
for result in iter.allowNontermination do
for result in iter do
match result with
| .ok value =>
if cancel then cancelHook
@@ -654,7 +654,7 @@ If `cancel := true` (the default), cancels all remaining tasks after the first s
-/
def parFirst {α : Type} (jobs : List (TacticM α)) (cancel : Bool := true) : TacticM α := do
let (cancelHook, iter) parIterGreedyWithCancel jobs
for result in iter.allowNontermination do
for result in iter do
match result with
| .ok value =>
if cancel then cancelHook

View File

@@ -41,7 +41,7 @@ theorem Iter.atIdxSlow?_drop {α β}
induction k generalizing it <;> induction l generalizing it
all_goals
induction it using Iter.inductSkips with | step it ih
rw [atIdxSlow?.eq_def, atIdxSlow?.eq_def, step_drop]
rw [atIdxSlow?_eq_match, atIdxSlow?_eq_match, step_drop]
cases it.step using PlausibleIterStep.casesOn <;> simp [*]
@[simp]

View File

@@ -57,11 +57,11 @@ theorem Iter.atIdxSlow?_takeWhile {α β}
[Iterator α Id β] [Productive α Id] {l : Nat}
{it : Iter (α := α) β} {P} :
(it.takeWhile P).atIdxSlow? l = if k, k l (it.atIdxSlow? k).any P then it.atIdxSlow? l else none := by
fun_induction it.atIdxSlow? l
case case1 it it' out h h' =>
induction l, it using atIdxSlow?.induct_unfolding
case yield_zero it it' out h h' =>
rw [atIdxSlow?_eq_match]
simp only [val_step_takeWhile, h', Nat.le_zero_eq, forall_eq]
rw [atIdxSlow?, h']
rw [atIdxSlow?_eq_match, h']
simp only [Option.any_some]
apply Eq.symm
split
@@ -71,10 +71,10 @@ theorem Iter.atIdxSlow?_takeWhile {α β}
· cases h' : P out
· simp
· exfalso; simp_all
case case2 it it' out h h' l ih =>
case yield_succ it it' out h h' l ih =>
rw [atIdxSlow?_eq_match]
simp only [Nat.succ_eq_add_one, val_step_takeWhile, h']
simp only [atIdxSlow?.eq_def (it := it), h']
simp only [atIdxSlow?_eq_match (it := it), h']
cases hP : P out
· simp
intro h
@@ -96,11 +96,11 @@ theorem Iter.atIdxSlow?_takeWhile {α β}
apply hl
intro k hk
exact hl' (k + 1) (Nat.succ_le_succ hk)
case case3 l it it' h h' ih =>
simp only [atIdxSlow?.eq_def (it := it.takeWhile P), step_takeWhile, h', ih]
simp only [atIdxSlow?.eq_def (it := it), h']
case case4 l it h h' =>
simp only [atIdxSlow?.eq_def (it := it), atIdxSlow?.eq_def (it := it.takeWhile P), h',
case skip_case l it it' h h' ih =>
simp only [atIdxSlow?_eq_match (it := it.takeWhile P), step_takeWhile, h', ih]
simp only [atIdxSlow?_eq_match (it := it), h']
case done_case l it h h' =>
simp only [atIdxSlow?_eq_match (it := it), atIdxSlow?_eq_match (it := it.takeWhile P), h',
step_takeWhile]
split <;> rfl

View File

@@ -184,9 +184,9 @@ theorem Iter.atIdxSlow?_intermediateZip [Iterator α₁ Id β₁] [Iterator α
| n' + 1 => do return ( it₁.atIdxSlow? n', it₂.atIdxSlow? (n' + 1))) := by
generalize h : Intermediate.zip it₁ memo it₂ = it
revert h it₁ memo it₂
fun_induction it.atIdxSlow? n
induction n, it using atIdxSlow?.induct_unfolding
rintro it₁ memo it₂ rfl
case case1 it it' out h h' =>
case yield_zero it it' out h h' =>
rw [atIdxSlow?]
simp only [Option.pure_def, Option.bind_eq_bind]
simp only [step_intermediateZip, PlausibleIterStep.skip, PlausibleIterStep.done,
@@ -195,9 +195,9 @@ theorem Iter.atIdxSlow?_intermediateZip [Iterator α₁ Id β₁] [Iterator α
· split at h' <;> cases h'
· split at h' <;> cases h'
rename_i hs₂
rw [atIdxSlow?, hs₂]
rw [atIdxSlow?_eq_match, hs₂]
simp
case case2 it it' out h h' n ih =>
case yield_succ it it' out h h' n ih =>
rintro it₁ memo it₂ rfl
simp only [Nat.succ_eq_add_one, Option.pure_def, Option.bind_eq_bind]
cases memo
@@ -211,8 +211,8 @@ theorem Iter.atIdxSlow?_intermediateZip [Iterator α₁ Id β₁] [Iterator α
split at h' <;> cases h'
rename_i hs₂
simp only [ih rfl, Option.pure_def, Option.bind_eq_bind]
rw [atIdxSlow?.eq_def (it := it₂), hs₂]
case case3 it it' h h' ih =>
rw [atIdxSlow?_eq_match (it := it₂), hs₂]
case skip_case it it' h h' ih =>
rintro it₁ memo it₂ rfl
obtain it₁', memo', it₂', rfl := Intermediate.zip_surj it'
specialize ih rfl
@@ -223,19 +223,19 @@ theorem Iter.atIdxSlow?_intermediateZip [Iterator α₁ Id β₁] [Iterator α
· split at h' <;> rename_i hs₁
· simp only [IterStep.skip.injEq, Intermediate.zip_inj] at h'
obtain rfl, rfl, rfl := h'
simp only [ih, Option.pure_def, Option.bind_eq_bind, atIdxSlow?.eq_def (it := it₁), hs₁]
simp only [ih, Option.pure_def, Option.bind_eq_bind, atIdxSlow?_eq_match (it := it₁), hs₁]
split <;> rfl
· simp only [IterStep.skip.injEq, Intermediate.zip_inj] at h'
obtain rfl, rfl, rfl := h'
simp [ih, atIdxSlow?.eq_def (it := it₁), hs₁]
simp [ih, atIdxSlow?_eq_match (it := it₁), hs₁]
· cases h'
· split at h' <;> rename_i hs₂ <;> (try cases h')
simp only [IterStep.skip.injEq, Intermediate.zip_inj] at h'
obtain rfl, rfl, rfl := h'
simp [ih, atIdxSlow?.eq_def (it := it₂), hs₂]
case case4 it _ h =>
simp [ih, atIdxSlow?_eq_match (it := it₂), hs₂]
case done_case it _ h =>
rintro it₁ memo it₂ rfl
rw [atIdxSlow?]
rw [atIdxSlow?_eq_match]
simp only [step_intermediateZip] at h
cases memo
case none =>
@@ -247,7 +247,7 @@ theorem Iter.atIdxSlow?_intermediateZip [Iterator α₁ Id β₁] [Iterator α
simp only at h
split at h <;> cases h
rename_i hs₂
simp only [atIdxSlow?.eq_def (it := it₂), hs₂, Option.pure_def, Option.bind_eq_bind,
simp only [atIdxSlow?_eq_match (it := it₂), hs₂, Option.pure_def, Option.bind_eq_bind,
Option.bind_none, Option.bind_fun_none]
split <;> rfl

View File

@@ -22,15 +22,15 @@ theorem Iter.step_repeat :
theorem Iter.atIdxSlow?_zero_repeat :
(Iter.repeat f init).atIdxSlow? 0 = some init := by
rw [atIdxSlow?, step_repeat]
rw [atIdxSlow?_eq_match, step_repeat]
theorem Iter.atIdxSlow?_succ_repeat {k : Nat} :
(Iter.repeat f init).atIdxSlow? (k + 1) = (Iter.repeat f (f init)).atIdxSlow? k := by
rw [atIdxSlow?, step_repeat]
rw [atIdxSlow?_eq_match, step_repeat]
theorem Iter.atIdxSlow?_succ_repeat_eq_map {k : Nat} :
(Iter.repeat f init).atIdxSlow? (k + 1) = f <$> ((Iter.repeat f init).atIdxSlow? k) := by
rw [atIdxSlow?, step_repeat]
rw [atIdxSlow?_eq_match, step_repeat]
simp only
induction k generalizing init
· simp [atIdxSlow?_zero_repeat, Functor.map]

View File

@@ -35,7 +35,7 @@ instance [Pure m] : Std.Iterator RandomIterator m UInt64 where
def mkMapWithCap (seed : UInt64) (size : Nat) : Std.HashMap UInt64 UInt64 := Id.run do
let mut map := Std.HashMap.emptyWithCapacity size
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
return map
@@ -56,7 +56,7 @@ def benchContainsHit (seed : UInt64) (size : Nat) : IO Float := do
timeNanos checks do
let mut todo := checks
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
if !map.contains val then
throw <| .userError "Fail"
todo := todo - size
@@ -71,7 +71,7 @@ def benchContainsMiss (seed : UInt64) (size : Nat) : IO Float := do
timeNanos checks do
let mut todo := checks
while todo != 0 do
for val in iter |>.take size |>.allowNontermination do
for val in iter |>.take size do
if map.contains val then
throw <| .userError "Fail"
todo := todo - size
@@ -103,7 +103,7 @@ def benchInsertIfNewHit (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
let mut map := map
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insertIfNew val val
if map.size != size then
throw <| .userError "Fail"
@@ -120,7 +120,7 @@ def benchInsertHit (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
let mut map := map
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.size != size then
throw <| .userError "Fail"
@@ -135,7 +135,7 @@ def benchInsertMissEmpty (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
while todo != 0 do
let mut map : Std.HashMap _ _ := {}
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.size > size then
throw <| .userError "Fail"
@@ -150,7 +150,7 @@ def benchInsertMissEmptyWithCapacity (seed : UInt64) (size : Nat) : IO Float :=
let mut todo := checks
while todo != 0 do
let mut map := Std.HashMap.emptyWithCapacity size
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.size > size then
throw <| .userError "Fail"
@@ -168,7 +168,7 @@ def benchEraseInsert (seed : UInt64) (size : Nat) : IO Float := do
let mut map := map
let mut todo := checks
while todo != 0 do
for (eraseVal, newVal) in eraseIter.zip newIter |>.take size |>.allowNontermination do
for (eraseVal, newVal) in eraseIter.zip newIter |>.take size do
map := map.erase eraseVal |>.insert newVal newVal
if map.size != size then
throw <| .userError "Fail"

View File

@@ -33,7 +33,7 @@ instance [Pure m] : Std.Iterator RandomIterator m UInt64 where
def mkMapWithCap (seed : UInt64) (size : Nat) : Lean.PersistentHashMap UInt64 UInt64 := Id.run do
let mut map := Lean.PersistentHashMap.empty
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
return map
@@ -54,7 +54,7 @@ def benchContainsHit (seed : UInt64) (size : Nat) : IO Float := do
timeNanos checks do
let mut todo := checks
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
if !map.contains val then
throw <| .userError "Fail"
todo := todo - size
@@ -69,7 +69,7 @@ def benchContainsMiss (seed : UInt64) (size : Nat) : IO Float := do
timeNanos checks do
let mut todo := checks
while todo != 0 do
for val in iter |>.take size |>.allowNontermination do
for val in iter |>.take size do
if map.contains val then
throw <| .userError "Fail"
todo := todo - size
@@ -101,7 +101,7 @@ def benchInsertHit (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
let mut map := map
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.isEmpty then
throw <| .userError "Fail"
@@ -116,7 +116,7 @@ def benchInsertMissEmpty (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
while todo != 0 do
let mut map : Lean.PersistentHashMap _ _ := {}
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.isEmpty then
throw <| .userError "Fail"
@@ -133,7 +133,7 @@ def benchInsertMissEmptyShared (seed : UInt64) (size : Nat) : IO Float := do
while todo != 0 do
let mut map : Lean.PersistentHashMap _ _ := {}
let mut maps := Array.emptyWithCapacity size
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.isEmpty then
throw <| .userError "Fail"
@@ -154,7 +154,7 @@ def benchEraseInsert (seed : UInt64) (size : Nat) : IO Float := do
let mut map := map
let mut todo := checks
while todo != 0 do
for (eraseVal, newVal) in eraseIter.zip newIter |>.take size |>.allowNontermination do
for (eraseVal, newVal) in eraseIter.zip newIter |>.take size do
map := map.erase eraseVal |>.insert newVal newVal
if map.isEmpty then
throw <| .userError "Fail"

View File

@@ -30,7 +30,7 @@ instance [Pure m] : Std.Iterator RandomIterator m UInt64 where
def mkMap (seed : UInt64) (size : Nat) : Std.TreeMap UInt64 UInt64 := Id.run do
let mut map := {}
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
return map
@@ -51,7 +51,7 @@ def benchContainsHit (seed : UInt64) (size : Nat) : IO Float := do
timeNanos checks do
let mut todo := checks
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
if !map.contains val then
throw <| .userError "Fail"
todo := todo - size
@@ -66,7 +66,7 @@ def benchContainsMiss (seed : UInt64) (size : Nat) : IO Float := do
timeNanos checks do
let mut todo := checks
while todo != 0 do
for val in iter |>.take size |>.allowNontermination do
for val in iter |>.take size do
if map.contains val then
throw <| .userError "Fail"
todo := todo - size
@@ -98,7 +98,7 @@ def benchInsertIfNewHit (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
let mut map := map
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insertIfNew val val
if map.size != size then
throw <| .userError "Fail"
@@ -115,7 +115,7 @@ def benchInsertHit (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
let mut map := map
while todo != 0 do
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.size != size then
throw <| .userError "Fail"
@@ -130,7 +130,7 @@ def benchInsertRandomMissEmpty (seed : UInt64) (size : Nat) : IO Float := do
let mut todo := checks
while todo != 0 do
let mut map : Std.TreeMap UInt64 _ := {}
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.size > size then
throw <| .userError "Fail"
@@ -162,7 +162,7 @@ def benchInsertRandomMissEmptyShared (seed : UInt64) (size : Nat) : IO Float :=
while todo != 0 do
let mut map : Std.TreeMap UInt64 _ := {}
let mut maps := Array.emptyWithCapacity size
for val in iterRand seed |>.take size |>.allowNontermination do
for val in iterRand seed |>.take size do
map := map.insert val val
if map.isEmpty then
throw <| .userError "Fail"
@@ -183,7 +183,7 @@ def benchEraseInsert (seed : UInt64) (size : Nat) : IO Float := do
let mut map := map
let mut todo := checks
while todo != 0 do
for (eraseVal, newVal) in eraseIter.zip newIter |>.take size |>.allowNontermination do
for (eraseVal, newVal) in eraseIter.zip newIter |>.take size do
map := map.erase eraseVal |>.insert newVal newVal
if map.size != size then
throw <| .userError "Fail"

View File

@@ -64,7 +64,7 @@ def testStateThreading : IO Unit := do
let msgText msgs.headD default |>.data.toString
return (value, count, msgText)
| .error _ =>
return (0, 0, "error")).take 3 |>.allowNontermination.toList
return (0, 0, "error")).take 3 |>.toList
return (results.map (·.1), results.map (·.2.1), results.map (·.2.2))
@@ -215,7 +215,7 @@ def testTacticMStateThreading : IO Unit := do
let results (iter.mapM fun result =>
match result with
| .ok tacticName => return (tacticName, ( Lean.Elab.Tactic.getGoals).length)
| .error _ => return ("error", 999)).take 3 |>.allowNontermination.toList
| .error _ => return ("error", 999)).take 3 |>.toList
return results.unzip
let (tacticNames, goalCounts) runTacticTest tacticTest
@@ -249,7 +249,7 @@ def testTacticMParallel : IO Unit := do
let (_, iter) Lean.Elab.Tactic.TacticM.parIterWithCancel tasks
-- Consume the iterator and collect successful results
let results iter.take 3 |>.allowNontermination.toList
let results iter.take 3 |>.toList
return results.filterMap fun r => match r with | .ok n => some n | .error _ => none
let successResults runTacticTest tacticTest
@@ -289,7 +289,7 @@ def testParIterOrdering : IO Unit := do
-- Consume all results from the iterator
let mut results := []
for result in iter.allowNontermination do
for result in iter do
match result with
| .ok value => results := results.concat value
| .error _ => pure ()