module Cat.Monoidal.Instances.Day
  {ℓ} {C : Precategory ℓ ℓ} (cmon : Monoidal-category C)
  where

The Day convolution product🔗

The Day convolution monoidal structure on is the free cocompletion of a small monoidal category within the context of monoidal categories: its monoidal cocompletion. This uniquely determines the construction of which is perhaps sufficient motivation to a category theorist. However, it’s worth pointing out that the Day convolution comes up in practice surprisingly often, so that the motivation for this page does not rest entirely on abstract nonsense. Here are a few examples, before we get started:

  • Automata theory: If we have a set which we call the alphabet, then, as usual, we call a subset a language on Languages are closed under the generic operations of intersection and union of subsets, but we also have an operation specific to this domain: concatenation, which arises from the free monoid structure on

    More concretely, the concatenation is the subset which, expressed as a predicate, has value

    That is, the words belonging to are precisely those which decompose as a concatenation of a word from followed by a word from The operation of concatenation preserves joins in each variable: We can calculate

    and the other variable is symmetric. To give a concrete example, we can define the Kleene star where denotes the composition. Then our cocontinuity result says that we can compute concatenation with a star as a union of simpler concatenations. For example, an enumeration of starts

  • Algebra: if we have a group and a ring there is a universal way to equip the free module with a multiplication that makes it into a ring, and where this multiplication is also in each variable: the group , which we also refer to as For simplicity, let us assume that is a finite group.

    Note that, since is finite, we can take the elements of to simply be arbitrary functions If we think of as a polynomial, then we associate to it the function that sends each to the element which appears as its coefficient. In the other direction, an assignment of coefficients determines the polynomial

    The multiplication on is determined uniquely by the requirement that it extends the multiplication on in an way: for polynomials we should have

    It is not immediately obvious that we can rewrite this double summation in “coefficient form”. But if we recall the diagonal function defined so that if (and otherwise), then we can express this as

    since, intuitively, we have = since, for each value of if we do not have then the summand is equal to zero.

Drawing a generalisation from the cases above, we can equip the collection of functions with a monoid structure whenever and are monoids, and admits an operation for aggregation over , to play the role of the existential quantifier and summation. Writing for this aggregation operation, the product is given pointwise by

This operation is generally referred to as the convolution product of and and it can be seen as the special case of the Day convolution where the domain is a discrete category.

For those curious but unfamiliar with the abstract nonsense, we should explain what, exactly, is meant by monoidal cocompletion: in addition to showing that is cocomplete, and equipping it with a monoidal structure we must show that these behave nicely together:
  • The tensor product we construct must be cocontinuous in each variable;

  • Our chosen cocompletion which in this case is the Yoneda embedding must be a strong monoidal functor: We should have 1

As usual when we have an object defined by a universal property, the Day convolution monoidal structure is unique: making this particular case explicit, given any other monoidal cocompletion we have a unique equivalence of monoidal categories Among the univalent monoidal categories, we may sharpen this result to saying that has a contractible space of monoidal cocompletions.

The construction🔗

We will interpret the formula above literally, relying on the fact that coends are also written with an integral sign. To generalise away from a discrete domain, we must express the idea of decomposing an object into parts without the use of equality. An obvious idea would be isomorphism, but this turns out to be too strong: we can simply take the product with the into the product:

\ Warning

It’s worth taking a second to read the formalised definition, below, if you are unfamiliar with coends. We must express the “integrand” as a functor This provides us with “polarised” versions of the variables which we write and

We then distribute these variables according to the polarities of each functor. Since is covariant in its second argument, it sees but the presheaves are contravariant, so we have factors and

module Day (X Y : ⌞ PSh ℓ C ⌟) where
  Day-diagram : Ob → Functor ((C Ă—á¶œ C) ^op Ă—á¶œ (C Ă—á¶œ C)) (Sets ℓ)
  ∣ Day-diagram c .F₀ ((c₁⁻ , c₂⁻) , c₁âș , c₂âș) ∣ = Hom c (c₁âș ⊗ c₂âș) × (X Ê» c₁⁻) × (Y Ê» c₂⁻)
  opaque
    Day-coend : (c : Ob) → Coend (Day-diagram c)
    Day-coend c = Set-coend (Day-diagram c)

