Skip to content

Commit 0a98a2c

Browse files
committed
docstrings, move option WF lemmas
1 parent 1bb10a7 commit 0a98a2c

File tree

4 files changed

+132
-53
lines changed

4 files changed

+132
-53
lines changed

src/Init/Data/Option/Basic.lean

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,31 @@ instance (r : α → β → Prop) [s : DecidableRel r] : DecidableRel (Option.lt
256256
| some _, none => isFalse not_false
257257
| none, none => isFalse not_false
258258

259+
namespace SomeLtNone
260+
261+
/--
262+
Lifts an ordering relation to `Option`, such that `none` is the greatest element.
263+
264+
It can be understood as adding a distinguished greatest element, represented by `none`, to both `α`
265+
and `β`.
266+
267+
Caution: Given `LT α`, `Option.SomeLtNone.lt LT.lt` differs from the `LT (Option α)` instance,
268+
which is implemented by `Option.lt Lt.lt`.
269+
270+
Examples:
271+
* `Option.lt (fun n k : Nat => n < k) none none = False`
272+
* `Option.lt (fun n k : Nat => n < k) none (some 3) = False`
273+
* `Option.lt (fun n k : Nat => n < k) (some 3) none = True`
274+
* `Option.lt (fun n k : Nat => n < k) (some 4) (some 5) = True`
275+
* `Option.lt (fun n k : Nat => n < k) (some 4) (some 4) = False`
276+
-/
277+
def lt {α} (r : α → α → Prop) : Option α → Option α → Prop
278+
| none, _ => false
279+
| some _, none => true
280+
| some a', some a => r a' a
281+
282+
end SomeLtNone
283+
259284
/--
260285
Applies a function to a two optional values if both are present. Otherwise, if one value is present,
261286
it is returned and the function is not used.

src/Init/Data/Option/Lemmas.lean

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,4 +1902,40 @@ theorem map_min [Min α] [Min β] {o o' : Option α} {f : α → β} (hf : ∀ x
19021902
(min o o').map f = min (o.map f) (o'.map f) := by
19031903
cases o <;> cases o' <;> simp [*]
19041904

1905+
theorem wellFounded_lt {α} {rel : α → α → Prop} (h : WellFounded rel) :
1906+
WellFounded (Option.lt rel) := by
1907+
refine ⟨fun x => ?_⟩
1908+
have hn : Acc (Option.lt rel) none := by
1909+
refine Acc.intro none ?_
1910+
intro y hyx
1911+
cases y <;> cases hyx
1912+
cases x
1913+
· exact hn
1914+
· rename_i x
1915+
induction h.apply x
1916+
rename_i x' h ih
1917+
refine Acc.intro _ ?_
1918+
intro y hyx'
1919+
cases y
1920+
· exact hn
1921+
· exact ih _ hyx'
1922+
1923+
theorem SomeLtNone.wellFounded_lt {α} {r : α → α → Prop} (h : WellFounded r) :
1924+
WellFounded (SomeLtNone.lt r) := by
1925+
refine ⟨?_⟩
1926+
intro x
1927+
constructor
1928+
intro x' hlt
1929+
match x' with
1930+
| none => contradiction
1931+
| some x' =>
1932+
clear hlt
1933+
induction h.apply x'
1934+
rename_i ih
1935+
constructor
1936+
intro x'' hlt'
1937+
match x'' with
1938+
| none => contradiction
1939+
| some x'' => exact ih x'' hlt'
1940+
19051941
end Option

src/Std/Data/Iterators/Combinators/Monadic/Zip.lean

Lines changed: 41 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Paul Reichert
55
-/
66
prelude
7+
import Init.Data.Option.Lemmas
78
import Std.Data.Iterators.Basic
89
import Std.Data.Iterators.Consumers.Collect
910
import Std.Data.Iterators.Consumers.Loop
@@ -58,32 +59,42 @@ instance Zip.instIterator [Monad m] :
5859
| .done hp =>
5960
pure <| .done (.doneRight hm hp)
6061

61-
@[inline]
62+
/--
63+
Given two iterators `left` and `right`, `left.zip right` is an iterator that yields pairs of
64+
outputs of `left` and `right`. When one of them terminates,
65+
the `zip` iterator will also terminate.
66+
67+
**Marble diagram:**
68+
69+
```text
70+
left --a ---b --c
71+
right --x --y --⊥
72+
left.zip right -----(a, x)------(b, y)-----⊥
73+
```
74+
75+
**Termination properties:**
76+
77+
* `Finite` instance: only if either `left` or `right` is finite and the other is productive
78+
* `Productive` instance: only if `left` and `right` are productive
79+
80+
There are situations where `left.zip right` is finite (or productive) but none of the instances
81+
above applies. For example, if the computation happens in an `Except` monad and `left` immediately
82+
fails when calling `step`, then `left.zip right` will also do so. In such a case, the `Finite`
83+
(or `Productive`) instance needs to be proved manually.
84+
85+
**Performance:**
86+
87+
This combinator incurs an additional O(1) cost with each step taken by `left` or `right`.
88+
89+
Right now, the compiler does not unbox the internal state, leading to worse performance than
90+
possible.
91+
-/
92+
@[always_inline, inline]
6293
def IterM.zip
6394
(left : IterM (α := α₁) m β₁) (right : IterM (α := α₂) m β₂) :
6495
IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂) :=
6596
toIterM ⟨left, none, right⟩ m _
6697

67-
-- TODO: put this into core. This is also duplicated in FlatMap
68-
theorem Zip.wellFounded_optionLt {α} {rel : α → α → Prop} (h : WellFounded rel) :
69-
WellFounded (Option.lt rel) := by
70-
refine ⟨?_⟩
71-
intro x
72-
have hn : Acc (Option.lt rel) none := by
73-
refine Acc.intro none ?_
74-
intro y hyx
75-
cases y <;> cases hyx
76-
cases x
77-
· exact hn
78-
· rename_i x
79-
induction h.apply x
80-
rename_i x' h ih
81-
refine Acc.intro _ ?_
82-
intro y hyx'
83-
cases y
84-
· exact hn
85-
· exact ih _ hyx'
86-
8798
variable (m) in
8899
def Zip.Rel₁ [Finite α₁ m] [Productive α₂ m] :
89100
IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂) → IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂) → Prop :=
@@ -119,7 +130,7 @@ def Zip.instFinitenessRelation₁ [Monad m] [Finite α₁ m] [Productive α₂ m
119130
refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
120131
· exact WellFoundedRelation.wf
121132
· refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
122-
· apply Zip.wellFounded_optionLt
133+
· apply Option.wellFounded_lt
123134
exact emptyWf.wf
124135
· exact WellFoundedRelation.wf
125136
subrelation {it it'} h := by
@@ -151,35 +162,12 @@ instance Zip.instFinite₁ [Monad m] [Finite α₁ m] [Productive α₂ m] :
151162
Finite (Zip α₁ m α₂ β₂) m :=
152163
Finite.of_finitenessRelation Zip.instFinitenessRelation₁
153164

154-
def Zip.lt_with_top {α} (r : α → α → Prop) : Option α → Option α → Prop
155-
| none, _ => false
156-
| some _, none => true
157-
| some a', some a => r a' a
158-
159-
theorem Zip.wellFounded_lt_with_top {α} {r : α → α → Prop} (h : WellFounded r) :
160-
WellFounded (lt_with_top r) := by
161-
refine ⟨?_⟩
162-
intro x
163-
constructor
164-
intro x' hlt
165-
match x' with
166-
| none => contradiction
167-
| some x' =>
168-
clear hlt
169-
induction h.apply x'
170-
rename_i ih
171-
constructor
172-
intro x'' hlt'
173-
match x'' with
174-
| none => contradiction
175-
| some x'' => exact ih x'' hlt'
176-
177165
variable (m) in
178166
def Zip.Rel₂ [Productive α₁ m] [Finite α₂ m] :
179167
IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂) → IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂) → Prop :=
180168
InvImage (Prod.Lex
181169
IterM.TerminationMeasures.Finite.Rel
182-
(Prod.Lex (Zip.lt_with_top emptyRelation) IterM.TerminationMeasures.Productive.Rel))
170+
(Prod.Lex (Option.SomeLtNone.lt emptyRelation) IterM.TerminationMeasures.Productive.Rel))
183171
(fun it => (it.internalState.right.finitelyManySteps, (it.internalState.memoizedLeft, it.internalState.left.finitelyManySkips)))
184172

