l3lab/ntp-mathlib huggingface dataset:
theorem Faithful.div_comp (F : C ⥤ E) [Faithful F] (G : D ⥤ E) [Faithful G] (obj : C → D)
    (h_obj : ∀ X, G.obj (obj X) = F.obj X) (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq (G.map (map f)) (F.map f)) :
    Faithful.div F G obj @h_obj @map @h_map ⋙ G = F := by
  -- Porting note: Have to unfold the structure twice because the first one recovers only the
  -- prefunctor `F_pre`
  cases' F with F_pre _ _; cases' G with G_pre _ _
  cases' F_pre with F_obj _; cases' G_pre with G_obj _
  

Proof state:
case mk.mk.mk.mk
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F F' : C ⥤ D
G : D ⥤ E
obj : C → D
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
F_obj : C → E
map✝¹ : {X Y : C} → (X ⟶ Y) → (F_obj X ⟶ F_obj Y)
map_id✝¹ : ∀ (X : C), { obj := F_obj, map := map✝¹ }.map (𝟙 X) = 𝟙 ({ obj := F_obj, map := map✝¹ }.obj X)
map_comp✝¹ :
  ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := F_obj, map := map✝¹ }.map (f ≫ g) =
      { obj := F_obj, map := map✝¹ }.map f ≫ { obj := F_obj, map := map✝¹ }.map g
inst✝¹ : Faithful (Functor.mk { obj := F_obj, map := map✝¹ })
G_obj : D → E
map✝ : {X Y : D} → (X ⟶ Y) → (G_obj X ⟶ G_obj Y)
map_id✝ : ∀ (X : D), { obj := G_obj, map := map✝ }.map (𝟙 X) = 𝟙 ({ obj := G_obj, map := map✝ }.obj X)
map_comp✝ :
  ∀ {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj, map := map✝ }.map (f ≫ g) =
      { obj := G_obj, map := map✝ }.map f ≫ { obj := G_obj, map := map✝ }.map g
inst✝ : Faithful (Functor.mk { obj := G_obj, map := map✝ })
h_obj :
  ∀ (X : C), (Functor.mk { obj := G_obj, map := map✝ }).obj (obj X) = (Functor.mk { obj := F_obj, map := map✝¹ }).obj X
h_map :
  ∀ {X Y : C} {f : X ⟶ Y},
    HEq ((Functor.mk { obj := G_obj, map := map✝ }).map (map f)) ((Functor.mk { obj := F_obj, map := map✝¹ }).map f)
⊢ Faithful.div (Functor.mk { obj := F_obj, map := map✝¹ }) (Functor.mk { obj := G_obj, map := map✝ }) obj h_obj map
        h_map ⋙
      Functor.mk { obj := G_obj, map := map✝ } =
    Functor.mk { obj := F_obj, map := map✝¹ }

Next tactic:
unfold Faithful.div Functor.comp
theorem Faithful.div_comp (F : C ⥤ E) [Faithful F] (G : D ⥤ E) [Faithful G] (obj : C → D)
    (h_obj : ∀ X, G.obj (obj X) = F.obj X) (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq (G.map (map f)) (F.map f)) :
    Faithful.div F G obj @h_obj @map @h_map ⋙ G = F := by
  -- Porting note: Have to unfold the structure twice because the first one recovers only the
  -- prefunctor `F_pre`
  cases' F with F_pre _ _; cases' G with G_pre _ _
  cases' F_pre with F_obj _; cases' G_pre with G_obj _
  unfold Faithful.div Functor.comp
  -- Porting note: unable to find the lean4 analogue to `unfold_projs`, works without it
  

Proof state:
case mk.mk.mk.mk
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F F' : C ⥤ D
G : D ⥤ E
obj : C → D
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
F_obj : C → E
map✝¹ : {X Y : C} → (X ⟶ Y) → (F_obj X ⟶ F_obj Y)
map_id✝¹ : ∀ (X : C), { obj := F_obj, map := map✝¹ }.map (𝟙 X) = 𝟙 ({ obj := F_obj, map := map✝¹ }.obj X)
map_comp✝¹ :
  ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := F_obj, map := map✝¹ }.map (f ≫ g) =
      { obj := F_obj, map := map✝¹ }.map f ≫ { obj := F_obj, map := map✝¹ }.map g