We shall now repeat some of our knowledge about coends valued in sets, but specialised to the case of the Day convolution. First, we note that we can write the elements of the coend (at as triples where and

    day : {i a b : Ob} (h : Hom i (a ⊗ b)) (x : X ʻ a) (y : Y ʻ b) → Day.nadir ʻ i
    day h x y = inc ((_ , _) , h , x , y)

Moreover, these triples have identifications generated by letting be whenever these both make sense. More generally, we have equal to whenever

    day-glue
      : {i a b a' b' : Ob} {f : Hom a' a} {g : Hom b' b} {h : Hom i (a' ⊗ b')} {x : X ʻ a} {y : Y ʻ b}
      → {fgh : Hom i (a ⊗ b)} (p : fgh ≡ (f ⊗₁ g) ∘ h)
      → day fgh x y ≡ day h (X .F₁ f x) (Y .F₁ g y)
    day-glue {i} {a} {b} {a'} {b'} {f} {g} {h} {x} {y} {fgh} p =
      day fgh x y                                  ≡⟹ day-ap p (sym (X .F-id) #ₚ x) (sym (Y .F-id) #ₚ y) âŸ©â‰Ą
      day ((f ⊗₁ g) ∘ h) (X .F₁ id x) (Y .F₁ id y) ≡⟹ Coeq.glue {f = dimapl (Day-diagram i)} {g = dimapr (Day-diagram i)} ((a , b) , (a' , b') , (f , g) , h , x , y) âŸ©â‰Ą
      day ((id ⊗₁ id) ∘ h) (X .F₁ f x) (Y .F₁ g y) ≡⟹ day-apₘ (eliml ⊗.F-id) âŸ©â‰Ą
      day h (X .F₁ f x) (Y .F₁ g y)                ∎

Finally, we will use the formalism of cowedges to define functions out of Essentially, this says that we can define a function whenever we can define in a way compatible with the relation above.

    factor : ∀ {i} (W : Cowedge (Day-diagram i)) → Day.nadir ʻ i → ⌞ W .nadir ⌟
    factor W = Day.factor _ W
    factor-day
      : ∀ {i a b} {W : Cowedge (Day-diagram i)} {h : Hom i (a ⊗ b)} {x : X ʻ a} {y : Y ʻ b}
      → factor W (day h x y) ≡rw W .ψ (a , b) (h , x , y)
    factor-day = idrw

  {-# REWRITE factor-day #-}

  -- To have better type inference we define the Day-coend and its
  -- associated projections as opaque symbols. Agda will treat them as
  -- injective so e.g. an equation between `Day.nadir F G i = Day.nadir
  -- ? ? ?` will actually solve those three metas.
  --
  -- But, of course, opaque symbols don't compute, and we'd really
  -- really like to have `factor W (day h x y) = W .ψ h x y`. One
  -- approach would be to lift everything that needs this definitional
  -- equality into an opaque block, but that would massively bloat the
  -- file with mandatory type signatures.
  --
  -- Rewrite rules to the rescue: `factor-day` allows us to "export" the
  -- computation rule for `factor W (day ...)` without exposing the
  -- computational behaviour of any other of the symbols here.

  instance
    Extensional-day-map
      : ∀ {i ℓ' ℓr} {C : Type ℓ'} ⩃ _ : H-Level C 2 ⩄
      → ⊃ sf : ∀ {a b} → Extensional ((h : Hom i (a ⊗ b)) (x : X Ê» a) (y : Y Ê» b) → C) ℓr ⩄
      → Extensional (⌞ Day.nadir i ⌟ → C) (ℓ ⊔ ℓr)
    Extensional-day-map {i} {C = C} ⩃ sf ⩄ = done where
      T : Type _
      T = {a b : Ob} (h : Hom i (a ⊗ b)) (x : X ʻ a) (y : Y ʻ b) → C

      unday : (⌞ Day.nadir i ⌟ → C) → T
      unday f h x y = f (day h x y)

      opaque
        unfolding Day-coend day

        to-p : ∀ {f g} → Path T (unday f) (unday g) → f ≡ g
        to-p p = ext λ a b h x y i → p i {a} {b} h x y

      done : Extensional (⌞ Day.nadir i ⌟ → C) _
      done = injection→extensional (hlevel 2) to-p auto

  day-swap
    : ∀ {i a b a' b'} {f : Hom a' a} {g : Hom b' b} {h : Hom i (a' ⊗ b')}
        {a'' b''} {f' : Hom a'' a} {g' : Hom b'' b} {h' : Hom i (a'' ⊗ b'')}
        {x : X Ê» a} {y : Y Ê» b}
    → (f ⊗₁ g) ∘ h ≡ (f' ⊗₁ g') ∘ h'
    → day h (X .F₁ f x) (Y .F₁ g y) ≡ day h' (X .F₁ f' x) (Y .F₁ g' y)
  day-swap p = sym (day-glue refl) ·· day-apₘ p ·· day-glue refl

As an example of constructing a map using cowedges, we can construct the restriction given Pointwise, this sends to It’s a straightforward-but-annoying calculation to show that this extends to the quotient.

  Day-cowedge : ∀ {x} {y} → Hom y x → Cowedge (Day-diagram x)
  Day-cowedge {y = y} h .nadir = Day.nadir y
  Day-cowedge h .ψ (a , b) (f , x , y) = day (f ∘ h) x y
  Day-cowedge h .extranatural {a , b} {a' , b'} (f , g) = funext λ (i , x , y) →
    day (((f ⊗₁ g) ∘ i) ∘ h) (X .F₁ id x) (Y .F₁ id y) ≡⟹ day-ap refl (X .F-id #ₚ x) (Y .F-id #ₚ y) âŸ©â‰Ą
    day (((f ⊗₁ g) ∘ i) ∘ h) x y                       ≡⟹ day-glue (sym (assoc _ _ _)) âŸ©â‰Ą
    day (i ∘ h) (X .F₁ f x) (Y .F₁ g y)                ≡⟹ day-apₘ (introl ⊗.F-id ∙ assoc _ _ _) âŸ©â‰Ą
    day (((id ⊗₁ id) ∘ i) ∘ h) (X .F₁ f x) (Y .F₁ g y) ∎

  _⊗᮰_ : ⌞ PSh ℓ C ⌟
  _⊗᮰_ .F₀ c = Day.nadir c
  _⊗᮰_ .F₁ {x} {y} h v = factor (Day-cowedge h) v
  _⊗᮰_ .F-id    = ext λ h x y → day-apₘ (idr h)
  _⊗᮰_ .F-∘ f g = ext λ h x y → day-apₘ (assoc h g f)
Together with some quick functoriality proofs, we have shown above that the Day convolution is a presheaf. If we have natural transformations and then we can extend these to a so that we actually have a functor This is but another annoying calculation.
Day-bifunctor-cowedge
  : ∀ {X Y X' Y' : ⌞ PSh ℓ C ⌟} {i}
  → X => X'
  → Y => Y'
  → Cowedge (Day-diagram X Y i)
Day-bifunctor-cowedge {X} {Y} {X'} {Y'} {i} F G = go where
  private module D = Day X' Y'
  go : Cowedge (Day-diagram X Y i)
  go .nadir           = D.nadir i
  go .ψ c (h , x , y) = D.day h (F .η _ x) (G .η _ y)
  go .extranatural (f , g) = ext λ h x y →
    D.day ((f ⊗₁ g) ∘ h)   (F .η _ (X .F₁ id x))   (G .η _ (Y .F₁ id y))   ≡⟹ D.day-ap refl (F .is-natural _ _ id #ₚ _) (G .is-natural _ _ id #ₚ _) âŸ©â‰Ą
    D.day ((f ⊗₁ g) ∘ h)   (X' .F₁ id (F .η _ x))  (Y' .F₁ id (G .η _ y))  ≡⟹ D.day-swap (extendl (eliml ⊗.F-id ∙ intror ⊗.F-id)) âŸ©â‰Ą
    D.day ((id ⊗₁ id) ∘ h) (X' .F₁ f (F .η _ x))   (Y' .F₁ g (G .η _ y))   ≡˘⟹ D.day-ap refl (F .is-natural _ _ f #ₚ _) (G .is-natural _ _ g #ₚ _) âŸ©â‰ĄË˜
    D.day ((id ⊗₁ id) ∘ h) (F .η _ (X .F₁ f x))    (G .η _ (Y .F₁ g y))    ∎

Day-map : ∀ {X X' Y Y'} (F : X => X') (G : Y => Y') → X ⊗᮰ Y => X' ⊗᮰ Y'
Day-map F G .η i = Day-rec (Day-bifunctor-cowedge F G)
Day-map F G .is-natural x y f = trivial!

Day-bifunctor : Functor (PSh ℓ C Ă—á¶œ PSh ℓ C) (PSh ℓ C)
Day-bifunctor .F₀ (X , Y) = X ⊗᮰ Y
Day-bifunctor .F₁ (F , G) = Day-map F G
Day-bifunctor .F-id    = trivial!
Day-bifunctor .F-∘ f g = trivial!

The monoidal structure🔗

The rest of this module is devoted to showing that the Day convolution is actually a monoidal structure: that is, we have unitors and an associator, which satisfy the triangle and pentagon identities. We will give an overview of the constructor of the right unitor, It’s a representative example of the nasty calculations to come.

Fixing a presheaf and coordinate we want to show that

is isomorphic to Were we not working in a proof assistant, we could do this by coend calculus: it’s an instance of the Yoneda lemma. However, it will be much easier in the long run to bang out an explicit isomorphism. At the level of points, we are given and We must produce an element of The composite

acts on to give us precisely the element we want. In the other direction, we can send to We can then perform the extremely annoying calculations to show that (a) this map extends to the coend, (b) the resulting map is a natural transformation, and (c) the inverse construction we sketched is actually an inverse.

module _ (X : ⌞ PSh ℓ C ⌟) where
  idr-to-cowedge : ∀ x → Cowedge (Day-diagram X (よ₀ C Unit) x)
  idr-to-cowedge i .nadir = X # i
  idr-to-cowedge i .ψ (a , b) (h , x , y) = X .F₁ (ρ← ∘ (id ⊗₁ y) ∘ h) x
  idr-to-cowedge i .extranatural {a , b} {a' , b'} (f , g) = ext λ h x y →
    X .F₁ (ρ← ∘ (id ⊗₁ y ∘ id) ∘ (f ⊗₁ g) ∘ h) (X .F₁ id x) ≡⟹ ap₂ (X .F₁) (ap (ρ← ∘_) (⊗.pulll (ap₂ _,_ (idl f) (ap (_∘ g) (idr y))))) refl âŸ©â‰Ą
    X .F₁ (ρ← ∘ (f ⊗₁ y ∘ g) ∘ h) (X .F₁ id x)              ≡⟹ ap₂ (X .F₁) (ap (ρ← ∘_) (⊗.pushl (ap₂ _,_ (intror refl) (introl refl)))) refl âŸ©â‰Ą
    X .F₁ (ρ← ∘ (f ⊗₁ id) ∘ (id ⊗₁ y ∘ g) ∘ h) (X .F₁ id x) ≡⟹ ap₂ (X .F₁) (extendl (unitor-r .Isoⁿ.from .is-natural a a' f)) refl âŸ©â‰Ą
    X .F₁ (f ∘ ρ← ∘ (id ⊗₁ y ∘ g) ∘ h) (X .F₁ id x)         ≡⟹ X .F-∘ _ _ #ₚ _ âŸ©â‰Ą
    X .F₁ (ρ← ∘ (id ⊗₁ y ∘ g) ∘ h) (X .F₁ f (X .F₁ id x))   ≡⟹ ap₂ (X .F₁) (ap (ρ← ∘_) (ap₂ _∘_ refl (introl ⊗.F-id))) (ap (X .F₁ f) (X .F-id #ₚ x)) âŸ©â‰Ą
    X .F₁ (ρ← ∘ (id ⊗₁ y ∘ g) ∘ (id ⊗₁ id) ∘ h) (X .F₁ f x) ∎

  Day-idr : X ⊗᮰ よ₀ C Unit ≅ⁿ X
  Day-idr = to-natural-iso mk-idr where
    mk-idr : make-natural-iso (X ⊗᮰ よ₀ C Unit) X
    mk-idr .eta x   = Day-rec (idr-to-cowedge x)
    mk-idr .inv x a = day ρ→ a id
    mk-idr .eta∘inv x = ext λ a → ap₂ (X .F₁) (ap (ρ← ∘_) (eliml ⊗.F-id) ∙ unitor-r .Isoⁿ.invr ηₚ _) refl ∙ (X .F-id #ₚ a)
    mk-idr .inv∘eta i = ext λ h x y →
      day ρ→ (X .F₁ (ρ← ∘ (id ⊗₁ y) ∘ h) x) id          ≡⟹ day-ap refl refl (introl refl) âŸ©â‰Ą
      day ρ→ (X .F₁ (ρ← ∘ (id ⊗₁ y) ∘ h) x) (id ∘ id)   ≡⟹ day-swap (sym (unitor-r .Isoⁿ.to .is-natural _ _ _) ∙ cancell (unitor-r .Isoⁿ.invl ηₚ _)) âŸ©â‰Ą
      day h (X .F₁ id x) (id ∘ y)                       ≡⟹ day-ap refl (X .F-id #ₚ x) (idl y) âŸ©â‰Ą
      day h x y                                         ∎
    mk-idr .natural x y f = ext λ h x y →
      X .F₁ f (X .F₁ (ρ← ∘ (id ⊗₁ y) ∘ h) x) ≡⟹ sym (X .F-∘ _ _) #ₚ _ âŸ©â‰Ą
      X .F₁ ((ρ← ∘ (id ⊗₁ y) ∘ h) ∘ f) x     ≡⟹ ap₂ (X .F₁) (pullr (pullr refl)) refl âŸ©â‰Ą
      X .F₁ (ρ← ∘ (id ⊗₁ y) ∘ h ∘ f) x       ∎

This completes the construction of the right unitor. It also completes the commentary on this module: the construction of the left unitor, is analogous: just flip everything. The construction of the associator must be done in steps. However, at the level of points, these are all trivial operations, and the vast majority of this module is dedicated to (extra)naturality conditions and proofs of isomorphy.

module _ (Y : ⌞ PSh ℓ C ⌟) where
  idl-to-cowedge : ∀ x → Cowedge (Day-diagram (よ₀ C Unit) Y x)
  idl-to-cowedge i .nadir = Y # i
  idl-to-cowedge i .ψ (a , b) (h , x , y) = Y .F₁ (λ← ∘ (x ⊗₁ id) ∘ h) y
  idl-to-cowedge i .extranatural {a , b} {a' , b'} (f , g) = ext λ h x y →
       ap₂ (Y .F₁) (ap (λ← ∘_) (⊗.extendl (ap₂ _,_ (ap (_∘ f) (idr x) ∙ introl refl) id-comm-sym)) ∙ extendl (unitor-l .Isoⁿ.from .is-natural _ _ _)) (Y .F-id #ₚ y)
    ·· (Y .F-∘ _ _ #ₚ y)
    ·· ap₂ (Y .F₁) (ap (λ← ∘_) (ap₂ _∘_ refl (introl ⊗.F-id))) refl

  Day-idl : よ₀ C Unit ⊗᮰ Y ≅ⁿ Y
  Day-idl = to-natural-iso mk-idl where
    mk-idl : make-natural-iso (よ₀ C Unit ⊗᮰ Y) Y
    mk-idl .eta x = Day-rec (idl-to-cowedge x)
    mk-idl .inv x a = day λ→ id a
    mk-idl .eta∘inv x = ext λ a → ap₂ (Y .F₁) (ap (λ← ∘_) (eliml ⊗.F-id) ∙ unitor-l .Isoⁿ.invr ηₚ _) refl ∙ (Y .F-id #ₚ a)
    mk-idl .inv∘eta i = ext λ h x y →
      day λ→ id (Y .F₁ (λ← ∘ (x ⊗₁ id) ∘ h) y)        ≡⟹ day-ap refl (introl refl) refl âŸ©â‰Ą
      day λ→ (id ∘ id) (Y .F₁ (λ← ∘ (x ⊗₁ id) ∘ h) y) ≡⟹ day-swap (sym (unitor-l .Isoⁿ.to .is-natural _ _ _) ∙ cancell (unitor-l .Isoⁿ.invl ηₚ _)) âŸ©â‰Ą
      day h (id ∘ x) (Y .F₁ id y)                     ≡⟹ day-ap refl (idl x) (Y .F-id #ₚ y) âŸ©â‰Ą
      day h x y                                       ∎
    mk-idl .natural = λ x y f → ext λ h x y →
      Y .F₁ f (Y .F₁ (λ← ∘ (x ⊗₁ id) ∘ h) y) ≡˘⟹ Y .F-∘ _ _ #ₚ _ âŸ©â‰ĄË˜
      Y .F₁ ((λ← ∘ (x ⊗₁ id) ∘ h) ∘ f) y     ≡⟹ ap₂ (Y .F₁) (pullr (pullr refl)) refl âŸ©â‰Ą
      Y .F₁ (λ← ∘ (x ⊗₁ id) ∘ h ∘ f) y       ∎

module _ (X Y Z : ⌞ PSh ℓ C ⌟) where
  assoc-to₀ : ∀ i {a b} (h : Hom i (a ⊗ b)) (z : Z ʻ b) → Cowedge (Day-diagram X Y a)
  assoc-to₀ i h z .nadir = Day.nadir X (Y ⊗᮰ Z) i
  assoc-to₀ i h z .ψ (a' , b') (h' , x , y) = day (α→ _ _ _ ∘ (h' ⊗₁ id) ∘ h) x (day id y z)
  assoc-to₀ i h z .extranatural (f , g) = ext λ h' x y →
    day (α→ _ _ _ ∘ ((f ⊗₁ g) ∘ h' ⊗₁ id) ∘ h) (X .F₁ id x) (day id (Y .F₁ id y) z)  ≡⟹ day-ap (ap (α→ _ _ _ ∘_) (⊗.pushl (ap₂ _,_ refl (introl refl)))) (X .F-id #ₚ x) (day-ap refl (Y .F-id #ₚ y) refl) âŸ©â‰Ą
    day (α→ _ _ _ ∘ ((f ⊗₁ g) ⊗₁ id) ∘ (h' ⊗₁ id) ∘ h) x (day id y z)                ≡⟹ day-apₘ (extendl (associator .Isoⁿ.to .is-natural _ _ _)) âŸ©â‰Ą
    day ((f ⊗₁ (g ⊗₁ id)) ∘ α→ _ _ _ ∘ (h' ⊗₁ id) ∘ h) x (day id y z)                ≡⟹ day-glue refl âŸ©â‰Ą
    day (α→ _ _ _ ∘ (h' ⊗₁ id) ∘ h) (X .F₁ f x) (day (id ∘ (g ⊗₁ id)) y z)           ≡⟹ day-ap (ap (α→ _ _ _ ∘_) (ap (_∘ h) (ap₂ _⊗₁_ (introl ⊗.F-id) refl))) refl (day-apₘ id-comm-sym ·· day-glue refl ·· day-ap refl refl (Z .F-id #ₚ z)) âŸ©â‰Ą
    day (α→ _ _ _ ∘ ((id ⊗₁ id) ∘ h' ⊗₁ id) ∘ h) (X .F₁ f x) (day id (Y .F₁ g y) z)  ∎

  assoc-to-cowedge : ∀ i → Cowedge (Day-diagram (X ⊗᮰ Y) Z i)
  assoc-to-cowedge i .nadir = Day.nadir X (Y ⊗᮰ Z) i
  assoc-to-cowedge i .ψ (a , b) (h , x , y) = Day-rec (assoc-to₀ i h y) x
  assoc-to-cowedge i .extranatural (f , g) = ext λ h h' x y z →
    day (α→ _ _ _ ∘ (h' ∘ id ⊗₁ id) ∘ (f ⊗₁ g) ∘ h) x (day id y (Z .F₁ id z))   ≡⟹ day-ap (ap (α→ _ _ _ ∘_) (⊗.extendl (ap₂ _,_ (ap (_∘ f) (idr h') ∙ introl ⊗.F-id) id-comm-sym))) refl (day-ap refl refl (Z .F-id #ₚ z)) âŸ©â‰Ą
    day (α→ _ _ _ ∘ ((id ⊗₁ id) ⊗₁ g) ∘ (h' ∘ f ⊗₁ id) ∘ h) x (day id y z)      ≡⟹ day-apₘ (extendl (associator .Isoⁿ.to .is-natural _ _ _)) âŸ©â‰Ą
    day ((id ⊗₁ (id ⊗₁ g)) ∘ α→ _ _ _ ∘ (h' ∘ f ⊗₁ id) ∘ h) x (day id y z)      ≡⟹ day-glue refl âŸ©â‰Ą
    day (α→ _ _ _ ∘ (h' ∘ f ⊗₁ id) ∘ h) (X .F₁ id x) (day (id ∘ (id ⊗₁ g)) y z) ≡⟹ day-ap (ap (α→ _ _ _ ∘_) (ap₂ _∘_ refl (introl ⊗.F-id))) (X .F-id #ₚ x) (day-glue id-comm-sym ∙ day-ap refl (Y .F-id #ₚ y) refl) âŸ©â‰Ą
    day (α→ _ _ _ ∘ (h' ∘ f ⊗₁ id) ∘ (id ⊗₁ id) ∘ h) x (day id y (Z .F₁ g z))   ∎

  assoc-from₀ : ∀ i {a b} (h : Hom i (a ⊗ b)) (x : X ʻ a) → Cowedge (Day-diagram Y Z b)
  assoc-from₀ i h x .nadir = Day.nadir (X ⊗᮰ Y) Z i
  assoc-from₀ i h x .ψ (a' , b') (h' , y , z) = day (α← _ _ _ ∘ (id ⊗₁ h') ∘ h) (day id x y) z
  assoc-from₀ i h x .extranatural (f , g) = ext λ h' y z →
    day (α← _ _ _ ∘ (id ⊗₁ ((f ⊗₁ g) ∘ h')) ∘ h) (day id x (Y .F₁ id y)) (Z .F₁ id z) ≡⟹ day-ap (extendl (pushr (ap₂ _⊗₁_ (introl refl) refl ∙ ⊗.F-∘ _ _) ·· pullr refl ·· extendl (associator .Isoⁿ.from .is-natural _ _ _))) (day-ap refl refl (Y .F-id #ₚ y)) (Z .F-id #ₚ z) âŸ©â‰Ą
    day (((id ⊗₁ f) ⊗₁ g) ∘ (α← _ _ _ ∘ (id ⊗₁ h')) ∘ h) (day id x y) z               ≡⟹ day-glue refl âŸ©â‰Ą
    day ((α← _ _ _ ∘ (id ⊗₁ h')) ∘ h) (day (id ∘ (id ⊗₁ f)) x y) (Z .F₁ g z)          ≡⟹ day-ap (pullr (ap (_∘ h) (ap₂ _⊗₁_ refl (introl ⊗.F-id)))) (day-glue id-comm-sym ∙ day-ap refl (X .F-id #ₚ x) refl) refl âŸ©â‰Ą
    day (α← _ _ _ ∘ (id ⊗₁ ((id ⊗₁ id) ∘ h')) ∘ h) (day id x (Y .F₁ f y)) (Z .F₁ g z) ∎

  assoc-from-cowedge : ∀ i → Cowedge (Day-diagram X (Y ⊗᮰ Z) i)
  assoc-from-cowedge i .nadir = Day.nadir (X ⊗᮰ Y) Z i
  assoc-from-cowedge i .ψ (a , b) (h , x , y) = Day-rec (assoc-from₀ i h x) y
  assoc-from-cowedge i .extranatural (f , g) = ext λ h x h' y z →
    day (α← _ _ _ ∘ (id ⊗₁ h' ∘ id) ∘ (f ⊗₁ g) ∘ h) (day id (X .F₁ id x) y) z   ≡⟹ day-ap (ap (α← _ _ _ ∘_) (⊗.extendl (ap₂ _,_ id-comm-sym (ap (_∘ g) (idr h') ∙ introl ⊗.F-id)))) (day-ap refl (X .F-id #ₚ _) refl) refl âŸ©â‰Ą
    day (α← _ _ _ ∘ (f ⊗₁ (id ⊗₁ id)) ∘ (id ⊗₁ h' ∘ g) ∘ h) (day id x y) z      ≡⟹ day-apₘ (extendl (associator .Isoⁿ.from .is-natural _ _ _)) âŸ©â‰Ą
    day (((f ⊗₁ id) ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ h' ∘ g) ∘ h) (day id x y) z      ≡⟹ day-glue refl âŸ©â‰Ą
    day (α← _ _ _ ∘ (id ⊗₁ h' ∘ g) ∘ h) (day (id ∘ (f ⊗₁ id)) x y) (Z .F₁ id z) ≡⟹ day-ap (ap (α← _ _ _ ∘_) (ap₂ _∘_ refl (introl ⊗.F-id))) (day-glue id-comm-sym ∙ day-ap refl refl (Y .F-id #ₚ y)) (Z .F-id #ₚ z) âŸ©â‰Ą
    day (α← _ _ _ ∘ (id ⊗₁ h' ∘ g) ∘ (id ⊗₁ id) ∘ h) (day id (X .F₁ f x) y) z   ∎

  Day-assoc : (X ⊗᮰ Y) ⊗᮰ Z ≅ⁿ X ⊗᮰ (Y ⊗᮰ Z)
  Day-assoc = to-natural-iso mk-assoc where
    mk-assoc : make-natural-iso ((X ⊗᮰ Y) ⊗᮰ Z) (X ⊗᮰ (Y ⊗᮰ Z))
    mk-assoc .eta x = Day-rec (assoc-to-cowedge x)
    mk-assoc .inv x = Day-rec (assoc-from-cowedge x)
    mk-assoc .eta∘inv x = ext λ h x h' y z →
      day (α→ _ _ _ ∘ (id ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ h') ∘ h) x (day id y z) ≡⟹ day-apₘ (pulll (elimr ⊗.F-id) ∙ cancell (associator .Isoⁿ.invl ηₚ _)) âŸ©â‰Ą
      day ((id ⊗₁ h') ∘ h) x (day id y z)                                    ≡⟹ day-glue refl âŸ©â‰Ą
      day h (X .F₁ id x) (day (id ∘ h') y z)                                 ≡⟹ day-ap refl (X .F-id #ₚ x) (day-apₘ (idl h')) âŸ©â‰Ą
      day h x (day h' y z)                                                   ∎
    mk-assoc .inv∘eta x = ext λ h h' x y z →
      day (α← _ _ _ ∘ (id ⊗₁ id) ∘ α→ _ _ _ ∘ (h' ⊗₁ id) ∘ h) (day id x y) z ≡⟹ day-apₘ (pulll (elimr ⊗.F-id) ∙ cancell (associator .Isoⁿ.invr ηₚ _)) âŸ©â‰Ą
      day ((h' ⊗₁ id) ∘ h) (day id x y) z                                    ≡⟹ day-glue refl âŸ©â‰Ą
      day h (day (id ∘ h') x y) (Z .F₁ id z)                                 ≡⟹ day-ap refl (day-apₘ (idl h')) (Z .F-id #ₚ z) âŸ©â‰Ą
      day h (day h' x y) z                                                   ∎
    mk-assoc .natural x y f = ext λ h h' x y z →
      day ((α→ _ _ _ ∘ (h' ⊗₁ id) ∘ h) ∘ f) x (day id y z) ≡⟹ day-ap (pullr (pullr refl)) refl refl âŸ©â‰Ą
      day (α→ _ _ _ ∘ (h' ⊗₁ id) ∘ h ∘ f) x (day id y z)   ∎

private module M = Monoidal-category

abstract
  day-triangle : ∀ {A B : ⌞ PSh ℓ C ⌟} → Day-map (Day-idr A .Isoⁿ.to) idnt ∘nt Day-assoc A (よ₀ C Unit) B .Isoⁿ.from ≡ Day-map idnt (Day-idl B .Isoⁿ.to)
  day-triangle {A} {B} = ext λ i h x h' y z →
    day (α← _ _ _ ∘ (id ⊗₁ h') ∘ h) (A .F₁ (ρ← ∘ (id ⊗₁ y) ∘ id) x) z         ≡⟹ day-ap refl (ap₂ (A .F₁) (ap (ρ← ∘_) (idr _)) refl) (sym (B .F-id #ₚ z)) âŸ©â‰Ą
    day (α← _ _ _ ∘ (id ⊗₁ h') ∘ h) (A .F₁ (ρ← ∘ (id ⊗₁ y)) x) (B .F₁ id z)   ≡⟹ sym (day-glue refl) âŸ©â‰Ą
    day ((ρ← ∘ (id ⊗₁ y) ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ h') ∘ h) x z              ≡⟹ day-apₘ (⊗.pushl (ap₂ _,_ refl (introl refl))) âŸ©â‰Ą
    day ((ρ← ⊗₁ id) ∘ ((id ⊗₁ y) ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ h') ∘ h) x z      ≡⟹ day-apₘ (ap₂ _∘_ refl (extendl (sym (associator .Isoⁿ.from .is-natural _ _ _)))) âŸ©â‰Ą
    day ((ρ← ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ (y ⊗₁ id)) ∘ (id ⊗₁ h') ∘ h) x z      ≡⟹ day-apₘ (pulll triangle) âŸ©â‰Ą
    day ((id ⊗₁ λ←) ∘ (id ⊗₁ (y ⊗₁ id)) ∘ (id ⊗₁ h') ∘ h) x z                 ≡⟹ day-apₘ (pulll (sym (⊗.F-∘ _ _)) ∙ pulll (sym (⊗.F-∘ _ _)) ∙ ap (_∘ h) (ap₂ _⊗₁_ (eliml (eliml refl)) (pullr refl))) âŸ©â‰Ą
    day ((id ⊗₁ (λ← ∘ (y ⊗₁ id) ∘ h')) ∘ h) x z                               ≡⟹ day-glue refl âŸ©â‰Ą
    day h (A .F₁ id x) (B .F₁ (λ← ∘ (y ⊗₁ id) ∘ h') z)                        ≡⟹ day-ap refl (A .F-id #ₚ x) refl âŸ©â‰Ą
    day h x (B .F₁ (λ← ∘ (y ⊗₁ id) ∘ h') z)                                   ∎

  day-pentagon
    : ∀ {A B C D : ⌞ PSh ℓ C ⌟}
    → Day-map (Day-assoc A B C .Isoⁿ.from) idnt
      ∘nt Day-assoc A (B ⊗᮰ C) D .Isoⁿ.from
      ∘nt Day-map idnt (Day-assoc B C D .Isoⁿ.from)
    ≡ Day-assoc (A ⊗᮰ B) C D .Isoⁿ.from
      ∘nt Day-assoc A B (C ⊗᮰ D) .Isoⁿ.from
  day-pentagon {D = D} = ext λ i h a h' b h'' c d →
    let
      it =
        (α← _ _ _ ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ α← _ _ _ ∘ (id ⊗₁ h'') ∘ h') ∘ h         ≡⟹ ap₂ _∘_ refl (ap₂ _∘_ refl (⊗.pushl (ap₂ _,_ (intror refl) refl))) âŸ©â‰Ą
        (α← _ _ _ ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ α← _ _ _) ∘ (id ⊗₁ (id ⊗₁ h'') ∘ h') ∘ h ≡⟹ pulll refl ∙ extendl (pullr refl ∙ pentagon) âŸ©â‰Ą
        α← _ _ _ ∘ α← _ _ _ ∘ (id ⊗₁ (id ⊗₁ h'') ∘ h') ∘ h                            ≡⟹ ap₂ _∘_ refl (ap₂ _∘_ refl (⊗.pushl (ap₂ _,_ (intror refl) refl))) âŸ©â‰Ą
        α← _ _ _ ∘ α← _ _ _ ∘ (id ⊗₁ (id ⊗₁ h'')) ∘ (id ⊗₁ h') ∘ h                    ≡⟹ ap₂ _∘_ refl (extendl (associator .Isoⁿ.from .is-natural _ _ _)) âŸ©â‰Ą
        α← _ _ _ ∘ ((id ⊗₁ id) ⊗₁ h'') ∘ α← _ _ _ ∘ (id ⊗₁ h') ∘ h                    ≡⟹ ap₂ _∘_ refl (ap₂ _∘_ (ap (_⊗₁ h'') ⊗.F-id) refl) âŸ©â‰Ą
        (α← _ _ _ ∘ (id ⊗₁ h'') ∘ α← _ _ _ ∘ (id ⊗₁ h') ∘ h)                          ∎
    in
      day (α← _ _ _ ∘ (id ⊗₁ (α← _ _ _) ∘ (id ⊗₁ h'') ∘ h') ∘ h) (day (α← _ _ _ ∘ (id ⊗₁ id) ∘ id) (day id a b) c) d  ≡⟹ day-ap refl (day-ap (elimr (eliml ⊗.F-id) ∙ introl refl) refl refl) (sym (D .F-id #ₚ d)) âŸ©â‰Ą
      day (α← _ _ _ ∘ (id ⊗₁ (α← _ _ _) ∘ (id ⊗₁ h'') ∘ h') ∘ h) (day (id ∘ α← _ _ _) (day id a b) c) (D .F₁ id d)    ≡⟹ sym (day-glue refl) âŸ©â‰Ą
      day ((α← _ _ _ ⊗₁ id) ∘ α← _ _ _ ∘ (id ⊗₁ (α← _ _ _) ∘ (id ⊗₁ h'') ∘ h') ∘ h) (day id (day id a b) c) d         ≡⟹ day-apₘ it âŸ©â‰Ą
      day (α← _ _ _ ∘ (id ⊗₁ h'') ∘ α← _ _ _ ∘ (id ⊗₁ h') ∘ h) (day id (day id a b) c) d                              ∎

Day-monoidal : Monoidal-category (PSh ℓ C)
Day-monoidal .M.-⊗-      = Day-bifunctor
Day-monoidal .M.Unit     = よ₀ C Unit
Day-monoidal .M.unitor-l = to-natural-iso mk-λ where
  mk-λ : make-natural-iso _ _
  mk-λ .eta x = Day-idl x .Isoⁿ.from
  mk-λ .inv x = Day-idl x .Isoⁿ.to
  mk-λ .eta∘inv x = Day-idl x .Isoⁿ.invr
  mk-λ .inv∘eta x = Day-idl x .Isoⁿ.invl
  mk-λ .natural x y f = trivial!
Day-monoidal .M.unitor-r = to-natural-iso mk-ρ where
  mk-ρ : make-natural-iso _ _
  mk-ρ .eta x = Day-idr x .Isoⁿ.from
  mk-ρ .inv x = Day-idr x .Isoⁿ.to
  mk-ρ .eta∘inv x = Day-idr x .Isoⁿ.invr
  mk-ρ .inv∘eta x = Day-idr x .Isoⁿ.invl
  mk-ρ .natural x y f = trivial!
Day-monoidal .M.associator = to-natural-iso mk-α where
  mk-α : make-natural-iso _ _
  mk-α .eta (x , y , z) = Day-assoc x y z .Isoⁿ.to
  mk-α .inv (x , y , z) = Day-assoc x y z .Isoⁿ.from
  mk-α .eta∘inv (x , y , z) = Day-assoc x y z .Isoⁿ.invl
  mk-α .inv∘eta (x , y , z) = Day-assoc x y z .Isoⁿ.invr
  mk-α .natural x y f = trivial!
Day-monoidal .M.triangle {A} {B} = day-triangle
Day-monoidal .M.pentagon {A} {B} {C} {D} = day-pentagon

  1. This is actually a slight under-approximation of strong monoidal functors: the unit must also be preserved, of course, and the preservation isomorphisms need to be compatible with the structural morphisms — the unitors and associator.↩