Theory CZH_SMC_PSemicategory

(* Copyright 2021 (C) Mihails Milehins *)

section‹Product semicategory›
theory CZH_SMC_PSemicategory
  imports 
    CZH_SMC_Semifunctor
    CZH_SMC_Small_Semicategory
    CZH_DG_PDigraph
begin



subsection‹Background›


text‹
The concept of a product semicategory, as presented in this work, 
is a generalization of the concept of a product category, as presented in
Chapter II-3 in cite"mac_lane_categories_2010".
›

named_theorems smc_prod_cs_simps
named_theorems smc_prod_cs_intros



subsection‹Product semicategory: definition and elementary properties›

definition smc_prod :: "V  (V  V)  V" 
  where "smc_prod I 𝔄 = 
    [
      (iI. 𝔄 iObj), 
      (iI. 𝔄 iArr), 
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iDomfi)), 
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iCodfi)),
      (λgfcomposable_arrs (dg_prod I 𝔄). (λiI. gf0i A𝔄 igf1i))
    ]"

syntax "_PSEMICATEGORY" :: "pttrn  V  (V  V)  V" 
  ((3SMC__./ _) [0, 0, 10] 10)
syntax_consts "_PSEMICATEGORY"  smc_prod
translations "SMCiI. 𝔄"  "CONST smc_prod I (λi. 𝔄)"


text‹Components.›

lemma smc_prod_components:
  shows "(SMCiI. 𝔄 i)Obj = (iI. 𝔄 iObj)"
    and "(SMCiI. 𝔄 i)Arr = (iI. 𝔄 iArr)"
    and "(SMCiI. 𝔄 i)Dom = 
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iDomfi))"
    and "(SMCiI. 𝔄 i)Cod = 
      (λf(iI. 𝔄 iArr). (λiI. 𝔄 iCodfi))"
    and "(SMCiI. 𝔄 i)Comp = 
      (λgfcomposable_arrs (dg_prod I 𝔄). (λiI. gf0i A𝔄 igf1i))"
  unfolding smc_prod_def dg_field_simps by (simp_all add: nat_omega_simps)


text‹Slicing.›

lemma smc_dg_smc_prod[slicing_commute]: 
  "dg_prod I (λi. smc_dg (𝔄 i)) = smc_dg (smc_prod I 𝔄)"
  unfolding dg_prod_def smc_dg_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. smc_dg (𝔄 i), unfolded slicing_simps slicing_commute]:
  smc_prod_ObjI = dg_prod_ObjI
  and smc_prod_ObjD = dg_prod_ObjD
  and smc_prod_ObjE = dg_prod_ObjE
  and smc_prod_Obj_cong = dg_prod_Obj_cong
  and smc_prod_ArrI = dg_prod_ArrI
  and smc_prod_ArrD = dg_prod_ArrD
  and smc_prod_ArrE = dg_prod_ArrE
  and smc_prod_Arr_cong = dg_prod_Arr_cong
  and smc_prod_Dom_vsv[smc_cs_intros] = dg_prod_Dom_vsv
  and smc_prod_Dom_vdomain[smc_cs_simps] = dg_prod_Dom_vdomain
  and smc_prod_Dom_app = dg_prod_Dom_app
  and smc_prod_Dom_app_component_app[smc_cs_simps] = 
    dg_prod_Dom_app_component_app
  and smc_prod_Cod_vsv[smc_cs_intros] = dg_prod_Cod_vsv
  and smc_prod_Cod_app = dg_prod_Cod_app
  and smc_prod_Cod_vdomain[smc_cs_simps] = dg_prod_Cod_vdomain
  and smc_prod_Cod_app_component_app[smc_cs_simps] = 
    dg_prod_Cod_app_component_app
  and smc_prod_vunion_Obj_in_Obj = dg_prod_vunion_Obj_in_Obj
  and smc_prod_vdiff_vunion_Obj_in_Obj = dg_prod_vdiff_vunion_Obj_in_Obj
  and smc_prod_vunion_Arr_in_Arr = dg_prod_vunion_Arr_in_Arr
  and smc_prod_vdiff_vunion_Arr_in_Arr = dg_prod_vdiff_vunion_Arr_in_Arr

end

lemma smc_prod_dg_prod_is_arr: 
  "g : b DGiI. 𝔄 ic  g : b SMCiI. 𝔄 ic"
  unfolding is_arr_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 (DGiI. 𝔄 i) = composable_arrs (SMCiI. 𝔄 i)"
  unfolding composable_arrs_def smc_prod_dg_prod_is_arr by simp



subsection‹Local assumptions for a product semicategory›

locale psemicategory_base = 𝒵 α for α I 𝔄 +
  assumes psmc_semicategories[smc_prod_cs_intros]: 
    "i  I  semicategory α (𝔄 i)"
    and psmc_index_in_Vset[smc_cs_intros]: "I  Vset α"


text‹Rules.›

lemma (in psemicategory_base) psemicategory_base_axioms'[smc_prod_cs_intros]: 
  assumes "α' = α" and "I' = I"
  shows "psemicategory_base α' I' 𝔄"
  unfolding assms by (rule psemicategory_base_axioms)

mk_ide rf psemicategory_base_def[unfolded psemicategory_base_axioms_def]
  |intro psemicategory_baseI|
  |dest psemicategory_baseD[dest]|
  |elim psemicategory_baseE[elim]|

lemma psemicategory_base_pdigraph_baseI:
  assumes "pdigraph_base α I (λi. smc_dg (𝔄 i))" 
    and "i. i  I  semicategory α (𝔄 i)"
  shows "psemicategory_base α I 𝔄"
proof-
  interpret pdigraph_base α I λi. smc_dg (𝔄 i)
    rewrites "smc_dg ℭ'Obj = ℭ'Obj" and "smc_dg ℭ'Arr = ℭ'Arr" for ℭ'
    by (rule assms(1)) (simp_all add: slicing_simps)
  show ?thesis
    by (intro psemicategory_baseI)
      (auto simp: assms(2) pdg_index_in_Vset pdg_Obj_in_Vset pdg_Arr_in_Vset) 
qed


text‹Product semicategory is a product digraph.›

context psemicategory_base
begin

lemma psmc_pdigraph_base: "pdigraph_base α I (λi. smc_dg (𝔄 i))"
proof(intro pdigraph_baseI)
  show "digraph α (smc_dg (𝔄 i))" if "i  I" for i 
    by 
      (
        use that in 
          cs_concl cs_shallow cs_intro: slicing_intros smc_prod_cs_intros
      )
  show "I  Vset α" by (cs_concl cs_shallow cs_intro: smc_cs_intros)
qed auto

interpretation pdg: pdigraph_base α I λi. smc_dg (𝔄 i) 
  by (rule psmc_pdigraph_base)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  psmc_Obj_in_Vset = pdg.pdg_Obj_in_Vset
  and psmc_Arr_in_Vset = pdg.pdg_Arr_in_Vset
  and psmc_smc_prod_Obj_in_Vset = pdg.pdg_dg_prod_Obj_in_Vset
  and psmc_smc_prod_Arr_in_Vset = pdg.pdg_dg_prod_Arr_in_Vset
  and smc_prod_Dom_app_in_Obj[smc_cs_intros] = pdg.dg_prod_Dom_app_in_Obj
  and smc_prod_Cod_app_in_Obj[smc_cs_intros] = pdg.dg_prod_Cod_app_in_Obj
  and smc_prod_is_arrI = pdg.dg_prod_is_arrI
  and smc_prod_is_arrD[dest] = pdg.dg_prod_is_arrD
  and smc_prod_is_arrE[elim] = pdg.dg_prod_is_arrE

end

lemmas [smc_cs_intros] = psemicategory_base.smc_prod_is_arrD(7)


text‹Elementary properties.›

lemma (in psemicategory_base) psmc_vsubset_index_psemicategory_base:
  assumes "J  I"
  shows "psemicategory_base α J 𝔄"
proof(intro psemicategory_baseI)
  show "semicategory α (𝔄 i)" if "i  J" for i 
    using that assms by (auto intro: smc_prod_cs_intros)
  from assms show "J  Vset α" by (simp add: vsubset_in_VsetI smc_cs_intros)
qed auto


subsubsection‹Composition›

lemma smc_prod_Comp:
  "(SMCiI. 𝔄 i)Comp = 
    (
      λgfcomposable_arrs (SMCiI. 𝔄 i). 
        (λiI. gf0i A𝔄 igf1i)
    )"
  unfolding smc_prod_components smc_prod_composable_arrs_dg_prod by simp

lemma smc_prod_Comp_vdomain[smc_cs_simps]: 
  "𝒟 ((SMCiI. 𝔄 i)Comp) = composable_arrs (SMCiI. 𝔄 i)" 
  unfolding smc_prod_Comp by simp

lemma smc_prod_Comp_app: 
  assumes "g : b SMCiI. 𝔄 ic" and "f : a SMCiI. 𝔄 ib"
  shows "g A(SMCiI. 𝔄 i)f = (λiI. gi A𝔄 ifi)" 
proof-
  from assms have "[g, f]  composable_arrs (SMCiI. 𝔄 i)" 
    by (auto intro: smc_cs_intros)  
  then show ?thesis unfolding smc_prod_Comp by (auto simp: nat_omega_simps)
qed

lemma smc_prod_Comp_app_component[smc_cs_simps]: 
  assumes "g : b SMCiI. 𝔄 ic" 
    and "f : a SMCiI. 𝔄 ib"
    and "i  I"
  shows "(g A(SMCiI. 𝔄 i)f)i = gi A𝔄 ifi"
  using assms(3) unfolding smc_prod_Comp_app[OF assms(1,2)] by simp

