lean4-htt/tests/elab/inductionComplexMotive.lean
Garmelon 08eb78a5b2
chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

187 lines
5.1 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: Failed: `fail` tactic was invoked
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: Failed: `fail` tactic was invoked
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: Failed: `fail` tactic was invoked
case case1
⊢ True ∧ 0 < 42
-/
#guard_msgs in
example : n -1 ≤ n ∧ n < n +1 := by
induction n using strange_induction
fail
/--
error: Failed: `fail` tactic was invoked
case case1
⊢ True ∧ 0 < 42
-/
#guard_msgs in
example : n -1 ≤ n ∧ n < n +1 := by
cases n using strange_induction
fail
/--
error: Failed: `fail` tactic was invoked
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: Failed: `fail` tactic was invoked
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: Failed: `fail` tactic was invoked
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: Failed: `fail` tactic was invoked
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: Failed: `fail` tactic was invoked
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: Failed: `fail` tactic was invoked
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