Theory CZH_ECAT_PCategory

(* Copyright 2021 (C) Mihails Milehins *)

section‹Product category›
theory CZH_ECAT_PCategory
  imports 
    CZH_ECAT_NTCF
    CZH_ECAT_Small_Category
    CZH_Foundations.CZH_SMC_PSemicategory
begin



subsection‹Background›


text‹See Chapter II-3 in cite"mac_lane_categories_2010".›

named_theorems cat_prod_cs_simps
named_theorems cat_prod_cs_intros



subsection‹Product category: definition and elementary properties› 

definition cat_prod :: "V  (V  V)  V" 
  where "cat_prod I 𝔄 =
    [
      (iI. 𝔄 iObj),
      (iI. 𝔄 iArr),
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iDomfi)),
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iCodfi)),
      (
        λgfcomposable_arrs (dg_prod I 𝔄).
          (λiI. vpfst gfi A𝔄 ivpsnd gfi)
      ),
      (λa(iI. 𝔄 iObj). (λiI. 𝔄 iCIdai))
    ]"

syntax "_PCATEGORY" :: "pttrn  V  (V  V)  V" 
  ("(3C__./ _)" [0, 0, 10] 10)
translations "CiI. 𝔄"  "CONST cat_prod I (λi. 𝔄)"


text‹Components.›

lemma cat_prod_components:
  shows "(CiI. 𝔄 i)Obj = (iI. 𝔄 iObj)"
    and "(CiI. 𝔄 i)Arr = (iI. 𝔄 iArr)"
    and "(CiI. 𝔄 i)Dom =
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iDomfi))"
    and "(CiI. 𝔄 i)Cod =
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iCodfi))"
    and "(CiI. 𝔄 i)Comp =
      (
        λgfcomposable_arrs (dg_prod I 𝔄).
          (λiI. vpfst gfi A𝔄 ivpsnd gfi)
      )"
    and "(CiI. 𝔄 i)CId =
      (λa(iI. 𝔄 iObj). (λiI. 𝔄 iCIdai))"
  unfolding cat_prod_def dg_field_simps by (simp_all add: nat_omega_simps)


text‹Slicing.›

lemma cat_smc_cat_prod[slicing_commute]: 
  "smc_prod I (λi. cat_smc (𝔄 i)) = cat_smc (CiI. 𝔄 i)"
  unfolding dg_prod_def cat_smc_def cat_prod_def smc_prod_def dg_field_simps
  by (simp_all add: nat_omega_simps)

context
  fixes 𝔄 φ :: "V  V"
    and  :: V
begin

lemmas_with [
  where 𝔄=λi. cat_smc (𝔄 i), unfolded slicing_simps slicing_commute
  ]:
  cat_prod_ObjI = smc_prod_ObjI
  and cat_prod_ObjD = smc_prod_ObjD
  and cat_prod_ObjE = smc_prod_ObjE
  and cat_prod_Obj_cong = smc_prod_Obj_cong
  and cat_prod_ArrI = smc_prod_ArrI
  and cat_prod_ArrD = smc_prod_ArrD
  and cat_prod_ArrE = smc_prod_ArrE
  and cat_prod_Arr_cong = smc_prod_Arr_cong
  and cat_prod_Dom_vsv[cat_cs_intros] = smc_prod_Dom_vsv
  and cat_prod_Dom_vdomain[cat_cs_simps] = smc_prod_Dom_vdomain
  and cat_prod_Dom_app = smc_prod_Dom_app
  and cat_prod_Dom_app_component_app[cat_cs_simps] = 
    smc_prod_Dom_app_component_app
  and cat_prod_Cod_vsv[cat_cs_intros] = smc_prod_Cod_vsv
  and cat_prod_Cod_app = smc_prod_Cod_app
  and cat_prod_Cod_vdomain[cat_cs_simps] = smc_prod_Cod_vdomain
  and cat_prod_Cod_app_component_app[cat_cs_simps] = 
    smc_prod_Cod_app_component_app
  and cat_prod_Comp = smc_prod_Comp
  and cat_prod_Comp_vdomain[cat_cs_simps] = smc_prod_Comp_vdomain
  and cat_prod_Comp_app = smc_prod_Comp_app
  and cat_prod_Comp_app_component[cat_cs_simps] = 
    smc_prod_Comp_app_component
  and cat_prod_Comp_app_vdomain = smc_prod_Comp_app_vdomain
  and cat_prod_vunion_Obj_in_Obj = smc_prod_vunion_Obj_in_Obj
  and cat_prod_vdiff_vunion_Obj_in_Obj = smc_prod_vdiff_vunion_Obj_in_Obj
  and cat_prod_vunion_Arr_in_Arr = smc_prod_vunion_Arr_in_Arr
  and cat_prod_vdiff_vunion_Arr_in_Arr = smc_prod_vdiff_vunion_Arr_in_Arr

end



subsection‹Local assumptions for a product category›

locale pcategory_base = 𝒵 α for α I 𝔄 +
  assumes pcat_categories: "i  I  category α (𝔄 i)"
    and pcat_index_in_Vset[cat_cs_intros]: "I  Vset α"

lemma (in pcategory_base) pcat_categories'[cat_prod_cs_intros]:
  assumes "i  I" and "α' = α"
  shows "category α' (𝔄 i)" 
  using assms(1) unfolding assms(2) by (rule pcat_categories)


text‹Rules.›

lemma (in pcategory_base) pcategory_base_axioms'[cat_prod_cs_intros]: 
  assumes "α' = α" and "I' = I"
  shows "pcategory_base α' I' 𝔄"
  unfolding assms by (rule pcategory_base_axioms)

mk_ide rf pcategory_base_def[unfolded pcategory_base_axioms_def]
  |intro pcategory_baseI|
  |dest pcategory_baseD[dest]|
  |elim pcategory_baseE[elim]|

lemma pcategory_base_psemicategory_baseI:
  assumes "psemicategory_base α I (λi. cat_smc (𝔄 i))" 
    and "i. i  I  category α (𝔄 i)"
  shows "pcategory_base α I 𝔄"
proof-
  interpret psemicategory_base α I λi. cat_smc (𝔄 i) by (rule assms(1))
  show ?thesis
    by (intro pcategory_baseI)
      (auto simp: assms(2) psmc_index_in_Vset psmc_Obj_in_Vset psmc_Arr_in_Vset) 
qed


text‹Product category is a product semicategory.›

context pcategory_base
begin

lemma pcat_psemicategory_base: "psemicategory_base α I (λi. cat_smc (𝔄 i))"
proof(intro psemicategory_baseI)
  from pcat_index_in_Vset show "I  Vset α" by auto
qed (auto simp: category.cat_semicategory cat_prod_cs_intros)

interpretation psmc: psemicategory_base α I λi. cat_smc (𝔄 i) 
  by (rule pcat_psemicategory_base)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  pcat_Obj_in_Vset = psmc.psmc_Obj_in_Vset
  and pcat_Arr_in_Vset = psmc.psmc_Arr_in_Vset
  and pcat_smc_prod_Obj_in_Vset = psmc.psmc_smc_prod_Obj_in_Vset
  and pcat_smc_prod_Arr_in_Vset = psmc.psmc_smc_prod_Arr_in_Vset
  and cat_prod_Dom_app_in_Obj[cat_cs_intros] = psmc.smc_prod_Dom_app_in_Obj
  and cat_prod_Cod_app_in_Obj[cat_cs_intros] = psmc.smc_prod_Cod_app_in_Obj
  and cat_prod_is_arrI = psmc.smc_prod_is_arrI
  and cat_prod_is_arrD[dest] = psmc.smc_prod_is_arrD
  and cat_prod_is_arrE[elim] = psmc.smc_prod_is_arrE

end

lemma cat_prod_dg_prod_is_arr: 
  "g : b dg_prod I 𝔄c  g : b (CiI. 𝔄 i)c"
  unfolding is_arr_def cat_prod_def smc_prod_def dg_prod_def dg_field_simps
  by (simp add: nat_omega_simps)

lemma smc_prod_composable_arrs_dg_prod:
  "composable_arrs (dg_prod I 𝔄) = composable_arrs (CiI. 𝔄 i)"
  unfolding composable_arrs_def cat_prod_dg_prod_is_arr by simp


text‹Elementary properties.›

lemma (in pcategory_base) pcat_vsubset_index_pcategory_base:
  assumes "J  I"
  shows "pcategory_base α J 𝔄"