lemma (in psemicategory_base) smc_prod_Comp_vrange: 
  " ((SMCiI. 𝔄 i)Comp)  (SMCiI. 𝔄 i)Arr" 
proof(intro vsubsetI)
  fix h assume prems: "h   ((SMCiI. 𝔄 i)Comp)"
  then obtain gf 
    where h_def: "h = (SMCiI. 𝔄 i)Compgf" 
      and "gf  composable_arrs (SMCiI. 𝔄 i)"
    by (auto simp: smc_prod_Comp intro: smc_cs_intros)
  then obtain g f a b c 
    where gf_def: "gf = [g, f]" 
      and g: "g : b SMCiI. 𝔄 ic" 
      and f: "f : a SMCiI. 𝔄 ib"
    by clarsimp
  from g f have gf_comp: "g A(SMCiI. 𝔄 i)f = (λiI. gi A𝔄 ifi)"
    by (rule smc_prod_Comp_app)
  show "h  (SMCiI. 𝔄 i)Arr"
    unfolding smc_prod_components
    unfolding h_def gf_def gf_comp
  proof(rule VLambda_in_vproduct)
    fix i assume prems: "i  I"
    interpret semicategory α 𝔄 i 
      using prems by (simp add: smc_prod_cs_intros)
    from prems smc_prod_is_arrD(7)[OF g] smc_prod_is_arrD(7)[OF f] have
      "gi A𝔄 ifi : ai 𝔄 ici" 
      by (auto intro: smc_cs_intros)
    then show "gi A𝔄 ifi  𝔄 iArr" by (simp add: smc_cs_intros)
  qed
qed

lemma smc_prod_Comp_app_vdomain[smc_cs_simps]:
  assumes "g : b SMCiI. 𝔄 ic" and "f : a SMCiI. 𝔄 ib"
  shows "𝒟 (g A(SMCiI. 𝔄 i)f) = I" 
  unfolding smc_prod_Comp_app[OF assms] by simp


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

lemma (in psemicategory_base) psmc_tiny_semicategory_smc_prod:
  assumes "𝒵 β" and "α  β" 
  shows "tiny_semicategory β (SMCiI. 𝔄 i)"
proof(intro tiny_semicategoryI, (unfold slicing_simps)?)

  show "tiny_digraph β (smc_dg (smc_prod I 𝔄))"
    unfolding slicing_commute[symmetric]
    by 
      (
        intro pdigraph_base.pdg_tiny_digraph_dg_prod; 
        (rule assms psmc_pdigraph_base)?
      )

  show "vfsequence (SMCiI. 𝔄 i)" unfolding smc_prod_def by auto
  show "vcard (SMCiI. 𝔄 i) = 5"
    unfolding smc_prod_def by (simp add: nat_omega_simps)
  show "vsv ((SMCiI. 𝔄 i)Comp)" unfolding smc_prod_Comp by simp
  
  show
    "(gf  𝒟 ((SMCiI. 𝔄 i)Comp)) 
      (
        g f b c a. 
          gf = [g, f]  g : b smc_prod I 𝔄c  f : a smc_prod I 𝔄b
      )"
    for gf
    by (auto intro: smc_cs_intros simp: smc_cs_simps)
  
  show Comp_is_arr[intro]: "g A(SMCiI. 𝔄 i)f : a SMCiI. 𝔄 ic"
    if "g : b SMCiI. 𝔄 ic" and "f : a SMCiI. 𝔄 ib" 
    for g b c f a
  proof(intro smc_prod_is_arrI)
    from that show "vsv (g Asmc_prod I 𝔄f)" 
      by (auto simp: smc_prod_Comp_app)
    from that show "𝒟 (g Asmc_prod I 𝔄f) = I"
      by (auto simp: smc_prod_Comp_app)
    from that(2) have f: "f  (SMCiI. 𝔄 i)Arr"
      by (elim is_arrE) (auto simp: smc_prod_components)
    from that(1) have g: "g  (SMCiI. 𝔄 i)Arr"
      by (elim is_arrE) (auto simp: smc_prod_components)
    from f have a: "a  (SMCiI. 𝔄 i)Obj"
      by (rule smc_prod_Dom_app_in_Obj[of f, unfolded is_arrD(2)[OF that(2)]])
    then show "vsv a" by (auto simp: smc_prod_components)
    from a show "𝒟 a = I" by (auto simp: smc_prod_components)
    from g have c: "c  (SMCiI. 𝔄 i)Obj"
      by (rule smc_prod_Cod_app_in_Obj[of g, unfolded is_arrD(3)[OF that(1)]])
    then show "vsv c" by (auto simp: smc_prod_components)
    from c show "𝒟 c = I" by (auto simp: smc_prod_components)
    fix i assume prems: "i  I"
    interpret semicategory α 𝔄 i 
      using prems by (auto intro: smc_prod_cs_intros)
    from 
      prems 
      smc_prod_is_arrD(7)[OF that(1) prems] 
      smc_prod_is_arrD(7)[OF that(2) prems] 
    show "(g Asmc_prod I 𝔄f)i : ai 𝔄 ici"
      unfolding smc_prod_Comp_app[OF that] by (auto intro: smc_cs_intros)
  qed
  
  show 
    "h Asmc_prod I 𝔄g Asmc_prod I 𝔄f =
      h Asmc_prod I 𝔄(g Asmc_prod I 𝔄f)"
    if "h : c smc_prod I 𝔄d"
      and "g : b smc_prod I 𝔄c"
      and "f : a smc_prod I 𝔄b"
    for h c d g b f a
  proof(rule smc_prod_Arr_cong)
    show "(h Asmc_prod I 𝔄g) Asmc_prod I 𝔄f  (SMCiI. 𝔄 i)Arr"
      by (meson that Comp_is_arr is_arrD)
    show "h Asmc_prod I 𝔄(g Asmc_prod I 𝔄f)  smc_prod I 𝔄Arr"
      by (meson that Comp_is_arr is_arrD)
    fix i assume prems: "i  I"
    then interpret semicategory α 𝔄 i by (simp add: smc_prod_cs_intros)
    from prems that have "hi : ci 𝔄 idi"
      and "gi : bi 𝔄 ici"
      and "fi : ai 𝔄 ibi"
      and "h Asmc_prod I 𝔄g : b smc_prod I 𝔄d"
      and "g Asmc_prod I 𝔄f : a smc_prod I 𝔄c"
      by (auto simp: smc_prod_is_arrD)
    with prems that show 
      "(h Asmc_prod I 𝔄g Asmc_prod I 𝔄f)i =
        (h Asmc_prod I 𝔄(g Asmc_prod I 𝔄f))i"
      by (simp add: smc_prod_Comp_app_component smc_Comp_assoc)
  qed

qed (intro assms)



subsection‹Further local assumptions for product semicategories›


subsubsection‹Definition and elementary properties›

locale psemicategory = psemicategory_base α I 𝔄 for α I 𝔄 +
  assumes psmc_Obj_vsubset_Vset: 
    "J  I  (SMCiJ. 𝔄 i)Obj  Vset α"
    and psmc_Hom_vifunion_in_Vset: 
      "
        J  I;
        A  (SMCiJ. 𝔄 i)Obj;
        B  (SMCiJ. 𝔄 i)Obj;
        A  Vset α;
        B  Vset α
        (aA. bB. Hom (SMCiJ. 𝔄 i) a b)  Vset α"


text‹Rules.›

lemma (in psemicategory) psemicategory_axioms'[smc_prod_cs_intros]: 
  assumes "α' = α" and "I' = I"
  shows "psemicategory α' I' 𝔄"
  unfolding assms by (rule psemicategory_axioms)

mk_ide rf psemicategory_def[unfolded psemicategory_axioms_def]
  |intro psemicategoryI|
  |dest psemicategoryD[dest]|
  |elim psemicategoryE[elim]|

lemmas [smc_prod_cs_intros] = psemicategoryD(1)

lemma psemicategory_pdigraphI:
  assumes "pdigraph α I (λi. smc_dg (𝔄 i))" 
    and "i. i  I  semicategory α (𝔄 i)"
  shows "psemicategory α I 𝔄"
proof-
  interpret pdigraph α I λi. smc_dg (𝔄 i) by (rule assms(1))
  note [unfolded slicing_simps slicing_commute, smc_cs_intros] = 
    pdg_Obj_vsubset_Vset
    pdg_Hom_vifunion_in_Vset
  show ?thesis
    by (intro psemicategoryI psemicategory_base_pdigraph_baseI)
      (auto simp: assms(2) dg_prod_cs_intros intro!: smc_cs_intros) 
qed


text‹Product semicategory is a product digraph.›

context psemicategory
begin

lemma psmc_pdigraph: "pdigraph α I (λi. smc_dg (𝔄 i))"
proof(intro pdigraphI, unfold slicing_simps slicing_commute)
  show "pdigraph_base α I (λi. smc_dg (𝔄 i))" by (rule psmc_pdigraph_base)
qed (auto intro!: psmc_Obj_vsubset_Vset psmc_Hom_vifunion_in_Vset)

interpretation pdg: pdigraph α I λi. smc_dg (𝔄 i) by (rule psmc_pdigraph)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  psmc_Obj_vsubset_Vset' = pdg.pdg_Obj_vsubset_Vset'
  and psmc_Hom_vifunion_in_Vset' = pdg.pdg_Hom_vifunion_in_Vset'
  and psmc_smc_prod_vunion_is_arr = pdg.pdg_dg_prod_vunion_is_arr
  and psmc_smc_prod_vdiff_vunion_is_arr = pdg.pdg_dg_prod_vdiff_vunion_is_arr

