Drawing#

class discopy.drawing.drawing.Drawing(inside, dom, cod, boxes=(), width=0, height=0, _check=True)[source]#

Bases: discopy.abc.TracedCategory

A drawing is a plane graph with designated input and output types.

Parameters:
  • inside (PlaneGraph) – The plane graph underlying the drawing.

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

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

  • boxes (tuple[monoidal.Box, ...]) – The boxes inside the drawing.

  • width (float) – The width of the drawing.

  • height (float) – The height of the drawing.

  • _check (bool) – Whether to call validate_attributes().

Summary

validate_attributes()

Check that the attributes of a drawing are consistent.

draw(**params)

Call add_box_corners() then backend.draw().

from_box(box)

Draw a diagram with just one box.

id([dom, length])

Draw the identity diagram.

then(other[, draw_step_by_step])

Draw one diagram composed with another.

tensor(other)

Draw two diagrams side by side.

dagger()

The reflection of a drawing along the the horizontal axis.

bubble([dom, cod, name, width, height, ...])

Draw a closed line around a drawing, with some wires coming in and out.

frame(*others[, dom, cod, name, ...])

>>> from discopy.monoidal import *

validate_attributes()[source]#

Check that the attributes of a drawing are consistent.

>>> from discopy.monoidal import Ty, Id
>>> x = Ty('x')
>>> drawing = Id(x).to_drawing()
>>> drawing.add_edges([(Node("cod", i=0, x=x), Node("dom", i=0, x=x))])
>>> drawing.validate_attributes()
Traceback (most recent call last):
...
ValueError: Wrong edge Node('cod', i=0, x=x) -> Node('dom', i=0, x=x)
draw(**params)[source]#

Call add_box_corners() then backend.draw().

add_box_corners()[source]#

Recenter boxes w.r.t their wires then draw the corners.

union(other, dom, cod, width=None, height=None, _check=True)[source]#

Take the union of two drawings, assuming nodes are distinct.

add_nodes(positions)[source]#

Add nodes to the graph given their positions.

Parameters:

positions (dict[Node, Point]) –

add_edges(edges)[source]#

Add edges from a list.

Parameters:

edges (list[tuple[Node, Node]]) –

relabel_nodes(mapping={}, positions={}, copy=True, _check=False)[source]#

Relabel nodes and/or their positions.

make_space(space, x, y_min=None, y_max=None, exclusive=False, copy=False)[source]#

Make some horizontal space after position x for all nodes between y_min and y_max (inclusive).

Example

>>> from discopy.monoidal import Ty, Box
>>> x, y, z = map(Ty, "xyz")
>>> f = Drawing.from_box(Box('f', x @ y, z))
>>> f.make_space(2, 0.5, 0.75, 1.0, copy=True).draw(
...     aspect='equal', path="docs/_static/drawing/make-space.svg")
../_images/make-space.svg
reposition_box_dom(j=0)[source]#

Recenter dom nodes, used when drawing frames.

reposition_box_cod(j=-1)[source]#

Recenter cod nodes to recover legacy behaviour for layers.

align_box_cod(j=-1)[source]#

Align outputs with inputs when they have equal number of wires.

property is_identity#

A drawing with no boxes is the identity.

property is_empty#

A drawing with no boxes and no wires is empty.

property is_box#

Whether the drawing is just one box.

property is_layer#

Whether the drawing is just one box with wires on both sides.

property box#

Syntactic sugar for self.boxes[0] when self.is_box

property left_is_whiskered#

Whether self = x @ f for some non-empty type x.

property right_is_whiskered#

Whether self = f @ x for some non-empty type x.

static from_box(box)[source]#

Draw a diagram with just one box.

>>> from discopy.monoidal import Ty, Box
>>> x, y, z = map(Ty, "xyz")
>>> f = Box('f', x, y @ z)
>>> assert f.to_drawing() == Drawing.from_box(f)
>>> for ps in f.to_drawing().positions.items(): print(*ps)
Node('box', box=f, j=0) Point(x=1.0, y=0.5)
Node('dom', i=0, x=x) Point(x=1.0, y=1)
Node('box_dom', i=0, j=0, x=x) Point(x=1.0, y=0.75)
Node('box_cod', i=0, j=0, x=y) Point(x=0.5, y=0.25)
Node('box_cod', i=1, j=0, x=z) Point(x=1.5, y=0.25)
Node('cod', i=0, x=y) Point(x=0.5, y=0)
Node('cod', i=1, x=z) Point(x=1.5, y=0)
>>> f.draw(path="docs/_static/drawing/box.svg")
../_images/box.svg
Parameters:

box (monoidal.Box) –

Return type:

Drawing

static id(dom=None, length=0)[source]#

Draw the identity diagram.

>>> from discopy.monoidal import Ty
>>> Drawing.id(Ty()).draw(path="docs/_static/drawing/empty.svg")
../_images/empty.svg
>>> Drawing.id(Ty('x')).draw(path="docs/_static/drawing/idx.svg")
../_images/idx.svg
>>> Drawing.id(Ty('x', 'y')).draw(path="docs/_static/drawing/idxy.svg")
../_images/idxy.svg
Parameters:

dom (monoidal.Ty) –

Return type:

Drawing

then(other, draw_step_by_step=False)[source]#

Draw one diagram composed with another.

This is done by calling make_space() to align the output wires of self and the input wires of other while keeping them straight.

Example