inst✝¹ : Faithful (Functor.mk { obj := F_obj, map := map✝¹ })
G_obj : D → E
map✝ : {X Y : D} → (X ⟶ Y) → (G_obj X ⟶ G_obj Y)
map_id✝ : ∀ (X : D), { obj := G_obj, map := map✝ }.map (𝟙 X) = 𝟙 ({ obj := G_obj, map := map✝ }.obj X)
map_comp✝ :
  ∀ {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj, map := map✝ }.map (f ≫ g) =
      { obj := G_obj, map := map✝ }.map f ≫ { obj := G_obj, map := map✝ }.map g
inst✝ : Faithful (Functor.mk { obj := G_obj, map := map✝ })
h_obj :
  ∀ (X : C), (Functor.mk { obj := G_obj, map := map✝ }).obj (obj X) = (Functor.mk { obj := F_obj, map := map✝¹ }).obj X
h_map :
  ∀ {X Y : C} {f : X ⟶ Y},
    HEq ((Functor.mk { obj := G_obj, map := map✝ }).map (map f)) ((Functor.mk { obj := F_obj, map := map✝¹ }).map f)
⊢ Functor.mk
      { obj := fun X => (Functor.mk { obj := G_obj, map := map✝ }).obj ((Functor.mk { obj := obj, map := map }).obj X),
        map := fun {X Y} f =>
          (Functor.mk { obj := G_obj, map := map✝ }).map ((Functor.mk { obj := obj, map := map }).map f) } =
    Functor.mk { obj := F_obj, map := map✝¹ }

Next tactic:
have : F_obj = G_obj ∘ obj := (funext h_obj).symm
theorem Faithful.div_comp (F : C ⥤ E) [Faithful F] (G : D ⥤ E) [Faithful G] (obj : C → D)
    (h_obj : ∀ X, G.obj (obj X) = F.obj X) (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq (G.map (map f)) (F.map f)) :
    Faithful.div F G obj @h_obj @map @h_map ⋙ G = F := by
  -- Porting note: Have to unfold the structure twice because the first one recovers only the
  -- prefunctor `F_pre`
  cases' F with F_pre _ _; cases' G with G_pre _ _
  cases' F_pre with F_obj _; cases' G_pre with G_obj _
  unfold Faithful.div Functor.comp
  -- Porting note: unable to find the lean4 analogue to `unfold_projs`, works without it
  have : F_obj = G_obj ∘ obj := (funext h_obj).symm
  

Proof state:
case mk.mk.mk.mk
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F F' : C ⥤ D
G : D ⥤ E
obj : C → D
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
F_obj : C → E
map✝¹ : {X Y : C} → (X ⟶ Y) → (F_obj X ⟶ F_obj Y)
map_id✝¹ : ∀ (X : C), { obj := F_obj, map := map✝¹ }.map (𝟙 X) = 𝟙 ({ obj := F_obj, map := map✝¹ }.obj X)
map_comp✝¹ :
  ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := F_obj, map := map✝¹ }.map (f ≫ g) =
      { obj := F_obj, map := map✝¹ }.map f ≫ { obj := F_obj, map := map✝¹ }.map g
inst✝¹ : Faithful (Functor.mk { obj := F_obj, map := map✝¹ })
G_obj : D → E
map✝ : {X Y : D} → (X ⟶ Y) → (G_obj X ⟶ G_obj Y)
map_id✝ : ∀ (X : D), { obj := G_obj, map := map✝ }.map (𝟙 X) = 𝟙 ({ obj := G_obj, map := map✝ }.obj X)
map_comp✝ :
  ∀ {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj, map := map✝ }.map (f ≫ g) =
      { obj := G_obj, map := map✝ }.map f ≫ { obj := G_obj, map := map✝ }.map g