end


text‹Elementary properties.›

lemma (in psemicategory) psmc_vsubset_index_psemicategory:
  assumes "J  I"
  shows "psemicategory α J 𝔄"
proof(intro psemicategoryI psemicategory_pdigraphI)
  show "smc_prod J' 𝔄Obj  Vset α" if J'  J for J'
  proof-
    from that assms have "J'  I" by simp
    then show "smc_prod J' 𝔄Obj  Vset α" by (rule psmc_Obj_vsubset_Vset)
  qed
  fix A B J' assume prems:
    "J'  J"
    "A  (SMCiJ'. 𝔄 i)Obj"
    "B  (SMCiJ'. 𝔄 i)Obj"
    "A  Vset α" 
    "B  Vset α"
  show "(aA. bB. Hom (SMCiJ'. 𝔄 i) a b)  Vset α"
  proof-
    from prems(1) assms have "J'  I" by simp
    from psmc_Hom_vifunion_in_Vset[OF this prems(2-5)] show ?thesis.
  qed
qed (rule psmc_vsubset_index_psemicategory_base[OF assms])


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

lemma (in psemicategory) psmc_semicategory_smc_prod: 
  "semicategory α (SMCiI. 𝔄 i)"
proof-
  interpret tiny_semicategory α + ω SMCiI. 𝔄 i
    by (intro psmc_tiny_semicategory_smc_prod) 
      (auto simp: 𝒵_α_αω 𝒵.intro 𝒵_Limit_αω 𝒵_ω_αω)
  show ?thesis
    by (rule semicategory_if_semicategory)  
      (
        auto 
          intro!: psmc_Hom_vifunion_in_Vset psmc_Obj_vsubset_Vset
          intro: smc_cs_intros
      )
qed



subsection‹Local assumptions for a finite product semicategory›


subsubsection‹Definition and elementary properties›

locale finite_psemicategory = psemicategory_base α I 𝔄 for α I 𝔄 +
  assumes fin_psmc_index_vfinite: "vfinite I"


text‹Rules.›

lemma (in finite_psemicategory) finite_psemicategory_axioms[smc_prod_cs_intros]: 
  assumes "α' = α" and "I' = I"
  shows "finite_psemicategory α' I' 𝔄"
  unfolding assms by (rule finite_psemicategory_axioms)

mk_ide rf finite_psemicategory_def[unfolded finite_psemicategory_axioms_def]
  |intro finite_psemicategoryI|
  |dest finite_psemicategoryD[dest]|
  |elim finite_psemicategoryE[elim]|

lemmas [smc_prod_cs_intros] = finite_psemicategoryD(1)

lemma finite_psemicategory_finite_pdigraphI:
  assumes "finite_pdigraph α I (λi. smc_dg (𝔄 i))" 
    and "i. i  I  semicategory α (𝔄 i)"
  shows "finite_psemicategory α I 𝔄"
proof-
  interpret finite_pdigraph α I λi. smc_dg (𝔄 i) by (rule assms(1))
  show ?thesis
    by 
      (
        intro 
          assms
          finite_psemicategoryI 
          psemicategory_base_pdigraph_baseI 
          finite_pdigraphD(1)[OF assms(1)]
          fin_pdg_index_vfinite
      )
qed


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

sublocale finite_psemicategory  psemicategory α I 𝔄
proof-
  interpret finite_pdigraph α I λi. smc_dg (𝔄 i)
  proof(intro finite_pdigraphI pdigraph_baseI)
    fix i assume i: "i  I"
    interpret 𝔄i: semicategory α 𝔄 i by (simp add: i psmc_semicategories)
    show "digraph α (smc_dg (𝔄 i))" by (simp add: 𝔄i.smc_digraph)
  qed (auto intro!: smc_cs_intros fin_psmc_index_vfinite)
  show "psemicategory α I 𝔄"
    by (intro psemicategory_pdigraphI) 
      (simp_all add: psmc_semicategories pdigraph_axioms)
qed



subsection‹Binary union and complement›

lemma (in psemicategory) psmc_smc_prod_vunion_Comp:
  assumes "vdisjnt J K"
    and "J  I"
    and "K  I"
    and "g : b (SMCjJ. 𝔄 j)c"
    and "g' : b' (SMCkK. 𝔄 k)c'"
    and "f : a (SMCjJ. 𝔄 j)b"
    and "f' : a' (SMCkK. 𝔄 k)b'"
  shows "(g A(SMCjJ. 𝔄 j)f)  (g' A(SMCjK. 𝔄 j)f') = 
    g  g' A(SMCjJ  K. 𝔄 j)f  f'"
