Theory Category3.ProductCategory
chapter ProductCategory
theory ProductCategory
imports Category EpiMonoIso
begin
text‹
This theory defines the product of two categories @{term C1} and @{term C2},
which is the category @{term C} whose arrows are ordered pairs consisting of an
arrow of @{term C1} and an arrow of @{term C2}, with composition defined
componentwise. As the ordered pair ‹(C1.null, C2.null)› is available
to serve as ‹C.null›, we may directly identify the arrows of the product
category @{term C} with ordered pairs, leaving the type of arrows of @{term C}
transparent.
›
locale product_category =
C1: category C1 +
C2: category C2
for C1 :: "'a1 comp" (infixr ‹⋅⇩1› 55)
and C2 :: "'a2 comp" (infixr ‹⋅⇩2› 55)
begin
type_synonym ('aa1, 'aa2) arr = "'aa1 * 'aa2"
notation C1.in_hom (‹«_ : _ →⇩1 _»›)
notation C2.in_hom (‹«_ : _ →⇩2 _»›)
abbreviation (input) Null :: "('a1, 'a2) arr"
where "Null ≡ (C1.null, C2.null)"
abbreviation (input) Arr :: "('a1, 'a2) arr ⇒ bool"
where "Arr f ≡ C1.arr (fst f) ∧ C2.arr (snd f)"
abbreviation (input) Ide :: "('a1, 'a2) arr ⇒ bool"
where "Ide f ≡ C1.ide (fst f) ∧ C2.ide (snd f)"
abbreviation (input) Dom :: "('a1, 'a2) arr ⇒ ('a1, 'a2) arr"
where "Dom f ≡ (if Arr f then (C1.dom (fst f), C2.dom (snd f)) else Null)"
abbreviation (input) Cod :: "('a1, 'a2) arr ⇒ ('a1, 'a2) arr"
where "Cod f ≡ (if Arr f then (C1.cod (fst f), C2.cod (snd f)) else Null)"
definition comp :: "('a1, 'a2) arr ⇒ ('a1, 'a2) arr ⇒ ('a1, 'a2) arr"
where "comp g f = (if Arr f ∧ Arr g ∧ Cod f = Dom g then
(C1 (fst g) (fst f), C2 (snd g) (snd f))
else Null)"
notation comp (infixr ‹⋅› 55)
lemma not_Arr_Null:
shows "¬Arr Null"
by simp
interpretation partial_composition comp
proof
show "∃!n. ∀f. n ⋅ f = n ∧ f ⋅ n = n"
proof
let ?P = "λn. ∀f. n ⋅ f = n ∧ f ⋅ n = n"
show 1: "?P Null" using comp_def not_Arr_Null by metis
thus "⋀n. ∀f. n ⋅ f = n ∧ f ⋅ n = n ⟹ n = Null" by metis
qed
qed
notation in_hom (‹«_ : _ → _»›)
lemma null_char [simp]:
shows "null = Null"
proof -
let ?P = "λn. ∀f. n ⋅ f = n ∧ f ⋅ n = n"
have "?P Null" using comp_def not_Arr_Null by metis
thus ?thesis
unfolding null_def using the1_equality [of ?P Null] ex_un_null by blast
qed
lemma ide_Ide:
assumes "Ide a"
shows "ide a"
unfolding ide_def comp_def null_char
using assms C1.not_arr_null C1.ide_in_hom C1.comp_arr_dom C1.comp_cod_arr
C2.comp_arr_dom C2.comp_cod_arr
by auto
lemma has_domain_char:
shows "domains f ≠ {} ⟷ Arr f"
proof
show "domains f ≠ {} ⟹ Arr f"
unfolding domains_def comp_def null_char by (auto; metis)
assume f: "Arr f"
show "domains f ≠ {}"
proof -
have "ide (Dom f) ∧ comp f (Dom f) ≠ null"
using f comp_def ide_Ide C1.comp_arr_dom C1.arr_dom_iff_arr C2.arr_dom_iff_arr
by auto
thus ?thesis using domains_def by blast
qed
qed
lemma has_codomain_char:
shows "codomains f ≠ {} ⟷ Arr f"
proof
show "codomains f ≠ {} ⟹ Arr f"
unfolding codomains_def comp_def null_char by (auto; metis)
assume f: "Arr f"
show "codomains f ≠ {}"
proof -
have "ide (Cod f) ∧ comp (Cod f) f ≠ null"
using f comp_def ide_Ide C1.comp_cod_arr C1.arr_cod_iff_arr C2.arr_cod_iff_arr
by auto
thus ?thesis using codomains_def by blast
qed
qed
lemma arr_char [iff]:
shows "arr f ⟷ Arr f"
using has_domain_char has_codomain_char arr_def by simp
lemma arrI⇩P⇩C [intro]:
assumes "C1.arr f1" and "C2.arr f2"
shows "arr (f1, f2)"
using assms by simp
lemma arrE:
assumes "arr f"
and "C1.arr (fst f) ∧ C2.arr (snd f) ⟹ T"
shows "T"
using assms by auto
lemma seqI⇩P⇩C [intro]:
assumes "C1.seq g1 f1 ∧ C2.seq g2 f2"
shows "seq (g1, g2) (f1, f2)"
using assms comp_def by auto
lemma seqE⇩P⇩C [elim]:
assumes "seq g f"
and "C1.seq (fst g) (fst f) ⟹ C2.seq (snd g) (snd f) ⟹ T"
shows "T"
using assms comp_def
by (metis (no_types, lifting) C1.seqI C2.seqI Pair_inject not_arr_null null_char)
lemma seq_char [iff]:
shows "seq g f ⟷ C1.seq (fst g) (fst f) ∧ C2.seq (snd g) (snd f)"
using comp_def by auto
lemma Dom_comp:
assumes "seq g f"
shows "Dom (g ⋅ f) = Dom f"
proof -
have "C1.arr (fst f) ∧ C1.arr (fst g) ∧ C1.dom (fst g) = C1.cod (fst f)"
using assms by blast
moreover have "C2.arr (snd f) ∧ C2.arr (snd g) ∧ C2.dom (snd g) = C2.cod (snd f)"
using assms by blast
ultimately show ?thesis
by (simp add: comp_def)
qed
lemma Cod_comp:
assumes "seq g f"
shows "Cod (g ⋅ f) = Cod g"
proof -
have "C1.arr (fst f) ∧ C1.arr (fst g) ∧ C1.dom (fst g) = C1.cod (fst f)"
using assms by blast
moreover have "C2.arr (snd f) ∧ C2.arr (snd g) ∧ C2.dom (snd g) = C2.cod (snd f)"
using assms by blast
ultimately show ?thesis
by (simp add: comp_def)
qed
theorem is_category:
shows "category comp"
proof
fix f
show "(domains f ≠ {}) = (codomains f ≠ {})"
using has_domain_char has_codomain_char by simp
fix g
show "g ⋅ f ≠ null ⟹ seq g f"
using comp_def seq_char by (metis C1.seqI C2.seqI Pair_inject null_char)
fix h
show "seq h g ⟹ seq (h ⋅ g) f ⟹ seq g f"
using seq_char
by (metis category.seqE category.seqI Dom_comp
product_category_axioms product_category_def fst_conv snd_conv)
show "seq h (g ⋅ f) ⟹ seq g f ⟹ seq h g"
using seq_char
by (metis category.seqE category.seqI Cod_comp
product_category_axioms product_category_def fst_conv snd_conv)
show "seq g f ⟹ seq h g ⟹ seq (h ⋅ g) f"
using seq_char
by (metis arrE category.seqE category.seqI Dom_comp
product_category_axioms product_category_def fst_conv snd_conv)
show "seq g f ⟹ seq h g ⟹ (h ⋅ g) ⋅ f = h ⋅ g ⋅ f"
using comp_def null_char seq_char C1.comp_assoc C2.comp_assoc
by (elim seqE⇩P⇩C C1.seqE C2.seqE, simp)
qed
sublocale category comp
using is_category comp_def by auto
lemma dom_char:
shows "dom f = Dom f"
proof (cases "Arr f")
show "¬Arr f ⟹ dom f = Dom f"
unfolding dom_def using has_domain_char by auto
show "Arr f ⟹ dom f = Dom f"
using ide_Ide apply (intro dom_eqI, simp)
using seq_char comp_def C1.arr_dom_iff_arr C2.arr_dom_iff_arr by auto
qed
lemma dom_simp [simp]:
assumes "arr f"
shows "dom f = (C1.dom (fst f), C2.dom (snd f))"
using assms dom_char by auto
lemma cod_char:
shows "cod f = Cod f"
proof (cases "Arr f")
show "¬Arr f ⟹ cod f = Cod f"
unfolding cod_def using has_codomain_char by auto
show "Arr f ⟹ cod f = Cod f"
using ide_Ide seqI apply (intro cod_eqI, simp)
using seq_char comp_def C1.arr_cod_iff_arr C2.arr_cod_iff_arr by auto
qed
lemma cod_simp [simp]:
assumes "arr f"
shows "cod f = (C1.cod (fst f), C2.cod (snd f))"
using assms cod_char by auto
lemma in_homI⇩P⇩C [intro, simp]:
assumes "«fst f: fst a →⇩1 fst b»" and "«snd f: snd a →⇩2 snd b»"
shows "«f: a → b»"
using assms by fastforce
lemma in_homE⇩P⇩C [elim]:
assumes "«f: a → b»"
and "«fst f: fst a →⇩1 fst b» ⟹ «snd f: snd a →⇩2 snd b» ⟹ T"
shows "T"
using assms
by (metis C1.in_homI C2.in_homI arr_char cod_simp dom_simp fst_conv in_homE snd_conv)
lemma ide_char⇩P⇩C [iff]:
shows "ide f ⟷ Ide f"
using ide_in_hom C1.ide_in_hom C2.ide_in_hom by blast
lemma comp_char:
shows "g ⋅ f = (if C1.arr (C1 (fst g) (fst f)) ∧ C2.arr (C2 (snd g) (snd f)) then
(C1 (fst g) (fst f), C2 (snd g) (snd f))
else Null)"
using comp_def by auto
lemma comp_simp [simp]:
assumes "C1.seq (fst g) (fst f)" and "C2.seq (snd g) (snd f)"
shows "g ⋅ f = (fst g ⋅⇩1 fst f, snd g ⋅⇩2 snd f)"
using assms comp_char by simp
lemma iso_char [iff]:
shows "iso f ⟷ C1.iso (fst f) ∧ C2.iso (snd f)"
proof
assume f: "iso f"
obtain g where g: "inverse_arrows f g" using f by auto
have 1: "ide (g ⋅ f) ∧ ide (f ⋅ g)"
using f g by (simp add: inverse_arrows_def)
have "g ⋅ f = (fst g ⋅⇩1 fst f, snd g ⋅⇩2 snd f) ∧ f ⋅ g = (fst f ⋅⇩1 fst g, snd f ⋅⇩2 snd g)"
using 1 comp_char arr_char by (meson ideD(1) seq_char)
hence "C1.ide (fst g ⋅⇩1 fst f) ∧ C2.ide (snd g ⋅⇩2 snd f) ∧
C1.ide (fst f ⋅⇩1 fst g) ∧ C2.ide (snd f ⋅⇩2 snd g)"
using 1 ide_char by simp
hence "C1.inverse_arrows (fst f) (fst g) ∧ C2.inverse_arrows (snd f) (snd g)"
by auto
thus "C1.iso (fst f) ∧ C2.iso (snd f)" by auto
next
assume f: "C1.iso (fst f) ∧ C2.iso (snd f)"
obtain g1 where g1: "C1.inverse_arrows (fst f) g1" using f by blast
obtain g2 where g2: "C2.inverse_arrows (snd f) g2" using f by blast
have "C1.ide (g1 ⋅⇩1 fst f) ∧ C2.ide (g2 ⋅⇩2 snd f) ∧
C1.ide (fst f ⋅⇩1 g1) ∧ C2.ide (snd f ⋅⇩2 g2)"
using g1 g2 ide_char⇩P⇩C by force
hence "inverse_arrows f (g1, g2)"
using f g1 g2 ide_char⇩P⇩C comp_char by (intro inverse_arrowsI, auto)
thus "iso f" by auto
qed
lemma isoI⇩P⇩C [intro, simp]:
assumes "C1.iso (fst f)" and "C2.iso (snd f)"
shows "iso f"
using assms by simp
lemma isoD:
assumes "iso f"
shows "C1.iso (fst f)" and "C2.iso (snd f)"
using assms by auto
lemma inv_simp [simp]:
assumes "iso f"
shows "inv f = (C1.inv (fst f), C2.inv (snd f))"
proof -
have "inverse_arrows f (C1.inv (fst f), C2.inv (snd f))"
proof
have 1: "C1.inverse_arrows (fst f) (C1.inv (fst f))"
using assms iso_char C1.inv_is_inverse by simp
have 2: "C2.inverse_arrows (snd f) (C2.inv (snd f))"
using assms iso_char C2.inv_is_inverse by simp
show "ide ((C1.inv (fst f), C2.inv (snd f)) ⋅ f)"
using 1 2 ide_char⇩P⇩C comp_char by auto
show "ide (f ⋅ (C1.inv (fst f), C2.inv (snd f)))"
using 1 2 ide_char⇩P⇩C comp_char by auto
qed
thus ?thesis using inverse_unique by auto
qed
end
end