inst✝ : Faithful (Functor.mk { obj := G_obj, map := map✝ })
h_obj :
  ∀ (X : C), (Functor.mk { obj := G_obj, map := map✝ }).obj (obj X) = (Functor.mk { obj := F_obj, map := map✝¹ }).obj X
h_map :
  ∀ {X Y : C} {f : X ⟶ Y},
    HEq ((Functor.mk { obj := G_obj, map := map✝ }).map (map f)) ((Functor.mk { obj := F_obj, map := map✝¹ }).map f)
this : F_obj = G_obj ∘ obj
⊢ Functor.mk
      { obj := fun X => (Functor.mk { obj := G_obj, map := map✝ }).obj ((Functor.mk { obj := obj, map := map }).obj X),
        map := fun {X Y} f =>
          (Functor.mk { obj := G_obj, map := map✝ }).map ((Functor.mk { obj := obj, map := map }).map f) } =
    Functor.mk { obj := F_obj, map := map✝¹ }

Next tactic:
subst this
theorem Faithful.div_comp (F : C ⥤ E) [Faithful F] (G : D ⥤ E) [Faithful G] (obj : C → D)
    (h_obj : ∀ X, G.obj (obj X) = F.obj X) (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq (G.map (map f)) (F.map f)) :
    Faithful.div F G obj @h_obj @map @h_map ⋙ G = F := by
  -- Porting note: Have to unfold the structure twice because the first one recovers only the
  -- prefunctor `F_pre`
  cases' F with F_pre _ _; cases' G with G_pre _ _
  cases' F_pre with F_obj _; cases' G_pre with G_obj _
  unfold Faithful.div Functor.comp
  -- Porting note: unable to find the lean4 analogue to `unfold_projs`, works without it
  have : F_obj = G_obj ∘ obj := (funext h_obj).symm
  subst this
  

Proof state:
case mk.mk.mk.mk
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F F' : C ⥤ D
G : D ⥤ E
obj : C → D
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
G_obj : D → E
map✝¹ : {X Y : D} → (X ⟶ Y) → (G_obj X ⟶ G_obj Y)
map_id✝¹ : ∀ (X : D), { obj := G_obj, map := map✝¹ }.map (𝟙 X) = 𝟙 ({ obj := G_obj, map := map✝¹ }.obj X)
map_comp✝¹ :
  ∀ {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj, map := map✝¹ }.map (f ≫ g) =
      { obj := G_obj, map := map✝¹ }.map f ≫ { obj := G_obj, map := map✝¹ }.map g
inst✝¹ : Faithful (Functor.mk { obj := G_obj, map := map✝¹ })
map✝ : {X Y : C} → (X ⟶ Y) → ((G_obj ∘ obj) X ⟶ (G_obj ∘ obj) Y)
map_id✝ : ∀ (X : C), { obj := G_obj ∘ obj, map := map✝ }.map (𝟙 X) = 𝟙 ({ obj := G_obj ∘ obj, map := map✝ }.obj X)
map_comp✝ :
  ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj ∘ obj, map := map✝ }.map (f ≫ g) =
      { obj := G_obj ∘ obj, map := map✝ }.map f ≫ { obj := G_obj ∘ obj, map := map✝ }.map g
inst✝ : Faithful (Functor.mk { obj := G_obj ∘ obj, map := map✝ })
h_obj :
  ∀ (X : C),
    (Functor.mk { obj := G_obj, map := map✝¹ }).obj (obj X) = (Functor.mk { obj := G_obj ∘ obj, map := map✝ }).obj X
h_map :
  ∀ {X Y : C} {f : X ⟶ Y},
    HEq ((Functor.mk { obj := G_obj, map := map✝¹ }).map (map f))
      ((Functor.mk { obj := G_obj ∘ obj, map := map✝ }).map f)
