{-# OPTIONS --without-K --rewriting --overlapping-instances #-}

open import lib.Basics
open import lib.types.Sigma
open import lib.types.Pi

module Bicategory where

module _ (j : ULevel) where

  -- Nota bene: We define a bicategory as a (2,1)-category with paths as 2-cells.
  record BicatStr {i} (B₀ : Type i) : Type (lmax i (lsucc j)) where
    constructor bicatstr
    infixr 82 _◻_
    field
      hom : B₀  B₀  Type j
      id₁ : (a : B₀)  hom a a
      _◻_ : {a b c : B₀}  hom b c  hom a b  hom a c
      ρ : {a b : B₀} (f : hom a b)  f == f  id₁ a
      lamb : {a b : B₀} (f : hom a b)  f == id₁ b  f
      α : {a b c d : B₀} (h : hom c d) (g : hom b c) (f : hom a b)  h  g  f == (h  g)  f
      tri-bc : {a b c : B₀} (f : hom a b) (g : hom b c)
         α g (id₁ b) f == ! (ap  m  g  m) (lamb f))  ap  m  m  f) (ρ g)
      pent-bc : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e)
         α i h (g  f)  α (i  h) g f == ap  m  i  m) (α h g f)  α i (h  g) f  ap  m  m  f) (α i h g)
      {{hom-trunc}} : {a b : B₀}  has-level 1 (hom a b)
    
    abstract

      tri-bc◃ : {a b c : B₀} (f : hom a b) (g : hom b c) 
        α g (id₁ b) f ◃∎
          =ₛ
        ! (ap  m  g  m) (lamb f)) ◃∙
        ap  m  m  f) (ρ g) ◃∎
      tri-bc◃ f g = =ₛ-in (tri-bc f g)

      tri-bc◃! : {a b c : B₀} (f : hom a b) (g : hom b c) 
        ! (α g (id₁ b) f) ◃∎
          =ₛ
        ! (ap  m  m  f) (ρ g)) ◃∙
        ap  m  g  m) (lamb f) ◃∎
      tri-bc◃! {a} {b} f g =
        ! (α g (id₁ b) f) ◃∎
          =ₛ⟨ !-=ₛ (tri-bc◃ f g) 
        ! (ap  m  m  f) (ρ g)) ◃∙
        ! (! (ap  m  g  m) (lamb f))) ◃∎
          =ₛ₁⟨ 1 & 1 & !-! (ap  m  g  m) (lamb f)) 
        ! (ap  m  m  f) (ρ g)) ◃∙
        ap  m  g  m) (lamb f) ◃∎ ∎ₛ

      tri-bc◃-rot : {a b c : B₀} (f : hom a b) (g : hom b c) 
        ap  m  g  m) (lamb f) ◃∙
        α g (id₁ b) f ◃∎
          =ₛ
        ap  m  m  f) (ρ g) ◃∎
      tri-bc◃-rot f g = pre-rotate-out (tri-bc◃ f g)

      tri-bc◃-rot2-pre : {a b c : B₀} (f : hom a b) (g : hom b c) 
        ap  m  g  m) (lamb f) ◃∙
        α g (id₁ b) f ◃∙
        ! (ap  m  m  f) (ρ g)) ◃∎
          =ₛ
        []
      tri-bc◃-rot2-pre f g = post-rotate'-in (tri-bc◃-rot f g)

      tri-bc◃-rot2 : {a b c : B₀} (f : hom a b) (g : hom b c) 
        ap  m  g  m) (lamb f) ◃∙
        α g (id₁ b) f ◃∙
        ap  m  m  f) (! (ρ g)) ◃∎
          =ₛ
        []
      tri-bc◃-rot2 {b = b} f g =
        ap  m  g  m) (lamb f) ◃∙
        α g (id₁ b) f ◃∙
        ap  m  m  f) (! (ρ g)) ◃∎
          =ₛ₁⟨ 2 & 1 & ap-!  m  m  f) (ρ g) 
        ap  m  g  m) (lamb f) ◃∙
        α g (id₁ b) f ◃∙
        ! (ap  m  m  f) (ρ g)) ◃∎
          =ₛ⟨ tri-bc◃-rot2-pre f g 
        [] ∎ₛ

      tri-bc◃-rot3-pre : {a b c : B₀} (f : hom a b) (g : hom b c) 
        []
          =ₛ
        ap  m  m  f) (ρ g) ◃∙
        ! (α g (id₁ b) f) ◃∙
        ! (ap  m  g  m) (lamb f)) ◃∎
      tri-bc◃-rot3-pre f g = post-rotate-in (post-rotate-in (tri-bc◃-rot f g))

      tri-bc◃-rot3 : {a b c : B₀} (f : hom a b) (g : hom b c) 
        []
          =ₛ
        ap  m  m  f) (ρ g) ◃∙
        ! (α g (id₁ b) f) ◃∙
        ap  m  g  m) (! (lamb f)) ◃∎
      tri-bc◃-rot3 {b = b} f g =
        []
          =ₛ⟨ tri-bc◃-rot3-pre f g 
        ap  m  m  f) (ρ g) ◃∙
        ! (α g (id₁ b) f) ◃∙
        ! (ap  m  g  m) (lamb f)) ◃∎
          =ₛ₁⟨ 2 & 1 & !-ap  m  g  m) (lamb f) 
        ap  m  m  f) (ρ g) ◃∙
        ! (α g (id₁ b) f) ◃∙
        ap  m  g  m) (! (lamb f)) ◃∎ ∎ₛ

      tri-bc◃-rot4 : {a b c : B₀} (f : hom a b) (g : hom b c) 
        ! (ap  m  m  f) (ρ g)) ◃∎
          =ₛ
        ! (α g (id₁ b) f) ◃∙
        ! (ap  m  g  m) (lamb f)) ◃∎
      tri-bc◃-rot4 {b = b} f g = pre-rotate'-in (tri-bc◃-rot3-pre f g)

      tri-bc◃-rot5 : {a b c : B₀} (f : hom a b) (g : hom b c) 
        ap  m  m  f) (! (ρ g)) ◃∎
          =ₛ
        ! (α g (id₁ b) f) ◃∙
        ap  m  g  m) (! (lamb f)) ◃∎
      tri-bc◃-rot5 {b = b} f g =
        ap  m  m  f) (! (ρ g)) ◃∎
          =ₛ₁⟨ ap-!  m  m  f) (ρ g) 
        ! (ap  m  m  f) (ρ g)) ◃∎
          =ₛ⟨ tri-bc◃-rot4 f g 
        ! (α g (id₁ b) f) ◃∙
        ! (ap  m  g  m) (lamb f)) ◃∎
          =ₛ₁⟨ 1 & 1 & !-ap  m  g  m) (lamb f) 
        ! (α g (id₁ b) f) ◃∙
        ap  m  g  m) (! (lamb f)) ◃∎ ∎ₛ

      pent-bc◃ : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        α i h (g  f) ◃∙
        α (i  h) g f ◃∎
          =ₛ
        ap  m  i  m) (α h g f) ◃∙
        α i (h  g) f ◃∙
        ap  m  m  f) (α i h g) ◃∎
      pent-bc◃ f g h i = =ₛ-in (pent-bc f g h i)

      pent-bc◃-rot : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        α (i  h) g f ◃∙
        ap  m  m  f) (! (α i h g)) ◃∙
        ! (α i (h  g) f) ◃∙
        ap  m  i  m) (! (α h g f)) ◃∙
        α i h (g  f) ◃∎
          =ₛ
        []
      pent-bc◃-rot f g h i = 
        α (i  h) g f ◃∙
        ap  m  m  f) (! (α i h g)) ◃∙
        ! (α i (h  g) f) ◃∙
        ap  m  i  m) (! (α h g f)) ◃∙
        α i h (g  f) ◃∎
          =ₛ₁⟨ 1 & 1 & ap-!  m  m  f) (α i h g) 
        α (i  h) g f ◃∙
        ! (ap  m  m  f) (α i h g)) ◃∙
        ! (α i (h  g) f) ◃∙
        ap  m  i  m) (! (α h g f)) ◃∙
        α i h (g  f) ◃∎
          =ₛ₁⟨ 3 & 1 & ap-!  m  i  m) (α h g f) 
        α (i  h) g f ◃∙
        ! (ap  m  m  f) (α i h g)) ◃∙
        ! (α i (h  g) f) ◃∙
        ! (ap  m  i  m) (α h g f)) ◃∙
        α i h (g  f) ◃∎
          =ₛ⟨ post-rotate-out (pre-rotate-in (post-rotate'-in (post-rotate'-in (post-rotate'-in (pent-bc◃ f g h i))))) 
        [] ∎ₛ

      pent-bc◃-rot2 : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        ! (ap  m  m  f) (α i h g)) ◃∙
        ! (α i (h  g) f) ◃∎
          =ₛ
        ! (α (i  h) g f) ◃∙
        ! (α i h (g  f)) ◃∙
        ap  m  i  m) (α h g f) ◃∎
      pent-bc◃-rot2 f g h i = post-rotate'-in (post-rotate'-in (pre-rotate-in (pre-rotate-in (pent-bc◃ f g h i))))

      pent-bc◃-rot3 : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        ! (α i (h  g) f) ◃∙
        ! (ap  m  i  m) (α h g f)) ◃∎
          =ₛ
        ap  m  m  f) (α i h g) ◃∙
        ! (α (i  h) g f) ◃∙
        ! (α i h (g  f)) ◃∎
      pent-bc◃-rot3 f g h i = pre-rotate'-out (post-rotate'-in (pent-bc◃-rot2 f g h i))

      pent-bc◃-rot4 : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        ! (ap  m  i  m) (α h g f)) ◃∙
        α i h (g  f) ◃∙
        α (i  h) g f ◃∎
          =ₛ
        α i (h  g) f ◃∙
        ap  m  m  f) (α i h g) ◃∎
      pent-bc◃-rot4 f g h i = pre-rotate'-in (pent-bc◃ f g h i)

      pent-bc◃-rot5 : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        α i h (g  f) ◃∎
          =ₛ
        ap  m  i  m) (α h g f) ◃∙
        α i (h  g) f ◃∙
        ap  m  m  f) (α i h g) ◃∙
        ! (α (i  h) g f) ◃∎
      pent-bc◃-rot5 f g h i = post-rotate-in (pent-bc◃ f g h i)

      pent-bc◃-rot6 : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        ! (ap  m  i  m) (α h g f)) ◃∙
        α i h (g  f) ◃∎
          =ₛ
        α i (h  g) f ◃∙
        ap  m  m  f) (α i h g) ◃∙
        ! (α (i  h) g f) ◃∎
      pent-bc◃-rot6 f g h i = pre-rotate'-in (pent-bc◃-rot5 f g h i)

      pent-bc◃-rot7 : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        ! (ap  m  i  m) (α h g f)) ◃∎
          =ₛ
        α i (h  g) f ◃∙
        ap  m  m  f) (α i h g) ◃∙
        ! (α (i  h) g f) ◃∙
        ! (α i h (g  f)) ◃∎
      pent-bc◃-rot7 f g h i = pre-rotate'-out (pent-bc◃-rot3 f g h i)

      pent-bc◃-rot8 : {a b c d e : B₀} (f : hom a b) (g : hom b c) (h : hom c d) (i : hom d e) 
        α (i  h) g f ◃∙
        ! (ap  m  m  f) (α i h g)) ◃∎
          =ₛ
        ! (α i h (g  f)) ◃∙
        ap  m  i  m) (α h g f) ◃∙
        α i (h  g) f ◃∎
      pent-bc◃-rot8 f g h i = post-rotate'-out (pre-rotate-out (pent-bc◃-rot2 f g h i))

  Bicat : (i : ULevel)  Type (lmax (lsucc j) (lsucc i))
  Bicat i = Σ (Type i) BicatStr

