lean4-htt/tests/lean/run/try_induction.lean
Leonardo de Moura ef1dc21f1c
feat: use new grind? infrastructure to implement try? (#11197)
This PR implements `try?` using the new `finish?` infrastructure. It
also removes the old tracing infrastructure, which is now obsolete.
Example:

```lean
/--
info: Try these:
  [apply] grind
  [apply] grind only [findIdx, insert, = mem_indices_of_mem, = getElem?_neg, = getElem?_pos, = HashMap.mem_insert,
    = HashMap.getElem_insert, #1bba]
  [apply] grind only [findIdx, insert, = mem_indices_of_mem, = getElem?_neg, = getElem?_pos, = HashMap.mem_insert,
    = HashMap.getElem_insert]
  [apply] grind =>
    instantiate only [findIdx, insert, = mem_indices_of_mem]
    instantiate only [= getElem?_neg, = getElem?_pos]
    cases #1bba
    · instantiate only [findIdx]
    · instantiate only
      instantiate only [= HashMap.mem_insert, = HashMap.getElem_insert]
-/
#guard_msgs in
example (m : IndexMap α β) (a : α) (b : β) :
    (m.insert a b).findIdx a = if h : a ∈ m then m.findIdx a else m.size := by
  try?
```
2025-11-16 05:26:17 +00:00

145 lines
4.1 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.

/-
Tests for `try?` suggesting `induction` tactic.
NOTE: Tests using Nat or List from the standard library don't work because
induction candidates are filtered by `isEligible` in Try/Collect.lean, which
only accepts types defined in the current module and/or namespace.
This is why we use custom inductive types below.
Real working examples from the library (like grind_hyper_ex.lean) use:
`induction k with grind`
to prove things like `hyperoperation 1 m k = m + k`. However, `try?` won't
suggest these because `k : Nat`.
-/
-- Simple list-like structure
inductive MyList (α : Type _) where
| nil : MyList α
| cons : α → MyList α → MyList α
axiom MyListProp : MyList α → Prop
@[grind .] axiom mylist_nil : MyListProp (MyList.nil : MyList α)
@[grind .] axiom mylist_cons : ∀ (x : α) (xs : MyList α), MyListProp xs → MyListProp (MyList.cons x xs)
/--
info: Try these:
[apply] (induction xs) <;> grind
[apply] (induction xs) <;> grind only [mylist_nil, mylist_cons]
[apply] ·
induction xs
· grind => instantiate only [mylist_nil]
· grind => instantiate only [mylist_cons]
-/
#guard_msgs (info) in
example (xs : MyList α) : MyListProp xs := by
try?
-- Expression tree
inductive Expr where
| const : Nat → Expr
| add : Expr → Expr → Expr
| mul : Expr → Expr → Expr
axiom ExprProp : Expr → Prop
@[grind .] axiom expr_const : ∀ n, ExprProp (Expr.const n)
@[grind .] axiom expr_add : ∀ e1 e2, ExprProp e1 → ExprProp e2 → ExprProp (Expr.add e1 e2)
@[grind .] axiom expr_mul : ∀ e1 e2, ExprProp e1 → ExprProp e2 → ExprProp (Expr.mul e1 e2)
/--
info: Try these:
[apply] (induction e) <;> grind
[apply] (induction e) <;> grind only [expr_const, expr_add, expr_mul]
[apply] ·
induction e
· grind => instantiate only [expr_const]
· grind => instantiate only [expr_add]
· grind => instantiate only [expr_mul]
-/
#guard_msgs (info) in
example (e : Expr) : ExprProp e := by
try?
-- For now, `try?` will not do induction on `Nat`, so we use a custom Nat-like type.
inductive MyNat where
| zero : MyNat
| succ : MyNat → MyNat
abbrev := MyNat
def add : MyNat → MyNat → MyNat
| .zero, n => n
| .succ m, n => .succ (add m n)
/--
info: Try these:
[apply] (induction n) <;> grind [= add]
[apply] (induction n) <;> grind only [add]
[apply] (induction n) <;> grind => instantiate only [add]
-/
#guard_msgs in
@[grind =]
theorem add_zero (n : ) : add n .zero = n := by
try?
/--
info: Try these:
[apply] (fun_induction add) <;> grind [= add]
[apply] (fun_induction add) <;> grind only [add]
[apply] (fun_induction add) <;> grind => instantiate only [add]
-/
#guard_msgs in
@[grind =]
theorem add_succ (m n : ) : add m (.succ n) = .succ (add m n) := by
try?
def hyperoperation :
| .zero, _, k => .succ k
| .succ .zero, m, .zero => m
| .succ (.succ .zero), _, .zero => .zero
| .succ (.succ (.succ _)), _, .zero => .succ .zero
| .succ n, m, .succ k => hyperoperation n m (hyperoperation (.succ n) m k)
attribute [local grind] hyperoperation add
/--
info: Try these:
[apply] grind
[apply] grind only [hyperoperation]
[apply] grind => instantiate only [hyperoperation]
-/
#guard_msgs in
@[grind =]
theorem hyperoperation_zero (m k : ) : hyperoperation .zero m k = .succ k := by
try?
/--
info: Try these:
[apply] grind
[apply] grind only [hyperoperation]
[apply] grind => instantiate only [hyperoperation]
-/
#guard_msgs in
@[grind =]
theorem hyperoperation_recursion (n m k : ) :
hyperoperation (.succ n) m (.succ k) = hyperoperation n m (hyperoperation (.succ n) m k) := by
try?
/--
info: Try these:
[apply] (induction k) <;> grind
[apply] (induction k) <;> grind only [hyperoperation, = add_zero, = add_succ, = hyperoperation_zero]
[apply] ·
induction k
· grind => instantiate only [hyperoperation, = add_zero]
·
grind =>
instantiate only [hyperoperation, = add_succ]
instantiate only [= hyperoperation_zero]
-/
#guard_msgs in
@[grind =]
theorem hyperoperation_one (m k : ) : hyperoperation (.succ .zero) m k = add m k := by
try?