⊢ Functor.mk
      { obj := fun X => (Functor.mk { obj := G_obj, map := map✝¹ }).obj ((Functor.mk { obj := obj, map := map }).obj X),
        map := fun {X Y} f =>
          (Functor.mk { obj := G_obj, map := map✝¹ }).map ((Functor.mk { obj := obj, map := map }).map f) } =
    Functor.mk { obj := G_obj ∘ obj, map := map✝ }

Next tactic:
congr
theorem Faithful.div_comp (F : C ⥤ E) [Faithful F] (G : D ⥤ E) [Faithful G] (obj : C → D)
    (h_obj : ∀ X, G.obj (obj X) = F.obj X) (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq (G.map (map f)) (F.map f)) :
    Faithful.div F G obj @h_obj @map @h_map ⋙ G = F := by
  -- Porting note: Have to unfold the structure twice because the first one recovers only the
  -- prefunctor `F_pre`
  cases' F with F_pre _ _; cases' G with G_pre _ _
  cases' F_pre with F_obj _; cases' G_pre with G_obj _
  unfold Faithful.div Functor.comp
  -- Porting note: unable to find the lean4 analogue to `unfold_projs`, works without it
  have : F_obj = G_obj ∘ obj := (funext h_obj).symm
  subst this
  congr
  

Proof state:
case mk.mk.mk.mk.e_toPrefunctor.e_map
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F F' : C ⥤ D
G : D ⥤ E
obj : C → D
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
G_obj : D → E
map✝¹ : {X Y : D} → (X ⟶ Y) → (G_obj X ⟶ G_obj Y)
map_id✝¹ : ∀ (X : D), { obj := G_obj, map := map✝¹ }.map (𝟙 X) = 𝟙 ({ obj := G_obj, map := map✝¹ }.obj X)
map_comp✝¹ :
  ∀ {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj, map := map✝¹ }.map (f ≫ g) =
      { obj := G_obj, map := map✝¹ }.map f ≫ { obj := G_obj, map := map✝¹ }.map g
inst✝¹ : Faithful (Functor.mk { obj := G_obj, map := map✝¹ })
map✝ : {X Y : C} → (X ⟶ Y) → ((G_obj ∘ obj) X ⟶ (G_obj ∘ obj) Y)
map_id✝ : ∀ (X : C), { obj := G_obj ∘ obj, map := map✝ }.map (𝟙 X) = 𝟙 ({ obj := G_obj ∘ obj, map := map✝ }.obj X)
map_comp✝ :
  ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj ∘ obj, map := map✝ }.map (f ≫ g) =
      { obj := G_obj ∘ obj, map := map✝ }.map f ≫ { obj := G_obj ∘ obj, map := map✝ }.map g
inst✝ : Faithful (Functor.mk { obj := G_obj ∘ obj, map := map✝ })
h_obj :
  ∀ (X : C),
    (Functor.mk { obj := G_obj, map := map✝¹ }).obj (obj X) = (Functor.mk { obj := G_obj ∘ obj, map := map✝ }).obj X
h_map :
  ∀ {X Y : C} {f : X ⟶ Y},
    HEq ((Functor.mk { obj := G_obj, map := map✝¹ }).map (map f))
      ((Functor.mk { obj := G_obj ∘ obj, map := map✝ }).map f)
⊢ (fun {X Y} f => (Functor.mk { obj := G_obj, map := map✝¹ }).map ((Functor.mk { obj := obj, map := map }).map f)) =
    map✝

Next tactic:
simp only [Function.comp_apply, heq_eq_eq] at h_map
theorem Faithful.div_comp (F : C ⥤ E) [Faithful F] (G : D ⥤ E) [Faithful G] (obj : C → D)
    (h_obj : ∀ X, G.obj (obj X) = F.obj X) (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq (G.map (map f)) (F.map f)) :
    Faithful.div F G obj @h_obj @map @h_map ⋙ G = F := by
  -- Porting note: Have to unfold the structure twice because the first one recovers only the
  -- prefunctor `F_pre`
  cases' F with F_pre _ _; cases' G with G_pre _ _
  cases' F_pre with F_obj _; cases' G_pre with G_obj _
  unfold Faithful.div Functor.comp
  -- Porting note: unable to find the lean4 analogue to `unfold_projs`, works without it
  have : F_obj = G_obj ∘ obj := (funext h_obj).symm
  subst this
  congr
  simp only [Function.comp_apply, heq_eq_eq] at h_map
  