185173
theorem Zip.rel₂_of_right [Productive α₁ m] [Finite α₂ m] {it' it : IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂)}
@@ -188,7 +176,7 @@ theorem Zip.rel₂_of_right [Productive α₁ m] [Finite α₂ m] {it' it : Iter
188176

189177
theorem Zip.rel₂_of_memoizedLeft [Productive α₁ m] [Finite α₂ m]
190178
{right : IterM (α := α₂) m β₂} {b' b} {left' left : IterM (α := α₁) m β₁}
191-
(h : lt_with_top emptyRelation b' b) :
179+
(h : Option.SomeLtNone.lt emptyRelation b' b) :
192180
Zip.Rel₂ m ⟨left, b', right⟩ ⟨left', b, right⟩ :=
193181
Prod.Lex.right _ <| Prod.Lex.left _ _ h
194182

@@ -208,7 +196,7 @@ def Zip.instFinitenessRelation₂ [Monad m] [Productive α₁ m] [Finite α₂ m
208196
refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
209197
· exact WellFoundedRelation.wf
210198
· refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
211-
· apply Zip.wellFounded_lt_with_top
199+
· apply Option.SomeLtNone.wellFounded_lt
212200
exact emptyWf.wf
213201
· exact WellFoundedRelation.wf
214202
subrelation {it it'} h := by
@@ -217,7 +205,7 @@ def Zip.instFinitenessRelation₂ [Monad m] [Productive α₁ m] [Finite α₂ m
217205
case yieldLeft hm it' out hp =>
218206
cases h
219207
apply Zip.rel₂_of_memoizedLeft
220-
simp_all [Zip.lt_with_top]
208+
simp_all [Option.SomeLtNone.lt]
221209
case skipLeft hm it' hp =>
222210
cases h
223211
apply Zip.rel₂_of_left
@@ -244,12 +232,12 @@ variable (m) in
244232
def Zip.Rel₃ [Productive α₁ m] [Productive α₂ m] :
245233
IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂) → IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂) → Prop :=
246234
InvImage (Prod.Lex
247-
(lt_with_top emptyRelation)
235+
(Option.SomeLtNone.lt emptyRelation)
248236
(Prod.Lex (IterM.TerminationMeasures.Productive.Rel) IterM.TerminationMeasures.Productive.Rel))
249237
(fun it => (it.internalState.memoizedLeft, (it.internalState.left.finitelyManySkips, it.internalState.right.finitelyManySkips)))
250238

251239
theorem Zip.rel₃_of_memoizedLeft [Productive α₁ m] [Productive α₂ m] {it' it : IterM (α := Zip α₁ m α₂ β₂) m (β₁ × β₂)}
252-
(h : lt_with_top emptyRelation it'.internalState.memoizedLeft it.internalState.memoizedLeft) :
240+
(h : Option.SomeLtNone.lt emptyRelation it'.internalState.memoizedLeft it.internalState.memoizedLeft) :
253241
Zip.Rel₃ m it' it :=
254242
Prod.Lex.left _ _ h
255243

@@ -273,7 +261,7 @@ def Zip.instProductivenessRelation [Monad m] [Productive α₁ m] [Productive α
273261
wf := by
274262
apply InvImage.wf
275263
refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
276-
· apply Zip.wellFounded_lt_with_top
264+
· apply Option.SomeLtNone.wellFounded_lt
277265
exact emptyWf.wf
278266
· refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
279267
· exact WellFoundedRelation.wf
@@ -282,7 +270,7 @@ def Zip.instProductivenessRelation [Monad m] [Productive α₁ m] [Productive α
282270
cases h
283271
case yieldLeft hm it' out hp =>
284272
apply Zip.rel₃_of_memoizedLeft
285-
simp [lt_with_top, hm]
273+
simp [Option.SomeLtNone.lt, hm]
286274
case skipLeft hm it' hp =>
287275
obtain ⟨⟨left, memoizedLeft, right⟩⟩ := it
288276
simp only at hm

src/Std/Data/Iterators/Combinators/Zip.lean

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,36 @@ import Std.Data.Iterators.Combinators.Monadic.Zip
88

99
namespace Std.Iterators
1010

11+
/--
12+
Given two iterators `left` and `right`, `left.zip right` is an iterator that yields pairs of
13+
outputs of `left` and `right`. When one of them terminates,
14+
the `zip` iterator will also terminate.
15+
16+
**Marble diagram:**
17+
18+
```text
19+
left --a ---b --c
20+
right --x --y --⊥
21+
left.zip right -----(a, x)------(b, y)-----⊥
22+
```
23+
24+
**Termination properties:**
25+
26+
* `Finite` instance: only if either `left` or `right` is finite and the other is productive
27+
* `Productive` instance: only if `left` and `right` are productive
28+
29+
There are situations where `left.zip right` is finite (or productive) but none of the instances
30+
above applies. For example, if `left` immediately terminates but `right` always skips, then
31+
`left.zip.right` is finite even though no `Finite` (or even `Productive`) instance is available.
32+
Such instances need to be proved manually.
33+
34+
**Performance:**
35+
36+
This combinator incurs an additional O(1) cost with each step taken by `left` or `right`.
37+
38+
Right now, the compiler does not unbox the internal state, leading to worse performance than
39+
theoretically possible.
40+
-/
1141
@[always_inline, inline]
1242
def Iter.zip {α₁ : Type w} {β₁: Type w} {α₂ : Type w} {β₂ : Type w}
1343
[Iterator α₁ Id β₁] [Iterator α₂ Id β₂]

0 commit comments

Comments
 (0)