Zulip Chat Archive
Stream: lean4
Topic: Policy/Preference on very long `simp only`s
Robert Maxton (Mar 11 2025 at 22:39):
What's the community preference on non-terminal simps when the alternative simp only
is very long? I've got a simp
whose replacement is a solid ten lines long, and I'm wondering if it's really worth replacing.
Robert Maxton (Mar 11 2025 at 22:42):
(There may or may not be a way to refactor this to be terminal -- though the relevant proof is difficult precisely because of a very long and highly dependent goal, so I kind of doubt it -- but for the sake of argument, assume there isn't. Is there a point where we draw the line, or alternatively is there some other consideration like "internally complex simp
calls save disproportionately more time if converted to simp only
" or something similar I don't know about?)
Kim Morrison (Mar 11 2025 at 22:54):
Is this asking about Mathlib or more generally?
More generally, there's no "policy". For Mathlib, I think we'd have to look at concrete examples to decide exceptions. have
and suffices
can nearly always --- for goals that appear in Mathlib --- help constrain the size of simp only
.
Kevin Buzzard (Mar 11 2025 at 23:03):
Yes, before simp?
the workflow (in the Lean 3 days) used to be
1) run simp
2) delete it and instead write suffices [the goal after simp] by simp
Robert Maxton (Mar 11 2025 at 23:05):
unfortunately in my case even the goal after simp is many lines long ^.^;
I'm currently cleaning it up a little, but I'll post it in a minute as I could use the advice
(It's making a docs#CategoryTheory.Pseudofunctor from ULift Cat
to ULift Cat
, so I have tangled n-morphisms everywhere >.>;)
Robert Maxton (Mar 11 2025 at 23:45):
Right, here's as minimal a #mwe as I can get.
import Mathlib.CategoryTheory.Bicategory.Functor.Pseudofunctor
import Mathlib.CategoryTheory.Category.Cat
import Mathlib.CategoryTheory.Category.ULift
-- import DiagrammaticMathlib.Bicategory.Basic
-- import DiagrammaticMathlib.Bicategory.Functor.Strict
namespace CategoryTheory
open CategoryTheory renaming ULiftHomULiftCategory.equiv → UHUC.equiv
open Bicategory ULift
universe w₂ w₁ w₀ v₂ v₁ v₀ u₂ u₁ u₀
attribute [pp_with_univ] Cat ULiftHom
variable (B : Type u₁) [Bicategory.{w₁, v₁} B] [Strict B]
@[simps!?]
instance (B : Type u₁) [Bicategory.{w₁, v₁} B] [Strict B] :
Bicategory.{max w₂ w₁, max v₂ v₁} (ULiftHom.{v₂} (ULift.{u₂} B)) :=
let homCategory (X Y : ULiftHom (ULift.{u₂} B)) : Category (X ⟶ Y) := {
Hom f g := ULift.{w₂} <| (ULift.down f) ⟶ (ULift.down g)
id f := ⟨𝟙 f.down⟩
comp η ϑ := ⟨η.down ≫ ϑ.down⟩}
have eqToHom_down {X Y : ULiftHom (ULift.{u₂} B)} {f g : X ⟶ Y} (η : f = g) :
(eqToHom η).down = eqToHom (congrArg ULift.down η) := by
cases η; rfl
{ __ := inferInstanceAs (Category <| ULiftHom.{v₂} <| ULift.{u₂} B)
homCategory := homCategory
whiskerLeft {X Y Z} f {g₁ g₂} η := ⟨f.down ◁ η.down⟩
whiskerRight := fun ⟨η⟩ ⟨h⟩ ↦ ⟨η ▷ h⟩
associator f g h := eqToIso (Category.assoc f g h)
leftUnitor f := eqToIso (Category.id_comp f)
rightUnitor f := eqToIso (Category.comp_id f)
whiskerLeft_id := by intros; apply ULift.ext; unfold_projs; simp
id_whiskerRight := by intros; apply ULift.ext; unfold_projs; simp
comp_whiskerRight := by
rintro _ _ _ _ _ _ ⟨η⟩ ⟨ϑ⟩ ⟨i⟩; apply ULift.ext; unfold_projs; simp
id_whiskerLeft := by
intros; apply ULift.ext; unfold_projs
simp [Strict.leftUnitor_eqToIso, eqToHom_down]
comp_whiskerLeft := by
intros; apply ULift.ext; unfold_projs
simp [Strict.associator_eqToIso, eqToHom_down]
whiskerRight_id := by
rintro _ _ _ _ ⟨η⟩; apply ULift.ext; unfold_projs
simp [Strict.rightUnitor_eqToIso, eqToHom_down]
whiskerRight_comp := by
rintro _ _ _ _ _ _ ⟨η⟩ _ _; apply ULift.ext; unfold_projs
simp [Strict.associator_eqToIso, eqToHom_down]
whisker_assoc := by
rintro _ _ _ _ _ _ _ ⟨η⟩ _; apply ULift.ext; unfold_projs
simp [Strict.associator_eqToIso, eqToHom_down]
whisker_exchange := by
rintro _ _ _ ⟨f⟩ ⟨g⟩ ⟨h⟩ ⟨i⟩ ⟨η⟩ ⟨ϑ⟩; apply ULift.ext; unfold_projs
simpa using Bicategory.whisker_exchange η ϑ }
#check ULiftHomULiftCategory.equiv
#synth Bicategory (ULiftHom <| ULift Cat)
namespace Cat
section uLiftEmbedding
variable {C D E : ULiftHom.{v₂} (ULift.{u₂} Cat.{v₁, u₁})}
(F : C ⟶ D) {F₁ F₂ : C ⟶ D} (η : F₁ ⟶ F₂)
{G₁ G₂ : D ⟶ E} (G : D ⟶ E) (ϑ : G₁ ⟶ G₂)
@[simps]
private def _prelax :
CategoryTheory.PrelaxFunctor (ULiftHom.{v₂} <| ULift.{u₂} Cat.{v₁, u₁}) Cat.{max v₂ v₁, max u₂ u₁} where
obj C := Cat.of (ULiftHom.{v₂} <| ULift.{u₂} ↑C.1)
map {C D} F := (UHUC.equiv C.1).inverse ⋙ F.down ⋙ (UHUC.equiv D.1).functor
map₂ η := whiskerLeft _ (whiskerRight η.down _)
private abbrev _mapId (C : ULiftHom.{v₂} <| ULift.{u₂} Cat.{v₁, u₁}) : _prelax.map (𝟙 C) ≅ 𝟙 (_prelax.obj C) :=
isoWhiskerLeft (UHUC.equiv C.1).inverse (Functor.leftUnitor (UHUC.equiv C.1).functor)
≪≫ (UHUC.equiv C.1).counitIso
private abbrev _mapComp : _prelax.map ⟨F.1 ⋙ G.1⟩ ≅ _prelax.map F ⋙ _prelax.map G :=
let ι₀ := (isoWhiskerRight (isoWhiskerLeft F.1 (UHUC.equiv.{v₂, u₂} D.1).unitIso.symm) G.down).symm
let ι₁ := isoWhiskerRight (Functor.rightUnitor F.1).symm G.1 ≪≫ ι₀
≪≫ isoWhiskerRight (Functor.associator F.1 (UHUC.equiv ↑D.1).functor _).symm G.1
≪≫ (Functor.associator _ _ _)
let ι₂ := isoWhiskerRight ι₁ _ ≪≫ (Functor.associator _ _ _) ≪≫ isoWhiskerLeft _ (Functor.associator _ _ _)
isoWhiskerLeft _ ι₂ ≪≫ (Functor.associator _ _ _).symm
private lemma _map₂_whisker_left : _prelax.map₂ (F ◁ ϑ) = (_mapComp F G₁).hom ≫
_prelax.map F ◁ _prelax.map₂ ϑ ≫ (_mapComp F G₂).inv := by
revert C D E; rintro ⟨C⟩ ⟨D⟩ ⟨E⟩ ⟨F⟩ ⟨G₁⟩ ⟨G₂⟩ ⟨ϑ⟩
unfold_projs; ext
simp
simp_rw [← (UHUC.equiv E.1).functor.map_comp]
erw [ϑ.naturality_assoc]
simp_rw [← G₂.map_comp, (UHUC.equiv D.1).unitIso.hom_inv_id_app]
erw [G₂.map_id, Category.comp_id]
Robert Maxton (Mar 11 2025 at 23:46):
Offending nonterminal simp is in the last lemma; it expands into about ten lines of simp only
on my screen, though probably two of those could be saved by giving certain long instance names shorter ones.
Ruben Van de Velde (Mar 12 2025 at 08:23):
You could use simp? says
Robert Maxton (Mar 12 2025 at 08:24):
How is that different from simp?
?
Last updated: May 02 2025 at 03:31 UTC