/-
Copyright (c) 2017 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Stephen Morgan, Scott Morrison

! This file was ported from Lean 3 source module category_theory.products.bifunctor
! leanprover-community/mathlib commit 1ead22342e1a078bd44744ace999f85756555d35
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.CategoryTheory.Products.Basic

/-!
# Lemmas about functors out of product categories.

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.
-/

open CategoryTheory

namespace CategoryTheory.Bifunctor

universe v₁ v₂ v₃ u₁ u₂ u₃

variable {C : Type u₁} {D : Type u₂} {E : Type u₃}

variable [Category.{v₁} C] [Category.{v₂} D] [Category.{v₃} E]

/- warning: category_theory.bifunctor.map_id -> CategoryTheory.Bifunctor.map_id is a dubious translation:
lean 3 declaration is
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (Y : D), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y))) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) X) (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) Y))) (CategoryTheory.CategoryStruct.id.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y)))
but is expected to have type
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u5 u4, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (Y : D), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y))) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) X) (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) Y))) (CategoryTheory.CategoryStruct.id.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y)))
Case conversion may be inaccurate. Consider using '#align category_theory.bifunctor.map_id CategoryTheory.Bifunctor.map_idₓ'. -/
@[simp]
theorem map_id (F : C × D ⥤ E) (X : C) (Y : D) :
    F.map ((𝟙 X, 𝟙 Y) : (X, Y) ⟶ (X, Y)) = 𝟙 (F.obj (X, Y)) :=
  F.map_id (X, Y)
#align category_theory.bifunctor.map_id CategoryTheory.Bifunctor.map_id

/- warning: category_theory.bifunctor.map_id_comp -> CategoryTheory.Bifunctor.map_id_comp is a dubious translation:
lean 3 declaration is
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (W : C) {X : D} {Y : D} {Z : D} (f : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) X Y) (g : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) Y Z), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W X)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W Z))) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W X) (Prod.mk.{u4, u5} C D W Z) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) W) (CategoryTheory.CategoryStruct.comp.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) Y (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z)) f g))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W X)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W Y)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W Z)) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W X) (Prod.mk.{u4, u5} C D W Y) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) W) f)) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D W Y) (Prod.mk.{u4, u5} C D W Z) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) W) g)))
but is expected to have type
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u5 u4, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (W : C) {X : D} {Y : D} {Z : D} (f : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) X Y) (g : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) Y Z), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W X)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W Z))) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W X) (Prod.mk.{u4, u5} C D W Z) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) W) (CategoryTheory.CategoryStruct.comp.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) Y (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z)) f g))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W X)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W Y)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W Z)) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W X) (Prod.mk.{u4, u5} C D W Y) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W X)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) W) f)) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D W Y) (Prod.mk.{u4, u5} C D W Z) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D W Z))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) W) g)))
Case conversion may be inaccurate. Consider using '#align category_theory.bifunctor.map_id_comp CategoryTheory.Bifunctor.map_id_compₓ'. -/
@[simp]
theorem map_id_comp (F : C × D ⥤ E) (W : C) {X Y Z : D} (f : X ⟶ Y) (g : Y ⟶ Z) :
    F.map ((𝟙 W, f ≫ g) : (W, X) ⟶ (W, Z)) =
      F.map ((𝟙 W, f) : (W, X) ⟶ (W, Y)) ≫ F.map ((𝟙 W, g) : (W, Y) ⟶ (W, Z)) :=
  by rw [← functor.map_comp, prod_comp, category.comp_id]
#align category_theory.bifunctor.map_id_comp CategoryTheory.Bifunctor.map_id_comp

/- warning: category_theory.bifunctor.map_comp_id -> CategoryTheory.Bifunctor.map_comp_id is a dubious translation:
lean 3 declaration is
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (Y : C) (Z : C) (W : D) (f : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) X Y) (g : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) Y Z), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X W)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D Z W))) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X W) (Prod.mk.{u4, u5} C D Z W) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) (CategoryTheory.CategoryStruct.comp.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) Y (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W)) f g) (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) W))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X W)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D Y W)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D Z W)) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X W) (Prod.mk.{u4, u5} C D Y W) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W))) f (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) W))) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D Y W) (Prod.mk.{u4, u5} C D Z W) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) g (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) W))))
but is expected to have type
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u5 u4, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (Y : C) (Z : C) (W : D) (f : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) X Y) (g : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) Y Z), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X W)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D Z W))) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X W) (Prod.mk.{u4, u5} C D Z W) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) (CategoryTheory.CategoryStruct.comp.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) Y (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W)) f g) (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) W))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X W)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D Y W)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D Z W)) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X W) (Prod.mk.{u4, u5} C D Y W) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X W)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W))) f (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) W))) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D Y W) (Prod.mk.{u4, u5} C D Z W) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Y W)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D Z W))) g (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) W))))
Case conversion may be inaccurate. Consider using '#align category_theory.bifunctor.map_comp_id CategoryTheory.Bifunctor.map_comp_idₓ'. -/
@[simp]
theorem map_comp_id (F : C × D ⥤ E) (X Y Z : C) (W : D) (f : X ⟶ Y) (g : Y ⟶ Z) :
    F.map ((f ≫ g, 𝟙 W) : (X, W) ⟶ (Z, W)) =
      F.map ((f, 𝟙 W) : (X, W) ⟶ (Y, W)) ≫ F.map ((g, 𝟙 W) : (Y, W) ⟶ (Z, W)) :=
  by rw [← functor.map_comp, prod_comp, category.comp_id]
#align category_theory.bifunctor.map_comp_id CategoryTheory.Bifunctor.map_comp_id

/- warning: category_theory.bifunctor.diagonal -> CategoryTheory.Bifunctor.diagonal is a dubious translation:
lean 3 declaration is
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (X' : C) (f : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) X X') (Y : D) (Y' : D) (g : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) Y Y'), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X' Y'))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y')) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X' Y')) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y'))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) X) g)) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y') (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y')) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y')) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) f (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) Y')))) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) f g))
but is expected to have type
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u5 u4, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (X' : C) (f : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) X X') (Y : D) (Y' : D) (g : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) Y Y'), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X' Y'))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y')) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X' Y')) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y'))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) X) g)) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y') (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y')) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y')) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) f (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) Y')))) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) f g))
Case conversion may be inaccurate. Consider using '#align category_theory.bifunctor.diagonal CategoryTheory.Bifunctor.diagonalₓ'. -/
@[simp]
theorem diagonal (F : C × D ⥤ E) (X X' : C) (f : X ⟶ X') (Y Y' : D) (g : Y ⟶ Y') :
    F.map ((𝟙 X, g) : (X, Y) ⟶ (X, Y')) ≫ F.map ((f, 𝟙 Y') : (X, Y') ⟶ (X', Y')) =
      F.map ((f, g) : (X, Y) ⟶ (X', Y')) :=
  by rw [← functor.map_comp, prod_comp, category.id_comp, category.comp_id]
#align category_theory.bifunctor.diagonal CategoryTheory.Bifunctor.diagonal

/- warning: category_theory.bifunctor.diagonal' -> CategoryTheory.Bifunctor.diagonal' is a dubious translation:
lean 3 declaration is
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (X' : C) (f : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) X X') (Y : D) (Y' : D) (g : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) Y Y'), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X' Y'))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X' Y)) (CategoryTheory.Functor.obj.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X' Y')) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X' Y) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y))) f (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) Y))) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X' Y) (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) X') g))) (CategoryTheory.Functor.map.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) f g))
but is expected to have type
  forall {C : Type.{u4}} {D : Type.{u5}} {E : Type.{u6}} [_inst_1 : CategoryTheory.Category.{u1, u4} C] [_inst_2 : CategoryTheory.Category.{u2, u5} D] [_inst_3 : CategoryTheory.Category.{u3, u6} E] (F : CategoryTheory.Functor.{max u1 u2, u3, max u5 u4, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3) (X : C) (X' : C) (f : Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) X X') (Y : D) (Y' : D) (g : Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) Y Y'), Eq.{succ u3} (Quiver.Hom.{succ u3, u6} E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X' Y'))) (CategoryTheory.CategoryStruct.comp.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X' Y)) (Prefunctor.obj.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X' Y')) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X' Y) (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y))) f (CategoryTheory.CategoryStruct.id.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2) Y))) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X' Y) (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (CategoryTheory.CategoryStruct.id.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1) X') g))) (Prefunctor.map.{max (succ u1) (succ u2), succ u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.CategoryStruct.toQuiver.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.Category.toCategoryStruct.{max u1 u2, max u4 u5} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2))) E (CategoryTheory.CategoryStruct.toQuiver.{u3, u6} E (CategoryTheory.Category.toCategoryStruct.{u3, u6} E _inst_3)) (CategoryTheory.Functor.toPrefunctor.{max u1 u2, u3, max u4 u5, u6} (Prod.{u4, u5} C D) (CategoryTheory.prod.{u1, u2, u4, u5} C _inst_1 D _inst_2) E _inst_3 F) (Prod.mk.{u4, u5} C D X Y) (Prod.mk.{u4, u5} C D X' Y') (Prod.mk.{u1, u2} (Quiver.Hom.{succ u1, u4} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u4} C (CategoryTheory.Category.toCategoryStruct.{u1, u4} C _inst_1)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.fst.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) (Quiver.Hom.{succ u2, u5} D (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} D (CategoryTheory.Category.toCategoryStruct.{u2, u5} D _inst_2)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X Y)) (Prod.snd.{u4, u5} C D (Prod.mk.{u4, u5} C D X' Y'))) f g))
