{-# OPTIONS --type-in-type #-}

module Concurrent where

open import Base
open import Monoidal

module ≤-Reasoning { : MonoidalCategory} {X Y : MonoidalCategory.obj } where
  open MonoidalCategory 

  eq2≤refl : {f g : MonoidalCategory.hom  X Y}  f  g  f  g
  eq2≤refl {f} {g} refl = ≤refl {X} {Y} {g}

  infix  3 _≤∎
  infixr 2 _≤⟨⟩_ step-≤ step-≦
  infix  1 ≤begin_

  ≤begin_ : {x y : hom X Y}  x  y  x  y
  ≤begin_ x≤y = x≤y

  _≤⟨⟩_ : (x {y} : hom X Y)  x  y  x  y
  _ ≤⟨⟩ x≤y = x≤y

  step-≤ : (x {y z} : hom X Y)  y  z  x  y  x  z
  step-≤ _ y≤z x≤y = ≤trans x≤y y≤z

  step-≦ : (x {y z} : hom X Y)  y  z  x  y  x  z
  step-≦ x y≤z x≡y = ≤trans (eq2≤refl x≡y) y≤z

  _≤∎ : (x : hom X Y)  x  x
  _≤∎ _ = ≤refl

  syntax step-≤ x y≤z x≤y = x ≤⟨ x≤y  y≤z
  syntax step-≦ x y≤z x≡y = x ≦⟨ x≡y  y≤z


record IsKLaxMonoidalFunctor {c : Set} {⊗₀ : c × c  c} {I₀ :   c}
                             {𝕂 : ParamMonoidalLikeCategory c ⊗₀ I₀} { : ParamMonoidalCategory c ⊗₀ I₀}
                             (funcJ : ParamFunctor (ParamMonoidalCategory.P ) (ParamMonoidalLikeCategory.P 𝕂)  C  C))
                             (funcK : Functor (ParamMonoidalLikeCategory.U 𝕂) (ParamMonoidalCategory.U )): Set where
  private
    module 𝕂 = ParamMonoidalLikeCategory 𝕂
    module  = ParamMonoidalCategory 
    open Functor funcK renaming (F₀ to K ; F₁ to K₁)
    module J = ParamFunctor funcJ
    J₁ = J.F₁
  field
    ϕ-at : (A B : c)  ℂ.hom (K A ℂ.⊗ K B) (K (A 𝕂.⊗ B)) 
    ϕ-naturality : {A B C D : c} {f1 : 𝕂.hom A B} {f2 : 𝕂.hom C D}
                       ϕ-at A C ℂ.▷ K₁ (f1 𝕂.∥ f2) ℂ.≤ K₁ f1 ℂ.⊗₁ K₁ f2 ℂ.▷ ϕ-at B D
    ϕ⁰ : ℂ.hom ℂ.I (K 𝕂.I)
    laxAssoc : {X Y Z : c}
       ϕ-at X Y ℂ.⊗₁ ℂ.id (K Z) ℂ.▷ ϕ-at (X 𝕂.⊗ Y) Z ℂ.▷ K₁ (J₁ (ℂ.α-at X Y Z))
         ℂ.α-at (K X) (K Y) (K Z) ℂ.▷ ℂ.id (K X) ℂ.⊗₁ ϕ-at Y Z ℂ.▷ ϕ-at X (Y 𝕂.⊗ Z)
    laxLunital : {X : c}  ℂ.λ-at (K X)
         ϕ⁰ ℂ.⊗₁ ℂ.id (K X) ℂ.▷ ϕ-at 𝕂.I X ℂ.▷ K₁ (J₁ (ℂ.λ-at X))
    laxRunital : {X : c}  K₁ (J₁ (ℂ.ρ-at X))
         ℂ.ρ-at (K X) ℂ.▷ ℂ.id (K X) ℂ.⊗₁ ϕ⁰ ℂ.▷ ϕ-at X 𝕂.I

    -- conditions on morphisms
    -- preserve⊗ is the exact same as ϕ-naturality!
    preserveI₁ :  ϕ⁰ ℂ.▷ K₁ 𝕂.jd ℂ.≤ ℂ.I₁ ℂ.▷ ϕ⁰
    preserve⊗₁ : {X Y U V : 𝕂.obj} {f : 𝕂.hom X Y} {g : 𝕂.hom U V}
                   ϕ-at X U ℂ.▷ K₁ (f 𝕂.∥ g) ℂ.≤ K₁ f ℂ.⊗₁ K₁ g ℂ.▷ ϕ-at Y V 

