hypergraph#

The free hypergraph category with diagrams encoded as cospans of hypergraphs.

Summary#

Diagram

Diagram in a hypergraph category.

Box

Box in a discopy.hypergraph.Diagram.

Functions

pushout

Computes the pushout of two finite mappings using connected components.

Axioms#

Spiders

We can check spider fusion, i.e. special commutative Frobenius algebra.

>>> x, y, z = map(Ty, "xyz")
>>> split, merge = spiders(1, 2, x), spiders(2, 1, x)
>>> unit, counit = spiders(0, 1, x), spiders(1, 0, x)
  • (Co)commutative (co)monoid:

>>> assert unit @ Id(x) >> merge == Id(x) == Id(x) @ unit >> merge
>>> assert merge @ Id(x) >> merge == Id(x) @ merge >> merge
>>> assert Swap(x, x) >> merge == merge
>>> assert split >> counit @ Id(x) == Id(x) == split >> Id(x) @ counit
>>> assert split >> split @ Id(x) == split >> Id(x) @ split
>>> assert split >> Swap(x, x) == split
  • Frobenius:

>>> assert split @ Id(x) >> Id(x) @ merge\
...     == merge >> split\
...     == Id(x) @ split >> merge @ Id(x)\
...     == spiders(2, 2, x)
  • Speciality:

>>> assert split >> merge == spiders(1, 1, x) == Id(x)
  • Coherence:

>>> assert spiders(0, 1, x @ x) == unit @ unit
>>> assert spiders(2, 1, x @ x) == Id(x) @ Swap(x, x) @ Id(x) >> merge @ merge
>>> assert spiders(1, 0, x @ x) == counit @ counit
>>> assert spiders(1, 2, x @ x) == split @ split >> Id(x) @ Swap(x, x) @ Id(x)

Snakes

Special commutative Frobenius algebras imply compact-closedness, i.e.

  • Snake equations:

>>> left_snake = lambda x: caps(x, x.r) @ Id(x) >> Id(x) @ cups(x.r, x)
>>> right_snake = lambda x: Id(x) @ caps(x.r, x) >> cups(x, x.r) @ Id(x)
>>> assert left_snake(x) == Id(x) == right_snake(x)
>>> assert left_snake(x @ y) == Id(x @ y) == right_snake(x @ y)
  • Yanking (a.k.a. Reidemeister move 1):

>>> right_loop = lambda x: Id(x) @ caps(x, x.r)\
...     >> Swap(x, x) @ Id(x.r) >> Id(x) @ cups(x, x.r)
>>> left_loop = lambda x: caps(x.r, x) @ Id(x)\
...     >> Id(x.r) @ Swap(x, x) >> cups(x.r, x) @ Id(x)
>>> top_loop = lambda x: caps(x, x.r) >> Swap(x, x.r)
>>> bottom_loop = lambda x: Swap(x, x.r) >> cups(x.r, x)
>>> reidemeister1 = lambda x:\
...     top_loop(x) == caps(x.r, x) and bottom_loop(x) == cups(x, x.r)\
...     and left_loop(x) == Id(x) == right_loop(x)
>>> assert reidemeister1(x) and reidemeister1(x @ y) and reidemeister1(Ty())
  • Coherence:

>>> assert caps(x @ y, y @ x)\
...     == caps(x, x) @ caps(y, y) >> Id(x) @ Swap(x, y @ y)\
...     == spiders(0, 2, x @ y) >> Id(x @ y) @ Swap(x, y)
>>> assert caps(x, x) >> cups(x, x) == spiders(0, 0, x)

Swaps

We can also check that the axioms for symmetry hold on the nose.

  • Involution (a.k.a. Reidemeister move 2):

>>> reidermeister2 = lambda x, y: Swap(x, y) >> Swap(y, x) == Id(x @ y)
>>> assert reidermeister2(x, y) and reidermeister2(x @ y, z)
  • Yang-Baxter (a.k.a. Reidemeister move 3):

>>> left = Swap(x, y) @ Id(z)\
...     >> Id(y) @ Swap(x, z)\
...     >> Swap(y, z) @ Id(x)
>>> right = Id(x) @ Swap(y, z)\
...     >> Swap(x, z) @ Id(y)\
...     >> Id(z) @ Swap(x, y)
>>> assert left == right
  • Coherence (a.k.a. pentagon equations):

>>> assert Swap(x, y @ z) == Swap(x, y) @ Id(z) >> Id(y) @ Swap(x, z)
>>> assert Swap(x @ y, z) == Id(x) @ Swap(y, z) >> Swap(x, z) @ Id(y)
  • Naturality:

>>> f = Box("f", x, y)
>>> assert f @ Id(z) >> Swap(f.cod, z) == Swap(f.dom, z) >> Id(z) @ f
>>> assert Id(z) @ f >> Swap(z, f.cod) == Swap(z, f.dom) >> f @ Id(z)