>>> from discopy.monoidal import Ty, Box, Diagram
>>> x = Ty('x')
>>> f = Drawing.from_box(Box('f', x, x @ x @ x))
>>> g = Drawing.from_box(Box('g', x @ x, x))
>>> u = Drawing.from_box(Box('u', Ty(), x ** 3))
>>> v = Drawing.from_box(Box('v', x ** 7, Ty()))
>>> top, bottom = u >> g @ f, g @ f @ f >> v
>>> Diagram.to_gif(
...     *top.then(bottom, draw_step_by_step=True), loop=True,
...     wire_labels=False, draw_box_labels=False,
...     path="docs/_static/drawing/composition.gif")
<IPython.core.display.HTML object>
../_images/composition.gif
Parameters:

other (Drawing) –

Return type:

Drawing

stretch(y, copy=True)[source]#

Stretch input and output wires to increase the height of a diagram by a given length. . .. admonition:: Example

>>> from discopy.monoidal import Box
>>> f = Drawing.from_box(Box('f', 'x', 'x'))
>>> f.stretch(2).draw(path="docs/_static/drawing/stretch.svg")
../_images/stretch.svg
tensor(other)[source]#

Draw two diagrams side by side.

Example

>>> from discopy.monoidal import Box
>>> f = Drawing.from_box(Box('f', 'x', 'x'))
>>> d = (f >> f >> f) @ (f >> f)
>>> d.draw(path="docs/_static/drawing/tensor.svg")
../_images/tensor.svg
Parameters:

other (Drawing) –

Return type:

Drawing

dagger()[source]#

The reflection of a drawing along the the horizontal axis.

Return type:

Drawing

static bubble_opening(dom, arg_dom, left, right, frame_boundary=False)[source]#

Construct the opening of a bubble, i.e. a box drawn as wires.

>>> from discopy.monoidal import Ty
>>> x, y, z = map(Ty, "xyz")
>>> Drawing.bubble_opening(x, y, z, Ty("")).draw(
...     path="docs/_static/drawing/bubble-opening.svg")
../_images/bubble-opening.svg
static bubble_closing(arg_cod, cod, left, right, frame_boundary=False)[source]#

Construct the closing of a bubble, i.e. a box drawn as wires.

>>> from discopy.monoidal import Ty
>>> x, y, z = map(Ty, "xyz")
>>> Drawing.bubble_closing(x, y, z, Ty("")).draw(
...     path="docs/_static/drawing/bubble-closing.svg")
../_images/bubble-closing.svg
static frame_opening(dom, arg_dom, left, right)[source]#

Construct the opening of a frame as the opening of a bubble squashed to zero height so that it looks like the upper half of a rectangle.

>>> from discopy.monoidal import Ty
>>> x, y, z = map(Ty, "xyz")
>>> Drawing.frame_opening(x, y, z, Ty("")).draw(
...     path="docs/_static/drawing/frame-opening.svg")
../_images/frame-opening.svg
static frame_closing(arg_cod, cod, left, right)[source]#

Construct the closing of a frame as the closing of a bubble squashed to zero height so that it looks like the lower half of a rectangle.

>>> from discopy.monoidal import Ty
>>> x, y, z = map(Ty, "xyz")
>>> Drawing.frame_closing(x, y, z, Ty("")).draw(
...     path="docs/_static/drawing/frame-closing.svg")
../_images/frame-closing.svg
bubble(dom=None, cod=None, name=None, width=None, height=None, draw_as_square=False)[source]#

Draw a closed line around a drawing, with some wires coming in and out.

Parameters:
  • dom (monoidal.Ty) – The wires coming into the bubble.

  • cod (monoidal.Ty) – The wires coming out of the bubble.

  • name (str) – The label of the bubble, drawn on the top left.

  • width

Return type:

Drawing

>>> from discopy.symmetric import *
>>> a, b, c, d = map(Ty, "abcd")
>>> f = Box('f', a @ b, c @ d).to_drawing()
>>> f.bubble(d @ c @ c, b @ a @ a, name="g").draw(
...     path="docs/_static/drawing/bubble-drawing.svg")
../_images/bubble-drawing.svg
factory#

alias of Drawing

ob#

alias of Ty

slot(colour, **params)[source]#

Wrap the drawing in a square slot filled with a background colour, so that several terms can be tiled on the same background.

This is shared by frame(), for its arguments, and by add(), for the terms of an Equation between differently-coloured diagrams.

Parameters:
  • colour – The monoidal.Colour of the slot’s background.

  • params – Passed to bubble(), e.g. height or width.

frame(*others, dom=None, cod=None, name=None, draw_vertically=False, frame_colour=None)[source]#
>>> from discopy.monoidal import *
>>> x, y = Ty('x'), Ty('y')
>>> f, g, h = Box('f', x, y ** 3), Box('g', y, y @ y), Box('h', x, y)
>>> f.bubble(dom=x @ x, cod=y @ y, name="b", draw_as_frame=True
...     ).draw(path="docs/_static/drawing/single-frame.svg")
../_images/single-frame.svg
>>> Bubble(f, g, h >> h[::-1], dom=x, cod=y @ y
...     ).draw(path="docs/_static/drawing/horizontal-frame.svg")
../_images/horizontal-frame.svg
>>> Bubble(f, g, h, dom=x, cod=y @ y, draw_vertically=True
...     ).draw(path="docs/_static/drawing/vertical-frame.svg")
../_images/vertical-frame.svg
Parameters:

others (Drawing) –

Return type:

Drawing

add(other, symbol='+', space=1)[source]#

Concatenate two drawings with a symbol in between.

Parameters:

other (Drawing) –