proof(intro pcategory_baseI)
  show "category α (𝔄 i)" if "i  J" for i 
    using that assms by (auto intro: cat_prod_cs_intros)
  from assms show "J  Vset α" by (simp add: vsubset_in_VsetI cat_cs_intros)
qed auto


subsubsection‹Identity›

lemma cat_prod_CId_vsv[cat_cs_intros]: "vsv ((CiI. 𝔄 i)CId)"
  unfolding cat_prod_components by auto

lemma cat_prod_CId_vdomain[cat_cs_simps]: 
  "𝒟 ((CiI. 𝔄 i)CId) = (CiI. 𝔄 i)Obj" 
  unfolding cat_prod_components by simp

lemma cat_prod_CId_app: 
  assumes "a  (CiI. 𝔄 i)Obj"
  shows "(CiI. 𝔄 i)CIda = (λiI. 𝔄 iCIdai)" 
  using assms unfolding cat_prod_components by simp

lemma cat_prod_CId_app_component[cat_cs_simps]: 
  assumes "a  (CiI. 𝔄 i)Obj" and "i  I"
  shows "(CiI. 𝔄 i)CIdai = 𝔄 iCIdai" 
  using assms unfolding cat_prod_components by simp

lemma (in pcategory_base) cat_prod_CId_vrange: 
  " ((CiI. 𝔄 i)CId)  (iI. 𝔄 iArr)" 
proof(intro vsubsetI)
  interpret CId: vsv ((CiI. 𝔄 i)CId) by (rule cat_prod_CId_vsv)
  fix f assume "f   ((CiI. 𝔄 i)CId)"
  then obtain a where f_def: "f = ((CiI. 𝔄 i)CId)a" 
    and "a  𝒟 ((CiI. 𝔄 i)CId)"
    by (blast dest: CId.vrange_atD)
  then have a: "a  (CiI. 𝔄 i)Obj" 
    unfolding cat_prod_components by simp
  show "f  (iI. 𝔄 iArr)"
    unfolding f_def cat_prod_CId_app[OF a]
  proof(rule VLambda_in_vproduct)
    fix i assume prems: "i  I"
    interpret 𝔄: category α 𝔄 i 
      by (simp add: i  I cat_cs_intros cat_prod_cs_intros)
    from prems a have "ai  𝔄 iObj" unfolding cat_prod_components by auto
    with is_arrD(1) show "𝔄 iCIdai  𝔄 iArr" 
      by (auto intro: cat_cs_intros)
  qed
qed


subsubsection‹A product α›-category is a tiny β›-category›

lemma (in pcategory_base) pcat_tiny_category_cat_prod:
  assumes "𝒵 β" and "α  β" 
  shows "tiny_category β (CiI. 𝔄 i)"
proof-

  interpret β: 𝒵 β by (rule assms(1))

  show ?thesis
  proof(intro tiny_categoryI, (unfold slicing_simps)?)
  
    show Π: "tiny_semicategory β (cat_smc (CiI. 𝔄 i))"
      unfolding slicing_commute[symmetric]
      by 
        (
          intro psemicategory_base.psmc_tiny_semicategory_smc_prod; 
          (rule assms pcat_psemicategory_base)?
        )
    interpret Π: tiny_semicategory β cat_smc (CiI. 𝔄 i) by (rule Π)
  
    show "vfsequence (CiI. 𝔄 i)" unfolding cat_prod_def by auto
    show "vcard (CiI. 𝔄 i) = 6"
      unfolding cat_prod_def by (simp add: nat_omega_simps)
  
    show CId: "(CiI. 𝔄 i)CIda : a (CiI. 𝔄 i)a"
      if a: "a  (CiI. 𝔄 i)Obj" for a
    proof(rule cat_prod_is_arrI)
      have [cat_cs_intros]: "ai  𝔄 iObj" if i: "i  I" for i
        by (rule cat_prod_ObjD(3)[OF a i])
      from that show "(CiI. 𝔄 i)CIdai : ai 𝔄 iai"
        if "i  I" for i
        by 
          (
            cs_concl cs_shallow
              cs_simp: cat_cs_simps 
              cs_intro: cat_cs_intros cat_prod_cs_intros that
          )
    qed (use that in auto simp: cat_prod_components cat_prod_CId_app that)
  
    show "(CiI. 𝔄 i)CIdb A(CiI. 𝔄 i)f = f"
      if "f : a (CiI. 𝔄 i)b" for f a b
    proof(rule cat_prod_Arr_cong)
      note f = Π.smc_is_arrD[unfolded slicing_simps, OF that]
      note a = f(2) and b = f(3) and f = f(1)
      from CId[OF b] have CId_b: 
        "(CiI. 𝔄 i)CIdb : b (CiI. 𝔄 i)b"
        by simp
      from Π.smc_Comp_is_arr[unfolded slicing_simps, OF this that] show 
        "(CiI. 𝔄 i)CIdb A(CiI. 𝔄 i)f  (CiI. 𝔄 i)Arr"
        by (simp add: cat_cs_intros)
      from that show "f  (CiI. 𝔄 i)Arr" by auto
      fix i assume prems: "i  I"
      interpret 𝔄i: category α 𝔄 i by (simp add: prems cat_prod_cs_intros)
      from prems cat_prod_is_arrD(7)[OF that] have fi: 
        "fi : ai 𝔄 ibi" 
        by auto
      from prems show "((CiI. 𝔄 i)CIdb A(CiI. 𝔄 i)f)i = fi"
        unfolding cat_prod_Comp_app_component[OF CId_b that prems]
        unfolding cat_prod_CId_app[OF b]
        by (auto intro: 𝔄i.cat_CId_left_left[OF fi])
    qed

    show "f A(CiI. 𝔄 i)(CiI. 𝔄 i)CIdb = f"
      if "f : b (CiI. 𝔄 i)c" for f b c
    proof(rule cat_prod_Arr_cong)
      note f = Π.smc_is_arrD[unfolded slicing_simps, OF that]
      note b = f(2) and c = f(3) and f = f(1)
      from CId[OF b] have CId_b: 
        "(CiI. 𝔄 i)CIdb : b (CiI. 𝔄 i)b"
        by simp
      from Π.smc_Comp_is_arr[unfolded slicing_simps, OF that this] show 
        "f A(CiI. 𝔄 i)(CiI. 𝔄 i)CIdb  (CiI. 𝔄 i)Arr"
        by (simp add: cat_cs_intros)
      from that show "f  (CiI. 𝔄 i)Arr" by auto
      fix i assume prems: "i  I"
      interpret 𝔄i: category α 𝔄 i by (simp add: prems cat_prod_cs_intros)
      from prems cat_prod_is_arrD[OF that] have fi: "fi : bi 𝔄 ici"
        by simp
      from prems show "(f A(CiI. 𝔄 i)(CiI. 𝔄 i)CIdb)i = fi"
        unfolding cat_prod_Comp_app_component[OF that CId_b prems]
        unfolding cat_prod_CId_app[OF b]
        by (auto intro: 𝔄i.cat_CId_right_left[OF fi])
    qed
  
  qed (auto simp: cat_cs_intros cat_cs_simps intro: cat_cs_intros)

qed



subsection‹Further local assumptions for product categories›


subsubsection‹Definition and elementary properties›

locale pcategory = pcategory_base α I 𝔄 for α I 𝔄 +
  assumes pcat_Obj_vsubset_Vset: "J  I  (CiJ. 𝔄 i)Obj  Vset α"
    and pcat_Hom_vifunion_in_Vset: 
      "
        J  I;
        A  (CiJ. 𝔄 i)Obj;
        B  (CiJ. 𝔄 i)Obj;
        A  Vset α;
        B  Vset α
        (aA. bB. Hom (CiJ. 𝔄 i) a b)  Vset α"


text‹Rules.›

lemma (in pcategory) pcategory_axioms'[cat_prod_cs_intros]: 
  assumes "α' = α" and "I' = I"
  shows "pcategory α' I' 𝔄"
  unfolding assms by (rule pcategory_axioms)

mk_ide rf pcategory_def[unfolded pcategory_axioms_def]
  |intro pcategoryI|
  |dest pcategoryD[dest]|
  |elim pcategoryE[elim]|

lemmas [cat_prod_cs_intros] = pcategoryD(1)

lemma pcategory_psemicategoryI:
  assumes "psemicategory α I (λi. cat_smc (𝔄 i))" 
    and "i. i  I  category α (𝔄 i)"
  shows "pcategory α I 𝔄"
