lean4-htt/tests/lean/run/inductionComplexMotive.lean
euprunin 88078930a9
chore: fix spelling mistakes (#8324)
Co-authored-by: euprunin <euprunin@users.noreply.github.com>
2025-05-14 06:52:16 +00:00

187 lines
5 KiB
Text

def ackermann : Nat → Nat → Nat
| 0, m => m + 1
| n+1, 0 => ackermann n 1
| n+1, m+1 => ackermann n (ackermann (n + 1) m)
termination_by n m => (n, m)
-- This is the unfolding induction principle, proven by hand for this test to make
-- it independent of the actual generation code
theorem ackermann_induct_unfolding (motive : Nat → Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m (m + 1))
(case2 : ∀ (n : Nat), motive n 1 (ackermann n 1) → motive n.succ 0 (ackermann n 1))
(case3 :
∀ (n m : Nat),
motive (n + 1) m (ackermann (n + 1) m) →
motive n (ackermann (n + 1) m) (ackermann n (ackermann (n + 1) m)) →
motive n.succ m.succ (ackermann n (ackermann (n + 1) m)))
(n m : Nat) : motive n m (ackermann n m) :=
ackermann.induct (motive := fun n m => motive n m (ackermann n m))
(fun m => by simpa [ackermann] using case1 m)
(fun n ih => by simpa [ackermann] using case2 n ih)
(fun n m ih1 ih2 => by simpa [ackermann] using case3 n m ih1 ih2)
n m
/--
error: tactic 'fail' failed
case case1
m✝ : Nat
⊢ m✝ + 1 ≤ ackermann (0 + 1) m✝
case case2
n✝ : Nat
a✝ : ackermann n✝ 1 ≤ ackermann (n✝ + 1) 1
⊢ ackermann n✝ 1 ≤ ackermann (n✝.succ + 1) 0
case case3
n✝ m✝ : Nat
a✝¹ : ackermann (n✝ + 1) m✝ ≤ ackermann (n✝ + 1 + 1) m✝
a✝ : ackermann n✝ (ackermann (n✝ + 1) m✝) ≤ ackermann (n✝ + 1) (ackermann (n✝ + 1) m✝)
⊢ ackermann n✝ (ackermann (n✝ + 1) m✝) ≤ ackermann (n✝.succ + 1) m✝.succ
-/
#guard_msgs in
theorem ackermann_mono1:
ackermann n m ≤ ackermann (n+1) m := by
induction n, m using ackermann_induct_unfolding
fail
--- Now with cases
theorem ackermann_cases_unfolding (motive : Nat → Nat → Nat → Prop)
(case1 : ∀ (m : Nat), motive 0 m (m + 1))
(case2 : ∀ (n : Nat), motive n.succ 0 (ackermann n 1))
(case3 : ∀ (n m : Nat), motive n.succ m.succ (ackermann n (ackermann (n + 1) m)))
(n m : Nat) : motive n m (ackermann n m) :=
ackermann.fun_cases (motive := fun n m => motive n m (ackermann n m))
(fun m => by simpa [ackermann] using case1 m)
(fun n => by simpa [ackermann] using case2 n)
(fun n m => by simpa [ackermann] using case3 n m)
n m
/--
error: tactic 'fail' failed
case case1
m : Nat
⊢ m + 1 ≤ ackermann (0 + 1) m
case case2
n✝ : Nat
⊢ ackermann n✝ 1 ≤ ackermann (n✝.succ + 1) 0
case case3
n✝ m✝ : Nat
⊢ ackermann n✝ (ackermann (n✝ + 1) m✝) ≤ ackermann (n✝.succ + 1) m✝.succ
-/
#guard_msgs(pass trace, all) in
example : ackermann n m ≤ ackermann (n+1) m := by
cases n, m using ackermann_cases_unfolding
fail
-- Now an artificial one with multiple complex arguments.
axiom strange_induction
{motive : Nat → Prop → Nat → Prop}
(case1 : motive 0 True 42) :
∀ n, motive n (n-1 ≤ n) (n+1)
/--
error: tactic 'fail' failed
case case1
⊢ True ∧ 0 < 42
-/
#guard_msgs in
example : n -1 ≤ n ∧ n < n +1 := by
induction n using strange_induction
fail
/--
error: tactic 'fail' failed
case case1
⊢ True ∧ 0 < 42
-/
#guard_msgs in
example : n -1 ≤ n ∧ n < n +1 := by
cases n using strange_induction
fail
/--
error: tactic 'fail' failed
case case1
n : Nat
⊢ n - 1 ≤ n ∧ n < 0
-/
#guard_msgs in
example : n -1 ≤ n ∧ n < n + 1 := by
cases n+1 using strange_induction
fail
-- And now one where abstracting would cause a type error
-- (induction silently skips abstracting over these)
/--
error: tactic 'fail' failed
case case1
P : (n : Nat) → n > 0 → Prop
⊢ P (0 + 1) ⋯
-/
#guard_msgs in
example (P : (n : Nat) → (h : n > 0) → Prop) : P (n + 1) (Nat.zero_lt_succ n) := by
induction n using strange_induction
fail
/--
error: tactic 'fail' failed
case case1
P : (n : Nat) → n > 0 → Prop
⊢ P (0 + 1) ⋯
-/
#guard_msgs in
example (P : (n : Nat) → (h : n > 0) → Prop) : P (n + 1) (Nat.zero_lt_succ n) := by
cases n using strange_induction
fail
-- One where the type of the complex argument depends on the other targets
axiom dep_induction
{motive : (n : Nat) → Fin (n+1) → Prop}
(case1 : motive 0 0) :
∀ n, motive n (Fin.last n)
/--
error: tactic 'fail' failed
case case1
P : (n : Nat) → Fin (n + 1) → Prop
⊢ P 0 0
-/
#guard_msgs in
example (P : (n : Nat) → Fin (n+1) → Prop) : P n (Fin.last n) := by
induction n using dep_induction
fail
-- Using cases does not unfold as expected, due to the dependent motive.
-- This can be improved, but at least it does not error
/--
error: tactic 'fail' failed
case case1
P : (n : Nat) → Fin (n + 1) → Prop
⊢ P 0 (Fin.last 0)
-/
#guard_msgs in
example (P : (n : Nat) → Fin (n+1) → Prop) : P n (Fin.last n) := by
cases n using dep_induction
fail
-- Using cases does not unfold as expected, due to the dependent motive.
-- This can be improved, but at least it does not error
/--
error: tactic 'fail' failed
case case1
P : (n : Nat) → Fin (n + 1) → Prop
⊢ P 0 (Fin.last 0)
-/
#guard_msgs(pass trace, all) in
example (P : (n : Nat) → Fin (n+1) → Prop) : P 10 (Fin.last 10) := by
cases 10 using dep_induction
fail