Theory CZH_UCAT_Limit_Pullback

(* Copyright 2021 (C) Mihails Milehins *)

section‹Pullbacks and pushouts as limits and colimits›
theory CZH_UCAT_Limit_Pullback
  imports 
    CZH_UCAT_Limit
    CZH_Elementary_Categories.CZH_ECAT_SS
begin



subsection‹Pullback and pushout›


subsubsection‹Definition and elementary properties›


text‹
The definitions and the elementary properties of the pullbacks and the 
pushouts can be found, for example, in Chapter III-3 and Chapter III-4 in 
cite‹"mac_lane_categories_2010"›. 
›

locale is_cat_pullback =
  is_cat_limit α ‹→∙←C› ℭ ‹⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙› X x + 
  cf_scospan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ
  for α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x 

syntax "_is_cat_pullback" :: "V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ bool"
  (‹(_ :/ _ <CF.pb _→_→_←_←_ ↦↦Cı _)› [51, 51, 51, 51, 51, 51, 51, 51] 51)
syntax_consts "_is_cat_pullback" ⇌ is_cat_pullback
translations "x : X <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ" ⇌
  "CONST is_cat_pullback α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x"
                        
locale is_cat_pushout =
  is_cat_colimit α ‹←∙→C› ℭ ‹⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙› X x +
  cf_sspan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ
  for α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x

syntax "_is_cat_pushout" :: "V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ V ⇒ bool"
  (‹(_ :/ _←_←_→_→_ >CF.po _ ↦↦Cı _)› [51, 51, 51, 51, 51, 51, 51, 51] 51)
syntax_consts "_is_cat_pushout" ⇌ is_cat_pushout
translations "x : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X ↦↦C⇘α⇙ ℭ" ⇌
  "CONST is_cat_pushout α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x"


text‹Rules.›

lemma (in is_cat_pullback) is_cat_pullback_axioms'[cat_lim_cs_intros]:
  assumes "α' = α"
    and "𝔞' = 𝔞"
    and "𝔤' = 𝔤"
    and "𝔬' = 𝔬"
    and "𝔣' = 𝔣"
    and "𝔟' = 𝔟"
    and "ℭ' = ℭ"
    and "X' = X"
  shows "x : X' <CF.pb 𝔞'→𝔤'→𝔬'←𝔣'←𝔟' ↦↦C⇘α'⇙ ℭ'"
  unfolding assms by (rule is_cat_pullback_axioms)

mk_ide rf is_cat_pullback_def
  |intro is_cat_pullbackI|
  |dest is_cat_pullbackD[dest]|
  |elim is_cat_pullbackE[elim]|

lemmas [cat_lim_cs_intros] = is_cat_pullbackD

lemma (in is_cat_pushout) is_cat_pushout_axioms'[cat_lim_cs_intros]:
  assumes "α' = α"
    and "𝔞' = 𝔞"
    and "𝔤' = 𝔤"
    and "𝔬' = 𝔬"
    and "𝔣' = 𝔣"
    and "𝔟' = 𝔟"
    and "ℭ' = ℭ"
    and "X' = X"
  shows "x : 𝔞'←𝔤'←𝔬'→𝔣'→𝔟' >CF.po X' ↦↦C⇘α'⇙ ℭ'"
  unfolding assms by (rule is_cat_pushout_axioms)

mk_ide rf is_cat_pushout_def
  |intro is_cat_pushoutI|
  |dest is_cat_pushoutD[dest]|
  |elim is_cat_pushoutE[elim]|

lemmas [cat_lim_cs_intros] = is_cat_pushoutD


text‹Duality.›

lemma (in is_cat_pullback) is_cat_pushout_op:
  "op_ntcf x : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X ↦↦C⇘α⇙ op_cat ℭ"
  by (intro is_cat_pushoutI) 
    (cs_concl cs_shallow cs_simp: cat_op_simps cs_intro: cat_op_intros)+

lemma (in is_cat_pullback) is_cat_pushout_op'[cat_op_intros]:
  assumes "ℭ' = op_cat ℭ"
  shows "op_ntcf x : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X ↦↦C⇘α⇙ ℭ'"
  unfolding assms by (rule is_cat_pushout_op)