proof-
  interpret psemicategory α I λi. cat_smc (𝔄 i) by (rule assms(1))
  note [unfolded slicing_simps slicing_commute, cat_cs_intros] = 
    psmc_Obj_vsubset_Vset
    psmc_Hom_vifunion_in_Vset
  show ?thesis
    by (intro pcategoryI pcategory_base_psemicategory_baseI)
      (auto simp: assms(2) smc_prod_cs_intros intro!: cat_cs_intros)
qed


text‹Product category is a product semicategory.›

context pcategory
begin

lemma pcat_psemicategory: "psemicategory α I (λi. cat_smc (𝔄 i))"
proof(intro psemicategoryI, unfold slicing_simps slicing_commute)
  show "psemicategory_base α I (λi. cat_smc (𝔄 i))" 
    by (rule pcat_psemicategory_base)
qed (auto intro!: pcat_Obj_vsubset_Vset pcat_Hom_vifunion_in_Vset)

interpretation psmc: psemicategory α I λi. cat_smc (𝔄 i) 
  by (rule pcat_psemicategory)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  pcat_Obj_vsubset_Vset' = psmc.psmc_Obj_vsubset_Vset'
  and pcat_Hom_vifunion_in_Vset' = psmc.psmc_Hom_vifunion_in_Vset'
  and pcat_cat_prod_vunion_is_arr = psmc.psmc_smc_prod_vunion_is_arr
  and pcat_cat_prod_vdiff_vunion_is_arr = psmc.psmc_smc_prod_vdiff_vunion_is_arr

lemmas_with [unfolded slicing_simps slicing_commute]: 
  pcat_cat_prod_vunion_Comp = psmc.psmc_smc_prod_vunion_Comp
  and pcat_cat_prod_vdiff_vunion_Comp = psmc.psmc_smc_prod_vdiff_vunion_Comp

end


text‹Elementary properties.›

lemma (in pcategory) pcat_vsubset_index_pcategory:
  assumes "J  I"
  shows "pcategory α J 𝔄"
proof(intro pcategoryI pcategory_psemicategoryI)
  show "cat_prod J' 𝔄Obj  Vset α" if J'  J for J'
  proof-
    from that assms have "J'  I" by simp
    then show "cat_prod J' 𝔄Obj  Vset α" by (rule pcat_Obj_vsubset_Vset)
  qed
  fix A B J' assume prems:
    "J'  J"
    "A  (CiJ'. 𝔄 i)Obj"
    "B  (CiJ'. 𝔄 i)Obj"
    "A  Vset α" 
    "B  Vset α"
  show "(aA. bB. Hom (CiJ'. 𝔄 i) a b)  Vset α"
  proof-
    from prems(1) assms have "J'  I" by simp
    from pcat_Hom_vifunion_in_Vset[OF this prems(2-5)] show ?thesis.
  qed
  
qed (rule pcat_vsubset_index_pcategory_base[OF assms])


subsubsection‹A product α›-category is an α›-category›

lemma (in pcategory) pcat_category_cat_prod: "category α (CiI. 𝔄 i)"
proof-
  interpret tiny_category α + ω CiI. 𝔄 i
    by (intro pcat_tiny_category_cat_prod) 
      (auto simp: 𝒵_α_αω 𝒵.intro 𝒵_Limit_αω 𝒵_ω_αω)
  show ?thesis
    by (rule category_if_category)  
      (
        auto 
          intro!: pcat_Hom_vifunion_in_Vset pcat_Obj_vsubset_Vset
          intro: cat_cs_intros
      )
qed



subsection‹Local assumptions for a finite product category›


subsubsection‹Definition and elementary properties›

locale finite_pcategory = pcategory_base α I 𝔄 for α I 𝔄 +
  assumes fin_pcat_index_vfinite: "vfinite I"


text‹Rules.›

lemma (in finite_pcategory) finite_pcategory_axioms[cat_prod_cs_intros]: 
  assumes "α' = α" and "I' = I"
  shows "finite_pcategory α' I' 𝔄"
  unfolding assms by (rule finite_pcategory_axioms)

mk_ide rf finite_pcategory_def[unfolded finite_pcategory_axioms_def]
  |intro finite_pcategoryI|
  |dest finite_pcategoryD[dest]|
  |elim finite_pcategoryE[elim]|

lemmas [cat_prod_cs_intros] = finite_pcategoryD(1)

lemma finite_pcategory_finite_psemicategoryI:
  assumes "finite_psemicategory α I (λi. cat_smc (𝔄 i))" 
    and "i. i  I  category α (𝔄 i)"
  shows "finite_pcategory α I 𝔄"
proof-
  interpret finite_psemicategory α I λi. cat_smc (𝔄 i) by (rule assms(1))
  show ?thesis
    by 
      (
        intro 
          assms
          finite_pcategoryI 
          pcategory_base_psemicategory_baseI 
          finite_psemicategoryD(1)[OF assms(1)]
          fin_psmc_index_vfinite
      )
qed


subsubsection‹
Local assumptions for a finite product semicategory and local
assumptions for an arbitrary product semicategory
›

sublocale finite_pcategory  pcategory α I 𝔄
proof-
  interpret finite_psemicategory α I λi. cat_smc (𝔄 i)
  proof(intro finite_psemicategoryI psemicategory_baseI)
    fix i assume "i  I"
    then interpret 𝔄i: category α 𝔄 i by (simp add: pcat_categories)
    show "semicategory α (cat_smc (𝔄 i))" by (simp add: 𝔄i.cat_semicategory)
  qed (auto intro!: cat_cs_intros fin_pcat_index_vfinite)
  show "pcategory α I 𝔄"
    by (intro pcategory_psemicategoryI) 
      (simp_all add: pcat_categories psemicategory_axioms)
qed



subsection‹Binary union and complement›

lemma (in pcategory) pcat_cat_prod_vunion_CId:
  assumes "vdisjnt J K"
    and "J  I"
    and "K  I"
    and "a  (CjJ. 𝔄 j)Obj"
    and "b  (CjK. 𝔄 j)Obj"
  shows 
    "(CjJ. 𝔄 j)CIda  (CjK. 𝔄 j)CIdb = 
      (CiJ  K. 𝔄 i)CIda  b"
