packages feed

proarrow-0.1.0.0: src/Proarrow/Category/Monoidal/Hypergraph.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# OPTIONS_GHC -Wno-orphans #-}

-- | Hypergraph categories: compact closed categories where every object carries a 'Frobenius'
-- structure (a compatible 'Proarrow.Monoid.Monoid' and 'Proarrow.Monoid.Comonoid'), giving n-to-m
-- 'spider's, 'cup's and 'cap's. This is the setting for string diagrams with arbitrary
-- fan-in\/fan-out such as "Proarrow.Category.Instance.ZX".
module Proarrow.Category.Monoidal.Hypergraph where

import Data.Kind (Constraint)
import Data.Type.Nat (SNatI)
import Prelude (($))

import Proarrow.Category.Instance.Free (FREE)
import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..), NFold, NFoldS, SymMonoidal (..), (==))
import Proarrow.Category.Monoidal.CompactClosed (CompactClosed)
import Proarrow.Category.Monoidal.Strictified (Strictified (..), obj1, singleton, swap2)
import Proarrow.Core (CategoryOf (..), Kind, Profunctor (..), Promonad (..), obj)
import Proarrow.Monoid
  ( CocommutativeComonoid
  , CommutativeMonoid
  , Comonoid (..)
  , Monoid (..)
  , Supplies
  , fanIn
  , fanInS
  , fanOut
  , fanOutS
  )
import Proarrow.Tools.Laws (Law (..), Laws (..), (===))

-- | A __special commutative Frobenius algebra__: a commutative monoid and cocommutative comonoid
-- satisfying speciality (@mappend . comult = id@) and the Frobenius law. A 'Hypergraph' category
-- supplies this structure at every object, and with it the 'spider' from n-fold @a@ to m-fold @a@
-- is the unique connected map (commutativity\/cocommutativity make
-- 'fanIn'\/'fanOut' independent of wiring order). The bare notion of a Frobenius monoid needs
-- neither (co)commutativity, but the library only ever uses the special commutative one.
class (CommutativeMonoid a, CocommutativeComonoid a) => Frobenius a

instance (forall (a :: k). (Ob a) => Frobenius a) => Supplies Frobenius k

spider :: forall n m a. (Frobenius a, SNatI n, SNatI m) => NFold n a ~> NFold m a
spider = fanOut @m @a . fanIn @n @a

spiderS :: forall n m a. (Frobenius a, SNatI n, SNatI m) => NFoldS n a ~> NFoldS m a
spiderS = fanOutS @m @a . fanInS @n @a

cup :: (Frobenius a) => Unit ~> a ** a
cup @a = comult @a . mempty @a

cupS :: (Frobenius a) => '[] ~> [a, a]
cupS @a = Str (cup @a)

cap :: (Frobenius a) => a ** a ~> Unit
cap @a = counit @a . mappend @a

capS :: (Frobenius a) => [a, a] ~> '[]
capS @a = Str (cap @a)

-- | A hypergraph category has a special frobenius algebra for every object, and the
-- frobenius algebra of any tensor product X ⊗ Y is induced in the canonical way from those of X and Y.
class (Supplies Frobenius k, CompactClosed k) => Hypergraph k

-- | A hypergraph category is self-dual compact closed.
dualHG :: forall {k} (a :: k) b. (Hypergraph k) => a ~> b -> b ~> a
dualHG f =
  unStr @'[b] @'[a] $
    cupS ** obj1
      == obj1 ** singleton f ** obj1
      == obj1 ** capS
      \\ f

linDistHG :: forall {k} (a :: k) b c. (Hypergraph k, Ob a, Ob b) => a ** b ~> c -> a ~> b ** c
linDistHG f =
  unStr @'[a] @[b, c] $
    obj1 ** cupS
      == Str @[a, b] @'[c] f ** obj1
      == swap2
      \\ f

linDistInvHG :: forall {k} (a :: k) b c. (Hypergraph k, Ob b, Ob c) => a ~> b ** c -> a ** b ~> c
linDistInvHG f =
  unStr @[a, b] @'[c] $
    swap2
      == obj1 ** Str @'[a] @[b, c] f
      == capS ** obj1
      \\ f

-- | A hypergraph category has a trace.
traceHG :: forall {k} u (x :: k) y. (Hypergraph k, Ob x, Ob y, Ob u) => u ** x ~> u ** y -> x ~> y
traceHG f =
  unStr $
    cupS ** obj1
      == obj1 ** Str @[u, x] @'[u, y] f
      == capS ** obj1

-- | A hypergraph category is monoidal closed.
type ExpHG a b = a ** b

curryHG :: forall {k} (a :: k) b c. (Hypergraph k, Ob a, Ob b) => a ** b ~> c -> a ~> ExpHG b c
curryHG = linDistHG @a @b @c

applyHG :: forall {k} (b :: k) c. (Hypergraph k, Ob b, Ob c) => ExpHG b c ** b ~> c
applyHG = linDistInvHG @_ @b (obj @b ** obj @c)

-- | In the free category the supply generators (see @'Supplies' 'Monoid'@\/@'Supplies' 'Comonoid'@
-- in "Proarrow.Monoid") are compatible by fiat, so monoid + comonoid is already 'Frobenius'. With
-- both supplies in @cs@, @'Supplies' 'Frobenius'@ and 'Hypergraph' are derived, with no structure
-- of their own. Superclasses are taken directly as the context to keep dictionary construction
-- acyclic. Bundling them into an 'Proarrow.Category.Instance.Free.All'-style constraint here builds
-- a dictionary that references itself through the quantified 'Supplies' constraint, looping at
-- runtime.
instance (CommutativeMonoid a, CocommutativeComonoid (a :: FREE cs p)) => Frobenius (a :: FREE cs p)

instance (Supplies Frobenius (FREE cs p), CompactClosed (FREE cs p)) => Hypergraph (FREE cs p)

-- | The structures the laws of a category supplying special commutative Frobenius algebras are
-- stated for: the monoids and comonoids, together.
type FrobeniusStructures :: [Kind -> Constraint]
type FrobeniusStructures = '[Monoidal, SymMonoidal, Supplies Monoid, Supplies Comonoid]

-- | The supplied monoids and comonoids are special and satisfy the Frobenius law. Their monoid and
-- comonoid laws, and their commutativity, are separate instances, in "Proarrow.Monoid".
instance Laws FrobeniusStructures where
  laws =
    [ Law "speciality" \ @a _ -> obj @a === mappend @a . comult @a
    , Law "Frobenius (left)" \ @a _ ->
        withOb2 @_ @a @a $
          comult @a . mappend @a === (mappend @a ** obj @a) . associatorInv @_ @a @a @a . (obj @a ** comult @a)
    , Law "Frobenius (right)" \ @a _ ->
        withOb2 @_ @a @a $
          comult @a . mappend @a === (obj @a ** mappend @a) . associator @_ @a @a @a . (comult @a ** obj @a)
    ]