open BicatStr {{...}}

module _ {i j} {B₀ : Type i} where

  -- to aid instance search in Agda 2.6.4.3
  infixr 82 ⟦_⟧_◻_
  ⟦_⟧_◻_ : (ξ : BicatStr j B₀) {a b c : B₀}  hom {{ξ}} b c  hom {{ξ}} a b  hom {{ξ}} a c
  ⟦_⟧_◻_ ξ g f = _◻_ {{ξ}} g f 

  id₁-bc-rght-≃ : {{ξB : BicatStr j B₀}} {x y : B₀}  hom x y  hom x y
  fst (id₁-bc-rght-≃  {{ξB}}) f =  ξB  f  id₁ _
  snd id₁-bc-rght-≃ = ∼-preserves-equiv  x  ρ x) (idf-is-equiv _)

module _ {i₁ i₂ j₁ j₂} {B₀ : Type i₁} {C₀ : Type i₂} {{ξB : BicatStr j₁ B₀}} {{ξC : BicatStr j₂ C₀}} where

  -- pseudofunctors
  record PsftorStr (F₀ : B₀  C₀) : Type (lmax (lmax i₁ j₁) (lmax i₂ j₂)) where
    constructor psfunctorstr
    field
      F₁ : {a b : B₀}  hom a b  hom (F₀ a) (F₀ b)
      F-id₁ : (a : B₀)  F₁ (id₁ a) == id₁ (F₀ a)
      F-◻ : {a b c : B₀} (f : hom a b) (g : hom b c)
         F₁ ( ξB  g  f) ==  ξC  F₁ g  F₁ f
      F-ρ : {a b : B₀} (f : hom a b)  ap F₁ (ρ f)  F-◻ (id₁ a) f  ap  m  F₁ f  m) (F-id₁ a) == ρ (F₁ f)
      F-λ : {a b : B₀} (f : hom a b)  ap F₁ (lamb f)  F-◻ f (id₁ b)  ap  m  m  F₁ f) (F-id₁ b) == lamb (F₁ f)
      F-α : {a b c d : B₀} (h : hom c d) (g : hom b c) (f : hom a b) 
        ! (ap  m  F₁ h  m) (F-◻ f g)) 
        ! (F-◻ ( ξB  g  f) h) 
        ap F₁ (α h g f) 
        F-◻ f ( ξB  h  g) 
        ap  m  m  F₁ f) (F-◻ g h)
         ==
        α (F₁ h) (F₁ g) (F₁ f)

    abstract

      F-ρ-◃ : {a b : B₀} (f : hom a b) 
        ap F₁ (ρ f) ◃∙ F-◻ (id₁ a) f ◃∙ ap  m  F₁ f  m) (F-id₁ a) ◃∎ =ₛ ρ (F₁ f) ◃∎
      F-ρ-◃ f = =ₛ-in (F-ρ f)

      F-ρ-rot-!3 : {a b : B₀} (f : hom a b) 
        [] =ₛ ρ (F₁ f) ◃∙ ! (ap  m  F₁ f  m) (F-id₁ a)) ◃∙ ! (F-◻ (id₁ a) f) ◃∙ ! (ap F₁ (ρ f)) ◃∎
      F-ρ-rot-!3 f = post-rotate-in (post-rotate-in (post-rotate-in (F-ρ-◃ f)))

      F-λ-◃ : {a b : B₀} (f : hom a b)  ap F₁ (lamb f) ◃∙ F-◻ f (id₁ b) ◃∙ ap  m  m  F₁ f) (F-id₁ b) ◃∎ =ₛ lamb (F₁ f) ◃∎
      F-λ-◃ f = =ₛ-in (F-λ f)

      F-λ-rot : {a b : B₀} (f : hom a b) 
        ! (lamb (F₁ f)) ◃∙ ap F₁ (lamb f) ◃∙ F-◻ f (id₁ b) ◃∙ ap  m  m  F₁ f) (F-id₁ b) ◃∎ =ₛ []
      F-λ-rot f = pre-rotate'-in (F-λ-◃ f)

      F-α-◃ : {a b c d : B₀} (h : hom c d) (g : hom b c) (f : hom a b) 
        α (F₁ h) (F₁ g) (F₁ f) ◃∎
          =ₛ
        ! (ap  m  F₁ h  m) (F-◻ f g)) ◃∙
        ! (F-◻ ( ξB  g  f) h) ◃∙
        ap F₁ (α h g f) ◃∙
        F-◻ f ( ξB  h  g) ◃∙
        ap  m  m  F₁ f) (F-◻ g h) ◃∎
      F-α-◃ h g f = !ₛ (=ₛ-in (F-α h g f))      

      -- hnat properties of F-◻
      F-◻-nat-l : {a b c : B₀} {m₁ m₂ : hom a b} (m₃ : hom b c) (q : m₁ == m₂)
         F-◻ m₁ m₃ == ap  m  F₁ ( ξB  m₃  m)) q  F-◻ m₂ m₃ ∙' ! (ap  m   ξC  F₁ m₃  F₁ m) q)
      F-◻-nat-l m₃ q = apCommSq2-∙'  m  F-◻ m m₃) q
      F-◻-nat-r : {a b c : B₀} (m₁ : hom a b) {m₂ m₃ : hom b c} (q : m₂ == m₃)
         F-◻ m₁ m₂ == ap  m  F₁ ( ξB  m  m₁)) q  F-◻ m₁ m₃ ∙' ! (ap  m   ξC  F₁ m  F₁ m₁) q)
      F-◻-nat-r m₁ q = apCommSq2-∙' (F-◻ m₁) q

  record Psfunctor : Type (lmax (lmax i₁ j₁) (lmax i₂ j₂)) where
    constructor psfunctor
    field
      map-pf : B₀  C₀
      {{str-pf}} : PsftorStr map-pf

open PsftorStr
open Psfunctor

-- pseudofunctors with the proposition-valued fields omitted
module _ {i₁ i₂ j₁ j₂} {B₀ : Type i₁} {C₀ : Type i₂} {{ξB : BicatStr j₁ B₀}} {{ξC : BicatStr j₂ C₀}} where

  record PsfunctorNcStr (F₀ : B₀  C₀) : Type (lmax (lmax i₁ j₁) (lmax i₂ j₂)) where
    constructor psfunctorncstr
    field
      F₁ : {a b : B₀}  hom a b  hom (F₀ a) (F₀ b)
      F-id₁ : (a : B₀)  F₁ (id₁ a) == id₁ (F₀ a)
      F-◻ : {a b c : B₀} (f : hom a b) (g : hom b c)
         F₁ ( ξB  g  f) ==  ξC  F₁ g  F₁ f

  record Psfunctor-nc : Type (lmax (lmax i₁ j₁) (lmax i₂ j₂)) where
    constructor psfunctornc
    field
      map-pf : B₀  C₀
      {{str-pf}} : PsfunctorNcStr map-pf

  open Psfunctor-nc
  -- the underlying structure of a pseudofunctor
  psftor-str : Psfunctor {{ξB}} {{ξC}}  Psfunctor-nc
  map-pf (psftor-str R) = map-pf R
  str-pf (psftor-str R) = psfunctorncstr (F₁ (str-pf R)) (F-id₁ (str-pf R)) (F-◻ (str-pf R))

  open PsfunctorNcStr
  Psf-coh-data : Psfunctor-nc  Type (lmax (lmax i₁ j₁) j₂)
  Psf-coh-data (psfunctornc _ {{sR}}) =
    ({a b : B₀} (f : hom a b)  ap (F₁ sR) (ρ f)  F-◻ sR (id₁ a) f  ap  m  F₁ sR f  m) (F-id₁ sR a) == ρ (F₁ sR f)) ×
    ({a b : B₀} (f : hom a b)  ap (F₁ sR) (lamb f)  F-◻ sR f (id₁ b)  ap  m  m  F₁ sR f) (F-id₁ sR b) == lamb (F₁ sR f)) ×
    ({a b c d : B₀} (h : hom c d) (g : hom b c) (f : hom a b) 
       ! (ap  m  F₁ sR h  m) (F-◻ sR f g)) 
       ! (F-◻ sR ( ξB  g  f) h) 
       ap (F₁ sR) (α h g f) 
       F-◻ sR f ( ξB  h  g) 
       ap  m  m  F₁ sR f) (F-◻ sR g h)
        ==
       α (F₁ sR h) (F₁ sR g) (F₁ sR f))

  instance
    Psf-coh-data-is-prop :  {ψ}  is-prop (Psf-coh-data ψ)
    Psf-coh-data-is-prop = ×-level ⟨⟩ (×-level ⟨⟩ ⟨⟩)

  -- reforming Psfunctor as a Σ-type
  Psftor-Σ-≃ : Psfunctor {{ξB}} {{ξC}}  Σ Psfunctor-nc Psf-coh-data
  Psftor-Σ-≃ = equiv
     (psfunctor m {{σ}})  (psfunctornc m {{psfunctorncstr (F₁ σ) (F-id₁ σ) (F-◻ σ)}} , (F-ρ σ) , ((F-λ σ) , (F-α σ))))
     (psfunctornc m {{psfunctorncstr F1 Fid Fcmp}} , F-r , F-l , F-assoc)  psfunctor m
      {{psfunctorstr F1 Fid Fcmp F-r F-l F-assoc}})
     _  idp)
    λ _  idp

-- identity pseudofunctor
module _ {i j} {B₀ : Type i} {{ξ : BicatStr j B₀}} where
  
  idfBCσ : PsftorStr (idf B₀)
  F₁ idfBCσ = λ f  f
  F-id₁ idfBCσ = λ a  idp
  F-◻ idfBCσ = λ f g  idp
  F-ρ idfBCσ = λ f  ∙-unit-r (ap  z  z) (ρ f))  ap-idf (ρ f)
  F-λ idfBCσ = λ f  ∙-unit-r (ap  z  z) (lamb f))  ap-idf (lamb f)
  F-α idfBCσ = λ h g f  ∙-unit-r (ap  z  z) (α h g f))  ap-idf (α h g f)

  idfBC : Psfunctor
  map-pf idfBC = idf B₀
  str-pf idfBC = idfBCσ

  idpfBC : Psfunctor-nc
  idpfBC = psftor-str idfBC

-- composition of pseudofunctors  
module _ {i₁ i₂ i₃ j₁ j₂ j₃} {B₀ : Type i₁} {C₀ : Type i₂} {D₀ : Type i₃}
  {{ξB : BicatStr j₁ B₀}} {{ξC : BicatStr j₂ C₀}} {{ξD : BicatStr j₃ D₀}} where

  open Psfunctor-nc
  open PsfunctorNcStr

  -- "s" stands for "stripped"
  infixr 50 _∘BC-s_
  _∘BC-s_ :  (φ₂ : Psfunctor-nc {{ξC}} {{ξD}}) (φ₁ : Psfunctor-nc {{ξB}} {{ξC}})  Psfunctor-nc {{ξB}} {{ξD}}
  map-pf (φ₂ ∘BC-s φ₁) = map-pf φ₂  map-pf φ₁
  F₁ (str-pf (φ₂ ∘BC-s φ₁)) = F₁ (str-pf φ₂)  F₁ (str-pf φ₁)
  F-id₁ (str-pf (φ₂ ∘BC-s φ₁)) a = ap (F₁ (str-pf φ₂)) (F-id₁ (str-pf φ₁) a)  F-id₁ (str-pf φ₂) (map-pf φ₁ a)
  F-◻ (str-pf (φ₂ ∘BC-s φ₁)) f g = ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) f g)  F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g)

  infixr 60 _∘BCσ_
  _∘BCσ_ : (φ₂ : Psfunctor {{ξC}} {{ξD}}) (φ₁ : Psfunctor {{ξB}} {{ξC}})  PsftorStr (map-pf φ₂  map-pf φ₁)
  F₁ (φ₂ ∘BCσ φ₁) = F₁ (str-pf (psftor-str φ₂ ∘BC-s psftor-str φ₁))
  F-id₁ (φ₂ ∘BCσ φ₁) = F-id₁ (str-pf (psftor-str φ₂ ∘BC-s psftor-str φ₁)) 
  F-◻ (φ₂ ∘BCσ φ₁) =  F-◻ (str-pf (psftor-str φ₂ ∘BC-s psftor-str φ₁))
  F-ρ (φ₂ ∘BCσ φ₁) {a} {b} f =
    ap
       q 
        ap (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) (ρ f) 
        (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) (id₁ a) f)  q) 
        ap  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) f  m)
          (ap (F₁ (str-pf φ₂)) (F-id₁ (str-pf φ₁) a)  F-id₁ (str-pf φ₂) (map-pf φ₁ a)))
      (F-◻-nat-l (str-pf φ₂) (F₁ (str-pf φ₁) f) (F-id₁ (str-pf φ₁) a)) 
    lemma-ρ (ρ f) (F-◻ (str-pf φ₁) (id₁ a) f) (F-id₁ (str-pf φ₁) a)
      (F-id₁ (str-pf φ₁) a) (F-id₁ (str-pf φ₂) (map-pf φ₁ a))
      (F-◻ (str-pf φ₂) (id₁ (map-pf φ₁ a)) (F₁ (str-pf φ₁) f)) 
    ap
       q 
        ap (F₁ (str-pf φ₂)) q 
        F-◻ (str-pf φ₂) (id₁ (map-pf φ₁ a)) (F₁ (str-pf φ₁) f) 
        ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)  m) (F-id₁ (str-pf φ₂) (map-pf φ₁ a)))
      (F-ρ (str-pf φ₁) f) 
    F-ρ (str-pf φ₂) (F₁ (str-pf φ₁) f)
    where abstract
      lemma-ρ : {x : B₀} {g₁ g₂ : hom x b} (p₁ : g₁ == g₂)
        {k₁ k₂ k₃ k₄ : hom (map-pf φ₁ x) (map-pf φ₁ a)}
        (p₂ : F₁ (str-pf φ₁) g₂ ==  ξC  F₁ (str-pf φ₁) f  k₁)
        (p₃ : k₁ == k₂) (p₅ : k₃ == k₄)
        {v : hom (map-pf φ₂ (map-pf φ₁ x)) (map-pf φ₂ (map-pf φ₁ a))}
        (p₆ : F₁ (str-pf φ₂) k₄ == v) (p₄ : _)  
        ap (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) p₁ 
        (ap (F₁ (str-pf φ₂)) p₂ 
        ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f  m)) p₃  p₄ ∙'
        ! (ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)  F₁ (str-pf φ₂) m) p₅)) 
        ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)  m)
          (ap (F₁ (str-pf φ₂)) p₅  p₆)
          ==
        ap (F₁ (str-pf φ₂))
          (ap (F₁ (str-pf φ₁)) p₁  p₂  ap  m  F₁ (str-pf φ₁) f  m) p₃)  p₄ 
        ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)  m) p₆
      lemma-ρ idp p₂ idp idp idp p₄ = aux-ρ (F₁ (str-pf φ₂)) p₂ p₄
        where
          aux-ρ :  {i j} {A : Type i} {B : Type j} (g : A  B)
            {x₁ x₂ : A} (q₁ : x₁ == x₂) {b : B} (q₂ : g x₂ == b)
             (ap g q₁  q₂)  idp == ap g (q₁  idp)  q₂  idp
          aux-ρ _ idp idp = idp
  F-λ (φ₂ ∘BCσ φ₁) {a} {b} f =
    ap
       q 
        ap (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) (lamb f) 
        (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) f (id₁ b))  q) 
        ap  m  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) f)
          (ap (F₁ (str-pf φ₂)) (F-id₁ (str-pf φ₁) b)  F-id₁ (str-pf φ₂) (map-pf φ₁ b)))
      (F-◻-nat-r (str-pf φ₂) (F₁ (str-pf φ₁) f) (F-id₁ (str-pf φ₁) b)) 
    lemma-λ (lamb f) (F-id₁ (str-pf φ₁) b) (F-id₁ (str-pf φ₁) b)
      (F-◻ (str-pf φ₁) f (id₁ b)) (F-id₁ (str-pf φ₂) (map-pf φ₁ b))
      (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (id₁ (map-pf φ₁ b))) 
    ap
       q 
        ap (F₁ (str-pf φ₂)) q 
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (id₁ (map-pf φ₁ b)) 
        ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (F-id₁ (str-pf φ₂) (map-pf φ₁ b)))
      (F-λ (str-pf φ₁) f) 
    F-λ (str-pf φ₂) (F₁ (str-pf φ₁) f)
    where abstract
      lemma-λ : {x : B₀} {g₁ g₂ : hom a x} (p₁ : g₁ == g₂)
        {k₁ k₂ k₃ k₄ : hom (map-pf φ₁ b) (map-pf φ₁ x)}
        (p₃ : k₁ == k₂) (p₅ : k₃ == k₄)
        (p₂ : F₁ (str-pf φ₁) g₂ ==  ξC  k₁  F₁ (str-pf φ₁) f)
        {t : hom (map-pf φ₂ (map-pf φ₁ b)) (map-pf φ₂ (map-pf φ₁ x))}
        (p₆ : F₁ (str-pf φ₂) k₄ == t) (p₄ : _)  
        ap (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) p₁ 
        (ap (F₁ (str-pf φ₂)) p₂ 
        ap  m  F₁ (str-pf φ₂) (m  F₁ (str-pf φ₁) f)) p₃  p₄ ∙'
        ! (ap  m  F₁ (str-pf φ₂) m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) p₅)) 
        ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f))
          (ap (F₁ (str-pf φ₂)) p₅  p₆)
          ==
        ap (F₁ (str-pf φ₂))
          (ap (F₁ (str-pf φ₁)) p₁  p₂  ap  m  m  F₁ (str-pf φ₁) f) p₃)  p₄ 
        ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) p₆
      lemma-λ idp idp idp p₂ idp p₄ = aux-λ (F₁ (str-pf φ₂)) p₂ p₄
        where
          aux-λ :  {i j} {A : Type i} {B : Type j} (g : A  B)
            {x₁ x₂ : A} (q₁ : x₁ == x₂) {b : B} (q₂ : g x₂ == b)
             (ap g q₁  q₂)  idp == ap g (q₁  idp)  q₂  idp
          aux-λ _ idp idp = idp
  F-α (φ₂ ∘BCσ φ₁) {a} {b} {c} {d} h g f =
    ! (=ₛ-out lemma-α) 
    ap
       q 
        ! (ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  m) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))) 
        ! (F-◻ (str-pf φ₂) ( ξC  F₁ (str-pf φ₁) g  F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) h)) 
        ap (F₁ (str-pf φ₂)) q 
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) ( ξC  F₁ (str-pf φ₁) h  F₁ (str-pf φ₁) g) 
        ap  m  m  (F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f))) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)))
      (F-α (str-pf φ₁) h g f) 
    F-α (str-pf φ₂) (F₁ (str-pf φ₁) h) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) f)
    where abstract
      lemma-α :
        ! (ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  m) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))) ◃∙
        ! (F-◻ (str-pf φ₂) ( ξC  F₁ (str-pf φ₁) g  F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) h)) ◃∙
        ap (F₁ (str-pf φ₂))
          (! (ap  m  F₁ (str-pf φ₁) h  m) (F-◻ (str-pf φ₁) f g)) 
          ! (F-◻ (str-pf φ₁) ( ξB  g  f) h) 
          ap (F₁ (str-pf φ₁)) (α h g f) 
          F-◻ (str-pf φ₁) f ( ξB  h  g) 
          ap  m  m  F₁ (str-pf φ₁) f) (F-◻ (str-pf φ₁) g h)) ◃∙
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) ( ξC  F₁ (str-pf φ₁) h  F₁ (str-pf φ₁) g) ◃∙
        ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)) ◃∎
          =ₛ
        ! (ap  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) h  m)
            (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) f g) 
            F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))) ◃∙
        ! (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) ( ξB  g  f) h) 
          F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) ( ξB  g  f)) (F₁ (str-pf φ₁) h)) ◃∙
        ap (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) (α h g f) ◃∙
        (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) f ( ξB  h  g)) 
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) ( ξB  h  g))) ◃∙
        ap  m  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) f)
          (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) g h) 
          F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)) ◃∎
      lemma-α =
        ! (ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  m) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))) ◃∙
        ! (F-◻ (str-pf φ₂) ( ξC  F₁ (str-pf φ₁) g  F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) h)) ◃∙  -- here
        ap (F₁ (str-pf φ₂))
          (! (ap  m  F₁ (str-pf φ₁) h  m) (F-◻ (str-pf φ₁) f g)) 
          ! (F-◻ (str-pf φ₁) ( ξB  g  f) h) 
          ap (F₁ (str-pf φ₁)) (α h g f) 
          F-◻ (str-pf φ₁) f ( ξB  h  g) 
          ap  m  m  F₁ (str-pf φ₁) f) (F-◻ (str-pf φ₁) g h)) ◃∙
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) ( ξC  F₁ (str-pf φ₁) h  F₁ (str-pf φ₁) g) ◃∙
        ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)) ◃∎
          =ₛ₁⟨ 3 & 1 & F-◻-nat-r (str-pf φ₂) (F₁ (str-pf φ₁) f) (! (F-◻ (str-pf φ₁) g h)) 
        ! (ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  m) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))) ◃∙
        ! (F-◻ (str-pf φ₂) ( ξC  F₁ (str-pf φ₁) g  F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) h)) ◃∙
        ap (F₁ (str-pf φ₂))
          (! (ap  m  F₁ (str-pf φ₁) h  m) (F-◻ (str-pf φ₁) f g)) 
          ! (F-◻ (str-pf φ₁) ( ξB  g  f) h) 
          ap (F₁ (str-pf φ₁)) (α h g f) 
          F-◻ (str-pf φ₁) f ( ξB  h  g) 
          ap  m  m  F₁ (str-pf φ₁) f) (F-◻ (str-pf φ₁) g h)) ◃∙
        (ap  m  F₁ (str-pf φ₂) ( ξC  m  F₁ (str-pf φ₁) f)) (! (F-◻ (str-pf φ₁) g h)) 
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) ( ξB  h  g)) ∙'
        ! (ap  m   ξD  F₁ (str-pf φ₂) m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (! (F-◻ (str-pf φ₁) g h)))) ◃∙
        ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)) ◃∎
          =ₛ₁⟨ 1 & 1 & ap ! (F-◻-nat-l (str-pf φ₂) (F₁ (str-pf φ₁) h) (! (F-◻ (str-pf φ₁) f g))) 
        ! (ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  m) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))) ◃∙
        ! (ap  m  F₁ (str-pf φ₂) ( ξC  F₁ (str-pf φ₁) h  m)) (! (F-◻ (str-pf φ₁) f g)) 
          F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) ( ξB  g  f)) (F₁ (str-pf φ₁) h) ∙'
          ! (ap  m   ξD  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  F₁ (str-pf φ₂) m) (! (F-◻ (str-pf φ₁) f g)))) ◃∙
        ap (F₁ (str-pf φ₂))
          (! (ap  m  F₁ (str-pf φ₁) h  m) (F-◻ (str-pf φ₁) f g)) 
          ! (F-◻ (str-pf φ₁) ( ξB  g  f) h) 
          ap (F₁ (str-pf φ₁)) (α h g f) 
          F-◻ (str-pf φ₁) f ( ξB  h  g) 
          ap  m  m  F₁ (str-pf φ₁) f) (F-◻ (str-pf φ₁) g h)) ◃∙
        (ap  m  F₁ (str-pf φ₂) ( ξC  m  F₁ (str-pf φ₁) f)) (! (F-◻ (str-pf φ₁) g h)) 
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) ( ξB  h  g)) ∙'
        ! (ap  m   ξD  F₁ (str-pf φ₂) m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (! (F-◻ (str-pf φ₁) g h)))) ◃∙
        ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)) ◃∎
          =ₛ⟨ =ₛ-in $
                aux-α
                  (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))
                  (F-◻ (str-pf φ₁) f g)
                  (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) ( ξB  g  f)) (F₁ (str-pf φ₁) h))
                  (F-◻ (str-pf φ₁) ( ξB  g  f) h)
                  (α h g f)
                  (F-◻ (str-pf φ₁) f ( ξB  h  g))
                  (F-◻ (str-pf φ₁) g h)
                  (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) ( ξB  h  g)))
                  (F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)) 
        ! (ap  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) h  m)
            (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) f g) 
            F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) g))) ◃∙
        ! (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) ( ξB  g  f) h) 
          F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) ( ξB  g  f)) (F₁ (str-pf φ₁) h)) ◃∙
        ap (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) (α h g f) ◃∙
        (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) f ( ξB  h  g)) 
        F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) f) (F₁ (str-pf φ₁) ( ξB  h  g))) ◃∙
        ap  m  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) f)
          (ap (F₁ (str-pf φ₂)) (F-◻ (str-pf φ₁) g h) 
          F-◻ (str-pf φ₂) (F₁ (str-pf φ₁) g) (F₁ (str-pf φ₁) h)) ◃∎ ∎ₛ
        where
          aux-α :
            {k₁ : hom (map-pf φ₂ (map-pf φ₁ a)) (map-pf φ₂ (map-pf φ₁ c))}
            {h₁ h₂ : hom (map-pf φ₁ a) (map-pf φ₁ c)}
            {h₆ h₇ : hom (map-pf φ₁ b) (map-pf φ₁ d)}
            {g₁ g₂ : hom a d}
            {k₅ : hom (map-pf φ₂ (map-pf φ₁ b)) (map-pf φ₂ (map-pf φ₁ d))}
            (p₁ : F₁ (str-pf φ₂) h₂ == k₁) (p₂ : h₁ == h₂)
            (p₃ : F₁ (str-pf φ₂) ( ξC  F₁ (str-pf φ₁) h  h₁) ==  ξD  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  F₁ (str-pf φ₂) h₁)
            (p₄ : F₁ (str-pf φ₁) g₁ ==  ξC  F₁ (str-pf φ₁) h  h₁)
            (p₅ : g₁ == g₂) (p₆ : F₁ (str-pf φ₁) g₂ ==  ξC  h₆  F₁ (str-pf φ₁) f) (p₇ : h₆ == h₇)
            (p₈ : F₁ (str-pf φ₂) ( ξC  h₆  F₁ (str-pf φ₁) f) ==  ξD  F₁ (str-pf φ₂) h₆  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f))
            (p₉ : F₁ (str-pf φ₂) h₇ == k₅) 
            ! (ap  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  m) p₁) 
            ! (ap  m  F₁ (str-pf φ₂) ( ξC  F₁ (str-pf φ₁) h  m)) (! p₂)  p₃ ∙'
              ! (ap  m   ξD  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) h)  F₁ (str-pf φ₂) m) (! p₂))) 
            ap (F₁ (str-pf φ₂))
              (! (ap  m  F₁ (str-pf φ₁) h  m) p₂)  ! p₄ 
              ap (F₁ (str-pf φ₁)) p₅  p₆ 
              ap  m  m  F₁ (str-pf φ₁) f) p₇) 
            (ap  m  F₁ (str-pf φ₂) ( ξC  m  F₁ (str-pf φ₁) f)) (! p₇)  p₈ ∙'
            ! (ap  m   ξD  F₁ (str-pf φ₂) m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) (! p₇))) 
            ap  m  m  F₁ (str-pf φ₂) (F₁ (str-pf φ₁) f)) p₉
              ==
            ! (ap  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) h  m)
                (ap (F₁ (str-pf φ₂)) p₂  p₁)) 
            ! (ap (F₁ (str-pf φ₂)) p₄  p₃) 
            ap (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) p₅ 
            (ap (F₁ (str-pf φ₂)) p₆  p₈) 
            ap  m  m  (F₁ (str-pf φ₂)  F₁ (str-pf φ₁)) f)
              (ap (F₁ (str-pf φ₂)) p₇  p₉)
          aux-α idp idp p₃ p₄ idp p₆ idp p₈ idp = aux2-α (F₁ (str-pf φ₂)) p₃ p₄ p₆ p₈
            where
              aux2-α :  {i j} {A : Type i} {B : Type j} (g : A  B) {y₁ y₂ : B} {x₁ x₂ x₃ : A}
                (q₁ : g x₂ == y₁) (q₂ : x₁ == x₂) (q₃ : x₁ == x₃) (q₄ : g x₃ == y₂) 
                ! q₁  ap g (! q₂  q₃  idp)  q₄  idp == ! (ap g q₂  q₁)  (ap g q₃  q₄)  idp
              aux2-α _ idp idp idp idp = idp

  infixr 50 _∘BC_
  _∘BC_ :  (φ₂ : Psfunctor {{ξC}} {{ξD}}) (φ₁ : Psfunctor {{ξB}} {{ξC}})  Psfunctor {{ξB}} {{ξD}}
  map-pf (φ₂ ∘BC φ₁) = map-pf φ₂  map-pf φ₁
  str-pf (φ₂ ∘BC φ₁) = φ₂ ∘BCσ φ₁

  psf-str-∘ : {φ₂ : Psfunctor {{ξC}} {{ξD}}} {φ₁ : Psfunctor {{ξB}} {{ξC}}}  psftor-str (φ₂ ∘BC φ₁) == (psftor-str φ₂) ∘BC-s (psftor-str φ₁)
  psf-str-∘ = idp