This PR adjusts the experimental module system to not export any private declarations from modules. Fixes #5002
458 lines
16 KiB
Text
458 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
|
||
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}
|
||
|
||
def 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)
|
||
|
||
-- `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
|