Proof state:
case mk.mk.mk.mk.e_toPrefunctor.e_map
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F F' : C ⥤ D
G : D ⥤ E
obj : C → D
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
G_obj : D → E
map✝¹ : {X Y : D} → (X ⟶ Y) → (G_obj X ⟶ G_obj Y)
map_id✝¹ : ∀ (X : D), { obj := G_obj, map := map✝¹ }.map (𝟙 X) = 𝟙 ({ obj := G_obj, map := map✝¹ }.obj X)
map_comp✝¹ :
  ∀ {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj, map := map✝¹ }.map (f ≫ g) =
      { obj := G_obj, map := map✝¹ }.map f ≫ { obj := G_obj, map := map✝¹ }.map g
inst✝¹ : Faithful (Functor.mk { obj := G_obj, map := map✝¹ })
map✝ : {X Y : C} → (X ⟶ Y) → ((G_obj ∘ obj) X ⟶ (G_obj ∘ obj) Y)
map_id✝ : ∀ (X : C), { obj := G_obj ∘ obj, map := map✝ }.map (𝟙 X) = 𝟙 ({ obj := G_obj ∘ obj, map := map✝ }.obj X)
map_comp✝ :
  ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj ∘ obj, map := map✝ }.map (f ≫ g) =
      { obj := G_obj ∘ obj, map := map✝ }.map f ≫ { obj := G_obj ∘ obj, map := map✝ }.map g
inst✝ : Faithful (Functor.mk { obj := G_obj ∘ obj, map := map✝ })
h_obj :
  ∀ (X : C),
    (Functor.mk { obj := G_obj, map := map✝¹ }).obj (obj X) = (Functor.mk { obj := G_obj ∘ obj, map := map✝ }).obj X
h_map✝ :
  ∀ {X Y : C} {f : X ⟶ Y},
    HEq ((Functor.mk { obj := G_obj, map := map✝¹ }).map (map f))
      ((Functor.mk { obj := G_obj ∘ obj, map := map✝ }).map f)
h_map : ∀ {X Y : C} {f : X ⟶ Y}, map✝¹ (map f) = map✝ f
⊢ (fun {X Y} f => (Functor.mk { obj := G_obj, map := map✝¹ }).map ((Functor.mk { obj := obj, map := map }).map f)) =
    map✝

Next tactic:
ext
theorem Faithful.div_comp (F : C ⥤ E) [Faithful F] (G : D ⥤ E) [Faithful G] (obj : C → D)
    (h_obj : ∀ X, G.obj (obj X) = F.obj X) (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq (G.map (map f)) (F.map f)) :
    Faithful.div F G obj @h_obj @map @h_map ⋙ G = F := by
  -- Porting note: Have to unfold the structure twice because the first one recovers only the
  -- prefunctor `F_pre`
  cases' F with F_pre _ _; cases' G with G_pre _ _
  cases' F_pre with F_obj _; cases' G_pre with G_obj _
  unfold Faithful.div Functor.comp
  -- Porting note: unable to find the lean4 analogue to `unfold_projs`, works without it
  have : F_obj = G_obj ∘ obj := (funext h_obj).symm
  subst this
  congr
  simp only [Function.comp_apply, heq_eq_eq] at h_map
  ext
  

