# 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)
```