proof-

  interpret J𝔄: pcategory α J 𝔄 
    using assms(2) by (simp add: pcat_vsubset_index_pcategory)
  interpret K𝔄: pcategory α K 𝔄 
    using assms(3) by (simp add: pcat_vsubset_index_pcategory)
  interpret JK𝔄: pcategory α J  K 𝔄 
    using assms(2,3) by (simp add: pcat_vsubset_index_pcategory)

  interpret J𝔄': category α cat_prod J 𝔄 
    by (rule J𝔄.pcat_category_cat_prod)
  interpret K𝔄': category α cat_prod K 𝔄 
    by (rule K𝔄.pcat_category_cat_prod)
  interpret JK𝔄': category α cat_prod (J  K) 𝔄 
    by (rule JK𝔄.pcat_category_cat_prod)

  from assms(4) have CId_a: "cat_prod J 𝔄CIda : a (CjJ. 𝔄 j)a" 
    by (auto intro: cat_cs_intros)
  from assms(5) have CId_b: "cat_prod K 𝔄CIdb : b (CkK. 𝔄 k)b" 
    by (auto intro: cat_cs_intros)
  have CId_a_CId_b: "cat_prod J 𝔄CIda  cat_prod K 𝔄CIdb :
    a  b cat_prod (J  K) 𝔄a  b"
    by (rule pcat_cat_prod_vunion_is_arr[OF assms(1-3) CId_a CId_b])
  from CId_a have a: "a  cat_prod J 𝔄Obj" by (auto intro: cat_cs_intros)
  from CId_b have b: "b  cat_prod K 𝔄Obj" by (auto intro: cat_cs_intros)
  from CId_a_CId_b have ab: "a  b  cat_prod (J  K) 𝔄Obj" 
    by (auto intro: cat_cs_intros)

  note CId_aD = J𝔄.cat_prod_is_arrD[OF CId_a]
    and CId_bD = K𝔄.cat_prod_is_arrD[OF CId_b]

  show ?thesis
  proof(rule cat_prod_Arr_cong[of _ J  K 𝔄])
    from CId_a_CId_b show 
      "cat_prod J 𝔄CIda  cat_prod K 𝔄CIdb  cat_prod (J  K) 𝔄Arr"
      by auto
    from ab show "cat_prod (J  K) 𝔄CIda  b  cat_prod (J  K) 𝔄Arr"
      by (auto intro: JK𝔄'.cat_is_arrD(1) cat_cs_intros)
    fix i assume "i  J  K"
    then consider (iJ) i  J | (iK) i  K by auto
    then show "(cat_prod J 𝔄CIda  cat_prod K 𝔄CIdb)i = 
      cat_prod (J  K) 𝔄CIda  bi"
      by cases
        (
          auto simp: 
            assms(1) 
            CId_aD(1-4) 
            CId_bD(1-4)
            cat_prod_CId_app[OF ab]
            cat_prod_CId_app[OF a]
            cat_prod_CId_app[OF b]
         )
  qed

qed

lemma (in pcategory) pcat_cat_prod_vdiff_vunion_CId:
  assumes "J  I"
    and "a  (CjI - J. 𝔄 j)Obj"
    and "b  (CjJ. 𝔄 j)Obj"
  shows 
    "(CjI - J. 𝔄 j)CIda  (CjJ. 𝔄 j)CIdb = 
      (CiI. 𝔄 i)CIda  b"
  by 
    (
      vdiff_of_vunion' 
        rule: pcat_cat_prod_vunion_CId assms: assms(2-3) subset: assms(1)
    )



subsection‹Projection›


subsubsection‹Definition and elementary properties›


text‹See Chapter II-3 in cite"mac_lane_categories_2010".›

definition cf_proj :: "V  (V  V)  V  V" (πC)
  where "πC I 𝔄 i =
    [
      (λa(iI. 𝔄 iObj). ai),
      (λf(iI. 𝔄 iArr). fi),
      (CiI. 𝔄 i),
      𝔄 i
    ]"


text‹Components.›

lemma cf_proj_components:
  shows "πC I 𝔄 iObjMap = (λa(iI. 𝔄 iObj). ai)"
    and "πC I 𝔄 iArrMap = (λf(iI. 𝔄 iArr). fi)"
    and "πC I 𝔄 iHomDom = (CiI. 𝔄 i)"
    and "πC I 𝔄 iHomCod = 𝔄 i"
  unfolding cf_proj_def dghm_field_simps by (simp_all add: nat_omega_simps)


text‹Slicing›

lemma cf_smcf_cf_proj[slicing_commute]: 
  "πSMC I (λi. cat_smc (𝔄 i)) i = cf_smcf (πC I 𝔄 i)"
  unfolding 
    cat_smc_def 
    cf_smcf_def 
    smcf_proj_def 
    cf_proj_def 
    cat_prod_def 
    smc_prod_def
    dg_prod_def
    dg_field_simps 
    dghm_field_simps 
  by (simp add: nat_omega_simps)

context pcategory
begin

interpretation psmc: psemicategory α I λi. cat_smc (𝔄 i) 
  by (rule pcat_psemicategory)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  pcat_cf_proj_is_semifunctor = psmc.psmc_smcf_proj_is_semifunctor

end


subsubsection‹Projection functor is a functor›

lemma (in pcategory) pcat_cf_proj_is_functor: 
  assumes "i  I"
  shows "πC I 𝔄 i : (CiI. 𝔄 i) ↦↦Cα𝔄 i"
proof(intro is_functorI)
  interpret 𝔄: category α (CiI. 𝔄 i) 
    by (simp add: pcat_category_cat_prod)
  show "vfsequence (πC I 𝔄 i)" unfolding cf_proj_def by simp
  show "category α (CiI. 𝔄 i)" by (simp add: 𝔄.category_axioms)
  show "vcard (πC I 𝔄 i) = 4"
    unfolding cf_proj_def by (simp add: nat_omega_simps)
  show "πC I 𝔄 iArrMap(CiI. 𝔄 i)CIdc = 𝔄 iCIdπC I 𝔄 iObjMapc"
    if "c  (CiI. 𝔄 i)Obj" for c
  proof-
    interpret 𝔄i: category α 𝔄 i 
      by (auto intro: assms cat_prod_cs_intros)
    from that have "(CiI. 𝔄 i)CIdc : c (CiI. 𝔄 i)c"
      by (simp add: 𝔄.cat_CId_is_arr)
    then have "(CiI. 𝔄 i)CIdc  (CiI. 𝔄 i)Arr" 
      by (auto intro: cat_cs_intros)
    with assms have 
      "πC I 𝔄 iArrMap(CiI. 𝔄 i)CIdc = (CiI. 𝔄 i)CIdci"
      unfolding cf_proj_components cat_prod_components by simp
    also from assms have " = 𝔄 iCIdci"
      unfolding cat_prod_CId_app[OF that] by simp
    also from that have " = 𝔄 iCIdπC I 𝔄 iObjMapc"
      unfolding cf_proj_components cat_prod_components by simp
    finally show 
      "πC I 𝔄 iArrMap(CiI. 𝔄 i)CIdc = 𝔄 iCIdπC I 𝔄 iObjMapc"
      by simp
  qed
qed 
  (
    auto simp: 
      assms cf_proj_components pcat_cf_proj_is_semifunctor cat_prod_cs_intros
  ) 

lemma (in pcategory) pcat_cf_proj_is_functor':
  assumes "i  I" and " = (CiI. 𝔄 i)" and "𝔇 = 𝔄 i"
  shows "πC I 𝔄 i :  ↦↦Cα𝔇"
  using assms(1) unfolding assms(2,3) by (rule pcat_cf_proj_is_functor)

lemmas [cat_cs_intros] = pcategory.pcat_cf_proj_is_functor'



subsection‹Category product universal property functor›


subsubsection‹Definition and elementary properties›

text‹
The functor that is presented in this section is used in the proof of 
the universal property of the product category later in this work.
›

definition cf_up :: "V  (V  V)  V  (V  V)  V"
  where "cf_up I 𝔄  φ =
    [
      (λaObj. (λiI. φ iObjMapa)),
      (λfArr. (λiI. φ iArrMapf)),
      ,
      (CiI. 𝔄 i)
    ]"


text‹Components.›

lemma cf_up_components: 
  shows "cf_up I 𝔄  φObjMap = (λaObj. (λiI. φ iObjMapa))"
    and "cf_up I 𝔄  φArrMap = (λfArr. (λiI. φ iArrMapf))"
    and "cf_up I 𝔄  φHomDom = "
    and "cf_up I 𝔄  φHomCod = (CiI. 𝔄 i)"
  unfolding cf_up_def dghm_field_simps by (simp_all add: nat_omega_simps)


text‹Slicing.›

lemma smcf_dghm_cf_up[slicing_commute]: 
  "smcf_up I (λi. cat_smc (𝔄 i)) (cat_smc ) (λi. cf_smcf (φ i)) = 
    cf_smcf (cf_up I 𝔄  φ)"
  unfolding 
    cat_smc_def 
    cf_smcf_def 
    cf_up_def 
    smcf_up_def 
    cat_prod_def 
    smc_prod_def
    dg_prod_def
    dg_field_simps 
    dghm_field_simps 
  by (simp add: nat_omega_simps)

context
  fixes 𝔄 φ :: "V  V"
    and  :: V
begin

lemmas_with 
  [
    where 𝔄=λi. cat_smc (𝔄 i) and φ=λi. cf_smcf (φ i) and= cat_smc , 
    unfolded slicing_simps slicing_commute
  ]:
  cf_up_ObjMap_vdomain[simp] = smcf_up_ObjMap_vdomain
  and cf_up_ObjMap_app = smcf_up_ObjMap_app
  and cf_up_ObjMap_app_vdomain[simp] = smcf_up_ObjMap_app_vdomain
  and cf_up_ObjMap_app_component = smcf_up_ObjMap_app_component
  and cf_up_ArrMap_vdomain[simp] = smcf_up_ArrMap_vdomain
  and cf_up_ArrMap_app = smcf_up_ArrMap_app
  and cf_up_ArrMap_app_vdomain[simp] = smcf_up_ArrMap_app_vdomain
  and cf_up_ArrMap_app_component = smcf_up_ArrMap_app_component

lemma cf_up_ObjMap_vrange:
  assumes "i. i  I  φ i :  ↦↦Cα𝔄 i"
  shows " (cf_up I 𝔄  φObjMap)  (CiI. 𝔄 i)Obj"
proof
  (
    rule smcf_up_ObjMap_vrange[
      where 𝔄=λi. cat_smc (𝔄 i) 
        and φ=λi. cf_smcf (φ i) 
        and=cat_smc , 
      unfolded slicing_simps slicing_commute
      ]
  )
  fix i assume "i  I"
  then interpret is_functor α  𝔄 i φ i by (rule assms)
  show "cf_smcf (φ i) : cat_smc  ↦↦SMCαcat_smc (𝔄 i)"
    by (rule cf_is_semifunctor)
qed

lemma cf_up_ObjMap_app_vrange:
  assumes "a  Obj" and "i. i  I  φ i :  ↦↦Cα𝔄 i"
  shows "  (cf_up I 𝔄  φObjMapa)  (iI. 𝔄 iObj)"
proof
  (
    rule smcf_up_ObjMap_app_vrange[
      where 𝔄=λi. cat_smc (𝔄 i) 
        and φ=λi. cf_smcf (φ i) 
        and=cat_smc , 
      unfolded slicing_simps slicing_commute
      ]
  )
  show "a  Obj" by (rule assms)
  fix i assume "i  I"
  then interpret is_functor α  𝔄 i φ i by (rule assms(2))
  show "cf_smcf (φ i) : cat_smc  ↦↦SMCαcat_smc (𝔄 i)"
    by (rule cf_is_semifunctor)
qed

lemma cf_up_ArrMap_vrange:
  assumes "i. i  I  φ i :  ↦↦Cα𝔄 i"
  shows " (cf_up I 𝔄  φArrMap)  (CiI. 𝔄 i)Arr"
proof
  (
    rule smcf_up_ArrMap_vrange[
      where 𝔄=λi. cat_smc (𝔄 i) 
        and φ=λi. cf_smcf (φ i) 
        and=cat_smc , 
      unfolded slicing_simps slicing_commute
      ]
  )
  fix i assume "i  I"
  then interpret is_functor α  𝔄 i φ i by (rule assms)
  show "cf_smcf (φ i) : cat_smc  ↦↦SMCαcat_smc (𝔄 i)"
    by (rule cf_is_semifunctor)
qed

lemma cf_up_ArrMap_app_vrange:
  assumes "a  Arr" and "i. i  I  φ i :  ↦↦Cα𝔄 i"
  shows "  (cf_up I 𝔄  φArrMapa)  (iI. 𝔄 iArr)"
proof
  (
    rule smcf_up_ArrMap_app_vrange
      [
        where 𝔄=λi. cat_smc (𝔄 i) 
          and φ=λi. cf_smcf (φ i) 
          and=cat_smc , 
        unfolded slicing_simps slicing_commute
      ]
  )
  fix i assume "i  I"
  then interpret is_functor α  𝔄 i φ i by (rule assms(2))
  show "cf_smcf (φ i) : cat_smc  ↦↦SMCαcat_smc (𝔄 i)"
    by (rule cf_is_semifunctor)
qed (rule assms)

end

context pcategory
begin

interpretation psmc: psemicategory α I λi. cat_smc (𝔄 i) 
  by (rule pcat_psemicategory)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  pcat_smcf_comp_smcf_proj_smcf_up = psmc.psmc_Comp_smcf_proj_smcf_up
  and pcat_smcf_up_eq_smcf_proj = psmc.psmc_smcf_up_eq_smcf_proj

end


subsubsection‹Category product universal property functor is a functor›

lemma (in pcategory) pcat_cf_up_is_functor:
  assumes "category α " and "i. i  I  φ i :  ↦↦Cα𝔄 i"
  shows "cf_up I 𝔄  φ :  ↦↦Cα(CiI. 𝔄 i)"
proof-
  interpret: category α  by (simp add: assms(1))
  interpret 𝔄: category α (CiI. 𝔄 i) by (rule pcat_category_cat_prod)
  show ?thesis
  proof(intro is_functorI)
    show "vfsequence (cf_up I 𝔄  φ)" unfolding cf_up_def by simp
    show "vcard (cf_up I 𝔄  φ) = 4"
      unfolding cf_up_def by (simp add: nat_omega_simps)
    show "cf_smcf (cf_up I 𝔄  φ) : cat_smc  ↦↦SMCαcat_smc (CiI. 𝔄 i)"
      unfolding slicing_commute[symmetric]
      by (rule psemicategory.psmc_smcf_up_is_semifunctor)
        (
          auto simp: 
            assms(2)
            pcat_psemicategory 
            is_functor.cf_is_semifunctor 
            slicing_intros
        )
    show "cf_up I 𝔄  φArrMapCIdc = 
      (CiI. 𝔄 i)CIdcf_up I 𝔄  φObjMapc"
      if "c  Obj" for c
    proof(rule cat_prod_Arr_cong)
      from that is_arrD(1) have CId_c: "CIdc  Arr" 
        by (auto intro: cat_cs_intros)
      from CId_c cf_up_ArrMap_vrange[OF assms(2), simplified]
      show "cf_up I 𝔄  φArrMapCIdc  (CiI. 𝔄 i)Arr"
        unfolding cf_up_components by force
      have cf_up_φ_c: "cf_up I 𝔄  φObjMapc  (CiI. 𝔄 i)Obj"
        unfolding cat_prod_components
      proof(intro vproductI ballI)
        fix i assume prems: "i  I"
        interpret φ: is_functor α  𝔄 i φ i by (simp add: prems assms(2))
        from that show  "cf_up I 𝔄  φObjMapci  𝔄 iObj"
          unfolding cf_up_ObjMap_app_component[OF that prems] 
          by (auto intro: cat_cs_intros)
      qed (simp_all add: cf_up_ObjMap_app that cf_up_ObjMap_app[OF that])
      from 𝔄.cat_CId_is_arr[OF this] show 
        "(CiI. 𝔄 i)CIdcf_up I 𝔄  φObjMapc  (CiI. 𝔄 i)Arr"
        by auto
      fix i assume prems: "i  I"
      interpret φ: is_functor α  𝔄 i φ i by (simp add: prems assms(2))
      from cf_up_φ_c prems show 
        "cf_up I 𝔄  φArrMapCIdci =
          (CiI. 𝔄 i)CIdcf_up I 𝔄  φObjMapci"
        unfolding cf_up_ArrMap_app_component[OF CId_c prems] cat_prod_components
        by 
          (
            simp add: 
              that cf_up_ObjMap_app_component[OF that prems] φ.cf_ObjMap_CId 
          )
    qed 
  qed (auto simp: cf_up_components cat_cs_intros)
qed


subsubsection‹Further properties›

lemma (in pcategory) pcat_Comp_cf_proj_cf_up: 
  assumes "category α " 
    and "i. i  I  φ i :  ↦↦Cα𝔄 i" 
    and "i  I" 
  shows "φ i = πC I 𝔄 i CF (cf_up I 𝔄  φ)"
proof-
  interpret φ: is_functor α  𝔄 i φ i by (rule assms(2)[OF assms(3)])
  interpret π: is_functor α (CiI. 𝔄 i) 𝔄 i πC I 𝔄 i
    by (simp add: assms(3) pcat_cf_proj_is_functor)
  interpret up: is_functor α  (CiI. 𝔄 i) cf_up I 𝔄  φ
    by (simp add: assms(2) φ.HomDom.category_axioms pcat_cf_up_is_functor)
  show ?thesis
  proof(rule cf_smcf_eqI)
    show "πC I 𝔄 i CF cf_up I 𝔄  φ :  ↦↦Cα𝔄 i" 
      by (auto intro: cat_cs_intros)
    from assms show "cf_smcf (φ i) = cf_smcf (πC I 𝔄 i CF cf_up I 𝔄  φ)"
      unfolding slicing_simps slicing_commute[symmetric]
      by 
        (
          intro pcat_smcf_comp_smcf_proj_smcf_up[
            where φ=λi. cf_smcf (φ i), unfolded slicing_commute[symmetric]
            ]
        )
        (auto simp: is_functor.cf_is_semifunctor)
  qed (auto intro: cat_cs_intros)
qed

lemma (in pcategory) pcat_cf_up_eq_cf_proj:
  assumes "𝔉 :  ↦↦Cα(CiI. 𝔄 i)"
    and "i. i  I  φ i = πC I 𝔄 i CF 𝔉"
  shows "cf_up I 𝔄  φ = 𝔉"
proof(rule cf_smcf_eqI)
  interpret 𝔉: is_functor α  (CiI. 𝔄 i) 𝔉 by (rule assms(1))
  show "cf_up I 𝔄  φ :  ↦↦Cα(CiI. 𝔄 i)"
  proof(rule pcat_cf_up_is_functor)
    fix i assume prems: "i  I"
    then interpret π: is_functor α (CiI. 𝔄 i) 𝔄 i πC I 𝔄 i
      by (rule pcat_cf_proj_is_functor)
    show "φ i :  ↦↦Cα𝔄 i" 
      unfolding assms(2)[OF prems] by (auto intro: cat_cs_intros)
  qed (auto intro: cat_cs_intros)
  show "𝔉 :  ↦↦Cα(CiI. 𝔄 i)" by (rule assms(1))
  from assms show "cf_smcf (cf_up I 𝔄  φ) = cf_smcf 𝔉"
    unfolding slicing_commute[symmetric]
    by (intro pcat_smcf_up_eq_smcf_proj) (auto simp: slicing_commute)
qed simp_all



subsection‹Prodfunctor with respect to a fixed argument›

text‹
A prodfunctor is a functor whose domain is a product category. 
It is a generalization of the concept of the bifunctor,
as presented in Chapter II-3 in cite"mac_lane_categories_2010".  
›

definition prodfunctor_proj :: "V  V  (V  V)  V  V  V  V"
  where "prodfunctor_proj 𝔖 I 𝔄 𝔇 J c =
    [
      (λb(CiI - J. 𝔄 i)Obj. 𝔖ObjMapb  c),
      (λf(CiI - J. 𝔄 i)Arr. 𝔖ArrMapf  (CjJ. 𝔄 j)CIdc),
      (CiI - J. 𝔄 i),
      𝔇
    ]"

syntax "_PPRODFUNCTOR_PROJ" :: "V  pttrn  V  V  (V  V)  V  V  V" 
  ((_(3C__-_./_),_/'(/-,_/')) [51, 51, 51, 51, 51, 51, 51] 51)