Proof state:
case mk.mk.mk.mk.e_toPrefunctor.e_map.h.h.h
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F F' : C ⥤ D
G : D ⥤ E
obj : C → D
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
G_obj : D → E
map✝¹ : {X Y : D} → (X ⟶ Y) → (G_obj X ⟶ G_obj Y)
map_id✝¹ : ∀ (X : D), { obj := G_obj, map := map✝¹ }.map (𝟙 X) = 𝟙 ({ obj := G_obj, map := map✝¹ }.obj X)
map_comp✝¹ :
  ∀ {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj, map := map✝¹ }.map (f ≫ g) =
      { obj := G_obj, map := map✝¹ }.map f ≫ { obj := G_obj, map := map✝¹ }.map g
inst✝¹ : Faithful (Functor.mk { obj := G_obj, map := map✝¹ })
map✝ : {X Y : C} → (X ⟶ Y) → ((G_obj ∘ obj) X ⟶ (G_obj ∘ obj) Y)
map_id✝ : ∀ (X : C), { obj := G_obj ∘ obj, map := map✝ }.map (𝟙 X) = 𝟙 ({ obj := G_obj ∘ obj, map := map✝ }.obj X)
map_comp✝ :
  ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := G_obj ∘ obj, map := map✝ }.map (f ≫ g) =
      { obj := G_obj ∘ obj, map := map✝ }.map f ≫ { obj := G_obj ∘ obj, map := map✝ }.map g
inst✝ : Faithful (Functor.mk { obj := G_obj ∘ obj, map := map✝ })
h_obj :
  ∀ (X : C),
    (Functor.mk { obj := G_obj, map := map✝¹ }).obj (obj X) = (Functor.mk { obj := G_obj ∘ obj, map := map✝ }).obj X
h_map✝ :
  ∀ {X Y : C} {f : X ⟶ Y},
    HEq ((Functor.mk { obj := G_obj, map := map✝¹ }).map (map f))
      ((Functor.mk { obj := G_obj ∘ obj, map := map✝ }).map f)
h_map : ∀ {X Y : C} {f : X ⟶ Y}, map✝¹ (map f) = map✝ f
x✝² x✝¹ : C
x✝ : x✝² ⟶ x✝¹
⊢ (Functor.mk { obj := G_obj, map := map✝¹ }).map ((Functor.mk { obj := obj, map := map }).map x✝) = map✝ x✝