proof-

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

  interpret J𝔄': semicategory α smc_prod J 𝔄 
    by (rule J𝔄.psmc_semicategory_smc_prod)
  interpret K𝔄': semicategory α smc_prod K 𝔄 
    by (rule K𝔄.psmc_semicategory_smc_prod)
  interpret JK𝔄': semicategory α smc_prod (J  K) 𝔄 
    by (rule JK𝔄.psmc_semicategory_smc_prod)

  note gg' = psmc_smc_prod_vunion_is_arr[OF assms(1-3,4,5)]
    and ff' = psmc_smc_prod_vunion_is_arr[OF assms(1-3,6,7)]

  note gD = J𝔄.smc_prod_is_arrD[OF assms(4)]
    and g'D = K𝔄.smc_prod_is_arrD[OF assms(5)]
    and fD = J𝔄.smc_prod_is_arrD[OF assms(6)]
    and f'D = K𝔄.smc_prod_is_arrD[OF assms(7)]

  from assms(4,6) have gf: 
    "g Asmc_prod J 𝔄f : a (SMCjJ. 𝔄 j)c" 
    by (auto intro: smc_cs_intros)
  from assms(5,7) have g'f': 
    "g' Asmc_prod K 𝔄f' : a' (SMCkK. 𝔄 k)c'"
    by (auto intro: smc_cs_intros)
  from gf have "g Asmc_prod J 𝔄f  smc_prod J 𝔄Arr" by auto
  from g'f' have "g' Asmc_prod K 𝔄f'  smc_prod K 𝔄Arr" by auto
  from gg' ff' have gg'_ff': 
    "g  g' Asmc_prod (J  K) 𝔄f  f' :
      a  a' smc_prod (J  K) 𝔄c  c'"
    by (simp add: smc_cs_intros)

  show ?thesis
  proof(rule smc_prod_Arr_cong[of _ J  K 𝔄])
    from gf g'f' assms(1) show 
      "(g Asmc_prod J 𝔄f)  (g' Asmc_prod K 𝔄f')  
        smc_prod (J  K) 𝔄Arr"
      by (auto intro: smc_prod_vunion_Arr_in_Arr)
    from gg'_ff' show 
      "g  g' Asmc_prod (J  K) 𝔄f  f'  smc_prod (J  K) 𝔄Arr"
      by auto
    fix i assume prems: "i  J  K"
    then consider (iJ) i  J | (iK) i  K by auto
    then show 
      "((g Asmc_prod J 𝔄f)  (g' Asmc_prod K 𝔄f'))i =
        (g  g' Asmc_prod (J  K) 𝔄f  f')i"
    proof cases
      case iJ
      have [simp]:
        "((g Asmc_prod J 𝔄f)  (g' Asmc_prod K 𝔄f'))i = 
          gi A𝔄 ifi"
      proof
        (
          fold smc_prod_Comp_app_component[OF assms(4,6) iJ], 
          rule vsv_vunion_app_left
        )
        from gf show "vsv (g Asmc_prod J 𝔄f)" by auto
        from g'f' show "vsv (g' Asmc_prod K 𝔄f')" by auto
      qed 
        (
          use assms(4-7) in 
            simp_all add: iJ assms(1) smc_prod_Comp_app_vdomain
        )
      have gg'_i: "(g  g')i = gi" 
        by (simp add: iJ assms(1) gD(1,2) g'D(1,2))
      have ff'_i: "(f  f')i = fi" 
        by (simp add: iJ assms(1) fD(1,2) f'D(1,2))
      have [simp]: 
        "(g  g' Asmc_prod (J  K) 𝔄f  f')i = gi A𝔄 ifi" 
        by (fold gg'_i ff'_i) 
          (rule smc_prod_Comp_app_component[OF gg' ff' prems])
      show ?thesis by simp
    next
      case iK
      have [simp]:
        "((g Asmc_prod J 𝔄f)  (g' Asmc_prod K 𝔄f'))i = 
          g'i A𝔄 if'i"
      proof
        (
          fold smc_prod_Comp_app_component[OF assms(5,7) iK], 
          rule vsv_vunion_app_right
        )
        from gf show "vsv (g Asmc_prod J 𝔄f)" by auto
        from g'f' show "vsv (g' Asmc_prod K 𝔄f')" by auto
      qed 
        (
          use assms(4-7) in 
            simp_all add: iK smc_prod_Comp_app_vdomain assms(1)
        )
      have gg'_i: "(g  g')i = g'i" 
        by (simp add: iK assms(1) gD(1,2) g'D(1,2))
      have ff'_i: "(f  f')i = f'i" 
        by (simp add: iK assms(1) fD(1,2) f'D(1,2))
      have [simp]:
        "(g  g' Asmc_prod (J  K) 𝔄f  f')i = g'i A𝔄 if'i" 
        by (fold gg'_i ff'_i)
          (rule smc_prod_Comp_app_component[OF gg' ff' prems])
      show ?thesis by simp
    qed
  qed

qed

lemma (in psemicategory) psmc_smc_prod_vdiff_vunion_Comp:
  assumes "J  I"   
    and "g : b (SMCjI - J. 𝔄 j)c"
    and "g' : b' (SMCkJ. 𝔄 k)c'"
    and "f : a (SMCjI - J. 𝔄 j)b"
    and "f' : a' (SMCkJ. 𝔄 k)b'"
  shows "(g A(SMCjI - J. 𝔄 j)f)  (g' A(SMCjJ. 𝔄 j)f') = 
    g  g' A(SMCjI. 𝔄 j)f  f'"
  by 
    (
      vdiff_of_vunion' 
        rule: psmc_smc_prod_vunion_Comp assms: assms(2-5) subset: assms(1)
    )



subsection‹Projection›


subsubsection‹Definition and elementary properties›


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

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


text‹Components.›

lemma smcf_proj_components:
  shows "(πSMC I 𝔄 i)ObjMap = (λa(iI. 𝔄 iObj). ai)"
    and "(πSMC I 𝔄 i)ArrMap = (λf(iI. 𝔄 iArr). fi)"
    and "(πSMC I 𝔄 i)HomDom = (SMCiI. 𝔄 i)"
    and "(πSMC I 𝔄 i)HomCod = 𝔄 i"
  unfolding smcf_proj_def dghm_field_simps by (simp_all add: nat_omega_simps)


text‹Slicing›

lemma smcf_dghm_smcf_proj[slicing_commute]: 
  "πDG I (λi. smc_dg (𝔄 i)) i = smcf_dghm (πSMC I 𝔄 i)"
  unfolding 
    smc_dg_def 
    smcf_dghm_def 
    smcf_proj_def 
    dghm_proj_def 
    smc_prod_def 
    dg_prod_def
    dg_field_simps 
    dghm_field_simps 
  by (simp add: nat_omega_simps)

context psemicategory
begin

interpretation pdg: pdigraph α I λi. smc_dg (𝔄 i) by (rule psmc_pdigraph)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  smcf_proj_is_dghm = pdg.pdg_dghm_proj_is_dghm

end


subsubsection‹Projection semifunctor is a semifunctor›

lemma (in psemicategory) psmc_smcf_proj_is_semifunctor: 
  assumes "i  I"
  shows "πSMC I 𝔄 i : (SMCiI. 𝔄 i) ↦↦SMCα𝔄 i"
proof(intro is_semifunctorI)
  show "vfsequence (πSMC I 𝔄 i)"
    unfolding smcf_proj_def by (simp add: nat_omega_simps)
  show "vcard (πSMC I 𝔄 i) = 4"
    unfolding smcf_proj_def by (simp add: nat_omega_simps)
  interpret 𝔄: semicategory α smc_prod I 𝔄 
    by (rule psmc_semicategory_smc_prod)
  interpret 𝔄i: semicategory α 𝔄 i 
    using assms by (simp add: smc_prod_cs_intros)
  show "πSMC I 𝔄 iArrMapg Asmc_prod I 𝔄f =
    πSMC I 𝔄 iArrMapg A𝔄 iπSMC I 𝔄 iArrMapf"
    if "g : b smc_prod I 𝔄c" and "f : a smc_prod I 𝔄b" for g b c f a
  proof-
    from that have "g Asmc_prod I 𝔄f : a smc_prod I 𝔄c" 
      by (auto simp: smc_cs_intros)
    then have "g Asmc_prod I 𝔄f  (iI. 𝔄 iArr)"
      unfolding smc_prod_components[symmetric] by auto
    then have π_gf: "πSMC I 𝔄 iArrMapg Asmc_prod I 𝔄f = gi A𝔄 ifi"
      unfolding smcf_proj_components 
      by (simp add: smc_prod_Comp_app_component[OF that assms])
    from that(1) have g: "g  (iI. 𝔄 iArr)" 
      unfolding smc_prod_components[symmetric] by auto
    from that(2) have f: "f  (iI. 𝔄 iArr)" 
      unfolding smc_prod_components[symmetric] by auto
    from g f have πg_πf: 
      "πSMC I 𝔄 iArrMapg A𝔄 iπSMC I 𝔄 iArrMapf = gi A𝔄 ifi"
      unfolding smcf_proj_components by simp
    from π_gf πg_πf show ?thesis by simp
  qed
qed 
  (
    auto simp:
      smc_prod_cs_intros
      assms
      smcf_proj_components
      psmc_semicategory_smc_prod 
      smcf_proj_is_dghm
  )

lemma (in psemicategory) psmc_smcf_proj_is_semifunctor':
  assumes "i  I" and " = (SMCiI. 𝔄 i)" and "𝔇 = 𝔄 i"
  shows "πSMC I 𝔄 i :  ↦↦SMCα𝔇"
  using assms(1) unfolding assms(2,3) by (rule psmc_smcf_proj_is_semifunctor)

lemmas [smc_cs_intros] = psemicategory.psmc_smcf_proj_is_semifunctor'



subsection‹Semicategory product universal property semifunctor›


subsubsection‹Definition and elementary properties›


text‹
The following semifunctor is used in the 
proof of the universal property of the product semicategory 
later in this work.
›

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


text‹Components.›

lemma smcf_up_components: 
  shows "smcf_up I 𝔄  φObjMap = (λaObj. (λiI. φ iObjMapa))"
    and "smcf_up I 𝔄  φArrMap = (λfArr. (λiI. φ iArrMapf))"
    and "smcf_up I 𝔄  φHomDom = "
    and "smcf_up I 𝔄  φHomCod = (SMCiI. 𝔄 i)"
  unfolding smcf_up_def dghm_field_simps by (simp_all add: nat_omega_simps)


text‹Slicing.›

lemma smcf_dghm_smcf_up[slicing_commute]: 
  "dghm_up I (λi. smc_dg (𝔄 i)) (smc_dg ) (λi. smcf_dghm (φ i)) = 
    smcf_dghm (smcf_up I 𝔄  φ)"
  unfolding 
    smc_dg_def 
    smcf_dghm_def 
    smcf_up_def 
    dghm_up_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. smc_dg (𝔄 i) and φ=λi. smcf_dghm (φ i) and=smc_dg , 
    unfolded slicing_simps slicing_commute
  ]:
  smcf_up_ObjMap_vdomain[smc_cs_simps] = dghm_up_ObjMap_vdomain
  and smcf_up_ObjMap_app = dghm_up_ObjMap_app
  and smcf_up_ObjMap_app_vdomain[smc_cs_simps] = dghm_up_ObjMap_app_vdomain
  and smcf_up_ObjMap_app_component[smc_cs_simps] = dghm_up_ObjMap_app_component
  and smcf_up_ArrMap_vdomain[smc_cs_simps] = dghm_up_ArrMap_vdomain
  and smcf_up_ArrMap_app = dghm_up_ArrMap_app
  and smcf_up_ArrMap_app_vdomain[smc_cs_simps] = dghm_up_ArrMap_app_vdomain
  and smcf_up_ArrMap_app_component[smc_cs_simps] = dghm_up_ArrMap_app_component

lemma smcf_up_ObjMap_vrange:
  assumes "i. i  I  φ i :  ↦↦SMCα𝔄 i"
  shows " (smcf_up I 𝔄  φObjMap)  (SMCiI. 𝔄 i)Obj"
proof
  (
    rule dghm_up_ObjMap_vrange
      [
        where 𝔄=λi. smc_dg (𝔄 i) 
          and φ=λi. smcf_dghm (φ i) 
          and=smc_dg , 
        unfolded slicing_simps slicing_commute
      ]
  )
  fix i assume "i  I"
  then interpret is_semifunctor α  𝔄 i φ i by (rule assms)
  show "smcf_dghm (φ i) : smc_dg  ↦↦DGαsmc_dg (𝔄 i)" 
    by (rule smcf_is_dghm)
qed

lemma smcf_up_ObjMap_app_vrange:
  assumes "a  Obj" and "i. i  I  φ i :  ↦↦SMCα𝔄 i"
  shows "  (smcf_up I 𝔄  φObjMapa)  (iI. 𝔄 iObj)"
proof
  (
    rule dghm_up_ObjMap_app_vrange
      [
        where 𝔄=λi. smc_dg (𝔄 i) 
          and φ=λi. smcf_dghm (φ i) 
          and=smc_dg , 
        unfolded slicing_simps slicing_commute
      ]
  )
  show "a  Obj" by (rule assms)
  fix i assume "i  I"
  then interpret is_semifunctor α  𝔄 i φ i by (rule assms(2))
  show "smcf_dghm (φ i) : smc_dg  ↦↦DGαsmc_dg (𝔄 i)"
    by (rule smcf_is_dghm)
qed

lemma smcf_up_ArrMap_vrange:
  assumes "i. i  I  φ i :  ↦↦SMCα𝔄 i"
  shows " (smcf_up I 𝔄  φArrMap)  (SMCiI. 𝔄 i)Arr"
proof
  (
    rule dghm_up_ArrMap_vrange
      [
        where 𝔄=λi. smc_dg (𝔄 i) 
          and φ=λi. smcf_dghm (φ i) 
          and=smc_dg , 
        unfolded slicing_simps slicing_commute
      ]
  )
  fix i assume "i  I"
  then interpret is_semifunctor α  𝔄 i φ i by (rule assms)
  show "smcf_dghm (φ i) : smc_dg  ↦↦DGαsmc_dg (𝔄 i)"
    by (rule smcf_is_dghm)
qed

lemma smcf_up_ArrMap_app_vrange:
  assumes "a  Arr" and "i. i  I  φ i :  ↦↦SMCα𝔄 i"
  shows " (smcf_up I 𝔄  φArrMapa)  (iI. 𝔄 iArr)"
