This PR removes a rather ugly hack in the module system, exposing the bodies of theorems whose type mention `WellFounded`. The original motivation was that reducing well-founded definitions (e.g. in `by rfl`) requires reducing proofs, so they need to be available. But reducing proofs is generally fraught with peril, and we have been nudging our users away from using it for a while, e.g. in #5182. Since the module system is opt-in and users will gradually migrate to it, it may be reasonable to expect them to avoid reducing well-founded recursion in the process This way we don't need hacks like this (which, without evidence, I believe would be incomplete anyways) and we get the nice guarantee that within the module system, theorems bodies are always private.
457 lines
16 KiB
Text
457 lines
16 KiB
Text
/-
|
||
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
|
||
public import Init.SizeOf
|
||
public import Init.BinderNameHint
|
||
public import Init.Data.Nat.Basic
|
||
|
||
public section
|
||
|
||
@[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}
|
||
|
||
theorem 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
|
||
|
||
theorem 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}
|
||
|
||
theorem accAux (f : α → β) {b : β} (ac : Acc r b) : (x : α) → f x = b → Acc (InvImage r f) x :=
|
||
Acc.recOn ac fun _ _ ih => fun _ e => Acc.intro _ (fun y lt => ih (f y) (e ▸ lt) y rfl)
|
||
|
||
theorem accessible {a : α} (f : α → β) (ac : Acc r (f a)) : Acc (InvImage r f) a :=
|
||
accAux f ac a rfl
|
||
|
||
theorem 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
|