translations "𝔖CiI-J. 𝔄,𝔇(-,c)"  
  "CONST prodfunctor_proj 𝔖 I (λi. 𝔄) 𝔇 J c"


text‹Components.›

lemma prodfunctor_proj_components:
  shows "(𝔖CiI - J. 𝔄 i,𝔇(-,c))ObjMap = 
      (λb(CiI - J. 𝔄 i)Obj. 𝔖ObjMapb  c)"
    and "(𝔖CiI - J. 𝔄 i,𝔇(-,c))ArrMap = 
      (λf(CiI - J. 𝔄 i)Arr. 𝔖ArrMapf  (CjJ. 𝔄 j)CIdc)"
    and "(𝔖CiI - J. 𝔄 i,𝔇(-,c))HomDom = (CiI - J. 𝔄 i)"
    and "(𝔖CiI - J. 𝔄 i,𝔇(-,c))HomCod = 𝔇"
  unfolding prodfunctor_proj_def dghm_field_simps
  by (simp_all add: nat_omega_simps)


subsubsection‹Object map›

mk_VLambda prodfunctor_proj_components(1)
  |vsv prodfunctor_proj_ObjMap_vsv[cat_cs_intros]|
  |vdomain prodfunctor_proj_ObjMap_vdomain[cat_cs_simps]|
  |app prodfunctor_proj_ObjMap_app[cat_cs_simps]|


