Theory Coherence

(*  Title:       Coherence
    Author:      Eugene W. Stark <stark@cs.stonybrook.edu>, 2019
    Maintainer:  Eugene W. Stark <stark@cs.stonybrook.edu>
*)

section "Coherence"

theory Coherence
imports Bicategory
begin

 text ‹
   \sloppypar
   In this section, we generalize to bicategories the proof of the Coherence Theorem
   that we previously gave for monoidal categories
   (see MonoidalCategory.evaluation_map.coherence› in @{session MonoidalCategory}).
   As was the case for the previous proof, the current proof takes a syntactic approach.
   First we define a formal ``bicategorical language'' of terms constructed using
   syntactic operators that correspond to the various operations (vertical and horizontal
   composition, associators and unitors) found in a bicategory.
   Terms of the language are classified as formal ``arrows'', ``identities'', or ``objects''
   according to the syntactic operators used in their formation.
   A class of terms called ``canonical'' is also defined in this way.
   Functions that map ``arrows'' to their ``domain'' and ``codomain'', and to their
   ``source'' and ``target'' are defined by recursion on the structure of terms.
   Next, we define a notion of ``normal form'' for terms in this language and we
   give a recursive definition of a function that maps terms to their normal forms.
   Normalization moves vertical composition inside of horizontal composition and
   ``flattens'' horizontal composition by associating all horizontal compositions to the right.
   In addition, normalization deletes from a term any horizontal composites involving an arrow
   and its source or target, replacing such composites by just the arrow itself.
   We then define a ``reduction function'' that maps each identity term t› to a
   ``canonical'' term t that connects t› with its normal form.  The definition of reduction
   is also recursive, but it is somewhat more complex than normalization in that it
   involves two mutually recursive functions: one that applies to any identity term
   and another that applies only to terms that are the horizontal composite
   of two identity terms.

   The next step is to define an ``evaluation function'' that evaluates terms in a given
   bicategory (which is left as an unspecified parameter).  We show that evaluation respects
   bicategorical structure:
   the domain, codomain, source, and target mappings on terms correspond under evaluation
   to the actual domain, codomain, source and target mappings on the given bicategory,
   the vertical and horizontal composition on terms correspond to the actual vertical
   and horizontal composition of the bicategory, and unit and associativity terms evaluate
   to the actual unit and associativity isomorphisms of the bicategory.
   In addition, ``object terms'' evaluate to objects (\emph{i.e.}~0-cells),
   ``identity terms'' evaluate to identities (\emph{i.e.}~1-cells),
   ``arrow terms'' evaluate to arrows (\emph{i.e.}~2-cells), and ``canonical terms'' evaluate
   to canonical isomorphisms.
   A term is defined to be ``coherent'' if, roughly speaking, it is a formal arrow
   whose evaluation commutes with the evaluations of the reductions to normal form of
   its domain and codomain.
   We then prove the Coherence Theorem, expressed in the form: ``every arrow is coherent.''
   This implies a more classical version of the Coherence Theorem, which says that:
   ``syntactically parallel arrows with the same normal form have equal evaluations''.
  ›

  subsection "Bicategorical Language"

    text ‹
      For the most part, the definition of the ``bicategorical language'' of terms is
      a straightforward generalization of the ``monoidal language'' that we used for
      monoidal categories.
      Some modifications are required, however, due to the fact that horizontal composition
      in a bicategory is a partial operation, whereas the the tensor product in a monoidal
      category is well-defined for all pairs of arrows.
      One difference is that we have found it necessary to introduce a new class of primitive
      terms whose elements represent ``formal objects'', so that there is some way to
      identify the source and target of what would otherwise be an empty horizontal composite.
      This was not an issue for monoidal categories, because the totality of horizontal
      composition meant that there was no need for syntactically defined sources and targets.
      Another difference is what we have chosen for the ``generators'' of the language
      and how they are used to form primitive terms.  For monoidal categories,
      we supposed that we were given a category C› and the syntax contained a constructor
      to form a primitive term corresponding to each arrow of C›.
      We assumed a category as the given data, rather than something less structured,
      such as a graph, because we were primarily interested in the tensor product and
      the associators and unitors, and were relatively uninterested in the strictly
      associative and unital composition of the underlying category.
      For bicategories, we also take the vertical composition as given for the same
      reasons; however, this is not yet sufficient due to the fact that horizontal
      composition in a bicategory is a partial operation, in contrast to the tensor
      product in a monoidal category, which is defined for all pairs of arrows.
      To deal with this issue, for bicategories we assume that source and target
      mappings are also given, so that the given data forms a category with
      ``horizontal homs''.  The given source and target mappings are extended to all terms
      and used to define when two terms are ``formally horizontally composable''.
  ›

  locale bicategorical_language =
    category V +
    horizontal_homs V src trg
    for V :: "'a comp"                       (infixr  55)
    and src :: "'a  'a"
    and trg :: "'a  'a"
  begin

    text ‹
      Constructor Prim0 is used to construct ``formal objects'' and Prim› is used to
      construct primitive terms that are not formal objects.
    ›

    datatype (discs_sels) 't "term" =
      Prim0 't                             (_0)
    | Prim 't                              (_)
    | Hcomp "'t term" "'t term"            (infixr  53)
    | Vcomp "'t term" "'t term"            (infixr  55)
    | Lunit "'t term"                      (𝗅[_])
    | Lunit' "'t term"                     (𝗅-1[_])
    | Runit "'t term"                      (𝗋[_])
    | Runit' "'t term"                     (𝗋-1[_])
    | Assoc "'t term" "'t term" "'t term"  (𝖺[_, _, _])
    | Assoc' "'t term" "'t term" "'t term" (𝖺-1[_, _, _])

    text ‹
      We define formal domain, codomain, source, and target functions on terms.
    ›

    primrec Src :: "'a term  'a term"
    where "Src μ0 = μ0"
        | "Src μ = src μ0"
        | "Src (t  u) = Src u"
        | "Src (t  u) = Src t"
        | "Src 𝗅[t] = Src t"
        | "Src 𝗅-1[t] = Src t"
        | "Src 𝗋[t] = Src t"
        | "Src 𝗋-1[t] = Src t"
        | "Src 𝖺[t, u, v] = Src v"
        | "Src 𝖺-1[t, u, v] = Src v"

    primrec Trg :: "'a term  'a term"
    where "Trg μ0 = μ0"
        | "Trg μ = trg μ0"
        | "Trg (t  u) = Trg t"
        | "Trg (t  u) = Trg t"
        | "Trg 𝗅[t] = Trg t"
        | "Trg 𝗅-1[t] = Trg t"
        | "Trg 𝗋[t] = Trg t"
        | "Trg 𝗋-1[t] = Trg t"
        | "Trg 𝖺[t, u, v] = Trg t"
        | "Trg 𝖺-1[t, u, v] = Trg t"

    primrec Dom :: "'a term  'a term"
    where "Dom μ0 = μ0"
        | "Dom μ = dom μ"
        | "Dom (t  u) = Dom t  Dom u"
        | "Dom (t  u) = Dom u"
        | "Dom 𝗅[t] = Trg t  Dom t"
        | "Dom 𝗅-1[t] = Dom t"
        | "Dom 𝗋[t] = Dom t  Src t"
        | "Dom 𝗋-1[t] = Dom t"
        | "Dom 𝖺[t, u, v] = (Dom t  Dom u)  Dom v"
        | "Dom 𝖺-1[t, u, v] = Dom t  (Dom u  Dom v)"

    primrec Cod :: "'a term  'a term"
    where "Cod μ0 = μ0"
        | "Cod μ = cod μ"
        | "Cod (t  u) = Cod t  Cod u"
        | "Cod (t  u) = Cod t"
        | "Cod 𝗅[t] = Cod t"
        | "Cod 𝗅-1[t] = Trg t  Cod t"
        | "Cod 𝗋[t] = Cod t"
        | "Cod 𝗋-1[t] = Cod t  Src t"
        | "Cod 𝖺[t, u, v] = Cod t  (Cod u  Cod v)"
        | "Cod 𝖺-1[t, u, v] = (Cod t  Cod u)  Cod v"

    text ‹
      A term is a ``formal arrow'' if it is constructed from primitive arrows in such a way
      that horizontal and vertical composition are applied only to formally composable pairs
      of terms.  The definitions of ``formal identity'' and ``formal object'' follow a
      similar pattern.
    ›

    primrec Arr :: "'a term  bool"
    where "Arr μ0 = obj μ"
        | "Arr μ = arr μ"
        | "Arr (t  u) = (Arr t  Arr u  Src t = Trg u)"
        | "Arr (t  u) = (Arr t  Arr u  Dom t = Cod u)"
        | "Arr 𝗅[t] = Arr t"
        | "Arr 𝗅-1[t] = Arr t"
        | "Arr 𝗋[t] = Arr t"
        | "Arr 𝗋-1[t] = Arr t"
        | "Arr 𝖺[t, u, v] = (Arr t  Arr u  Arr v  Src t = Trg u  Src u = Trg v)"
        | "Arr 𝖺-1[t, u, v] = (Arr t  Arr u  Arr v  Src t = Trg u  Src u = Trg v)"

    primrec Ide :: "'a term  bool"
    where "Ide μ0 = obj μ"
        | "Ide μ = ide μ"
        | "Ide (t  u) = (Ide t  Ide u  Src t = Trg u)"
        | "Ide (t  u) = False"
        | "Ide 𝗅[t] = False"
        | "Ide 𝗅-1[t] = False"
        | "Ide 𝗋[t] = False"
        | "Ide 𝗋-1[t] = False"
        | "Ide 𝖺[t, u, v] = False"
        | "Ide 𝖺-1[t, u, v] = False"

    primrec Obj :: "'a term  bool"
    where "Obj μ0 = obj μ"
        | "Obj μ = False"
        | "Obj (t  u) = False"
        | "Obj (t  u) = False"
        | "Obj 𝗅[t] = False"
        | "Obj 𝗅-1[t] = False"
        | "Obj 𝗋[t] = False"
        | "Obj 𝗋-1[t] = False"
        | "Obj 𝖺[t, u, v] = False"
        | "Obj 𝖺-1[t, u, v] = False"

    abbreviation HSeq :: "'a term  'a term  bool"
    where "HSeq t u  Arr t  Arr u  Src t = Trg u"

    abbreviation VSeq :: "'a term  'a term  bool"
    where "VSeq t u  Arr t  Arr u  Dom t = Cod u"

    abbreviation HPar :: "'a term => 'a term  bool"
    where "HPar t u  Arr t  Arr u  Src t = Src u  Trg t = Trg u"

    abbreviation VPar :: "'a term => 'a term  bool"
    where "VPar t u  Arr t  Arr u  Dom t = Dom u  Cod t = Cod u"

    abbreviation HHom :: "'a term  'a term  'a term set"
    where "HHom a b  { t. Arr t  Src t = a  Trg t = b }"

    abbreviation VHom :: "'a term  'a term  'a term set"
    where "VHom f g  { t. Arr t  Dom t = f  Cod t = g }"

    lemma is_Prim0_Src:
    shows "is_Prim0 (Src t)"
      by (induct t; simp)

    lemma is_Prim0_Trg:
    shows "is_Prim0 (Trg t)"
      by (induct t; simp)

    lemma Src_Src [simp]:
    shows "Arr t  Src (Src t) = Src t"
      by (induct t) auto

    lemma Trg_Trg [simp]:
    shows "Arr t  Trg (Trg t) = Trg t"
      by (induct t) auto

    lemma Src_Trg [simp]:
    shows "Arr t  Src (Trg t) = Trg t"
      by (induct t) auto

    lemma Trg_Src [simp]:
    shows "Arr t  Trg (Src t) = Src t"
      by (induct t) auto

    lemma Dom_Src [simp]:
    shows "Arr t  Dom (Src t) = Src t"
      by (induct t) auto

    lemma Dom_Trg [simp]:
    shows "Arr t  Dom (Trg t) = Trg t"
      by (induct t) auto

    lemma Cod_Src [simp]:
    shows "Arr t  Cod (Src t) = Src t"
      by (induct t) auto

    lemma Cod_Trg [simp]:
    shows "Arr t  Cod (Trg t) = Trg t"
      by (induct t) auto

    lemma Src_Dom_Cod:
    shows "Arr t  Src (Dom t) = Src t  Src (Cod t) = Src t"
       using src_dom src_cod by (induct t) auto

    lemma Src_Dom [simp]:
    shows "Arr t  Src (Dom t) = Src t"
      using Src_Dom_Cod by blast

    lemma Src_Cod [simp]:
    shows "Arr t  Src (Cod t) = Src t"
      using Src_Dom_Cod by blast

    lemma Trg_Dom_Cod:
    shows "Arr t  Trg (Dom t) = Trg t  Trg (Cod t) = Trg t"
       using trg_dom trg_cod by (induct t) auto

    lemma Trg_Dom [simp]:
    shows "Arr t  Trg (Dom t) = Trg t"
      using Trg_Dom_Cod by blast

    lemma Trg_Cod [simp]:
    shows "Arr t  Trg (Cod t) = Trg t"
      using Trg_Dom_Cod by blast

    lemma VSeq_implies_HPar:
    shows "VSeq t u  HPar t u"
      using Src_Dom [of t] Src_Cod [of u] Trg_Dom [of t] Trg_Cod [of u] by auto

    lemma Dom_Dom [simp]:
    shows "Arr t  Dom (Dom t) = Dom t"
      by (induct t, auto)

    lemma Cod_Cod [simp]:
    shows "Arr t  Cod (Cod t) = Cod t"
      by (induct t, auto)

    lemma Dom_Cod [simp]:
    shows "Arr t  Dom (Cod t) = Cod t"
      by (induct t, auto)

    lemma Cod_Dom [simp]:
    shows "Arr t  Cod (Dom t) = Dom t"
      by (induct t, auto)
      
    lemma Obj_implies_Ide (*[simp]*):
    shows "Obj t  Ide t"
      by (induct t) auto

    lemma Ide_implies_Arr [simp]:
    shows "Ide t  Arr t"
      by (induct t, auto)

    lemma Dom_Ide:
    shows "Ide t  Dom t = t"
      by (induct t, auto)

    lemma Cod_Ide:
    shows "Ide t  Cod t = t"
      by (induct t, auto)

    lemma Obj_Src [simp]:
    shows "Arr t  Obj (Src t)"
      by (induct t) auto

    lemma Obj_Trg [simp]:
    shows "Arr t  Obj (Trg t)"
      by (induct t) auto

    lemma Ide_Dom [simp]:
    shows "Arr t  Ide (Dom t)"
      using Obj_implies_Ide
      by (induct t, auto)

    lemma Ide_Cod [simp]:
    shows "Arr t  Ide (Cod t)"
      using Obj_implies_Ide
      by (induct t, auto)

    lemma Arr_in_Hom:
    assumes "Arr t"
    shows "t  HHom (Src t) (Trg t)" and "t  VHom (Dom t) (Cod t)"
    proof -
      have 1: "Arr t  t  HHom (Src t) (Trg t)  t  VHom (Dom t) (Cod t)"
        by (induct t, auto)
      show "t  HHom (Src t) (Trg t)" using assms 1 by simp
      show "t  VHom (Dom t) (Cod t)" using assms 1 by simp
    qed

    lemma Ide_in_Hom:
    assumes "Ide t"
    shows "t  HHom (Src t) (Trg t)" and "t  VHom t t"
    proof -
      have 1: "Ide t  t  HHom (Src t) (Trg t)  t  VHom t t"
        by (induct t, auto)
      show "t  HHom (Src t) (Trg t)" using assms 1 by simp
      show "t  VHom t t" using assms 1 by simp
    qed

    lemma Obj_in_Hom:
    assumes "Obj t"
    shows "t  HHom t t" and "t  VHom t t"
    proof -
      have 1: "Obj t  t  HHom t t  t  VHom t t"
        by (induct t, auto)
      show "t  HHom t t" using assms 1 by simp
      show "t  VHom t t" using assms 1 by simp
    qed

    text ‹
      A formal arrow is ``canonical'' if the only primitive arrows used in its construction
      are objects and identities.
    ›

    primrec Can :: "'a term  bool"
    where "Can μ0 = obj μ"
        | "Can μ = ide μ"
        | "Can (t  u) = (Can t  Can u  Src t = Trg u)"
        | "Can (t  u) = (Can t  Can u  Dom t = Cod u)"
        | "Can 𝗅[t] = Can t"
        | "Can 𝗅-1[t] = Can t"
        | "Can 𝗋[t] = Can t"
        | "Can 𝗋-1[t] = Can t"
        | "Can 𝖺[t, u, v] = (Can t  Can u  Can v  Src t = Trg u  Src u = Trg v)"
        | "Can 𝖺-1[t, u, v] = (Can t  Can u  Can v  Src t = Trg u  Src u = Trg v)"

    lemma Ide_implies_Can:
    shows "Ide t  Can t"
      by (induct t, auto)

    lemma Can_implies_Arr:
    shows "Can t  Arr t"
      by (induct t, auto)

    text ‹
      Canonical arrows can be formally inverted.
    ›

    primrec Inv :: "'a term  'a term"
    where "Inv μ0 = μ0"
        | "Inv μ = inv μ"
        | "Inv (t  u) = (Inv t  Inv u)"
        | "Inv (t  u) = (Inv u  Inv t)"
        | "Inv 𝗅[t] = 𝗅-1[Inv t]"
        | "Inv 𝗅-1[t] = 𝗅[Inv t]"
        | "Inv 𝗋[t] = 𝗋-1[Inv t]"
        | "Inv 𝗋-1[t] = 𝗋[Inv t]"
        | "Inv 𝖺[t, u, v] = 𝖺-1[Inv t, Inv u, Inv v]"
        | "Inv 𝖺-1[t, u, v] = 𝖺[Inv t, Inv u, Inv v]"

    lemma Src_Inv [simp]:
    shows "Can t  Src (Inv t) = Src t"
      using Can_implies_Arr VSeq_implies_HPar
      apply (induct t, auto)
      by metis

    lemma Trg_Inv [simp]:
    shows "Can t  Trg (Inv t) = Trg t"
      using Can_implies_Arr VSeq_implies_HPar 
      apply (induct t, auto)
      by metis

    lemma Dom_Inv [simp]:
    shows "Can t  Dom (Inv t) = Cod t"
      by (induct t, auto)

    lemma Cod_Inv [simp]:
    shows "Can t  Cod (Inv t) = Dom t"
      by (induct t, auto)

    lemma Inv_preserves_Ide:
    shows "Ide t  Ide (Inv t)"
      using Ide_implies_Can by (induct t, auto)

    lemma Can_Inv [simp]:
    shows "Can t  Can (Inv t)"
      by (induct t, auto)

    lemma Inv_in_Hom [intro]:
    assumes "Can t"
    shows "Inv t  HHom (Src t) (Trg t)" and "Inv t  VHom (Cod t) (Dom t)"
      using assms Can_Inv Can_implies_Arr by simp_all

    lemma Inv_Ide [simp]:
    assumes "Ide a"
    shows "Inv a = a"
      using assms by (induct a, auto)

    lemma Inv_Inv [simp]:
    assumes "Can t"
    shows "Inv (Inv t) = t"
      using assms by (induct t, auto)

    subsection "Normal Terms"

    text ‹
      We call a term ``normal'' if it is either a formal object or it is constructed from
      primitive arrows using only horizontal composition associated to the right.
      Essentially, such terms are (typed) composable sequences of arrows of @{term V},
      where the empty list is represented by a formal object and  is used as
      the list constructor.
    ›

    fun Nml :: "'a term  bool"
    where "Nml μ0 = obj μ"
        | "Nml μ = arr μ"
        | "Nml (ν  u) = (arr ν  Nml u  ¬ is_Prim0 u  src ν0 = Trg u)"
        | "Nml _ = False"

    lemma Nml_HcompD:
    assumes "Nml (t  u)"
    shows "un_Prim t = t" and "arr (un_Prim t)" and "Nml t" and "Nml u"
    and "¬ is_Prim0 u" and "src (un_Prim t)0 = Trg u" and "Src t = Trg u"
    proof -
      have 1: "t = un_Prim t  arr (un_Prim t)  Nml t  Nml u  ¬ is_Prim0 u 
               src (un_Prim t)0 = Trg u"
        using assms by (cases t; simp; cases u; simp)
      show "un_Prim t = t" using 1 by simp
      show "arr (un_Prim t)" using 1 by simp
      show "Nml t" using 1 by simp
      show "Nml u" using 1 by simp
      show "¬ is_Prim0 u" using 1 by simp
      show "src (un_Prim t)0 = Trg u" using 1 by simp
      show "Src t = Trg u"
        using assms
        apply (cases t) by simp_all
    qed

    lemma Nml_implies_Arr:
    shows "Nml t  Arr t"
      by (induct t, auto simp add: Nml_HcompD)

    lemma Nml_Src [simp]:
    shows "Nml t  Nml (Src t)"
      apply (induct t, simp_all)
      using Nml_HcompD by metis

    lemma Nml_Trg [simp]:
    shows "Nml t  Nml (Trg t)"
      apply (induct t, simp_all)
      using Nml_HcompD by metis

    lemma Nml_Dom [simp]:
    shows "Nml t  Nml (Dom t)"
    proof (induct t, simp_all add: Nml_HcompD)
      fix u v
      assume I1: "Nml (Dom u)"
      assume I2: "Nml (Dom v)"
      assume uv: "Nml (u  v)"
      show "Nml (Dom u  Dom v)"
      proof -
        have 1: "is_Prim (Dom u)  arr (un_Prim (Dom u))  Dom u = dom (un_Prim u)"
          using uv by (cases u; simp; cases v, simp_all)
        have 2: "Nml v  ¬ is_Prim0 v  ¬ is_Vcomp v  ¬ is_Lunit' v  ¬ is_Runit' v"
          using uv by (cases u, simp_all; cases v, simp_all)
        have "arr (dom (un_Prim u))"
          using 1 by fastforce
        moreover have "Nml (Dom v)  ¬ is_Prim0 v"
          using 2 I2 by (cases v, simp_all)
        moreover have "src (dom (un_Prim u))0 = Trg (Dom v)"
        proof -
          have "Trg (Dom v) = Src (Dom u)"
            using uv Nml_implies_Arr by fastforce
          also have "... = src (dom (un_Prim u))0"
            using 1 by fastforce
          finally show ?thesis by argo
        qed
        moreover have "¬ is_Prim0 (Dom v)"
          using 2 by (cases v, simp_all)
        ultimately show ?thesis using 1 2 by simp
      qed
    qed
    
    lemma Nml_Cod [simp]:
    shows "Nml t  Nml (Cod t)"
    proof (induct t, simp_all add: Nml_HcompD)
      fix u v
      assume I1: "Nml (Cod u)"
      assume I2: "Nml (Cod v)"
      assume uv: "Nml (u  v)"
      show "Nml (Cod u  Cod v)"
      proof -
        have 1: "is_Prim (Cod u)  arr (un_Prim (Cod u))  Cod u = cod (un_Prim u)"
          using uv by (cases u; simp; cases v, simp_all)
        have 2: "Nml v  ¬ is_Prim0 v  ¬ is_Vcomp v  ¬ is_Lunit' v  ¬ is_Runit' v"
          using uv by (cases u; simp; cases v, simp_all)
        have "arr (cod (un_Prim u))"
          using 1 by fastforce
        moreover have "Nml (Cod v)  ¬ is_Prim0 v"
          using 2 I2 by (cases v, simp_all)
        moreover have "src (cod (un_Prim u))0 = Trg (Cod v)"
        proof -
          have "Trg (Cod v) = Src (Cod u)"
            using uv Nml_implies_Arr by fastforce
          also have "... = src (cod (un_Prim u))0"
            using 1 by fastforce
          finally show ?thesis by argo
        qed
        moreover have "¬ is_Prim0 (Cod v)"
          using 2 by (cases v; simp)
        ultimately show ?thesis using 1 2 by simp
      qed
    qed
    
    lemma Nml_Inv [simp]:
    assumes "Can t" and "Nml t"
    shows "Nml (Inv t)"
    proof -
      have "Can t  Nml t  Nml (Inv t)"
        apply (induct t, simp_all)
      proof -
        fix u v
        assume I1: "Nml u  Nml (Inv u)"
        assume I2: "Nml v  Nml (Inv v)"
        assume uv: "Can u  Can v  Src u = Trg v  Nml (u  v)"
        show "Nml (Inv u  Inv v)"
        proof -
          have u: "Arr u  Can u" using uv Can_implies_Arr by blast
          have v: "Arr v  Can v" using uv Can_implies_Arr by blast
          have 1: "un_Prim u = u  ide (un_Prim u)  Nml u  Nml v  ¬ is_Prim0 v 
                   src (un_Prim u)0 = Trg v"
            using uv Nml_HcompD [of u v] apply simp
            using uv by (cases u, simp_all)
          have 2: "un_Prim (Inv u) = Inv u  arr (un_Prim (Inv u))  Nml (Inv u)"
            using 1 by (cases u; simp)
          moreover have "Nml (Inv v)  ¬ is_Prim0 (Inv v)"
            using 1 I2 by (cases v, simp_all)
          moreover have "src (un_Prim (Inv u))0 = Trg (Inv v)"
            using 1 2 v by (cases u, simp_all)
          ultimately show ?thesis
            by (cases u, simp_all)
        qed
      qed
      thus ?thesis using assms by blast
    qed

    text ‹
      The following function defines a horizontal composition for normal terms.
      If such terms are regarded as lists, this is just (typed) list concatenation.
    ›

    fun HcompNml  (infixr  53)
    where "ν0  u = u"
        | "t  μ0 = t"
        | "ν  u = ν  u"
        | "(t  u)  v = t  (u  v)"
        | "t  u = undefined"

    lemma HcompNml_Prim [simp]:
    assumes "¬ is_Prim0 t"
    shows "ν  t = ν  t"
      using assms by (cases t, simp_all)

    lemma HcompNml_term_Prim0 [simp]:
    assumes "Src t = Trg μ0"
    shows "t  μ0 = t"
      using assms by (cases t, simp_all)

    lemma HcompNml_Nml:
    assumes "Nml (t  u)"
    shows "t  u = t  u"
      using assms HcompNml_Prim by (metis Nml_HcompD(1) Nml_HcompD(5))

    lemma Nml_HcompNml:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Nml (t  u)"
    and "Dom (t  u) = Dom t  Dom u"
    and "Cod (t  u) = Cod t  Cod u"
    and "Src (t  u) = Src u"
    and "Trg (t  u) = Trg t"
    proof -
      have 0: "u.  Nml t; Nml u; Src t = Trg u  
                     Nml (t  u)  Dom (t  u) = Dom t  Dom u 
                                      Cod (t  u) = Cod t  Cod u 
                                      Src (t  u) = Src u  Trg (t  u) = Trg t"
      proof (induct t, simp_all add: Nml_HcompD(1-4))
        fix ν :: 'a and u :: "'a term"
        assume ν: "arr ν"
        assume u: "Nml u"
        assume 1: "src ν0 = Trg u"
        show "Nml (ν  u)  Dom (ν  u) = dom ν  Dom u 
                                 Cod (ν  u) = cod ν  Cod u 
                                 Src (ν  u) = Src u  Trg (ν  u) = trg ν0"
          using u ν 1 by (cases u, simp_all)
        next
        fix u v w
        assume I1: "x. Nml x  Src v = Trg x 
                         Nml (v  x)  Dom (v  x) = Dom v  Dom x 
                                          Cod (v  x) = Cod v  Cod x 
                                          Src (v  x) = Src x  Trg (v  x) = Trg v"
        assume I2: "x. Nml x  Trg u = Trg x 
                         Nml (w  x)  Dom (w  x) = Dom w  Dom x 
                                          Cod (w  x) = Cod w  Cod x 
                                          Src (w  x) = Src x  Trg (w  x) = Trg w"
        assume vw: "Nml (v  w)"
        assume u: "Nml u"
        assume wu: "Src w = Trg u"
        show "Nml ((v  w)  u) 
              Dom ((v  w)  u) = (Dom v  Dom w)  Dom u 
              Cod ((v  w)  u) = (Cod v  Cod w)  Cod u 
              Src ((v  w)  u) = Src u  Trg ((v  w)  u) = Trg v"
        proof -
          have v: "v = un_Prim v  Nml v"
            using vw Nml_implies_Arr Nml_HcompD by metis
          have w: "Nml w  ¬ is_Prim0 w  src (un_Prim v)0 = Trg w"
            using vw by (simp add: Nml_HcompD)
          have "is_Prim0 u  ?thesis" by (cases u; simp add: vw wu)
          moreover have "¬ is_Prim0 u  ?thesis"
          proof -
            assume 1: "¬ is_Prim0 u"
            have "Src v = Trg (w  u)"
              using u v w I2 [of u] by (cases v, simp_all)
            hence "Nml (v  w  u) 
                   Dom (v  w  u) = Dom v  Dom (w  u) 
                   Cod (v  w  u) = Cod v  Cod (w  u) 
                   Src (v  w  u) = Src u  Trg (v  w  u) = Trg v"
              using u v w I1 [of "w  u"] I2 [of u] by argo
            moreover have "v  w  u = (v  w)  u"
              using 1 by (cases u, simp_all)
            moreover have "(Dom v  Dom w)  Dom u = Dom v  Dom (w  u)"
              using v w u vw 1 I2 Nml_Dom HcompNml_Prim Nml_HcompD(1) Nml_HcompD(5)
              by (cases u, simp_all)
            moreover have "(Cod v  Cod w)  Cod u = Cod v  Cod (w  u)"
              using v w u vw 1 I2 Nml_HcompD(1) Nml_HcompD(5) HcompNml_Prim
              by (cases u, simp_all)
            ultimately show ?thesis
              by argo
          qed
          ultimately show ?thesis by blast
        qed
        next
        fix a u
        assume a: "obj a"
        assume u: "Nml u"
        assume au: "a0 = Trg u"
        show "Nml (Trg u  u) 
              Dom (Trg u  u) = Dom (Trg u)  Dom u 
              Cod (Trg u  u) = Cod (Trg u)  Cod u 
              Src (Trg u  u) = Src u  Trg (Trg u  u) = Trg (Trg u)"
          using au
          by (metis Cod.simps(1) Dom.simps(1) HcompNml.simps(1) Trg.simps(1) u)
      qed
      show "Nml (t  u) " using assms 0 by blast
      show "Dom (t  u) = Dom t  Dom u" using assms 0 by blast
      show "Cod (t  u) = Cod t  Cod u" using assms 0 by blast
      show "Src (t  u) = Src u" using assms 0 by blast
      show "Trg (t  u) = Trg t" using assms 0 by blast
    qed

    lemma HcompNml_in_Hom [intro]:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    shows "t  u  HHom (Src u) (Trg t)"
    and "t  u  VHom (Dom t  Dom u) (Cod t  Cod u)"
      using assms Nml_HcompNml Nml_implies_Arr by auto

    lemma Src_HcompNml:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Src (t  u) = Src u"
      using assms Nml_HcompNml(4) by simp

    lemma Trg_HcompNml:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Trg (t  u) = Trg t"
      using assms Nml_HcompNml(5) by simp

    lemma Dom_HcompNml:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Dom (t  u) = Dom t  Dom u"
      using assms Nml_HcompNml(2) by simp

    lemma Cod_HcompNml:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Cod (t  u) = Cod t  Cod u"
      using assms Nml_HcompNml(3) by simp

    lemma is_Hcomp_HcompNml:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    and "¬ is_Prim0 t" and "¬ is_Prim0 u"
    shows "is_Hcomp (t  u)"
    proof -
      have " ¬ is_Hcomp (t  u); Nml t; Nml u; Src t = Trg u; ¬ is_Prim0 t; ¬ is_Prim0 u 
                 False"
      proof (induct t, simp_all add: Nml_HcompD)
        fix a
        assume a: "obj a"
        assume u: "Nml u"
        assume 1: "¬ is_Hcomp u"
        assume 2: "¬ is_Prim0 (Trg u)"
        show "False"
          using u 1 2 by (cases u; simp)
        next
        fix v w
        assume I2: "¬ is_Hcomp (w  u)  False"
        assume vw: "Nml (v  w)"
        assume u: "Nml u"
        assume 1: "¬ is_Hcomp ((v  w)  u)"
        assume 2: "¬ is_Prim0 u"
        assume 3: "Src w = Trg u"
        show "False"
        proof -
          have v: "v = un_Prim v"
            using vw Nml_HcompD by metis
          have w: "Nml w  ¬ is_Prim0 w  src (un_Prim v)0 = Trg w"
            using vw Nml_HcompD [of v w] by blast
          have "(v  w)  u = v  (w  u)"
          proof -
            have "(v  w)  u = un_Prim v  (w  u)"
              using u v 2 by (cases u, simp_all)
            also have "... = un_Prim v  (w  u)"
              using u w I2 by fastforce
            also have "... = v  (w  u)"
              using v by simp
            finally show ?thesis by simp
          qed
          thus ?thesis using 1 by simp
        qed
      qed
      thus ?thesis using assms by blast
    qed

    text ‹
      The following function defines the ``dimension'' of a term,
      which is the number of inputs (or outputs) when the term is regarded as an
      interconnection matrix.
      For normal terms, this is just the length of the term when regarded as a list
      of arrows of @{term C}.
      This function is used as a ranking of terms in the subsequent associativity proof.
    ›

    primrec dim :: "'a term  nat"
    where "dim μ0 = 0"
        | "dim μ = 1"
        | "dim (t  u) = (dim t + dim u)"
        | "dim (t  u) = dim t"
        | "dim 𝗅[t] = dim t"
        | "dim 𝗅-1[t] = dim t"
        | "dim 𝗋[t] = dim t"
        | "dim 𝗋-1[t] = dim t"
        | "dim 𝖺[t, u, v] = dim t + dim u + dim v"
        | "dim 𝖺-1[t, u, v] = dim t + dim u + dim v"

    lemma HcompNml_assoc:
    assumes "Nml t" and "Nml u" and "Nml v" and "Src t = Trg u" and "Src u = Trg v"
    shows "(t  u)  v = t  (u  v)"
    proof -
      have "n t u v.  dim t = n; Nml t; Nml u; Nml v; Src t = Trg u; Src u = Trg v  
                        (t  u)  v = t  (u  v)"
      proof -
        fix n
        show "t u v.  dim t = n; Nml t; Nml u; Nml v; Src t = Trg u; Src u = Trg v  
                        (t  u)  v = t  (u  v)"
        proof (induction n rule: nat_less_induct)
          fix n :: nat and t :: "'a term" and u v
          assume I: "m<n. t u v. dim t = m  Nml t  Nml u  Nml v 
                                   Src t = Trg u  Src u = Trg v 
                                   (t  u)  v = t  (u  v)"
          assume dim: "dim t = n"
          assume t: "Nml t"
          assume u: "Nml u"
          assume v: "Nml v"
          assume tu: "Src t = Trg u"
          assume uv: "Src u = Trg v"
          show "(t  u)  v = t  (u  v)"
          proof -
            have "is_Prim0 t  ?thesis" by (cases t; simp)
            moreover have "¬is_Prim0 t  is_Prim0 u  ?thesis"
              by (cases t; simp; cases u; simp)
            moreover have "¬ is_Prim0 t  ¬ is_Prim0 u  is_Prim0 v  ?thesis"
            proof -
              assume 1: "¬ is_Prim0 t"
              assume 2: "¬ is_Prim0 u"
              assume 3: "is_Prim0 v"
              have "¬is_Prim0 (t  u)"
                using 1 2 t u tu is_Hcomp_HcompNml [of t u]
                by (cases t, simp, cases u, auto)
              thus ?thesis
                using 1 2 3 tu uv by (cases v, simp, cases "t  u", simp_all)
            qed
            moreover have "¬is_Prim0 t  ¬ is_Prim0 u  ¬ is_Prim0 v  is_Prim t  ?thesis"
              using v by (cases t, simp_all, cases u, simp_all; cases v, simp_all)
            moreover have "¬is_Prim0 t  ¬ is_Prim0 u  ¬ is_Prim0 v  is_Hcomp t  ?thesis"
            proof (cases t, simp_all)
              fix w :: "'a term" and x :: "'a term"
              assume 1: " ¬ is_Prim0 u  ¬ is_Prim0 v"
              assume 2: "t = (w  x)"
              show "((w  x)  u)  v = (w  x)  (u  v)"
              proof -
                have w: "w = un_Prim w"
                  using t 1 2 Nml_HcompD by metis
                have x: "Nml x"
                  using t w 1 2 by (metis Nml.simps(3))
                have "((w  x)  u)  v = (w  (x  u))  v"
                  using u v w x 1 2 by (cases u, simp_all)
                also have "... = (w  (x  u))  v"
                  using t w u 1 2 HcompNml_Prim is_Hcomp_HcompNml Nml_HcompD
                  by (metis Src.simps(3) term.distinct_disc(3) tu)
                also have "... = w  ((x  u)  v)"
                  using u v w x 1 by (cases u, simp_all; cases v, simp_all)
                also have "... = w  (x  (u  v))"
                proof -
                  have "dim x < dim t"
                    using 2 w by (cases w; simp)
                  moreover have "Src x = Trg u  Src u = Trg v"
                    using tu uv 2 by auto
                  ultimately show ?thesis 
                    using u v x dim I by simp
                qed
                also have "... = (w  x)  (u  v)"
                proof -
                  have 3: "is_Hcomp (u  v)"
                    using u v uv 1 is_Hcomp_HcompNml by auto
                  obtain u' :: "'a term" and v' where uv': "u  v = u'  v'"
                    using 3 is_Hcomp_def by blast
                  thus ?thesis by simp
                qed
                finally show ?thesis by simp
              qed
            qed
            moreover have "is_Prim0 t  is_Prim t  is_Hcomp t"
              using t by (cases t, simp_all)
            ultimately show ?thesis by blast
          qed
        qed
      qed
      thus ?thesis using assms by blast
    qed

    lemma HcompNml_Trg_Nml:
    assumes "Nml t"
    shows "Trg t  t = t"
    proof -
      have "Nml t  Trg t  t = t"
      proof (induct t, simp_all add: Nml_HcompD)
        fix u v
        assume uv: "Nml (u  v)"
        assume I1: "Trg u  u = u"
        have 1: "Nml u  Nml v  Src u = Trg v"
          using uv Nml_HcompD by blast
        have 2: "Trg (u  v) = Trg u"
          using uv by auto
        show "Trg u  u  v = u  v"
        proof -
          have "Trg u  u  v = Trg u  u  v"
            using uv HcompNml_Nml by simp
          also have "... = (Trg u  u)  v"
            using 1 2 HcompNml_assoc Src_Trg Nml_Trg Nml_implies_Arr by simp
          also have "... = u  v"
            using I1 uv HcompNml_Nml by simp
          finally show ?thesis by simp
        qed
      qed
      thus ?thesis using assms by simp
    qed

    lemma HcompNml_Nml_Src:
    assumes "Nml t"
    shows "t  Src t = t"
    proof -
      have "Nml t  t  Src t = t"
      proof (induct t, simp_all add: Nml_HcompD)
        fix u v
        assume uv: "Nml (u  v)"
        assume I2: "v  Src v = v"
        have 1: "Nml u  Nml v  Src u = Trg v"
          using uv Nml_HcompD by blast
        have 2: "Src (u  v) = Src v"
          using uv Trg_HcompNml by auto
        show "(u  v)  Src v = u  v"
        proof -
          have "(u  v)  Src v = (u  v)  Src v"
            using uv HcompNml_Nml by simp
          also have "... = u  (v  Src v)"
            using 1 2 HcompNml_assoc Trg_Src Nml_Src Nml_implies_Arr by simp
          also have "... = u  v"
            using I2 uv HcompNml_Nml by simp
          finally show ?thesis by simp
        qed
      qed
      thus ?thesis using assms by simp
    qed

    lemma HcompNml_Obj_Nml:
    assumes "Obj t" and "Nml u" and "Src t = Trg u"
    shows "t  u = u"
      using assms by (cases t, simp_all add: HcompNml_Trg_Nml)

    lemma HcompNml_Nml_Obj:
    assumes "Nml t" and "Obj u" and "Src t = Trg u"
    shows "t  u = t"
      using assms by (cases u, simp_all)

    lemma Ide_HcompNml:
    assumes "Ide t" and "Ide u" and "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Ide (t  u)"
      using assms
      by (metis (mono_tags, lifting) Nml_HcompNml(1) Nml_implies_Arr Dom_HcompNml
          Ide_Dom Ide_in_Hom(2) mem_Collect_eq)

    lemma Can_HcompNml:
    assumes "Can t" and "Can u" and "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Can (t  u)"
    proof -
      have "u.  Can t  Nml t; Can u  Nml u; Src t = Trg u   Can (t  u)"
      proof (induct t, simp_all add: HcompNml_Trg_Nml HcompNml_Nml_Src)
        show "x u. ide x  arr x  Can u  Nml u  src x0 = Trg u  Can (x  u)"
          by (metis Ide.simps(1-2) Ide_implies_Can Can.simps(3) Nml.elims(2)
              Nml.simps(2) HcompNml.simps(12) HcompNml_Prim Ide_HcompNml
              Src.simps(2) term.disc(2))
        show "v w u.
                 (u. Nml v  Can u  Nml u  Trg w = Trg u  Can (v  u)) 
                 (ua. Nml w  Can ua  Nml ua  Trg u = Trg ua  Can (w  ua)) 
                 Can v  Can w  Src v = Trg w  Nml (v  w) 
                 Can u  Nml u  Src w = Trg u  Can ((v  w)  u)"
          by (metis Nml_HcompD(3-4) HcompNml_Nml Nml_HcompNml(1)
              HcompNml_assoc Trg_HcompNml)
      qed
      thus ?thesis using assms by blast
    qed

    lemma Inv_HcompNml:
    assumes "Can t" and "Can u" and "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Inv (t  u) = Inv t  Inv u"
    proof -
      have "u.  Can t  Nml t; Can u  Nml u; Src t = Trg u 
                    Inv (t  u) = Inv t  Inv u"
      proof (induct t, simp_all add: HcompNml_Trg_Nml HcompNml_Nml_Src)
        show "x u.  obj x; Can u  Nml u; x0 = Trg u   Inv u = Inv (Trg u)  Inv u"
          by (metis HcompNml.simps(1) Inv.simps(1))
        show "x u. ide x  arr x  Can u  Nml u  src x0 = Trg u   
                    Inv (x  u) = x  Inv u"
          by (metis Ide.simps(2) HcompNml.simps(2) HcompNml_Prim Inv.simps(1,3)
                    Inv_Ide Inv_Inv is_Prim0_def)
        fix v w u
        assume I1: "x. Nml v  Can x  Nml x  Trg w = Trg x 
                        Inv (v  x) = Inv v  Inv x"
        assume I2: "x. Nml w  Can x  Nml x  Trg u = Trg x 
                              Inv (w  x) = Inv w  Inv x"
        assume vw: "Can v  Can w  Src v = Trg w  Nml (v  w)"
        assume wu: "Src w = Trg u"
        assume u: "Can u  Nml u"
        have v: "Can v  Nml v"
          using vw Nml_HcompD by blast
        have w: "Can w  Nml w"
          using v vw by (cases v, simp_all)
        show "Inv ((v  w)  u) = (Inv v  Inv w)  Inv u"
        proof -
          have "is_Prim0 u  ?thesis"
            apply (cases u) by simp_all
          moreover have "¬ is_Prim0 u  ?thesis"
          proof -
            assume 1: "¬ is_Prim0 u"
            have "Inv ((v  w)  u) = Inv (v  (w  u))"
              using 1 by (cases u, simp_all)
            also have "... = Inv v  Inv (w  u)"
              using u v w vw wu I1 Nml_HcompNml Can_HcompNml Nml_Inv Can_Inv
              by simp
            also have "... = Inv v  (Inv w  Inv u)"
              using u v w I2 Nml_HcompNml by simp
            also have "... = (Inv v  Inv w)  Inv u"
              using v 1 by (cases u, simp_all)
            finally show ?thesis by blast
          qed
          ultimately show ?thesis by blast
        qed
      qed
      thus ?thesis using assms by blast
    qed

    text ‹
       The following function defines vertical composition for compatible normal terms,
       by ``pushing the composition down'' to arrows of @{text V}.
    ›

    fun VcompNml :: "'a term  'a term  'a term"  (infixr  55)
    where "ν0  u = u"
        | "ν  μ = ν  μ"
        | "(u  v)  (w  x) = (u  w  v  x)"
        | "t  μ0 = t"
        | "t  _ = undefined  undefined"

    text ‹
      Note that the last clause above is not relevant to normal terms.
      We have chosen a provably non-normal value in order to validate associativity.
    ›

    lemma Nml_VcompNml:
    assumes "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Nml (t  u)"
    and "Dom (t  u) = Dom u"
    and "Cod (t  u) = Cod t"
    proof -
      have 0: "u.  Nml t; Nml u; Dom t = Cod u  
                     Nml (t  u)  Dom (t  u) = Dom u  Cod (t  u) = Cod t"
      proof (induct t, simp_all add: Nml_HcompD)
        show "x u. obj x  Nml u  x0 = Cod u 
                     Nml (Cod u  u)  Dom (Cod u  u) = Dom u 
                     Cod (Cod u  u) = Cod (Cod u)"
          by (metis Cod.simps(1) VcompNml.simps(1))
        fix ν u
        assume ν: "arr ν"
        assume u: "Nml u"
        assume 1: "dom ν = Cod u"
        show "Nml (ν  u)  Dom (ν  u) = Dom u  Cod (ν  u) = cod ν"
          using ν u 1 by (cases u, simp_all)
        next
        fix u v w
        assume I2: "u.  Nml u; Dom w = Cod u  
                          Nml (w  u)  Dom (w  u) = Dom u  Cod (w  u) = Cod w"
        assume vw: "Nml (v  w)"
        have v: "Nml v"
          using vw Nml_HcompD by blast
        have w: "Nml w"
          using vw Nml_HcompD by blast
        assume u: "Nml u"
        assume 1: "(Dom v  Dom w) = Cod u"
        show "Nml ((v  w)  u)  Dom ((v  w)  u) = Dom u 
                                     Cod ((v  w)  u) = Cod v  Cod w"
          using u v w 1
        proof (cases u, simp_all)
          fix x y
          assume 2: "u = x  y"
          have 4: "is_Prim x  x = un_Prim x  arr (un_Prim x)  Nml y  ¬ is_Prim0 y"
            using u 2 by (cases x, cases y, simp_all)
          have 5: "is_Prim v  v = un_Prim v  arr (un_Prim v)  Nml w  ¬ is_Prim0 w"
            using v w vw by (cases v, simp_all)
          have 6: "dom (un_Prim v) = cod (un_Prim x)  Dom w = Cod y"
          proof -
            have "src (un_Prim v)0 = Trg w" using vw Nml_HcompD [of v w] by simp
            thus "dom (un_Prim v) = cod (un_Prim x)  Dom w = Cod y"
              using 1 2 4 5 apply (cases u, simp_all)
              by (metis Cod.simps(2) Dom.simps(2) term.simps(2))
          qed
          have "(v  w)  u = un_Prim v  un_Prim x  w  y"
            using 2 4 5 6 VcompNml.simps(2) [of "un_Prim v" "un_Prim x"] by simp
          moreover have "Nml (un_Prim v  un_Prim x  w  y)"
          proof -
            have "Nml (w  y)"
              using I2 4 5 6 by simp
            moreover have "¬ is_Prim0 (w  y)"
              using vw 4 5 6 I2 Nml_Cod Nml_HcompD(5) is_Prim0_def
              by (metis Cod.simps(1) Cod.simps(3))
            moreover have "src (un_Prim v  un_Prim x)0 = Trg (w  y)"
              using vw 4 5 6 I2 Nml_HcompD(6) Nml_implies_Arr
                    src.as_nat_trans.is_natural_1 src.as_nat_trans.preserves_comp_2
                    Trg_Cod src_cod
              by (metis seqI)
            ultimately show ?thesis
              using 4 5 6 Nml.simps(3) [of "un_Prim v  un_Prim x" "(w  y)"]
              by simp
          qed
          ultimately show "Nml (v  x  w  y) 
                           Dom (v  x) = Dom x  Dom (w  y) = Dom y 
                           Cod (v  x) = Cod v  Cod (w  y) = Cod w"
            using 4 5 6 I2
            by (metis (no_types, lifting) Cod.simps(2) Dom.simps(2) VcompNml.simps(2)
                cod_comp dom_comp seqI)
        qed
      qed
      show "Nml (t  u)" using assms 0 by blast
      show "Dom (t  u) = Dom u" using assms 0 by blast
      show "Cod (t  u) = Cod t" using assms 0 by blast
    qed

    lemma VcompNml_in_Hom [intro]:
    assumes "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "t  u  HHom (Src u) (Trg u)" and "t  u  VHom (Dom u) (Cod t)"
    proof -
      show 1: "t  u  VHom (Dom u) (Cod t)"
        using assms Nml_VcompNml Nml_implies_Arr by simp
      show "t  u  HHom (Src u) (Trg u)"
        using assms 1 Src_Dom Trg_Dom Nml_implies_Arr by fastforce
    qed

    lemma Src_VcompNml:
    assumes "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Src (t  u) = Src u"
      using assms VcompNml_in_Hom by simp

    lemma Trg_VcompNml:
    assumes "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Trg (t  u) = Trg u"
      using assms VcompNml_in_Hom by simp

    lemma Dom_VcompNml:
    assumes "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Dom (t  u) = Dom u"
      using assms Nml_VcompNml(2) by simp

    lemma Cod_VcompNml:
    assumes "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Cod (t  u) = Cod t"
      using assms Nml_VcompNml(3) by simp

    lemma VcompNml_Cod_Nml [simp]:
    assumes "Nml t"
    shows "VcompNml (Cod t) t = t"
    proof -
      have "Nml t  Cod t  t = t"
        apply (induct t)
        by (auto simp add: Nml_HcompD comp_cod_arr)
      thus ?thesis using assms by blast
    qed

    lemma VcompNml_Nml_Dom [simp]:
    assumes "Nml t"
    shows "t  (Dom t) = t"
    proof -
      have "Nml t  t  Dom t = t"
        apply (induct t) by (auto simp add: Nml_HcompD comp_arr_dom)
      thus ?thesis using assms by blast
    qed

    lemma VcompNml_Ide_Nml [simp]:
    assumes "Nml t" and "Ide a" and "Dom a = Cod t"
    shows "a  t = t"
      using assms Ide_in_Hom by simp

    lemma VcompNml_Nml_Ide [simp]:
    assumes "Nml t" and "Ide a" and "Dom t = Cod a"
    shows "t  a = t"
      using assms Ide_in_Hom by auto

    lemma VcompNml_assoc:
    assumes "Nml t" and "Nml u" and "Nml v"
    and "Dom t = Cod u" and "Dom u = Cod v"
    shows "(t  u)  v = t  (u  v)"
    proof -
      have "u v.  Nml t; Nml u; Nml v; Dom t = Cod u; Dom u = Cod v  
                    (t  u)  v = t  (u  v)"
      proof (induct t, simp_all)
        show "x u v. obj x  Nml u  Nml v  x0 = Cod u  Dom u = Cod v 
                       u  v = Cod u  u  v"
          by (metis VcompNml.simps(1))
        fix f u v
        assume f: "arr f"
        assume u: "Nml u"
        assume v: "Nml v"
        assume 1: "dom f = Cod u"
        assume 2: "Dom u = Cod v"
        show "(f  u)  v = f  (u  v)"
          using u v f 1 2 comp_assoc
          apply (cases u)
                   apply simp_all
          apply (cases v)
          by simp_all
        next
        fix u v w x
        assume I1: "u v.  Nml w; Nml u; Nml v; Dom w = Cod u; Dom u = Cod v  
                            (w  u)  v = w  (u  v)"
        assume I2: "u v.  Nml x; Nml u; Nml v; Dom x = Cod u; Dom u = Cod v  
                            (x  u)  v = x  (u  v)"
        assume wx: "Nml (w  x)"
        assume u: "Nml u"
        assume v: "Nml v"
        assume 1: "(Dom w  Dom x) = Cod u"
        assume 2: "Dom u = Cod v"
        show "((w  x)  u)  v = (w  x)  u  v"
        proof -
          have w: "Nml w"
            using wx Nml_HcompD by blast
          have x: "Nml x"
            using wx Nml_HcompD by blast
          have "is_Hcomp u"
            using u 1 by (cases u) simp_all
          thus ?thesis
            using u v apply (cases u, simp_all, cases v, simp_all)
          proof -
            fix u1 u2 v1 v2
            assume 3: "u = (u1  u2)"
            assume 4: "v = (v1  v2)"
            show "(w  u1)  v1 = w  u1  v1 
                  (x  u2)  v2 = x  u2  v2"
            proof -
              have "Nml u1  Nml u2"
                using u 3 Nml_HcompD by blast
              moreover have "Nml v1  Nml v2"
                using v 4 Nml_HcompD by blast
              ultimately show ?thesis using w x I1 I2 1 2 3 4 by simp
            qed
          qed
        qed
      qed
      thus ?thesis using assms by blast
    qed

    lemma Ide_VcompNml:
    assumes "Ide t" and "Ide u" and "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Ide (t  u)"
    proof -
      have "u.  Ide t; Ide u; Nml t; Nml u; Dom t = Cod u   Ide (VcompNml t u)"
        by (induct t, simp_all)
      thus ?thesis using assms by blast
    qed

    lemma Can_VcompNml:
    assumes "Can t" and "Can u" and "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Can (t  u)"
    proof -
      have "u.  Can t  Nml t; Can u  Nml u; Dom t = Cod u   Can (t  u)"
      proof (induct t, simp_all)
        fix t u v
        assume I1: "v.  Nml t; Can v  Nml v; Dom t = Cod v   Can (t  v)"
        assume I2: "v.  Nml u; Can v  Nml v; Dom u = Cod v   Can (u  v)"
        assume tu: "Can t  Can u  Src t = Trg u  Nml (t  u)"
        have t: "Can t  Nml t"
          using tu Nml_HcompD by blast
        have u: "Can u  Nml u"
          using tu Nml_HcompD by blast
        assume v: "Can v  Nml v"
        assume 1: "(Dom t  Dom u) = Cod v"
        show "Can ((t  u)  v)"
        proof -
          have 2: "(Dom t  Dom u) = Cod v" using 1 by simp
          show ?thesis
            using v 2
          proof (cases v; simp)
            fix w x
            assume wx: "v = (w  x)"
            have "Can w  Nml w" using v wx Nml_HcompD Can.simps(3) by blast
            moreover have "Can x  Nml x" using v wx Nml_HcompD Can.simps(3) by blast
            moreover have "Dom t = Cod w" using 2 wx by simp
            moreover have ux: "Dom u = Cod x" using 2 wx by simp
            ultimately show "Can (t  w)  Can (u  x)  Src (t  w) = Trg (u  x)"
              using t u v tu wx I1 I2
              by (metis Nml_HcompD(7) Src_VcompNml Trg_VcompNml)
          qed
        qed
      qed
      thus ?thesis using assms by blast
    qed

    lemma Inv_VcompNml:
    assumes "Can t" and "Can u" and "Nml t" and "Nml u" and "Dom t = Cod u"
    shows "Inv (t  u) = Inv u  Inv t"
    proof -
      have "u.  Can t  Nml t; Can u  Nml u; Dom t = Cod u  
              Inv (t  u) = Inv u  Inv t"
      proof (induct t, simp_all)
        show "x u.  obj x; Can u  Nml u; x0 = Cod u   Inv u = Inv u  Inv (Cod u)"
          by (simp add: Can_implies_Arr)
        show "x u.  ide x  arr x; Can u  Nml u; x = Cod u  
                      Inv u = Inv u  Inv (Cod u)"
          by (simp add: Can_implies_Arr)
        fix v w u
        assume vw: "Can v  Can w  Src v = Trg w  Nml (v  w)"
        have v: "Can v  Nml w"
          using vw Nml_HcompD by blast
        have w: "Can w  Nml w"
          using vw Nml_HcompD by blast
        assume I1: "x.  Nml v; Can x  Nml x; Dom v = Cod x  
                          Inv (v  x) = Inv x  Inv v"
        assume I2: "x.  Nml w; Can x  Nml x; Dom w = Cod x  
                          Inv (w  x) = Inv x  Inv w"
        assume u: "Can u  Nml u"
        assume 1: "(Dom v  Dom w) = Cod u"
        show "Inv ((v  w)  u) = Inv u  (Inv v  Inv w)"
          using v 1
        proof (cases w, simp_all)
          show "μ. obj μ  Dom v  μ0 = Cod u  w = μ0  Can v 
                     Inv ((v  μ0)  u) = Inv u  (Inv v  μ0)"
            using Nml_HcompD(5) is_Prim0_def vw by blast
          show "μ. arr μ  Dom v  dom μ = Cod u  w = μ  Can v 
                     Inv ((v  μ)  u) = Inv u  (Inv v  inv μ)"
            by (metis Ide.simps(2) Can.simps(2) Nml_HcompD(1) Dom.simps(2) Inv_Ide
                      Dom_Inv Nml_Inv ideD(2) inv_ide VcompNml_Cod_Nml VcompNml_Nml_Dom
                      u vw)
          show "y z. Nml (y  z)  Dom v  Dom y  Dom z = Cod u 
                           w = y  z  Can v 
                          Inv ((v  y  z)  u) = Inv u  (Inv v  Inv y  Inv z)"
          proof -
            fix y z
            assume 2: "Nml (y  z)"
            assume yz: "w = y  z"
            show "Inv ((v  y  z)  u) = Inv u  (Inv v  Inv y  Inv z)"
              using u vw yz I1 I2 1 2 VcompNml_Nml_Ide
              apply (cases u)
                       apply simp_all
              by (metis Nml_HcompD(3-4))
          qed
        qed
      qed
      thus ?thesis using assms by blast
    qed

    lemma Can_and_Nml_implies_Ide:
    assumes "Can t" and "Nml t"
    shows "Ide t"
    proof -
      have " Can t; Nml t   Ide t"
        apply (induct t) by (simp_all add: Nml_HcompD)
      thus ?thesis using assms by blast
    qed

    lemma VcompNml_Can_Inv [simp]:
    assumes "Can t" and "Nml t"
    shows "t  Inv t = Cod t"
      using assms Can_and_Nml_implies_Ide Ide_in_Hom by simp
      
    lemma VcompNml_Inv_Can [simp]:
    assumes "Can t" and "Nml t"
    shows "Inv t  t = Dom t"
      using assms Can_and_Nml_implies_Ide Ide_in_Hom by simp

    text ‹
      The next fact is a syntactic version of the interchange law, for normal terms.
    ›

    lemma VcompNml_HcompNml:
    assumes "Nml t" and "Nml u" and "Nml v" and "Nml w"
    and "VSeq t v" and "VSeq u w" and "Src v = Trg w"
    shows "(t  u)  (v  w) = (t  v)  (u  w)"
    proof -
      have "u v w.  Nml t; Nml u; Nml v; Nml w; VSeq t v; VSeq u w;
                      Src t = Trg u; Src v = Trg w  
                      (t  u)  (v  w) = (t  v)  (u  w)"
      proof (induct t, simp_all)
        fix u v w x
        assume u: "Nml u"
        assume v: "Nml v"
        assume w: "Nml w"
        assume uw: "VSeq u w"
        show "x. Arr v  x0 = Cod v  (Cod v  u)  (v  w) = v  u  w"
          using u v w uw by (cases v) simp_all
        show "x.  arr x; Arr v  dom x = Cod v; src x0 = Trg u; Src v = Trg w  
                  (x  u)  (v  w) = x  v  u  w"
        proof -
          fix x
          assume x: "arr x"
          assume 1: "Arr v  dom x = Cod v"
          assume tu: "src x0 = Trg u"
          assume vw: "Src v = Trg w"
          show "(x  u)  (v  w) = x  v  u  w"
          proof -
            have 2: "v = un_Prim v  arr (un_Prim v)" using v 1 by (cases v) simp_all
            have "is_Prim0 u  ?thesis"
              using u v w x tu uw vw 1 2 Cod.simps(3) VcompNml_Cod_Nml Dom.simps(2)
                    HcompNml_Prim HcompNml_term_Prim0 Nml_HcompNml(3) HcompNml_Trg_Nml
              apply (cases u)
                apply simp_all
              by (cases w, simp_all add: Src_VcompNml)
            moreover have "¬ is_Prim0 u  ?thesis"
            proof -
              assume 3: "¬ is_Prim0 u"
              hence 4: "¬ is_Prim0 w" using u w uw by (cases u, simp_all; cases w, simp_all)
              have "(x  u)  (v  w) = (x  u)  (v  w)"
              proof -
                have "x  u = x  u"
                  using u x 3 HcompNml_Nml by (cases u, simp_all)
                moreover have "v  w = v  w"
                  using w 2 4 HcompNml_Nml by (cases v, simp_all; cases w, simp_all)
                ultimately show ?thesis by simp
              qed
              also have 5: "... = (x  v)  (u  w)" by simp
              also have "... = (x  v)  (u  w)"
                using x u w uw vw 1 2 3 4 5
                      HcompNml_Nml HcompNml_Prim Nml_HcompNml(1)
                by (metis Cod.simps(3) Nml.simps(3) Dom.simps(2) Dom.simps(3)
                    Nml_VcompNml(1) tu v)
              finally show ?thesis by blast
            qed
            ultimately show ?thesis by blast
          qed
        qed
        fix t1 t2
        assume t12: "Nml (t1  t2)"
        assume I1: "u v w.  Nml t1; Nml u; Nml v; Nml w;
                              Arr v  Dom t1 = Cod v; VSeq u w;
                              Trg t2 = Trg u; Src v = Trg w  
                              (t1  u)  (v  w) = t1  v  u  w"
        assume I2: "u' v w.  Nml t2; Nml u'; Nml v; Nml w;
                               Arr v  Dom t2 = Cod v; VSeq u' w;
                               Trg u = Trg u'; Src v = Trg w  
                              (t2  u')  (v  w) = (t2  v)  (u'  w)"
        have t1: "t1 = un_Prim t1  arr (un_Prim t1)  Nml t1"
          using t12 by (cases t1, simp_all)
        have t2: "Nml t2  ¬is_Prim0 t2"
          using t12 by (cases t1, simp_all)
        assume vw: "Src v = Trg w"
        assume tu: "Src t2 = Trg u"
        assume 1: "Arr t1  Arr t2  Src t1 = Trg t2  Arr v  (Dom t1  Dom t2) = Cod v"
        show "((t1  t2)  u)  (v  w) = (t1  t2)  v  u  w"
        proof -
          have "is_Prim0 u  ?thesis"
            using u v w uw tu vw t12 I1 I2 1 Obj_Src
            apply (cases u)
              apply simp_all
            by (cases w, simp_all add: Src_VcompNml)
          moreover have "¬ is_Prim0 u  ?thesis"
          proof -
            assume u': "¬ is_Prim0 u"
            hence w': "¬ is_Prim0 w" using u w uw by (cases u, simp_all; cases w, simp_all)
            show ?thesis
              using 1 v
            proof (cases v, simp_all)
              fix v1 v2
              assume v12: "v = v1  v2"
              have v1: "v1 =  un_Prim v1  arr (un_Prim v1)  Nml v1"
                using v v12 by (cases v1, simp_all)
              have v2: "Nml v2  ¬ is_Prim0 v2"
                using v v12 by (cases v1, simp_all)
              have 2: "v = (un_Prim v1  v2)"
                using v1 v12 by simp
              show "((t1  t2)  u)  ((v1  v2)  w) = (t1  v1  t2  v2)  u  w"
              proof -
                have 3: "(t1  t2)  u = t1  (t2  u)"
                  using u u' by (cases u, simp_all)
                have 4: "v  w = v1  v2  w"
                proof -
                  have "Src v1 = Trg v2"
                    using v v12 1 Arr.simps(3) Nml_HcompD(7) by blast
                  moreover have "Src v2 = Trg w"
                    using v v12 vw by simp
                  ultimately show ?thesis
                    using v w v1 v2 v12 2 HcompNml_assoc [of v1 v2 w] HcompNml_Nml by metis
                qed
                have "((t1  t2)  u)  ((v1  v2)  w)
                        = (t1  (t2  u))  (v1  (v2  w))"
                  using 3 4 v12 by simp
                also have "... = (t1  v1)  ((t2  u)  (v2  w))"
                proof -
                  have "is_Hcomp (t2  u)"
                    using t2 u u' tu is_Hcomp_HcompNml by auto
                  moreover have "is_Hcomp (v2  w)"
                    using v2 v12 w w' vw is_Hcomp_HcompNml by auto
                  ultimately show ?thesis
                    using u u' v w t1 v1 t12 v12 HcompNml_Prim
                    by (metis VcompNml.simps(2) VcompNml.simps(3) is_Hcomp_def
                        term.distinct_disc(3))
                qed
                also have "... = (t1  v1)  (t2  v2)  (u  w)"
                  using u w tu uw vw t2 v2 1 2 Nml_implies_Arr I2 by auto
                also have "... = ((t1  v1)  (t2  v2))  (u  w)"
                proof -
                  have "¬is_Prim0 (u  w)"
                    using u w u' w' by (cases u, simp_all; cases w, simp_all)
                  hence "((t1  v1)  (t2  v2))  (u  w)
                           = (t1  v1)  ((t2  v2)  (u  w))"
                    by (cases "u  w") simp_all
                  thus ?thesis by presburger
                qed
                finally show ?thesis by blast
              qed
            qed
          qed
          ultimately show ?thesis by blast
        qed
      qed
      moreover have "Src t = Trg u"
        using assms Src_Dom Trg_Dom Src_Cod Trg_Cod Nml_implies_Arr by metis
      ultimately show ?thesis using assms by simp
    qed

    text ‹
      The following function reduces a formal arrow to normal form.
    ›

    fun Nmlize :: "'a term  'a term"   (_)
    where "μ0 = μ0"
        | "μ = μ"
        | "t  u = t  u"
        | "t  u = t  u"
        | "𝗅[t] = t"
        | "𝗅-1[t] = t"
        | "𝗋[t] = t"
        | "𝗋-1[t] = t"
        | "𝖺[t, u, v] = (t  u)  v"
        | "𝖺-1[t, u, v] = t  (u  v)"

    lemma Nml_Nmlize:
    assumes "Arr t"
    shows "Nml t" and "Src t = Src t" and "Trg t = Trg t"
    and "Dom t = Dom t" and "Cod t = Cod t"
    proof -
      have 0: "Arr t  Nml t  Src t = Src t  Trg t = Trg t 
                                     Dom t = Dom t  Cod t = Cod t"
        using Nml_HcompNml Nml_VcompNml HcompNml_assoc
              Src_VcompNml Trg_VcompNml VSeq_implies_HPar
        apply (induct t)
                 apply auto
      proof -
        fix t
        assume 1: "Arr t"
        assume 2: "Nml t"
        assume 3: "Src t = Src t"
        assume 4: "Trg t = Trg t"
        assume 5: "Dom t = Dom t"
        assume 6: "Cod t = Cod t"
        have 7: "Nml Dom t"
          using 2 5 Nml_Dom by fastforce
        have 8: "Trg t = Trg t"
          using 1 2 4 Nml_Trg Obj_Trg
          by (metis Nml.elims(2) Nmlize.simps(1) Nmlize.simps(2) Obj.simps(3))
        have 9: "Nml Cod t"
          using 2 6 Nml_Cod by fastforce
        have 10: "Src t = Src t"
          using 1 2 3 Nml_Src Obj_Src
          by (metis Nml.elims(2) Nmlize.simps(1) Nmlize.simps(2) Obj.simps(3))
        show "Dom t = Trg t  Dom t"
          using 2 5 7 8 Nml_implies_Arr Trg_Dom HcompNml_Trg_Nml by metis
        show "Cod t = Trg t  Cod t"
          using 2 6 8 9 Nml_implies_Arr Trg_Cod HcompNml_Trg_Nml by metis
        show "Dom t = Dom t  Src t"
          using 2 5 7 10 Nml_implies_Arr Src_Dom HcompNml_Nml_Src by metis
        show "Cod t = Cod t  Src t"
          using 2 6 9 10 Nml_implies_Arr Src_Cod HcompNml_Nml_Src by metis
        next
        fix t1 t2 t3
        assume "Nml t1" and "Nml t2" and "Nml t3"
        assume "Src t1 = Trg t2" and "Src t2 = Trg t3"
        assume "Src t1 = Trg t2" and "Src t2 = Trg t3"
        assume "Trg t1 = Trg t1" and "Trg t2 = Trg t2" and "Trg t3 = Trg t3"
        assume "Dom t1 = Dom t1" and "Cod t1 = Cod t1" and "Dom t2 = Dom t2"
        and "Cod t2 = Cod t2" and "Dom t3 = Dom t3" and "Cod t3 = Cod t3"
        show "Dom t1  Dom t2  Dom t3 =
              (Dom t1  Dom t2)  Dom t3"
          using Nml_Dom Nml_implies_Arr Src_Dom Trg_Dom
                HcompNml_assoc [of "Dom t1" "Dom t2" "Dom t3"]
                Nml t1 Nml t2 Nml t3
                Dom t1 = Dom t1 Dom t2 = Dom t2 Dom t3 = Dom t3
                Src t1 = Trg t2 Trg t2 = Trg t2
                Src t2 = Trg t3 Trg t3 = Trg t3
          by metis
        show "Cod t1  Cod t2  Cod t3 = (Cod t1  Cod t2)  Cod t3"
          using Nml_Cod Nml_implies_Arr Src_Cod Trg_Cod
                HcompNml_assoc [of "Cod t1" "Cod t2" "Cod t3"]
                Nml t1 Nml t2 Nml t3
                Cod t1 = Cod t1 Cod t2 = Cod t2 Cod t3 = Cod t3
                Src t1 = Trg t2 Trg t2 = Trg t2
                Src t2 = Trg t3 Trg t3 = Trg t3
          by metis
      qed
      show "Nml t" using assms 0 by blast
      show "Src t = Src t" using assms 0 by blast
      show "Trg t = Trg t" using assms 0 by blast
      show "Dom t = Dom t" using assms 0 by blast
      show "Cod t = Cod t" using assms 0 by blast
    qed

    lemma Nmlize_in_Hom [intro]:
    assumes "Arr t"
    shows "t  HHom (Src t) (Trg t)" and "t  VHom Dom t Cod t"
      using assms Nml_Nmlize Nml_implies_Arr by auto

    lemma Nmlize_Src:
    assumes "Arr t"
    shows "Src t = Src t" and "Src t = Src t"
    proof -
      have 1: "Obj (Src t)"
        using assms by simp
      obtain a where a: "obj a  Src t = a0"
        using 1 by (cases "Src t", simp_all)
      show "Src t = Src t"
        using a by simp
      thus "Src t = Src t"
        using assms Nmlize_in_Hom by simp
    qed

    lemma Nmlize_Trg:
    assumes "Arr t"
    shows "Trg t = Trg t" and "Trg t = Trg t"
    proof -
      have 1: "Obj (Trg t)"
        using assms by simp
      obtain a where a: "obj a  Trg t = a0"
        using 1 by (cases "Trg t", simp_all)
      show "Trg t = Trg t"
        using a by simp
      thus "Trg t = Trg t"
        using assms Nmlize_in_Hom by simp
    qed

    lemma Nmlize_Dom:
    assumes "Arr t"
    shows "Dom t = Dom t"
      using assms Nmlize_in_Hom by simp

    lemma Nmlize_Cod:
    assumes "Arr t"
    shows "Cod t = Cod t"
      using assms Nmlize_in_Hom by simp

    lemma Ide_Nmlize_Ide:
    assumes "Ide t"
    shows "Ide t"
    proof -
      have "Ide t  Ide t"
        using Ide_HcompNml Nml_Nmlize
        by (induct t, simp_all)
      thus ?thesis using assms by blast
    qed

    lemma Ide_Nmlize_Can:
    assumes "Can t"
    shows "Ide t"
    proof -
      have "Can t  Ide t"
        using Can_implies_Arr Ide_HcompNml Nml_Nmlize Ide_VcompNml Nml_HcompNml
        apply (induct t)
          apply (auto simp add: Dom_Ide Cod_Ide)
        by (metis Ide_VcompNml)
      thus ?thesis using assms by blast
    qed

    lemma Can_Nmlize_Can:
    assumes "Can t"
    shows "Can t"
      using assms Ide_Nmlize_Can Ide_implies_Can by auto

    lemma Nmlize_Nml [simp]:
    assumes "Nml t"
    shows "t = t"
    proof -
      have "Nml t  t = t"
        apply (induct t, simp_all)
        using HcompNml_Prim Nml_HcompD by metis
      thus ?thesis using assms by blast
    qed

    lemma Nmlize_Nmlize [simp]:
    assumes "Arr t"
    shows "t = t"
      using assms Nml_Nmlize Nmlize_Nml by blast

    lemma Nmlize_Hcomp:
    assumes "Arr t" and "Arr u"
    shows "t  u = t  u"
      using assms Nmlize_Nmlize by simp

    lemma Nmlize_Hcomp_Obj_Arr [simp]:
    assumes "Arr u"
    shows "b0  u = u"
      using assms by simp

    lemma Nmlize_Hcomp_Arr_Obj [simp]:
    assumes "Arr t" and "Src t = a0"
    shows "t  a0 = t"
      using assms HcompNml_Nml_Src Nmlize_in_Hom by simp

    lemma Nmlize_Hcomp_Prim_Arr [simp]:
    assumes "Arr u" and "¬ is_Prim0 u"
    shows "μ  u = μ  u"
      using assms by simp

    lemma Nmlize_Hcomp_Hcomp:
    assumes "Arr t" and "Arr u" and "Arr v" and "Src t = Trg u" and "Src u = Trg v"
    shows "(t  u)  v = t  (u  v)"
      using assms Nml_Nmlize Nmlize_Nmlize by (simp add: HcompNml_assoc)

    lemma Nmlize_Hcomp_Hcomp':
    assumes "Arr t" and "Arr u" and "Arr v" and "Src t = Trg u" and "Src u = Trg v"
    shows "t  u  v = t  u  v"
      using assms Nml_Nmlize Nmlize_Nmlize by (simp add: HcompNml_assoc)

    lemma Nmlize_Vcomp_Cod_Arr:
    assumes "Arr t"
    shows "Cod t  t = t"
    proof -
      have "Arr t  Cod t  t = t"
      proof (induct t, simp_all)
        show "x. arr x  cod x  x = x"
          using comp_cod_arr by blast
        fix t1 t2
        show "t1 t2. Cod t1  t1 = t1  Cod t2  t2 = t2  HSeq t1 t2 
                      (Cod t1  Cod t2)  (t1  t2) = t1  t2"
          using VcompNml_HcompNml Ide_Cod Nml_Nmlize Nmlize_in_Hom
          by simp
        show "Cod t1  t1 = t1  Cod t2  t2 = t2  VSeq t1 t2 
              Cod t1  t1  t2 = t1  t2"
          using VcompNml_assoc [of "Cod t1" "t1" "t2"] Ide_Cod
                Nml_Nmlize
          by simp
        next
        show "t. Cod t  t = t  Arr t  (Trg t  Cod t)  t = t"
          by (metis Arr.simps(6) Cod.simps(6) Nmlize.simps(3) Nmlize.simps(6)
              Nmlize_Cod)
        show "t. Cod t  t = t  Arr t  (Cod t  Src t)  t = t"
          by (simp add: Nml_Nmlize(1) Nml_Nmlize(2) Nmlize_Src(2) HcompNml_Nml_Obj)
        show "t1 t2 t3. Cod t1  t1 = t1  Cod t2  t2 = t2 
                          Cod t3  t3 = t3 
                          Arr t1  Arr t2  Arr t3  Src t1 = Trg t2  Src t2 = Trg t3 
                         (Cod t1  Cod t2  Cod t3)  ((t1  t2)  t3) =
                         (t1  t2)  t3"
          using VcompNml_HcompNml Ide_Cod HcompNml_in_Hom Nml_HcompNml
                Nml_Nmlize Nmlize_in_Hom HcompNml_assoc
          by simp
        show "t1 t2 t3. Cod t1  t1 = t1  Cod t2  t2 = t2 
                          Cod t3  t3 = t3 
                          Arr t1  Arr t2  Arr t3  Src t1 = Trg t2  Src t2 = Trg t3 
                          ((Cod t1  Cod t2)  Cod t3)  (t1  t2  t3) =
                          t1  t2  t3"
          using VcompNml_HcompNml Ide_Cod HcompNml_in_Hom Nml_HcompNml
                Nml_Nmlize Nmlize_in_Hom HcompNml_assoc
          by simp
      qed
      thus ?thesis using assms by blast
    qed

    lemma Nmlize_Vcomp_Arr_Dom:
    assumes "Arr t"
    shows "t  Dom t = t"
    proof -
      have "Arr t  t  Dom t = t"
      proof (induct t, simp_all)
        show "x. arr x  x  local.dom x = x"
          using comp_arr_dom by blast
        fix t1 t2
        show "t1  Dom t1 = t1  t2  Dom t2 = t2  HSeq t1 t2 
              (t1  t2)  (Dom t1  Dom t2) = t1  t2"
          using VcompNml_HcompNml Ide_Dom HcompNml_in_Hom Nml_HcompNml
                Nml_Nmlize Nmlize_in_Hom HcompNml_assoc
          by simp
        show "t1  Cod t2 = t1  t2  Dom t2 = t2  VSeq t1 t2 
              (t1  t2)  Dom t2 = t1  t2"
          using VcompNml_assoc [of "t1" "t2" "Dom t2"] Ide_Dom Nml_Nmlize
          by simp
        next
        show "t. t  Dom t = t  Arr t  t  (Trg t  Dom t) = t"
          by (simp add: Nml_Nmlize(1) Nml_Nmlize(3) Nmlize_Trg(2)
              HcompNml_Obj_Nml bicategorical_language.Ide_Dom
              bicategorical_language_axioms)
        show "t. t  Dom t = t  Arr t  t  (Dom t  Src t) = t"
          by (simp add: Nml_Nmlize(1) Nml_Nmlize(2) Nmlize_Src(2) HcompNml_Nml_Obj)
        show "t1 t2 t3. t1  Dom t1 = t1  t2  Dom t2 = t2 
                          t3  Dom t3 = t3 
                          Arr t1  Arr t2  Arr t3  Src t1 = Trg t2  Src t2 = Trg t3 
                          ((t1  t2)  t3)  ((Dom t1  Dom t2)  Dom t3) =
                          (t1  t2)  t3"
          using VcompNml_HcompNml Ide_Dom HcompNml_in_Hom Nml_HcompNml
                Nml_Nmlize Nmlize_in_Hom HcompNml_assoc
          by simp
        show "t1 t2 t3. t1  Dom t1 = t1  t2  Dom t2 = t2 
                          t3  Dom t3 = t3 
                          Arr t1  Arr t2  Arr t3  Src t1 = Trg t2  Src t2 = Trg t3 
                          (t1  t2  t3)  (Dom t1  Dom t2  Dom t3) =
                          t1  t2  t3"
          using VcompNml_HcompNml Ide_Dom HcompNml_in_Hom Nml_HcompNml
                Nml_Nmlize Nmlize_in_Hom HcompNml_assoc
          by simp
      qed
      thus ?thesis using assms by blast
    qed

    lemma Nmlize_Inv:
    assumes "Can t"
    shows "Inv t = Inv t"
    proof -
      have "Can t  Inv t = Inv t"
      proof (induct t, simp_all)
        fix u v
        assume I1: "Inv u = Inv u"
        assume I2: "Inv v = Inv v"
        show "Can u  Can v  Src u = Trg v  Inv u  Inv v = Inv (u  v)"
          using Inv_HcompNml Nml_Nmlize Can_implies_Arr Can_Nmlize_Can
                I1 I2
          by simp
        show "Can u  Can v  Dom u = Cod v  Inv v  Inv u = Inv (u  v)"
          using Inv_VcompNml Nml_Nmlize Can_implies_Arr Nmlize_in_Hom Can_Nmlize_Can
                I1 I2
          by simp
        fix w
        assume I3: "Inv w = Inv w"
        assume uvw: "Can u  Can v  Can w  Src u = Trg v  Src v = Trg w"
        show "Inv u  (Inv v  Inv w) = Inv ((u  v)  w)"
          using uvw I1 I2 I3
                Inv_HcompNml Nml_Nmlize Can_implies_Arr Can_Nmlize_Can
                Nml_HcompNml Can_HcompNml HcompNml_assoc
          by simp
        show "(Inv u  Inv v)  Inv w = Inv (u  (v  w))"
          using uvw I1 I2 I3
                Inv_HcompNml Nml_Nmlize Can_implies_Arr Can_Nmlize_Can
                Nml_HcompNml Can_HcompNml HcompNml_assoc Can_Inv
          by simp
      qed
      thus ?thesis using assms by blast
    qed

    subsection "Reductions"

    text ‹
      Function red› defined below takes a formal identity @{term t} to a canonical arrow
      f ∈ Hom f f.  The auxiliary function red2› takes a pair @{term "(f, g)"}
      of normalized formal identities and produces a canonical arrow
      f  g ∈ Hom (f  g) f  g.
    ›

    fun red2                       (infixr  53)
    where "b0  u = 𝗅[u]"
        | "f  a0 = 𝗋[f]"
        | "f  u = f  u"
        | "(t  u)  a0 = 𝗋[t  u]"
        | "(t  u)  v = (t  u  v)  (t  (u  v))  𝖺[t, u, v]"
        | "t  u = undefined"

    fun red                         (‹_ [56] 56)
    where "f0 = f0"
        | "f = f"
        | "(t  u) = (if Nml (t  u) then t  u else (t  u)  (t  u))"
        | "t = undefined"

    lemma red_Nml [simp]:
    assumes "Nml a"
    shows "a = a"
      using assms by (cases a, simp_all)

    lemma red2_Nml:
    assumes "Nml (a  b)"
    shows "a  b = a  b"
    proof -
      have a: "a = un_Prim a"
        using assms Nml_HcompD by metis
      have b: "Nml b  ¬ is_Prim0 b"
        using assms Nml_HcompD by metis
      show ?thesis using a b
        apply (cases b)
          apply simp_all
         apply (metis red2.simps(3))
        by (metis red2.simps(4))
    qed

    lemma Can_red2:
    assumes "Ide a" and "Nml a" and "Ide b" and "Nml b" and "Src a = Trg b"
    shows "Can (a  b)"
    and "a  b  VHom (a  b) a  b"
    proof -
      have 0: "b.  Ide a  Nml a; Ide b  Nml b; Src a = Trg b  
                     Can (a  b)  a  b  VHom (a  b) a  b"
      proof (induct a, simp_all add: HcompNml_Nml_Src HcompNml_Trg_Nml)
        fix x b
        show "Ide b  Nml b  Can (Trg b  b)  Arr (Trg b  b) 
                                 Dom (Trg b  b) = Trg b  b  Cod (Trg b  b) = b"
          using Ide_implies_Can Ide_in_Hom Nmlize_Nml
          apply (cases b, simp_all)
        proof -
          fix u v
          assume uv: "Ide u  Ide v  Src u = Trg v  Nml (u  v)"
          show "Can (Trg u  (u  v))  Arr (Trg u  (u  v)) 
                Dom (Trg u  (u  v)) = Trg u  u  v 
                Cod (Trg u  (u  v)) = u  v"
            using uv Ide_implies_Can Can_implies_Arr Ide_in_Hom
            by (cases u, simp_all)
        qed
        show "ide x  arr x  Ide b  Nml b  src x0 = Trg b 
              Can (x  b)  Arr (x  b)  Dom (x  b) = x  b  Cod (x  b) =
              x  b"
            using Ide_implies_Can Can_implies_Arr Nmlize_Nml Ide_in_Hom
            by (cases b, simp_all)
        next
        fix u v w
        assume uv: "Ide u  Ide v  Src u = Trg v  Nml (u  v)"
        assume vw: "Src v = Trg w"
        assume w: "Ide w  Nml w"
        assume I1: "w.  Nml u; Ide w  Nml w; Trg v = Trg w  
                          Can (u  w)  Arr (u  w) 
                          Dom (u  w) = u  w  Cod (u  w) = u  w"
        assume I2: "x.  Nml v; Ide x  Nml x; Trg w = Trg x  
                          Can (v  x)  Arr (v  x) 
                          Dom (v  x) = v  x  Cod (v  x) = v  x"
        show "Can ((u  v)  w)  Arr ((u  v)  w) 
              Dom ((u  v)  w) = (u  v)  w 
              Cod ((u  v)  w) = (u  v)  w"
        proof -
          have u: "Nml u  Ide u"
            using uv Nml_HcompD by blast
          have v: "Nml v  Ide v"
            using uv Nml_HcompD by blast
          have "is_Prim0 w  ?thesis"
          proof -
            assume 1: "is_Prim0 w"
            have 2: "(u  v)  w = 𝗋[u  v]"
              using 1 by (cases w, simp_all)
            have 3: "Can (u  v)  Arr (u  v)  Dom (u  v) = u  v  Cod (u  v) = u  v"
              using u v uv 1 2 I1 Nmlize_Nml Nmlize.simps(3) by metis
            hence 4: "VSeq (u  v) 𝗋[u  v]"
              using uv
              by (metis (mono_tags, lifting) Arr.simps(7) Cod.simps(3) Cod.simps(7)
                  Nml_implies_Arr Ide_in_Hom(2) mem_Collect_eq)
            have "Can ((u  v)  w)"
              using 1 2 3 4 uv by (simp add: Ide_implies_Can)
            moreover have "Dom ((u  v)  w) = (u  v)  w"
              using 1 2 3 4 u v w uv vw I1 Ide_in_Hom Nml_HcompNml Ide_in_Hom
              apply (cases w) by simp_all
            moreover have "Cod ((u  v)  w) = (u  v)  w"
              using 1 2 3 4 uv
              using Nmlize_Nml apply (cases w, simp_all)
              by (metis Nmlize.simps(3) Nmlize_Nml HcompNml.simps(3))
            ultimately show ?thesis using w Can_implies_Arr by (simp add: 1 uv)
          qed
          moreover have "¬ is_Prim0 w  ?thesis"
          proof -
            assume 1: "¬ is_Prim0 w"
            have 2: "(u  v)  w = (u  v  w)  (u  v  w)  𝖺[u, v, w]"
              using 1 u v uv w by (cases w; simp)
            have 3: "Can (u  v  w)  Dom (u  v  w) = u  v  w 
                                         Cod (u  v  w) = u  (v  w)"
            proof -
              have "Can (u  v  w)  Dom (u  v  w) = u  v  w 
                                        Cod (u  v  w) = u  v  w"
                using w uv Ide_HcompNml Nml_HcompNml(1)
                apply (cases u, simp_all)
                using u v vw I1 Nmlize_in_Hom(1) [of "v  w"] Nml_Nmlize Ide_Nmlize_Ide
                by simp
              moreover have "u  v  w = u  (v  w)"
                using uv u w Nmlize_Hcomp Nmlize_Nmlize Nml_implies_Arr by simp
              ultimately show ?thesis by presburger
            qed
            have 4: "Can (v  w)  Dom (v  w) = v  w  Cod (v  w) = v  w"
              using v w vw 1 2 I2 by simp
            hence 5: "Src (v  w) = Src w  Trg (v  w) = Trg v"
              using Src_Dom Trg_Dom Can_implies_Arr by fastforce
            have "Can (u  (v  w))  Dom (u  (v  w)) = u  (v  w) 
                                       Cod (u  (v  w)) = u  v  w"
              using u uv vw 4 5 Ide_implies_Can Ide_in_Hom by simp
            moreover have "u  v  w = u  v  w"
            proof -
              have "u  v  w = u  (v  w)"
                using u v w 4
                by (metis Ide_Dom Can_implies_Arr Ide_implies_Arr
                    Nml_Nmlize(1) Nmlize.simps(3) Nmlize_Nml)
              also have "... = (u  v)  w"
                using u v w uv vw HcompNml_assoc by metis
              also have "... = u  v  w"
                using u v w by (metis Nmlize.simps(3) Nmlize_Nml)
              finally show ?thesis by blast
            qed
            moreover have "Can 𝖺[u, v, w]  Dom 𝖺[u, v, w] = (u  v)  w 
                                            Cod 𝖺[u, v, w] = u  (v  w)"
              using uv vw w Ide_implies_Can Ide_in_Hom by auto
            ultimately show ?thesis
              using uv w 2 3 4 Nml_implies_Arr Nmlize_Nmlize Ide_implies_Can
                    Nmlize_Nml Ide_Dom Can_implies_Arr
              by (metis Can.simps(4) Cod.simps(4) Dom.simps(4) Nmlize.simps(3))
          qed
          ultimately show ?thesis by blast
        qed
      qed
      show "Can (a  b)" using assms 0 by blast
      show "a  b  VHom (a  b) a  b" using 0 assms by blast
    qed

    lemma red2_in_Hom [intro]:
    assumes "Ide u" and "Nml u" and "Ide v" and "Nml v" and "Src u = Trg v"
    shows "u  v  HHom (Src v) (Trg u)" and "u  v  VHom (u  v) u  v"
    proof -
      show 1: "u  v  VHom (u  v) u  v"
        using assms Can_red2 Can_implies_Arr by simp
      show "u  v  HHom (Src v) (Trg u)"
        using assms 1 Src_Dom [of "u  v"] Trg_Dom [of "u  v"] Can_red2 Can_implies_Arr by simp
    qed

    lemma red2_simps [simp]:
    assumes "Ide u" and "Nml u" and "Ide v" and "Nml v" and "Src u = Trg v"
    shows "Src (u  v) = Src v" and "Trg (u  v) = Trg u"
    and "Dom (u  v) = u  v" and "Cod (u  v) = u  v"
      using assms red2_in_Hom by auto

    lemma Can_red:
    assumes "Ide u"
    shows "Can (u)" and "u  VHom u u"
    proof -
      have 0: "Ide u  Can (u)  u  VHom u u"
      proof (induct u, simp_all add: Dom_Ide Cod_Ide)
        fix v w
        assume v: "Can (v)  Arr (v)  Dom (v) = v  Cod (v) = v"
        assume w: "Can (w)  Arr (w)  Dom (w) = w  Cod (w) = w"
        assume vw: "Ide v  Ide w  Src v = Trg w"
        show "(Nml (v  w) 
                 Can v  Can w  v  w = v  w) 
              (¬ Nml (v  w) 
                 Can (v  w)  Src (v) = Trg (w) 
                 Dom (v  w) = v  w  Arr (v  w)  Src (v) = Trg (w) 
                 Dom (v  w) = v  w  Cod (v  w) = v  w)"
        proof
          show "Nml (v  w) 
                  Can v  Can w  v  w = v  w"
            using vw Nml_HcompD Ide_implies_Can Dom_Inv VcompNml_Ide_Nml Inv_Ide
                  Nmlize.simps(3) Nmlize_Nml
            by metis
          show "¬ Nml (v  w) 
                  Can (v  w)  Src (v) = Trg (w) 
                  Dom (v  w) = v  w  Arr (v  w)  Src (v) = Trg (w) 
                  Dom (v  w) = v  w  Cod (v  w) = v  w"
          proof
            assume 1: "¬ Nml (v  w)"
            have "Can (v  w)"
              using v w vw Can_red2 Nml_Nmlize Ide_Nmlize_Ide Nml_HcompNml Ide_HcompNml
              by simp
            moreover have "Src (v) = Trg (w)"
              using v w vw Src_Dom Trg_Dom by metis
            moreover have "Dom (v  w) = v  w  Cod (v  w) = v  w"
              using v w vw Can_red2 Nml_Nmlize Ide_Nmlize_Ide by simp
            ultimately show "Can (v  w)  Src (v) = Trg (w) 
                             Dom (v  w) = v  w  Arr (v  w) 
                             Src (v) = Trg (w)  Dom (v  w) = v  w 
                             Cod (v  w) = v  w"
              using Can_implies_Arr by blast
          qed
        qed
      qed
      show "Can (u)" using assms 0 by blast
      show "u  VHom u u" using assms 0 by blast
    qed

    lemma red_in_Hom [intro]:
    assumes "Ide t"
    shows "t  HHom (Src t) (Trg t)" and "t  VHom t t"
    proof -
      show 1: "t  VHom t t"
        using assms Can_red Can_implies_Arr by simp
      show "t  HHom (Src t) (Trg t)"
        using assms 1 Src_Dom [of "t"] Trg_Dom [of "t"] Can_red Can_implies_Arr by simp
    qed

    lemma red_simps [simp]:
    assumes "Ide t"
    shows "Src (t) = Src t" and "Trg (t) = Trg t"
    and "Dom (t) = t" and "Cod (t) = t"
      using assms red_in_Hom by auto

    lemma red_Src:
    assumes "Ide t"
    shows "Src t = Src t"
      using assms is_Prim0_Src [of t]
      by (cases "Src t", simp_all)

    lemma red_Trg:
    assumes "Ide t"
    shows "Trg t = Trg t"
      using assms is_Prim0_Trg [of t]
      by (cases "Trg t", simp_all)

    lemma Nmlize_red [simp]:
    assumes "Ide t"
    shows "t = t"
      using assms Can_red Ide_Nmlize_Can Nmlize_in_Hom Ide_in_Hom by fastforce

    lemma Nmlize_red2 [simp]:
    assumes "Ide t" and "Ide u" and "Nml t" and "Nml u" and "Src t = Trg u"
    shows "t  u = t  u"
      using assms Can_red2 Ide_Nmlize_Can Nmlize_in_Hom [of "t  u"] red2_in_Hom Ide_in_Hom
      by simp

  end

  subsection "Evaluation"

  text ‹
    The following locale is concerned with the evaluation of terms of the bicategorical
    language determined by C›, srcC, and trgC in a bicategory (V, H, 𝖺, 𝗂, src, trg)›,
    given a source and target-preserving functor from C› to V›.
  ›

  locale evaluation_map =
    C: horizontal_homs C srcC trgC +
    bicategorical_language C srcC trgC +
    bicategory V H 𝖺 𝗂 src trg +
    E: "functor" C V E
    for C :: "'c comp"                   (infixr C 55)
    and srcC :: "'c  'c"
    and trgC :: "'c  'c"
    and V :: "'b comp"                   (infixr  55)
    and H :: "'b comp"                   (infixr  53)
    and 𝖺 :: "'b  'b  'b  'b"       (𝖺[_, _, _])
    and 𝗂 :: "'b  'b"                   (𝗂[_])
    and src :: "'b  'b"
    and trg :: "'b  'b"
    and E :: "'c  'b" +
    assumes preserves_src: "E (srcC x) = src (E x)"
    and preserves_trg: "E (trgC x) = trg (E x)"
  begin

    (* TODO: Figure out why this notation has to be reinstated. *)
    notation Nmlize  (_)
    notation HcompNml    (infixr  53)
    notation VcompNml    (infixr  55)
    notation red          (‹_ [56] 56)
    notation red2         (infixr  53)

    primrec eval :: "'c term  'b"    (_)
    where "f0 = E f"
        | "f = E f"
        | "t  u = t  u"
        | "t  u = t  u"
        | "𝗅[t] = 𝔩 t"
        | "𝗅-1[t] = 𝔩'.map t"
        | "𝗋[t] = 𝔯 t"
        | "𝗋-1[t] = 𝔯'.map t"
        | "𝖺[t, u, v] = α (t, u, v)"
        | "𝖺-1[t, u, v] = α'.map (t, u, v)"

    lemma preserves_obj:
    assumes "C.obj a"
    shows "obj (E a)"
    proof (unfold obj_def)
      show "arr (E a)  src (E a) = E a"
      proof
        show "arr (E a)" using assms C.obj_simps by simp
        have "src (E a) = E (srcC a)"
           using assms preserves_src by metis
        also have "... = E a"
           using assms C.obj_simps by simp
        finally show "src (E a) = E a" by simp
      qed
    qed

    lemma eval_in_hom':
    shows "Arr t  «t : Src t  Trg t»  «t : Dom t  Cod t»"
    proof (induct t)
      show "x. Arr x0 
                 «x0 : Src x0  Trg x0»  «x0 : Dom x0  Cod x0»"
        apply (simp add: preserves_src preserves_trg)
        using preserves_src preserves_trg C.objE
        by (metis (full_types) C.obj_def' E.preserves_arr E.preserves_ide in_hhom_def
            ide_in_hom(2))
      show "x. Arr x 
                «x : Src x  Trg x»  «x : Dom x  Cod x»"
        by (auto simp add: preserves_src preserves_trg)
      show "t1 t2.
              (Arr t1  «t1 : Src t1  Trg t1»  «t1 : Dom t1  Cod t1») 
              (Arr t2  «t2 : Src t2  Trg t2»  «t2 : Dom t2  Cod t2») 
              Arr (t1  t2) 
              «t1  t2 : Src (t1  t2)  Trg (t1  t2)» 
              «t1  t2 : Dom (t1  t2)  Cod (t1  t2)»"
        using hcomp_in_hhom in_hhom_def vconn_implies_hpar(1) vconn_implies_hpar(2) by auto
      show "t1 t2.
              (Arr t1  «t1 : Src t1  Trg t1»  «t1 : Dom t1  Cod t1») 
              (Arr t2  «t2 : Src t2  Trg t2»  «t2 : Dom t2  Cod t2») 
              Arr (t1  t2) 
              «t1  t2 : Src (t1  t2)  Trg (t1  t2)» 
              «t1  t2 : Dom (t1  t2)  Cod (t1  t2)»"
        using VSeq_implies_HPar seqI' by auto
      show "t. (Arr t  «t : Src t  Trg t»  «t : Dom t  Cod t») 
                Arr 𝗅[t] 
                «𝗅[t] : Src 𝗅[t]  Trg 𝗅[t]»  «𝗅[t] : Dom 𝗅[t]  Cod 𝗅[t]»"
      proof (simp add: preserves_src preserves_trg)
        fix t
        assume t: "«t : Src t  Trg t»  «t : Dom t  Cod t»"
        assume 1: "Arr t"
        show "«𝔩 t : Src t  Trg t»  «𝔩 t : Trg t  Dom t  Cod t»"
        proof -
          have "src (𝔩 t) = Src t"
            using t 1
            by (metis (no_types, lifting) 𝔩.preserves_cod arr_cod in_hhomE map_simp src_cod)
          moreover have "trg (𝔩 t) = Trg t"
            using t 1
            by (metis (no_types, lifting) 𝔩.preserves_cod arr_cod in_hhomE map_simp trg_cod)
          moreover have "«𝔩 t : Trg t  Dom t  Cod t»"
            using t 1
            apply (elim conjE in_hhomE)
            by (intro in_homI, auto)
          ultimately show ?thesis by auto
        qed
      qed
      show "t. (Arr t  «t : Src t  Trg t»  «t : Dom t  Cod t») 
                Arr 𝗅-1[t] 
                «𝗅-1[t] : Src 𝗅-1[t]  Trg 𝗅-1[t]» 
                «𝗅-1[t] : Dom 𝗅-1[t]  Cod 𝗅-1[t]»"
      proof (simp add: preserves_src preserves_trg)
        fix t
        assume t: "«t : Src t  Trg t»  «t : Dom t  Cod t»"
        assume 1: "Arr t"
        show "«𝔩'.map t : Src t  Trg t» 
              «𝔩'.map t : Dom t  Trg t  Cod t»"
        proof -
          have "src (𝔩'.map t) = Src t"
            using t 1 𝔩'.preserves_dom arr_dom map_simp 𝔩'.preserves_reflects_arr src_dom
            by (metis (no_types, lifting) in_hhomE)
          moreover have "trg (𝔩'.map t) = Trg t"
            using t 1 𝔩'.preserves_dom arr_dom map_simp 𝔩'.preserves_reflects_arr trg_dom
            by (metis (no_types, lifting) in_hhomE)
          moreover have "«𝔩'.map t : Dom t  Trg t  Cod t»"
            using t 1 𝔩'.preserves_hom
            apply (intro in_homI)
              apply auto[1]
             apply fastforce
            by fastforce
          ultimately show ?thesis by blast
        qed
      qed
      show "t. (Arr t  «t : Src t  Trg t»  «t : Dom t  Cod t») 
                 Arr 𝗋[t] 
                 «𝗋[t] : Src 𝗋[t]  Trg 𝗋[t]»  «𝗋[t] : Dom 𝗋[t]  Cod 𝗋[t]»"
      proof (simp add: preserves_src preserves_trg)
        fix t
        assume t: "«t : Src t  Trg t»  «t : Dom t  Cod t»"
        assume 1: "Arr t"
        show "«𝔯 t : Src t  Trg t»  «𝔯 t : Dom t  Src t  Cod t»"
        proof -
          have "src (𝔯 t) = Src t"
            using t 1 𝔯.preserves_cod arr_cod map_simp 𝔯.preserves_reflects_arr src_cod
            by (metis (no_types, lifting) in_hhomE)
          moreover have "trg (𝔯 t) = Trg t"
            using t 1 𝔯.preserves_cod arr_cod map_simp 𝔯.preserves_reflects_arr trg_cod
            by (metis (no_types, lifting) in_hhomE)
          moreover have "«𝔯 t : Dom t  Src t  Cod t»"
            using t 1 by force
          ultimately show ?thesis by blast
        qed
      qed
      show "t. (Arr t  «t : Src t  Trg t»  «t : Dom t  Cod t») 
                 Arr 𝗋-1[t] 
                 «𝗋-1[t] : Src 𝗋-1[t]  Trg 𝗋-1[t]» 
                 «𝗋-1[t] : Dom 𝗋-1[t]  Cod 𝗋-1[t]»"
      proof (simp add: preserves_src preserves_trg)
        fix t
        assume t: "«t : Src t  Trg t»  «t : Dom t  Cod t»"
        assume 1: "Arr t"
        show "«𝔯'.map t : Src t  Trg t» 
              «𝔯'.map t : Dom t  Cod t  Src t»"
        proof -
          have "src (𝔯'.map t) = Src t"
            using t 1 𝔯'.preserves_dom arr_dom map_simp 𝔯'.preserves_reflects_arr src_dom
            by (metis (no_types, lifting) in_hhomE)
          moreover have "trg (𝔯'.map t) = Trg t"
            using t 1 𝔯'.preserves_dom arr_dom map_simp 𝔯'.preserves_reflects_arr trg_dom
            by (metis (no_types, lifting) in_hhomE)
          moreover have "«𝔯'.map t : Dom t  Cod t  Src t»"
            using t 1 src_cod arr_cod 𝔯'.preserves_hom [of "t" "Dom t" "Cod t"]
            apply (elim conjE in_hhomE)
            by (intro in_homI, auto)
          ultimately show ?thesis by blast
        qed
      qed
      show "t u v.
            (Arr t  «t : Src t  Trg t»  «t : Dom t  Cod t») 
            (Arr u  «u : Src u  Trg u»  «u : Dom u  Cod u») 
            (Arr v  «v : Src v  Trg v»  «v : Dom v  Cod v») 
            Arr 𝖺[t, u, v] 
            «𝖺[t, u, v] : Src 𝖺[t, u, v]  Trg 𝖺[t, u, v]» 
            «𝖺[t, u, v] : Dom 𝖺[t, u, v]  Cod 𝖺[t, u, v]»"
      proof (simp add: preserves_src preserves_trg)
        fix t u v
        assume t: "«t : Trg u  Trg t»  «t : Dom t  Cod t»"
        assume u: "«u : Trg v  Trg u»  «u : Dom u  Cod u»"
        assume v: "«v : Src v  Trg v»  «v : Dom v  Cod v»"
        assume tuv: "Arr t  Arr u  Arr v  Src t = Trg u  Src u = Trg v"
        show "«α (t, u, v) : Src v  Trg t» 
              «α (t, u, v) :
                 (Dom t  Dom u)  Dom v  Cod t  Cod u  Cod v»"
        proof -
          have 1: "VVV.in_hom (t, u, v)
                                (Dom t, Dom u, Dom v) (Cod t, Cod u, Cod v)"
          proof -
            have "(t, u, v) 
                    VxVxV.hom (Dom t, Dom u, Dom v) (Cod t, Cod u, Cod v)"
              using t u v tuv by simp
            moreover have "(t, u, v) 
                             {τμν. arr (fst τμν)  VV.arr (snd τμν)  
                                   src (fst τμν) = trg (fst (snd τμν))}"
              using t u v tuv by fastforce
            ultimately show ?thesis
              using VVV.hom_char
                      [of "(Dom t, Dom u, Dom v)" "(Cod t, Cod u, Cod v)"]
              by blast
          qed
          have 4: "VVV.arr (Dom t, Dom u, Dom v)"
            using 1 VVV.ide_dom VVV.dom_simp by (elim VVV.in_homE) force
          have 5: "VVV.arr (Cod t, Cod u, Cod v)"
            using 1 VVV.ide_cod VVV.cod_simp VVV.in_hom_charSbC by blast
          have 2: "«α (t, u, v) :
                      (Dom t  Dom u)  Dom v  Cod t  Cod u  Cod v»"
            using 1 4 5 HoHV_def HoVH_def α_def
                  α.preserves_hom [of "(t, u, v)" "(Dom t, Dom u, Dom v)"
                                      "(Cod t, Cod u, Cod v)"]
            by simp
          have 3: "«α (t, u, v) : Src v  Trg t»"
          proof
            show "arr (α (t, u, v))"
              using 2 by auto
            show "src (α (t, u, v)) = Src v"
            proof -
              have "src (α (t, u, v)) = src ((Dom t  Dom u)  Dom v)"
                using 2 src_dom [of "α (t, u, v)"] by fastforce
              also have "... = src Dom v"
                using 4 VVV.arr_charSbC VV.arr_charSbC by simp
              also have "... = src (dom v)"
                using v by fastforce
              also have "... = Src v"
                using v by auto
              finally show ?thesis by auto
            qed
            show "trg (α (t, u, v)) = Trg t"
            proof -
              have "trg (α (t, u, v)) = trg ((Dom t  Dom u)  Dom v)"
                using 2 trg_dom [of "α (t, u, v)"] by fastforce
              also have "... = trg Dom t"
                using 4 VVV.arr_charSbC VV.arr_charSbC by simp
              also have "... = trg (dom t)"
                using t by fastforce
              also have "... = Trg t"
                using t by auto
              finally show ?thesis by auto
            qed
          qed
          show ?thesis using 2 3 by simp
        qed
      qed
      show "t u v.
            (Arr t  «t : Src t  Trg t»  «t : Dom t  Cod t») 
            (Arr u  «u : Src u  Trg u»  «u : Dom u  Cod u») 
            (Arr v  «v : Src v  Trg v»  «v : Dom v  Cod v») 
            Arr 𝖺-1[t, u, v] 
            «𝖺-1[t, u, v] : Src 𝖺-1[t, u, v]  Trg 𝖺-1[t, u, v]» 
            «𝖺-1[t, u, v] : Dom 𝖺-1[t, u, v]  Cod 𝖺-1[t, u, v]»"
      proof (simp add: preserves_src preserves_trg)
        fix t u v
        assume t: "«t : Trg u  Trg t»  «t : Dom t  Cod t»"
        assume u: "«u : Trg v  Trg u»  «u : Dom u  Cod u»"
        assume v: "«v : Src v  Trg v»  «v : Dom v  Cod v»"
        assume tuv: "Arr t  Arr u  Arr v  Src t = Trg u  Src u = Trg v"
        show "«α'.map (t, u, v) : Src v  Trg t» 
              «α'.map (t, u, v) :
                 Dom t  Dom u  Dom v  (Cod t  Cod u)  Cod v»"
        proof -
          have 1: "VVV.in_hom (t, u, v)
                                (Dom t, Dom u, Dom v) (Cod t, Cod u, Cod v)"
            using t u v tuv VVV.hom_char VVV.arr_charSbC VV.arr_charSbC VVV.dom_charSbC VVV.cod_charSbC
            apply (elim conjE in_hhomE in_homE)
            apply (intro VVV.in_homI)
            by simp_all
          have 4: "VVV.arr (Dom t, Dom u, Dom v)"
            using "1" VVV.in_hom_charSbC by blast
          have 5: "VVV.arr (Cod t, Cod u, Cod v)"
            using "1" VVV.in_hom_charSbC by blast
          have 2: "«α'.map (t, u, v) :
                      Dom t  Dom u  Dom v  (Cod t  Cod u)  Cod v»"
            using 1 4 5 HoHV_def HoVH_def α'.map_def
                  α'.preserves_hom [of "(t, u, v)" "(Dom t, Dom u, Dom v)"
                                       "(Cod t, Cod u, Cod v)"]
            by simp
          have 3: "«α'.map (t, u, v) : Src v  Trg t»"
          proof
            show "arr (α'.map (t, u, v))"
              using 2 by auto
            show "src (α'.map (t, u, v)) = Src v"
            proof -
              have "src (α'.map (t, u, v)) = src (Dom t  Dom u  Dom v)"
                using 2 src_dom [of "α'.map (t, u, v)"] by fastforce
              also have "... = src Dom v"
                using 4 VVV.arr_charSbC VV.arr_charSbC by simp
              also have "... = src (dom v)"
                using v by fastforce
              also have "... = Src v"
                using v by auto
              finally show ?thesis by auto
            qed
            show "trg (α'.map (t, u, v)) = Trg t"
            proof -
              have "trg (α'.map (t, u, v)) = trg (Dom t  Dom u  Dom v)"
                using 2 trg_dom [of "α'.map (t, u, v)"] by fastforce
              also have "... = trg Dom t"
                using 4 VVV.arr_charSbC VV.arr_charSbC hseqI' by simp
              also have "... = trg (dom t)"
                using t by fastforce
              also have "... = Trg t"
                using t by auto
              finally show ?thesis by auto
            qed
          qed
          show ?thesis using 2 3 by simp
        qed
      qed
    qed

    lemma eval_in_hom [intro]:
    assumes "Arr t"
    shows "«t : Src t  Trg t»" and "«t : Dom t  Cod t»"
      using assms eval_in_hom' by simp_all

    (*
     * TODO: It seems to me that the natural useful orientation of these facts is syntax
     * to semantics.  However, having this as the default makes it impossible to do various
     * proofs by simp alone.  This has to be sorted out.  For right now, I am going to include
     * both versions, which will have to be explicitly invoked where needed.
     *)
    lemma eval_simps:
    assumes "Arr f"
    shows "arr f" and "Src f = src f" and "Trg f = trg f"
    and "Dom f = dom f" and "Cod f = cod f"
      using assms eval_in_hom [of f] by auto

    lemma eval_simps':
    assumes "Arr f"
    shows "arr f" and "src f = Src f" and "trg f = Trg f"
    and "dom f = Dom f" and "cod f = Cod f"
      using assms eval_in_hom by auto

    lemma obj_eval_Obj:
    shows "Obj t  obj t"
      using preserves_obj
      by (induct t) auto

    lemma ide_eval_Ide:
    shows "Ide t  ide t"
      by (induct t, auto simp add: eval_simps')

    lemma arr_eval_Arr [simp]:
    assumes "Arr t"
    shows "arr t"
      using assms by (simp add: eval_simps')

    (*
     * TODO: The next few results want eval_simps oriented from syntax to semantics.
     *)

    lemma eval_Lunit [simp]:
    assumes "Arr t"
    shows "𝗅[t] = 𝗅[Cod t]  (trg t  t)"
      using assms 𝔩.is_natural_2 𝔩_ide_simp by (simp add: eval_simps)

    lemma eval_Lunit' [simp]:
    assumes "Arr t"
    shows "𝗅-1[t] = 𝗅-1[Cod t]  t"
      using assms 𝔩'.is_natural_2 𝔩_ide_simp by (simp add: eval_simps)

    lemma eval_Runit [simp]:
    assumes "Arr t"
    shows "𝗋[t] = 𝗋[Cod t]  (t  src t)"
      using assms 𝔯.is_natural_2 𝔯_ide_simp by (simp add: eval_simps)

    lemma eval_Runit' [simp]:
    assumes "Arr t"
    shows "𝗋-1[t] = 𝗋-1[Cod t]  t"
      using assms 𝔯'.is_natural_2 𝔯_ide_simp by (simp add: eval_simps)

    lemma eval_Assoc [simp]:
    assumes "Arr t" and "Arr u" and "Arr v" and "Src t = Trg u" and "Src u = Trg v"
    shows "𝖺[t, u, v] = α (cod t, cod u, cod v)  ((t  u)  v)"
    proof -
      have "𝖺[t, u, v] = α (t, u, v)" by simp
      also have "... = α (VVV.cod (t, u, v))  HoHV (t, u, v)"
        using assms α.is_natural_2 [of "(t, u, v)"] VVV.arr_charSbC VVV.cod_charSbC
              α.is_extensional α_def
        by auto
      also have "... = α (cod t, cod u, cod v)  ((t  u)  v)"
        unfolding HoHV_def α_def
        using assms VVV.arr_charSbC VV.arr_charSbC VVV.cod_charSbC α.is_extensional
        by auto
      finally show ?thesis by simp
    qed

    lemma eval_Assoc' [simp]:
    assumes "Arr t" and "Arr u" and "Arr v" and "Src t = Trg u" and "Src u = Trg v"
    shows "𝖺-1[t, u, v] = 𝖺-1[cod t, cod u, cod v]  (t  u  v)"
    proof -
      have "𝖺-1[t, u, v] = α'.map (t, u, v)" by simp
      also have "... = α'.map (VVV.cod (t, u, v))  HoVH (t, u, v)"
        using assms α'.is_natural_2 [of "(t, u, v)"] VVV.arr_charSbC VVV.cod_charSbC
              α'.is_extensional
        by simp
      also have "... = α'.map (cod t, cod u, cod v)  (t  u  v)"
        unfolding HoVH_def
        using assms VVV.arr_charSbC VV.arr_charSbC VVV.cod_charSbC α'.is_extensional
        apply simp
        using eval_simps'(2) eval_simps'(3) by presburger
      finally show ?thesis
        using 𝖺'_def by simp
    qed

    lemma eval_Lunit_Ide [simp]:
    assumes "Ide t"
    shows "𝗅[t] = 𝗅[t]"
      using assms 𝔩_ide_simp ide_eval_Ide by simp

    lemma eval_Lunit'_Ide [simp]:
    assumes "Ide t"
    shows "𝗅-1[t] = 𝗅-1[t]"
      using assms 𝔩_ide_simp ide_eval_Ide by simp

    lemma eval_Runit_Ide [simp]:
    assumes "Ide t"
    shows "𝗋[t] = 𝗋[t]"
      using assms 𝔯_ide_simp ide_eval_Ide by simp

    lemma eval_Runit'_Ide [simp]:
    assumes "Ide t"
    shows "𝗋-1[t] = 𝗋-1[t]"
      using assms 𝔯_ide_simp ide_eval_Ide by simp

    lemma eval_Assoc_Ide [simp]:
    assumes "Ide t" and "Ide u" and "Ide v" and "Src t = Trg u" and "Src u = Trg v"
    shows "𝖺[t, u, v] = α (t, u, v)"
      using assms by simp

    lemma eval_Assoc'_Ide [simp]:
    assumes "Ide t" and "Ide u" and "Ide v" and "Src t = Trg u" and "Src u = Trg v"
    shows "𝖺-1[t, u, v] = 𝖺-1[t, u, v]"
      using assms 𝖺'_def by simp

    lemma iso_eval_Can:
    shows "Can t  iso t"
    proof (induct t; simp add: fsts.intros snds.intros)
      show "x. C.obj x  iso (E x)" by auto
      show "t1 t2.  iso t1; iso t2; Can t1  Can t2  Src t1 = Trg t2  
                      iso (t1  t2)"
        using Can_implies_Arr by (simp add: eval_simps')
      show "t1 t2.  iso t1; iso t2; Can t1  Can t2  Dom t1 = Cod t2  
                      iso (t1  t2)"
        using Can_implies_Arr isos_compose by (simp add: eval_simps')
      show "t.  iso t; Can t   iso (𝔩 t)"
        using 𝔩.preserves_iso by auto
      show "t.  iso t; Can t   iso (𝔩'.map t)"
        using 𝔩'.preserves_iso by simp
      show "t.  iso t; Can t   iso (𝔯 t)"
        using 𝔯.preserves_iso by auto
      show "t.  iso t; Can t   iso (𝔯'.map t)"
        using 𝔯'.preserves_iso by simp
      fix t1 t2 t3
      assume t1: "iso t1" and t2: "iso t2" and t3: "iso t3"
      assume 1: "Can t1  Can t2  Can t3  Src t1 = Trg t2  Src t2 = Trg t3"
      have 2: "VVV.iso (t1, t2, t3)"
      proof -
        have 3: "VxVxV.iso (t1, t2, t3)"
          using t1 t2 t3 Can_implies_Arr VxVxV.iso_char VxV.iso_char by simp
        moreover have "VVV.arr (VxVxV.inv (t1, t2, t3))"
        proof -
          have "VxVxV.inv (t1, t2, t3) = (inv t1, inv t2, inv t3)"
            using t1 t2 t3 3 by simp
          thus ?thesis
            using t1 t2 t3 1 Can_implies_Arr VVV.arr_charSbC VV.arr_charSbC
            by (simp add: eval_simps')
        qed
        ultimately show ?thesis
          using t1 t2 t3 1 Can_implies_Arr VVV.iso_charSbC VVV.arr_charSbC
          by (auto simp add: eval_simps')
      qed
      show "iso (α (t1, t2, t3))"
        using 2 α_def α.preserves_iso by auto
      show "iso (α'.map (t1, t2, t3))"
        using 2 α'.preserves_iso by simp
    qed

    lemma eval_Inv_Can:
    shows "Can t  Inv t = inv t"
    proof (induct t)
      show "x. Can x0  Inv x0 = inv x0" by auto
      show "x. Can x  Inv x = inv x" by simp
      show "t1 t2. (Can t1  Inv t1 = inv t1) 
                    (Can t2  Inv t2 = inv t2) 
                     Can (t1  t2)  Inv (t1  t2) = inv t1  t2"
        using iso_eval_Can Can_implies_Arr
        by (simp add: eval_simps')
      show "t1 t2. (Can t1  Inv t1 = inv t1) 
                    (Can t2  Inv t2 = inv t2) 
                     Can (t1  t2)  Inv (t1  t2) = inv t1  t2"
        using iso_eval_Can inv_comp Can_implies_Arr
        by (simp add: eval_simps')
      fix t
      assume I: "Can t  Inv t = inv t"
      show "Can 𝗅[t]  Inv 𝗅[t] = inv 𝗅[t]"
      proof -
        assume t: "Can 𝗅[t]"
        have "Inv 𝗅[t] = 𝗅-1[Inv t]" by simp
        also have "... = 𝔩'.map (inv t)"
          using t I by simp
        also have "... = 𝔩'.map (cod (inv t))  inv t"
          using t 𝔩'.is_natural_2 iso_inv_iso iso_eval_Can iso_is_arr
          by (metis (no_types, lifting) Can.simps(5) map_simp)
        also have "... = inv (t  𝔩 (dom t))"
        proof -
          have 1: "iso t" using t iso_eval_Can by simp
          moreover have "iso (𝔩 (dom t))"
            using t 1 𝔩.components_are_iso ide_dom by blast
          moreover have "seq t (𝔩 (dom t))"
            using t 1 iso_is_arr by auto
          ultimately show ?thesis
            using t 1 inv_comp by auto
        qed
        also have "... = inv 𝗅[t]"
          using t iso_eval_Can 𝔩_ide_simp lunit_naturality Can_implies_Arr eval_Lunit
          by (auto simp add: eval_simps)
        finally show ?thesis by blast
      qed
      show "Can 𝗅-1[t]  Inv 𝗅-1[t] = inv 𝗅-1[t]"
      proof -
        assume t: "Can (Lunit' t)"
        have "Inv (Lunit' t) = Lunit (Inv t)" by simp
        also have "... = 𝔩 (inv t)"
          using t I by simp
        also have "... = inv t  𝔩 (dom (inv t))"
          using t 𝔩.is_natural_1 iso_inv_iso iso_eval_Can iso_is_arr
          by (metis (no_types, lifting) Can.simps(6) map_simp)
        also have "... = inv (𝔩'.map (cod t)  t)"
        proof -
          have 1: "iso t" using t iso_eval_Can by simp
          moreover have "iso (𝔩'.map (cod t))"
            using t 1 𝔩'.components_are_iso ide_cod by blast
          moreover have "seq (𝔩'.map (cod t)) t"
            using t 1 iso_is_arr by auto
          ultimately show ?thesis
            using t 1 inv_comp by auto
        qed
        also have "... = inv 𝗅-1[t]"
          using t 𝔩'.is_natural_2 iso_eval_Can iso_is_arr by force
        finally show ?thesis by auto
      qed
      show "Can 𝗋[t]  Inv 𝗋[t] = inv 𝗋[t]"
      proof -
        assume t: "Can 𝗋[t]"
        have "Inv 𝗋[t] = 𝗋-1[Inv t]" by simp
        also have "... = 𝔯'.map (inv t)"
          using t I by simp
        also have "... = 𝔯'.map (cod (inv t))  inv t"
          using t 𝔯'.is_natural_2 map_simp iso_inv_iso iso_eval_Can iso_is_arr
          by (metis (no_types, lifting) Can.simps(7))
        also have "... = inv (t  𝔯 (dom t))"
        proof -
          have 1: "iso t" using t iso_eval_Can by simp
          moreover have "iso (𝔯 (dom t))"
            using t 1 𝔯.components_are_iso ide_dom by blast
          moreover have "seq t (𝔯 (dom t))"
            using t 1 iso_is_arr by simp
          ultimately show ?thesis
            using t 1 inv_comp by auto
        qed
        also have "... = inv 𝗋[t]"
          using t 𝔯_ide_simp iso_eval_Can runit_naturality Can_implies_Arr eval_Runit
          by (auto simp add: eval_simps)
        finally show ?thesis by blast
      qed
      show "Can 𝗋-1[t]  Inv 𝗋-1[t] = inv 𝗋-1[t]"
      proof -
        assume t: "Can 𝗋-1[t]"
        have "Inv 𝗋-1[t] = 𝗋[Inv t]"
          by simp
        also have "... = 𝔯 (inv t)"
          using t I by simp
        also have "... = inv t  𝔯 (dom (inv t))"
          using t 𝔯.is_natural_1 map_simp iso_inv_iso iso_eval_Can iso_is_arr
          by (metis (no_types, lifting) Can.simps(8))
        also have "... = inv (𝔯'.map (cod t)  t)"
        proof -
          have 1: "iso t" using t iso_eval_Can by simp
          moreover have "iso (𝔯'.map (cod t))"
            using t 1 𝔯'.components_are_iso ide_cod by blast
          moreover have "seq (𝔯'.map (cod t)) t"
            using t 1 iso_is_arr by auto
          ultimately show ?thesis
            using t 1 inv_comp by auto
        qed
        also have "... = inv 𝗋-1[t]"
          using t 𝔯'.is_natural_2 iso_eval_Can iso_is_arr by auto
        finally show ?thesis by auto
      qed
      next
      fix t u v
      assume I1: "Can t  Inv t = inv t"
      assume I2: "Can u  Inv u = inv u"
      assume I3: "Can v  Inv v = inv v"
      show "Can 𝖺[t, u, v]  Inv 𝖺[t, u, v] = inv 𝖺[t, u, v]"
      proof -
        assume "Can 𝖺[t, u, v]"
        hence tuv: "Can t  Can u  Can v  Src t = Trg u  Src u = Trg v" by simp
        have "Inv 𝖺[t, u, v] = 𝖺-1[Inv t, Inv u, Inv v]" by simp
        also have "... = 𝖺-1[dom t, dom u, dom v]  (inv t  inv u  inv v)"
          using tuv I1 I2 I3 eval_in_hom α'.map_ide_simp inv_in_hom iso_eval_Can assoc'_naturality
                Can_implies_Arr Src_Inv Trg_Inv eval_Assoc' Dom_Inv Can_Inv cod_inv
          by presburger
        also have "... = inv ((t  u  v)  α (dom t, dom u, dom v))"
          using tuv iso_eval_Can Can_implies_Arr eval_simps'(2) eval_simps'(3) α_def
          by (simp add: inv_comp)
        also have "... = inv (α (t, u, v))"
          using tuv Can_implies_Arr α_def
          by (metis assoc_is_natural_1 arr_eval_Arr eval_simps'(2) eval_simps'(3) fst_conv snd_conv)
        also have "... = inv 𝖺[t, u, v]" by simp
        finally show ?thesis by blast
      qed
      show "Can 𝖺-1[t, u, v]  Inv 𝖺-1[t, u, v] = inv 𝖺-1[t, u, v]"
      proof -
        assume tuv: "Can 𝖺-1[t, u, v]"
        have t: "Can t" using tuv by simp
        have u: "Can u" using tuv by simp
        have v: "Can v" using tuv by simp
        have "Inv 𝖺-1[t, u, v] = 𝖺[Inv t, Inv u, Inv v]" by simp
        also have "... = (inv t  inv u  inv v)  α (cod t, cod u, cod v)"
          using α_def tuv I1 I2 I3 iso_eval_Can Can_implies_Arr eval_simps'(2) eval_simps'(3)
          apply simp
          using assoc_is_natural_1 arr_inv dom_inv src_inv trg_inv by presburger
        also have "... = inv (𝖺-1[cod t, cod u, cod v]  (t  u  v))"
          using tuv inv_comp [of "t  u  v" "𝖺-1[cod t, cod u, cod v]"]
                Can_implies_Arr iso_assoc α_def
          by (simp add: eval_simps'(2) eval_simps'(3) iso_eval_Can)
        also have 1: "... = inv (((t  u)  v)  𝖺-1[dom t, dom u, dom v])"
          using tuv assoc'_naturality [of "t" "u" "v"] Can_implies_Arr
                eval_simps'(2) eval_simps'(3)
          by simp
        also have "... = inv 𝖺-1[t, u, v]"
          using tuv 1 Can_implies_Arr eval_Assoc' by auto
        finally show ?thesis by blast
      qed
    qed

    lemma eval_VcompNml:
    assumes "Nml t" and "Nml u" and "VSeq t u"
    shows "t  u = t  u"
    proof -
      have "u.  Nml t; Nml u; VSeq t u   t  u = t  u"
      proof (induct t, simp_all add: eval_simps)
        fix u a
        assume u: "Nml u"
        assume 1: "Arr u  a0 = Cod u"
        show "u = cod u  u"
          using 1 comp_cod_arr by simp
        next
        fix u f
        assume u: "Nml u"
        assume f: "C.arr f"
        assume 1: "Arr u  C.dom f = Cod u"
        show "f  u = E f  u"
          using f u 1 as_nat_trans.preserves_comp_2 by (cases u; simp)
        next
        fix u v w
        assume I1: "u.  Nml v; Nml u; Arr u  Dom v = Cod u   v  u = v  u"
        assume I2: "u.  Nml w; Nml u; Arr u  Dom w = Cod u   w  u = w  u"
        assume vw: "Nml (v  w)"
        have v: "Nml v  v = Prim (un_Prim v)"
          using vw by (simp add: Nml_HcompD)
        have w: "Nml w"
          using vw by (simp add: Nml_HcompD)
        assume u: "Nml u"
        assume 1: "Arr v  Arr w  Src v = Trg w  Arr u  Dom v  Dom w = Cod u"
        show "(v  w)  u = (v  w)  u"
          using u 1 HcompNml_in_Hom apply (cases u, simp_all)
        proof -
          fix x y
          assume 3: "u = x  y"
          have x: "Nml x"
            using u 1 3 Nml_HcompD by blast
          have y: "Nml y"
            using u x 1 3 Nml_HcompD by blast
          assume 4: "Arr v  Arr w  Src v = Trg w  Dom v = Cod x  Dom w = Cod y"
          have "v  x  w  y = v  x  w  y"
            using v w x y 4 HcompNml_in_Hom by simp
          moreover have "... = v  x  w  y" by simp
          moreover have "... = v  x  w  y"
            using v w x y 4 I1 [of x] I2 [of y] Nml_implies_Arr by simp
          moreover have "... = (v  w)  (x  y)"
            using v w x y 4 Nml_implies_Arr interchange [of "v" "x" "w" "y"]
            by (simp add: eval_simps')
          ultimately have "v  x  w  y = (v  w)  (x  y)" by presburger
          moreover have "arr v  x  arr w  y"
            using v w x y 4 VcompNml_in_Hom by simp
          ultimately show "v  x  w  y = (v  w)  (x  y)"
            by simp
        qed
      qed
      thus ?thesis using assms by blast
    qed

    lemma eval_red_Hcomp:
    assumes "Ide a" and "Ide b"
    shows "(a  b) = a  b  (a  b)"
    proof -
      have "Nml (a  b)  ?thesis"
      proof -
        assume 1: "Nml (a  b)"
        hence 2: "Nml a  Nml b  Src a = Trg b"
          using Nml_HcompD(3-4,7) by simp
        have "(a  b) = a  b"
          using 1 Nml_HcompD
          by (metis eval.simps(3) red_Nml)
        also have "... = a  b  (a  b)"
          using assms 1 2 ide_eval_Ide Nmlize_in_Hom red2_Nml Nmlize_Nml
          by (simp add: eval_simps')
        finally show ?thesis by simp
      qed
      moreover have "¬ Nml (a  b)  ?thesis"
        using assms Can_red2 by (simp add: Can_red(1) iso_eval_Can)
      ultimately show ?thesis by blast
    qed

    (* TODO: Would the following still be useful if a0 is replaced by Src t? *)
    lemma eval_red2_Nml_Prim0:
    assumes "Ide t" and "Nml t" and "Src t = a0"
    shows "t  a0 = 𝗋[t]"
      using assms 𝔯_ide_simp
      apply (cases t)
               apply simp_all
    proof -
      show "C.obj a  t = a0  𝔩 (E a) = 𝗋[E a]"
        using unitor_coincidence obj_eval_Obj [of t] 𝔩_ide_simp by auto
      show "b c. Ide b  Ide c  Src b = Trg c  𝔯 (b  c) = 𝗋[b  c]"
        using 𝔯_ide_simp by (simp add: eval_simps' ide_eval_Ide)
    qed

  end

  text ‹
    Most of the time when we interpret the @{locale evaluation_map} locale, we are evaluating
    terms formed from the arrows in a bicategory as arrows of the bicategory itself.
    The following locale streamlines that use case.
  ›

  locale self_evaluation_map =
    bicategory
  begin

    sublocale bicategorical_language V src trg ..

    sublocale evaluation_map V src trg V H 𝖺 𝗂 src trg λμ. if arr μ then μ else null
      using src.is_extensional trg.is_extensional
      by (unfold_locales, auto)

    notation eval (_)
    notation Nmlize (_)

  end

  subsection "Coherence"

  text ‹
    We define an individual term to be \emph{coherent} if it commutes, up to evaluation,
    with the reductions of its domain and codomain.  We then formulate the coherence theorem
    as the statement ``every formal arrow is coherent''.  Because reductions evaluate
    to isomorphisms, this implies the standard version of coherence, which says that
    ``parallel canonical terms have equal evaluations''.
  ›

  context evaluation_map
  begin

    abbreviation coherent
    where "coherent t  Cod t  t = t  Dom t"

    lemma Nml_implies_coherent:
    assumes "Nml t"
    shows "coherent t"
      using assms Nml_implies_Arr Ide_Dom Ide_Cod Nml_Dom Nml_Cod Nmlize_Nml red_Nml
      by (metis Dom_Cod VcompNml_Cod_Nml arr_eval_Arr comp_arr_dom eval_VcompNml
          eval_simps(4))

    lemma canonical_factorization:
    assumes "Arr t"
    shows "coherent t  t = inv Cod t  t  Dom t"
    proof
      assume 1: "coherent t"
      have "inv Cod t  t  Dom t = inv Cod t  Cod t  t"
        using 1 by simp
      also have "... = (inv Cod t  Cod t)  t"
        using comp_assoc by simp
      also have "... = t"
        using assms red_in_Hom Ide_Cod Can_red iso_eval_Can comp_cod_arr
        by (simp add: comp_inv_arr' eval_simps'(4) eval_simps'(5))
      finally show "t = inv Cod t  t  Dom t"
        by presburger
      next
      assume 1: "t = inv Cod t  t  Dom t"
      hence "Cod t  t = Cod t  inv Cod t  t  Dom t" by simp
      also have "... = (Cod t  inv Cod t)  t  Dom t"
        using comp_assoc by simp
      also have "... = t  Dom t"
      proof -
        have "Cod t  inv Cod t = cod t"
          using assms red_in_Hom Ide_Cod Can_red iso_eval_Can
                inv_is_inverse Nmlize_in_Hom comp_arr_inv
          by (simp add: eval_simps')
        thus ?thesis
          using assms red_in_Hom Ide_Cod Can_red iso_eval_Can
                Ide_Dom Nmlize_in_Hom comp_cod_arr
          by (auto simp add: eval_simps')
      qed
      finally show "coherent t" by blast
    qed

    lemma coherent_iff_coherent_Inv:
    assumes "Can t"
    shows "coherent t  coherent (Inv t)"
    proof
      have 1: "t. Can t  coherent t  coherent (Inv t)"
      proof -
        fix t
        assume "Can t"
        hence t: "Can t  Arr t  Ide (Dom t)  Ide (Cod t) 
                  arr t  iso t  inverse_arrows t (inv t) 
                  Can t  Arr t  arr t  iso t  t  VHom Dom t Cod t 
                  inverse_arrows t (inv t)  Inv t  VHom (Cod t) (Dom t)"
          using assms Can_implies_Arr Ide_Dom Ide_Cod iso_eval_Can inv_is_inverse
                Nmlize_in_Hom Can_Nmlize_Can Inv_in_Hom
          by simp
        assume coh: "coherent t"
        have "Cod (Inv t)  Inv t = (inv t  t)  Cod (Inv t)  Inv t"
          using t comp_inv_arr red_in_Hom
                comp_cod_arr [of "Cod (Inv t)  Inv t" "inv t  t"]
          by (auto simp add: eval_simps')
        also have "... = inv t  t  Dom t  inv t"
          using t eval_Inv_Can comp_assoc by auto
        also have "... = inv t  (t  Dom t)  inv t"
          using comp_assoc by simp
        also have "... = inv t  (Cod t  t)  inv t"
          using t coh by simp
        also have "... = inv t  Cod t  t  inv t"
          using comp_assoc by simp
        also have "... = Inv t  Dom (Inv t)"
        proof -
          have "Cod t  t  inv t = Dom (Inv t)"
            using t eval_Inv_Can red_in_Hom comp_arr_inv comp_arr_dom
            by (simp add: eval_simps')
          thus ?thesis
            using t Nmlize_Inv eval_Inv_Can by simp
        qed
        finally show "coherent (Inv t)" by blast
      qed
      show "coherent t  coherent (Inv t)" using assms 1 by simp
      show "coherent (Inv t)  coherent t"
      proof -
        assume "coherent (Inv t)"
        hence "coherent (Inv (Inv t))"
          using assms 1 Can_Inv by blast
        thus ?thesis using assms by simp
      qed
    qed

    text ‹
      The next two facts are trivially proved by the simplifier, so formal named facts
      are not really necessary, but we include them for logical completeness of the
      following development, which proves coherence by structural induction.
    ›

    lemma coherent_Prim0:
    assumes "C.obj a"
    shows "coherent a0"
      by simp

    lemma coherent_Prim:
    assumes "Arr f"
    shows "coherent f"
      using assms by simp

    lemma coherent_Lunit_Ide:
    assumes "Ide t"
    shows "coherent 𝗅[t]"
    proof -
      have t: "Ide t  Arr t  Dom t = t  Cod t = t 
               ide t  ide t  t  hom t t"
        using assms Ide_in_Hom Ide_Nmlize_Ide
              red_in_Hom eval_in_hom ide_eval_Ide
        by force
      have 1: "Obj (Trg t)" using t by auto
      have "Cod 𝗅[t]  𝗅[t] = 𝗅[t]  (Trg t  t)"
        using t 𝔩_ide_simp lunit_naturality [of "t"] red_in_Hom
        by (simp add: eval_simps')
      also have "... = t  𝗅[t]  (Trg t  t)"
         using t 1 lunit_in_hom Nmlize_in_Hom ide_eval_Ide red_in_Hom comp_cod_arr
               Obj_implies_Ide
         by (auto simp add: eval_simps')
      also have "... = 𝗅[t]  Dom 𝗅[t]"
        using 1 t Nml_Trg 𝔩_ide_simp by (cases "Trg t"; simp)
      finally show ?thesis by simp
    qed
      
    text ‹
      Unlike many of the other results, the next one was not quite so straightforward to adapt
      from @{sessionMonoidalCategory}.
    ›

    lemma coherent_Runit_Ide:
    assumes "Ide t"
    shows "coherent 𝗋[t]"
    proof -
      have t: "Ide t  Arr t  Dom t = t  Cod t = t 
               ide t  ide t  t  hom t t"
        using assms Ide_in_Hom Ide_Nmlize_Ide
              red_in_Hom eval_in_hom ide_eval_Ide
        by force
      have "Cod 𝗋[t]  𝗋[t] = 𝗋[t]  (t  Src t)"
        using t 𝔯_ide_simp red_in_Hom runit_naturality [of "t"]
        by (simp add: eval_simps')
      also have "... = 𝗋[t]  Dom 𝗋[t]"
      proof -
         have "𝗋[t]  Dom 𝗋[t] = t  t  Src t  (t  Src t)"
           using t by (cases t; simp; cases "Src t"; simp)
         also have "... = (t  t  Src t)  (t  Src t)"
         proof -
           have "t  hom t t"
             using t Nmlize_in_Hom by auto
           moreover have "t  Src t  hom (t  Src t) t"
           proof -
             have "t  Src t  hom t  Src t t"
             proof -
               have "Src t = Trg Src t  t  Src t = t"
                 using t Nmlize_Src Nml_Nmlize HcompNml_Nml_Src [of "t"]
                 by simp
               thus ?thesis
                 using t Ide_Nmlize_Ide Nml_Nmlize Obj_Src red2_in_Hom(2) Obj_implies_Ide
                 by (auto simp add: eval_simps')
             qed
             thus ?thesis using t Nmlize_in_Hom Nmlize_Src by simp
           qed
           moreover have "t  Src t  hom (t  Src t) (t  Src t)"
             using t red_in_Hom red_Src Obj_Src eval_simps' Obj_implies_Ide by auto
           ultimately show ?thesis using comp_assoc by fastforce
         qed
         also have "... = 𝗋[t]  (t  Src t)"
         proof -
           have "t  Src t = 𝗋[t]"
           proof -
             have "Nml t" using t Nml_Nmlize by blast
             moreover have "is_Prim0 Src t"
               using t is_Prim0_Src Nmlize_Src by presburger
             ultimately show ?thesis
               apply (cases "t"; simp; cases "Src t"; simp)
               using t unitor_coincidence 𝔩_ide_simp 𝔯_ide_simp Nmlize_in_Hom
                 apply simp_all
               using t is_Prim0_Src
               apply (cases "t"; simp)
               using t Nmlize_Src unitor_coincidence preserves_obj by simp
           qed
           moreover have "𝗋[t]  hom (t  Src t) t"
             using t Nmlize_in_Hom by (auto simp add: eval_simps'(2))
           ultimately show ?thesis
             using comp_cod_arr [of "𝗋[t]"] by fastforce
         qed
         also have "... = 𝗋[t]  (t  Src t)"
           using t red_Src by auto
         finally show ?thesis by argo
      qed
      finally show ?thesis by blast
    qed

    lemma coherent_Lunit'_Ide:
    assumes "Ide a"
    shows "coherent 𝗅-1[a]"
      using assms Ide_implies_Can coherent_Lunit_Ide
            coherent_iff_coherent_Inv [of "Lunit a"]
      by simp

    lemma coherent_Runit'_Ide:
    assumes "Ide a"
    shows "coherent 𝗋-1[a]"
      using assms Ide_implies_Can coherent_Runit_Ide
            coherent_iff_coherent_Inv [of "Runit a"]
      by simp

    lemma red2_Nml_Src:
    assumes "Ide t" and "Nml t"
    shows "t  Src t = 𝗋[t]"
      using assms eval_red2_Nml_Prim0 is_Prim0_Src [of t]
      by (cases "Src t"; simp)

    lemma red2_Trg_Nml:
    assumes "Ide t" and "Nml t"
    shows "Trg t  t = 𝗅[t]"
      using assms is_Prim0_Trg [of t] 𝔩_ide_simp ide_eval_Ide
      by (cases "Trg t"; simp)

    lemma coherence_key_fact:
    assumes "Ide a  Nml a" and "Ide b  Nml b" and "Ide c  Nml c"
    and "Src a = Trg b" and "Src b = Trg c"
    shows "(a  b)  c  (a  b  c) =
           (a  (b  c)  (a  b  c))  𝖺[a, b, c]"
    proof -
      have "is_Prim0 b  ?thesis"
      proof -
        assume b: "is_Prim0 b"
        have "a  c  (𝗋[a]  c) = (a  c  (a  𝗅[c]))  𝖺[a, Trg c, c]"
        proof -
          have "Src b = Trg b"
            using b by (cases b; simp)
          thus ?thesis
            using assms triangle [of "c" "a"] ide_eval_Ide comp_assoc
            by (simp add: eval_simps')
        qed
        thus ?thesis
          using assms b HcompNml_Nml_Src [of a] HcompNml_Trg_Nml red2_Nml_Src [of a]
                red2_Trg_Nml
          by (cases b, simp_all)
      qed
      moreover have " ¬ is_Prim0 b; is_Prim0 c   ?thesis"
      proof -
        assume b: "¬ is_Prim0 b"
        assume c: "is_Prim0 c"
        have "(a  b)  c  (a  b  c) = (a  b)  Src b  (a  b  src b)"
          using assms b c by (cases c, simp_all add: eval_simps')
        also have "... = 𝗋[a  b]  (a  b  src b)"
          using assms red2_Nml_Src [of "a  b"] Nml_HcompNml(1) Src_HcompNml Ide_HcompNml
          by simp
        also have "... = a  b  𝗋[a  b]"
        proof -
          have "«a  b : a  b  a  b»"
            using assms red2_in_Hom eval_in_hom [of "a  b"] by simp
          thus ?thesis
            using assms runit_naturality [of "a  b"] arr_dom in_homE src_dom src_hcomp
                  hcomp_simps(1)
            by (elim in_homE, metis)
        qed
        also have "... = (a  (b  c)  (a  b  c))  𝖺[a, b, c]"
        proof -
          have "(a  (b  c)  (a  b  c))  𝖺[a, b, c] =
                             (a  b  (a  𝗋[b]))  𝖺[a, b, src b]"
            using assms c red2_Nml_Src [of b]
            by (cases c, simp_all add: eval_simps')
          thus ?thesis
            using assms runit_hcomp ide_eval_Ide comp_assoc
            by (simp add: eval_simps')
        qed
        finally show ?thesis by blast
      qed
      moreover have " ¬ is_Prim0 b; ¬ is_Prim0 c   ?thesis"
      proof -
        assume b': "¬ is_Prim0 b"
        hence b: "Ide b  Nml b  Arr b  ¬ is_Prim0 b 
                  ide b  arr b  b = b  b = b  Dom b = b  Cod b = b"
          using assms Ide_Nmlize_Ide Ide_in_Hom ide_eval_Ide by simp
        assume c': "¬ is_Prim0 c"
        hence c: "Ide c  Nml c  Arr c  ¬ is_Prim0 c 
                  ide c  arr c  c = c  c = c  Dom c = c  Cod c = c"
          using assms Ide_Nmlize_Ide Ide_in_Hom ide_eval_Ide by simp
        have "a. Ide a  Nml a  Src a = Trg b 
                   (a  b)  c  (a  b  c)
                      = (a  (b  c)  (a  b  c))  𝖺[a, b, c]"
        proof -
          fix a :: "'c term"
          show "Ide a  Nml a  Src a = Trg b 
                (a  b)  c  (a  b  c)
                   = (a  (b  c)  (a  b  c))  𝖺[a, b, c]"
            apply (induct a)
            using b c HcompNml_in_Hom
                     apply (simp_all add: HcompNml_Nml_Src HcompNml_Trg_Nml)
          proof -
            fix f
            assume f: "C.ide f  C.arr f  srcC f0 = Trg b"
            show "(f  b)  c  (f  b  c) =
                    (f  b  c  (E f  b  c))  𝖺[E f, b, c]"
            proof -
              have "(f  b)  c  (f  b  c) =
                      ((E f  b  c)  (E f  b  c)  𝖺[E f, b, c]) 
                      ((E f  b)  c)"
              proof -
                have "((E f  b  c)  (E f  b  c)  𝖺[E f, b, c]) 
                      ((E f  b)  c) =
                      ((E f  b  c)  (E f  b  c)  𝖺[E f, b, c]) 
                      (f  b  c)"
                  using f b red2_Nml by simp
                also have "... = (f  b  c  (E f  b  c)  𝖺[E f, b, c]) 
                                 (f  b  c)"
                proof -
                  have "f  b  c = E f  b  c"
                    using assms(5) b c is_Hcomp_HcompNml red2_Nml Nml_HcompNml(1)
                          is_Hcomp_def
                    by (metis eval.simps(2) eval.simps(3) red2.simps(4))
                  thus ?thesis by argo
                qed
                also have "... = (f  b)  c  (f  b  c)"
                  using b c α_def by (cases c, simp_all)
                finally show ?thesis by argo
              qed
              also have "... = ((E f  b  c)  (E f  b  c))  𝖺[E f, b, c]"
              proof -
                have "src (E f) = trg b"
                  using b f preserves_src
                  by (cases "Trg b", auto simp add: eval_simps')
                thus ?thesis
                  using assms b c f comp_arr_dom comp_assoc
                  by (auto simp add: eval_simps')
              qed
              also have "... = (f  (b  c)  (E f  b  c))  𝖺[E f, b, c]"
                using assms f b c Ide_HcompNml Nml_HcompNml is_Hcomp_HcompNml [of b c] α_def
                by (cases "b  c") simp_all
              finally show ?thesis by blast
            qed
            next
            fix x
            assume x: "C.obj x  x0 = Trg b"
            show "b  c  (Trg b  b  c) =
                  (Trg b  b  c  (Trg b  b  c))  𝖺[Trg b, b, c]"
            proof -
              have 1: "Trg (b  c) = Trg b"
                using assms b c Trg_HcompNml by blast
              have 2: "Trg b  b  c = 𝗅[b  c]"
                using assms b c 1 Nml_HcompNml red2_Trg_Nml [of "b  c"] Ide_HcompNml
                by simp
              have "b  c  (Trg b  b  c) = b  c  (𝗅[b]  c)"
                using b c 1 2 HcompNml_Trg_Nml red2_Trg_Nml Trg_HcompNml by simp
              also have "... = b  c  𝗅[b  c]  𝖺[Trg b, b, c]"
                using assms b c lunit_hcomp [of "b" "c"]
                by (metis (no_types, lifting) eval_simps'(3) eval_simps(2))
              also have "... = (b  c  𝗅[b  c])  𝖺[Trg b, b, c]"
                using comp_assoc by simp
              also have "... = (𝗅[b  c]  (Trg b  b  c))  𝖺[Trg b, b, c]"
                using assms b c lunit_naturality [of "b  c"] red2_in_Hom
                by (simp add: eval_simps')
              also have "... = (Trg b  b  c  (Trg b  b  c))  𝖺[Trg b, b, c]"
                using b c 1 2 HcompNml_Trg_Nml red2_Trg_Nml Trg_HcompNml comp_assoc
                by simp
              finally show ?thesis
                by blast
            qed
            next
            fix d e
            assume I: "Nml e  (e  b)  c  (e  b  c)
                                    = (e  b  c  (e  b  c))  𝖺[e, b, c]"
            assume de: "Ide d  Ide e  Src d = Trg e  Nml (d  e)  Src e = Trg b"
            show "((d  e)  b)  c  ((d  e)  b  c)
                    = ((d  e)  (b  c)  ((d  e)  b  c))  𝖺[d  e, b, c]"
            proof -
              let ?f = "un_Prim d"
              have "is_Prim d"
                using de Nml_HcompD
                by (metis term.disc(12))
              hence "d = ?f  C.ide ?f"
                using de by (cases d; simp)
              hence d: "Ide d  Arr d  Dom d = d  Cod d = d  Nml d 
                        d = ?f  C.ide ?f  ide d  arr d"
                using de ide_eval_Ide Nml_Nmlize(1) Ide_in_Hom Nml_HcompD [of d e]
                by simp
              have "Nml e  ¬ is_Prim0 e"
                using de Nml_HcompD by metis
              hence e: "Ide e  Arr e  Dom e = e  Cod e = e  Nml e 
                        ¬ is_Prim0 e  ide e  arr e"
                using de Ide_in_Hom ide_eval_Ide by simp
              have 1: "is_Hcomp (e  b)  is_Hcomp (b  c)  is_Hcomp (e  b  c)"
                using assms b c e de is_Hcomp_HcompNml [of e b] Nml_HcompNml
                      is_Hcomp_HcompNml [of b c] is_Hcomp_HcompNml [of e "b  c"]
                by auto
              have eb: "Src e = Trg b"
                using assms b c e de by argo
              have bc: "Src b = Trg c"
                using assms b c by simp
              have 4: "is_Hcomp ((e  b)  c)"
                using assms b c e eb de 1 is_Hcomp_HcompNml [of e b]
                      is_Hcomp_HcompNml [of "e  b" c] is_Hcomp_HcompNml [of e b]
                      Nml_HcompNml(1) [of e b] Src_HcompNml
                by auto
              have "((d  e)  b)  c  ((d  e)  b  c)
                      = ((d  (e  b)  c)  (d  (e  b)  c) 
                         𝖺[d, e  b, c]) 
                        ((d  e  b)  (d  e  b)  𝖺[d, e, b]  c)"
              proof -
                have "((d  e)  b)  c
                         = (d  (e  b)  c)  (d  (e  b)  c) 
                           𝖺[d, e  b, c]"
                proof -
                  have "((d  e)  b)  c = (d  (e  b))  c"
                    using b c d e de 1 HcompNml_Nml Nml_HcompNml HcompNml_assoc
                          HcompNml_Prim
                    by (metis term.distinct_disc(4))
                  also have "... = (d  ((e  b)  c))  (d  ((e  b)  c)) 
                                   𝖺[d, e  b, c]"
                    using b c d e de 1 Nml_HcompNml Nmlize_Nml
                    by (cases c) simp_all
                  also have "... = (d  ((e  b)  c))  (d  ((e  b)  c)) 
                                   𝖺[d, e  b, c]"
                    using d 4
                    apply (cases d, simp_all)
                    by (cases "(e  b)  c") simp_all
                  finally show ?thesis
                    using b c d e HcompNml_in_Hom red2_in_Hom
                          Nml_HcompNml Ide_HcompNml α_def
                    by simp
                qed
                moreover have "(d  e)  b
                                 = (d  e  b)  (d  e  b)  𝖺[d, e, b]"
                proof -
                  have "(d  e)  b = (d  (e  b))  (d  (e  b))  𝖺[d, e, b]"
                      using b c d e de 1 HcompNml_Prim Nmlize_Nml
                      by (cases b, simp_all)
                  also have "... = (d  (e  b))  (d  (e  b))  𝖺[d, e, b]"
                    using b c d e de 1 HcompNml_Nml Nml_HcompNml
                    apply (cases d, simp_all)
                    by (cases "e  b", simp_all)
                  finally show ?thesis
                    using b d e HcompNml_in_Hom red2_in_Hom α_def by simp
                qed
                ultimately show ?thesis by argo
              qed
              also have "... = ((d  (e  b)  c)  𝖺[d, e  b, c]) 
                               ((d  e  b)  c)  (𝖺[d, e, b]  c)"
              proof -
                have "(d  e  b)  (d  e  b)  𝖺[d, e, b]  c
                        = ((d  e  b)  c)  (𝖺[d, e, b]  c)"
                  using assms b c d e de eb HcompNml_in_Hom red2_in_Hom comp_cod_arr
                        Ide_HcompNml Nml_HcompNml comp_assoc
                        interchange [of "d  e  b" "𝖺[d, e, b]" "c" "c"]
                  by (auto simp add: eval_simps')
                moreover have "(d  (e  b)  c)  (d  (e  b)  c) 
                                 𝖺[d, e  b, c] =
                               (d  (e  b)  c)  𝖺[d, e  b, c]"
                proof -
                  have "(d  (e  b)  c)  (d  (e  b)  c) 
                                   𝖺[d, e  b, c] =
                                   ((d  (e  b)  c)  (d  (e  b)  c)) 
                                   𝖺[d, e  b, c]"
                    using comp_assoc by simp
                  thus ?thesis
                    using assms b c d e de eb HcompNml_in_Hom red2_in_Hom
                          Ide_HcompNml Nml_HcompNml comp_cod_arr
                    by (simp add: eval_simps')
                qed
                ultimately show ?thesis by argo
              qed
              also have "... = (d  (e  b)  c)  (d  (e  b  c)) 
                               𝖺[d, e  b, c]  (𝖺[d, e, b]  c)"
                using assms b c d e de HcompNml_in_Hom red2_in_Hom
                      Ide_HcompNml Nml_HcompNml ide_eval_Ide
                      assoc_naturality [of "d" "e  b" "c"]
                      comp_permute [of "𝖺[d, e  b, c]" "(d  e  b)  c"
                                       "d  (e  b  c)" "𝖺[d, e  b, c]"]
                      comp_assoc
                by (simp add: eval_simps')
              also have "... = ((d  (e  b)  c)  (d  (e  b  c))) 
                               𝖺[d, e  b, c]  (𝖺[d, e, b]  c)"
                using comp_assoc by simp
              also have "... = (((d  e  (b  c))  (d  e  b  c)) 
                                (d  𝖺[e, b, c])) 
                               𝖺[d, e  b, c]  (𝖺[d, e, b]  c)"
                using assms b c d e de eb I HcompNml_in_Hom red2_in_Hom
                      Ide_HcompNml Nml_HcompNml whisker_left [of "d"]
                      interchange [of "d" "d" "(e  b)  c" "e  b  c"]
                by (auto simp add: eval_simps')
              also have "... = ((d  e  (b  c))  (d  e  b  c)) 
                               ((d  𝖺[e, b, c]) 
                                𝖺[d, e  b, c]  (𝖺[d, e, b]  c))"
                using comp_assoc by simp
              also have "... = ((d  e  (b  c))  (d  (e  b  c))) 
                               𝖺[d, e, b  c]  𝖺[d  e, b, c]"
                using assms b c d e de pentagon
                by (simp add: eval_simps')
              also have "... = (d  e  (b  c)) 
                               ((d  (e  b  c))  𝖺[d, e, b  c]) 
                               𝖺[d  e, b, c]"
                using comp_assoc by simp
              also have "... = ((d  e  b  c)  (d  e  b  c)) 
                               (𝖺[d, e, b  c]  ((d  e)  b  c)) 
                               𝖺[d  e, b, c]"
                using assms d e de HcompNml_in_Hom red2_in_Hom Ide_HcompNml Nml_HcompNml
                      assoc_naturality [of "d" "e" "b  c"] comp_cod_arr [of "d  e  b  c"]
                by (simp add: eval_simps')
              also have "... = ((d  e  b  c)  (d  e  b  c) 
                                𝖺[d, e, b  c]) 
                               ((d  e)  b  c)  𝖺[d  e, b, c]"
                using comp_assoc by simp
              also have "... = (d  e)  (b  c)  ((d  e)  b  c) 
                               𝖺[d  e, b, c]"
              proof -
                have "(d  e)  (b  c)
                         = (d  e  (b  c))  (d  e  (b  c)) 
                           𝖺[d, e, b  c]"
                proof -
                  have "(d  e)  (b  c)
                          = (d  (e  b  c))  (d  (e  (b  c)))  𝖺[d, e, b  c]"
                    using e 1 by (cases "b  c") auto
                  also have "... = (d  (e  (b  c)))  (d  (e  (b  c))) 
                                   𝖺[d, e, b  c]"
                    using assms Nml_HcompNml Nmlize_Nml by simp
                  also have "... = (d  (e  (b  c)))  (d  (e  (b  c))) 
                                   𝖺[d, e, b  c]"
                    using d 1
                    apply (cases "e  b  c", simp_all)
                    by (cases d, simp_all)
                  finally show ?thesis
                    using α_def by simp
                qed
                thus ?thesis by simp
              qed
              also have "... = ((d  e)  (b  c)  ((d  e)  b  c)) 
                               𝖺[d  e, b, c]"
                 using comp_assoc by simp
              finally show ?thesis by auto
            qed
          qed
        qed
        thus ?thesis using assms(1,4) by blast
      qed
      ultimately show ?thesis by blast
    qed

    lemma coherent_Assoc_Ide:
    assumes "Ide a" and "Ide b" and "Ide c" and "Src a = Trg b" and "Src b = Trg c"
    shows "coherent 𝖺[a, b, c]"
    proof -
      have a: "Ide a  Arr a  Dom a = a  Cod a = a 
               ide a  ide a  a  hom a a"
        using assms Ide_in_Hom Ide_Nmlize_Ide ide_eval_Ide red_in_Hom eval_in_hom(2)
        by force
      have b: "Ide b  Arr b  Dom b = b  Cod b = b 
               ide b  ide b  b  hom b b"
        using assms Ide_in_Hom Ide_Nmlize_Ide ide_eval_Ide red_in_Hom(2)
              eval_in_hom(2) [of "b"]
        by auto
      have c: "Ide c  Arr c  Dom c = c  Cod c = c 
               ide c  ide c  c  hom c c"
        using assms Ide_in_Hom Ide_Nmlize_Ide red_in_Hom eval_in_hom(2) [of "c"]
              ide_eval_Ide
        by auto
      have "Cod 𝖺[a, b, c]  𝖺[a, b, c]
              = (a  (b  c)  (a  b  c)  (a  b  c)) 
                𝖺[a, b, c]"
        using assms a b c red_in_Hom red2_in_Hom Nml_Nmlize Ide_Nmlize_Ide
              α_def eval_red_Hcomp interchange [of "a" "a"] comp_cod_arr [of "a"]
        by (simp add: eval_simps')
      also have "... = ((a  (b  c)  (a  b  c))  𝖺[a, b, c]) 
                       ((a  b)  c)"
        using assms red_in_Hom Ide_HcompNml assoc_naturality [of "a" "b" "c"] comp_assoc
        by (simp add: eval_simps')
      also have "... = ((a  b)  c  (a  b  c))  ((a  b)  c)"
        using assms Nml_Nmlize Ide_Nmlize_Ide coherence_key_fact by simp
      also have "... = 𝖺[a, b, c]  Dom 𝖺[a, b, c]"
        using assms a b c red_in_Hom red2_in_Hom Ide_Nmlize_Ide
              Nml_Nmlize eval_red_Hcomp HcompNml_assoc
              interchange [of "a  b" "a  b" "c" "c"]
              comp_cod_arr [of "c" "c"]
        apply (simp add: eval_simps')
      proof -
        have "seq (a  b)  c ((a  b  c)  ((a  b)  c))"
          using assms c red_in_Hom red2_in_Hom Nml_HcompNml Ide_Nmlize_Ide Ide_HcompNml
                Nml_Nmlize
          by (simp_all add: eval_simps')
        moreover have
            "cod ((a  b)  c  (a  b  c)  ((a  b)  c)) =
             a  b  c"
          using assms c red_in_Hom red2_in_Hom Nml_HcompNml Ide_Nmlize_Ide Ide_HcompNml
                Nml_Nmlize HcompNml_assoc
          by (simp add: eval_simps')
        ultimately
        show "((a  b)  c  (a  b  c))  ((a  b)  c) =
              a  b  c 
                (a  b)  c  (a  b  c)  ((a  b)  c)"
         using comp_cod_arr comp_assoc by simp
       qed
       finally show ?thesis by blast
    qed

    lemma coherent_Assoc'_Ide:
    assumes "Ide a" and "Ide b" and "Ide c" and "Src a = Trg b" and "Src b = Trg c"
    shows "coherent 𝖺-1[a, b, c]"
        using assms Ide_implies_Can coherent_Assoc_Ide Inv_Ide coherent_iff_coherent_Inv
              Can.simps(10) Inv.simps(10)
        by presburger

    lemma eval_red2_naturality:
    assumes "Nml t" and "Nml u" and "Src t = Trg u"
    shows "Cod t  Cod u  (t  u) = t  u  Dom t  Dom u"
    proof -
      have *: "t u. Nml (t  u)  arr t  arr u"
        using Nml_implies_Arr Nml_HcompD
        by (metis eval_simps'(1))
      have "is_Prim0 t  ?thesis"
        using assms Nml_implies_Arr is_Prim0_Trg 𝔩.naturality [of "u"]
        by (cases t) (simp_all add: eval_simps', cases "Trg t", simp_all)
      moreover have "¬ is_Prim0 t  is_Prim0 u  ?thesis"
        using assms Nml_implies_Arr eval_red2_Nml_Prim0 runit_naturality [of "t"]
        by (cases u) (simp_all add: eval_simps')
      moreover have "¬ is_Prim0 t  ¬ is_Prim0 u  ?thesis"
        using assms * Nml_implies_Arr
        apply (induct t, simp_all)
      proof -
        fix f
        assume f: "C.arr f"
        assume "¬ is_Prim0 u"
        hence u: "¬ is_Prim0 u 
                  Nml u  Nml (Dom u)  Nml (Cod u)  Ide (Dom u)  Ide (Cod u) 
                  arr u  arr Dom u  arr Cod u  ide Dom u  ide Cod u"
          using assms(2) Nml_implies_Arr ide_eval_Ide by simp
        hence 1: "¬ is_Prim0 (Dom u)  ¬ is_Prim0 (Cod u)"
          using u by (cases u) simp_all
        assume "srcC f0 = Trg u"
        hence "srcC f0 = Trg u" by simp
        hence fu: "src (E f) = trg u"
          using f u preserves_src Nml_implies_Arr
          by (simp add: eval_simps')
        show "C.cod f  Cod u  (E f  u) = (E f  u)  C.dom f  Dom u"
        proof -
          have "C.cod f  Cod u = E (C.cod f)  cod u"
            using f u 1 Nml_implies_Arr
            by (cases "Cod u", simp_all add: eval_simps')
          moreover have "C.dom f  Dom u = E (C.dom f)  dom u"
            using f u 1 Nml_implies_Arr
            by (cases "Dom u", simp_all add: eval_simps')
          moreover have "«E f  u : E (C.dom f)  Dom u  E (C.cod f)  Cod u»"
            using f u fu Nml_implies_Arr
            apply (intro hcomp_in_vhom)
              apply auto
            by (metis C.src_dom eval_simps(4) preserves_src trg_dom u)
          ultimately show ?thesis
            using f u comp_arr_dom comp_cod_arr
            by (simp add: fu)
        qed
        next
        fix v w
        assume I2: " ¬ is_Prim0 w; Nml w  
                      Cod w  Cod u  (w  u) = w  u  Dom w  Dom u"
        assume "¬ is_Prim0 u"
        hence u: "¬ is_Prim0 u  Arr u  Arr (Dom u)  Arr (Cod u) 
                  Nml u  Nml (Dom u)  Nml (Cod u)  Ide (Dom u)  Ide (Cod u) 
                  arr u  arr Dom u  arr Cod u  ide Dom u  ide Cod u"
          using assms(2) Nml_implies_Arr ide_eval_Ide by simp
        assume vw: "Nml (v  w)"
        assume wu: "Src w = Trg u"
        let ?f = "un_Prim v"
        have "v = ?f  C.arr ?f"
          using vw by (metis Nml_HcompD(1) Nml_HcompD(2))
        hence "Arr v  v = un_Prim v  C.arr ?f  Nml v" by (cases v; simp)
        hence v: "v = ?f  C.arr ?f  Arr v  Arr (Dom v)  Arr (Cod v)  Nml v 
                  Nml (Dom v)  Nml (Cod v) 
                  arr v  arr Dom v  arr Cod v  ide Dom v  ide Cod v"
          using vw * by (cases v, simp_all)
        have "Nml w  ¬ is_Prim0 w"
          using vw v by (metis Nml.simps(3))
        hence w: "¬ is_Prim0 w  Arr w  Arr (Dom w)  Arr (Cod w) 
                  Nml w  Nml (Dom w)  Nml (Cod w) 
                  Ide (Dom w)  Ide (Cod w) 
                  arr w  arr Dom w  arr Cod w  ide Dom w  ide Cod w"
          using vw * Nml_implies_Arr ide_eval_Ide by simp
        have u': "¬ is_Prim0 (Dom u)  ¬ is_Prim0 (Cod u)"
          using u by (cases u, simp_all)
        have w':  "¬ is_Prim0 (Dom w)  ¬ is_Prim0 (Cod w)"
          using w by (cases w, simp_all)
        have vw': "Src v = Trg w"
          using vw Nml_HcompD(7) by simp
        have X: "Nml (Dom v  (Dom w  Dom u))"
          using u u' v w w' wu vw is_Hcomp_HcompNml Nml_HcompNml Nml_Dom
          by (metis Dom.simps(3) Nml.simps(3) term.distinct_disc(3))
        have Y: "Nml (Cod v  (Cod w  Cod u))"
          using u u' w w' wu vw is_Hcomp_HcompNml Nml_HcompNml Src_Cod Trg_Cod
          by (metis Cod.simps(3) Nml.simps(3) Nml_Cod term.distinct_disc(3) v)
        show "(Cod v  Cod w)  Cod u  ((v  w)  u)
                = (v  w)  u  (Dom v  Dom w)  Dom u"
        proof -
          have "(Cod v  Cod w)  Cod u  ((v  w)  u)
                  = (Cod v  (Cod w  Cod u)  (Cod v  Cod w  Cod u) 
                    𝖺[Cod v, Cod w, Cod u])  ((v  w)  u)"
          proof -
            have "(Cod v  Cod w)  Cod u
                    = (Cod v  (Cod w  Cod u))  (Cod v  Cod w  Cod u) 
                      𝖺[Cod v, Cod w, Cod u]"
              using u v w by (cases u) simp_all
            hence "(Cod v  Cod w)  Cod u
                     = Cod v  (Cod w  Cod u)  (Cod v  Cod w  Cod u) 
                       𝖺[Cod v, Cod w, Cod u]"
              using u v w α_def by simp
            thus ?thesis by presburger
          qed
          also have "... = ((Cod v  Cod w  Cod u)  (Cod v  Cod w  Cod u) 
                            𝖺[Cod v, Cod w, Cod u])  ((v  w)  u)"
            using u v w Y red2_Nml by simp
          also have "... = ((Cod v  Cod w  Cod u)  𝖺[Cod v, Cod w, Cod u]) 
                           ((v  w)  u)"
            using u v w vw' wu comp_cod_arr red2_in_Hom HcompNml_in_Hom comp_reduce
           by (simp add: eval_simps')
          also have "... = (Cod v  Cod w  Cod u)  𝖺[Cod v, Cod w, Cod u] 
                           ((v  w)  u)"
            using comp_assoc by simp
          also have "... = (Cod v  Cod w  Cod u)  (v  w  u) 
                           𝖺[Dom v, Dom w, Dom u]"
            using u v w vw' wu assoc_naturality [of "v" "w" "u"]
            by (simp add: eval_simps')
          also have "... = ((Cod v  Cod w  Cod u)  (v  w  u)) 
                           𝖺[Dom v, Dom w, Dom u]"
            using comp_assoc by simp
          also have
            "... = (v  w  u  Dom w  Dom u)  𝖺[Dom v, Dom w, Dom u]"
            using v w u vw' wu I2 red2_in_Hom HcompNml_in_Hom comp_cod_arr
                  interchange [of "Cod v" "v" "Cod w  Cod u" "w  u"]
            by (simp add: eval_simps')
          also have "... = ((v  w  u)  (Dom v  Dom w  Dom u)) 
                           𝖺[Dom v, Dom w, Dom u]"
            using v w u vw' wu red2_in_Hom HcompNml_in_Hom comp_arr_dom
                  interchange [of "v" "Dom v" "w  u" "Dom w  Dom u"]
            by (simp add: eval_simps')
          also have "... = (v  w  u)  (Dom v  Dom w  Dom u) 
                           𝖺[Dom v, Dom w, Dom u]"
            using comp_assoc by simp
          also have "... = v  w  u  (Dom v  Dom w  Dom u) 
                           𝖺[Dom v, Dom w, Dom u]"
            using u u' v w vw' wu is_Hcomp_HcompNml HcompNml_Prim [of "w  u" ?f]
            by force
          also have "... = v  w  u  Dom v  Dom w  Dom u 
                          (Dom v  Dom w  Dom u)  𝖺[Dom v, Dom w, Dom u]"
          proof -
            have "v  w  u  (Dom v  Dom w  Dom u) 
                    𝖺[Dom v, Dom w, Dom u] =
                  (v  w  u  Dom v  Dom w  Dom u) 
                    (Dom v  Dom w  Dom u)  𝖺[Dom v, Dom w, Dom u]"
              using u v w vw' wu comp_arr_dom Nml_HcompNml HcompNml_in_Hom
              by (simp add: eval_simps')
            also have "... = v  w  u  Dom v  Dom w  Dom u 
                               (Dom v  Dom w  Dom u)  𝖺[Dom v, Dom w, Dom u]"
              using comp_assoc by simp
            finally show ?thesis by blast
          qed
          also have "... = (v  w)  u  (Dom v  Dom w)  Dom u"
          proof -
            have "(Dom v  Dom w)  Dom u
                     = (Dom v  (Dom w  Dom u))  (Dom v  (Dom w  Dom u)) 
                       𝖺[Dom v, Dom w, Dom u]"
              using u u' v w vw' wu by (cases u, simp_all)
            hence
              "(Dom v  Dom w)  Dom u
                     = Dom v  (Dom w  Dom u)  (Dom v  Dom w  Dom u) 
                       𝖺[Dom v, Dom w, Dom u]"
              using u v w α_def by simp
            also have
              "... = Dom v  Dom w  Dom u  (Dom v  Dom w  Dom u) 
                             𝖺[Dom v, Dom w, Dom u]"
              using X HcompNml_Nml red2_Nml by presburger
            finally have
              "(Dom v  Dom w)  Dom u
                   = Dom v  Dom w  Dom u  (Dom v  Dom w  Dom u) 
                     𝖺[Dom v, Dom w, Dom u]"
              by blast
            thus ?thesis
              using assms v w vw' wu HcompNml_assoc by presburger
          qed
          finally show ?thesis
            using vw HcompNml_Nml by simp
        qed
      qed
      ultimately show ?thesis by blast
    qed

    lemma coherent_Hcomp:
    assumes "Arr t" and "Arr u" and "Src t = Trg u" and "coherent t" and "coherent u"
    shows "coherent (t  u)"
    proof -
      have t: "Arr t  Ide (Dom t)  Ide (Cod t)  Ide Dom t  Ide Cod t 
               arr t  arr Dom t  ide Dom t  arr Cod t  ide Cod t"
        using assms Ide_Nmlize_Ide ide_eval_Ide by auto
      have u: "Arr u  Ide (Dom u)  Ide (Cod u)  Ide Dom u  Ide Cod u 
               arr u  arr Dom u  ide Dom u  arr Cod u  ide Cod u"
        using assms Ide_Nmlize_Ide ide_eval_Ide by auto
      have "Cod (t  u)  (t  u)
              = (Cod t  Cod u  (Cod t  Cod u))  (t  u)"
        using t u eval_red_Hcomp by simp
      also have "... = Cod t  Cod u  (Cod t  Cod u)  (t  u)"
        using comp_assoc by simp
      also have "... = Cod t  Cod u  (t  u)  (Dom t  Dom u)"
        using assms t u Nmlize_in_Hom red_in_Hom
              interchange [of "Cod t" "t" "Cod u" "u"]
              interchange [of "t" "Dom t" "u" "Dom u"]
        by (simp add: eval_simps')
      also have "... = (Cod t  Cod u  (t  u))  (Dom t  Dom u)"
        using comp_assoc by simp
      also have "... = (t  u  Dom t  Dom u)  (Dom t  Dom u)"
        using assms t u Nml_Nmlize Nmlize_in_Hom
              eval_red2_naturality [of "Nmlize t" "Nmlize u"]
        by simp
      also have "... = t  u  Dom t  Dom u  (Dom t  Dom u)"
        using comp_assoc by simp
      also have "... = t  u  (Dom t  Dom u)"
        using t u eval_red_Hcomp by simp
      finally have "Cod (t  u)  (t  u) = t  u  (Dom t  Dom u)"
        by blast
      thus ?thesis using t u by simp
    qed

    lemma coherent_Vcomp:
    assumes "Arr t" and "Arr u" and "Dom t = Cod u"
    and "coherent t" and "coherent u"
    shows "coherent (t  u)"
    proof -
      have t: "Arr t  Ide (Dom t)  Ide (Cod t)  Ide Dom t  Ide Cod t 
               arr t  arr Dom t  ide Dom t  arr Cod t  ide Cod t"
        using assms Ide_Nmlize_Ide ide_eval_Ide by auto
      have u: "Arr u  Ide (Dom u)  Ide (Cod u)  Ide Dom u  Ide Cod u 
               arr u  arr Dom u  ide Dom u  arr Cod u  ide Cod u"
        using assms Ide_Nmlize_Ide ide_eval_Ide by auto
      have "Cod (t  u)  t  u = Cod t  t  u"
        using t u by simp
      also have "... = (Cod t  t)  u"
      proof -
        have "seq Cod t t"
          using assms t red_in_Hom
          by (intro seqI, auto simp add: eval_simps')
        moreover have "seq t u"
          using assms t u by (auto simp add: eval_simps')
        ultimately show ?thesis
          using comp_assoc by auto
      qed
      also have "... = t  u  Dom (t  u)"
        using t u assms red_in_Hom Nml_Nmlize comp_assoc
        by (simp add: eval_simps' Nml_implies_Arr eval_VcompNml)
      finally show "coherent (t  u)" by blast
    qed

    text ‹
      The main result: ``Every formal arrow is coherent.''
    ›

    theorem coherence:
    assumes "Arr t"
    shows "coherent t"
    proof -
      have "Arr t  coherent t"
      proof (induct t)
        show "a. Arr a0  coherent a0" by simp
        show "μ. Arr μ  coherent μ" by simp
        fix u v
        show " Arr u  coherent u; Arr v  coherent v   Arr (u  v)
                   coherent (u  v)"
          using coherent_Hcomp by simp
        show " Arr u  coherent u; Arr v  coherent v   Arr (u  v)
                   coherent (u  v)"
          using coherent_Vcomp by simp
        next
        fix t
        assume I: "Arr t  coherent t"
        show Lunit: "Arr 𝗅[t]  coherent 𝗅[t]"
          using I Ide_Dom coherent_Lunit_Ide Ide_in_Hom
                coherent_Vcomp [of t "𝗅[Dom t]"] Nmlize_Vcomp_Arr_Dom
                eval_in_hom 𝔩.is_natural_1 [of "t"]
          by force
        show Runit: "Arr 𝗋[t]  coherent 𝗋[t]"
          using I Ide_Dom coherent_Runit_Ide Ide_in_Hom ide_eval_Ide
                coherent_Vcomp [of t "𝗋[Dom t]"] Nmlize_Vcomp_Arr_Dom 𝔯_ide_simp
                eval_in_hom 𝔯.is_natural_1 [of "t"]
          by force
        show "Arr 𝗅-1[t]  coherent 𝗅-1[t]"
        proof -
          assume "Arr 𝗅-1[t]"
          hence t: "Arr t" by simp
          have "coherent (𝗅-1[Cod t]  t)"
            using t I Ide_Cod coherent_Lunit'_Ide Ide_in_Hom coherent_Vcomp [of "𝗅-1[Cod t]" t]
                  Arr.simps(6) Dom.simps(6) Dom_Cod Ide_implies_Arr
            by presburger
          moreover have "𝗅-1[t] = 𝗅-1[Cod t]  t"
            using t 𝔩'.is_natural_2 [of "t"]
            by (simp add: eval_simps(5))
          ultimately show ?thesis
            using t Nmlize_Vcomp_Cod_Arr by simp
        qed
        show "Arr 𝗋-1[t]  coherent 𝗋-1[t]"
        proof -
          assume "Arr 𝗋-1[t]"
          hence t: "Arr t" by simp
          have "coherent (𝗋-1[Cod t]  t)"
            using t I Ide_Cod coherent_Runit'_Ide Ide_in_Hom coherent_Vcomp [of "𝗋-1[Cod t]" t]
                  Arr.simps(8) Dom.simps(8) Dom_Cod Ide_implies_Arr
            by presburger
          moreover have "𝗋-1[t] = 𝗋-1[Cod t]  t"
            using t 𝔯'.is_natural_2 [of "t"]
            by (simp add: eval_simps(5))
          ultimately show ?thesis
            using t Nmlize_Vcomp_Cod_Arr by simp
        qed
        next
        fix t u v
        assume I1: "Arr t  coherent t"
        assume I2: "Arr u  coherent u"
        assume I3: "Arr v  coherent v"
        show "Arr 𝖺[t, u, v]  coherent 𝖺[t, u, v]"
        proof -
          assume tuv: "Arr 𝖺[t, u, v]"
          have t: "Arr t" using tuv by simp
          have u: "Arr u" using tuv by simp
          have v: "Arr v" using tuv by simp
          have tu: "Src t = Trg u" using tuv by simp
          have uv: "Src u = Trg v" using tuv by simp
          have "coherent ((t  u  v)  𝖺[Dom t, Dom u, Dom v])"
          proof -
            have "Arr (t  u  v)  coherent (t  u  v)"
              using t u v tu uv tuv I1 I2 I3 coherent_Hcomp Arr.simps(3) Trg.simps(3)
              by presburger
            moreover have "Arr 𝖺[Dom t, Dom u, Dom v]"
              using t u v tu uv Ide_Dom by simp
            moreover have "coherent 𝖺[Dom t, Dom u, Dom v]"
              using t u v tu uv Src_Dom Trg_Dom Ide_Dom coherent_Assoc_Ide by metis
            moreover have "Dom (t  u  v) = Cod 𝖺[Dom t, Dom u, Dom v]"
              using t u v by simp
            ultimately show ?thesis
              using t u v coherent_Vcomp by blast
          qed
          moreover have "VPar 𝖺[t, u, v] ((t  u  v)  𝖺[Dom t, Dom u, Dom v])"
            using t u v tu uv Ide_Dom by simp
          moreover have "𝖺[t, u, v] = (t  u   v)  𝖺[Dom t, Dom u, Dom v]"
          proof -
            have "(t  u)  v
                     = (t  u  v)  ((Dom t  Dom u)  Dom v)"
            proof -
              have 1: "Nml t  Nml u  Nml v 
                       Dom t = Dom t  Dom u = Dom u  Dom v = Dom v"
                using t u v Nml_Nmlize by blast
              moreover have "Nml (t  u)"
                using 1 t u tu Nmlize_Src Nmlize_Trg Nml_HcompNml(1)
                by presburger
              moreover have "t. Arr t  t  Dom t = t"
                using t Nmlize_Vcomp_Arr_Dom by simp
              moreover have "Dom 𝖺[t, u, v] = Dom 𝖺[t, u, v]"
                using Nml_Nmlize tuv by blast
              ultimately show ?thesis
                using t u v tu uv tuv 1 HcompNml_assoc Nml_HcompNml
                      Nml_Nmlize VcompNml_Nml_Dom [of "(t  u)  v"]
                by auto
            qed
            thus ?thesis
              using t u v Nmlize_Vcomp_Arr_Dom VcompNml_HcompNml Nml_Nmlize
              by simp
          qed
          moreover have "𝖺[t, u, v] = (t  u  v)  𝖺[Dom t, Dom u, Dom v]"
            using t u v tu uv Ide_Dom comp_cod_arr ide_eval_Ide α_def
            apply (simp add: eval_simps')
            using assoc_is_natural_1 arr_eval_Arr eval_simps'(2-4) by presburger
          ultimately show "coherent 𝖺[t, u, v]" by argo
        qed
        show "Arr 𝖺-1[t, u, v]  coherent 𝖺-1[t, u, v]"
        proof -
          assume tuv: "Arr 𝖺-1[t, u, v]"
          have t: "Arr t" using tuv by simp
          have u: "Arr u" using tuv by simp
          have v: "Arr v" using tuv by simp
          have tu: "Src t = Trg u" using tuv by simp
          have uv: "Src u = Trg v" using tuv by simp
          have "coherent (((t  u)  v)  𝖺-1[Dom t, Dom u, Dom v])"
          proof -
            have "Arr ((t  u)  v)  coherent ((t  u)  v)"
              using t u v tu uv tuv I1 I2 I3 coherent_Hcomp Arr.simps(3) Src.simps(3)
              by presburger
            moreover have "Arr 𝖺-1[Dom t, Dom u, Dom v]"
              using t u v tu uv Ide_Dom by simp
            moreover have "coherent 𝖺-1[Dom t, Dom u, Dom v]"
              using t u v tu uv Src_Dom Trg_Dom Ide_Dom coherent_Assoc'_Ide
              by metis
            moreover have "Dom ((t  u)  v) = Cod 𝖺-1[Dom t, Dom u, Dom v]"
              using t u v by simp
            ultimately show ?thesis
              using t u v coherent_Vcomp by metis
          qed
          moreover have "VPar 𝖺-1[t, u, v] (((t  u)  v)  𝖺-1[Dom t, Dom u, Dom v])"
            using t u v tu uv Ide_Dom by simp
          moreover have "𝖺-1[t, u, v] = ((t  u)  v)  𝖺-1[Dom t, Dom u, Dom v]"
            using t u v tu uv Nmlize_Vcomp_Arr_Dom VcompNml_HcompNml Nml_Nmlize
                  HcompNml_assoc Nml_HcompNml HcompNml_in_Hom
                  VcompNml_Nml_Dom [of "(t  u)  v"]
            using Nmlize.simps(3-4,10) by presburger
          moreover have "𝖺-1[t, u, v] = ((t  u)  v)  𝖺-1[Dom t, Dom u, Dom v]"
          proof -
            have 1: "VVV.arr (t, u, v)"
              using tuv α'.preserves_reflects_arr arr_eval_Arr eval.simps(10)
              by (metis (no_types, lifting))
            have "𝖺-1[t, u, v] = ((t  u)  v)  𝖺-1[dom t, dom u, dom v]"
            proof -
              have "VVV.arr (t, u, v)"
                using tuv α'.preserves_reflects_arr arr_eval_Arr eval.simps(10)
                by (metis (no_types, lifting))
              thus ?thesis
                using t u v α'.is_natural_1 [of "(t, u, v)"] HoHV_def 𝖺'_def
                      VVV.dom_simp
                by simp
            qed
            also have "... = ((t  u)  v)  𝖺-1[Dom t, Dom u, Dom v]"
              by (simp add: eval_simps'(4) t u v 𝖺'_def)
            finally show ?thesis by blast
          qed
          ultimately show "coherent 𝖺-1[t, u, v]" by argo
        qed
      qed
      thus ?thesis using assms by blast
    qed

    corollary eval_eqI:
    assumes "VPar t u" and "t = u"
    shows "t = u"
      using assms coherence canonical_factorization by simp

    text ‹
      The following allows us to prove that two 1-cells in a bicategory are isomorphic
      simply by expressing them as the evaluations of terms having the same normalization.
      The benefits are: (1) we do not have to explicitly exhibit the isomorphism,
      which is canonical and is obtained by evaluating the reductions of the terms
      to their normalizations, and (2) the normalizations can be computed automatically
      by the simplifier.
    ›

    lemma canonically_isomorphicI:
    assumes "f = t" and "g = u" and "Ide t" and "Ide u" and "t = u"
    shows "f  g"
    proof -
      have "f  t"
        using assms isomorphic_reflexive ide_eval_Ide by blast
      also have "...  t"
      proof -
        have "«t : t  t»  iso t"
          using assms(1,3) Can_red iso_eval_Can red_in_Hom(2) eval_in_hom(2) by fastforce
        thus ?thesis
          using isomorphic_def by blast
      qed
      also have "...  u"
        using assms isomorphic_reflexive
        by (simp add: Ide_Nmlize_Ide ide_eval_Ide)
      also have "...  u"
      proof -
        have "«u : u  u»  iso u"
          using assms(2,4) Can_red iso_eval_Can red_in_Hom(2) eval_in_hom(2) by fastforce
        thus ?thesis
          using isomorphic_def isomorphic_symmetric by blast
      qed
      also have "...  g"
        using assms isomorphic_reflexive ide_eval_Ide by blast
      finally show ?thesis by simp
    qed

  end

end