DisCoPy: string diagrams as a Python data structure
The Python toolkit for computing with string diagrams.
At a glance
- What is it?
- DisCoPy turns monoidal categories into Python classes you can compose, draw and evaluate. It is a research toolkit first, and its own README is honest about the gotchas.
- Who is it for?
- Adopt DisCoPy if you are doing applied category theory, QNLP or diagrammatic reasoning and you already think in terms of objects, boxes and functors; the abstract base classes in discopy.abc are a real map of the field. Do not adopt it if you want a general graph-drawing library or a production NLP pipeline, since the grammar and quantum paths pull in optional extras that the base install does not include.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What DisCoPy solves, and for whom
String diagrams are a notation, and a notation is not a data structure. If you want to compose two diagrams, rewrite one of them, draw the result and then evaluate it as a tensor, you need a representation that survives all four operations. DisCoPy provides that representation in Python. The README states the project is a Python toolkit for computing with string diagrams, and the package metadata in pyproject.toml describes it as production/stable, though the intended audience classifiers point at developers and researchers rather than end users.
The people who get value from it fall into three groups. Applied category theorists get abstract base classes for Category, MonoidalCategory and their subclasses, classified against Selinger's survey of graphical languages for monoidal categories. Quantum computer scientists get categorical quantum mechanics with interfaces to tket for circuit compilation and PyZX for ZX-calculus optimisation. Computational linguists get context-free, categorial, pregroup and dependency grammars with interfaces to lambeq, spaCy and NLTK. Those are three different research communities sharing one diagram data structure, which is the actual design bet of the project.
Diagram, Layer, Box: the data model underneath
The core abstraction is not a picture. A monoidal Layer is a tensor product of boxes and plumbing, represented by a non-empty type, with at least one box and no adjacent plumbing. A Diagram is a sequence of composable layers with a designated input dom and output cod. The identity diagram is the empty sequence where dom equals cod, and composition f >> g is sequence concatenation. That is the whole trick: composition is list concatenation, so the data structure is cheap and the categorical laws are enforced by construction rather than checked afterwards.
The tensor product is where the design gets opinionated. The README states that f @ g decomposes as f @ g.dom >> f.cod @ g, which is biased: f happens before g. The consequence, spelled out in the README itself, is that diagrams really live in a premonoidal category rather than a monoidal one. If you need the unbiased tensor, that is a modelling decision you have to make yourself, not a flag you can flip.
Two gotchas are documented in the README and both bite newcomers. First, Box is a subclass of Diagram with a cyclic reference, so list(box.inside) == [Layer(box)]. Second, every category C has a class attribute ar with C.ar = C, installed by the @factory decorator, so that Box knows it lives inside a bigger Diagram category. The factory method pattern is used throughout: Diagram.swap computes the symmetry of arbitrary types using Diagram.swap_factory = Swap to generate subclasses of Box for atomic types. If you subclass DisCoPy classes without the @factory decorator, expect confusing failures.
Installing DisCoPy and building a first diagram
The README gives a single install command. The base package pulls in numpy, networkx, matplotlib and pillow, and pyproject.toml requires Python 3.12 or later, with classifiers for 3.12, 3.13 and 3.14.
pip install discopyQuantum and grammar support are optional dependency groups, so a plain install does not give you pytket, pyzx, spaCy or NLTK. The README points at three notebooks to start with: What is a diagram?, the QNLP Tutorial, and Geometry of Chatbot Interaction. The cooking example in the README defines a custom category by subclassing Ty, Diagram, Box, Permutation and Swap, each concrete class decorated with @factory. That is the intended workflow when you want your own objects and boxes rather than the built-in ones.
from discopy.utils import factory
from discopy.symmetric import Ty, Box, Diagram, Permutation, Swap
@factory
class Ingredient(Ty):
"The objects of the category of recipe diagrams."
@factory
class Recipe(Diagram):
ob = Ingredient
class CookingStep(Box, Recipe):
"A cooking step is a box in a recipe diagram."What you should see after running this is a new category whose objects are Ingredient and whose morphisms are Recipe diagrams built from CookingStep boxes. The README also walks through a natural language example (Alice loves Bob) and a geometry of chatbot interaction, both of which are longer than the cooking sketch.
Functors are where diagrams become numbers
A diagram on its own computes nothing. Evaluation happens through Functor, and the README lists two targets. Function treats wires as types and boxes as functions, with either disjoint union (python.additive) or tuples (python.multiplicative). Tensor treats wires as dimensions and boxes as arrays, and it backs onto NumPy, PyTorch, TensorFlow, TensorNetwork, JAX and Quimb.
That list is the practical reason to use DisCoPy rather than writing your own diagram class. The same diagram can be evaluated as a tensor network, as a JAX array or as a PyTorch tensor by changing the functor target, and the optional dependency group named quantum in pyproject.toml is what pulls in pytket, pyzx == 0.7.3, sympy, tensornetwork, jax, jaxlib, torch, qiskit and qiskit-aer. Note the pinned pyzx version: the project does not float that dependency, so a pyzx upgrade is a DisCoPy release decision, not yours.
The cost of this breadth is that the quantum extra is heavy. Installing it brings a JAX stack and a Qiskit stack into the same environment, and the README does not document a supported combination matrix beyond the pins in pyproject.toml. If your environment is sensitive to dependency resolution, install the base package first and add extras deliberately.
Beyond monoidal: hypergraphs, streams, terms and the Int-construction
The monoidal core is only the beginning of the module list. DisCoPy ships a Hypergraph data structure for string diagrams in hypergraph categories and its restrictions to symmetric, traced, compact and Markov categories. It ships a combinatorial map data structure for compact categories, with box orientation that can enforce planarity. It ships a Stream data structure implementing monoidal streams as a category with delayed feedback. It ships a Term data structure for lambda terms in the internal language of (bi)closed monoidal categories, with translation back and forth to diagrams. And it ships the Int-construction, also called the geometry of interaction, described as the free tortile or compact closed category on a balanced or symmetric traced category.
That is a lot of surface area for one package. The README documents each of these in a sentence or two, then moves on. A reader who needs to know, for example, exactly which restrictions the Hypergraph structure enforces, or how planarity is decided by orientation on boxes, will not find the answer in the README. The documentation site at docs.discopy.org is the place that would have to carry that detail, and the README does not summarise what it contains. Treat the module list as a map of what exists, not as a description of how each piece behaves at the edges.
Where DisCoPy is the wrong tool
The first limitation is the premonoidal bias in the tensor. If your application requires a genuinely symmetric monoidal tensor as the default, you are working against the grain of the data structure, and the README says so plainly rather than hiding it.
The second is the Python version floor. pyproject.toml requires >=3.12. If you are pinned to an older interpreter for other reasons, DisCoPy 1.2.2 is not available to you without upgrading Python first, and the README does not describe a backport path.
The third is that this is a research toolkit, not a diagram-drawing library. If all you want is to render a flow chart or a state machine to SVG, matplotlib and networkx will do it with fewer concepts. DisCoPy makes you define objects, boxes and a category before you can draw anything, and that ceremony only pays off if you also need composition, rewriting and functor evaluation.
The fourth is dependency weight on the quantum side. The quantum extra includes pyzx pinned at 0.7.3, plus jax, torch, qiskit and qiskit-aer. For a small experiment that needs one tensor contraction, that is a large install. The README offers no minimal quantum subset.
Compared with a tensor-network library used directly
The obvious alternative for the evaluation half is to skip DisCoPy and build the contraction directly in TensorNetwork, Quimb, JAX or PyTorch. The difference in approach is what you get to keep. A tensor-network library gives you arrays and a contraction order. DisCoPy gives you a syntax layer above those arrays: you define boxes and types, compose them into a diagram, then choose a functor that maps the diagram into whichever array library you already use. The diagram is the artifact; the tensor is one interpretation of it.
That matters when the diagram is the thing you want to reason about. If you plan to rewrite a circuit, prove two diagrams equal, or translate a grammatical derivation into a tensor network and back, the syntax layer is doing work that a bare contraction cannot. If you only ever want the final array, the syntax layer is overhead, and the README's own framing (a toolkit for computing with string diagrams) tells you the project is aimed at the first case. The interfaces to tket and PyZX reinforce this: those are tools that consume or produce diagrammatic structure, not just numbers.
Maintenance, releases and licence
The repository is not archived, and the last push was on 2026-09-15. Recent releases are 1.2.0 on 2025-01-13, 1.2.1 on 2025-10-22 and 1.2.2 on 2025-12-19, so the release cadence is measured in months rather than weeks, and the version number has not moved past the 1.2 line in that window. The repository carries a CHANGELOG.md, which is where upgrade notes would live; the README does not document a rollback procedure or a deprecation policy.
Upgrade cost is dominated by the optional extras. Because pyzx is pinned to 0.7.3 inside the quantum group, a DisCoPy upgrade is also a decision about your ZX-calculus dependency, and the README does not describe how that pin is chosen. The base dependencies (numpy, networkx, matplotlib, pillow) are unpinned in pyproject.toml, so the base install tracks upstream.
The licence is BSD-3-Clause, declared in pyproject.toml as a file reference to LICENSE. That is a permissive licence, which matters if you intend to vendor the diagram classes into a larger codebase. It is not a copyleft licence, so redistribution does not carry a source-disclosure obligation. This is a description of the declared licence, not legal advice; read LICENSE and your own counsel before relying on it.
Editorial conclusion
Adopt DisCoPy if you are doing applied category theory, QNLP or diagrammatic reasoning and you already think in terms of objects, boxes and functors; the abstract base classes in discopy.abc are a real map of the field. Do not adopt it if you want a general graph-drawing library or a production NLP pipeline, since the grammar and quantum paths pull in optional extras that the base install does not include. Before committing, run pip install discopy on Python 3.12 or later, work through the What is a diagram? notebook, and check whether the Functor target you need (NumPy, PyTorch, TensorFlow, TensorNetwork, JAX or Quimb) is one you can actually pin.
Frequently asked questions
What is DisCoPy used for?
It is a Python toolkit for computing with string diagrams. The README lists applied uses in natural language processing through formal grammars and in quantum computing through categorical quantum mechanics, plus a general Diagram data structure with functor evaluation into NumPy, PyTorch, TensorFlow, TensorNetwork, JAX and Quimb.
Who is DisCoPy Labs?
The README lists an organisation page at discopy.org and a contact address of [email protected], and names DisCoPy as the project author in pyproject.toml. The README does not describe a separate entity called DisCoPy Labs.
What is discopy labs?
The README does not document a package or component by that name. It documents the discopy package itself, with modules including discopy.abc, discopy.monoidal and discopy.symmetric, and points to docs.discopy.org for documentation.
What is the function of the discopy command?
The README does not document a command-line entry point. Installation is given as pip install discopy, and usage in the README is through Python imports such as from discopy.symmetric import Ty, Box, Diagram, Permutation, Swap.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/discopy-discopy)