Zulip Chat Archive

Stream: mathlib4

Topic: Meta code in order to do multiple substitutions


Joël Riou (May 22 2024 at 16:58):

Following the start #12798 of the development of fibered categories by @Calle Sönne and @Paul Lezeau I feel that some meta code would be useful in the following situation:

import Mathlib.CategoryTheory.EqToHom

namespace CategoryTheory.Functor

variable {𝒮 𝒳 : Type*} [Category 𝒮] [Category 𝒳 ] (p :  𝒳  𝒮 )

class IsHomLift {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) : Prop where
  domain_eq : p.obj a = R := by aesop_cat
  codomain_eq : p.obj b = S := by aesop_cat
  fac : f = eqToHom domain_eq.symm  p.map φ  eqToHom codomain_eq := by aesop_cat

lemma test {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) [p.IsHomLift f φ] : 0 = 1 := by
  -- initially, we have a morphism `φ` which is "over" a morphism `f` via the functor `p`
  obtain rfl : p.obj a = R := IsHomLift.domain_eq (f := f) (φ := φ)
  obtain rfl : p.obj b = S := IsHomLift.codomain_eq (f := f) (φ := φ)
  obtain rfl : f = p.map φ := by simpa using IsHomLift.fac (p := p) (f := f) (φ := φ)
  -- now, we only have the morphism `φ`
  sorry

end CategoryTheory.Functor

Is there a way to define a tactic subst_hom_lift p f φ which would attempt at doing the three substitutions done by obtain above?

I know that an alternative approach would be to use an inductive type (which could be repackaged in a type-class):

inductive IsHomLift' :  {R S : 𝒮} {a b : 𝒳} (_ : R  S) (_ : a  b), Prop
  | map {a b : 𝒳} (φ : a  b) : IsHomLift' (p.map φ) φ

lemma test' {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) (hp : p.IsHomLift' f φ) : 0 = 1 := by
  -- initially, we have a morphism `φ` which is "over" a morphism `f` via the functor `p`
  cases hp
  -- now, we only have the morphism `φ`
  sorry

What would be the recommended ways to do such things?

Adam Topaz (May 22 2024 at 17:08):

Can you get by with something along the following lines?

inductive IsHomLiftAux : {R S : 𝒮}  {a b : 𝒳}  (R  S)  (a  b)  Prop where
  | mk {a b} (φ : a  b) : IsHomLiftAux (p.map φ) φ

class IsHomLift {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) : Prop where
  cond : IsHomLiftAux p f φ

lemma test {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) [p.IsHomLift f φ] : 0 = 1 := by
  obtain ⟨⟩ := IsHomLift.cond (p := p) (f := f) (φ := φ)
  sorry

Adam Topaz (May 22 2024 at 17:08):

Alternatively making a tactic is certainly possible, but would require some work.

Adam Topaz (May 22 2024 at 17:12):

Jeez, I seem to have completely missed your second code block :rofl:

Adam Topaz (May 22 2024 at 17:12):

Anyway, I think going with the inductive type is preferable. I think the fact that the first IsHomLift has eqToHoms is a red flag.

Andrew Yang (May 22 2024 at 17:14):

Maybe

lemma test {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) [h : p.IsHomLift f φ] : 0 = 1 := by
  obtain rfl, rfl, rfl := h
  sorry

Adam Topaz (May 22 2024 at 17:15):

Doesn't that still leave eqToHoms? (yes, they would simplify away with simp, but still...)

Andrew Yang (May 22 2024 at 17:17):

But if p, f, q aren't actually substitutable variables then inductives might be harder to use?

Adam Topaz (May 22 2024 at 17:17):

E.g. this doesn't work:

import Mathlib.CategoryTheory.EqToHom

namespace CategoryTheory.Functor

variable {𝒮 𝒳 : Type*} [Category 𝒮] [Category 𝒳 ] (p :  𝒳  𝒮 )

class IsHomLift {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) : Prop where
  domain_eq : p.obj a = R := by aesop_cat
  codomain_eq : p.obj b = S := by aesop_cat
  fac : f = eqToHom domain_eq.symm  p.map φ  eqToHom codomain_eq := by aesop_cat

lemma test {R S : 𝒮} {a b : 𝒳} (f g : R  S) (φ : a  b) [h : p.IsHomLift f φ] [h' : p.IsHomLift g φ] : f = g := by
  obtain rfl, rfl, rfl := h
  obtain rfl, rfl, rfl := h' -- fails
  sorry

Adam Topaz (May 22 2024 at 17:18):

Well, that fails also with the inductive approach, so I don't know.

Joël Riou (May 22 2024 at 17:19):

Anyway, it seems the better approach is to use a definition using an inductive type, and provide an API (alternate constructors/lemmas) which may have to feature some eqToHom.

Calle Sönne (May 23 2024 at 07:51):

Thanks for this! I didn't know about this technique with using an inductive type, so I will play around with it a bit to see what improvements I can get

Calle Sönne (May 23 2024 at 09:33):

Also with this approach subst_hom_lift, like @Joël Riou suggested, can be very easily defined as a macro (and is imo a lot more readable than obtain ⟨⟩ := IsHomLift.cond (p := p) (f := f) (φ := φ))

Calle Sönne (May 24 2024 at 11:01):

Adam Topaz said:

lemma test {R S : 𝒮} {a b : 𝒳} (f : R  S) (φ : a  b) [p.IsHomLift f φ] : 0 = 1 := by
  obtain ⟨⟩ := IsHomLift.cond (p := p) (f := f) (φ := φ)
  sorry

When using this in more complicated proofs, I am running into the issue that the first line only replaces φ and f, and not also R, S, a, b. So φ : a ⟶ b becomes φ : a✝⟶ b✝ after the first line, and f becomes p.map φ : p.obj a✝ ⟶ p.obj b✝ (and R, S, a, b are still in the context). Is there a way to make this line of code also replace R, S, a, b? Or at least so that I can give other names to a✝, b✝?

Calle Sönne (May 24 2024 at 14:46):

I now found out that I can just do clear a b :)

Eric Wieser (May 24 2024 at 14:57):

Another approach here is to use the non-inductive type, but then write an induction principle to match the one generated by inductive


Last updated: May 02 2025 at 03:31 UTC