Drawing#

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

Bases: Composable, Whiskerable

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, draw_vertically])

>>> 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.png")
../_images/make-space.png
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.png")
../_images/box.png
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.png")
../_images/empty.png
>>> Drawing.id(Ty('x')).draw(path="docs/_static/drawing/idx.png")
../_images/idx.png
>>> Drawing.id(Ty('x', 'y')).draw(path="docs/_static/drawing/idxy.png")
../_images/idxy.png
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,
...     draw_type_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.png")
../_images/stretch.png
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.png")
../_images/tensor.png
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.png")
../_images/bubble-opening.png
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.png")
../_images/bubble-closing.png
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.png")
../_images/frame-opening.png
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.png")
../_images/frame-closing.png
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.png")
../_images/bubble-drawing.png
frame(*others, dom=None, cod=None, name=None, draw_vertically=False)[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.png")
../_images/single-frame.png
>>> Bubble(f, g, h >> h[::-1], dom=x, cod=y @ y
...     ).draw(path="docs/_static/drawing/horizontal-frame.png")
../_images/horizontal-frame.png
>>> Bubble(f, g, h, dom=x, cod=y @ y, draw_vertically=True
...     ).draw(path="docs/_static/drawing/vertical-frame.png")
../_images/vertical-frame.png
Parameters:

others (Drawing) –

Return type:

Drawing

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

Concatenate two drawings with a symbol in between.

Parameters:

other (Drawing) –