Zulip Chat Archive

Stream: lean4

Topic: Failed to generate equational theorem


Anand Rao (Feb 12 2022 at 12:51):

I am facing an error when trying to simplify function definitions that make use of decreasing_by to show termination. I have created a minimal example of this issue that tries to calculate the length of a list in an extremely contrived way:

inductive ListSplit : List α  Type _
  | split l₁ l₂ : ListSplit (l₁ ++ l₂)

def splitList {α : Type _} : (l : List α)  ListSplit l
  | [] => ListSplit.split [] []
  | h :: t => ListSplit.split [h] t

theorem Nat.lt_add_left {m n : Nat}  : m < n + m := sorry
theorem Nat.lt_add_right {m n : Nat} : m < m + n := sorry

def len : List α  Nat
  | [] => 0
  | a :: [] => 1
  | l =>
    match (splitList l) with
      | ListSplit.split fst snd =>
        len fst + len snd
termination_by _ l => l.length
decreasing_by
  simp [measure, id, invImage, InvImage, Nat.lt_wfRel, WellFoundedRelation.rel, sizeOf] <;>
  first
    | apply Nat.lt_add_right
    | apply Nat.lt_add_left

theorem listlen :  l : List α, l.length = len l := by
  intro l
  induction l with
    | nil => rfl
    | cons h t ih =>
      simp [List.length]
      simp [len] -- Error: failed to generate equational theorem for 'len'

Does anyone know the reason for this issue and how to bypass it? Thank you in advance.

Leonardo de Moura (Feb 12 2022 at 15:58):

This issue has been fixed a few days ago. The Lean 4 master can generate the equational theorems for len.
Here is the full example.

inductive ListSplit : List α  Type _
  | split l₁ l₂ : ListSplit (l₁ ++ l₂)

def splitList {α : Type _} : (l : List α)  ListSplit l
  | [] => ListSplit.split [] []
  | h :: t => ListSplit.split [h] t

theorem Nat.lt_add_left {m n : Nat}  : m < n + m := sorry
theorem Nat.lt_add_right {m n : Nat} : m < m + n := sorry

def len : List α  Nat
  | [] => 0
  | a :: [] => 1
  | l =>
    match splitList l with
    | ListSplit.split fst snd => len fst + len snd
termination_by _ l => l.length
decreasing_by
  simp [measure, id, invImage, InvImage, Nat.lt_wfRel, WellFoundedRelation.rel, sizeOf] <;>
  first
    | apply Nat.lt_add_right
    | apply Nat.lt_add_left

theorem len_nil : len ([] : List α) = 0 := by
  simp [len]

-- The `simp [len]` above generated the following equation theorems for len
#check @len._eq_1
#check @len._eq_2
#check @len._eq_3 -- It is conditional, and may be tricky to use.

theorem len_1 (a : α) : len [a] = 1 := by
  simp [len]

theorem len_2 (a b : α) (bs : List α) : len (a::b::bs) = 1 + len (b::bs) := by
  conv => lhs; unfold len

-- The `unfold` tactic above generated the following theorem
#check @len._unfold

theorem len_cons (a : α) (as : List α) : len (a::as) = 1 + len as := by
  cases as with
  | nil => simp [len_1, len_nil]
  | cons b bs => simp [len_2]

theorem listlen :  l : List α, l.length = len l := by
  intro l
  induction l with
  | nil => rfl
  | cons h t ih =>
    simp [List.length, len_cons, ih]
    rw [Nat.add_comm]

Jakub Nowak (Dec 06 2025 at 14:54):

Lean failed to generate equational theorem for this type. I was told this is something that could be fixed in Lean itself. See #new members > What's going on with Prod?.

inductive VecOrd : Type 1 where
| zero : VecOrd
| succ : VecOrd  VecOrd

inductive VecType : Type where
| zero : VecType
| succ : VecType

def VecOrd.type : VecOrd  VecType
| .zero => .zero
| .succ .. => .succ

def VecT (m : Type  Type) (α : Type) (ord : VecOrd) : Type :=
  (type : VecType) × (_ : ord.type = type) ×' Unit × ((match type, ord with
    | .zero, .zero => Unit
    | .succ, .succ o => α × m (VecT m α o)
  ) : Type)

/--
error: failed to generate equational theorem for `VecT`
  no progress at goal
  m : Type → Type
  α : Type
  ord : VecOrd
  r : VecOrd.below ord :=
    (VecOrd.brecOn.go ord fun ord f =>
        (type : VecType) ×
          (x : ord.type = type) ×'
            Unit ×
              (match (motive := (type : VecType) → (ord : VecOrd) → ord.type = type → VecOrd.below ord → Type) type,
                  ord, x with
                | VecType.zero, VecOrd.zero, x => fun x => Unit
                | VecType.succ, o.succ, x => fun x => α × m x.1)
                f).2
  ⊢ ((type : VecType) ×
        (x : ord.type = type) ×'
          Unit ×
            (match (motive :=
                (type : VecType) →
                  (ord : VecOrd) → ord.type = type → VecOrd.rec PUnit (fun a a_ih => Type ×' a_ih) ord → Type)
                type, ord, x with
              | VecType.zero, VecOrd.zero, x => fun x => Unit
              | VecType.succ, o.succ, x => fun x => α × m x.1)
              r) =
      ((type : VecType) ×
        (x : ord.type = type) ×'
          Unit ×
            match type, ord, x with
            | VecType.zero, VecOrd.zero, x => Unit
            | VecType.succ, o.succ, x => α × m (VecT m α o))

-/
#guard_msgs in
example : VecT m α ord := by
  unfold VecT

Last updated: Dec 20 2025 at 21:32 UTC