proof
  (
    rule dghm_up_ArrMap_app_vrange[
      where 𝔄=λi. smc_dg (𝔄 i) 
        and φ=λi. smcf_dghm (φ i) 
        and=smc_dg , 
      unfolded slicing_simps slicing_commute
      ]
  )
  show "a  Arr" by (rule assms)
  fix i assume "i  I"
  then interpret is_semifunctor α  𝔄 i φ i by (rule assms(2))
  show "smcf_dghm (φ i) : smc_dg  ↦↦DGαsmc_dg (𝔄 i)"
    by (rule smcf_is_dghm)
qed

end

context psemicategory
begin

interpretation pdg: pdigraph α I λi. smc_dg (𝔄 i) by (rule psmc_pdigraph)

lemmas_with [unfolded slicing_simps slicing_commute]: 
  psmc_dghm_comp_dghm_proj_dghm_up = pdg.pdg_dghm_comp_dghm_proj_dghm_up
  and psmc_dghm_up_eq_dghm_proj = pdg.pdg_dghm_up_eq_dghm_proj

end


subsubsection‹
Semicategory product universal property semifunctor is a semifunctor
›

lemma (in psemicategory) psmc_smcf_up_is_semifunctor:
  assumes "semicategory α " and "i. i  I  φ i :  ↦↦SMCα𝔄 i"
  shows "smcf_up I 𝔄  φ :  ↦↦SMCα(SMCiI. 𝔄 i)"
