| /-! | |
| # Tests for `brecOn` on recursive inductive predicates | |
| -/ | |
| /-! | |
| Transitive closure (see issue 1672) | |
| -/ | |
| inductive TransClosure (r : α → α → Prop) : α → α → Prop | |
| | extends : r a b → TransClosure r a b | |
| | trans_left : r a b → TransClosure r b c → TransClosure r a c | |
| /-- | |
| info: TransClosure.brecOn.{u_1} {α : Sort u_1} {r : α → α → Prop} {motive : (a a_1 : α) → TransClosure r a a_1 → Prop} | |
| {a✝ a✝¹ : α} (t : TransClosure r a✝ a✝¹) | |
| (F_1 : ∀ (a a_1 : α) (t : TransClosure r a a_1), TransClosure.below t → motive a a_1 t) : motive a✝ a✝¹ t | |
| -/ | |
| #guard_msgs in | |
| #check TransClosure.brecOn | |
| theorem TransClosure.recTest (h : TransClosure r a b) : True := | |
| match h with | |
| | .extends _ => trivial | |
| | .trans_left _ h => h.recTest | |
| termination_by structural h | |
| /-! | |
| Symmetric closure (see issue 4540) | |
| -/ | |
| inductive SymmGen (r : α → α → Prop) : α → α → Prop | |
| | rel : ∀ x y, r x y → SymmGen r x y | |
| | symm : ∀ x y, SymmGen r x y → SymmGen r y x | |
| /-- | |
| info: SymmGen.brecOn.{u_1} {α : Sort u_1} {r : α → α → Prop} {motive : (a a_1 : α) → SymmGen r a a_1 → Prop} {a✝ a✝¹ : α} | |
| (t : SymmGen r a✝ a✝¹) (F_1 : ∀ (a a_1 : α) (t : SymmGen r a a_1), SymmGen.below t → motive a a_1 t) : motive a✝ a✝¹ t | |
| -/ | |
| #guard_msgs in | |
| #check SymmGen.brecOn | |
| theorem SymmGen.recTest (h : SymmGen r a b) : True := | |
| match h with | |
| | .rel _ _ _ => trivial | |
| | .symm _ _ h => h.recTest | |
| termination_by structural h | |
| /-! | |
| Basic typing relation | |
| -/ | |
| inductive Ty : Type where | |
| | unit : Ty | |
| | arr : Ty → Ty → Ty | |
| inductive Term : Type where | |
| | var : Nat → Term | |
| | unit : Term | |
| | abs : Term → Term | |
| | app : Term → Term → Term | |
| inductive Wt : List Ty → Term → Ty → Prop where | |
| | var {Γ x} : (h : x < Γ.length) → Wt Γ (.var x) Γ[x] | |
| | unit {Γ} : Wt Γ .unit .unit | |
| | abs {Γ b A B} : Wt (A :: Γ) b B → Wt Γ (.abs b) (.arr A B) | |
| | app {Γ b a A B} : Wt Γ b (.arr A B) → Wt Γ a A → Wt Γ (.app b a) B | |
| /-- | |
| info: Wt.brecOn {motive : (a : List Ty) → (a_1 : Term) → (a_2 : Ty) → Wt a a_1 a_2 → Prop} {a✝ : List Ty} {a✝¹ : Term} | |
| {a✝² : Ty} (t : Wt a✝ a✝¹ a✝²) | |
| (F_1 : ∀ (a : List Ty) (a_1 : Term) (a_2 : Ty) (t : Wt a a_1 a_2), Wt.below t → motive a a_1 a_2 t) : | |
| motive a✝ a✝¹ a✝² t | |
| -/ | |
| #guard_msgs in | |
| #check Wt.brecOn | |
| theorem Wt.recTest (h : Wt Γ a A) : True := | |
| match h with | |
| | .var _ => trivial | |
| | .unit => trivial | |
| | .abs h => h.recTest | |
| | .app h h' => h.recTest | |
| termination_by structural h | |
| /-! | |
| Mutual inductives | |
| -/ | |
| mutual | |
| inductive EvenDist : Nat → Nat → Prop where | |
| | zero : EvenDist 0 0 | |
| | succ_left (h : Nat → OddDist a b) : EvenDist a.succ b | |
| | succ_right (h : OddDist a b) : EvenDist a b.succ | |
| inductive OddDist : Nat → Nat → Prop where | |
| | succ_left (h : EvenDist a b) : OddDist a.succ b | |
| | succ_right (h : EvenDist a b) : OddDist a b.succ | |
| end | |
| /-- | |
| info: EvenDist.brecOn {motive_1 : (a a_1 : Nat) → EvenDist a a_1 → Prop} {motive_2 : (a a_1 : Nat) → OddDist a a_1 → Prop} | |
| {a✝ a✝¹ : Nat} (t : EvenDist a✝ a✝¹) (F_1 : ∀ (a a_1 : Nat) (t : EvenDist a a_1), t.below → motive_1 a a_1 t) | |
| (F_2 : ∀ (a a_1 : Nat) (t : OddDist a a_1), t.below → motive_2 a a_1 t) : motive_1 a✝ a✝¹ t | |
| -/ | |
| #guard_msgs in | |
| #check EvenDist.brecOn | |
| /-- | |
| info: OddDist.brecOn {motive_1 : (a a_1 : Nat) → EvenDist a a_1 → Prop} {motive_2 : (a a_1 : Nat) → OddDist a a_1 → Prop} | |
| {a✝ a✝¹ : Nat} (t : OddDist a✝ a✝¹) (F_1 : ∀ (a a_1 : Nat) (t : EvenDist a a_1), t.below → motive_1 a a_1 t) | |
| (F_2 : ∀ (a a_1 : Nat) (t : OddDist a a_1), t.below → motive_2 a a_1 t) : motive_2 a✝ a✝¹ t | |
| -/ | |
| #guard_msgs in | |
| #check OddDist.brecOn | |
| mutual | |
| theorem OddDist.recTest {a b} (h : OddDist b a) : True := | |
| match h with | |
| | .succ_left h => h.recTest | |
| | .succ_right h => h.recTest | |
| termination_by structural h | |
| theorem OddDist.recTest' {a b} (h : OddDist b a) : True := | |
| match h with | |
| | .succ_left h => h.recTest | |
| | .succ_right h => h.recTest | |
| termination_by structural h | |
| theorem EvenDist.recTest (h : EvenDist a b) : True := | |
| match h with | |
| | .zero => trivial | |
| | .succ_left h => (h 3).recTest | |
| | .succ_right h => h.recTest' | |
| termination_by structural h | |
| end | |
| /-! | |
| Nested inductives | |
| -/ | |
| inductive Test (p : Nat → Prop) : Nat → Prop | |
| | zero : Test p 0 | |
| | one (h : Test p 3 ∧ p 2) : Test p 1 | |
| /-- | |
| info: Test.brecOn {p : Nat → Prop} {motive_1 : (a : Nat) → Test p a → Prop} {motive_2 : Test p 3 ∧ p 2 → Prop} {a✝ : Nat} | |
| (t : Test p a✝) (F_1 : ∀ (a : Nat) (t : Test p a), t.below → motive_1 a t) | |
| (F_2 : ∀ (t : Test p 3 ∧ p 2), Test.below_1 t → motive_2 t) : motive_1 a✝ t | |
| -/ | |
| #guard_msgs in | |
| #check Test.brecOn | |
| /-- | |
| info: Test.brecOn_1 {p : Nat → Prop} {motive_1 : (a : Nat) → Test p a → Prop} {motive_2 : Test p 3 ∧ p 2 → Prop} | |
| (t : Test p 3 ∧ p 2) (F_1 : ∀ (a : Nat) (t : Test p a), t.below → motive_1 a t) | |
| (F_2 : ∀ (t : Test p 3 ∧ p 2), Test.below_1 t → motive_2 t) : motive_2 t | |
| -/ | |
| #guard_msgs in | |
| #check Test.brecOn_1 | |
| -- nested recursion | |
| theorem Test.recTest (h : Test p n) : True := | |
| match h with | |
| | .zero => trivial | |
| | .one ⟨h, h'⟩ => recTest h | |
| termination_by structural h | |
| -- mutual nested recursion | |
| mutual | |
| theorem Test.recTest2 (h : Test p n) : True := | |
| match h with | |
| | .zero => trivial | |
| | .one h => recTest3 h | |
| termination_by structural h | |
| theorem Test.recTest3 (h : Test p 3 ∧ p 2) : True := | |
| match h with | |
| | ⟨h, _⟩ => recTest2 h | |
| termination_by structural h | |
| end | |
| /-! | |
| Reflexive inductives | |
| -/ | |
| inductive Test2 (p : Nat → Prop) : Nat → Prop | |
| | zero : Test2 p 0 | |
| | abc (h : ∀ n, p (a + n) → Test2 p n) : Test2 p a | |
| /-- | |
| info: Test2.brecOn {p : Nat → Prop} {motive : (a : Nat) → Test2 p a → Prop} {a✝ : Nat} (t : Test2 p a✝) | |
| (F_1 : ∀ (a : Nat) (t : Test2 p a), Test2.below t → motive a t) : motive a✝ t | |
| -/ | |
| #guard_msgs in | |
| #check Test2.brecOn | |
| theorem Test2.recTest (h : Test2 (fun _ => True) n) : True := | |
| match h with | |
| | .zero => trivial | |
| | .abc h => recTest (h 0 trivial) | |
| termination_by structural h | |
| /-! | |
| Nested inductives with indices | |
| -/ | |
| set_option inductive.autoPromoteIndices false in | |
| inductive And2 (p : Prop) : (q : Prop) → Prop where | |
| | intro (left : p) (right : b) : And2 p b | |
| inductive Test' (p : Nat → Prop) : Nat → Prop where | |
| | zero : Test' p 0 | |
| | one (h : And2 (Test' p 2) (p 3)) : Test' p 1 | |
| /-- | |
| info: Test'.brecOn {p : Nat → Prop} {motive_1 : (a : Nat) → Test' p a → Prop} | |
| {motive_2 : (q : Prop) → And2 (Test' p 2) q → Prop} {a✝ : Nat} (t : Test' p a✝) | |
| (F_1 : ∀ (a : Nat) (t : Test' p a), t.below → motive_1 a t) | |
| (F_2 : ∀ (q : Prop) (t : And2 (Test' p 2) q), Test'.below_1 t → motive_2 q t) : motive_1 a✝ t | |
| -/ | |
| #guard_msgs in | |
| #check Test'.brecOn | |
| theorem Test'.recTest (h : Test p n) : True := | |
| match h with | |
| | .zero => trivial | |
| | .one ⟨h, h'⟩ => recTest h | |
| termination_by structural h | |
| /-! | |
| Recursion with the same inductive twice | |
| -/ | |
| inductive NatProp : Prop where | |
| | zero | |
| | succ (k : NatProp) : NatProp | |
| mutual | |
| theorem NatProp.recTest1 (_a : Nat) (x : NatProp) (_c : Nat) : True := | |
| match x with | |
| | .zero => trivial | |
| | .succ k => | |
| have := k.recTest2 7 | |
| this 3 | |
| termination_by structural x | |
| theorem NatProp.recTest2 (_b : Nat) (x : NatProp) (_d : Nat) : True := | |
| match x with | |
| | .zero => trivial | |
| | .succ k => k.recTest1 3 5 | |
| termination_by structural x | |
| end | |
| /-! | |
| Support for named patterns | |
| -/ | |
| mutual | |
| inductive TestEven (b : Bool) : Nat → Prop where | |
| | zero : TestEven b 0 | |
| | succ (h : Nat → TestOdd b n) (a : Nat) : TestEven b (n + 1) | |
| inductive TestOdd (b : Bool) : Nat → Prop where | |
| | succ (h : TestEven b n) : TestOdd b (n + 1) | |
| end | |
| theorem TestEven.recTest {b : Bool} {n : Nat} (h : TestEven b n) (_a : Bool) : True := | |
| match h with | |
| | .zero => trivial | |
| | @TestEven.succ _ n h' _a => | |
| match h' 2 with | |
| | .succ .zero => trivial | |
| | .succ h₁@hh₁:(.succ h'' _) => | |
| have : True := match h'' 3 with | |
| | .succ h''' => h'''.recTest false | |
| have := h₁ | |
| have := hh₁ | |
| have := h₁.recTest | |
| trivial | |
| termination_by structural h | |
| /-! | |
| Matching on partial applications | |
| -/ | |
| theorem TestEven.recTest2 {b : Bool} {n : Nat} (h : TestEven b n) : True := | |
| match h with | |
| | .zero => trivial | |
| | @TestEven.succ _ n h' _a => | |
| -- h' : ∀ (a : Nat), TestOdd b n | |
| match n, h' with | |
| | _ + 1, h'' => | |
| match h'' 2 with | |
| | .succ h''' => h'''.recTest2 | |
| | 0, _ => trivial | |
| termination_by structural h | |
| /-! | |
| Recursive calls as part of match discriminants | |
| -/ | |
| def addProofDependency {p : Prop} (_h : p) (a : α) : α := a | |
| theorem NatProp.recTest3 (p : NatProp) : True := | |
| match p with | |
| | .zero => trivial | |
| | .succ h => | |
| match addProofDependency h.recTest3 trivial, h with | |
| | ⟨⟩, .zero => trivial | |
| | ⟨⟩, .succ h => h.recTest3 | |
| termination_by structural p | |
| /-! | |
| Using the same match twice | |
| -/ | |
| theorem NatProp.recTest4 (p : NatProp) : True := | |
| match p with | |
| | .zero => trivial | |
| | .succ h => | |
| match h with | |
| | .zero => trivial | |
| | .succ h' => | |
| have := h.recTest3 | |
| h'.recTest4 | |
| termination_by structural p | |
| /-! | |
| Recursion on universe polymorphic functions | |
| -/ | |
| class SuccTest (α : Type u) where | |
| succ : α → α | |
| inductive SuccTest.le {α : Type u} [SuccTest α] : α → α → Prop where | |
| | refl {n : α} : le n n | |
| | step {a b : α} (h : le a b) : le a (SuccTest.succ b) | |
| theorem SuccTest.le_trans {α : Type u} [SuccTest α] {a b c : α} : le a b → le b c → le a c | |
| | h, .refl => h | |
| | h, .step h' => .step (le_trans h h') | |
| termination_by structural _ h => h |