Layer#

class discopy.monoidal.Layer(*inside, normalise=True)[source]#

Bases: discopy.cat.Box, discopy.abc.ColouredMonoid

A layer is a tensor product of boxes and plumbing, i.e. non-empty types.

Parameters:
  • inside (Ty | Box) – Boxes and plumbing, with at least one box.

  • normalise (bool) – Whether to type check the components and normalise them, i.e. remove empty plumbing and tensor consecutive types. The methods below build layers that satisfy this by construction and pass False, which skips every pass over inside so that tensoring n layers takes linear rather than quadratic time.

ob#

alias of Ty

classmethod id(dom=None)[source]#

There is no identity layer: a layer has at least one box, and a layer of empty plumbing would denote the identity diagram, which is the empty sequence of layers rather than a one-element one.

Whiskering merges a type into the boundary instead, see whisker() and tensor().

Parameters:

dom (Ty)

Return type:

Layer

classmethod whisker(other)[source]#

A type stays a type, which tensor() merges into the boundary; anything else is embedded as a layer.

Parameters:

other (Ty | Box | Layer) – The type, box or layer to be tensored on either side.

Return type:

Ty | Layer

classmethod unit(colour=None)[source]#

The unit of the layer product, i.e. the empty type on a colour.

A layer has at least one box, so the unit is not one: it lands in the types rather than in the layers, which tensor() accepts.

Example

>>> x = Ty('x')
>>> f = Box('f', x, x)
>>> unit, layer = Layer.unit(), Layer(f)
>>> assert unit @ layer == layer == layer @ unit
Parameters:

colour (Colour)

Return type:

Ty

plumbing#

alias of Ty

static check(inside)[source]#

Check that the components are types and boxes whose domains and codomains tensor, i.e. one linear pass comparing the colours of each adjacent pair on both rows.

classmethod normalise(inside)[source]#

The canonical word of boxes and non-empty plumbing: either we append or we tensor with the last element.

property boxes_and_types#

The layer expanded to alternating types and boxes.

Empty types are inserted around consecutive boxes for compatibility with algorithms defined on the old layer representation.

tensor(other)[source]#

Tensor another layer on the right, normalising the common boundary.

A type is merged into the boundary rather than embedded as a layer, so that whiskering never builds one out of empty plumbing.

Parameters:

other (Ty | Box | Layer)

Return type:

Layer

property boxes_and_offsets: list[tuple[Box, int]]#

The offsets of each box inside the layer.

Example

>>> a, b, c, d, e = map(Ty, "abcde")
>>> f, g = Box('f', a, b), Box('g', c, d)
>>> assert Layer(e, f, e, g, e).boxes_and_offsets == [(f, 1), (g, 3)]
merge(other)[source]#

Merge two layers into one or raise AxiomError, used by Diagram.foliation().

Parameters:

other (Layer) – The other layer with which to merge.

Return type:

Layer

Example

>>> a, b, c, d, e = map(Ty, "abcde")
>>> f, g = Box('f', a, b), Box('g', c, d)
>>> layer0 = Layer(e,  f,  e @ c @ e)
>>> layer1 = Layer(e @ b @ e,  g,  e)
>>> assert layer0.merge(layer1) == Layer(e, f, e, g, e)