proof(intro is_semifunctorI)
  interpret: semicategory α  by (simp add: assms(1))
  interpret 𝔄: semicategory α smc_prod I 𝔄 
    by (rule psmc_semicategory_smc_prod)
  show "vfsequence (smcf_up I 𝔄  φ)"
    unfolding smcf_up_def by simp
  show "vcard (smcf_up I 𝔄  φ) = 4"
    unfolding smcf_up_def by (simp add: nat_omega_simps)
  show dghm_smcf_up: 
    "smcf_dghm (smcf_up I 𝔄  φ) : smc_dg  ↦↦DGαsmc_dg (smc_prod I 𝔄)"
    by 
      (
        simp add: 
          assms 
          slicing_commute[symmetric]
          psmc_pdigraph 
          is_semifunctor.smcf_is_dghm 
          pdigraph.pdg_dghm_up_is_dghm 
          semicategory.smc_digraph
      )
  interpret smcf_up:
    is_dghm α smc_dg  smc_dg (smc_prod I 𝔄) smcf_dghm (smcf_up I 𝔄  φ)
    by (rule dghm_smcf_up)
  show "smcf_up I 𝔄  φArrMapg Af = 
    smcf_up I 𝔄  φArrMapg Asmc_prod I 𝔄smcf_up I 𝔄  φArrMapf"
    if "g : b c" and "f : a b" for g b c f a
  proof(rule smc_prod_Arr_cong[of _ I 𝔄])
    note smcf_up_f = 
        smcf_up.dghm_ArrMap_is_arr[unfolded slicing_simps, OF that(2)]
      and smcf_up_g = 
        smcf_up.dghm_ArrMap_is_arr[unfolded slicing_simps, OF that(1)]
    from that have gf: "g Af : a c" 
      by (simp add: smc_cs_intros)
    from smcf_up.dghm_ArrMap_is_arr[unfolded slicing_simps, OF this] show
      "smcf_up I 𝔄  φArrMapg Af  smc_prod I 𝔄Arr" 
      by (simp add: smc_cs_intros)
    from smcf_up_g smcf_up_f show 
      "smcf_up I 𝔄  φArrMapg Asmc_prod I 𝔄smcf_up I 𝔄  φArrMapf  
        smc_prod I 𝔄Arr"
      by (meson 𝔄.smc_is_arrE 𝔄.smc_Comp_is_arr)
    fix i assume prems: "i  I"
    from gf have gf': "g Af  Arr" by (simp add: smc_cs_intros)
    from that have g: "g  Arr" and f: "f  Arr" by auto
    interpret φ: is_semifunctor α  𝔄 i φ i by (rule assms(2)[OF prems])
    from that show "smcf_up I 𝔄  φArrMapg Afi = 
      (
        smcf_up I 𝔄  φArrMapg Asmc_prod I 𝔄smcf_up I 𝔄  φArrMapf
      )i"
      unfolding 
        smcf_up_ArrMap_app_component[OF gf' prems]
        smc_prod_Comp_app_component[OF smcf_up_g smcf_up_f prems]
        smcf_up_ArrMap_app_component[OF g prems]
        smcf_up_ArrMap_app_component[OF f prems]
      by (rule φ.smcf_ArrMap_Comp)
  qed
qed (auto simp: assms(1) psmc_semicategory_smc_prod smcf_up_components)


subsubsection‹Further properties›

lemma (in psemicategory) psmc_Comp_smcf_proj_smcf_up: 
  assumes "semicategory α " 
    and "i. i  I  φ i :  ↦↦SMCα𝔄 i" 
    and "i  I" 
  shows "φ i = πSMC I 𝔄 i SMCF smcf_up I 𝔄  φ"
proof(rule smcf_dghm_eqI)
  interpret φ: is_semifunctor α  𝔄 i φ i by (rule assms(2)[OF assms(3)])
  interpret π: is_semifunctor α smc_prod I 𝔄 𝔄 i πSMC I 𝔄 i
    by (simp add: assms(3) psmc_smcf_proj_is_semifunctor)
  interpret up: is_semifunctor α  smc_prod I 𝔄 smcf_up I 𝔄  φ
    by 
      (
        simp add: 
          assms(2) φ.HomDom.semicategory_axioms psmc_smcf_up_is_semifunctor
      )
  show "φ i :  ↦↦SMCα𝔄 i" by (simp add: smc_cs_intros)
  show "πSMC I 𝔄 i SMCF smcf_up I 𝔄  φ :  ↦↦SMCα𝔄 i" 
      by (auto intro: smc_cs_intros)
  from assms show 
    "smcf_dghm (φ i) = smcf_dghm (πSMC I 𝔄 i SMCF smcf_up I 𝔄  φ)"
    unfolding slicing_simps[symmetric] slicing_commute[symmetric]
    by 
      (
        intro 
          psmc_dghm_comp_dghm_proj_dghm_up
            [
              where φ=λi. smcf_dghm (φ i), 
              unfolded slicing_simps[symmetric] slicing_commute[symmetric]
            ]
      )
      (auto simp: is_semifunctor.smcf_is_dghm)
qed simp_all

lemma (in psemicategory) psmc_smcf_up_eq_smcf_proj:
  assumes "𝔉 :  ↦↦SMCα(SMCiI. 𝔄 i)"
    and "i. i  I  φ i = πSMC I 𝔄 i SMCF 𝔉"
  shows "smcf_up I 𝔄  φ = 𝔉"
proof(rule smcf_dghm_eqI)
  interpret 𝔉: is_semifunctor α  (SMCiI. 𝔄 i) 𝔉 by (rule assms(1))
  show "smcf_up I 𝔄  φ :  ↦↦SMCα(SMCiI. 𝔄 i)"
  proof(rule psmc_smcf_up_is_semifunctor)
    fix i assume prems: "i  I"
    interpret π: is_semifunctor α (SMCiI. 𝔄 i) 𝔄 i πSMC I 𝔄 i
      using prems by (rule psmc_smcf_proj_is_semifunctor)
    show "φ i :  ↦↦SMCα𝔄 i" 
      unfolding assms(2)[OF prems] by (auto intro: smc_cs_intros)
  qed (auto intro: smc_cs_intros)
  show "𝔉 :  ↦↦SMCα(SMCiI. 𝔄 i)" by (rule assms(1))
  from assms show "smcf_dghm (smcf_up I 𝔄  φ) = smcf_dghm 𝔉"
    unfolding slicing_simps[symmetric] slicing_commute[symmetric]
    by (intro psmc_dghm_up_eq_dghm_proj) 
      (auto simp: slicing_simps slicing_commute)
qed simp_all



subsection‹Singleton semicategory›


subsubsection‹Slicing›

context
  fixes  :: V
begin

lemmas_with [where=smc_dg , unfolded slicing_simps slicing_commute]:
  smc_singleton_ObjI = dg_singleton_ObjI
  and smc_singleton_ObjE = dg_singleton_ObjE
  and smc_singleton_ArrI = dg_singleton_ArrI
  and smc_singleton_ArrE = dg_singleton_ArrE

end

context semicategory
begin

interpretation dg: digraph α smc_dg  by (rule smc_digraph)

lemmas_with [unfolded slicing_simps slicing_commute]:
  smc_finite_pdigraph_smc_singleton = dg.dg_finite_pdigraph_dg_singleton
  and smc_singleton_is_arrI = dg.dg_singleton_is_arrI
  and smc_singleton_is_arrD = dg.dg_singleton_is_arrD
  and smc_singleton_is_arrE = dg.dg_singleton_is_arrE

end


subsubsection‹Singleton semicategory is a semicategory›

lemma (in semicategory) smc_finite_psemicategory_smc_singleton: 
  assumes "j  Vset α"
  shows "finite_psemicategory α (set {j}) (λi. )"
  by 
    (
      auto intro: 
        assms
        semicategory_axioms 
        finite_psemicategory_finite_pdigraphI 
        smc_finite_pdigraph_smc_singleton 
    )

lemma (in semicategory) smc_semicategory_smc_singleton:
  assumes "j  Vset α"
  shows "semicategory α (SMCiset {j}. )"
proof-
  interpret finite_psemicategory α set {j} λi. 
    using assms by (rule smc_finite_psemicategory_smc_singleton)
  show ?thesis by (rule psmc_semicategory_smc_prod)
qed



subsection‹Singleton semifunctor›


subsubsection‹Definition and elementary properties›

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


text‹Components.›

lemma smcf_singleton_components:
  shows "smcf_singleton j ObjMap = (λaObj. set {j, a})"
    and "smcf_singleton j ArrMap = (λfArr. set {j, f})"
    and "smcf_singleton j HomDom = "
    and "smcf_singleton j HomCod = (SMCiset {j}. )"
  unfolding smcf_singleton_def dghm_field_simps 
  by (simp_all add: nat_omega_simps)


text‹Slicing.›

lemma smcf_dghm_smcf_singleton[slicing_commute]: 
  "dghm_singleton j (smc_dg )= smcf_dghm (smcf_singleton j )"
  unfolding dghm_singleton_def smcf_singleton_def slicing_simps slicing_commute
  by 
    (
      simp add: 
        nat_omega_simps dghm_field_simps dg_field_simps smc_dg_def smcf_dghm_def
     )

context
  fixes  :: V
begin

lemmas_with [where=smc_dg , unfolded slicing_simps slicing_commute]:
  smcf_singleton_ObjMap_vsv[smc_cs_intros] = dghm_singleton_ObjMap_vsv
  and smcf_singleton_ObjMap_vdomain[smc_cs_simps] = 
    dghm_singleton_ObjMap_vdomain
  and smcf_singleton_ObjMap_vrange = dghm_singleton_ObjMap_vrange
  and smcf_singleton_ObjMap_app[smc_prod_cs_simps] = dghm_singleton_ObjMap_app
  and smcf_singleton_ArrMap_vsv[smc_cs_intros] = dghm_singleton_ArrMap_vsv
  and smcf_singleton_ArrMap_vdomain[smc_cs_simps] = 
    dghm_singleton_ArrMap_vdomain
  and smcf_singleton_ArrMap_vrange = dghm_singleton_ArrMap_vrange
  and smcf_singleton_ArrMap_app[smc_prod_cs_simps] = dghm_singleton_ArrMap_app

end

context semicategory
begin

interpretation dg: digraph α smc_dg  by (rule smc_digraph)

lemmas_with [unfolded slicing_simps slicing_commute]:
  smc_smcf_singleton_is_dghm = dg.dg_dghm_singleton_is_dghm

end


subsubsection‹Singleton semifunctor is an isomorphism of semicategories›

lemma (in semicategory) smc_smcf_singleton_is_iso_semifunctor:
  assumes "j  Vset α"
  shows "smcf_singleton j  :  ↦↦SMC.isoα(SMCiset {j}. )"
proof(intro is_iso_semifunctorI is_semifunctorI)
  show dghm_singleton: 
    "smcf_dghm (smcf_singleton j ) :
      smc_dg  ↦↦DG.isoαsmc_dg (SMCiset {j}. )"
    by (rule smc_smcf_singleton_is_dghm[OF assms, unfolded slicing_simps])
  show "vfsequence (smcf_singleton j )" unfolding smcf_singleton_def by simp
  show "vcard (smcf_singleton j ) = 4"
    unfolding smcf_singleton_def by (simp add: nat_omega_simps)
  from dghm_singleton show 
    "smcf_dghm (smcf_singleton j ) :
      smc_dg  ↦↦DGαsmc_dg (SMCiset {j}. )"
    by (simp add: is_iso_dghm.axioms(1))
  show "smcf_singleton j ArrMapg Af =
    smcf_singleton j ArrMapg ASMCiset {j}. smcf_singleton j ArrMapf"
    if "g : b c" and "f : a b" for g b c f a
  proof-
    let ?jg = smcf_singleton j ArrMapg
      and ?jf = smcf_singleton j ArrMapf
    from that have [simp]: "?jg = set {j, g}" "?jf = set {j, f}"
       by (simp_all add: smcf_singleton_ArrMap_app smc_cs_intros)
     from that have "g Af : a c" by (auto intro: smc_cs_intros)
    then have "smcf_singleton j ArrMapg Af = set {j, g Af}"
      by (simp_all add: smcf_singleton_ArrMap_app smc_cs_intros)
    moreover from 
      smc_singleton_is_arrI[OF assms that(1)]
      smc_singleton_is_arrI[OF assms that(2)] 
    have "?jg ASMCiset {j}. ?jf = set {j, g Af}"
      by (simp add: smc_prod_Comp_app VLambda_vsingleton)
    ultimately show ?thesis by auto
  qed
qed 
  (
    auto intro:
      smc_cs_intros
      assms 
      smc_semicategory_smc_singleton 
      smcf_singleton_components 
  )

lemmas [smc_cs_intros] = semicategory.smc_smcf_singleton_is_iso_semifunctor



subsection‹Product of two semicategories›


subsubsection‹Definition and elementary properties.›


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

definition smc_prod_2 :: "V  V  V" (infixr ×SMC 80)
  where "𝔄 ×SMC 𝔅  smc_prod (2) (λi. (i = 0 ? 𝔄 : 𝔅))"


text‹Slicing.›
  
lemma smc_dg_smc_prod_2[slicing_commute]: 
  "smc_dg 𝔄 ×DG smc_dg 𝔅 = smc_dg (𝔄 ×SMC 𝔅)"
  unfolding smc_prod_2_def dg_prod_2_def slicing_commute[symmetric] if_distrib
  by simp

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

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

lemmas_with 
  [
    where 𝔄=smc_dg 𝔄 and 𝔅=smc_dg 𝔅, 
    unfolded slicing_simps slicing_commute, 
    OF 𝔄.smc_digraph 𝔅.smc_digraph
  ]:
  smc_prod_2_ObjI = dg_prod_2_ObjI 
  and smc_prod_2_ObjI'[smc_prod_cs_intros] = dg_prod_2_ObjI'
  and smc_prod_2_ObjE = dg_prod_2_ObjE
  and smc_prod_2_ArrI = dg_prod_2_ArrI
  and smc_prod_2_ArrI'[smc_prod_cs_intros] = dg_prod_2_ArrI'
  and smc_prod_2_ArrE = dg_prod_2_ArrE
  and smc_prod_2_is_arrI = dg_prod_2_is_arrI
  and smc_prod_2_is_arrI'[smc_prod_cs_intros] = dg_prod_2_is_arrI'
  and smc_prod_2_is_arrE = dg_prod_2_is_arrE
  and smc_prod_2_Dom_vsv = dg_prod_2_Dom_vsv
  and smc_prod_2_Dom_vdomain[smc_cs_simps] = dg_prod_2_Dom_vdomain
  and smc_prod_2_Dom_app[smc_prod_cs_simps] = dg_prod_2_Dom_app
  and smc_prod_2_Dom_vrange = dg_prod_2_Dom_vrange
  and smc_prod_2_Cod_vsv = dg_prod_2_Cod_vsv
  and smc_prod_2_Cod_vdomain[smc_cs_simps] = dg_prod_2_Cod_vdomain
  and smc_prod_2_Cod_app[smc_prod_cs_simps] = dg_prod_2_Cod_app
  and smc_prod_2_Cod_vrange = dg_prod_2_Cod_vrange
  and smc_prod_2_op_smc_smc_Obj[smc_op_simps] = dg_prod_2_op_dg_dg_Obj
  and smc_prod_2_smc_op_smc_Obj[smc_op_simps] = dg_prod_2_dg_op_dg_Obj
  and smc_prod_2_op_smc_smc_Arr[smc_op_simps] = dg_prod_2_op_dg_dg_Arr
  and smc_prod_2_smc_op_smc_Arr[smc_op_simps] = dg_prod_2_dg_op_dg_Arr

end


subsubsection‹Product of two semicategories is a semicategory›

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

interpretation 𝒵 α by (rule semicategoryD[OF 𝔄])
interpretation 𝔄: semicategory α 𝔄 by (rule 𝔄)
interpretation 𝔅: semicategory α 𝔅 by (rule 𝔅)

lemma finite_psemicategory_smc_prod_2: 
  "finite_psemicategory α (2) (if2 𝔄 𝔅)"
proof(intro finite_psemicategoryI psemicategory_baseI)
  from Axiom_of_Infinity show z1_in_Vset: "2  Vset α" by blast
  show "semicategory α (i = 0 ? 𝔄 : 𝔅)" if "i  2" for i
    by (auto simp: smc_cs_intros)
qed auto

interpretation finite_psemicategory α 2 if2 𝔄 𝔅
  by (intro finite_psemicategory_smc_prod_2 𝔄 𝔅)

lemma semicategory_smc_prod_2[smc_cs_intros]: "semicategory α (𝔄 ×SMC 𝔅)"
  unfolding smc_prod_2_def by (rule psmc_semicategory_smc_prod)

end


subsubsection‹Composition›

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

interpretation 𝒵 α by (rule semicategoryD[OF 𝔄])

interpretation finite_psemicategory α 2 if2 𝔄 𝔅
  by (intro finite_psemicategory_smc_prod_2 𝔄 𝔅)

lemma smc_prod_2_Comp_app[smc_prod_cs_simps]:
  assumes "[g, g'] : [b, b'] 𝔄 ×SMC 𝔅[c, c']" 
    and "[f, f'] : [a, a'] 𝔄 ×SMC 𝔅[b, b']"
  shows "[g, g'] A𝔄 ×SMC 𝔅[f, f'] = [g A𝔄f, g' A𝔅f']"
proof-
  have "[g, g'] A𝔄 ×SMC 𝔅[f, f'] = 
    (λi2. [g, g']i Ai = 0 ? 𝔄 : 𝔅[f, f']i)"
    by 
      (
        rule smc_prod_Comp_app[
          OF assms[unfolded smc_prod_2_def], folded smc_prod_2_def
          ]
      )
  also have 
    "(λi2. [g, g']i Ai = 0 ? 𝔄 : 𝔅[f, f']i) = 
      [g A𝔄f, g' A𝔅f']"
  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. [g, g']i Ai = 0 ? 𝔄 : 𝔅[f, f']i)i = 
        [g A𝔄f, g' A𝔅f']i"
      by cases (simp_all add: two nat_omega_simps)
  qed (auto simp: two nat_omega_simps)
  finally show ?thesis by simp
