-
Notifications
You must be signed in to change notification settings - Fork 893
Expand file tree
/
Copy pathWF.lean
More file actions
464 lines (375 loc) · 15.9 KB
/
Copy pathWF.lean
File metadata and controls
464 lines (375 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
/-
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
-/
module
prelude
import Init.SizeOf
import Init.BinderNameHint
import Init.Data.Nat.Basic
@[expose] section
universe u v
/--
`Acc` is the accessibility predicate. Given some relation `r` (e.g. `<`) and a value `x`,
`Acc r x` means that `x` is accessible through `r`:
`x` is accessible if there exists no infinite sequence `... < y₂ < y₁ < y₀ < x`.
-/
inductive Acc {α : Sort u} (r : α → α → Prop) : α → Prop where
/--
A value is accessible if for all `y` such that `r y x`, `y` is also accessible.
Note that if there exists no `y` such that `r y x`, then `x` is accessible. Such an `x` is called a
_base case_.
-/
| intro (x : α) (h : (y : α) → r y x → Acc r y) : Acc r x
noncomputable abbrev Acc.ndrec.{u1, u2} {α : Sort u2} {r : α → α → Prop} {C : α → Sort u1}
(m : (x : α) → ((y : α) → r y x → Acc r y) → ((y : α) → (a : r y x) → C y) → C x)
{a : α} (n : Acc r a) : C a :=
n.rec m
noncomputable abbrev Acc.ndrecOn.{u1, u2} {α : Sort u2} {r : α → α → Prop} {C : α → Sort u1}
{a : α} (n : Acc r a)
(m : (x : α) → ((y : α) → r y x → Acc r y) → ((y : α) → (a : r y x) → C y) → C x)
: C a :=
n.rec m
namespace Acc
variable {α : Sort u} {r : α → α → Prop}
-- `def` for `WellFounded.fix`
def inv {x y : α} (h₁ : Acc r x) (h₂ : r y x) : Acc r y :=
h₁.recOn (fun _ ac₁ _ h₂ => ac₁ y h₂) h₂
end Acc
/--
A relation `r` is `WellFounded` if all elements of `α` are accessible within `r`.
If a relation is `WellFounded`, it does not allow for an infinite descent along the relation.
If the arguments of the recursive calls in a function definition decrease according to
a well founded relation, then the function terminates.
Well-founded relations are sometimes called _Artinian_ or said to satisfy the “descending chain condition”.
-/
inductive WellFounded {α : Sort u} (r : α → α → Prop) : Prop where
/--
If all elements are accessible via `r`, then `r` is well-founded.
-/
| intro (h : ∀ a, Acc r a) : WellFounded r
/--
A type that has a standard well-founded relation.
Instances are used to prove that functions terminate using well-founded recursion by showing that
recursive calls reduce some measure according to a well-founded relation. This relation can combine
well-founded relations on the recursive function's parameters.
-/
class WellFoundedRelation (α : Sort u) where
/-- A well-founded relation on `α`. -/
rel : α → α → Prop
/-- A proof that `rel` is, in fact, well-founded. -/
wf : WellFounded rel
namespace WellFounded
-- `def` for `WellFounded.fix`
def apply {α : Sort u} {r : α → α → Prop} (wf : WellFounded r) (a : α) : Acc r a :=
wf.rec (fun p => p) a
section
variable {α : Sort u} {r : α → α → Prop} (hwf : WellFounded r)
noncomputable def recursion {C : α → Sort v} (a : α) (h : ∀ x, (∀ y, r y x → C y) → C x) : C a := by
induction (apply hwf a) with
| intro x₁ _ ih => exact h x₁ ih
include hwf in
theorem induction {C : α → Prop} (a : α) (h : ∀ x, (∀ y, r y x → C y) → C x) : C a :=
recursion hwf a h
variable {C : α → Sort v}
variable (F : ∀ x, (∀ y, r y x → C y) → C x)
noncomputable def fixF (x : α) (a : Acc r x) : C x := by
induction a with
| intro x₁ _ ih => exact F x₁ ih
theorem fixF_eq (x : α) (acx : Acc r x) : fixF F x acx = F x (fun (y : α) (p : r y x) => fixF F y (Acc.inv acx p)) := by
induction acx with
| intro x r _ => exact rfl
@[deprecated fixF_eq (since := "2025-04-04")]
abbrev fixFEq := @fixF_eq
end
variable {α : Sort u} {C : α → Sort v} {r : α → α → Prop}
/--
A well-founded fixpoint. If satisfying the motive `C` for all values that are smaller according to a
well-founded relation allows it to be satisfied for the current value, then it is satisfied for all
values.
This function is used as part of the elaboration of well-founded recursion.
-/
-- Well-founded fixpoint
noncomputable def fix (hwf : WellFounded r) (F : ∀ x, (∀ y, r y x → C y) → C x) (x : α) : C x :=
fixF F x (apply hwf x)
-- Well-founded fixpoint satisfies fixpoint equation
theorem fix_eq (hwf : WellFounded r) (F : ∀ x, (∀ y, r y x → C y) → C x) (x : α) :
fix hwf F x = F x (fun y _ => fix hwf F y) :=
fixF_eq F x (apply hwf x)
end WellFounded
open WellFounded
-- Empty relation is well-founded
def emptyWf {α : Sort u} : WellFoundedRelation α where
rel := emptyRelation
wf := by
apply WellFounded.intro
intro a
apply Acc.intro a
intro b h
cases h
-- Subrelation of a well-founded relation is well-founded
namespace Subrelation
variable {α : Sort u} {r q : α → α → Prop}
theorem accessible {a : α} (h₁ : Subrelation q r) (ac : Acc r a) : Acc q a := by
induction ac with
| intro x _ ih =>
apply Acc.intro
intro y h
exact ih y (h₁ h)
theorem wf (h₁ : Subrelation q r) (h₂ : WellFounded r) : WellFounded q :=
⟨fun a => accessible @h₁ (apply h₂ a)⟩
end Subrelation
-- The inverse image of a well-founded relation is well-founded
namespace InvImage
variable {α : Sort u} {β : Sort v} {r : β → β → Prop}
private def accAux (f : α → β) {b : β} (ac : Acc r b) : (x : α) → f x = b → Acc (InvImage r f) x := by
induction ac with
| intro x acx ih =>
intro z e
apply Acc.intro
intro y lt
subst x
apply ih (f y) lt y rfl
-- `def` for `WellFounded.fix`
def accessible {a : α} (f : α → β) (ac : Acc r (f a)) : Acc (InvImage r f) a :=
accAux f ac a rfl
-- `def` for `WellFounded.fix`
def wf (f : α → β) (h : WellFounded r) : WellFounded (InvImage r f) :=
⟨fun a => accessible f (apply h (f a))⟩
end InvImage
/--
The inverse image of a well-founded relation is well-founded.
-/
@[reducible] def invImage (f : α → β) (h : WellFoundedRelation β) : WellFoundedRelation α where
rel := InvImage h.rel f
wf := InvImage.wf f h.wf
-- The transitive closure of a well-founded relation is well-founded
open Relation
theorem Acc.transGen (h : Acc r a) : Acc (TransGen r) a := by
induction h with
| intro x _ H =>
refine Acc.intro x fun y hy ↦ ?_
cases hy with
| single hyx =>
exact H y hyx
| tail hyz hzx =>
exact (H _ hzx).inv hyz
theorem acc_transGen_iff : Acc (TransGen r) a ↔ Acc r a :=
⟨Subrelation.accessible TransGen.single, Acc.transGen⟩
theorem WellFounded.transGen (h : WellFounded r) : WellFounded (TransGen r) :=
⟨fun a ↦ (h.apply a).transGen⟩
namespace Nat
-- less-than is well-founded
def lt_wfRel : WellFoundedRelation Nat where
rel := (· < ·)
wf := by
apply WellFounded.intro
intro n
induction n with
| zero =>
apply Acc.intro 0
intro _ h
apply absurd h (Nat.not_lt_zero _)
| succ n ih =>
apply Acc.intro (Nat.succ n)
intro m h
have : m = n ∨ m < n := Nat.eq_or_lt_of_le (Nat.le_of_succ_le_succ h)
match this with
| Or.inl e => subst e; assumption
| Or.inr e => exact Acc.inv ih e
/--
Strong induction on the natural numbers.
The induction hypothesis is that all numbers less than a given number satisfy the motive, which
should be demonstrated for the given number.
-/
@[elab_as_elim] protected noncomputable def strongRecOn
{motive : Nat → Sort u}
(n : Nat)
(ind : ∀ n, (∀ m, m < n → motive m) → motive n) : motive n :=
Nat.lt_wfRel.wf.fix ind n
/--
Case analysis based on strong induction for the natural numbers.
-/
@[elab_as_elim] protected noncomputable def caseStrongRecOn
{motive : Nat → Sort u}
(a : Nat)
(zero : motive 0)
(ind : ∀ n, (∀ m, m ≤ n → motive m) → motive (succ n)) : motive a :=
Nat.strongRecOn a fun n =>
match n with
| 0 => fun _ => zero
| n+1 => fun h₁ => ind n (λ _ h₂ => h₁ _ (lt_succ_of_le h₂))
end Nat
abbrev measure {α : Sort u} (f : α → Nat) : WellFoundedRelation α :=
invImage f Nat.lt_wfRel
abbrev sizeOfWFRel {α : Sort u} [SizeOf α] : WellFoundedRelation α :=
measure sizeOf
attribute [instance low] sizeOfWFRel
namespace Prod
open WellFounded
section
variable {α : Type u} {β : Type v}
variable (ra : α → α → Prop)
variable (rb : β → β → Prop)
/--
A lexicographical order based on the orders `ra` and `rb` for the elements of pairs.
-/
protected inductive Lex : α × β → α × β → Prop where
/--
If the first projections of two pairs are ordered, then they are lexicographically ordered.
-/
| left {a₁} (b₁) {a₂} (b₂) (h : ra a₁ a₂) : Prod.Lex (a₁, b₁) (a₂, b₂)
/--
If the first projections of two pairs are equal, then they are lexicographically ordered if the
second projections are ordered.
-/
| right (a) {b₁ b₂} (h : rb b₁ b₂) : Prod.Lex (a, b₁) (a, b₂)
theorem lex_def {r : α → α → Prop} {s : β → β → Prop} {p q : α × β} :
Prod.Lex r s p q ↔ r p.1 q.1 ∨ p.1 = q.1 ∧ s p.2 q.2 :=
⟨fun h => by cases h <;> simp [*], fun h =>
match p, q, h with
| _, _, Or.inl h => Lex.left _ _ h
| (_, _), (_, _), Or.inr ⟨e, h⟩ => by subst e; exact Lex.right _ h⟩
namespace Lex
instance [αeqDec : DecidableEq α] {r : α → α → Prop} [rDec : DecidableRel r]
{s : β → β → Prop} [sDec : DecidableRel s] : DecidableRel (Prod.Lex r s)
| (a, b), (a', b') =>
match rDec a a' with
| isTrue raa' => isTrue $ left b b' raa'
| isFalse nraa' =>
match αeqDec a a' with
| isTrue eq => by
subst eq
cases sDec b b' with
| isTrue sbb' => exact isTrue $ right a sbb'
| isFalse nsbb' =>
apply isFalse; intro contra; cases contra <;> contradiction
| isFalse neqaa' => by
apply isFalse; intro contra; cases contra <;> contradiction
-- TODO: generalize
theorem right' {a₁ : Nat} {b₁ : β} (h₁ : a₁ ≤ a₂) (h₂ : rb b₁ b₂) : Prod.Lex Nat.lt rb (a₁, b₁) (a₂, b₂) :=
match Nat.eq_or_lt_of_le h₁ with
| Or.inl h => h ▸ Prod.Lex.right a₁ h₂
| Or.inr h => Prod.Lex.left b₁ _ h
end Lex
-- relational product based on ra and rb
inductive RProd : α × β → α × β → Prop where
| intro {a₁ b₁ a₂ b₂} (h₁ : ra a₁ a₂) (h₂ : rb b₁ b₂) : RProd (a₁, b₁) (a₂, b₂)
end
section
variable {α : Type u} {β : Type v}
variable {ra : α → α → Prop} {rb : β → β → Prop}
theorem lexAccessible {a : α} (aca : Acc ra a) (acb : (b : β) → Acc rb b) (b : β) : Acc (Prod.Lex ra rb) (a, b) := by
induction aca generalizing b with
| intro xa _ iha =>
induction (acb b) with
| intro xb _ ihb =>
apply Acc.intro (xa, xb)
intro p lt
cases lt with
| left _ _ h => apply iha _ h
| right _ h => apply ihb _ h
-- The lexicographical order of well founded relations is well-founded
@[reducible] def lex (ha : WellFoundedRelation α) (hb : WellFoundedRelation β) : WellFoundedRelation (α × β) where
rel := Prod.Lex ha.rel hb.rel
wf := ⟨fun (a, b) => lexAccessible (WellFounded.apply ha.wf a) (WellFounded.apply hb.wf) b⟩
instance [ha : WellFoundedRelation α] [hb : WellFoundedRelation β] : WellFoundedRelation (α × β) :=
lex ha hb
-- relational product is a Subrelation of the Lex
theorem RProdSubLex (a : α × β) (b : α × β) (h : RProd ra rb a b) : Prod.Lex ra rb a b := by
cases h with
| intro h₁ h₂ => exact Prod.Lex.left _ _ h₁
-- The relational product of well founded relations is well-founded
def rprod (ha : WellFoundedRelation α) (hb : WellFoundedRelation β) : WellFoundedRelation (α × β) where
rel := RProd ha.rel hb.rel
wf := by
apply Subrelation.wf (r := Prod.Lex ha.rel hb.rel) (h₂ := (lex ha hb).wf)
intro a b h
exact RProdSubLex a b h
end
end Prod
namespace PSigma
section
variable {α : Sort u} {β : α → Sort v}
variable (r : α → α → Prop)
variable (s : ∀ a, β a → β a → Prop)
-- Lexicographical order based on r and s
inductive Lex : PSigma β → PSigma β → Prop where
| left : ∀ {a₁ : α} (b₁ : β a₁) {a₂ : α} (b₂ : β a₂), r a₁ a₂ → Lex ⟨a₁, b₁⟩ ⟨a₂, b₂⟩
| right : ∀ (a : α) {b₁ b₂ : β a}, s a b₁ b₂ → Lex ⟨a, b₁⟩ ⟨a, b₂⟩
end
section
variable {α : Sort u} {β : α → Sort v}
variable {r : α → α → Prop} {s : ∀ (a : α), β a → β a → Prop}
theorem lexAccessible {a} (aca : Acc r a) (acb : (a : α) → WellFounded (s a)) (b : β a) : Acc (Lex r s) ⟨a, b⟩ := by
induction aca with
| intro xa _ iha =>
induction (WellFounded.apply (acb xa) b) with
| intro xb _ ihb =>
apply Acc.intro
intro p lt
cases lt with
| left => apply iha; assumption
| right => apply ihb; assumption
-- The lexicographical order of well founded relations is well-founded
@[reducible] def lex (ha : WellFoundedRelation α) (hb : (a : α) → WellFoundedRelation (β a)) : WellFoundedRelation (PSigma β) where
rel := Lex ha.rel (fun a => hb a |>.rel)
wf := WellFounded.intro fun ⟨a, b⟩ => lexAccessible (WellFounded.apply ha.wf a) (fun a => hb a |>.wf) b
instance [ha : WellFoundedRelation α] [hb : (a : α) → WellFoundedRelation (β a)] : WellFoundedRelation (PSigma β) :=
lex ha hb
end
section
variable {α : Sort u} {β : Sort v}
def lexNdep (r : α → α → Prop) (s : β → β → Prop) :=
Lex r (fun _ => s)
theorem lexNdepWf {r : α → α → Prop} {s : β → β → Prop} (ha : WellFounded r) (hb : WellFounded s) : WellFounded (lexNdep r s) :=
WellFounded.intro fun ⟨a, b⟩ => lexAccessible (WellFounded.apply ha a) (fun _ => hb) b
end
section
variable {α : Sort u} {β : Sort v}
-- Reverse lexicographical order based on r and s
inductive RevLex (r : α → α → Prop) (s : β → β → Prop) : @PSigma α (fun _ => β) → @PSigma α (fun _ => β) → Prop where
| left : {a₁ a₂ : α} → (b : β) → r a₁ a₂ → RevLex r s ⟨a₁, b⟩ ⟨a₂, b⟩
| right : (a₁ : α) → {b₁ : β} → (a₂ : α) → {b₂ : β} → s b₁ b₂ → RevLex r s ⟨a₁, b₁⟩ ⟨a₂, b₂⟩
end
section
open WellFounded
variable {α : Sort u} {β : Sort v}
variable {r : α → α → Prop} {s : β → β → Prop}
theorem revLexAccessible {b} (acb : Acc s b) (aca : (a : α) → Acc r a): (a : α) → Acc (RevLex r s) ⟨a, b⟩ := by
induction acb with
| intro xb _ ihb =>
intro a
induction (aca a) with
| intro xa _ iha =>
apply Acc.intro
intro p lt
cases lt with
| left => apply iha; assumption
| right => apply ihb; assumption
theorem revLex (ha : WellFounded r) (hb : WellFounded s) : WellFounded (RevLex r s) :=
WellFounded.intro fun ⟨a, b⟩ => revLexAccessible (apply hb b) (WellFounded.apply ha) a
end
section
def SkipLeft (α : Type u) {β : Type v} (s : β → β → Prop) : @PSigma α (fun _ => β) → @PSigma α (fun _ => β) → Prop :=
RevLex emptyRelation s
def skipLeft (α : Type u) {β : Type v} (hb : WellFoundedRelation β) : WellFoundedRelation (PSigma fun _ : α => β) where
rel := SkipLeft α hb.rel
wf := revLex emptyWf.wf hb.wf
theorem mkSkipLeft {α : Type u} {β : Type v} {b₁ b₂ : β} {s : β → β → Prop} (a₁ a₂ : α) (h : s b₁ b₂) : SkipLeft α s ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ :=
RevLex.right _ _ h
end
end PSigma
/--
The `wfParam` gadget is used internally during the construction of recursive functions by
wellfounded recursion, to keep track of the parameter for which the automatic introduction
of `List.attach` (or similar) is plausible.
-/
def wfParam {α : Sort u} (a : α) : α := a
/--
Reverse direction of `dite_eq_ite`. Used by the well-founded definition preprocessor to extend the
context of a termination proof inside `if-then-else` with the condition.
-/
@[wf_preprocess] theorem ite_eq_dite [Decidable P] :
ite P a b = (dite P (fun h => binderNameHint h () a) (fun h => binderNameHint h () b)) := rfl