Zulip Chat Archive

Stream: general

Topic: Controling induction hypothesis


Paweł Balawender (May 28 2025 at 07:37):

Hey! I got stuck on proving a property by structural induction and am convinced that the problem is in the way I applied the induction tactic in Lean 4. I boiled down the following MWE:

import Lean
import Qq
open Lean Elab Tactic Term Meta Syntax PrettyPrinter Qq

inductive Formula where
| var : Name -> Formula
| imp : Formula -> Formula -> Formula
deriving Repr, DecidableEq

notation:60 a " ==> " b => Formula.imp a b

inductive Derivable : (List Formula) -> Formula -> Prop where
| axK {Γ} {phi psi} : Derivable Γ $ phi ==> psi ==> phi
-- "multiplicative" version of modus ponens
| mult_mp {Γ1 Γ2} {phi psi} :
  Derivable Γ2 (phi ==> psi) ->
  Derivable Γ1 phi ->
  Derivable (Γ1 ++ Γ2) psi

theorem weakening {Γ} {φ ψ} : Derivable Γ ψ -> Derivable (φ :: Γ) ψ := by
  generalize Sub1 : φ :: Γ = Sub1_
  generalize Sub2 : ψ = Sub2_
  intro h
  induction h
  case _ phi psi =>
    apply Derivable.axK
  case _ a b c d imp base imp_ih base_ih =>
    -- the induction hypothesis for some reason is unusable...
    -- imp_ih : φ :: b = Sub1_ → ...
    -- base_ih : φ :: a = Sub1_ → ...
    -- but: Sub1 : φ :: (a ++ b) = Sub1_
    sorry

And have questions to you:
a) Can you somehow do without these ugly generalize?
b) Do we have some kind of compilation of popular pitfalls when using induction? (Maybe it would be a nice addition to the new channel :) (#general > Documenting lean pitfalls: feedback requested )

c) Originally, I did my induction using induction h with, but just couldn't get the pattern matching right for some reason. I don't submit a MWE here (because in a MWE I wasn't able to reproduce), but basically my cases after induction were labeled as mp.Constructor instead of Constructor I'd expect and nothing really worked to fix it instead of switching to induction h cases => syntax. Does it spark any light in your head if it's a known problem? If not, I will work on creating the MWE, but it's not that easily reproducible in my case

theorem deduction {Γ} : Derivable (var φ :: Γ) [Logic|ψ] <-> Derivable Γ [Logic|φ -> ψ] := by
  apply Iff.intro
  {
    -- trick to bypass "index in target's type is not a variable" at `induction h`
    generalize Sub1 : var φ :: Γ = Sub1_
    generalize Sub2 : var ψ = Sub2_
    intro h
    induction h with
    -- APPROACH 1:
    -- | mp.axK =>
    --   -- invalid alternative name 'mp.axK', expected 'assumption', 'axK', 'axS' or 'mult_mp'
    -- APPROACH 2:
    -- | axK =>
      -- unexpected token 'axK'; expected '_' or identifier
    -- APPROACH 3:
    -- | _ =>
      -- invalid occurrence of wildcard alternative, it must be the last alternative

Kyle Miller (May 28 2025 at 08:27):

The generalize didn't seem to be necessary. There also didn't seem to be any issue with using induction h with. In your full code, you don't define axK to be notation somewhere, do you?

import Lean
import Qq
open Lean Elab Tactic Term Meta Syntax PrettyPrinter Qq

inductive Formula where
| var : Name -> Formula
| imp : Formula -> Formula -> Formula
deriving Repr, DecidableEq

notation:60 a " ==> " b => Formula.imp a b

inductive Derivable : (List Formula) -> Formula -> Prop where
| axK {Γ} {phi psi} : Derivable Γ $ phi ==> psi ==> phi
-- "multiplicative" version of modus ponens
| mult_mp {Γ1 Γ2} {phi psi} :
  Derivable Γ2 (phi ==> psi) ->
  Derivable Γ1 phi ->
  Derivable (Γ1 ++ Γ2) psi

theorem weakening {Γ} {φ ψ} (h : Derivable Γ ψ) : Derivable (φ :: Γ) ψ := by
  induction h with
  | axK =>
    apply Derivable.axK
  | mult_mp imp base imp_ih base_ih =>
    rw [ List.cons_append]
    exact Derivable.mult_mp imp base_ih

Kyle Miller (May 28 2025 at 08:39):

The reverse direction needs generalization though:

theorem weakening' {Γ} {φ ψ} (h : Derivable (φ :: Γ) ψ) : Derivable Γ ψ := by
  generalize hΓ' : φ :: Γ = Γ' at h
  induction h generalizing φ Γ with
  | axK =>
    apply Derivable.axK
  | mult_mp imp base imp_ih base_ih =>
    rw [List.cons_eq_append_iff] at hΓ'
    obtain rfl, rfl | Γ2', rfl, rfl := hΓ'
    · have := Derivable.mult_mp (imp_ih rfl) base
      rwa [List.nil_append] at this
    · exact Derivable.mult_mp imp (base_ih rfl)

Paweł Balawender (May 28 2025 at 15:34):

Kyle Miller said:

theorem weakening' {Γ} {φ ψ} (h : Derivable (φ :: Γ) ψ) : Derivable Γ ψ := by
  generalize hΓ' : φ :: Γ = Γ' at h
  induction h generalizing φ Γ with
  | axK =>
    apply Derivable.axK
  | mult_mp imp base imp_ih base_ih =>
    rw [List.cons_eq_append_iff] at hΓ'
    obtain rfl, rfl | Γ2', rfl, rfl := hΓ'
    · have := Derivable.mult_mp (imp_ih rfl) base
      rwa [List.nil_append] at this
    · exact Derivable.mult_mp imp (base_ih rfl)

Thank you @Kyle Miller ! I appreciate you helping me. It's actually funny that you proved the other direction, as it shouldn't really be provable :) But it's just an artifact of the MWE-ization that the logic trivialized.

The issue with induction h with really was about me using axK in notation! I didn't immediately conclude that it's the problem, as I used it as constructor in other parts of the code without any problems. But inside pattern matching, the custom syntax was a problem!

I was able to use your solution to the <- direction to finish the proof of deduction theorem for Hilbert-style calculus. What you wrote is really sorcerous to me! (edit: okay, I just misunderstood ϕ,ϕ=Xsth\forall \phi, \phi=X \rightarrow sth as (ϕ,ϕ=X)sth(\forall \phi, \phi=X) \rightarrow sth, which didn't make any sense. now it's clear) Thank you! (complete code of what I wanted to achieve: live.lean-org


Last updated: Dec 20 2025 at 21:32 UTC