Diagram#

class discopy.symmetric.Diagram(inside, dom, cod, _scan=True)[source]#

Bases: discopy.balanced.Diagram, discopy.abc.SymmetricCategory

A symmetric diagram is a balanced diagram with Swap boxes.

Parameters:
  • inside (Layer) – The layers inside the diagram.

  • dom (monoidal.Ty) – The domain of the diagram, i.e. its input.

  • cod (monoidal.Ty) – The codomain of the diagram, i.e. its output.

Note

Equality and hashing of symmetric diagrams is always syntactic: two diagrams are equal if and only if they are built from the same layers. To compare diagrams up to hypergraph isomorphism (swaps, spider fusion, trace plumbing) use from discopy.symmetric import Equation, i.e. the Equation whose up_to is to_hypergraph.

>>> x, y = Ty("x"), Ty("y")
>>> a = Swap(x, y) >> Swap(y, x)
>>> assert a != Id(x @ y)
>>> assert Equation(a, Id(x @ y))

Note

Symmetric diagrams can be defined using the standard syntax for functions.

>>> x = Ty('x')
>>> f = Box('f', x @ x, x)
>>> g = Box('g', x, x @ x)
>>> @Diagram.from_callable(x @ x @ x, x @ x @ x)
... def diagram(x0, x1, x2):
...     x3 = f(x2, x0)
...     x4, x5 = g(x1)
...     return x5, x3, x4
>>> diagram.draw(wire_labels=False,
...              doctest='docs/_static/symmetric/decorator.svg')
../_images/decorator.svg

Every variable must be used exactly once or this will raise an error.

>>> from pytest import raises
>>> from discopy.utils import AxiomError
>>> with raises(AxiomError) as err:
...     Diagram.from_callable(x, x @ x)(lambda x: (x, x))
>>> print(err.value)
symmetric.Diagram has no cups or caps for the wiring of this map.
>>> with raises(AxiomError) as err:
...     Diagram.from_callable(x, Ty())(lambda x: ())
>>> print(err.value)
symmetric.Diagram has no cups or caps for the wiring of this map.

Note

As for discopy.balanced.Diagram, our symmetric diagrams are traced by default. However now we have that the axioms for trace hold on the nose.

Note

The swaps of atomic types are generated by swap_factory, which subclasses should set to their own subclass of Swap. It is the braid of a symmetric category, i.e. braided.Diagram.braid_factory reads it:

>>> class Permutation(Diagram): ...
>>> class Transposition(Swap, Permutation): ...
>>> Permutation.swap_factory = Transposition
>>> assert Permutation.braid_factory is Transposition
braid_factory#

alias of Swap

layer_factory#

alias of Layer

property is_plumbing: bool#

Whether one of the layers plumbs its wires non-trivially.

classmethod swap(left, right)[source]#

The diagram that swaps the left and right wires.

Parameters:
  • left (Ty) – The type at the top left and bottom right.

  • right (Ty) – The type at the top right and bottom left.

Return type:

Diagram

Note

This calls balanced.hexagon() and swap_factory.

classmethod permutation(xs, doms=None)[source]#

The diagram that encodes a given permutation as a composition of swaps.

Parameters:
  • xs (Sequence[int]) – A permutation, as a sequence of integers or a finset.Permutation.

  • dom – A type of the same length as xs, default is Nat(len(xs)).

  • doms (Sequence[Ty] | None)

Return type:

Diagram

classmethod from_permutation(perm, dom=None)[source]#

Encode a permutation natively when the category has a matching Permutation factory. Descendant categories without one use their own swap decomposition instead. An identity permutation always becomes the identity diagram.

Parameters:
  • perm (Sequence[int]) – A permutation, as a sequence of integers or a finset.Permutation.

  • dom (Ty) – A type of the same length as perm, default is Nat(len(perm)).

Return type:

Diagram

Examples

>>> x, y, z = Ty('x'), Ty('y'), Ty('z')
>>> assert Diagram.from_permutation([1, 2, 0], x @ y @ z)\
...     == Permutation(x @ y @ z, [1, 2, 0])
>>> assert Diagram.from_permutation(
...     [0, 1, 2], x @ y @ z) == Id(x @ y @ z)
permute(*xs)[source]#

Post-compose with a permutation written as the historical swap decomposition. Use from_permutation() to construct a native Permutation box.

Parameters:

xs (int) – A list of integers representing a permutation.

Return type:

Diagram

Examples

>>> x, y, z = Ty('x'), Ty('y'), Ty('z')
>>> assert Id(x @ y @ z).permute(2, 0, 1).cod == z @ x @ y
simplify()[source]#

Simplify by translating back and forth to hypergraph.

foliation()[source]#

Merge independent generators, keeping native plumbing compact.

A hypergraph forgets that plumbing is native, so a diagram with a Permutation is foliated by merging its layers instead.

>>> x, y = Ty('x'), Ty('y')
>>> perm = Permutation(x @ y, [1, 0])
>>> assert perm.foliation() == perm
depth()[source]#

The depth of a symmetric diagram.

Examples

>>> x = Ty('x')
>>> f = Box('f', x, x)
>>> assert Id(x).depth() == Id().depth() == 0
>>> assert f.depth() == (f @ f).depth() == 1
>>> assert (f @ f >> Swap(x, x)).depth() == 1
>>> assert (f >> f).depth() == 2 and (f >> f >> f).depth() == 3
factory#

alias of Diagram

functor_factory#

alias of Functor

permutation_factory#

alias of Permutation

sum_factory#

alias of Sum

swap_factory#

alias of Swap

trace_factory#

alias of Trace