lemmas [cat_op_intros] = is_cat_pullback.is_cat_pushout_op'

lemma (in is_cat_pushout) is_cat_pullback_op:
  "op_ntcf x : X <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ op_cat ℭ"
  by (intro is_cat_pullbackI) 
    (cs_concl cs_shallow cs_simp: cat_op_simps cs_intro: cat_op_intros)+

lemma (in is_cat_pushout) is_cat_pullback_op'[cat_op_intros]:
  assumes "ℭ' = op_cat ℭ"
  shows "op_ntcf x : X <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ'"
  unfolding assms by (rule is_cat_pullback_op)

lemmas [cat_op_intros] = is_cat_pushout.is_cat_pullback_op'


text‹Elementary properties.›

lemma cat_cone_cospan:
  assumes "x : X <CF.cone ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ"
    and "cf_scospan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ"
  shows "x⦇NTMap⦈⦇𝔬SS⦈ = 𝔤 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈"
    and "x⦇NTMap⦈⦇𝔬SS⦈ = 𝔣 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
    and "𝔤 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ = 𝔣 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
proof-
  interpret x: is_cat_cone α X ‹→∙←C› ℭ ‹⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙› x 
    by (rule assms(1))
  interpret cospan: cf_scospan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ by (rule assms(2))
  have 𝔤SS: "𝔤SS : 𝔞SS ↦⇘→∙←C⇙ 𝔬SS" and 𝔣SS: "𝔣SS : 𝔟SS ↦⇘→∙←C⇙ 𝔬SS" 
    by (cs_concl cs_intro: cat_ss_cs_intros)+
  note x.cat_cone_Comp_commute[cat_cs_simps del]
  from x.ntcf_Comp_commute[OF 𝔤SS] 𝔤SS 𝔣SS show
    "x⦇NTMap⦈⦇𝔬SS⦈ = 𝔤 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈"
    by 
      (
        cs_prems cs_shallow
          cs_simp: cat_ss_cs_simps cat_cs_simps cs_intro: cat_cs_intros
      )
  moreover from x.ntcf_Comp_commute[OF 𝔣SS] 𝔤SS 𝔣SS show 
    "x⦇NTMap⦈⦇𝔬SS⦈ = 𝔣 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
    by 
      (
        cs_prems cs_shallow 
          cs_simp: cat_ss_cs_simps cat_cs_simps cs_intro: cat_cs_intros
      )
  ultimately show "𝔤 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ = 𝔣 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈" by simp
qed

lemma (in is_cat_pullback) cat_pb_cone_cospan:
  shows "x⦇NTMap⦈⦇𝔬SS⦈ = 𝔤 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈"
    and "x⦇NTMap⦈⦇𝔬SS⦈ = 𝔣 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
    and "𝔤 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ = 𝔣 ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
  by (all‹rule cat_cone_cospan[OF is_cat_cone_axioms cf_scospan_axioms]›)

lemma cat_cocone_span:
  assumes "x : ⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙ >CF.cocone X : ←∙→C ↦↦C⇘α⇙ ℭ"
    and "cf_sspan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ"
  shows "x⦇NTMap⦈⦇𝔬SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ 𝔤"
    and "x⦇NTMap⦈⦇𝔬SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ 𝔣"
    and "x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ 𝔤 = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ 𝔣"
proof-
  interpret x: is_cat_cocone α X ‹←∙→C› ℭ ‹⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙› x
    by (rule assms(1))
  interpret span: cf_sspan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ by (rule assms(2))
  note op = 
    cat_cone_cospan
      [
        OF 
          x.is_cat_cone_op[unfolded cat_op_simps] 
          span.cf_scospan_op, 
          unfolded cat_op_simps
      ]
  from op(1) show "x⦇NTMap⦈⦇𝔬SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ 𝔤"
    by 
      (
        cs_prems  
          cs_simp: cat_ss_cs_simps cat_op_simps 
          cs_intro: cat_cs_intros cat_ss_cs_intros
      )
  moreover from op(2) show "x⦇NTMap⦈⦇𝔬SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ 𝔣"
    by 
      (
        cs_prems 
          cs_simp: cat_ss_cs_simps cat_op_simps 
          cs_intro: cat_cs_intros cat_ss_cs_intros
      )
  ultimately show "x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ 𝔤 = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ 𝔣" by auto
