lean4-htt/tests/lean/run/induction1.lean
Kyle Miller 6a59926592
feat: add generalization hypotheses to induction tactic (#7103)
This PR gives the `induction` tactic the ability to name hypotheses to
use when generalizing targets, just like in `cases`. For example,
`induction h : xs.length` leads to goals with hypotheses `h : xs.length
= 0` and `h : xs.length = n + 1`. Target handling is also slightly
modified for multi-target induction principles: it used to be that if
any target was not a free variable, all of the targets would be
generalized (thus causing free variables to lose their connection to the
local hypotheses they appear in); now only the non-free-variable targets
are generalized.

This gives `induction` the last basic feature of the mathlib
`induction'` tactic, which has been long-requested. Recent Zulip
discussion:
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/To.20replace.20.60induction'.20h.20.3A.20f.20x.60/near/499482173
2025-02-18 03:46:23 +00:00

214 lines
4.7 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.

theorem tst0 {p q : Prop } (h : p q) : q p :=
by {
induction h;
{ apply Or.inr; assumption };
{ apply Or.inl; assumption }
}
theorem tst0' {p q : Prop } (h : p q) : q p := by
induction h
focus
apply Or.inr
assumption
focus
apply Or.inl
assumption
theorem tst1 {p q : Prop } (h : p q) : q p := by
induction h with
| inr h2 => exact Or.inl h2
| inl h1 => exact Or.inr h1
theorem tst6 {p q : Prop } (h : p q) : q p :=
by {
cases h with
| inr h2 => exact Or.inl h2
| inl h1 => exact Or.inr h1
}
theorem tst7 {α : Type} (xs : List α) (h : (a : α) → (as : List α) → xs ≠ a :: as) : xs = [] :=
by {
induction xs with
| nil => exact rfl
| cons z zs ih => exact absurd rfl (h z zs)
}
theorem tst8 {α : Type} (xs : List α) (h : (a : α) → (as : List α) → xs ≠ a :: as) : xs = [] := by {
induction xs;
exact rfl;
exact absurd rfl $ h _ _
}
theorem tst9 {α : Type} (xs : List α) (h : (a : α) → (as : List α) → xs ≠ a :: as) : xs = [] := by
cases xs with
| nil => exact rfl
| cons z zs => exact absurd rfl (h z zs)
theorem tst10 {p q : Prop } (h₁ : p ↔ q) (h₂ : p) : q := by
induction h₁ with
| intro h _ => exact h h₂
def Iff2 (m p q : Prop) := p ↔ q
theorem tst11 {p q r : Prop } (h₁ : Iff2 r p q) (h₂ : p) : q := by
induction h₁ using Iff.rec with
| intro h _ => exact h h₂
theorem tst12 {p q : Prop } (h₁ : p q) (h₂ : p ↔ q) (h₃ : p) : q := by
fail_if_success induction h₁ using Iff.casesOn
induction h₂ using Iff.casesOn with
| intro h _ =>
exact h h₃
inductive Tree
| leaf₁
| leaf₂
| node : Tree → Tree → Tree
def Tree.isLeaf₁ : Tree → Bool
| leaf₁ => true
| _ => false
theorem tst13 (x : Tree) (h : x = Tree.leaf₁) : x.isLeaf₁ = true := by
cases x with
| leaf₁ => rfl
| _ => injection h
theorem tst14 (x : Tree) (h : x = Tree.leaf₁) : x.isLeaf₁ = true := by
induction x with
| leaf₁ => rfl
| _ => injection h
inductive Vec (α : Type) : Nat → Type
| nil : Vec α 0
| cons : (a : α) → {n : Nat} → (as : Vec α n) → Vec α (n+1)
/--
info: case cons.cons.fst
α β : Type
n : Nat
a✝¹ : α
as✝¹ : Vec α n
a✝ : β
as✝ : Vec β n
α
case cons.cons.snd
α β : Type
n : Nat
a✝¹ : α
as✝¹ : Vec α n
a✝ : β
as✝ : Vec β n
⊢ β
case cons.cons.snd
α β : Type
n : Nat
a✝¹ : α
as✝¹ : Vec α n
a✝ : β
as✝ : Vec β n
⊢ β
-/
#guard_msgs in
def getHeads {α β} {n} (xs : Vec α (n+1)) (ys : Vec β (n+1)) : α × β := by
cases xs
cases ys
apply Prod.mk
repeat
trace_state
assumption
done
theorem ex1 (n m o : Nat) : n = m + 0 → m = o → m = o := by
intro (h₁ : n = m) h₂
rw [← h₁, ← h₂]
assumption
/-!
Test of named generalization, of an expression that does not appear in the goal.
-/
/--
info: case succ
α : Type
ys zs : List α
n : Nat
ih : ∀ (xs : List α), (xs ++ ys ++ zs).length = n → xs ++ ys ++ zs = xs ++ (ys ++ zs)
xs : List α
h : (xs ++ ys ++ zs).length = n + 1
⊢ xs ++ ys ++ zs = xs ++ (ys ++ zs)
-/
#guard_msgs in
example {α : Type} (xs ys zs : List α) : (xs ++ ys) ++ zs = xs ++ (ys ++ zs) := by
induction h : ((xs ++ ys) ++ zs).length generalizing xs with
| zero =>
simp only [List.length_append, Nat.add_eq_zero_iff, List.length_eq_zero] at h
obtain ⟨⟨rfl, rfl⟩, rfl⟩ := h
rfl
| succ n ih =>
trace_state
cases xs with
| nil => rfl
| cons x xs' =>
simp only [List.cons_append, List.length_cons, Nat.add_right_cancel_iff] at h
simp only [List.cons_append, ih _ h]
/-!
Test of named generalization, of an expression that appears in the goal.
-/
/--
info: case cons
α : Type
zs : List α
w : α
ws : List α
ih : ∀ (xs ys : List α), xs ++ ys ++ zs = ws → ws = xs ++ (ys ++ zs)
xs ys : List α
h : xs ++ ys ++ zs = w :: ws
⊢ w :: ws = xs ++ (ys ++ zs)
-/
#guard_msgs in
example {α : Type} (xs ys zs : List α) : (xs ++ ys) ++ zs = xs ++ (ys ++ zs) := by
induction h : (xs ++ ys) ++ zs generalizing xs ys with
| nil =>
cases xs <;> cases ys <;> cases zs <;> cases h
rfl
| cons w ws ih =>
trace_state
cases xs with
| nil =>
cases ys with
| nil =>
cases h
rfl
| cons _ ys' =>
cases h
rw [ih [] ys' rfl]
rfl
| cons _ xs' =>
cases h
rw [ih xs' ys rfl]
rfl
/-!
Test of hole for named generalization.
Yields a fresh hygienic name.
-/
/--
info: case zero
n : Nat
h✝ : n + 1 = 0
⊢ 0 = 1 + n
case succ
n n✝ : Nat
a✝ : n + 1 = n✝ → n✝ = 1 + n
h✝ : n + 1 = n✝ + 1
⊢ n✝ + 1 = 1 + n
-/
#guard_msgs in
example (n : Nat) : n + 1 = 1 + n := by
induction _ : n + 1
trace_state
omega
omega