Skip to content

Meta.isDefEq failure #2461

@kbuzzard

Description

@kbuzzard

Prerequisites

  • Put an X between the brackets on this line if you have done all of the following:
    • Checked that your issue isn't already filed.
    • Reduced the issue to a self-contained, reproducible test case.

Description

Meta.isDefEq fails to deduce that two defeq terms are defeq, causing simp to fail.

Steps to Reproduce

No doubt this can be minimised more, but

section algebra_hierarchy_classes_to_comm_ring

class Zero (α : Type) where
  zero : α

class One (α : Type) where
  one : α

class Semiring (α : Type) extends Add α, Mul α, Zero α, One α

class CommSemiring (R : Type) extends Semiring R

class Ring (R : Type) extends Semiring R

class CommRing (R : Type) extends Ring R

end algebra_hierarchy_classes_to_comm_ring

section algebra_hierarchy_morphisms

class FunLike (F : Type) (α : outParam Type) (β : outParam <| α → Type) where
  coe : F → ∀ a : α, β a

instance (priority := 100) FunLike.insthasCoeToFun {F α : Type} {β : α → Type} [FunLike F α β] : CoeFun F fun _ ↦ ∀ a : α, β a where coe := FunLike.coe

structure ZeroHom (M N : Type) [Zero M] [Zero N] where
  toFun : M → N

class ZeroHomClass (F : Type) (M N : outParam Type) [Zero M] [Zero N]
  extends FunLike F M fun _ => N where

structure OneHom (M : Type) (N : Type) [One M] [One N] where
  toFun : M → N

class OneHomClass (F : Type) (M N : outParam Type) [One M] [One N]
  extends FunLike F M fun _ => N where

structure AddHom (M : Type) (N : Type) [Add M] [Add N] where
  toFun : M → N

class AddHomClass (F : Type) (M N : outParam Type) [Add M] [Add N]
  extends FunLike F M fun _ => N where

structure MulHom (M : Type) (N : Type) [Mul M] [Mul N] where
  toFun : M → N

infixr:25 " →ₙ* " => MulHom

class MulHomClass (F : Type) (M N : outParam Type) [Mul M] [Mul N]
  extends FunLike F M fun _ => N where

structure AddMonoidHom (M : Type) (N : Type) [Add M] [Zero M] [Add N] [Zero N] extends
  ZeroHom M N, AddHom M N

infixr:25 " →+ " => AddMonoidHom

class AddMonoidHomClass (F : Type) (M N : outParam Type) [Add M] [Zero M] [Add N] [Zero N]
  extends AddHomClass F M N, ZeroHomClass F M N

structure MonoidHom (M : Type) (N : Type) [Mul M] [One M] [Mul N] [One N] extends
  OneHom M N, M →ₙ* N

infixr:25 " →* " => MonoidHom

class MonoidHomClass (F : Type) (M N : outParam Type) [Mul M] [One M] [Mul N] [One N]
  extends MulHomClass F M N, OneHomClass F M N

structure MonoidWithZeroHom (M : Type) (N : Type)
  [Mul M] [Zero M] [One M] [Mul N] [Zero N] [One N] extends ZeroHom M N, MonoidHom M N

infixr:25 " →*₀ " => MonoidWithZeroHom

structure NonUnitalRingHom (α β : Type) [Add α] [Zero α] [Mul α]
  [Add β] [Zero β] [Mul β] extends α →ₙ* β, α →+ β

class MonoidWithZeroHomClass (F : Type) (M N : outParam Type) [Mul M] [Zero M] [One M]
  [Mul N] [Zero N] [One N] extends MonoidHomClass F M N, ZeroHomClass F M N

infixr:25 " →ₙ+* " => NonUnitalRingHom

structure RingHom (α : Type) (β : Type) [Semiring α] [Semiring β] extends
  α →* β, α →+ β, α →ₙ+* β, α →*₀ β

infixr:25 " →+* " => RingHom

class RingHomClass (F : Type) (α β : outParam Type) [Semiring α]
  [Semiring β] extends MonoidHomClass F α β, AddMonoidHomClass F α β,
  MonoidWithZeroHomClass F α β

instance instRingHomClass (R S : Type) [Semiring R] [Semiring S] :
    RingHomClass (R →+* S) R S where
  coe f := f.toFun

-- this is needed to create the troublesome instance `Algebra.instid`
def RingHom.id (α : Type) [Semiring α] : α →+* α := by
  refine' { toFun := _root_.id.. }

end algebra_hierarchy_morphisms

section HSMul_stuff

class HSMul (α : Type) (β : Type) (γ : outParam Type) where
  hSMul : α → β → γ

class SMul (M : Type) (α : Type) where
  smul : M → α → α

infixr:73 "" => HSMul.hSMul

instance instHSMul {α β : Type} [SMul α β] : HSMul α β β where
  hSMul := SMul.smul

-- note that the function `SMulZeroClass.toSMul` is what disrupts `simp` later
class SMulZeroClass (M A : Type) extends SMul M A where

class SMulWithZero (R M : Type) extends SMulZeroClass R M where

instance MulZeroClass.toSMulWithZero (R : Type) [Mul R] [Zero R] : SMulWithZero R R where
  smul := (· * ·)

end HSMul_stuff

section Algebra_stuff