subsubsection‹Arrow map›

mk_VLambda prodfunctor_proj_components(2)
  |vsv prodfunctor_proj_ArrMap_vsv[cat_cs_intros]|
  |vdomain prodfunctor_proj_ArrMap_vdomain[cat_cs_simps]|
  |app  prodfunctor_proj_ArrMap_app[cat_cs_simps]|


subsubsection‹Prodfunctor with respect to a fixed argument is a functor›

lemma (in pcategory) pcat_prodfunctor_proj_is_functor: 
  assumes "𝔖 : (CiI. 𝔄 i) ↦↦Cα𝔇" 
    and "c  (CjJ. 𝔄 j)Obj"
    and "J  I"
  shows "(𝔖CiI - J. 𝔄 i,𝔇(-,c)) : (CiI - J. 𝔄 i) ↦↦Cα𝔇"
proof-

  interpret is_functor α (CiI. 𝔄 i) 𝔇 𝔖 by (rule assms(1))
  interpret 𝔄: pcategory α J 𝔄
    using assms(3) by (intro pcat_vsubset_index_pcategory) auto
  interpret J_𝔄: category α CiJ. 𝔄 i by (rule 𝔄.pcat_category_cat_prod)
  interpret IJ: pcategory α I - J 𝔄
    using assms(3) by (intro pcat_vsubset_index_pcategory) auto
  interpret IJ_𝔄: category α CiI - J. 𝔄 i
    by (rule IJ.pcat_category_cat_prod)

  let ?IJ𝔄 = (CiI - J. 𝔄 i)

  from assms(2) have "c  (jJ. 𝔄 jObj)"
    unfolding cat_prod_components by simp
  then have "(jJ. 𝔄 jObj)  0" by (auto intro!: cat_cs_intros)

  show ?thesis
  proof(intro is_functorI', unfold prodfunctor_proj_components)

    show "vfsequence (prodfunctor_proj 𝔖 I 𝔄 𝔇 J c)"
      unfolding prodfunctor_proj_def by simp
    show "vcard (prodfunctor_proj 𝔖 I 𝔄 𝔇 J c) = 4"
      unfolding prodfunctor_proj_def by (simp add: nat_omega_simps)

    show " (λb?IJ𝔄Obj. 𝔖ObjMapb  c)  𝔇Obj"
    proof(intro vsubsetI)
      fix x assume "x   (λb?IJ𝔄Obj. 𝔖ObjMapb  c)"
      then obtain b where x_def: "x = 𝔖ObjMapb  c" and b: "b  ?IJ𝔄Obj"  
        by auto
      have "b  c  cat_prod I 𝔄Obj"
      proof(rule cat_prod_vdiff_vunion_Obj_in_Obj)
        show "b  ?IJ𝔄Obj" by (rule b)
      qed (intro assms(2,3))+
      then show "x  𝔇Obj" unfolding x_def by (auto intro: cat_cs_intros)
    qed

    show is_arr:
      "(λf?IJ𝔄Arr. 𝔖ArrMapf  cat_prod J 𝔄CIdc)f : 
        (λb?IJ𝔄Obj. 𝔖ObjMapb  c)a 𝔇(λb?IJ𝔄Obj. 𝔖ObjMapb  c)b"
      (is ?V_f: ?V_a 𝔇?V_b)
      if "f : a ?IJ𝔄b" for f a b
    proof-
      let ?fc = f  cat_prod J 𝔄CIdc
      have "?fc : a  c cat_prod I 𝔄b  c"
      proof(rule pcat_cat_prod_vdiff_vunion_is_arr)
        show "f : a ?IJ𝔄b" by (rule that)
      qed (auto simp: assms cat_cs_intros)
      then have "𝔖ArrMap?fc : 𝔖ObjMapa  c 𝔇𝔖ObjMapb  c"
        by (auto intro: cat_cs_intros)
      moreover from that have "f  ?IJ𝔄Arr" "a  ?IJ𝔄Obj" "b  ?IJ𝔄Obj"
        by (auto intro: cat_cs_intros) 
      ultimately show ?thesis by simp
    qed

    show 
      "(λf?IJ𝔄Arr. 𝔖ArrMapf  cat_prod J 𝔄CIdc)g A?IJ𝔄f =
      (λf?IJ𝔄Arr. 𝔖ArrMapf  cat_prod J 𝔄CIdc)g A𝔇(λf?IJ𝔄Arr. 𝔖ArrMapf  cat_prod J 𝔄CIdc)f"
      if "g : b' ?IJ𝔄c'" and "f : a' ?IJ𝔄b'" for g b' c' f a'
    proof-
      from that have gf: "g A?IJ𝔄f : a' ?IJ𝔄c'" 
        by (auto intro: cat_cs_intros)
      from assms(2) have CId_c: "cat_prod J 𝔄CIdc : c cat_prod J 𝔄c" 
        by (auto intro: cat_cs_intros)
      then have [simp]:  
        "cat_prod J 𝔄CIdc Acat_prod J 𝔄cat_prod J 𝔄CIdc = 
          cat_prod J 𝔄CIdc"
        by (auto simp: cat_cs_simps)
      from assms(3) that(1) CId_c have g_CId_c:
        "g  cat_prod J 𝔄CIdc : b'  c cat_prod I 𝔄c'  c"
        by (rule pcat_cat_prod_vdiff_vunion_is_arr)
      from assms(3) that(2) CId_c have f_CId_c:
        "f  cat_prod J 𝔄CIdc : a'  c cat_prod I 𝔄b'  c"
        by (rule pcat_cat_prod_vdiff_vunion_is_arr)
      have 
        "𝔖ArrMap(g A?IJ𝔄f)  cat_prod J 𝔄CIdc = 
          𝔖ArrMapg  cat_prod J 𝔄CIdc A𝔇𝔖ArrMapf  cat_prod J 𝔄CIdc"
        unfolding 
          pcat_cat_prod_vdiff_vunion_Comp[
            OF assms(3) that(1) CId_c that(2) CId_c, simplified
            ]
        by (intro cf_ArrMap_Comp[OF g_CId_c f_CId_c])
      moreover from gf have "g A?IJ𝔄f  ?IJ𝔄Arr" by auto
      moreover from that have "g  ?IJ𝔄Arr" "f  ?IJ𝔄Arr" by auto
      ultimately show ?thesis by simp
    qed

    show 
      "(λf?IJ𝔄Arr. 𝔖ArrMapf  cat_prod J 𝔄CIdc)?IJ𝔄CIdc' = 
        𝔇CId(λb?IJ𝔄Obj. 𝔖ObjMapb  c)c'"
      if "c'  ?IJ𝔄Obj" for c'
    proof-
      have "?IJ𝔄CIdc'  cat_prod J 𝔄CIdc = cat_prod I 𝔄CIdc'  c"
        unfolding pcat_cat_prod_vdiff_vunion_CId[OF assms(3) that assms(2)] ..
      moreover from assms(3) that assms(2) have "c'  c  cat_prod I 𝔄Obj"
        by (rule cat_prod_vdiff_vunion_Obj_in_Obj)
      ultimately have "𝔖ArrMap?IJ𝔄CIdc'  cat_prod J 𝔄CIdc =
        𝔇CId𝔖ObjMapc'  c"
        by (auto intro: cat_cs_intros) 
      moreover from that have CId_c': "?IJ𝔄CIdc'  ?IJ𝔄Arr"
        by (auto dest!: IJ_𝔄.cat_CId_is_arr)
      ultimately show ?thesis by (simp add: that)
    qed

  qed (auto intro: cat_cs_intros) 

qed

lemma (in pcategory) pcat_prodfunctor_proj_is_functor': 
  assumes "𝔖 : (CiI. 𝔄 i) ↦↦Cα𝔇" 
    and "c  (CjJ. 𝔄 j)Obj"
    and "J  I"
    and "𝔄' = (CiI - J. 𝔄 i)"
    and "𝔅' = 𝔇"
  shows "(𝔖CiI - J. 𝔄 i,𝔇(-,c)) : 𝔄' ↦↦Cα𝔅'"
  using assms(1-3)
  unfolding assms(4,5)
  by (rule pcat_prodfunctor_proj_is_functor)

lemmas [cat_cs_intros] = pcategory.pcat_prodfunctor_proj_is_functor'



subsection‹Singleton category›


subsubsection‹Slicing›

context
  fixes  :: V
begin

lemmas_with [where=cat_smc , unfolded slicing_simps slicing_commute]:
  cat_singleton_ObjI = smc_singleton_ObjI
  and cat_singleton_ObjE = smc_singleton_ObjE
  and cat_singleton_ArrI = smc_singleton_ArrI
  and cat_singleton_ArrE = smc_singleton_ArrE

end

context category
begin

interpretation smc: semicategory α cat_smc  by (rule cat_semicategory)

lemmas_with [unfolded slicing_simps slicing_commute]:
  cat_finite_psemicategory_cat_singleton = 
    smc.smc_finite_psemicategory_smc_singleton
  and cat_singleton_is_arrI = smc.smc_singleton_is_arrI
  and cat_singleton_is_arrD = smc.smc_singleton_is_arrD
  and cat_singleton_is_arrE = smc.smc_singleton_is_arrE

end


subsubsection‹Identity›

lemma cat_singleton_CId_app: 
  assumes "set {j, a}  (Ciset {j}. )Obj"
  shows "(Ciset {j}. )CIdset {j, a} = set {j, CIda}"
  using assms unfolding cat_prod_components VLambda_vsingleton by simp


subsubsection‹Singleton category is a category›

lemma (in category) cat_finite_pcategory_cat_singleton: 
  assumes "j  Vset α"
  shows "finite_pcategory α (set {j}) (λi. )"
  by 
    (
      auto intro: 
        assms
        category_axioms 
        finite_pcategory_finite_psemicategoryI 
        cat_finite_psemicategory_cat_singleton 
    )

lemma (in category) cat_category_cat_singleton:
  assumes "j  Vset α"
  shows "category α (Ciset {j}. )"
proof-
  interpret finite_pcategory α set {j} λi. 
    using assms by (rule cat_finite_pcategory_cat_singleton)
  show ?thesis by (rule pcat_category_cat_prod)
qed



subsection‹Singleton functor›


subsubsection‹Definition and elementary properties›

definition cf_singleton :: "V  V  V"
  where "cf_singleton j  =
    [
      (λaObj. set {j, a}),
      (λfArr. set {j, f}),
      ,
      (Ciset {j}. )
    ]"


text‹Components.›

lemma cf_singleton_components:
  shows "cf_singleton j ObjMap = (λaObj. set {j, a})"
    and "cf_singleton j ArrMap = (λfArr. set {j, f})"
    and "cf_singleton j HomDom = "
    and "cf_singleton j HomCod = (Ciset {j}. )"
  unfolding cf_singleton_def dghm_field_simps by (simp_all add: nat_omega_simps)


text‹Slicing.›

lemma cf_smcf_cf_singleton[slicing_commute]: 
  "smcf_singleton j (cat_smc )= cf_smcf (cf_singleton j )"
  unfolding smcf_singleton_def cf_singleton_def slicing_simps slicing_commute
  by 
    (
      simp add: 
        nat_omega_simps dghm_field_simps dg_field_simps cat_smc_def cf_smcf_def
     )

context
  fixes  :: V
begin

lemmas_with [where=cat_smc , unfolded slicing_simps slicing_commute]:
  cf_singleton_ObjMap_vsv[cat_cs_intros] = smcf_singleton_ObjMap_vsv
  and cf_singleton_ObjMap_vdomain[cat_cs_simps] = smcf_singleton_ObjMap_vdomain
  and cf_singleton_ObjMap_vrange = smcf_singleton_ObjMap_vrange
  and cf_singleton_ObjMap_app[cat_prod_cs_simps] = smcf_singleton_ObjMap_app
  and cf_singleton_ArrMap_vsv[cat_cs_intros] = smcf_singleton_ArrMap_vsv
  and cf_singleton_ArrMap_vdomain[cat_cs_simps] = smcf_singleton_ArrMap_vdomain
  and cf_singleton_ArrMap_vrange = smcf_singleton_ArrMap_vrange
  and cf_singleton_ArrMap_app[cat_prod_cs_simps] = smcf_singleton_ArrMap_app

end


subsubsection‹Singleton functor is an isomorphism of categories›

lemma (in category) cat_cf_singleton_is_functor:
  assumes "j  Vset α"
  shows "cf_singleton j  :  ↦↦C.isoα(Ciset {j}. )"
proof(intro is_iso_functorI is_functorI)
  from assms show smcf_singleton: "cf_smcf (cf_singleton j ) : 
    cat_smc  ↦↦SMC.isoαcat_smc (Ciset {j}. )"
    unfolding slicing_commute[symmetric]
    by (intro semicategory.smc_smcf_singleton_is_iso_semifunctor) 
      (auto intro: smc_cs_intros slicing_intros)
  show "vfsequence (cf_singleton j )" unfolding cf_singleton_def by simp
  show "vcard (cf_singleton j ) = 4"
    unfolding cf_singleton_def by (simp add: nat_omega_simps)
  show "cf_smcf (cf_singleton j ) : 
    cat_smc  ↦↦SMCαcat_smc (Ciset {j}. )"
    by (intro is_iso_semifunctor.axioms(1) smcf_singleton)
  show "cf_singleton j ArrMapCIdc = 
    (Ciset {j}. )CIdcf_singleton j ObjMapc"
    if "c  Obj" for c 
  proof-
    from that have CId_c: "CIdc : c c" by (auto simp: cat_cs_intros)
    have "set {j, c}  (Ciset {j}. )Obj"
      by (simp add: cat_singleton_ObjI that)
    with that have "(Ciset {j}. )CIdcf_singleton j ObjMapc = 
      set {j, CIdc}"
      by (simp add: cf_singleton_ObjMap_app cat_singleton_CId_app)
    moreover from CId_c have 
      "cf_singleton j ArrMapCIdc = set {j, CIdc}"
      by (auto simp: cf_singleton_ArrMap_app cat_cs_intros)
    ultimately show ?thesis by simp
  qed
qed 
  (
    auto simp: 
      cat_cs_intros assms cat_category_cat_singleton cf_singleton_components 
  )



subsection‹Product of two categories›


subsubsection‹Definition and elementary properties.›


text‹See Chapter II-3 in cite"mac_lane_categories_2010".›

definition cat_prod_2 :: "V  V  V" (infixr ×C 80)
  where "𝔄 ×C 𝔅  cat_prod (2) (λi. if i = 0 then 𝔄 else 𝔅)"


text‹Slicing.›
  
lemma cat_smc_cat_prod_2[slicing_commute]: 
  "cat_smc 𝔄 ×SMC cat_smc 𝔅 = cat_smc (𝔄 ×C 𝔅)"
  unfolding cat_prod_2_def smc_prod_2_def slicing_commute[symmetric] if_distrib
  by simp

context 
  fixes α 𝔄 𝔅
  assumes 𝔄: "category α 𝔄" and 𝔅: "category α 𝔅"
begin

interpretation 𝔄: category α 𝔄 by (rule 𝔄)
interpretation 𝔅: category α 𝔅 by (rule 𝔅)

lemmas_with 
  [
    where 𝔄=cat_smc 𝔄 and 𝔅=cat_smc 𝔅, 
    unfolded slicing_simps slicing_commute, 
    OF 𝔄.cat_semicategory 𝔅.cat_semicategory
  ]:
  cat_prod_2_ObjI = smc_prod_2_ObjI 
  and cat_prod_2_ObjI'[cat_prod_cs_intros] = smc_prod_2_ObjI'
  and cat_prod_2_ObjE = smc_prod_2_ObjE
  and cat_prod_2_ArrI = smc_prod_2_ArrI
  and cat_prod_2_ArrI'[cat_prod_cs_intros] = smc_prod_2_ArrI'
  and cat_prod_2_ArrE = smc_prod_2_ArrE
  and cat_prod_2_is_arrI = smc_prod_2_is_arrI
  and cat_prod_2_is_arrI'[cat_prod_cs_intros] = smc_prod_2_is_arrI'
  and cat_prod_2_is_arrE = smc_prod_2_is_arrE
  and cat_prod_2_Dom_vsv = smc_prod_2_Dom_vsv
  and cat_prod_2_Dom_vdomain[cat_cs_simps] = smc_prod_2_Dom_vdomain
  and cat_prod_2_Dom_app[cat_prod_cs_simps] = smc_prod_2_Dom_app
  and cat_prod_2_Dom_vrange = smc_prod_2_Dom_vrange
  and cat_prod_2_Cod_vsv = smc_prod_2_Cod_vsv
  and cat_prod_2_Cod_vdomain[cat_cs_simps] = smc_prod_2_Cod_vdomain
  and cat_prod_2_Cod_app[cat_prod_cs_simps] = smc_prod_2_Cod_app
  and cat_prod_2_Cod_vrange = smc_prod_2_Cod_vrange
  and cat_prod_2_op_cat_cat_Obj[cat_op_simps] = smc_prod_2_op_smc_smc_Obj
  and cat_prod_2_cat_op_cat_Obj[cat_op_simps] = smc_prod_2_smc_op_smc_Obj
  and cat_prod_2_op_cat_cat_Arr[cat_op_simps] = smc_prod_2_op_smc_smc_Arr
  and cat_prod_2_cat_op_cat_Arr[cat_op_simps] = smc_prod_2_smc_op_smc_Arr

lemmas_with 
  [
    where 𝔄=cat_smc 𝔄 and 𝔅=cat_smc 𝔅, 
    unfolded slicing_simps slicing_commute, 
    OF 𝔄.cat_semicategory 𝔅.cat_semicategory
  ]:
  cat_prod_2_Comp_app[cat_prod_cs_simps] = smc_prod_2_Comp_app

end


subsubsection‹Product of two categories is a category›

context 
  fixes α 𝔄 𝔅
  assumes 𝔄: "category α 𝔄" and 𝔅: "category α 𝔅"
begin

interpretation 𝒵 α by (rule categoryD[OF 𝔄])
interpretation 𝔄: category α 𝔄 by (rule 𝔄)
interpretation 𝔅: category α 𝔅 by (rule 𝔅)

lemma finite_pcategory_cat_prod_2: "finite_pcategory α (2) (if2 𝔄 𝔅)"
proof(intro finite_pcategoryI pcategory_baseI)
  from Axiom_of_Infinity show z1_in_Vset: "2  Vset α" by blast
  show "category α (i = 0 ? 𝔄 : 𝔅)" if "i  2" for i
    by (auto simp: cat_cs_intros)
qed auto

interpretation finite_pcategory α 2 if2 𝔄 𝔅
  by (intro finite_pcategory_cat_prod_2 𝔄 𝔅)

lemma category_cat_prod_2[cat_cs_intros]: "category α (𝔄 ×C 𝔅)"
  unfolding cat_prod_2_def by (rule pcat_category_cat_prod)

end


subsubsection‹Identity›

lemma cat_prod_2_CId_vsv[cat_cs_intros]: "vsv ((𝔄 ×C 𝔅)CId)"
  unfolding cat_prod_2_def cat_prod_components by simp

lemma cat_prod_2_CId_vdomain[cat_cs_simps]: 
  "𝒟 ((𝔄 ×C 𝔅)CId) = (𝔄 ×C 𝔅)Obj"
  unfolding cat_prod_2_def cat_prod_components by simp

context 
  fixes α 𝔄 𝔅
  assumes 𝔄: "category α 𝔄" and 𝔅: "category α 𝔅"
begin

interpretation 𝔄: category α 𝔄 by (rule 𝔄)
interpretation 𝔅: category α 𝔅 by (rule 𝔅)

interpretation finite_pcategory α 2 (λi. if i = 0 then 𝔄 else 𝔅)
  by (intro finite_pcategory_cat_prod_2 𝔄 𝔅)

lemma cat_prod_2_CId_app[cat_prod_cs_simps]:
  assumes "[a, b]  (𝔄 ×C 𝔅)Obj"
  shows "(𝔄 ×C 𝔅)CIda, b = [𝔄CIda, 𝔅CIdb]"
proof-
  have "(𝔄 ×C 𝔅)CIda, b = 
    (λi2. (if i = 0 then 𝔄 else 𝔅)CId[a, b]i)"
    by 
      (
        rule 
          cat_prod_CId_app[
            OF assms[unfolded cat_prod_2_def], folded cat_prod_2_def
            ]
      )
  also have 
    "(λi2. (if i = 0 then 𝔄 else 𝔅)CId[a, b]i) = 
      [𝔄CIda, 𝔅CIdb]"
  proof(rule vsv_eqI, unfold vdomain_VLambda)
    fix i assume "i  2"
    then consider i = 0 | i = 1 unfolding two by auto
    then show 
      "(λi2. (if i = 0 then 𝔄 else 𝔅)CId[a, b]i)i = 
        [𝔄CIda, 𝔅CIdb]i"
      by cases (simp_all add: two nat_omega_simps)
  qed (auto simp: two nat_omega_simps)
  finally show ?thesis by simp
qed

lemma cat_prod_2_CId_vrange: " ((𝔄 ×C 𝔅)CId)  (𝔄 ×C 𝔅)Arr"
proof(rule vsv.vsv_vrange_vsubset, unfold cat_cs_simps)
  show "vsv ((𝔄 ×C 𝔅)CId)" by (rule cat_prod_2_CId_vsv)
  fix ab assume "ab  (𝔄 ×C 𝔅)Obj"
  then obtain a b where ab_def: "ab = [a, b]" 
    and a: "a  𝔄Obj" 
    and b: "b  𝔅Obj"
    by (elim cat_prod_2_ObjE[OF 𝔄 𝔅])
  from 𝔄 𝔅 a b show "(𝔄 ×C 𝔅)CIdab  (𝔄 ×C 𝔅)Arr"
    unfolding ab_def by (cs_concl cs_intro: cat_cs_intros cat_prod_cs_intros)
qed

end


subsubsection‹Opposite product category›

context 
  fixes α 𝔄 𝔅
  assumes 𝔄: "category α 𝔄" and 𝔅: "category α 𝔅"
begin

interpretation 𝔄: category α 𝔄 by (rule 𝔄)
interpretation 𝔅: category α 𝔅 by (rule 𝔅)

lemma op_smc_smc_prod_2[smc_op_simps]: 
  "op_cat (𝔄 ×C 𝔅) = op_cat 𝔄 ×C op_cat 𝔅"
proof(rule cat_smc_eqI [of α])
  from 𝔄 𝔅 show cat_lhs: "category α (op_cat (𝔄 ×C 𝔅))"
    by 
      (
        cs_concl cs_shallow
          cs_simp: cat_op_simps cs_intro