-- since this 'template' is only made for J, we have it very specific on purpose
-- it's param since it needs to be identity on objects and then Monoidal to MonoidalLike
record IsJOplaxMonoidalFunctor {obj : Set} {_⊗₀_ : obj × obj  obj} {I₀ :   obj}
       { : ParamMonoidalCategory obj _⊗₀_ I₀} {𝕂 : ParamMonoidalLikeCategory obj _⊗₀_ I₀}
       (funcJ : ParamFunctor (ParamMonoidalCategory.P ) (ParamMonoidalLikeCategory.P 𝕂)  C  C)): Set where
  module  = ParamMonoidalCategory 
  module 𝕂 = ParamMonoidalLikeCategory 𝕂
  J : obj  obj
  J = λ C  C
  open ParamFunctor funcJ renaming (F₁ to J₁)
  _∥_ = 𝕂._∥_
  field
    ω-at : (A B : ℂ.obj)  𝕂.hom (J (A ℂ.⊗ B)) (J A 𝕂.⊗ J B)
    ω-naturality : {A B C D : ℂ.obj} {f1 : ℂ.hom A B} {f2 : ℂ.hom C D}
                       J₁ (f1 ℂ.⊗₁ f2) 𝕂.▷ ω-at B D 𝕂.≤ ω-at A C 𝕂.▷ J₁ f1  J₁ f2
    ω⁰ : 𝕂.hom (J ℂ.I) 𝕂.I
    oplaxAssoc : {X Y Z : ℂ.obj}
       ω-at (X ℂ.⊗ Y) Z 𝕂.▷ ω-at X Y  𝕂.id (J Z) 𝕂.▷ J₁ (ℂ.α-at (J X) (J Y) (J Z))
         (J₁ (ℂ.α-at X Y Z) 𝕂.▷ ω-at X (Y ℂ.⊗ Z) 𝕂.▷ 𝕂.id (J X)  ω-at Y Z)
    oplaxLunital : {X : ℂ.obj}  J₁ (ℂ.λ-at X)
         ω-at ℂ.I X 𝕂.▷ ω⁰  𝕂.id (J X) 𝕂.▷ J₁ (ℂ.λ-at (J X))
    oplaxRunital : {X : ℂ.obj}  J₁ (ℂ.ρ-at (J X))
         J₁ (ℂ.ρ-at X) 𝕂.▷ ω-at X ℂ.I 𝕂.▷ 𝕂.id (J X)  ω⁰

    preserveI₁ : J₁ ℂ.I₁ 𝕂.≤ 𝕂.jd
    preserve⊗₁ : {X Y U V : ℂ.obj} (f : ℂ.hom X Y) (g : ℂ.hom U V)
                   J₁ (f ℂ.⊗₁ g) 𝕂.≤ J₁ f  J₁ g
                  
record JFunctor
       {c : Set} {⊗₀ : c × c  c} {I₀ :   c}
       ( : ParamMonoidalCategory c ⊗₀ I₀)
       (𝕂 : ParamMonoidalLikeCategory c ⊗₀ I₀)  : Set where
  field
    F : ParamFunctor (ParamMonoidalCategory.P ) (ParamMonoidalLikeCategory.P 𝕂)  C  C)
    isJOplaxMonoidalFunctor : IsJOplaxMonoidalFunctor {c} {⊗₀} {I₀} {} {𝕂} F
  open ParamFunctor F public

record KFunctor {c : Set} {⊗₀ : c × c  c} {I₀ :   c}
           (𝕂 : ParamMonoidalLikeCategory c ⊗₀ I₀) ( : ParamMonoidalCategory c ⊗₀ I₀) (J : JFunctor  𝕂) : Set where
  field
    F : Functor (ParamMonoidalLikeCategory.U 𝕂) (ParamMonoidalCategory.U )
    isKLaxMonoidalFunctor : IsKLaxMonoidalFunctor {c} {⊗₀} {I₀} {𝕂} {} (JFunctor.F J) F
  open Functor F public
  open IsKLaxMonoidalFunctor isKLaxMonoidalFunctor public