class Algebra (R A : Type) [CommSemiring R] [Semiring A] extends SMul R A,
  R →+* A where

-- needed for troublesome `Algebra.instid`
def RingHom.toAlgebra' {R S : Type} [CommSemiring R] [Semiring S] (i : R →+* S)
    : Algebra R S where
  smul c x := i c * x
  toRingHom := i

-- needed for troublesome `Algebra.instid`
def RingHom.toAlgebra {R S : Type} [CommSemiring R] [CommSemiring S] (i : R →+* S) : Algebra R S :=
  i.toAlgebra'

-- comment this out and the failing `simp` works
instance Algebra.instid (R : Type) [CommSemiring R] : Algebra R R :=
  (RingHom.id R).toAlgebra

end Algebra_stuff

namespace Pi_stuff

instance instSMul {I : Type} {f : I → Type} {M : Type} [∀ i, SMul M <| f i] : SMul M (∀ i : I, f i) :=
  ⟨fun s x => fun i => s • x i⟩

end Pi_stuff

section oliver_example

theorem Pi.smul_apply {I : Type} {f : I → Type} {β : Type} [∀ i, SMul β (f i)] (x : ∀ i, f i) (b : β) (i : I) : (b • x) i = b • (x i) :=
  rfl

instance (R : Type) [CommRing R] : CommSemiring R where

-- `foo` and `bar` are defeq
example {R : Type} [CommRing R] : True :=
  let foo := (Algebra.instid R).toSMul
  let bar : SMul R R := SMulZeroClass.toSMul
  have : foo = bar := rfl -- they are defeq
  trivial

-- this proof works fine
example {α R : Type} [CommRing R] (f : α → R) (r : R) (a : α) :
    (r • f) a = r • (f a) := by
  simp only [Pi.smul_apply]

-- the presence of `bar` breaks the proof
-- set_option trace.Meta.isDefEq true in
example {α R : Type} [CommRing R] (f : α → R) (r : R) (a : α) :
    (r • f) a = r • (f a) := by
  let bar : SMul R R := SMulZeroClass.toSMul
  --  have : Algebra.toSMul = bar := rfl
  --  have : (Algebra.instid R).toSMul = bar := rfl
  fail_if_success simp only [Pi.smul_apply]
  -- the isDefEq trace indicates a failure of isDefEq to prove
  -- that two defeq things are defeq
  sorry

-- The proof is fixed if we use `Ring` instead of `CommRing`.
example {α R : Type} [Ring R] (f : α → R) (r : R) (a : α) :
    (r • f) a = r • (f a) := by
  let bar : SMul R R := SMulZeroClass.toSMul
  simp only [Pi.smul_apply]

end oliver_example

The relevant part of the trace.Meta.isDefEq output is

[Meta.isDefEq] ❌ fun i ↦ Algebra.toSMul =?= fun i ↦ bar ▼
  [] ✅ α =?= α
  [] ❌ Algebra.toSMul =?= bar ▼
    [] ❌ Algebra.toSMul =?= SMulZeroClass.toSMul ▼
      [] ❌ (Algebra.instid R).1 =?= SMulWithZero.toSMulZeroClass.1 ▼
        [] ❌ (Algebra.instid R).1 =?= { smul := fun x x_1 ↦ x * x_1 } ▼
          [] ✅ SMul R R =?= SMul R R
          [] ❌ SMul.smul =?= fun x x_1 ↦ x * x_1 ▼
            [] ❌ fun x x_1 ↦ x * x_1 =?= fun a ↦ SMul.smul a ▼
              [] ✅ R =?= R
              [] ❌ fun x ↦ x✝ * x =?= SMul.smul x✝ ▼
                [] ❌ fun x ↦ x✝ * x =?= fun a ↦ SMul.smul x✝ a ▼
                  [] ✅ R =?= R
                  [] ❌ x✝¹ * x✝ =?= SMul.smul x✝¹ x✝ ▼
                    [] ❌ @HMul.hMul =?= @SMul.smul
                    [onFailure] ❌ x✝¹ * x✝ =?= SMul.smul x✝¹ x✝
                    [] ❌ Mul.mul x✝¹ x✝ =?= SMul.smul x✝¹ x✝ ▼
                      [] ❌ @Mul.mul =?= @SMul.smul
                      [onFailure] ❌ Mul.mul x✝¹ x✝ =?= SMul.smul x✝¹ x✝
                      [onFailure] ❌ Mul.mul x✝¹ x✝ =?= SMul.smul x✝¹ x✝
          [onFailure] ❌ (Algebra.instid R).1 =?= { smul := fun x x_1 ↦ x * x_1 }

and in particular the failure on line 3 [] ❌ Algebra.toSMul =?= bar ▼ is unexpected because the terms are defeq.

Expected behavior: [What you expect to happen]

I would not expect that randomly adding a term to the local context would break a simp proof.

Actual behavior: [What actually happens]

In the presence of bar, simp now makes no progress.

Reproduces how often: [What percentage of the time does it reproduce?]

100%

Versions

Lean (version 4.0.0-nightly-2023-08-19, commit 63d2bdd4908b, Release) on Ubuntu

Additional Information

There are workarounds, for example one can use simp only [Pi.smul_apply _]. But telling users to add _s everywhere is not an ideal solution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions