Theory Globular_Set

theory Globular_Set
  
imports "HOL-Library.FuncSet"

begin

section ‹Background material on extensional functions›

lemma PiE_imp_Pi: "f ∈ A →E B ⟹ f ∈ A → B" by fast

lemma PiE_iff': "f ∈ A →E B = (f ∈ A → B ∧ f ∈ extensional A)"
  by (simp add: PiE_iff Pi_iff)

abbreviation composing (‹_ ∘ _ ↓ _› [60,0,60]59)
  where "g ∘ f ↓ D ≡ compose D g f"

lemma compose_PiE: "f ∈ A → B ⟹ g ∈ B → C ⟹ g ∘ f ↓ A ∈ A →E C"
  by (metis funcset_compose compose_extensional PiE_iff')

lemma compose_eq_iff: "(g ∘ f ↓ A = k ∘ h ↓ A) = (∀x ∈ A. g (f x) = k (h x))"
proof (safe)
  fix x assume "g ∘ f ↓ A = k ∘ h ↓ A" "x ∈ A"
  then show "g (f x) = k (h x)" by (metis compose_eq)
next
  assume "∀x ∈ A. g (f x) = k (h x)"
  hence "⋀x. x ∈ A ⟹ (g ∘ f ↓ A) x = (k ∘ h ↓ A) x" by (metis compose_eq)
  then show "g ∘ f ↓ A = k ∘ h ↓ A" by (metis extensionalityI compose_extensional)
qed

lemma compose_eq_if: "(⋀x. x ∈ A ⟹ g (f x) = k (h x)) ⟹ g ∘ f ↓ A = k ∘ h ↓ A"
  using compose_eq_iff by blast

lemma compose_compose_eq_iff2: "(h ∘ (g ∘ f ↓ A) ↓ A = h' ∘ (g' ∘ f' ↓ A) ↓ A) =
  (∀x ∈ A. h (g (f x)) = h' (g' (f' x)))"
  by (simp add: compose_eq compose_eq_iff)

lemma compose_compose_eq_iff1: assumes "f ∈ A → B" "f' ∈ A → B"
  shows "((h ∘ g ↓ B) ∘ f ↓ A = (h' ∘ g' ↓ B) ∘ f' ↓ A) = (∀x ∈ A. h (g (f x)) = h' (g' (f' x)))"
proof -
  have "(h ∘ g ↓ B) ∘ f ↓ A = h ∘ (g ∘ f ↓ A) ↓ A" by (metis assms(1) compose_assoc)
  moreover have "(h' ∘ g' ↓ B) ∘ f' ↓ A = h' ∘ (g' ∘ f' ↓ A) ↓ A" by (metis assms(2) compose_assoc)
  ultimately have h: "((h ∘ g ↓ B) ∘ f ↓ A = (h' ∘ g' ↓ B) ∘ f' ↓ A) =
    (h ∘ (g ∘ f ↓ A) ↓ A = h' ∘ (g' ∘ f' ↓ A) ↓ A)" by presburger
  then show ?thesis by (simp only: h compose_compose_eq_iff2)
qed

lemma compose_compose_eq_if1: "⟦f ∈ A → B; f' ∈ A → B; ∀x ∈ A. h (g (f x)) = h' (g' (f' x))⟧ ⟹
  (h ∘ g ↓ B) ∘ f ↓ A = (h' ∘ g' ↓ B) ∘ f' ↓ A"
  using compose_compose_eq_iff1 by blast

lemma compose_compose_eq_if2: "∀x ∈ A. h (g (f x)) = h' (g' (f' x)) ⟹
  h ∘ (g ∘ f ↓ A) ↓ A = h' ∘ (g' ∘ f' ↓ A) ↓ A"
  using compose_compose_eq_iff2 by blast

lemma compose_restrict_eq1: "f ∈ A → B ⟹  restrict g B ∘ f ↓ A = g ∘ f ↓ A"
  by (smt (verit) PiE compose_eq_iff restrict_apply')

lemma compose_restrict_eq2: "g ∘ (restrict f A) ↓ A = g ∘ f ↓ A"
  by (metis (mono_tags, lifting) compose_eq_if restrict_apply')

lemma compose_Id_eq_restrict: "g ∘ (λx ∈ A. x) ↓ A = restrict g A"
  by (smt (verit) compose_restrict_eq1 compose_def restrict_apply' restrict_ext)

section ‹Globular sets›

subsection ‹Globular sets›

text ‹
  We define a locale ‹globular_set› that encodes the cell data of a strict $\omega$-category
  \cite[Def 1.4.5]{Leinster2004}. The elements of ‹X n› are the ‹n›-cells, and the maps ‹s›
  and ‹t› give the source and target of a cell, respectively.
›

locale globular_set =
  fixes X :: "nat ⇒ 'a set" and s :: "nat ⇒ 'a ⇒ 'a" and t :: "nat ⇒ 'a ⇒ 'a"
  assumes s_fun: "s n ∈ X (Suc n) → X n"
    and   t_fun: "t n ∈ X (Suc n) → X n"
    and  s_comp: "x ∈ X (Suc (Suc n)) ⟹ s n (t (Suc n) x) = s n (s (Suc n) x)"
    and  t_comp: "x ∈ X (Suc (Suc n)) ⟹ t n (s (Suc n) x) = t n (t (Suc n) x)"
begin

lemma s_comp': "s n ∘ t (Suc n) ↓ X (Suc (Suc n)) = s n ∘ s (Suc n) ↓ X (Suc (Suc n))"
  by (metis (full_types) compose_eq_if s_comp)

lemma t_comp': "t n ∘ s (Suc n) ↓ X (Suc (Suc n)) = t n ∘ t (Suc n) ↓ X (Suc (Suc n))"
  by (metis (full_types) compose_eq_if t_comp)

text ‹These are the generalised source and target maps. The arguments are the dimension of the
input and output, respectively. They allow notation similar to ‹sm-p› in \cite{Leinster2004}.›

fun s' :: "nat ⇒ nat ⇒ 'a ⇒ 'a" where
"s' 0 0 = id" |
"s' 0 (Suc n) = undefined" |
"s' (Suc m) n = (if Suc m < n then undefined
  else if Suc m = n then id
  else s' m n ∘ s m)"

fun t' :: "nat ⇒ nat ⇒ 'a ⇒ 'a" where
"t' 0 0 = id" |
"t' 0 (Suc n) = undefined" |
"t' (Suc m) n = (if Suc m < n then undefined
  else if Suc m = n then id
  else t' m n ∘ t m)"

lemma s'_n_n [simp]: "s' n n = id"
  by (cases n, simp_all)

lemma s'_Suc_n_n [simp]: "s' (Suc n) n = s n"
  by simp

lemma s'_Suc_Suc_n_n [simp]: "s' (Suc (Suc n)) n = s n ∘ s (Suc n)"
  by simp

lemma s'_Suc [simp]: "n ≤ m ⟹ s' (Suc m) n = s' m n ∘ s m"
  by simp

lemma s'_Suc': "n < m ⟹ s' m n = s n ∘ s' m (Suc n)"
proof (induction m arbitrary: n)
  case 0
  then show ?case by blast
next
  case (Suc m)
  hence "n ≤ m" by fastforce 
  show ?case proof (cases "n = m", simp)
    assume "n ≠ m" 
    then show "s' (Suc m) n = s n ∘ s' (Suc m) (Suc n)" using Suc by fastforce
  qed    
qed

lemma t'_n_n [simp]: "t' n n = id"
  by (cases n, simp_all)

lemma t'_Suc_n_n [simp]: "t' (Suc n) n = t n"
  by simp

lemma t'_Suc_Suc_n_n [simp]: "t' (Suc (Suc n)) n = t n ∘ t (Suc n)"
  by simp

lemma t'_Suc [simp]: "n ≤ m ⟹ t' (Suc m) n = t' m n ∘ t m"
  by simp

lemma t'_Suc': "n < m ⟹ t' m n = t n ∘ t' m (Suc n)"
proof (induction m arbitrary: n)
  case 0
  then show ?case by blast
next
  case (Suc m)
  hence "n ≤ m" by fastforce 
  show ?case proof (cases "n = m", simp)
    assume "n ≠ m" 
    then show "t' (Suc m) n = t n ∘ t' (Suc m) (Suc n)" using Suc by fastforce
  qed    
qed

lemma s'_fun: "n ≤ m ⟹ s' m n ∈ X m → X n"
proof (induction m arbitrary: n)
  case 0
  thus ?case by force
next
  case (Suc m)
  thus ?case proof (cases "n = Suc m")
    case True
    then show ?thesis by auto
  next
    case False
    hence "n ≤ m" using `n ≤ Suc m` by force
    thus ?thesis using Suc.IH s_fun s'_Suc by auto
  qed
qed

lemma t'_fun: "n ≤ m ⟹ t' m n ∈ X m → X n"
proof (induction m arbitrary: n)
  case 0
  thus ?case by force
next
  case (Suc m)
  thus ?case proof (cases "n = Suc m")
    case True
    then show ?thesis by auto
  next
    case False
    hence "n ≤ m" using `n ≤ Suc m` by force
    thus ?thesis using Suc.IH t_fun t'_Suc by auto
  qed
qed

lemma s'_comp: "⟦ n < m; x ∈ X m ⟧ ⟹ s n (t' m (Suc n) x) = s' m n x"
proof (induction "m - n" arbitrary: n)
  case 0
  then show ?case by force
next
  case IH: (Suc k)
  show ?case proof (cases k)
    case 0
    with IH(2) have "m = Suc n" by fastforce
    then show ?thesis using s'_Suc' by auto
  next
    case (Suc k')
    with ‹Suc k = m - n› have hle: "Suc (Suc n) ≤ m" by simp
    hence "Suc n < m" by force
    hence "Suc (Suc n) ≤ m" by fastforce
    have "s n (t' m (Suc n) x)
       = s n (t (Suc n) (t' m (Suc (Suc n)) x))" using t'_Suc' ‹Suc n < m› by simp
    also have "… = s n (s (Suc n) (t' m (Suc (Suc n)) x))"
      using t'_fun ‹Suc (Suc n) ≤ m› s_comp IH(4) by blast
    also have "… = s n (s' m (Suc n) x)"
      using IH Suc_diff_Suc Suc_inject ‹Suc n < m› by presburger
    finally show ?thesis using ‹n < m› s'_Suc' by simp
  qed
qed

lemma t'_comp: "⟦ n < m; x ∈ X m ⟧ ⟹ t n (s' m (Suc n) x) = t' m n x"
proof (induction "m - n" arbitrary: n)
  case 0
  then show ?case by force
next
  case IH: (Suc k)
  show ?case proof (cases k)
    case 0
    with IH(2) have "m = Suc n" by fastforce
    then show ?thesis using IH.prems(1) by auto
  next
    case (Suc k')
    with ‹Suc k = m - n› have hle: "Suc (Suc n) ≤ m" by simp
    hence "Suc n < m" by force
    hence "Suc (Suc n) ≤ m" by fastforce
    have "t n (s' m (Suc n) x)
       = t n (s (Suc n) (s' m (Suc (Suc n)) x))" using s'_Suc' ‹Suc n < m› by simp
    also have "… = t n (t (Suc n) (s' m (Suc (Suc n)) x))"
      using s'_fun ‹Suc (Suc n) ≤ m› t_comp IH(4) by blast
    also have "… = t n (t' m (Suc n) x)"
      using IH Suc_diff_Suc Suc_inject ‹Suc n < m› by presburger
    finally show ?thesis using ‹n < m› t'_Suc' by simp
  qed
qed

text ‹The following predicates and sets are needed to define composition in an $\omega$-category.›

definition is_parallel_pair :: "nat ⇒ nat ⇒ 'a ⇒ 'a ⇒ bool" where
"is_parallel_pair m n x y ≡ n ≤ m ∧ x ∈ X m ∧ y ∈ X m ∧ s' m n x = s' m n y ∧ t' m n x = t' m n y"

text ‹\cite[p. 44]{Leinster2004}›
definition is_composable_pair :: "nat ⇒ nat ⇒ 'a ⇒ 'a ⇒ bool" where
"is_composable_pair m n y x ≡ n < m ∧ y ∈ X m ∧ x ∈ X m ∧ t' m n x = s' m n y"

definition composable_pairs :: "nat ⇒ nat ⇒ ('a × 'a) set" where
"composable_pairs m n = {(y, x). is_composable_pair m n y x}"

lemma composable_pairs_empty: "m ≤ n ⟹ composable_pairs m n = {}"
  using is_composable_pair_def composable_pairs_def by simp

end

subsection ‹Maps between globular sets›

text ‹We define maps between globular sets to be natural transformations of the corresponding
functors \cite[Def 1.4.5]{Leinster2004}.›

locale globular_map = source: globular_set X sX tX + target: globular_set Y sY tY
  for X sX tX Y sY tY +
  fixes φ :: "nat ⇒ 'a ⇒ 'b"
  assumes map_fun: "φ m ∈ X m → Y m"
    and   is_natural_wrt_s: "x ∈ X (Suc m) ⟹ φ m (sX m x) = sY m (φ (Suc m) x)"
    and   is_natural_wrt_t: "x ∈ X (Suc m) ⟹ φ m (tX m x) = tY m (φ (Suc m) x)"
begin

lemma is_natural_wrt_s': "⟦ n ≤ m; x ∈ X m ⟧ ⟹ φ n (source.s' m n x) = target.s' m n (φ m x)"
proof (induction "m - n" arbitrary: n)
  case 0
  hence "m = n" by simp
  then show ?case by fastforce
next
  case (Suc k)
  hence "n < m" by force
  hence "Suc n ≤ m" by auto
  have "φ n (source.s' m n x) = φ n (sX n (source.s' m (Suc n) x))"
    using source.s'_Suc' ‹n < m› by simp
  also have "… = sY n (φ (Suc n) (source.s' m (Suc n) x))"
    using source.s'_fun ‹Suc n ≤ m› Suc(1) Suc(4) is_natural_wrt_s by blast
  also have "… = sY n (target.s' m (Suc n) (φ m x))"
    using Suc ‹Suc n ≤ m› Suc_diff_Suc Suc_inject ‹n < m› by presburger
  finally show ?case using target.s'_Suc' ‹n < m› by simp
qed

lemma is_natural_wrt_t': "⟦ n ≤ m; x ∈ X m ⟧ ⟹ φ n (source.t' m n x) = target.t' m n (φ m x)"
proof (induction "m - n" arbitrary: n)
  case 0
  hence "m = n" by simp
  then show ?case by fastforce
next
  case (Suc k)
  hence "n < m" by force
  hence "Suc n ≤ m" by auto
  have "φ n (source.t' m n x) = φ n (tX n (source.t' m (Suc n) x))"
    using source.t'_Suc' ‹n < m› by simp
  also have "… = tY n (φ (Suc n) (source.t' m (Suc n) x))"
    using source.t'_fun ‹Suc n ≤ m› Suc(1) Suc(4) is_natural_wrt_t by blast
  also have "… = tY n (target.t' m (Suc n) (φ m x))"
    using Suc ‹Suc n ≤ m› Suc_diff_Suc Suc_inject ‹n < m› by presburger
  finally show ?case using target.t'_Suc' ‹n < m› by simp
qed

end

text ‹The composition of two globular maps is itself a globular map. This intermediate
  locale gathers the data needed for such a statement.›
locale two_globular_maps = fst: globular_map X sX tX Y sY tY φ + snd: globular_map Y sY tY Z sZ tZ ψ
  for X sX tX Y sY tY Z sZ tZ φ ψ

sublocale two_globular_maps ⊆ comp: globular_map X sX tX Z sZ tZ "λm. ψ m ∘ φ m"
proof (unfold_locales)
  fix m
  show "ψ m ∘ φ m ∈ X m → Z m" using fst.map_fun snd.map_fun by fastforce
next
  fix x m assume "x ∈ X (Suc m)"
  then show "(ψ m ∘ φ m) (sX m x) = sZ m ((ψ (Suc m) ∘ φ (Suc m)) x)"
    using fst.is_natural_wrt_s snd.is_natural_wrt_s comp_apply fst.map_fun by fastforce
next
  fix x m assume "x ∈ X (Suc m)"
  then show "(ψ m ∘ φ m) (tX m x) = tZ m ((ψ (Suc m) ∘ φ (Suc m)) x)"
    using fst.is_natural_wrt_t snd.is_natural_wrt_t comp_apply fst.map_fun by fastforce
qed

sublocale two_globular_maps ⊆ compose: globular_map X sX tX Z sZ tZ "λm. ψ m ∘ φ m ↓ X m"
proof (unfold_locales)
  fix m
  show "ψ m ∘ φ m ↓ X m ∈ X m → Z m" using funcset_compose fst.map_fun snd.map_fun by fast
next
  fix x m assume "x ∈ X (Suc m)"
  then show "(ψ m ∘ φ m ↓ X m) (sX m x) = sZ m ((ψ (Suc m) ∘ φ (Suc m) ↓ X (Suc m)) x)"
    by (metis PiE fst.is_natural_wrt_s snd.is_natural_wrt_s fst.map_fun compose_eq fst.source.s_fun)
next
  fix x m assume "x ∈ X (Suc m)"
  then show "(ψ m ∘ φ m ↓ X m) (tX m x) = tZ m ((ψ (Suc m) ∘ φ (Suc m) ↓ X (Suc m)) x)"
    by (metis PiE fst.is_natural_wrt_t snd.is_natural_wrt_t fst.map_fun compose_eq fst.source.t_fun)
qed

subsection ‹The terminal globular set›

text ‹The terminal globular set, with a unique m-cell for each m \cite[p. 264]{Leinster2004}.›

interpretation final_glob: globular_set "λm. {()}" "λm. id" "λm. id"
  by (unfold_locales, auto)

context globular_set
begin

text ‹\cite[p. 272]{Leinster2004}›

interpretation map_to_final_glob: globular_map X s t
  "λm. {()}" "λm. id" "λm. id"
  "λm. (λx. ())"
  by (unfold_locales, simp_all)

end

end