Next tactic:
exact h_map
/-- Given a natural isomorphism between `F ⋙ H` and `G ⋙ H` for a fully faithful functor `H`, we
can 'cancel' it to give a natural iso between `F` and `G`.
-/
def fullyFaithfulCancelRight {F G : C ⥤ D} (H : D ⥤ E) [Full H] [Faithful H]
    (comp_iso : F ⋙ H ≅ G ⋙ H) : F ≅ G :=
  NatIso.ofComponents (fun X => H.preimageIso (comp_iso.app X)) fun f =>
    H.map_injective (by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F✝ F' : C ⥤ D
G✝ : D ⥤ E
F G : C ⥤ D
H : D ⥤ E
inst✝¹ : Full H
inst✝ : Faithful H
comp_iso : F ⋙ H ≅ G ⋙ H
X✝ Y✝ : C
f : X✝ ⟶ Y✝
⊢ H.map (F.map f ≫ ((fun X => Functor.preimageIso H (comp_iso.app X)) Y✝).hom) =
    H.map (((fun X => Functor.preimageIso H (comp_iso.app X)) X✝).hom ≫ G.map f)

Next tactic:
simpa using comp_iso.hom.naturality f
theorem Ideal.IsHomogeneous.isPrime_of_homogeneous_mem_or_mem {I : Ideal A} (hI : I.IsHomogeneous 𝒜)
    (I_ne_top : I ≠ ⊤)
    (homogeneous_mem_or_mem :
      ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I) :
    Ideal.IsPrime I :=
  ⟨I_ne_top, by
    

Proof state:
ι : Type u_1
σ : Type u_2
A : Type u_3
inst✝⁴ : CommRing A
inst✝³ : LinearOrderedCancelAddCommMonoid ι
inst✝² : SetLike σ A
inst✝¹ : AddSubmonoidClass σ A
𝒜 : ι → σ
inst✝ : GradedRing 𝒜
I : Ideal A
hI : IsHomogeneous 𝒜 I
I_ne_top : I ≠ ⊤
homogeneous_mem_or_mem : ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I
⊢ ∀ {x y : A}, x * y ∈ I → x ∈ I ∨ y ∈ I

Next tactic:
intro x y hxy
theorem Ideal.IsHomogeneous.isPrime_of_homogeneous_mem_or_mem {I : Ideal A} (hI : I.IsHomogeneous 𝒜)
    (I_ne_top : I ≠ ⊤)
    (homogeneous_mem_or_mem :
      ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I) :
    Ideal.IsPrime I :=
  ⟨I_ne_top, by
    intro x y hxy
    

Proof state:
ι : Type u_1
σ : Type u_2
A : Type u_3
inst✝⁴ : CommRing A
inst✝³ : LinearOrderedCancelAddCommMonoid ι
inst✝² : SetLike σ A
inst✝¹ : AddSubmonoidClass σ A
𝒜 : ι → σ
inst✝ : GradedRing 𝒜
I : Ideal A
hI : IsHomogeneous 𝒜 I
I_ne_top : I ≠ ⊤
homogeneous_mem_or_mem : ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I
x y : A
hxy : x * y ∈ I
⊢ x ∈ I ∨ y ∈ I

Next tactic:
by_contra! rid
theorem Ideal.IsHomogeneous.isPrime_of_homogeneous_mem_or_mem {I : Ideal A} (hI : I.IsHomogeneous 𝒜)
    (I_ne_top : I ≠ ⊤)
    (homogeneous_mem_or_mem :
      ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I) :
    Ideal.IsPrime I :=
  ⟨I_ne_top, by
    intro x y hxy
    by_contra! rid
    

Proof state:
ι : Type u_1
σ : Type u_2
A : Type u_3
inst✝⁴ : CommRing A
inst✝³ : LinearOrderedCancelAddCommMonoid ι
inst✝² : SetLike σ A
inst✝¹ : AddSubmonoidClass σ A
𝒜 : ι → σ
inst✝ : GradedRing 𝒜
I : Ideal A
hI : IsHomogeneous 𝒜 I
I_ne_top : I ≠ ⊤
homogeneous_mem_or_mem : ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I
x y : A
hxy : x * y ∈ I
rid : x ∉ I ∧ y ∉ I
⊢ False

Next tactic:
obtain ⟨rid₁, rid₂⟩ := rid
theorem Ideal.IsHomogeneous.isPrime_of_homogeneous_mem_or_mem {I : Ideal A} (hI : I.IsHomogeneous 𝒜)
    (I_ne_top : I ≠ ⊤)
    (homogeneous_mem_or_mem :
      ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I) :
    Ideal.IsPrime I :=
  ⟨I_ne_top, by
    intro x y hxy
    by_contra! rid
    obtain ⟨rid₁, rid₂⟩ := rid
    classical
      /-
        The idea of the proof is the following :
        since `x * y ∈ I` and `I` homogeneous, then `proj i (x * y) ∈ I` for any `i : ι`.
        Then consider two sets `{i ∈ x.support | xᵢ ∉ I}` and `{j ∈ y.support | yⱼ ∉ J}`;
        let `max₁, max₂` be the maximum of the two sets, then `proj (max₁ + max₂) (x * y) ∈ I`.
        Then, `proj max₁ x ∉ I` and `proj max₂ j ∉ I`
        but `proj i x ∈ I` for all `max₁ < i` and `proj j y ∈ I` for all `max₂ < j`.
        `  proj (max₁ + max₂) (x * y)`
        `= ∑ {(i, j) ∈ supports | i + j = max₁ + max₂}, xᵢ * yⱼ`
        `= proj max₁ x * proj max₂ y`
        `  + ∑ {(i, j) ∈ supports \ {(max₁, max₂)} | i + j = max₁ + max₂}, xᵢ * yⱼ`.
        This is a contradiction, because both `proj (max₁ + max₂) (x * y) ∈ I` and the sum on the
        right hand side is in `I` however `proj max₁ x * proj max₂ y` is not in `I`.
        -/
      

Proof state:
case intro
ι : Type u_1
σ : Type u_2
A : Type u_3
inst✝⁴ : CommRing A
inst✝³ : LinearOrderedCancelAddCommMonoid ι
inst✝² : SetLike σ A
inst✝¹ : AddSubmonoidClass σ A
𝒜 : ι → σ
inst✝ : GradedRing 𝒜
I : Ideal A
hI : IsHomogeneous 𝒜 I
I_ne_top : I ≠ ⊤
homogeneous_mem_or_mem : ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I
x y : A
hxy : x * y ∈ I
rid₁ : x ∉ I
rid₂ : y ∉ I
⊢ False

Next tactic:
set set₁ := (decompose 𝒜 x).support.filter (fun i => proj 𝒜 i x ∉ I) with set₁_eq
theorem Ideal.IsHomogeneous.isPrime_of_homogeneous_mem_or_mem {I : Ideal A} (hI : I.IsHomogeneous 𝒜)
    (I_ne_top : I ≠ ⊤)
    (homogeneous_mem_or_mem :
      ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I) :
    Ideal.IsPrime I :=
  ⟨I_ne_top, by
    intro x y hxy
    by_contra! rid
    obtain ⟨rid₁, rid₂⟩ := rid
    classical
      /-
        The idea of the proof is the following :
        since `x * y ∈ I` and `I` homogeneous, then `proj i (x * y) ∈ I` for any `i : ι`.
        Then consider two sets `{i ∈ x.support | xᵢ ∉ I}` and `{j ∈ y.support | yⱼ ∉ J}`;
        let `max₁, max₂` be the maximum of the two sets, then `proj (max₁ + max₂) (x * y) ∈ I`.
        Then, `proj max₁ x ∉ I` and `proj max₂ j ∉ I`
        but `proj i x ∈ I` for all `max₁ < i` and `proj j y ∈ I` for all `max₂ < j`.
        `  proj (max₁ + max₂) (x * y)`
        `= ∑ {(i, j) ∈ supports | i + j = max₁ + max₂}, xᵢ * yⱼ`
        `= proj max₁ x * proj max₂ y`
        `  + ∑ {(i, j) ∈ supports \ {(max₁, max₂)} | i + j = max₁ + max₂}, xᵢ * yⱼ`.
        This is a contradiction, because both `proj (max₁ + max₂) (x * y) ∈ I` and the sum on the
        right hand side is in `I` however `proj max₁ x * proj max₂ y` is not in `I`.
        -/
      set set₁ := (decompose 𝒜 x).support.filter (fun i => proj 𝒜 i x ∉ I) with set₁_eq
      

Proof state:
case intro
ι : Type u_1
σ : Type u_2
A : Type u_3
inst✝⁴ : CommRing A
inst✝³ : LinearOrderedCancelAddCommMonoid ι
inst✝² : SetLike σ A
inst✝¹ : AddSubmonoidClass σ A
𝒜 : ι → σ
inst✝ : GradedRing 𝒜
I : Ideal A
hI : IsHomogeneous 𝒜 I
I_ne_top : I ≠ ⊤
homogeneous_mem_or_mem : ∀ {x y : A}, Homogeneous 𝒜 x → Homogeneous 𝒜 y → x * y ∈ I → x ∈ I ∨ y ∈ I
x y : A
hxy : x * y ∈ I
rid₁ : x ∉ I
rid₂ : y ∉ I
set₁ : Finset ι := filter (fun i => (proj 𝒜 i) x ∉ I) (DFinsupp.support ((decompose 𝒜) x))
set₁_eq : set₁ = filter (fun i => (proj 𝒜 i) x ∉ I) (DFinsupp.support ((decompose 𝒜) x))
⊢ False

Next tactic:
set set₂ := (decompose 𝒜 y).support.filter (fun i => proj 𝒜 i y ∉ I) with set₂_eq