Zulip Chat Archive
Stream: mathlib4
Topic: subsingleton simp failure in presence of instance
Yakov Pechersky (May 24 2023 at 04:46):
I am experimenting with definitions in category theory, based on what we have in mathlib. I found that importing Mathlib.CategoryTheory.Category.Preorder
broke some of my simple simp
proofs. Specifically, it seems the Preorder.subsingleton_hom
instance gets in the way. Yet explicit reference to eq_iff_true_of_subsingleton
works.
Here is my repro:
section Std
theorem subsingleton_of_forall_eq (x : α) (h : ∀ y, y = x) : Subsingleton α :=
⟨fun a b => h a ▸ h b ▸ rfl⟩
theorem iff_of_true (ha : a) (hb : b) : a ↔ b := ⟨fun _ => hb, fun _ => ha⟩
theorem iff_true_intro (h : a) : a ↔ True := iff_of_true h ⟨⟩
theorem eq_iff_true_of_subsingleton [Subsingleton α] (x y : α) : x = y ↔ True :=
iff_true_intro (Subsingleton.elim ..)
end Std
section Unique
structure Unique (α : Sort u) extends Inhabited α where
uniq : ∀ a : α, a = default
attribute [class] Unique
namespace Unique
open Function
variable [Unique α]
instance (priority := 100) : Inhabited α :=
toInhabited ‹Unique α›
theorem eq_default (a : α) : a = default :=
uniq _ a
instance (priority := 100) : Subsingleton α :=
subsingleton_of_forall_eq _ eq_default
-- turning this `attribute [simp] ... in` off breaks the first `Initial.Iso`
attribute [simp] eq_iff_true_of_subsingleton in
theorem Unique.bijective {A B} [Unique A] [Unique B] {f : A → B} : True := trivial
end Unique
universe v u
class Quiver (V : Type u) where
Hom : V → V → Sort v
infixr:10 " ⟶ " => Quiver.Hom
class CategoryStruct (obj : Type u) extends Quiver.{v + 1} obj : Type max u (v + 1) where
id : ∀ X : obj, Hom X X
comp : ∀ {X Y Z : obj}, (X ⟶ Y) → (Y ⟶ Z) → (X ⟶ Z)
notation "𝟙" => CategoryStruct.id -- type as \b1
infixr:80 " ≫ " => CategoryStruct.comp -- type as \gg
abbrev SmallCategory (C : Type u) := CategoryStruct.{u} C
theorem ULift.ext (x y : ULift α) (h : x.down = y.down) : x = y :=
congrArg up h
instance [Subsingleton α] : Subsingleton (PLift α) := sorry
class Preorder (α : Type u) extends LE α where
le_refl : ∀ a : α, a ≤ a
le_trans : ∀ a b c : α, a ≤ b → b ≤ c → a ≤ c
structure Iso {C : Type u} [CategoryStruct.{v} C] (X Y : C) where
hom : X ⟶ Y
inv : Y ⟶ X
hom_inv_id : hom ≫ inv = 𝟙 X
inv_hom_id : inv ≫ hom = 𝟙 Y
infixr:10 " ≅ " => Iso
def Initial {C : Type u} [CategoryStruct C] (I : C) :=
∀ A : C, Unique (I ⟶ A)
set_option trace.Meta.synthInstance true
def Initial.Iso {C : Type u} [CategoryStruct C] {X Y : C} (hX : Initial X) (hY : Initial Y) : X ≅ Y where
hom := (hX Y).default
inv := (hY X).default
hom_inv_id := by have := hX X; simp -- uses eq_iff_true_of_subsingleton
inv_hom_id := by have := hY Y; simp
/-
[Meta.synthInstance] ✅ Subsingleton (X ⟶ X) ▼
[] new goal Subsingleton (X ⟶ X) ▼
[instances] #[@Unique.instSubsingleton, instSubsingleton]
[] ❌ apply instSubsingleton to Subsingleton (X ⟶ X) ▼
[tryResolve] ❌ Subsingleton (X ⟶ X) ≟ Subsingleton ?m.31237
[] ✅ apply @Unique.instSubsingleton to Subsingleton (X ⟶ X) ▼
[tryResolve] ✅ Subsingleton (X ⟶ X) ≟ Subsingleton (X ⟶ X)
[] new goal Unique (X ⟶ X) ▶
[] ✅ apply this to Unique (X ⟶ X) ▼
[tryResolve] ✅ Unique (X ⟶ X) ≟ Unique (X ⟶ X)
[resume] propagating Unique (X ⟶ X) to subgoal Unique (X ⟶ X) of Subsingleton (X ⟶ X) ▼
[] size: 1
[] result Unique.instSubsingleton
-/
section Mathlib.CategoryTheory.Category.Preorder
instance (priority := 100) Preorder.smallCategory (α : Type u) [Preorder α] : CategoryStruct.{u} α where
Hom U V := ULift (PLift (U ≤ V))
id X := ⟨⟨Preorder.le_refl X⟩⟩
comp f g := ⟨⟨Preorder.le_trans _ _ _ f.down.down g.down.down⟩⟩
-- porting note: added to ease the port of `CategoryTheory.Subobject.Basic`
instance Preorder.subsingleton_hom {α : Type u} [Preorder α] (U V : α) :
Subsingleton (U ⟶ V) := ⟨fun _ _ => ULift.ext _ _ (Subsingleton.elim _ _ )⟩
end Mathlib.CategoryTheory.Category.Preorder
def Initial.Iso' {C : Type u} [CategoryStruct C] {X Y : C} (hX : Initial X) (hY : Initial Y) : X ≅ Y where
hom := (hX Y).default
inv := (hY X).default
hom_inv_id := by have := hX X; simp -- now it breaks
inv_hom_id := by have := hY Y; simp -- now it breaks
/-
[Meta.synthInstance] 💥 Subsingleton (X ⟶ X) ▼
[] new goal Subsingleton (X ⟶ X) ▼
[instances] #[@Unique.instSubsingleton, instSubsingleton, @Preorder.subsingleton_hom]
[] 💥 apply @Preorder.subsingleton_hom to Subsingleton (X ⟶ X) ▼
[tryResolve] 💥 Subsingleton (X ⟶ X) ≟ Subsingleton (?m.31875 ⟶ ?m.31876)
[Meta.synthInstance] 💥 Subsingleton (X ⟶ X) ▼
[] new goal Subsingleton (X ⟶ X) ▼
[instances] #[@Unique.instSubsingleton, instSubsingleton, @Preorder.subsingleton_hom]
[] 💥 apply @Preorder.subsingleton_hom to Subsingleton (X ⟶ X) ▼
[tryResolve] 💥 Subsingleton (X ⟶ X) ≟ Subsingleton (?m.31905 ⟶ ?m.31906)
-/
def Initial.Iso'' {C : Type u} [CategoryStruct C] {X Y : C} (hX : Initial X) (hY : Initial Y) : X ≅ Y where
hom := (hX Y).default
inv := (hY X).default
hom_inv_id := by have := hX X; exact (eq_iff_true_of_subsingleton _ _).mpr trivial
inv_hom_id := by have := hY Y; exact (eq_iff_true_of_subsingleton _ _).mpr trivial
/-
[Meta.synthInstance] 💥 Subsingleton ?m.32133 ▼
[] new goal Subsingleton ?m.32133 ▼
[instances] #[@Unique.instSubsingleton, instSubsingleton, @instSubsingletonForAll, @Preorder.subsingleton_hom, instSubsingletonDecidable, @instSubsingletonSquash, @instSubsingletonPLift, instSubsingletonPUnit, @instSubsingletonStateM]
[] 💥 apply @instSubsingletonStateM to Subsingleton ?m.32133 ▼
[tryResolve] 💥 Subsingleton ?m.32133 ≟ Subsingleton (StateM ?m.32146 ?m.32147)
[Meta.synthInstance] ✅ Subsingleton (X ⟶ X) ▼
[] new goal Subsingleton (X ⟶ X) ▼
[instances] #[@Unique.instSubsingleton, instSubsingleton, @Preorder.subsingleton_hom]
[] ❌ apply @Preorder.subsingleton_hom to Subsingleton (X ⟶ X) ▼
[tryResolve] ❌ Subsingleton (X ⟶ X) ≟ Subsingleton (?m.32163 ⟶ ?m.32164)
[] ❌ apply instSubsingleton to Subsingleton (X ⟶ X) ▼
[tryResolve] ❌ Subsingleton (X ⟶ X) ≟ Subsingleton ?m.32181
[] ✅ apply @Unique.instSubsingleton to Subsingleton (X ⟶ X) ▼
[tryResolve] ✅ Subsingleton (X ⟶ X) ≟ Subsingleton (X ⟶ X)
[] new goal Unique (X ⟶ X) ▼
[instances] #[this]
[] ✅ apply this to Unique (X ⟶ X) ▼
[tryResolve] ✅ Unique (X ⟶ X) ≟ Unique (X ⟶ X)
[resume] propagating Unique (X ⟶ X) to subgoal Unique (X ⟶ X) of Subsingleton (X ⟶ X) ▼
[] size: 1
[] result Unique.instSubsingleton
-/
Yakov Pechersky (May 24 2023 at 04:50):
Ah, this was explored in https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Failure.20of.20TC.20search.20in.20.60simp.60.20with.20.60etaExperiment.60.2E
Yakov Pechersky (May 24 2023 at 04:50):
So setting explicit universes on Category.{v, u}
makes simp
work again.
Kevin Buzzard (May 24 2023 at 05:10):
Or [CategoryStruct.{v} C]
(you only need to give v, that's the one it's not synthesizing). Without it and with universes on you get
[] 💥 CategoryStruct.{?u.31729, u} C =?= CategoryStruct.{u, u} C ▼
[] ✅ C =?= C
and for some reason it won't solve that universe problem.
Scott Morrison (May 24 2023 at 18:18):
The other solution is to rely on Subsingleton.elim
instead, which is what aesop_cat
now does.
Yakov Pechersky (May 24 2023 at 18:33):
How would/does Subsingleton.elim
work still, if one hits a failure to synthesize a Subsingleton here?
[Meta.synthInstance] 💥 Subsingleton (X ⟶ X) ▼
[] new goal Subsingleton (X ⟶ X) ▼
[instances] #[@Unique.instSubsingleton, instSubsingleton, @Preorder.subsingleton_hom]
[] 💥 apply @Preorder.subsingleton_hom to Subsingleton (X ⟶ X) ▼
[tryResolve] 💥 Subsingleton (X ⟶ X) ≟ Subsingleton (?m.31875 ⟶ ?m.31876)
[Meta.synthInstance] 💥 Subsingleton (X ⟶ X) ▼
[] new goal Subsingleton (X ⟶ X) ▼
[instances] #[@Unique.instSubsingleton, instSubsingleton, @Preorder.subsingleton_hom]
[] 💥 apply @Preorder.subsingleton_hom to Subsingleton (X ⟶ X) ▼
[tryResolve] 💥 Subsingleton (X ⟶ X) ≟ Subsingleton (?m.31905 ⟶ ?m.31906)
Scott Morrison (May 25 2023 at 01:21):
There are apparently different behaviours here inside simp
vs just with apply
(presumably also exact
, etc).
Last updated: Dec 20 2023 at 11:08 UTC