Case conversion may be inaccurate. Consider using '#align category_theory.bifunctor.diagonal' CategoryTheory.Bifunctor.diagonal'ₓ'. -/
@[simp]
theorem diagonal' (F : C × D ⥤ E) (X X' : C) (f : X ⟶ X') (Y Y' : D) (g : Y ⟶ Y') :
    F.map ((f, 𝟙 Y) : (X, Y) ⟶ (X', Y)) ≫ F.map ((𝟙 X', g) : (X', Y) ⟶ (X', Y')) =
      F.map ((f, g) : (X, Y) ⟶ (X', Y')) :=
  by rw [← functor.map_comp, prod_comp, category.id_comp, category.comp_id]
#align category_theory.bifunctor.diagonal' CategoryTheory.Bifunctor.diagonal'

end CategoryTheory.Bifunctor


/-

Some goals:
  - Define matroid.
  - Define duality.
  - Define minors, deletion, contraction.
  - Prove that disjoint deletions and contractions commute.
  - Prove that dual of a minor is a minor of the dual.

Some things that are needed:
  - Finite sets, size.
  - Union, intersection, complement of finite subsets.

Paying special attention to:
  - When are things (propositionally) equal.

-/

import tactic.ext
import tactic.ring
import tactic.linarith

-- The API for finite boolean algebras (now moved)

import boolalg
import func_heq

/-

  --(inter_subset_right (X Y : subset) : contained (inter X Y) Y)

lemma boolalg.inter_subset_right {A: boolalg} (X Y : A) : (X ∩ Y) ⊆ Y := sorry
lemma boolalg.subset_inter {A: boolalg} (X Y Z : A) : (Z ⊆ X) → (Z ⊆ Y) → ((X ∩ Y) ⊆ Z) := sorry

def finite_set : Type := sorry
def finite_set.subset : finite_set → Type := sorry
def finite_set.subset.size {γ : finite_set} : γ.subset → ℤ := sorry
instance has_subset_finite_set_subset {γ : finite_set} : has_subset γ.subset := sorry
instance has_inter_finite_set_subset {γ : finite_set} : has_inter γ.subset := sorry
instance has_union_finite_set_subset {γ : finite_set} : has_union γ.subset := sorry
instance has_compl_finite_set_subset {γ : finite_set} : has_compl γ.subset := sorry
instance has_top_finite_set_subset {γ : finite_set} : has_top γ.subset := sorry
instance has_bot_finite_set_subset {γ : finite_set} : has_bot γ.subset := sorry

@[trans] lemma finite_set.subset.trans {γ : finite_set} {X Y Z : γ.subset} :
  (X ⊆ Y) → (Y ⊆ Z) → (X ⊆ Z) := sorry

def finite_set.canonical (size : ℤ) :
  (0 ≤ size) → finite_set := sorry

def finite_set.subset.as_finite_set {γ : finite_set} :
  γ.subset → finite_set := sorry

def finite_set.subset.as_finite_set.injective {γ : finite_set} {X Y : γ.subset} :
  (X.as_finite_set = Y.as_finite_set) → (X = Y) := sorry

def finite_set.subset.embed {γ : finite_set} (X : γ.subset) :
  X.as_finite_set.subset → γ.subset := sorry

def finite_set.subset.restrict {γ : finite_set} (X Y : γ.subset) :
  (X ⊆ Y) → Y.as_finite_set.subset := sorry

lemma finite_set.subset.embed_subset {γ : finite_set} (X : γ.subset) (Y : X.as_finite_set.subset) :
  (X.embed Y) ⊆ X := sorry

lemma finite_set.subset.subset_embed {γ : finite_set} (X : γ.subset) (Y Z : X.as_finite_set.subset) :
  (Y ⊆ Z) → (X.embed Y) ⊆ (X.embed Z) := sorry

lemma finite_set.subset.inter_embed {γ : finite_set} (X : γ.subset) (Y Z : X.as_finite_set.subset) :
  (X.embed (Y ∩ Z)) = (X.embed Y) ∩ (X.embed Z) := sorry

lemma finite_set.subset.union_embed {γ : finite_set} (X : γ.subset) (Y Z : X.as_finite_set.subset) :
  (X.embed (Y ∪ Z)) = (X.embed Y) ∪ (X.embed Z) := sorry

lemma finite_set.subset.embed_size {γ : finite_set} (X : γ.subset) (Y : X.as_finite_set.subset) :
  (X.embed Y).size = Y.size := sorry

lemma finite_set.subset.size_empty {γ : finite_set} :
  (⊥ : γ.subset).size = 0 := sorry

lemma finite_set.subset.size_nonneg {γ : finite_set} (X : γ.subset) :
  0 ≤ X.size := sorry

lemma finite_set.subset.size_monotone {γ : finite_set} (X Y : γ.subset) :
  (X ⊆ Y) → X.size ≤ Y.size := sorry

lemma finite_set.subset.size_modular {γ : finite_set} (X Y : γ.subset) :
  (X ∩ Y).size + (X ∪ Y).size = X.size + Y.size := sorry

lemma finite_set.subset.inter_subset_left {γ : finite_set} (X Y : γ.subset) :
  (X ∩ Y) ⊆ X := sorry

lemma finite_set.subset.inter_subset_right {γ : finite_set} (X Y : γ.subset) :
  (X ∩ Y) ⊆ Y := sorry

lemma finite_set.subset.left_subset_union {γ : finite_set} (X Y : γ.subset) :
  X ⊆ (X ∪ Y) := sorry

lemma finite_set.subset.right_subset_union {γ : finite_set} (X Y : γ.subset) :
  Y ⊆ (X ∪ Y) := sorry

lemma finite_set.subset.inter_compl_self {γ : finite_set} (X : γ.subset) :
  (X ∩ Xᶜ) = ⊥ := sorry

lemma finite_set.subset.union_compl_self {γ : finite_set} (X : γ.subset) :
  (X ∪ Xᶜ) = ⊤ := sorry

lemma finite_set.subset.subset_top {γ : finite_set} (X : γ.subset) :
  X ⊆ ⊤ := calc X ⊆ (X ∪ Xᶜ) : X.left_subset_union Xᶜ ... = ⊤ : X.union_compl

lemma finite_set.subset.compl_inter {γ : finite_set} (X Y : γ.subset) :
  (X ∩ Y)ᶜ = Xᶜ ∪ Yᶜ := sorry

lemma finite_set.subset.compl_union {γ : finite_set} (X Y : γ.subset) :
  (X ∪ Y)ᶜ = Xᶜ ∩ Yᶜ := sorry

lemma finite_set.subset.inter_assoc {γ : finite_set} (X Y Z : γ.subset) :
  (X ∩ Y) ∩ Z = X ∩ (Y ∩ Z) := sorry

lemma finite_set.subset.inter_bot {γ : finite_set} (X : γ.subset) :
  (X ∩ ⊥) = ⊥ := sorry

lemma finite_set.subset.inter_top {γ : finite_set} (X : γ.subset) :
  (X ∩ ⊤) = X := sorry

lemma finite_set.subset.union_distrib_inter_left {γ : finite_set} (X Y Z : γ.subset) :
  (X ∩ Y) ∪ Z = (X ∪ Z) ∩ (Y ∪ Z) := sorry

lemma finite_set.subset.union_distrib_union_left {γ : finite_set} (X Y Z : γ.subset) :
  (X ∪ Y) ∪ Z = (X ∪ Z) ∪ (Y ∪ Z) := sorry

lemma finite_set.subset.inter_eq_left {γ : finite_set} (X Y : γ.subset) :
  (X ⊆ Y) → (X ∩ Y) = X := sorry

lemma finite_set.subset.diff_size {γ : finite_set} (X Y : γ.subset) :
  (X ⊆ Y) → (Xᶜ ∩ Y).size = Y.size - X.size := sorry

lemma finite_set.subset.subset_inter_subset_left {γ : finite_set} (X Y Z : γ.subset) :
  (X ⊆ Y) → (X ∩ Z) ⊆ (Y ∩ Z) := sorry

lemma finite_set.subset.subset_union_subset_left {γ : finite_set} (X Y Z : γ.subset) :
  (X ⊆ Y) → (X ∪ Z) ⊆ (Y ∪ Z) := sorry

lemma finite_set.subset.subset_bot {γ : finite_set} (X : γ.subset) :
  (X ⊆ ⊥) → (X = ⊥) := sorry

end API

-/
namespace boolalg
-- The rank-function definition of a matroid, as a packed structure.
@[ext] structure matroid :=
  (A : boolalg)
  (rank : A → ℤ)

  (R0 : forall (X : A),
    0 ≤ rank X)
  (R1 : forall (X : A),
    rank X ≤ size X)
  (R2 : forall {X Y : A},
    X ⊆ Y → rank X ≤ rank Y)
  (R3 : forall (X Y : A),
    rank (X ∩ Y) + rank (X ∪ Y) ≤ rank X + rank Y)

-- An example: uniform matroids, with rank `k` and size `n`.
def uniform_matroid (k n : ℤ) : (0 ≤ k) → (k ≤ n) → matroid :=
  fun (h0k : 0 ≤ k) (hkn : k ≤ n), let
    A : boolalg := boolalg.canonical n (le_trans h0k hkn)
  in {
    A := A,
    rank := (fun (X : A), min k (size X)),

    R0 := (fun X, le_min h0k (size_nonneg X)),
    R1 := (fun X, min_le_right _ _),
    R2 := (fun X Y (h : X ⊆ Y), le_min (min_le_left k _) (le_trans (min_le_right _ (size X)) (size_monotone h))),
    R3 := (fun X Y, or.elim (le_total k (size X))
      (fun (hkX : k ≤ size X), or.elim (le_total k (size Y))
        (fun (hkY : k ≤ (size Y)), let
          term1 : (min k (size (X ∩ Y)) ) ≤ k := min_le_left _ _,
          term2 : (min k (size (X ∪ Y)) ) ≤ k := min_le_left _ _,
          term3 : (min k (size X)) = k := min_eq_left hkX,
          term4 : (min k (size Y)) = k := min_eq_left hkY
          in by linarith)
        (fun (hYk : (size Y) ≤ k), let
          term1 : (min k (size (X ∩ Y))) ≤ (size Y) := le_trans (min_le_right _ _) (size_monotone (inter_subset_right X Y)),
          term2 : (min k (size (X ∪ Y))) ≤ k := min_le_left _ _,
          term3 : (min k (size X)) = k := min_eq_left hkX,
          term4 : (min k (size Y)) = (size Y) := min_eq_right hYk
          in by linarith))
      (fun (hXk : (size X) ≤ k), or.elim (le_total k (size Y))
        (fun (hkY : k ≤ (size Y)), let
          term1 : (min k (size (X ∩ Y))) ≤ (size X) := le_trans (min_le_right _ _) (size_monotone (inter_subset_left X Y)),
          term2 : (min k (size (X ∪ Y))) ≤ k := min_le_left _ _,
          term3 : (min k (size X)) = (size X) := min_eq_right hXk,
          term4 : (min k (size Y)) = k := min_eq_left hkY
          in by linarith)
        (fun (hYk : size Y ≤ k), let
          term1 : (min k (size (X ∩ Y))) ≤ size (X ∩ Y) := min_le_right _ _,
          term2 : (min k (size (X ∪ Y))) ≤ size (X ∪ Y) := min_le_right _ _,
          term3 : (min k (size X)) = size X := min_eq_right hXk,
          term4 : (min k (size Y)) = size Y := min_eq_right hYk,
          term5 : size (X ∪ Y) + size (X ∩ Y) = size X + size Y := size_modular X Y
          in by linarith))),
  }

-- The empty set always has rank zero.
lemma matroid.rank_empty (M : matroid) :
  M.rank ⊥ = 0
    := le_antisymm (calc M.rank ⊥ ≤ size (⊥ : M.A) : M.R1 ⊥ ... = 0 : size_bot M.A) (M.R0 ⊥)

-- The definition of the dual matroid. R2 is the trickier axiom to prove.
def matroid.dual (M : matroid) : matroid :=
{
  A := M.A,
  rank := (fun (X : M.A), M.rank Xᶜ + (size X) - M.rank ⊤),

  R0 := (fun X, calc
    0   ≤ M.rank Xᶜ + M.rank X - M.rank (X ∪ Xᶜ) - M.rank (X ∩ Xᶜ) : by linarith [M.R3 X Xᶜ]
    ... ≤ M.rank Xᶜ + M.rank X - M.rank ⊤        - M.rank ⊥        : by rw [union_compl_self X, inter_compl_self X]
    ... ≤ M.rank Xᶜ + (size X)  - M.rank ⊤                         : by linarith [M.R1 X, M.rank_empty]),
  R1 := (fun X, by linarith [M.R2 (subset_top Xᶜ)]),
  R2 := (fun X Y (hXY : X ⊆ Y), let
    h₁ : (Xᶜ ∩ Y) ∩ Yᶜ = ⊥ := calc
      (Xᶜ ∩ Y) ∩ Yᶜ = Xᶜ ∩ (Y ∩ Yᶜ) : inter_assoc Xᶜ Y Yᶜ
      ...           = Xᶜ ∩ ⊥        : by rw [inter_compl_self Y]
      ...           = ⊥             : inter_bot Xᶜ,
    h₂ : (Xᶜ ∪ Yᶜ) = Xᶜ := calc
      (Xᶜ ∪ Yᶜ) = (X ∩ Y)ᶜ : (compl_inter X Y).symm
      ...       = Xᶜ       : by rw [inter_subset_mp hXY],
    h₃ : (Xᶜ ∩ Y) ∪ Yᶜ = Xᶜ := calc
      (Xᶜ ∩ Y) ∪ Yᶜ = (Xᶜ ∪ Yᶜ) ∩ (Y ∪ Yᶜ) : union_distrib_right Xᶜ Y Yᶜ --Xᶜ.union_distrib_inter_left Y Yᶜ
      ...           = Xᶜ ∩ ⊤               : by rw [h₂, union_compl_self Y]
      ...           = Xᶜ                   : inter_top Xᶜ,
    h₄ : M.rank Xᶜ ≤ size Y - size X + M.rank Yᶜ := calc
      M.rank Xᶜ = M.rank ⊥ + M.rank Xᶜ                            : by linarith [M.rank_empty]
      ...       = M.rank ((Xᶜ ∩ Y) ∩ Yᶜ) + M.rank ((Xᶜ ∩ Y) ∪ Yᶜ) : by rw [h₁, h₃]
      ...       ≤ M.rank (Xᶜ ∩ Y) + M.rank Yᶜ                     : M.R3 _ _
      ...       ≤ size (Xᶜ ∩ Y) + M.rank Yᶜ                       : by linarith [M.R1 (Xᶜ ∩ Y)]
      ...       = size Y - size X + M.rank Yᶜ                     : by rw [compl_inter_size_subset hXY]
    in by linarith),
  R3 := (fun X Y, calc
      (M.rank (X ∩ Y)ᶜ  + size (X ∩ Y) - M.rank ⊤) + (M.rank (X ∪ Y)ᶜ  + size (X ∪ Y) - M.rank ⊤)
    = (M.rank (Xᶜ ∪ Yᶜ) + size (X ∩ Y) - M.rank ⊤) + (M.rank (Xᶜ ∩ Yᶜ) + size (X ∪ Y) - M.rank ⊤) : by rw [compl_inter X Y, compl_union X Y]
... ≤ (M.rank Xᶜ        + size X       - M.rank ⊤) + (M.rank Yᶜ        + size Y       - M.rank ⊤) : by linarith [M.R3 Xᶜ Yᶜ, size_modular X Y]),
}

lemma rank_bot (M : matroid) :
  M.rank ⊥ = 0 :=
  by linarith[M.R0 ⊥, M.R1 ⊥, size_bot M.A]

lemma dual_dual (M : matroid) : M.dual.dual = M :=
begin
    ext, refl, refl,
    intros X X' hXX',
    apply heq_of_eq, rw ←(eq_of_heq hXX'),

    calc M.dual.dual.rank X = M.dual.rank Xᶜ + size X - M.dual.rank ⊤                                                 : rfl
    ...                     = (M.rank Xᶜᶜ + size Xᶜ - M.rank ⊤) + size X - (M.rank ⊤ᶜ + size (⊤ : M.A) - M.rank ⊤)   : rfl
    ...                     = M.rank Xᶜᶜ + (size X + size Xᶜ - size (⊤ : M.A)) - (M.rank ⊤ᶜ)                          : by linarith
    ...                     = M.rank X + (size (⊤ : M.A) - size (⊤ : M.A)) - M.rank ⊥                                 : by rw [compl_compl, size_compl_sum, compl_top]
    ...                     = M.rank X                                                                                : by linarith [rank_bot M]
end

-- The definition of a minor is weird-looking, but should correctly capture the notion of equality of minors.

/- This definition works in the sense that proofs below are sorry-free, but the problem is now that
it doesn't capture equality correctly; it allows multiple 'versions' of the same minor of M to be
propositionally distinct, both before and after as_matroid is applied. Changing the data in the minor
back to just including ground set and rank function solves this problem, but causes ugliness elsewhere. I
want to be able to insist that the embedding is the inclusion map, but I don't see how to make the inclusion
map canonical in type theory -/

@[ext] structure minor (M : matroid) :=
  (m_A : boolalg)
  (m_rank   : m_A → ℤ)
  (kernel : exists (C : M.A) (emb : boolalg.embedding m_A M.A),
    (emb.func (⊥ : m_A) = ⊥) ∧
    (emb.func (⊤ : m_A) ∩ C = ⊥) ∧
    (forall X, m_rank X = M.rank (emb.func X ∪ C) - M.rank C))

-- A matroid minor is a matroid in its own right.
def minor.as_matroid {M : matroid} (m : minor M) : matroid :=
{
  A := m.m_A,
  rank := m.m_rank,

  R0 := by intros X; rcases m.kernel with ⟨C,emb,⟨h0,hC,hr⟩⟩; linarith [M.R2 (subset_union_right (emb.func X) C), hr X],

  R1 :=
  begin
    intros X, rcases m.kernel with ⟨C,emb,⟨h0,hC,hr⟩⟩,
    linarith [bot_to_bot_embedding_size emb h0 X, M.R0 (emb.func X ∩ C), M.R3 (emb.func X) C, M.R1 (emb.func X), hr X],
  end,
  R2 :=
  begin
    intros X Y hXY, rcases m.kernel with ⟨C,emb,⟨h0,hC,hCr⟩⟩,
    linarith [M.R2 (subset_union_subset_left (emb.func X) (emb.func Y) C (embedding_on_subset emb hXY )), hCr X, hCr Y],
  end,
  R3 :=
  begin
    intros X Y, rcases m.kernel with ⟨C,emb,⟨h0,hC,hCr⟩⟩,
    let f := emb.func,
    have hu : (f X ∪ C) ∪ (f Y ∪ C) = f (X ∪ Y) ∪ C := by rw ←union_distrib_union_left; rw ←emb.on_union,
    have hi : (f X ∪ C) ∩ (f Y ∪ C) = f (X ∩ Y) ∪ C := by rw ←union_distrib_left; rw ←emb.on_inter,
    have hR3 := M.R3 (f X ∪ C) (f Y ∪ C),
    rw [hu, hi] at hR3,
    linarith [hCr X, hCr Y, hCr (X ∪ Y), hCr (X ∩ Y), hR3],
  end,
}

-- Is this possible to prove? Mathematically it should be.

-- Yes, it is! I'm not happy with the proof, though...
lemma minor.as_matroid.injective {M : matroid} (m₁ m₂ : minor M) :
  (m₁.as_matroid = m₂.as_matroid) → m₁ = m₂ :=
  begin
    intros hmm,

    have h : m₁.m_A = m₂.m_A :=
      by calc m₁.m_A = m₁.as_matroid.A : rfl
               ...   = m₂.as_matroid.A : by rw hmm
               ...   = m₂.m_A            : rfl,

    injections_and_clear,
    ext, exact h, rw h, intros a a' haa', apply heq_of_eq,
    apply congr_heq, exact h_2, exact haa',
  end

end boolalg

/-def minor.delete {M : matroid} (m : minor M) (D : M.ground.subset) :
  (D ⊆ m.ground) → (minor M) := fun h, {
    ground := (Dᶜ ∩ m.ground),
    rank := sorry,
    kernel := sorry,
  }

def minor.contract {M : matroid} (m : minor M) (C : M.ground.subset) :
  (C ⊆ m.ground) → (minor M) := fun h, {
    ground := (Cᶜ ∩ m.ground),
    rank := sorry,
    kernel := sorry,
  }-/


/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/

/-!
# Extra definitions on `option`

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

This file defines more operations involving `option α`. Lemmas about them are located in other
files under `data.option.`.
Other basic operations on `option` are defined in the core library.
-/

namespace option
variables {α : Type*} {β : Type*}

attribute [inline] option.is_some option.is_none

/-- An elimination principle for `option`. It is a nondependent version of `option.rec`. -/
@[simp] protected def elim (b : β) (f : α → β) : option α → β
| (some a) := f a
| none     := b

instance has_mem : has_mem α (option α) := ⟨λ a b, b = some a⟩

@[simp] theorem mem_def {a : α} {b : option α} : a ∈ b ↔ b = some a :=
iff.rfl

lemma mem_iff {a : α} {b : option α} : a ∈ b ↔ b = a := iff.rfl

theorem is_none_iff_eq_none {o : option α} : o.is_none = tt ↔ o = none :=
⟨option.eq_none_of_is_none, λ e, e.symm ▸ rfl⟩

theorem some_inj {a b : α} : some a = some b ↔ a = b := by simp

lemma mem_some_iff {α : Type*} {a b : α} : a ∈ some b ↔ b = a :=
by simp

/--
`o = none` is decidable even if the wrapped type does not have decidable equality.

This is not an instance because it is not definitionally equal to `option.decidable_eq`.
Try to use `o.is_none` or `o.is_some` instead.
-/
@[inline]
def decidable_eq_none {o : option α} : decidable (o = none) :=
decidable_of_decidable_of_iff (bool.decidable_eq _ _) is_none_iff_eq_none

instance decidable_forall_mem {p : α → Prop} [decidable_pred p] :
  ∀ o : option α, decidable (∀ a ∈ o, p a)
| none     := is_true (by simp [false_implies_iff])
| (some a) := if h : p a
  then is_true $ λ o e, some_inj.1 e ▸ h
  else is_false $ mt (λ H, H _ rfl) h

instance decidable_exists_mem {p : α → Prop} [decidable_pred p] :
  ∀ o : option α, decidable (∃ a ∈ o, p a)
| none     := is_false (λ ⟨a, ⟨h, _⟩⟩, by cases h)
| (some a) := if h : p a
  then is_true $ ⟨_, rfl, h⟩
  else is_false $ λ ⟨_, ⟨rfl, hn⟩⟩, h hn

/-- Inhabited `get` function. Returns `a` if the input is `some a`, otherwise returns `default`. -/
@[reducible] def iget [inhabited α] : option α → α
| (some x) := x
| none     := default

@[simp] theorem iget_some [inhabited α] {a : α} : (some a).iget = a := rfl

/-- `guard p a` returns `some a` if `p a` holds, otherwise `none`. -/
def guard (p : α → Prop) [decidable_pred p] (a : α) : option α :=
if p a then some a else none

/-- `filter p o` returns `some a` if `o` is `some a` and `p a` holds, otherwise `none`. -/
def filter (p : α → Prop) [decidable_pred p] (o : option α) : option α :=
o.bind (guard p)

/-- Cast of `option` to `list `. Returns `[a]` if the input is `some a`, and `[]` if it is
`none`. -/
def to_list : option α → list α
| none     := []
| (some a) := [a]

@[simp] theorem mem_to_list {a : α} {o : option α} : a ∈ to_list o ↔ a ∈ o :=
by cases o; simp [to_list, eq_comm]

/-- Two arguments failsafe function. Returns `f a b` if the inputs are `some a` and `some b`, and
"does nothing" otherwise. -/
def lift_or_get (f : α → α → α) : option α → option α → option α
| none     none     := none
| (some a) none     := some a       -- get a
| none     (some b) := some b       -- get b
| (some a) (some b) := some (f a b) -- lift f

instance lift_or_get_comm (f : α → α → α) [h : is_commutative α f] :
  is_commutative (option α) (lift_or_get f) :=
⟨λ a b, by cases a; cases b; simp [lift_or_get, h.comm]⟩

instance lift_or_get_assoc (f : α → α → α) [h : is_associative α f] :
  is_associative (option α) (lift_or_get f) :=
⟨λ a b c, by cases a; cases b; cases c; simp [lift_or_get, h.assoc]⟩

instance lift_or_get_idem (f : α → α → α) [h : is_idempotent α f] :
  is_idempotent (option α) (lift_or_get f) :=
⟨λ a, by cases a; simp [lift_or_get, h.idempotent]⟩

instance lift_or_get_is_left_id (f : α → α → α) :
  is_left_id (option α) (lift_or_get f) none :=
⟨λ a, by cases a; simp [lift_or_get]⟩

instance lift_or_get_is_right_id (f : α → α → α) :
  is_right_id (option α) (lift_or_get f) none :=
⟨λ a, by cases a; simp [lift_or_get]⟩

/-- Lifts a relation `α → β → Prop` to a relation `option α → option β → Prop` by just adding
`none ~ none`. -/
inductive rel (r : α → β → Prop) : option α → option β → Prop
/-- If `a ~ b`, then `some a ~ some b` -/
| some {a b} : r a b → rel (some a) (some b)
/-- `none ~ none` -/
| none       : rel none none

/-- Partial bind. If for some `x : option α`, `f : Π (a : α), a ∈ x → option β` is a
  partial function defined on `a : α` giving an `option β`, where `some a = x`,
  then `pbind x f h` is essentially the same as `bind x f`
  but is defined only when all `x = some a`, using the proof to apply `f`. -/
@[simp] def pbind : Π (x : option α), (Π (a : α), a ∈ x → option β) → option β
| none     _ := none
| (some a) f := f a rfl

/-- Partial map. If `f : Π a, p a → β` is a partial function defined on `a : α` satisfying `p`,
then `pmap f x h` is essentially the same as `map f x` but is defined only when all members of `x`
satisfy `p`, using the proof to apply `f`. -/
@[simp] def pmap {p : α → Prop} (f : Π (a : α), p a → β) :
  Π x : option α, (∀ a ∈ x, p a) → option β
| none     _ := none
| (some a) H := some (f a (H a (mem_def.mpr rfl)))

/-- Flatten an `option` of `option`, a specialization of `mjoin`. -/
@[simp] def join : option (option α) → option α :=
λ x, bind x id

protected def {u v} traverse {F : Type u → Type v} [applicative F] {α β : Type*} (f : α → F β) :
  option α → F (option β)
| none     := pure none
| (some x) := some <$> f x

/- By analogy with `monad.sequence` in `init/category/combinators.lean`. -/

/-- If you maybe have a monadic computation in a `[monad m]` which produces a term of type `α`, then
there is a naturally associated way to always perform a computation in `m` which maybe produces a
result. -/
def {u v} maybe {m : Type u → Type v} [monad m] {α : Type u} : option (m α) → m (option α)
| none      := return none
| (some fn) := some <$> fn

/-- Map a monadic function `f : α → m β` over an `o : option α`, maybe producing a result. -/
def {u v w} mmap {m : Type u → Type v} [monad m] {α : Type w} {β : Type u} (f : α → m β)
  (o : option α) : m (option β) := (o.map f).maybe

/-- A monadic analogue of `option.elim`. -/
def melim {α β : Type*} {m : Type* → Type*} [monad m] (y : m β) (z : α → m β) (x : m (option α)) :
  m β :=
x >>= option.elim y z

/-- A monadic analogue of `option.get_or_else`. -/
def mget_or_else {α : Type*} {m : Type* → Type*} [monad m] (x : m (option α)) (y : m α) : m α :=
melim y pure x

end option


import algebra.big_operators

universes u v w
variables {α : Type u} {β : Type v} {γ : Type w}

namespace finset
variables {s s₁ s₂ : finset α} {a : α} {f g : α → β}

section comm_monoid
variables [comm_monoid β]

@[to_additive finset.sum_filter']
lemma prod_filter' [decidable_eq β] (s : finset α) (f : α → β) :
  finset.prod (finset.filter (λ (x : α), f x ≠ 1) s) f = finset.prod s f :=
finset.prod_subset (finset.filter_subset s)
    (λ x hx₁ hx₂, not_not.1 (λ h, hx₂ (finset.mem_filter.2 ⟨hx₁, h⟩)))

end comm_monoid
end finset


/-
Copyright (c) 2022 Yaël Dillies. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies
-/
import order.hom.basic
import order.bounded_order

/-!
# Bounded order homomorphisms

This file defines (bounded) order homomorphisms.

We use the `fun_like` design, so each type of morphisms has a companion typeclass which is meant to
be satisfied by itself and all stricter types.

## Types of morphisms

* `top_hom`: Maps which preserve `⊤`.
* `bot_hom`: Maps which preserve `⊥`.
* `bounded_order_hom`: Bounded order homomorphisms. Monotone maps which preserve `⊤` and `⊥`.

## Typeclasses

* `top_hom_class`
* `bot_hom_class`
* `bounded_order_hom_class`
-/

open function order_dual

variables {F α β γ δ : Type*}

/-- The type of `⊤`-preserving functions from `α` to `β`. -/
structure top_hom (α β : Type*) [has_top α] [has_top β] :=
(to_fun   : α → β)
(map_top' : to_fun ⊤ = ⊤)

/-- The type of `⊥`-preserving functions from `α` to `β`. -/
structure bot_hom (α β : Type*) [has_bot α] [has_bot β] :=
(to_fun   : α → β)
(map_bot' : to_fun ⊥ = ⊥)

/-- The type of bounded order homomorphisms from `α` to `β`. -/
structure bounded_order_hom (α β : Type*) [preorder α] [preorder β] [bounded_order α]
  [bounded_order β]
  extends order_hom α β :=
(map_top' : to_fun ⊤ = ⊤)
(map_bot' : to_fun ⊥ = ⊥)

/-- `top_hom_class F α β` states that `F` is a type of `⊤`-preserving morphisms.

You should extend this class when you extend `top_hom`. -/
class top_hom_class (F : Type*) (α β : out_param $ Type*) [has_top α] [has_top β]
  extends fun_like F α (λ _, β) :=
(map_top (f : F) : f ⊤ = ⊤)

/-- `bot_hom_class F α β` states that `F` is a type of `⊥`-preserving morphisms.

You should extend this class when you extend `bot_hom`. -/
class bot_hom_class (F : Type*) (α β : out_param $ Type*) [has_bot α] [has_bot β]
  extends fun_like F α (λ _, β) :=
(map_bot (f : F) : f ⊥ = ⊥)

/-- `bounded_order_hom_class F α β` states that `F` is a type of bounded order morphisms.

You should extend this class when you extend `bounded_order_hom`. -/
class bounded_order_hom_class (F : Type*) (α β : out_param $ Type*) [has_le α] [has_le β]
  [bounded_order α] [bounded_order β]
  extends rel_hom_class F ((≤) : α → α → Prop) ((≤) : β → β → Prop) :=
(map_top (f : F) : f ⊤ = ⊤)
(map_bot (f : F) : f ⊥ = ⊥)

export top_hom_class (map_top) bot_hom_class (map_bot)

attribute [simp] map_top map_bot

@[priority 100] -- See note [lower instance priority]
instance bounded_order_hom_class.to_top_hom_class [has_le α] [has_le β]
  [bounded_order α] [bounded_order β] [bounded_order_hom_class F α β] :
  top_hom_class F α β :=
{ .. ‹bounded_order_hom_class F α β› }

@[priority 100] -- See note [lower instance priority]
instance bounded_order_hom_class.to_bot_hom_class [has_le α] [has_le β]
  [bounded_order α] [bounded_order β] [bounded_order_hom_class F α β] :
  bot_hom_class F α β :=
{ .. ‹bounded_order_hom_class F α β› }

@[priority 100] -- See note [lower instance priority]
instance order_iso_class.to_top_hom_class [has_le α] [order_top α] [partial_order β] [order_top β]
  [order_iso_class F α β] :
  top_hom_class F α β :=
⟨λ f, top_le_iff.1 $ (map_inv_le_iff f).1 le_top⟩

@[priority 100] -- See note [lower instance priority]
instance order_iso_class.to_bot_hom_class [has_le α] [order_bot α] [partial_order β] [order_bot β]
  [order_iso_class F α β] :
  bot_hom_class F α β :=
⟨λ f, le_bot_iff.1 $ (le_map_inv_iff f).1 bot_le⟩

@[priority 100] -- See note [lower instance priority]
instance order_iso_class.to_bounded_order_hom_class [has_le α] [bounded_order α] [partial_order β]
  [bounded_order β] [order_iso_class F α β] :
  bounded_order_hom_class F α β :=
{ ..order_iso_class.to_top_hom_class, ..order_iso_class.to_bot_hom_class }

@[simp] lemma map_eq_top_iff [has_le α] [order_top α] [partial_order β] [order_top β]
  [order_iso_class F α β] (f : F) {a : α} : f a = ⊤ ↔ a = ⊤ :=
by rw [←map_top f, (equiv_like.injective f).eq_iff]

@[simp] lemma map_eq_bot_iff [has_le α] [order_bot α] [partial_order β] [order_bot β]
  [order_iso_class F α β] (f : F) {a : α} : f a = ⊥ ↔ a = ⊥ :=
by rw [←map_bot f, (equiv_like.injective f).eq_iff]

instance [has_top α] [has_top β] [top_hom_class F α β] : has_coe_t F (top_hom α β) :=
⟨λ f, ⟨f, map_top f⟩⟩

instance [has_bot α] [has_bot β] [bot_hom_class F α β] : has_coe_t F (bot_hom α β) :=
⟨λ f, ⟨f, map_bot f⟩⟩

instance [preorder α] [preorder β] [bounded_order α] [bounded_order β]
  [bounded_order_hom_class F α β] : has_coe_t F (bounded_order_hom α β) :=
⟨λ f, { to_fun := f, map_top' := map_top f, map_bot' := map_bot f, ..(f : α →o β) }⟩

/-! ### Top homomorphisms -/

namespace top_hom
variables [has_top α]

section has_top
variables [has_top β] [has_top γ] [has_top δ]

instance : top_hom_class (top_hom α β) α β :=
{ coe := top_hom.to_fun,
  coe_injective' := λ f g h, by cases f; cases g; congr',
  map_top := top_hom.map_top' }

/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`
directly. -/
instance : has_coe_to_fun (top_hom α β) (λ _, α → β) := fun_like.has_coe_to_fun

@[simp] lemma to_fun_eq_coe {f : top_hom α β} : f.to_fun = (f : α → β) := rfl

@[ext] lemma ext {f g : top_hom α β} (h : ∀ a, f a = g a) : f = g := fun_like.ext f g h

/-- Copy of a `top_hom` with a new `to_fun` equal to the old one. Useful to fix definitional
equalities. -/
protected def copy (f : top_hom α β) (f' : α → β) (h : f' = f) : top_hom α β :=
{ to_fun := f',
  map_top' := h.symm ▸ f.map_top' }

instance : inhabited (top_hom α β) := ⟨⟨λ _, ⊤, rfl⟩⟩

variables (α)

/-- `id` as a `top_hom`. -/
protected def id : top_hom α α := ⟨id, rfl⟩

@[simp] lemma coe_id : ⇑(top_hom.id α) = id := rfl

variables {α}

@[simp] lemma id_apply (a : α) : top_hom.id α a = a := rfl

/-- Composition of `top_hom`s as a `top_hom`. -/
def comp (f : top_hom β γ) (g : top_hom α β) : top_hom α γ :=
{ to_fun := f ∘ g,
  map_top' := by rw [comp_apply, map_top, map_top] }

@[simp] lemma coe_comp (f : top_hom β γ) (g : top_hom α β) : (f.comp g : α → γ) = f ∘ g := rfl
@[simp] lemma comp_apply (f : top_hom β γ) (g : top_hom α β) (a : α) :
  (f.comp g) a = f (g a) := rfl
@[simp] lemma comp_assoc (f : top_hom γ δ) (g : top_hom β γ) (h : top_hom α β) :
  (f.comp g).comp h = f.comp (g.comp h) := rfl
@[simp] lemma comp_id (f : top_hom α β) : f.comp (top_hom.id α) = f := top_hom.ext $ λ a, rfl
@[simp] lemma id_comp (f : top_hom α β) : (top_hom.id β).comp f = f := top_hom.ext $ λ a, rfl

lemma cancel_right {g₁ g₂ : top_hom β γ} {f : top_hom α β} (hf : surjective f) :
  g₁.comp f = g₂.comp f ↔ g₁ = g₂ :=
⟨λ h, top_hom.ext $ hf.forall.2 $ fun_like.ext_iff.1 h, congr_arg _⟩

lemma cancel_left {g : top_hom β γ} {f₁ f₂ : top_hom α β} (hg : injective g) :
  g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ :=
⟨λ h, top_hom.ext $ λ a, hg $
  by rw [←top_hom.comp_apply, h, top_hom.comp_apply], congr_arg _⟩

end has_top

instance [preorder β] [has_top β] : preorder (top_hom α β) :=
preorder.lift (coe_fn : top_hom α β → α → β)

instance [partial_order β] [has_top β] : partial_order (top_hom α β) :=
partial_order.lift _ fun_like.coe_injective

section order_top
variables [preorder β] [order_top β]

instance : order_top (top_hom α β) := ⟨⟨⊤, rfl⟩, λ _, le_top⟩

@[simp] lemma coe_top : ⇑(⊤ : top_hom α β) = ⊤ := rfl
@[simp] lemma top_apply (a : α) : (⊤ : top_hom α β) a = ⊤ := rfl

end order_top

section semilattice_inf
variables [semilattice_inf β] [order_top β] (f g : top_hom α β)

instance : has_inf (top_hom α β) :=
⟨λ f g, ⟨f ⊓ g, by rw [pi.inf_apply, map_top, map_top, inf_top_eq]⟩⟩

instance : semilattice_inf (top_hom α β) := fun_like.coe_injective.semilattice_inf _ $ λ _ _, rfl

@[simp] lemma coe_inf : ⇑(f ⊓ g) = f ⊓ g := rfl
@[simp] lemma inf_apply (a : α) : (f ⊓ g) a = f a ⊓ g a := rfl

end semilattice_inf

section semilattice_sup
variables [semilattice_sup β] [order_top β] (f g : top_hom α β)

instance : has_sup (top_hom α β) :=
⟨λ f g, ⟨f ⊔ g, by rw [pi.sup_apply, map_top, map_top, sup_top_eq]⟩⟩

instance : semilattice_sup (top_hom α β) := fun_like.coe_injective.semilattice_sup _ $ λ _ _, rfl

@[simp] lemma coe_sup : ⇑(f ⊔ g) = f ⊔ g := rfl
@[simp] lemma sup_apply (a : α) : (f ⊔ g) a = f a ⊔ g a := rfl

end semilattice_sup

instance [lattice β] [order_top β] : lattice (top_hom α β) :=
fun_like.coe_injective.lattice _ (λ _ _, rfl) (λ _ _, rfl)

instance [distrib_lattice β] [order_top β] : distrib_lattice (top_hom α β) :=
fun_like.coe_injective.distrib_lattice _ (λ _ _, rfl) (λ _ _, rfl)

end top_hom

/-! ### Bot homomorphisms -/

namespace bot_hom
variables [has_bot α]

section has_bot
variables [has_bot β] [has_bot γ] [has_bot δ]

instance : bot_hom_class (bot_hom α β) α β :=
{ coe := bot_hom.to_fun,
  coe_injective' := λ f g h, by cases f; cases g; congr',
  map_bot := bot_hom.map_bot' }

/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`
directly. -/
instance : has_coe_to_fun (bot_hom α β) (λ _, α → β) := fun_like.has_coe_to_fun

@[simp] lemma to_fun_eq_coe {f : bot_hom α β} : f.to_fun = (f : α → β) := rfl

@[ext] lemma ext {f g : bot_hom α β} (h : ∀ a, f a = g a) : f = g := fun_like.ext f g h

/-- Copy of a `bot_hom` with a new `to_fun` equal to the old one. Useful to fix definitional
equalities. -/
protected def copy (f : bot_hom α β) (f' : α → β) (h : f' = f) : bot_hom α β :=
{ to_fun := f',
  map_bot' := h.symm ▸ f.map_bot' }

instance : inhabited (bot_hom α β) := ⟨⟨λ _, ⊥, rfl⟩⟩

variables (α)

/-- `id` as a `bot_hom`. -/
protected def id : bot_hom α α := ⟨id, rfl⟩

@[simp] lemma coe_id : ⇑(bot_hom.id α) = id := rfl

variables {α}

@[simp] lemma id_apply (a : α) : bot_hom.id α a = a := rfl

/-- Composition of `bot_hom`s as a `bot_hom`. -/
def comp (f : bot_hom β γ) (g : bot_hom α β) : bot_hom α γ :=
{ to_fun := f ∘ g,
  map_bot' := by rw [comp_apply, map_bot, map_bot] }

@[simp] lemma coe_comp (f : bot_hom β γ) (g : bot_hom α β) : (f.comp g : α → γ) = f ∘ g := rfl
@[simp] lemma comp_apply (f : bot_hom β γ) (g : bot_hom α β) (a : α) :
  (f.comp g) a = f (g a) := rfl
@[simp] lemma comp_assoc (f : bot_hom γ δ) (g : bot_hom β γ) (h : bot_hom α β) :
  (f.comp g).comp h = f.comp (g.comp h) := rfl
@[simp] lemma comp_id (f : bot_hom α β) : f.comp (bot_hom.id α) = f := bot_hom.ext $ λ a, rfl
@[simp] lemma id_comp (f : bot_hom α β) : (bot_hom.id β).comp f = f := bot_hom.ext $ λ a, rfl

lemma cancel_right {g₁ g₂ : bot_hom β γ} {f : bot_hom α β} (hf : surjective f) :
  g₁.comp f = g₂.comp f ↔ g₁ = g₂ :=
⟨λ h, bot_hom.ext $ hf.forall.2 $ fun_like.ext_iff.1 h, congr_arg _⟩

lemma cancel_left {g : bot_hom β γ} {f₁ f₂ : bot_hom α β} (hg : injective g) :
  g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ :=
⟨λ h, bot_hom.ext $ λ a, hg $
  by rw [←bot_hom.comp_apply, h, bot_hom.comp_apply], congr_arg _⟩

end has_bot

instance [preorder β] [has_bot β] : preorder (bot_hom α β) :=
preorder.lift (coe_fn : bot_hom α β → α → β)

instance [partial_order β] [has_bot β] : partial_order (bot_hom α β) :=
partial_order.lift _ fun_like.coe_injective

section order_bot
variables [preorder β] [order_bot β]

instance : order_bot (bot_hom α β) := ⟨⟨⊥, rfl⟩, λ _, bot_le⟩

@[simp] lemma coe_bot : ⇑(⊥ : bot_hom α β) = ⊥ := rfl
@[simp] lemma bot_apply (a : α) : (⊥ : bot_hom α β) a = ⊥ := rfl

end order_bot

section semilattice_inf
variables [semilattice_inf β] [order_bot β] (f g : bot_hom α β)

instance : has_inf (bot_hom α β) :=
⟨λ f g, ⟨f ⊓ g, by rw [pi.inf_apply, map_bot, map_bot, inf_bot_eq]⟩⟩

instance : semilattice_inf (bot_hom α β) := fun_like.coe_injective.semilattice_inf _ $ λ _ _, rfl

@[simp] lemma coe_inf : ⇑(f ⊓ g) = f ⊓ g := rfl
@[simp] lemma inf_apply (a : α) : (f ⊓ g) a = f a ⊓ g a := rfl

end semilattice_inf

section semilattice_sup
variables [semilattice_sup β] [order_bot β] (f g : bot_hom α β)

instance : has_sup (bot_hom α β) :=
⟨λ f g, ⟨f ⊔ g, by rw [pi.sup_apply, map_bot, map_bot, sup_bot_eq]⟩⟩

instance : semilattice_sup (bot_hom α β) := fun_like.coe_injective.semilattice_sup _ $ λ _ _, rfl

@[simp] lemma coe_sup : ⇑(f ⊔ g) = f ⊔ g := rfl
@[simp] lemma sup_apply (a : α) : (f ⊔ g) a = f a ⊔ g a := rfl

end semilattice_sup

instance [lattice β] [order_bot β] : lattice (bot_hom α β) :=
fun_like.coe_injective.lattice _ (λ _ _, rfl) (λ _ _, rfl)

instance [distrib_lattice β] [order_bot β] : distrib_lattice (bot_hom α β) :=
fun_like.coe_injective.distrib_lattice _ (λ _ _, rfl) (λ _ _, rfl)

end bot_hom

/-! ### Bounded order homomorphisms -/

namespace bounded_order_hom
variables [preorder α] [preorder β] [preorder γ] [preorder δ] [bounded_order α] [bounded_order β]
  [bounded_order γ] [bounded_order δ]

/-- Reinterpret a `bounded_order_hom` as a `top_hom`. -/
def to_top_hom (f : bounded_order_hom α β) : top_hom α β := { ..f }

/-- Reinterpret a `bounded_order_hom` as a `bot_hom`. -/
def to_bot_hom (f : bounded_order_hom α β) : bot_hom α β := { ..f }

instance : bounded_order_hom_class (bounded_order_hom α β) α β :=
{ coe := λ f, f.to_fun,
  coe_injective' := λ f g h, by obtain ⟨⟨_, _⟩, _⟩ := f; obtain ⟨⟨_, _⟩, _⟩ := g; congr',
  map_rel := λ f, f.monotone',
  map_top := λ f, f.map_top',
  map_bot := λ f, f.map_bot' }

/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`
directly. -/
instance : has_coe_to_fun (bounded_order_hom α β) (λ _, α → β) := fun_like.has_coe_to_fun

@[simp] lemma to_fun_eq_coe {f : bounded_order_hom α β} : f.to_fun = (f : α → β) := rfl

@[ext] lemma ext {f g : bounded_order_hom α β} (h : ∀ a, f a = g a) : f = g := fun_like.ext f g h

/-- Copy of a `bounded_order_hom` with a new `to_fun` equal to the old one. Useful to fix
definitional equalities. -/
protected def copy (f : bounded_order_hom α β) (f' : α → β) (h : f' = f) : bounded_order_hom α β :=
{ .. f.to_order_hom.copy f' h, .. f.to_top_hom.copy f' h, .. f.to_bot_hom.copy f' h }

variables (α)

/-- `id` as a `bounded_order_hom`. -/
protected def id : bounded_order_hom α α := { ..order_hom.id, ..top_hom.id α, ..bot_hom.id α }

instance : inhabited (bounded_order_hom α α) := ⟨bounded_order_hom.id α⟩

@[simp] lemma coe_id : ⇑(bounded_order_hom.id α) = id := rfl

variables {α}

@[simp] lemma id_apply (a : α) : bounded_order_hom.id α a = a := rfl

/-- Composition of `bounded_order_hom`s as a `bounded_order_hom`. -/
def comp (f : bounded_order_hom β γ) (g : bounded_order_hom α β) : bounded_order_hom α γ :=
{ ..f.to_order_hom.comp g.to_order_hom,
  ..f.to_top_hom.comp g.to_top_hom, ..f.to_bot_hom.comp g.to_bot_hom }

@[simp] lemma coe_comp (f : bounded_order_hom β γ) (g : bounded_order_hom α β) :
  (f.comp g : α → γ) = f ∘ g := rfl
@[simp] lemma comp_apply (f : bounded_order_hom β γ) (g : bounded_order_hom α β) (a : α) :
  (f.comp g) a = f (g a) := rfl
@[simp] lemma coe_comp_order_hom (f : bounded_order_hom β γ) (g : bounded_order_hom α β) :
  (f.comp g : order_hom α γ) = (f : order_hom β γ).comp g := rfl
@[simp] lemma coe_comp_top_hom (f : bounded_order_hom β γ) (g : bounded_order_hom α β) :
  (f.comp g : top_hom α γ) = (f : top_hom β γ).comp g := rfl
@[simp] lemma coe_comp_bot_hom (f : bounded_order_hom β γ) (g : bounded_order_hom α β) :
  (f.comp g : bot_hom α γ) = (f : bot_hom β γ).comp g := rfl
@[simp] lemma comp_assoc (f : bounded_order_hom γ δ) (g : bounded_order_hom β γ)
  (h : bounded_order_hom α β) :
  (f.comp g).comp h = f.comp (g.comp h) := rfl
@[simp] lemma comp_id (f : bounded_order_hom α β) : f.comp (bounded_order_hom.id α) = f :=
bounded_order_hom.ext $ λ a, rfl
@[simp] lemma id_comp (f : bounded_order_hom α β) : (bounded_order_hom.id β).comp f = f :=
bounded_order_hom.ext $ λ a, rfl

lemma cancel_right {g₁ g₂ : bounded_order_hom β γ} {f : bounded_order_hom α β} (hf : surjective f) :
  g₁.comp f = g₂.comp f ↔ g₁ = g₂ :=
⟨λ h, bounded_order_hom.ext $ hf.forall.2 $ fun_like.ext_iff.1 h, congr_arg _⟩

lemma cancel_left {g : bounded_order_hom β γ} {f₁ f₂ : bounded_order_hom α β} (hg : injective g) :
  g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ :=
⟨λ h, bounded_order_hom.ext $ λ a, hg $
  by rw [←bounded_order_hom.comp_apply, h, bounded_order_hom.comp_apply], congr_arg _⟩

end bounded_order_hom

/-! ### Dual homs -/

namespace top_hom
variables [has_le α] [order_top α] [has_le β] [order_top β] [has_le γ] [order_top γ]

/-- Reinterpret a top homomorphism as a bot homomorphism between the dual lattices. -/
@[simps] protected def dual : top_hom α β ≃ bot_hom (order_dual α) (order_dual β) :=
{ to_fun := λ f, ⟨f, f.map_top'⟩,
  inv_fun := λ f, ⟨f, f.map_bot'⟩,
  left_inv := λ f, top_hom.ext $ λ _, rfl,
  right_inv := λ f, bot_hom.ext $ λ _, rfl }

@[simp] lemma dual_id : (top_hom.id α).dual = bot_hom.id _ := rfl
@[simp] lemma dual_comp (g : top_hom β γ) (f : top_hom α β) :
  (g.comp f).dual = g.dual.comp f.dual := rfl

@[simp] lemma symm_dual_id : top_hom.dual.symm (bot_hom.id _) = top_hom.id α := rfl
@[simp] lemma symm_dual_comp (g : bot_hom (order_dual β) (order_dual γ))
  (f : bot_hom (order_dual α) (order_dual β)) :
  top_hom.dual.symm (g.comp f) = (top_hom.dual.symm g).comp (top_hom.dual.symm f) := rfl

end top_hom

namespace bot_hom
variables [has_le α] [order_bot α] [has_le β] [order_bot β] [has_le γ] [order_bot γ]

/-- Reinterpret a bot homomorphism as a top homomorphism between the dual lattices. -/
@[simps] protected def dual : bot_hom α β ≃ top_hom (order_dual α) (order_dual β) :=
{ to_fun := λ f, ⟨f, f.map_bot'⟩,
  inv_fun := λ f, ⟨f, f.map_top'⟩,
  left_inv := λ f, bot_hom.ext $ λ _, rfl,
  right_inv := λ f, top_hom.ext $ λ _, rfl }

@[simp] lemma dual_id : (bot_hom.id α).dual = top_hom.id _ := rfl
@[simp] lemma dual_comp (g : bot_hom β γ) (f : bot_hom α β) :
  (g.comp f).dual = g.dual.comp f.dual := rfl

@[simp] lemma symm_dual_id : bot_hom.dual.symm (top_hom.id _) = bot_hom.id α := rfl
@[simp] lemma symm_dual_comp (g : top_hom (order_dual β) (order_dual γ))
  (f : top_hom (order_dual α) (order_dual β)) :
  bot_hom.dual.symm (g.comp f) = (bot_hom.dual.symm g).comp (bot_hom.dual.symm f) := rfl

end bot_hom

namespace bounded_order_hom
variables [preorder α] [bounded_order α] [preorder β] [bounded_order β] [preorder γ]
  [bounded_order γ]

/-- Reinterpret a bounded order homomorphism as a bounded order homomorphism between the dual
orders. -/
@[simps] protected def dual :
   bounded_order_hom α β ≃ bounded_order_hom (order_dual α) (order_dual β) :=
{ to_fun := λ f, ⟨f.to_order_hom.dual, f.map_bot', f.map_top'⟩,
  inv_fun := λ f, ⟨order_hom.dual.symm f.to_order_hom, f.map_bot', f.map_top'⟩,
  left_inv := λ f, ext $ λ a, rfl,
  right_inv := λ f, ext $ λ a, rfl }

@[simp] lemma dual_id : (bounded_order_hom.id α).dual = bounded_order_hom.id _ := rfl
@[simp] lemma dual_comp (g : bounded_order_hom β γ) (f : bounded_order_hom α β) :
  (g.comp f).dual = g.dual.comp f.dual := rfl

@[simp] lemma symm_dual_id :
  bounded_order_hom.dual.symm (bounded_order_hom.id _) = bounded_order_hom.id α := rfl
@[simp] lemma symm_dual_comp (g : bounded_order_hom (order_dual β) (order_dual γ))
  (f : bounded_order_hom (order_dual α) (order_dual β)) :
  bounded_order_hom.dual.symm (g.comp f) =
    (bounded_order_hom.dual.symm g).comp (bounded_order_hom.dual.symm f) := rfl

end bounded_order_hom