record IsConcurrentCategory
       {c : Set} {⊗₀ : c × c  c} {I₀ :   c}
       ( : ParamMonoidalCategory c ⊗₀ I₀) (𝕂 : ParamMonoidalLikeCategory c ⊗₀ I₀)
       (funcJ : JFunctor  𝕂) : Set where
  open JFunctor funcJ renaming (F₁ to J₁)
  private
    module  = ParamMonoidalCategory 
    module 𝕂 = ParamMonoidalLikeCategory 𝕂
  open ParamMonoidalCategory  using (_⊗₁_)
  open ParamMonoidalLikeCategory 𝕂 using (_∥_; jd; _▷_)
  field
    λ-naturality :  {A B} {f : 𝕂.hom A B}  J₁ (ℂ.λ-at A)  f  jd  f  J₁ (ℂ.λ-at B)
    ρ-naturality :  {A B} {f : 𝕂.hom A B}  J₁ (ℂ.ρ-at A)  f  jd  f  J₁ (ℂ.ρ-at B)
    α-naturality :  {A B C X Y Z} {f : 𝕂.hom A X} {g : 𝕂.hom B Y} {h : 𝕂.hom C Z}
       (f  g)  h  J₁ (ℂ.α-at X Y Z)  J₁ (ℂ.α-at A B C)  f  (g  h)
    ich4a :  {A B C X Y Z} {f : ℂ.hom A B} {g : ℂ.hom X Y}
                            {m : 𝕂.hom B C} {n : 𝕂.hom Y Z}
             J₁ (f ⊗₁ g)  (m  n)  (J₁ f  m)  (J₁ g  n)
    ich4b :  {A B C X Y Z} {k : 𝕂.hom A B} { : 𝕂.hom X Y}
                            {h : ℂ.hom B C} {i : ℂ.hom Y Z}
             (k  )  J₁ (h ⊗₁ i)  (k  J₁ h)  (  J₁ i)


record ConcurrentCategory ( : MonoidalCategory) : Set where
  open MonoidalCategory 
  field
    𝕂 : ParamMonoidalLikeCategory obj MonoidalProduct₀ Identity₀
    J : JFunctor P-monoidal 𝕂 
    isConcurrentCategory : IsConcurrentCategory P-monoidal 𝕂 J
  𝕂-contained : MonoidalLikeCategory
  𝕂-contained = record
    { c = obj
    ; t⊗₀ = MonoidalProduct₀
    ; tI₀ = Identity₀
    ; P-monoidallike = 𝕂
    }
  open IsConcurrentCategory isConcurrentCategory public

-- the base is a monoidal category but the functor structure is not necessarily monidal
record IsConcurrentMonad { : MonoidalCategory}
       (M : Functor (MonoidalCategory.U )
                    (MonoidalCategory.U )) : Set where
  open MonoidalCategory 
  open Functor M public
  F = F₀
  field
    η-at : (C : obj)  hom C (F C)
    η-naturality : {C D : obj}  {f : hom C D}
       f  η-at D  η-at C  F₁ f
    μ-at : (C : obj)  hom (F (F C)) (F C)
    μ-naturality : {C D : obj}  {f : hom C D}
       F₁ (F₁ f)  μ-at D  μ-at C  F₁ f
    ψ⁰ : hom I (F I)
    ψ-at : (X Y : obj)  hom (F X  F Y) (F (X  Y))
    ψ-naturality : {X Y Z W : obj}  {f : hom X Y}  {g : hom Z W}
       F₁ f ⊗₁ F₁ g  ψ-at Y W  ψ-at X Z  F₁ (f ⊗₁ g)

    diagram1 : {X : obj}  η-at (F X)  μ-at X  id (F X)
    diagram2 : {X : obj}  F₁ (η-at X)  μ-at X  id (F X)
    diagram3 : {X : obj}  F₁ (μ-at X)  μ-at X  μ-at (F X)  μ-at X
    diagram4 : {X : obj}  λ-at (F X)
              ψ⁰ ⊗₁ id (F X)  ψ-at I X  F₁ (λ-at X)
    diagram5 : {X : obj}  ρ-at (F X)  id (F X) ⊗₁ ψ⁰  ψ-at X I
                        F₁ (ρ-at X)
    diagram6 : {X Y Z : obj}  α-at (F X) (F Y) (F Z)  id (F X) ⊗₁ ψ-at Y Z
                                   ψ-at X (Y  Z)
                            ψ-at X Y ⊗₁ id (F Z)  ψ-at (X  Y) Z  F₁ (α-at X Y Z)
    inequation1 : η-at I  ψ⁰
    inequation2 : ψ⁰  F₁ ψ⁰  μ-at I  ψ⁰
    inequation3 : {X Y : obj}  η-at (X  Y)  η-at X ⊗₁ η-at Y  ψ-at X Y
    inequation4 : {X Y : obj}  ψ-at (F X) (F Y)  F₁ (ψ-at X Y)  μ-at (X  Y)
                                 μ-at X ⊗₁ μ-at Y  ψ-at X Y

record ConcurrentMonad (this-ℂ : MonoidalCategory) : Set where
  module  = MonoidalCategory this-ℂ
  field
    M : Functor ℂ.U ℂ.U
    isConcurrentMonad : IsConcurrentMonad {this-ℂ} M
  open IsConcurrentMonad isConcurrentMonad public