qed

end


subsubsection‹Opposite product semicategory›

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

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

lemma op_smc_smc_prod_2[smc_op_simps]: 
  "op_smc (𝔄 ×SMC 𝔅) = op_smc 𝔄 ×SMC op_smc 𝔅"
proof(rule smc_dg_eqI[of α])

  from 𝔄 𝔅 show smc_lhs: "semicategory α (op_smc (𝔄 ×SMC 𝔅))"
    by 
      (
        cs_concl cs_shallow
          cs_simp: smc_cs_simps smc_op_simps 
          cs_intro: smc_cs_intros smc_op_intros
      )
  interpret smc_lhs: semicategory α op_smc (𝔄 ×SMC 𝔅) by (rule smc_lhs)
  
  from 𝔄 𝔅 show smc_rhs: "semicategory α (op_smc 𝔄 ×SMC op_smc 𝔅)"
    by 
      (
        cs_concl cs_shallow 
          cs_simp: smc_cs_simps smc_op_simps 
          cs_intro: smc_cs_intros smc_op_intros
      )
  interpret smc_rhs: semicategory α op_smc 𝔄 ×SMC op_smc 𝔅 by (rule smc_rhs)

  show "op_smc (𝔄 ×SMC 𝔅)Comp = (op_smc 𝔄 ×SMC op_smc 𝔅)Comp"
  proof(rule vsv_eqI)
    show "vsv (op_smc (𝔄 ×SMC 𝔅)Comp)"
      unfolding op_smc_components by (rule fflip_vsv)
    show "vsv ((op_smc 𝔄 ×SMC op_smc 𝔅)Comp)"
      unfolding smc_prod_2_def smc_prod_components by simp      
    show "𝒟 (op_smc (𝔄 ×SMC 𝔅)Comp) = 𝒟 ((op_smc 𝔄 ×SMC op_smc 𝔅)Comp)"
    proof(intro vsubset_antisym vsubsetI)
      fix gg'ff' assume gf: "gg'ff'  𝒟 (op_smc (𝔄 ×SMC 𝔅)Comp)"
      then obtain gg' ff' aa' bb' cc' 
        where gg'ff'_def: "gg'ff' = [gg', ff']" 
          and "gg' : bb' op_smc (𝔄 ×SMC 𝔅)cc'" 
          and "ff' : aa' op_smc (𝔄 ×SMC 𝔅)bb'"
        by clarsimp
      then have gg': "gg' : cc' 𝔄 ×SMC 𝔅bb'" 
        and ff': "ff' : bb' 𝔄 ×SMC 𝔅aa'"
        unfolding smc_op_simps by simp_all
      from gg' obtain g g' b b' c c' 
        where gg'_def: "gg' = [g, g']" 
          and "cc' = [c, c']" 
          and "bb' = [b, b']"
          and g: "g : c 𝔄b" 
          and g': "g' : c' 𝔅b'"
        by (elim smc_prod_2_is_arrE[OF 𝔄 𝔅])
      with ff' obtain f f' a a' 
        where ff'_def: "ff' = [f, f']" 
          and "bb' = [b, b']" 
          and "aa' = [a, a']"
          and f: "f : b 𝔄a" 
          and f': "f' : b' 𝔅a'"
        by (auto elim: smc_prod_2_is_arrE[OF 𝔄 𝔅])
      from 𝔄 𝔅 g g' f f' show "gg'ff'  𝒟 ((op_smc 𝔄 ×SMC op_smc 𝔅)Comp)"
        by
          (
            intro smc_rhs.smc_Comp_vdomainI[OF _ _ gg'ff'_def], 
            unfold gg'_def ff'_def
          )
          (
            cs_concl cs_shallow 
              cs_simp: smc_cs_simps smc_op_simps 
              cs_intro: smc_op_intros smc_prod_cs_intros
          )
    next
      fix gg'ff' assume gf: "gg'ff'  𝒟 ((op_smc 𝔄 ×SMC op_smc 𝔅)Comp)"
      then obtain gg' ff' aa' bb' cc' 
        where gg'ff'_def: "gg'ff' = [gg', ff']" 
          and gg': "gg' : bb' op_smc 𝔄 ×SMC op_smc 𝔅cc'" 
          and ff': "ff' : aa' op_smc 𝔄 ×SMC op_smc 𝔅bb'"
        by clarsimp
      from gg' obtain g g' b b' c c' 
        where gg'_def: "gg' = [g, g']" 
          and "bb' = [b, b']"
          and "cc' = [c, c']" 
          and g: "g : b op_smc 𝔄c" 
          and g': "g' : b' op_smc 𝔅c'"
        by (elim smc_prod_2_is_arrE[OF 𝔄.semicategory_op 𝔅.semicategory_op])
      with ff' obtain f f' a a' 
        where ff'_def: "ff' = [f, f']" 
          and "aa' = [a, a']"
          and "bb' = [b, b']" 
          and f: "f : a op_smc 𝔄b" 
          and f': "f' : a' op_smc 𝔅b'"
        by 
          (
            auto elim: 
              smc_prod_2_is_arrE[OF 𝔄.semicategory_op 𝔅.semicategory_op]
          )
      from 𝔄 𝔅 g g' f f' show "gg'ff'  𝒟 (op_smc (𝔄 ×SMC 𝔅)Comp)"
        by 
          (
            intro smc_lhs.smc_Comp_vdomainI[OF _ _ gg'ff'_def], 
            unfold gg'_def ff'_def smc_op_simps
          )
          (
            cs_concl cs_shallow 
              cs_simp: smc_cs_simps smc_op_simps 
              cs_intro: smc_op_intros smc_prod_cs_intros
          )
    qed
    fix gg'ff' assume "gg'ff'  𝒟 (op_smc (𝔄 ×SMC 𝔅)Comp)"
    then obtain gg' ff' aa' bb' cc' 
      where gg'ff'_def: "gg'ff' = [gg', ff']" 
        and "gg' : bb' op_smc (𝔄 ×SMC 𝔅)cc'" 
        and "ff' : aa' op_smc (𝔄 ×SMC 𝔅)bb'"
      by clarsimp
    then have gg': "gg' : cc' 𝔄 ×SMC 𝔅bb'" 
      and ff': "ff' : bb' 𝔄 ×SMC 𝔅aa'"
      unfolding smc_op_simps by simp_all
    from gg' obtain g g' b b' c c' 
      where gg'_def[smc_cs_simps]: "gg' = [g, g']" 
        and "cc' = [c, c']" 
        and "bb' = [b, b']"
        and g: "g : c 𝔄b" 
        and g': "g' : c' 𝔅b'"
      by (elim smc_prod_2_is_arrE[OF 𝔄 𝔅])
    with ff' obtain f f' a a' 
      where ff'_def[smc_cs_simps]: "ff' = [f, f']" 
        and "bb' = [b, b']" 
        and "aa' = [a, a']"
        and f: "f : b 𝔄a" 
        and f': "f' : b' 𝔅a'"
      by (auto elim: smc_prod_2_is_arrE[OF 𝔄 𝔅])
    from 𝔄 𝔅 g g' f f' show "op_smc (𝔄 ×SMC 𝔅)Compgg'ff' = 
      (op_smc 𝔄 ×SMC op_smc 𝔅)Compgg'ff'"
      unfolding gg'ff'_def 
      by 
        (
          cs_concl cs_shallow 
            cs_simp: smc_cs_simps smc_op_simps smc_prod_cs_simps
            cs_intro: smc_cs_intros smc_op_intros smc_prod_cs_intros
        )
  qed

  from 𝔄 𝔅 show 
    "smc_dg (op_smc (𝔄 ×SMC 𝔅)) = smc_dg (op_smc 𝔄 ×SMC op_smc 𝔅)"
    unfolding slicing_commute[symmetric]
    by (cs_concl cs_shallow cs_simp: dg_op_simps cs_intro: slicing_intros)

qed
  
end



subsection‹Projections for the product of two semicategories›


subsubsection‹Definition and elementary properties›


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

definition smcf_proj_fst :: "V  V  V" (πSMC.1)
  where "πSMC.1 𝔄 𝔅 = smcf_proj (2) (λi. (i = 0 ? 𝔄 : 𝔅)) 0"
definition smcf_proj_snd :: "V  V  V" (πSMC.2)
  where "πSMC.2 𝔄 𝔅 = smcf_proj (2) (λi. (i = 0 ? 𝔄 : 𝔅)) (1)"


text‹Slicing›

lemma smcf_dghm_smcf_proj_fst[slicing_commute]: 
  "πDG.1 (smc_dg 𝔄) (smc_dg 𝔅) = smcf_dghm (πSMC.1 𝔄 𝔅)"
  unfolding 
    smcf_proj_fst_def dghm_proj_fst_def slicing_commute[symmetric] if_distrib 
    ..

lemma smcf_dghm_smcf_proj_snd[slicing_commute]: 
  "πDG.2 (smc_dg 𝔄) (smc_dg 𝔅) = smcf_dghm (πSMC.2 𝔄 𝔅)"
  unfolding 
    smcf_proj_snd_def dghm_proj_snd_def slicing_commute[symmetric] if_distrib 
    ..

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

interpretation 𝒵 α by (rule semicategoryD[OF 𝔄])
interpretation 𝔄: semicategory α 𝔄 by (rule 𝔄)
interpretation 𝔅: semicategory α 𝔅 by (rule 𝔅)

lemmas_with 
  [
    where 𝔄=smc_dg 𝔄 and 𝔅=smc_dg 𝔅, 
    unfolded slicing_simps slicing_commute, 
    OF 𝔄.smc_digraph 𝔅.smc_digraph
  ]:
  smcf_proj_fst_ObjMap_app[smc_cs_simps] = dghm_proj_fst_ObjMap_app 
  and smcf_proj_snd_ObjMap_app[smc_cs_simps] = dghm_proj_snd_ObjMap_app
  and smcf_proj_fst_ArrMap_app[smc_cs_simps] = dghm_proj_fst_ArrMap_app
  and smcf_proj_snd_ArrMap_app[smc_cs_simps] = dghm_proj_snd_ArrMap_app

end


subsubsection‹
Domain and codomain of a projection of a product of two semicategories
›

lemma smcf_proj_fst_HomDom: "πSMC.1 𝔄 𝔅HomDom = 𝔄 ×SMC 𝔅"
  unfolding smcf_proj_fst_def smcf_proj_components smc_prod_2_def ..

lemma smcf_proj_fst_HomCod: "πSMC.1 𝔄 𝔅HomCod = 𝔄"
  unfolding smcf_proj_fst_def smcf_proj_components smc_prod_2_def by simp
  
lemma smcf_proj_snd_HomDom: "πSMC.2 𝔄 𝔅HomDom = 𝔄 ×SMC 𝔅"
  unfolding smcf_proj_snd_def smcf_proj_components smc_prod_2_def ..

lemma smcf_proj_snd_HomCod: "πSMC.2 𝔄 𝔅HomCod = 𝔅"
  unfolding smcf_proj_snd_def smcf_proj_components smc_prod_2_def by simp


subsubsection‹Projection of a product of two semicategories is a semifunctor›

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

interpretation 𝒵 α by (rule semicategoryD[OF 𝔄])
interpretation finite_psemicategory α 2 if2 𝔄 𝔅
  by (intro finite_psemicategory_smc_prod_2 𝔄 𝔅)

lemma smcf_proj_fst_is_semifunctor: 
  assumes "i  I" 
  shows "πSMC.1 𝔄 𝔅 : 𝔄 ×SMC 𝔅 ↦↦SMCα𝔄"
  by 
    (
      rule 
        psmc_smcf_proj_is_semifunctor[
          where i=0, simplified, folded smcf_proj_fst_def smc_prod_2_def
          ]
    )

lemma smcf_proj_fst_is_semifunctor'[smc_cs_intros]: 
  assumes "i  I" and " = 𝔄 ×SMC 𝔅" and "𝔇 = 𝔄"
  shows "πSMC.1 𝔄 𝔅 :  ↦↦SMCα𝔇"
  using assms(1) unfolding assms(2,3) by (rule smcf_proj_fst_is_semifunctor)

lemma smcf_proj_snd_is_semifunctor: 
  assumes "i  I" 
  shows "πSMC.2 𝔄 𝔅 : 𝔄 ×SMC 𝔅 ↦↦SMCα𝔅"
  by 
    (
      rule 
        psmc_smcf_proj_is_semifunctor[
          where i=1, simplified, folded smcf_proj_snd_def smc_prod_2_def
          ]
    )

lemma smcf_proj_snd_is_semifunctor'[smc_cs_intros]: 
  assumes "i  I" and " = 𝔄 ×SMC 𝔅" and "𝔇 = 𝔅"
  shows "πSMC.2 𝔄 𝔅 :  ↦↦SMCα𝔇"
  using assms(1) unfolding assms(2,3) by (rule smcf_proj_snd_is_semifunctor)

end



subsection‹Product of three semicategories›
(*TODO: find a way to generalize to the product of n semicategories*)


subsubsection‹Definition and elementary properties.›

definition smc_prod_3 :: "V  V  V  V"
  ((_ ×SMC3 _ ×SMC3 _) [81, 81, 81] 80)
  where "𝔄 ×SMC3 𝔅 ×SMC3  = (SMCi3. if3 𝔄 𝔅  i)"


text‹Slicing.›

lemma smc_dg_smc_prod_3[slicing_commute]: 
  "smc_dg 𝔄 ×DG3 smc_dg 𝔅 ×DG3 smc_dg  = smc_dg (𝔄 ×SMC3 𝔅 ×SMC3 )"
  unfolding smc_prod_3_def dg_prod_3_def slicing_commute[symmetric] if_distrib
  by (simp add: if_distrib[symmetric])

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

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

lemmas_with 
  [
    where 𝔄=smc_dg 𝔄 and 𝔅=smc_dg 𝔅 and=smc_dg , 
    unfolded slicing_simps slicing_commute, 
    OF 𝔄.smc_digraph 𝔅.smc_digraph ℭ.smc_digraph
  ]:
  smc_prod_3_ObjI = dg_prod_3_ObjI 
  and smc_prod_3_ObjI'[smc_prod_cs_intros] = dg_prod_3_ObjI'
  and smc_prod_3_ObjE = dg_prod_3_ObjE
  and smc_prod_3_ArrI = dg_prod_3_ArrI
  and smc_prod_3_ArrI'[smc_prod_cs_intros] = dg_prod_3_ArrI'
  and smc_prod_3_ArrE = dg_prod_3_ArrE
  and smc_prod_3_is_arrI = dg_prod_3_is_arrI
  and smc_prod_3_is_arrI'[smc_prod_cs_intros] = dg_prod_3_is_arrI'
  and smc_prod_3_is_arrE = dg_prod_3_is_arrE
  and smc_prod_3_Dom_vsv = dg_prod_3_Dom_vsv
  and smc_prod_3_Dom_vdomain[smc_cs_simps] = dg_prod_3_Dom_vdomain
  and smc_prod_3_Dom_app[smc_prod_cs_simps] = dg_prod_3_Dom_app
  and smc_prod_3_Dom_vrange = dg_prod_3_Dom_vrange
  and smc_prod_3_Cod_vsv = dg_prod_3_Cod_vsv
  and smc_prod_3_Cod_vdomain[smc_cs_simps] = dg_prod_3_Cod_vdomain
  and smc_prod_3_Cod_app[smc_prod_cs_simps] = dg_prod_3_Cod_app
  and smc_prod_3_Cod_vrange = dg_prod_3_Cod_vrange

end


subsubsection‹Product of three semicategories is a semicategory›

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

interpretation 𝒵 α by (rule semicategoryD[OF 𝔄])
interpretation 𝔄: semicategory α 𝔄 by (rule 𝔄)
interpretation 𝔅: semicategory α 𝔅 by (rule 𝔅)
interpretation: semicategory α  by (rule )

lemma finite_psemicategory_smc_prod_3: 
  "finite_psemicategory α (3) (if3 𝔄 𝔅 )"
proof(intro finite_psemicategoryI psemicategory_baseI)
  from Axiom_of_Infinity show z1_in_Vset: "3  Vset α" by blast
  show "semicategory α (if3 𝔄 𝔅  i)" if "i  3" for i
    by (auto simp: smc_cs_intros)
qed auto

interpretation finite_psemicategory α 3 if3 𝔄 𝔅 
  by (intro finite_psemicategory_smc_prod_3 𝔄 𝔅)

lemma semicategory_smc_prod_3[smc_cs_intros]: 
  "semicategory α (𝔄 ×SMC3 𝔅 ×SMC3 )"
  unfolding smc_prod_3_def by (rule psmc_semicategory_smc_prod)

end


subsubsection‹Composition›

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

interpretation 𝒵 α by (rule semicategoryD[OF 𝔄])

interpretation finite_psemicategory α 3 if3 𝔄 𝔅 
  by (intro finite_psemicategory_smc_prod_3 𝔄 𝔅 )

lemma smc_prod_3_Comp_app[smc_prod_cs_simps]:
  assumes "[g, g', g''] : [b, b', b''] 𝔄 ×SMC3 𝔅 ×SMC3 [c, c', c'']" 
    and "[f, f', f''] : [a, a', a''] 𝔄 ×SMC3 𝔅 ×SMC3 [b, b', b'']"
  shows 
    "[g, g', g''] A𝔄 ×SMC3 𝔅 ×SMC3 [f, f', f''] =
      [g A𝔄f, g' A𝔅f', g'' Af'']"
proof-
  have 
    "[g, g', g''] A𝔄 ×SMC3 𝔅 ×SMC3 [f, f', f''] =
      (λi3. [g, g', g'']i Aif3 𝔄 𝔅  i[f, f', f'']i)"
    by 
      (
        rule smc_prod_Comp_app[
          OF assms[unfolded smc_prod_3_def], folded smc_prod_3_def
          ]
      )
  also have 
    "(λi3. [g, g', g'']i Aif3 𝔄 𝔅  i[f, f', f'']i) = 
      [g A𝔄f, g' A𝔅f', g'' Af'']"
  proof(rule vsv_eqI, unfold vdomain_VLambda)
    fix i assume "i  3"
    then consider i = 0 | i = 1 | i = 2 unfolding three by auto 
    then show 
      "(λi3. [g, g', g'']i Aif3 𝔄 𝔅  i[f, f', f'']i)i = 
        [g A𝔄f, g' A𝔅f', g'' Af'']i"
      by cases (simp_all add: three nat_omega_simps)
  qed (auto simp: three nat_omega_simps)
  finally show ?thesis by simp
qed

end

text‹\newpage›

end