lean4-htt/tests/lean/run/funind_tests.lean
Joachim Breitner ab318dda2d
feat: use reserved name infrastructure for functional induction (#3776)
no need to enter `derive_functional_induction` anymore.

(Will remove the support for `derive_functional_induction` after the
next stage0 update, since we are already using it in Init.)
2024-03-26 22:25:10 +00:00

739 lines
20 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

namespace Unary
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 p => p
/--
info: Unary.ackermann.induct (motive : Nat × Nat → Prop) (case1 : ∀ (m : Nat), motive (0, m))
(case2 : ∀ (n : Nat), motive (n, 1) → motive (n.succ, 0))
(case3 : ∀ (n m : Nat), motive (n + 1, m) → motive (n, ackermann (n + 1, m)) → motive (n.succ, m.succ)) :
∀ (a : Nat × Nat), motive a
-/
#guard_msgs in
#check Unary.ackermann.induct
end Unary
namespace Binary
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)
/--
info: Binary.ackermann.induct (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (n : Nat), motive n 1 → motive n.succ 0)
(case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive n.succ m.succ) :
∀ (a a_1 : Nat), motive a a_1
-/
#guard_msgs in
#check Binary.ackermann.induct
end Binary
universe u
opaque _root_.List.attach : {α : Type u} → (l : List α) → List { x // x ∈ l }
inductive Tree | node : List Tree → Tree
def Tree.rev : Tree → Tree
| node ts => .node (ts.attach.map (fun ⟨t, _ht⟩ => t.rev) |>.reverse)
/--
info: Tree.rev.induct (motive : Tree → Prop)
(case1 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive t) → motive (Tree.node ts)) : ∀ (a : Tree), motive a
-/
#guard_msgs in
#check Tree.rev.induct
def fib : Nat → Nat
| 0 => 1
| 1 => 1
| n+2 => fib n + fib (n+1)
termination_by n => n
/--
info: fib.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 1)
(case3 : ∀ (n : Nat), motive n → motive (n + 1) → motive n.succ.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check fib.induct
set_option linter.unusedVariables false in
def have_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
have h2 : n < n+1 := Nat.lt_succ_self n
have_tailrec n
termination_by n => n
/--
info: have_tailrec.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), n < n + 1 → motive n → motive n.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check have_tailrec.induct
set_option linter.unusedVariables false in
def have_non_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
Nat.succ <|
have h2 : n < n+1 := Nat.lt_succ_self n
have_non_tailrec n
termination_by n => n
/--
info: have_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
-/
#guard_msgs in
#check have_non_tailrec.induct
set_option linter.unusedVariables false in
def let_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
let h2 : n < n+1 := Nat.lt_succ_self n
let_tailrec n
termination_by n => n
/--
info: let_tailrec.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 :
∀ (n : Nat),
let h2 := ⋯;
motive n → motive n.succ) :
∀ (a : Nat), motive a
-/
#guard_msgs in
#check let_tailrec.induct
set_option linter.unusedVariables false in
def let_non_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
Nat.succ <|
let h2 : n < n+1 := Nat.lt_succ_self n
let_non_tailrec n
termination_by n => n
/--
info: let_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
-/
#guard_msgs in
#check let_non_tailrec.induct
set_option linter.unusedVariables false in
def with_ite_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
if n % 2 = 0 then
with_ite_tailrec n
else
with_ite_tailrec n
termination_by n => n
/--
info: with_ite_tailrec.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), n % 2 = 0 → motive n → motive n.succ)
(case3 : ∀ (n : Nat), ¬n % 2 = 0 → motive n → motive n.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check with_ite_tailrec.induct
set_option linter.unusedVariables false in
def with_ite_non_tailrec : Nat → Nat
| 0 => 0
| 1 => 1
| n+2 =>
Nat.succ <|
if n % 2 = 0 then
with_ite_non_tailrec (n+1)
else
with_ite_non_tailrec n
termination_by n => n
/--
info: with_ite_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 1)
(case3 : ∀ (n : Nat), motive (n + 1) → motive n → motive n.succ.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check with_ite_non_tailrec.induct
set_option linter.unusedVariables false in
def with_dite_non_tailrec (n : Nat) : Nat :=
Nat.succ <|
if h : n - 1 < n then
with_dite_non_tailrec (n-1)
else
0
termination_by n
/--
info: with_dite_non_tailrec.induct (motive : Nat → Prop) (case1 : ∀ (x : Nat), (x - 1 < x → motive (x - 1)) → motive x)
(n : Nat) : motive n
-/
#guard_msgs in
#check with_dite_non_tailrec.induct
set_option linter.unusedVariables false in
def with_dite_tailrec (n : Nat) : Nat :=
if h : n - 1 < n then
with_dite_tailrec (n-1)
else
0
termination_by n
/--
info: with_dite_tailrec.induct (motive : Nat → Prop) (case1 : ∀ (x : Nat), x - 1 < x → motive (x - 1) → motive x)
(case2 : ∀ (x : Nat), ¬x - 1 < x → motive x) (n : Nat) : motive n
-/
#guard_msgs in
#check with_dite_tailrec.induct
set_option linter.unusedVariables false in
def with_match_refining_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
match n with
| 0 => with_match_refining_tailrec 0
| m => with_match_refining_tailrec m
termination_by n => n
/--
info: with_match_refining_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 0 → motive (Nat.succ 0))
(case3 : ∀ (m : Nat), (m = 0 → False) → motive m → motive m.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check with_match_refining_tailrec.induct
def with_arg_refining_match1 (i : Nat) : Nat → Nat
| 0 => 0
| n+1 =>
if h : i = 0 then 0 else with_arg_refining_match1 (i - 1) n
termination_by i
/--
info: with_arg_refining_match1.induct (motive : Nat → Nat → Prop) (case1 : ∀ (i : Nat), motive i 0)
(case2 : ∀ (n : Nat), motive 0 n.succ) (case3 : ∀ (i n : Nat), ¬i = 0 → motive (i - 1) n → motive i n.succ)
(i : Nat) : ∀ (a : Nat), motive i a
-/
#guard_msgs in
#check with_arg_refining_match1.induct
def with_arg_refining_match2 (i : Nat) (n : Nat) : Nat :=
if i = 0 then 0 else match n with
| 0 => 0
| n+1 => with_arg_refining_match2 (i - 1) n
termination_by i
/--
info: with_arg_refining_match2.induct (motive : Nat → Nat → Prop) (case1 : ∀ (n : Nat), motive 0 n)
(case2 : ∀ (i : Nat), ¬i = 0 → motive i 0)
(case3 : ∀ (i : Nat), ¬i = 0 → ∀ (n : Nat), motive (i - 1) n → motive i n.succ) (i n : Nat) : motive i n
-/
#guard_msgs in
#check with_arg_refining_match2.induct
set_option linter.unusedVariables false in
def with_other_match_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
match n % 2 with
| 0 => with_other_match_tailrec n
| _ => with_other_match_tailrec n
termination_by n => n
/--
info: with_other_match_tailrec.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), n % 2 = 0 → motive n → motive n.succ)
(case3 : ∀ (n : Nat), (n % 2 = 0 → False) → motive n → motive n.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check with_other_match_tailrec.induct
set_option linter.unusedVariables false in
def with_mixed_match_tailrec : Nat → Nat → Nat → Nat → Nat := fun a b c d =>
match a, h: b, c % 2, h : d % 2 with
| 0, _, _, _ => 0
| a+1, x, y, z => with_mixed_match_tailrec a x y z
termination_by n => n
/--
info: with_mixed_match_tailrec.induct (motive : Nat → Nat → Nat → Nat → Prop) (case1 : ∀ (a a_1 x : Nat), motive 0 x a a_1)
(case2 : ∀ (a a_1 a_2 x : Nat), motive a_2 x (a % 2) (a_1 % 2) → motive a_2.succ x a a_1) :
∀ (a a_1 a_2 a_3 : Nat), motive a a_1 a_2 a_3
-/
#guard_msgs in
#check with_mixed_match_tailrec.induct
set_option linter.unusedVariables false in
def with_mixed_match_tailrec2 : Nat → Nat → Nat → Nat → Nat → Nat := fun n a b c d =>
match n with
| 0 => 0
| n+1 =>
match a, h: b, c % 2, h : d % 2 with
| 0, _, _, _ => 0
| a+1, x, y, z => with_mixed_match_tailrec2 n a x y z
termination_by n => n
/--
info: with_mixed_match_tailrec2.induct (motive : Nat → Nat → Nat → Nat → Nat → Prop)
(case1 : ∀ (a a_1 a_2 a_3 : Nat), motive 0 a a_1 a_2 a_3) (case2 : ∀ (a a_1 n x : Nat), motive n.succ 0 x a a_1)
(case3 : ∀ (a a_1 n a_2 x : Nat), motive n a_2 x (a % 2) (a_1 % 2) → motive n.succ a_2.succ x a a_1) :
∀ (a a_1 a_2 a_3 a_4 : Nat), motive a a_1 a_2 a_3 a_4
-/
#guard_msgs in
#check with_mixed_match_tailrec2.induct
set_option linter.unusedVariables false in
def with_match_non_tailrec : Nat → Nat
| 0 => 0
| n+1 =>
Nat.succ <|
match n % 2 with
| 0 => with_match_non_tailrec n
| _ => with_match_non_tailrec n
termination_by n => n
/--
info: with_match_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
-/
#guard_msgs in
#check with_match_non_tailrec.induct
set_option linter.unusedVariables false in
def with_match_non_tailrec_refining : Nat → Nat
| 0 => 0
| n+1 =>
Nat.succ <|
match n with
| 0 => with_match_non_tailrec_refining 0
| m => with_match_non_tailrec_refining m
termination_by n => n
/--
info: with_match_non_tailrec_refining.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 :
∀ (n : Nat),
(match n with
| 0 => motive 0
| m => motive m) →
motive n.succ) :
∀ (a : Nat), motive a
-/
#guard_msgs in
#check with_match_non_tailrec_refining.induct
def with_overlap : Nat → Nat
| 0 => 0
| 1 => 1
| 2 => 2
| 3 => 3
| n+1 => with_overlap n
termination_by n => n
/--
info: with_overlap.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 1) (case3 : motive 2) (case4 : motive 3)
(case5 : ∀ (n : Nat), (n = 0 → False) → (n = 1 → False) → (n = 2 → False) → motive n → motive n.succ) :
∀ (a : Nat), motive a
-/
#guard_msgs in
#check with_overlap.induct
namespace UnusedExtraParams
-- This test how unused fixed function parameters are handled.
-- See comment in the code
def unary (base : Nat) : Nat → Nat
| 0 => base
| n+1 => unary base n
termination_by n => n
/--
info: UnusedExtraParams.unary.induct (base : Nat) (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), motive n → motive n.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check UnusedExtraParams.unary.induct
def binary (base : Nat) : Nat → Nat → Nat
| 0, m => base + m
| n+1, m => binary base n m
termination_by n => n
/--
info: UnusedExtraParams.binary.induct (base : Nat) (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (n m : Nat), motive n m → motive n.succ m) : ∀ (a a_1 : Nat), motive a a_1
-/
#guard_msgs in
#check UnusedExtraParams.binary.induct
end UnusedExtraParams
namespace NonTailrecMatch
def match_non_tail (n : Nat ) : Bool :=
n = 42 || match n with
| 0 => true
| 1 => true
| n+2 => match_non_tail n && match_non_tail (n+1)
termination_by n
def match_non_tail_induct
{motive : Nat → Prop}
(case1 : forall n, (IH : match n with | 0 => True | n+1 => motive n) → motive n)
(n : Nat) : motive n :=
WellFounded.fix Nat.lt_wfRel.wf (fun n IH =>
match n with
| 0 => case1 0 True.intro
| n+1 =>
case1 (n+1) (IH n (Nat.lt_succ_self _))
) n
/--
info: NonTailrecMatch.match_non_tail.induct (motive : Nat → Prop)
(case1 :
∀ (x : Nat),
(match x with
| 0 => True
| 1 => True
| n.succ.succ => motive n ∧ motive (n + 1)) →
motive x)
(n : Nat) : motive n
-/
#guard_msgs in
#check NonTailrecMatch.match_non_tail.induct
theorem match_non_tail_eq_true (n : Nat) : match_non_tail n = true := by
induction n using NonTailrecMatch.match_non_tail.induct
case case1 n IH =>
unfold match_non_tail
split <;> dsimp at IH <;> simp [IH]
end NonTailrecMatch
namespace AsPattern
def foo (n : Nat) :=
match n with
| 0 => 0
| x@(n+1) => x + foo n
termination_by n
/--
info: AsPattern.foo.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ)
(n : Nat) : motive n
-/
#guard_msgs in
#check AsPattern.foo.induct
def bar (n : Nat) :=
1 +
match n with
| 0 => 0
| x@(n+1) => x + bar n
termination_by n
/--
info: AsPattern.bar.induct (motive : Nat → Prop)
(case1 :
∀ (x : Nat),
(match x with
| 0 => True
| x@h:n.succ => motive n) →
motive x)
(n : Nat) : motive n
-/
#guard_msgs in
#check AsPattern.bar.induct
end AsPattern
namespace GramSchmidt
-- this tried to repoduce a problem with gramSchmidt,
-- with more proofs from `simp` abstracting over the IH.
-- I couldn't quite reproduce it, but let's keep it.
def below (n i : Nat) := i < n
@[simp]
def below_lt (n i : Nat) (h : below n i) : i < n := h
def sum_below (n : Nat) (f : (i : Nat) → below n i → Nat) :=
match n with
| 0 => 0
| n+1 => sum_below n (fun i hi => f i (Nat.lt_succ_of_le (Nat.le_of_lt hi))) +
f n (Nat.lt_succ_self n)
def foo (n : Nat) :=
1 + sum_below n (fun i _ => foo i)
termination_by n
decreasing_by
simp_wf
simp [below_lt, *]
/--
info: GramSchmidt.foo.induct (motive : Nat → Prop) (case1 : ∀ (x : Nat), (∀ (i : Nat), below x i → motive i) → motive x)
(n : Nat) : motive n
-/
#guard_msgs in
#check GramSchmidt.foo.induct
end GramSchmidt
namespace LetFun
def foo {α} (x : α) : List α → Nat
| .nil => 0
| .cons _y ys =>
let this := foo x ys
this
termination_by xs => xs
/--
info: LetFun.foo.induct.{u_1} {α : Type u_1} (x : α) (motive : List α → Prop) (case1 : motive [])
(case2 : ∀ (_y : α) (ys : List α), motive ys → motive (_y :: ys)) : ∀ (a : List α), motive a
-/
#guard_msgs in
#check LetFun.foo.induct
def bar {α} (x : α) : List α → Nat
| .nil => 0
| .cons _y ys =>
have this := bar x ys
this
termination_by xs => xs
/--
info: LetFun.bar.induct.{u_1} {α : Type u_1} (x : α) (motive : List α → Prop) (case1 : motive [])
(case2 : ∀ (_y : α) (ys : List α), motive ys → motive (_y :: ys)) : ∀ (a : List α), motive a
-/
#guard_msgs in
#check LetFun.bar.induct
end LetFun
namespace RecCallInDisrs
def foo : Nat → Nat
| 0 => 0
| n+1 => if foo n = 0 then 1 else 0
termination_by n => n
/--
info: RecCallInDisrs.foo.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), foo n = 0 → motive n → motive n.succ)
(case3 : ∀ (n : Nat), ¬foo n = 0 → motive n → motive n.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check RecCallInDisrs.foo.induct
set_option linter.unusedVariables false in
def bar : Nat → Nat
| 0 => 0
| n+1 => match _h : n, bar n with
| 0, 0 => 0
| 0, _ => 1
| m+1, _ => bar m
termination_by n => n
/--
info: RecCallInDisrs.bar.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : bar 0 = 0 → motive 0 → motive (Nat.succ 0))
(case3 : (bar 0 = 0 → False) → motive 0 → motive (Nat.succ 0))
(case4 : ∀ (m : Nat), motive m.succ → motive m → motive m.succ.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check RecCallInDisrs.bar.induct
end RecCallInDisrs
namespace EvenOdd
mutual
def even : Nat → Bool
| 0 => true
| n+1 => odd n
termination_by n => n
def odd : Nat → Bool
| 0 => false
| n+1 => even n
termination_by n => n
end
/--
info: EvenOdd.even.induct (motive1 motive2 : Nat → Prop) (case1 : motive1 0) (case2 : ∀ (n : Nat), motive2 n → motive1 n.succ)
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) : ∀ (a : Nat), motive1 a
-/
#guard_msgs in
#check EvenOdd.even.induct
/--
info: EvenOdd.odd.induct (motive1 motive2 : Nat → Prop) (case1 : motive1 0) (case2 : ∀ (n : Nat), motive2 n → motive1 n.succ)
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) : ∀ (a : Nat), motive2 a
-/
#guard_msgs in
#check EvenOdd.odd.induct
end EvenOdd
namespace Tree
inductive Tree : Type
| node : List Tree → Tree
mutual
def Tree.map (f : Tree → Tree) : Tree → Tree
| Tree.node ts => Tree.node (map_forest f ts)
def Tree.map_forest (f : Tree → Tree) (ts : List Tree) : List Tree :=
ts.attach.map (fun ⟨t, _ht⟩ => Tree.map f t)
end
/--
info: Tree.Tree.map.induct (f : Tree → Tree) (motive1 : Tree → Prop) (motive2 : List Tree → Prop)
(case1 : ∀ (ts : List Tree), motive2 ts → motive1 (Tree.node ts))
(case2 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive1 t) → motive2 ts) : ∀ (a : Tree), motive1 a
-/
#guard_msgs in
#check Tree.Tree.map.induct
/--
info: Tree.Tree.map_forest.induct (f : Tree → Tree) (motive1 : Tree → Prop) (motive2 : List Tree → Prop)
(case1 : ∀ (ts : List Tree), motive2 ts → motive1 (Tree.node ts))
(case2 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive1 t) → motive2 ts) (ts : List Tree) : motive2 ts
-/
#guard_msgs in
#check Tree.Tree.map_forest.induct
end Tree
namespace DefaultArgument
-- Default arguments should not be copied over
def unary (fixed : Bool := false) (n : Nat := 0) : Nat :=
match n with
| 0 => 0
| n+1 => unary fixed n
termination_by n
/--
info: DefaultArgument.unary.induct (fixed : Bool) (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), motive n → motive n.succ) (n : Nat) : motive n
-/
#guard_msgs in
#check DefaultArgument.unary.induct
def foo (fixed : Bool := false) (n : Nat) (m : Nat := 0) : Nat :=
match n with
| 0 => m
| n+1 => foo fixed n m
termination_by n
/--
info: DefaultArgument.foo.induct (fixed : Bool) (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (m n : Nat), motive n m → motive n.succ m) (n m : Nat) : motive n m
-/
#guard_msgs in
#check DefaultArgument.foo.induct
end DefaultArgument
namespace Nary
def foo : Nat → Nat → (k : Nat) → Fin k → Nat
| 0, _, _, _ => 0
| _, 0, _, _ => 0
| _, _, 0, _ => 0
| _, _, 1, _ => 0
| n+1, m+1, k+2, _ => foo n m (k+1) ⟨0, Nat.zero_lt_succ _⟩
termination_by n => n
/--
info: Nary.foo.induct (motive : Nat → Nat → (k : Nat) → Fin k → Prop)
(case1 : ∀ (x x_1 : Nat) (x_2 : Fin x_1), motive 0 x x_1 x_2)
(case2 : ∀ (x x_1 : Nat) (x_2 : Fin x_1), (x = 0 → False) → motive x 0 x_1 x_2)
(case3 : ∀ (x x_1 : Nat) (x_2 : Fin 0), (x = 0 → False) → (x_1 = 0 → False) → motive x x_1 0 x_2)
(case4 : ∀ (x x_1 : Nat) (x_2 : Fin 1), (x = 0 → False) → (x_1 = 0 → False) → motive x x_1 1 x_2)
(case5 : ∀ (n m k : Nat) (x : Fin (k + 2)), motive n m (k + 1) ⟨0, ⋯⟩ → motive n.succ m.succ k.succ.succ x) :
∀ (a a_1 k : Nat) (a_2 : Fin k), motive a a_1 k a_2
-/
#guard_msgs in
#check Nary.foo.induct
end Nary
namespace Dite
def foo (n : Nat) : Nat :=
let j := n - 1
if _h : j < n then
foo j
else
42
/--
info: Dite.foo.induct (motive : Nat → Prop)
(case1 :
∀ (x : Nat),
let j := x - 1;
j < x → motive j → motive x)
(case2 :
∀ (x : Nat),
let j := x - 1;
¬j < x → motive x)
(n : Nat) : motive n
-/
#guard_msgs in
#check Dite.foo.induct
end Dite
namespace PreserveParams
/-
Tests that cleaning up the goal state does not throw away useful equalties
relating varying parameters to fixed ones.
-/
def foo (a : Nat) : Nat → Nat
| 0 => 0
| n+1 =>
if a = 23 then 23 else
if a = n then 42 else
foo a n
termination_by n => n
/--
info: PreserveParams.foo.induct (a : Nat) (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), a = 23 → motive n.succ) (case3 : ¬a = 23 → motive a.succ)
(case4 : ∀ (n : Nat), ¬a = 23 → ¬a = n → motive n → motive n.succ) : ∀ (a : Nat), motive a
-/
#guard_msgs in
#check PreserveParams.foo.induct
end PreserveParams