qed

lemma (in is_cat_pushout) cat_po_cocone_span:
  shows "x⦇NTMap⦈⦇𝔬SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ 𝔤"
    and "x⦇NTMap⦈⦇𝔬SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ 𝔣"
    and "x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ 𝔤 = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ 𝔣"
  by (all‹rule cat_cocone_span[OF is_cat_cocone_axioms cf_sspan_axioms]›)


subsubsection‹Universal property›

lemma is_cat_pullbackI':
  assumes "x : X <CF.cone ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ"
    and "cf_scospan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ"
    and "⋀x' X'. x' : X' <CF.cone ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ ⟹
      ∃!f'.
        f' : X' ↦⇘ℭ⇙ X ∧
        x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f' ∧
        x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f'"
  shows "x : X <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ"
proof(intro is_cat_pullbackI is_cat_limitI)

  show "x : X <CF.cone ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ" 
    by (rule assms(1))
  interpret x: is_cat_cone α X ‹→∙←C› ℭ ‹⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙› x 
    by (rule assms(1))
  show "cf_scospan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ" by (rule assms(2))
  interpret cospan: cf_scospan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ by (rule assms(2))

  fix u' r' assume prems:
    "u' : r' <CF.cone ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ"

  interpret u': is_cat_cone α r' ‹→∙←C› ℭ ‹⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙› u' 
    by (rule prems)

  from assms(3)[OF prems] obtain f' 
    where f': "f' : r' ↦⇘ℭ⇙ X"
      and u'_𝔞SS: "u'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f'"
      and u'_𝔟SS: "u'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f'"
      and unique_f': "⋀f''.
        ⟦
          f'' : r' ↦⇘ℭ⇙ X;
          u'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f'';
          u'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f''
        ⟧ ⟹ f'' = f'"
    by metis

  show "∃!f'. f' : r' ↦⇘ℭ⇙ X ∧ u' = x ∙NTCF ntcf_const →∙←C ℭ f'"
  proof(intro ex1I conjI; (elim conjE)?)

    show "u' = x ∙NTCF ntcf_const →∙←C ℭ f'"
    proof(rule ntcf_eqI)
      show "u' : cf_const →∙←C ℭ r' ↦CF ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ"
        by (rule u'.is_ntcf_axioms)
      from f' show 
        "x ∙NTCF ntcf_const →∙←C ℭ f' :
          cf_const →∙←C ℭ r' ↦CF ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ :
          →∙←C ↦↦C⇘α⇙ ℭ"
        by (cs_concl cs_simp: cat_cs_simps cs_intro: cat_cs_intros)
      from f' have dom_rhs: 
        "𝒟∘ ((x ∙NTCF ntcf_const →∙←C ℭ f')⦇NTMap⦈) = →∙←C⦇Obj⦈"
        by (cs_concl cs_simp: cat_cs_simps cs_intro: cat_cs_intros)
      show "u'⦇NTMap⦈ = (x ∙NTCF ntcf_const →∙←C ℭ f')⦇NTMap⦈"
      proof(rule vsv_eqI, unfold cat_cs_simps dom_rhs)
        fix a assume prems': "a ∈∘ →∙←C⦇Obj⦈"
        from this f' x.is_ntcf_axioms show
          "u'⦇NTMap⦈⦇a⦈ = (x ∙NTCF ntcf_const →∙←C ℭ f')⦇NTMap⦈⦇a⦈"
          by (elim the_cat_scospan_ObjE; simp only:)
            (
              cs_concl 
                cs_simp:
                  cat_cs_simps cat_ss_cs_simps 
                  u'_𝔟SS u'_𝔞SS 
                  cat_cone_cospan(1)[OF assms(1,2)] 
                  cat_cone_cospan(1)[OF prems assms(2)] 
                cs_intro: cat_cs_intros cat_ss_cs_intros
            )+
      qed (cs_concl cs_intro: cat_cs_intros | auto)+
    qed simp_all

    fix f'' assume prems: 
      "f'' : r' ↦⇘ℭ⇙ X" "u' = x ∙NTCF ntcf_const →∙←C ℭ f''"
    have 𝔞SS: "𝔞SS ∈∘ →∙←C⦇Obj⦈" and 𝔟SS: "𝔟SS ∈∘ →∙←C⦇Obj⦈" 
      by (cs_concl cs_intro: cat_ss_cs_intros)+
    have "u'⦇NTMap⦈⦇a⦈ = x⦇NTMap⦈⦇a⦈ ∘A⇘ℭ⇙ f''" if "a ∈∘ →∙←C⦇Obj⦈" for a
    proof-
      from prems(2) have 
        "u'⦇NTMap⦈⦇a⦈ = (x ∙NTCF ntcf_const →∙←C ℭ f'')⦇NTMap⦈⦇a⦈"
        by simp
      from this that prems(1) show "u'⦇NTMap⦈⦇a⦈ = x⦇NTMap⦈⦇a⦈ ∘A⇘ℭ⇙ f''"
        by (cs_prems cs_simp: cat_cs_simps cs_intro: cat_cs_intros)
    qed
    from unique_f'[OF prems(1) this[OF 𝔞SS] this[OF 𝔟SS]] show "f'' = f'".

  qed (intro f')

qed

lemma is_cat_pushoutI':
  assumes "x : ⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙ >CF.cocone X : ←∙→C ↦↦C⇘α⇙ ℭ"
    and "cf_sspan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ"
    and "⋀x' X'. x' : ⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙ >CF.cocone X' : ←∙→C ↦↦C⇘α⇙ ℭ ⟹
      ∃!f'.
        f' : X ↦⇘ℭ⇙ X' ∧
        x'⦇NTMap⦈⦇𝔞SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ ∧
        x'⦇NTMap⦈⦇𝔟SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
  shows "x : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X ↦↦C⇘α⇙ ℭ"
proof-
  interpret x: is_cat_cocone α X ‹←∙→C› ℭ ‹⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙› x 
    by (rule assms(1))
  interpret span: cf_sspan α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ by (rule assms(2))
  have assms_3': 
    "∃!f'.
      f' : X ↦⇘ℭ⇙ X' ∧
      x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘op_cat ℭ⇙ f' ∧
      x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘op_cat ℭ⇙ f'"
    if "x' : X' <CF.cone ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘op_cat ℭ⇙ : →∙←C ↦↦C⇘α⇙ op_cat ℭ"
    for x' X'
  proof-
    from that(1) have [cat_op_simps]:
      "f' : X ↦⇘ℭ⇙ X' ∧ 
      x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘op_cat ℭ⇙ f' ∧
      x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘op_cat ℭ⇙ f' ⟷
        f' : X ↦⇘ℭ⇙ X' ∧
        x'⦇NTMap⦈⦇𝔞SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ ∧
        x'⦇NTMap⦈⦇𝔟SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈" 
      for f'
      by (intro iffI conjI; (elim conjE)?)
        (
          cs_concl 
            cs_simp: category.op_cat_Comp[symmetric] cat_op_simps cat_cs_simps 
            cs_intro: cat_cs_intros cat_ss_cs_intros
        )+
    interpret x': 
      is_cat_cone α X' ‹→∙←C› ‹op_cat ℭ› ‹⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘op_cat ℭ⇙› x'
      by (rule that)
    show ?thesis
      unfolding cat_op_simps
      by 
        (
          rule assms(3)[
            OF x'.is_cat_cocone_op[unfolded cat_op_simps], 
            unfolded cat_op_simps
            ]
        )
  qed
  interpret op_x: is_cat_pullback α 𝔞 𝔤 𝔬 𝔣 𝔟 ‹op_cat ℭ› X ‹op_ntcf x› 
    using 
      is_cat_pullbackI'
        [
          OF x.is_cat_cone_op[unfolded cat_op_simps] 
          span.cf_scospan_op, 
          unfolded cat_op_simps, 
          OF assms_3'
        ]
    by simp
  show "x : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X ↦↦C⇘α⇙ ℭ"
    by (rule op_x.is_cat_pushout_op[unfolded cat_op_simps])
qed
                   
lemma (in is_cat_pullback) cat_pb_unique_cone:
  assumes "x' : X' <CF.cone ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ"
  shows "∃!f'.
    f' : X' ↦⇘ℭ⇙ X ∧
    x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f' ∧
    x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f'"
proof-
  interpret x': is_cat_cone α X' ‹→∙←C› ℭ ‹⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙› x' 
    by (rule assms)
  from cat_lim_ua_fo[OF assms] obtain f'
    where f': "f' : X' ↦⇘ℭ⇙ X" 
      and x'_def: "x' = x ∙NTCF ntcf_const →∙←C ℭ f'"
      and unique_f': "⋀f''.
        ⟦ f'' : X' ↦⇘ℭ⇙ X; x' = x ∙NTCF ntcf_const →∙←C ℭ f'' ⟧ ⟹
        f'' = f'"
    by auto
  have 𝔞SS: "𝔞SS ∈∘ →∙←C⦇Obj⦈" and 𝔟SS: "𝔟SS ∈∘ →∙←C⦇Obj⦈"
    by (cs_concl cs_intro: cat_ss_cs_intros)+
  show ?thesis
  proof(intro ex1I conjI; (elim conjE)?)
    show "f' : X' ↦⇘ℭ⇙ X" by (rule f')
    have "x'⦇NTMap⦈⦇a⦈ = x⦇NTMap⦈⦇a⦈ ∘A⇘ℭ⇙ f'" if "a ∈∘ →∙←C⦇Obj⦈" for a
    proof-
      from x'_def have 
        "x'⦇NTMap⦈⦇a⦈ = (x ∙NTCF ntcf_const →∙←C ℭ f')⦇NTMap⦈⦇a⦈"
        by simp
      from this that f' show "x'⦇NTMap⦈⦇a⦈ = x⦇NTMap⦈⦇a⦈ ∘A⇘ℭ⇙ f'"
        by (cs_prems cs_simp: cat_cs_simps cs_intro: cat_cs_intros)
    qed
    from this[OF 𝔞SS] this[OF 𝔟SS] show 
      "x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f'"
      "x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f'"
      by auto
    fix f'' assume prems': 
      "f'' : X' ↦⇘ℭ⇙ X"
      "x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f''"
      "x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f''"
    have "x' = x ∙NTCF ntcf_const →∙←C ℭ f''"
    proof(rule ntcf_eqI)
      show "x' : cf_const →∙←C ℭ X' ↦CF ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ : →∙←C ↦↦C⇘α⇙ ℭ"
        by (rule x'.is_ntcf_axioms)
      from prems'(1) show
        "x ∙NTCF ntcf_const →∙←C ℭ f'' :
          cf_const →∙←C ℭ X' ↦CF ⟨𝔞→𝔤→𝔬←𝔣←𝔟⟩CF⇘ℭ⇙ :
          →∙←C ↦↦C⇘α⇙ ℭ"
        by (cs_concl cs_simp: cat_cs_simps cs_intro: cat_cs_intros)
      have dom_lhs: "𝒟∘ (x'⦇NTMap⦈) = →∙←C⦇Obj⦈" 
        by (cs_concl cs_shallow cs_simp: cat_cs_simps)
      from prems'(1) have dom_rhs:
        "𝒟∘ ((x ∙NTCF ntcf_const →∙←C ℭ f'')⦇NTMap⦈) = →∙←C⦇Obj⦈"
        by (cs_concl cs_simp: cat_cs_simps cs_intro: cat_cs_intros)
      show "x'⦇NTMap⦈ = (x ∙NTCF ntcf_const →∙←C ℭ f'')⦇NTMap⦈"
      proof(rule vsv_eqI, unfold dom_lhs dom_rhs)
        fix a assume prems'': "a ∈∘ →∙←C⦇Obj⦈"
        from this prems'(1) show 
          "x'⦇NTMap⦈⦇a⦈ = (x ∙NTCF ntcf_const →∙←C ℭ f'')⦇NTMap⦈⦇a⦈"
          by (elim the_cat_scospan_ObjE; simp only:)
            (
              cs_concl 
                cs_simp: 
                  prems'(2,3)
                  cat_cone_cospan(1,2)[OF assms cf_scospan_axioms] 
                  cat_pb_cone_cospan 
                  cat_ss_cs_simps cat_cs_simps 
                cs_intro: cat_ss_cs_intros cat_cs_intros
            )+
      qed (auto simp: cat_cs_intros)
    qed simp_all
    from unique_f'[OF prems'(1) this] show "f'' = f'".
  qed
qed

lemma (in is_cat_pullback) cat_pb_unique:
  assumes "x' : X' <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ"
  shows "∃!f'. f' : X' ↦⇘ℭ⇙ X ∧ x' = x ∙NTCF ntcf_const →∙←C ℭ f'"
  by (rule cat_lim_unique[OF is_cat_pullbackD(1)[OF assms]])

lemma (in is_cat_pullback) cat_pb_unique':
  assumes "x' : X' <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ"
  shows "∃!f'.
    f' : X' ↦⇘ℭ⇙ X ∧
    x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f' ∧
    x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f'"
proof-
  interpret x': is_cat_pullback α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X' x' by (rule assms(1))
  show ?thesis by (rule cat_pb_unique_cone[OF x'.is_cat_cone_axioms])
qed

lemma (in is_cat_pushout) cat_po_unique_cocone:
  assumes "x' : ⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙ >CF.cocone X' : ←∙→C ↦↦C⇘α⇙ ℭ"
  shows "∃!f'.
    f' : X ↦⇘ℭ⇙ X' ∧
    x'⦇NTMap⦈⦇𝔞SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ ∧
    x'⦇NTMap⦈⦇𝔟SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
proof-
  interpret x': is_cat_cocone α X' ‹←∙→C› ℭ ‹⟨𝔞←𝔤←𝔬→𝔣→𝔟⟩CF⇘ℭ⇙› x'
    by (rule assms(1))
  have [cat_op_simps]:
    "f' : X ↦⇘ℭ⇙ X' ∧
    x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘op_cat ℭ⇙ f' ∧
    x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘op_cat ℭ⇙ f' ⟷
      f' : X ↦⇘ℭ⇙ X' ∧
      x'⦇NTMap⦈⦇𝔞SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ ∧
      x'⦇NTMap⦈⦇𝔟SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈" 
    for f'
    by (intro iffI conjI; (elim conjE)?)
      (
        cs_concl 
          cs_simp: category.op_cat_Comp[symmetric] cat_op_simps cat_cs_simps  
          cs_intro: cat_cs_intros cat_ss_cs_intros
      )+
  show ?thesis
    by 
      (
        rule is_cat_pullback.cat_pb_unique_cone[
          OF is_cat_pullback_op x'.is_cat_cone_op[unfolded cat_op_simps], 
          unfolded cat_op_simps
          ]
     )
qed

lemma (in is_cat_pushout) cat_po_unique:
  assumes "x' : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X' ↦↦C⇘α⇙ ℭ"
  shows "∃!f'. f' : X ↦⇘ℭ⇙ X' ∧ x' = ntcf_const ←∙→C ℭ f' ∙NTCF x"
  by (rule cat_colim_unique[OF is_cat_pushoutD(1)[OF assms]])

lemma (in is_cat_pushout) cat_po_unique':
  assumes "x' : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X' ↦↦C⇘α⇙ ℭ"
  shows "∃!f'.
    f' : X ↦⇘ℭ⇙ X' ∧
    x'⦇NTMap⦈⦇𝔞SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈ ∧
    x'⦇NTMap⦈⦇𝔟SS⦈ = f' ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
proof-
  interpret x': is_cat_pushout α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X' x' by (rule assms(1))
  show ?thesis by (rule cat_po_unique_cocone[OF x'.is_cat_cocone_axioms])
qed

lemma cat_pullback_ex_is_iso_arr:
  assumes "x : X <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ"
    and "x' : X' <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ"
  obtains f where "f : X' ↦iso⇘ℭ⇙ X" 
    and "x' = x ∙NTCF ntcf_const →∙←C  ℭ f"
proof-
  interpret x: is_cat_pullback α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x by (rule assms(1))
  interpret x': is_cat_pullback α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X' x' by (rule assms(2))
  from that show ?thesis
    by 
      (
        elim cat_lim_ex_is_iso_arr[
          OF x.is_cat_limit_axioms x'.is_cat_limit_axioms
          ]
      )
qed

lemma cat_pullback_ex_is_iso_arr':
  assumes "x : X <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ"
    and "x' : X' <CF.pb 𝔞→𝔤→𝔬←𝔣←𝔟 ↦↦C⇘α⇙ ℭ"
  obtains f where "f : X' ↦iso⇘ℭ⇙ X" 
    and "x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f"
    and "x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f"
proof-
  interpret x: is_cat_pullback α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x by (rule assms(1))
  interpret x': is_cat_pullback α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X' x' by (rule assms(2))
  obtain f where f: "f : X' ↦iso⇘ℭ⇙ X"
    and "j ∈∘ →∙←C⦇Obj⦈ ⟹ x'⦇NTMap⦈⦇j⦈ = x⦇NTMap⦈⦇j⦈ ∘A⇘ℭ⇙ f" for j
    by 
      (
        elim cat_lim_ex_is_iso_arr'[
          OF x.is_cat_limit_axioms x'.is_cat_limit_axioms
          ]
      )
  then have 
    "x'⦇NTMap⦈⦇𝔞SS⦈ = x⦇NTMap⦈⦇𝔞SS⦈ ∘A⇘ℭ⇙ f" 
    "x'⦇NTMap⦈⦇𝔟SS⦈ = x⦇NTMap⦈⦇𝔟SS⦈ ∘A⇘ℭ⇙ f"
    by (auto simp: cat_ss_cs_intros)
  with f show ?thesis using that by simp
qed

lemma cat_pushout_ex_is_iso_arr:
  assumes "x : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X ↦↦C⇘α⇙ ℭ"
    and "x' : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X' ↦↦C⇘α⇙ ℭ"
  obtains f where "f : X ↦iso⇘ℭ⇙ X'" 
    and "x' = ntcf_const ←∙→C ℭ f ∙NTCF x"
proof-
  interpret x: is_cat_pushout α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x by (rule assms(1))
  interpret x': is_cat_pushout α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X' x' by (rule assms(2))
  from that show ?thesis
    by 
      (
        elim cat_colim_ex_is_iso_arr[
          OF x.is_cat_colimit_axioms x'.is_cat_colimit_axioms
          ]
      )
qed

lemma cat_pushout_ex_is_iso_arr':
  assumes "x : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X ↦↦C⇘α⇙ ℭ"
    and "x' : 𝔞←𝔤←𝔬→𝔣→𝔟 >CF.po X' ↦↦C⇘α⇙ ℭ"
  obtains f where "f : X ↦iso⇘ℭ⇙ X'" 
    and "x'⦇NTMap⦈⦇𝔞SS⦈ = f ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈"
    and "x'⦇NTMap⦈⦇𝔟SS⦈ = f ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
proof-
  interpret x: is_cat_pushout α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X x by (rule assms(1))
  interpret x': is_cat_pushout α 𝔞 𝔤 𝔬 𝔣 𝔟 ℭ X' x' by (rule assms(2))
  obtain f where f: "f : X ↦iso⇘ℭ⇙ X'"
    and "j ∈∘ ←∙→C⦇Obj⦈ ⟹ x'⦇NTMap⦈⦇j⦈ = f ∘A⇘ℭ⇙ x⦇NTMap⦈⦇j⦈" for j
    by 
      (
        elim cat_colim_ex_is_iso_arr'[
          OF x.is_cat_colimit_axioms x'.is_cat_colimit_axioms
          ]
      )
  then have "x'⦇NTMap⦈⦇𝔞SS⦈ = f ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔞SS⦈"
    and "x'⦇NTMap⦈⦇𝔟SS⦈ = f ∘A⇘ℭ⇙ x⦇NTMap⦈⦇𝔟SS⦈"
    by (auto simp: cat_ss_cs_intros)
  with f show ?thesis using that by simp
qed

text‹\newpage›

end