Discopy
The Python toolkit for computing with string diagrams.
Install / Use
/learn @discopy/DiscopyREADME
DisCoPy
DisCoPy is a Python toolkit for computing with string diagrams.
- Organisation: https://discopy.org
- Documentation: https://docs.discopy.org
- Source code: https://github.com/discopy/discopy
- Paper (for applied category theorists): https://doi.org/10.4204/EPTCS.333.13
- Paper (for quantum computer scientists): https://arxiv.org/abs/2205.05190
DisCoPy began as an implementation of DisCoCat and QNLP. This has now become its own library: lambeq.
Features
- a
Diagramdata structure for planar string diagrams in any (pre)monoidal category in the hierarchy of graphical languages (with braids, twists, spiders, etc.) with methods for diagram composition, drawing, rewriting andFunctorevaluation into:- Python code, i.e. wires as types and boxes as functions
- tensor networks, i.e. wires as dimensions and boxes as arrays from NumPy, PyTorch, TensorFlow, TensorNetwork, JAX and Quimb
- an implementation of formal grammars (context-free, categorial, pregroup or dependency) with interfaces to lambeq, spaCy and NLTK
- an implementation of categorical quantum mechanics interfacing with:
- tket for circuit compilation
- PyZX for optimisation with the ZX calculus
- PennyLane for automatic differentiation
- a
Hypergraphdata structure for string diagrams in hypergraph categories and its restrictions to symmetric, traced, compact and Markov categories - a
Streamdata structure, an implementation of monoidal streams as a category with delayed feedback - the
Int-construction, also called the geometry of interaction, i.e. the free tortile/compact closed category on a balanced/symmetric traced category
Quickstart
pip install discopy
If you want to see DisCoPy in action, you can check out the following notebooks:
Or you can keep scrolling down to the examples:
Contribute
We're keen to welcome new contributors!
First, read the contributing guidelines then open an issue.
How to cite
If you use DisCoPy in the context of an academic publication, we suggest you cite:
- G. de Felice, A. Toumi & B. Coecke, DisCoPy: Monoidal Categories in Python, EPTCS 333, 2021, pp. 183-197, DOI: 10.4204/EPTCS.333.13
If furthermore your work is related to quantum computing, you can also cite:
- A. Toumi, G. de Felice & R. Yeung, DisCoPy for the quantum computer scientist, arXiv:2205.05190
If you use any of the recent features (e.g. Hypergraph) you should also mention:
- A. Toumi, R. Yeung, B. Poór & G. de Felice, DisCoPy: the Hierarchy of Graphical Languages in Python arXiv:2311.10608
Example: Cooking
This example is inspired from Pawel Sobocinski's blog post Crema di Mascarpone and Diagrammatic Reasoning.
from discopy.symmetric import Ty, Box, Diagram
egg, white, yolk = Ty("egg"), Ty("white"), Ty("yolk")
crack = Box("crack", egg, white @ yolk)
merge = lambda X: Box("merge", X @ X, X)
# DisCoPy allows string diagrams to be defined as Python functions
@Diagram.from_callable(egg @ egg, white @ yolk)
def crack_two_eggs(x, y):
(a, b), (c, d) = crack(x), crack(y)
return (merge(white)(a, c), merge(yolk)(b, d))
# ... or in point-free style using parallel (@) and sequential (>>) composition
assert crack_two_eggs == crack @ crack\
>> white @ Diagram.swap(yolk, white) @ yolk\
>> merge(white) @ merge(yolk)
crack_two_eggs.draw()

By default, DisCoPy diagrams are made of layers with exactly one box in between some (possibly empty) list of wires on its left- and right-hand side. In more abstract terms, they are arrows in a free premonoidal category where the tensor product is biased to the left, i.e.
f @ g = f @ g.dom >> f.cod @ g != f.dom @ g >> f @ g.cod
We can get more general diagrams by specifying the list of layers inside manually or by calling the method Diagram.foliation.
from discopy.monoidal import Layer
crack_two_eggs_at_once = crack_two_eggs.foliation()
assert crack_two_eggs_at_once == Diagram(
dom=egg @ egg, cod=white @ yolk, inside=(
Layer(Ty(), crack, Ty(), crack, Ty()),
Layer(white, Diagram.swap(yolk, white), yolk),
Layer(Ty(), merge(white), Ty(), merge(yolk), Ty())))
crack_two_eggs_at_once.draw()

Example: Alice loves Bob
Snakes & Sentences
Wires can be bent using two special kinds of boxes: cups and caps, which satisfy the snake equations.
from discopy.drawing import Equation
from discopy.rigid import Ty, Id, Cup, Cap
x = Ty('x')
left_snake = x @ Cap(x.r, x) >> Cup(x, x.r) @ x
right_snake = Cap(x, x.l) @ x >> x @ Cup(x.l, x)
assert left_snake.normal_form() == Id(x) == right_snake.normal_form()
Equation(left_snake, Id(x), right_snake).draw()

In particular, DisCoPy can draw the grammatical structure of natural language sentences encoded as reductions in a pregroup grammar. See Lambek, From Word To Sentence (2008) for an introduction.
from discopy.grammar.pregroup import Ty, Word, Cup
s, n = Ty('s'), Ty('n') # sentence and noun
Alice, Bob = Word('Alice', n), Word('Bob', n)
loves = Word('loves', n.r @ s @ n.l)
sentence = Alice @ loves @ Bob >> Cup(n, n.r) @ s @ Cup(n.l, n)
sentence.foliation().draw()

Many other grammatical frameworks can be encoded as diagrams, e.g. cfg (context-free), categorial and dependency grammars.
Functors & Rewrites
Monoidal functors compute the meaning of a diagram, given an interpretation for each wire and for each box. In particular, tensor-valued functors evaluate a diagram as a tensor network using numpy, PyTorch, TensorFlow, TensorNetwork or JAX.
Applied to pregroup diagrams, DisCoPy implements the categorical compositional distributional (DisCoCat) models of [Clark, Coecke, Sadrzadeh (2008)](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.363.8703&rep=re
