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.
187 lines
5.1 KiB
Text
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
|