{"id":13993886,"url":"https://github.com/discopy/discopy","last_synced_at":"2025-07-22T18:32:26.893Z","repository":{"id":36464457,"uuid":"214391191","full_name":"discopy/discopy","owner":"discopy","description":"The Python toolkit for computing with string diagrams.","archived":false,"fork":false,"pushed_at":"2024-10-29T09:06:35.000Z","size":53528,"stargazers_count":347,"open_issues_count":39,"forks_count":66,"subscribers_count":24,"default_branch":"main","last_synced_at":"2024-10-29T09:56:25.220Z","etag":null,"topics":["category-theory","diagrams","nlp","quantum-computing"],"latest_commit_sha":null,"homepage":"https://discopy.org","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/discopy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-11T09:02:00.000Z","updated_at":"2024-10-29T08:42:52.000Z","dependencies_parsed_at":"2023-02-17T08:45:51.474Z","dependency_job_id":"a7fdae71-b5d5-42ab-8368-2d37bbb90325","html_url":"https://github.com/discopy/discopy","commit_stats":{"total_commits":1443,"total_committers":26,"mean_commits":55.5,"dds":0.5537075537075538,"last_synced_commit":"065e1eb91d1e706c590d5525ca480d49c149bea2"},"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discopy%2Fdiscopy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discopy%2Fdiscopy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discopy%2Fdiscopy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discopy%2Fdiscopy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/discopy","download_url":"https://codeload.github.com/discopy/discopy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227156426,"owners_count":17739302,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["category-theory","diagrams","nlp","quantum-computing"],"created_at":"2024-08-09T14:02:36.689Z","updated_at":"2025-07-22T18:32:26.626Z","avatar_url":"https://github.com/discopy.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/discopy/discopy/raw/main/docs/_static/snake-equation-dark.svg\"\u003e\n  \u003cimg alt=\"Snake equation\" width=\"60%\" src=\"https://github.com/discopy/discopy/raw/main/docs/_static/snake-equation.svg\"\u003e\n\u003c/picture\u003e\n\n# DisCoPy\n\n[![build](https://github.com/discopy/discopy/actions/workflows/build.yml/badge.svg)](https://github.com/discopy/discopy/actions/workflows/build.yml)\n[![readthedocs](https://readthedocs.org/projects/discopy/badge/?version=main)](https://docs.discopy.org/)\n[![PyPI version](https://badge.fury.io/py/discopy.svg)](https://badge.fury.io/py/discopy)\n[![DOI: 10.4204/EPTCS.333.13](http://img.shields.io/badge/DOI-10.4204/EPTCS.333.13-brightgreen.svg)](https://doi.org/10.4204/EPTCS.333.13)\n\nDisCoPy is a Python toolkit for computing with [string diagrams](https://en.wikipedia.org/wiki/String_diagram).\n\n* **Organisation:** \u003chttps://discopy.org\u003e\n* **Documentation:** \u003chttps://docs.discopy.org\u003e\n* **Source code:** \u003chttps://github.com/discopy/discopy\u003e\n* **Paper (for applied category theorists):** \u003chttps://doi.org/10.4204/EPTCS.333.13\u003e\n* **Paper (for quantum computer scientists):** \u003chttps://arxiv.org/abs/2205.05190\u003e\n\nDisCoPy began as an implementation of [DisCoCat](https://en.wikipedia.org/wiki/DisCoCat) and [QNLP](https://en.wikipedia.org/wiki/Quantum_natural_language_processing). This has now become its own library: [lambeq](https://cqcl.github.io/lambeq).\n\n## Features\n\n* a [`Diagram`](https://docs.discopy.org/en/main/_api/discopy.monoidal.Diagram.html) data structure for planar string diagrams in any ([pre](https://ncatlab.org/nlab/show/premonoidal+category))[monoidal category](https://en.wikipedia.org/wiki/Monoidal_category) in the [hierarchy of graphical languages](https://en.wikipedia.org/wiki/String_diagram#Hierarchy_of_graphical_languages) (with braids, twists, spiders, etc.) with methods for diagram composition, drawing, rewriting and [`Functor`](https://docs.discopy.org/en/main/_api/discopy.monoidal.Functor.html) evaluation into:\n  - Python code, i.e. wires as types and boxes as functions\n  - [tensor networks](https://en.wikipedia.org/wiki/Tensor_network), i.e. wires as dimensions and boxes as arrays from [NumPy](https://numpy.org), [PyTorch](https://pytorch.org/), [TensorFlow](https://www.tensorflow.org/), [TensorNetwork](https://github.com/google/TensorNetwork), [JAX](https://github.com/google/jax) and [Quimb](https://quimb.readthedocs.io/en/latest)\n* an implementation of formal grammars ([context-free](https://en.wikipedia.org/wiki/Context-free_grammar), [categorial](https://en.wikipedia.org/wiki/Categorial_grammar), [pregroup](https://en.wikipedia.org/wiki/Pregroup_grammar) or [dependency](https://en.wikipedia.org/wiki/Dependency_grammar)) with interfaces to [lambeq](https://cqcl.github.io/lambeq), [spaCy](https://spacy.io/) and [NLTK](https://www.nltk.org/)\n* an implementation of [categorical quantum mechanics](https://en.wikipedia.org/wiki/Categorical_quantum_mechanics) interfacing with:\n  - [tket](https://github.com/CQCL/tket) for circuit compilation\n  - [PyZX](https://github.com/Quantomatic/pyzx) for optimisation with the [ZX calculus](https://zxcalculus.com/)\n  - [PennyLane](https://pennylane.ai/) for automatic differentiation\n* a [`Hypergraph`](https://docs.discopy.org/en/main/_api/discopy.hypergraph.Hypergraph.html) data structure for string diagrams in hypergraph categories and its restrictions to symmetric, traced, compact and Markov categories\n* a [`Stream`](https://docs.discopy.org/en/main/_api/discopy.stream.Stream.html) data structure, an implementation of [monoidal streams](https://arxiv.org/abs/2212.14494) as a [category with delayed feedback](https://doi.org/10.1051/ita:2002009)\n* the [`Int`](https://docs.discopy.org/en/main/_api/discopy.interaction.Int.html)-construction, also called the [geometry of interaction](https://ncatlab.org/nlab/show/Geometry+of+Interaction), i.e. the free tortile/compact closed category on a balanced/symmetric traced category\n\n## Quickstart\n\n```shell\npip install discopy\n```\n\nIf you want to see DisCoPy in action, you can check out the following notebooks:\n\n- [What is a diagram?](https://docs.discopy.org/en/main/notebooks/diagrams.html)\n- [QNLP Tutorial](https://docs.discopy.org/en/main/notebooks/qnlp.html)\n\nOr you can keep scrolling down to the examples:\n\n- [Cooking](#example-cooking)\n- [Alice loves Bob](#example-alice-loves-bob)\n- [Geometry of Chatbot Interaction](#geometry-of-chatbot-interaction).\n\n## Contribute\n\nWe're keen to welcome new contributors!\n\nFirst, read the [contributing guidelines](https://github.com/discopy/discopy/blob/main/CONTRIBUTING.md) then [open an issue](https://github.com/discopy/discopy/issues/new).\n\n## How to cite\n\nIf you use DisCoPy in the context of an academic publication, we suggest you cite:\n\n* G. de Felice, A. Toumi \u0026 B. Coecke, _DisCoPy: Monoidal Categories in Python_, EPTCS 333, 2021, pp. 183-197, [DOI: 10.4204/EPTCS.333.13](https://doi.org/10.4204/EPTCS.333.13)\n\nIf furthermore your work is related to quantum computing, you can also cite:\n\n* A. Toumi, G. de Felice \u0026 R. Yeung, _DisCoPy for the quantum computer scientist_, [arXiv:2205.05190](https://arxiv.org/abs/2205.05190)\n\nIf you use any of the recent features (e.g. `Hypergraph`) you should also mention:\n\n* A. Toumi, R. Yeung, B. Poór \u0026 G. de Felice, _DisCoPy: the Hierarchy of Graphical Languages in Python_ [arXiv:2311.10608](https://arxiv.org/abs/2311.10608)\n\n## Example: Cooking\n\nThis example is inspired from Pawel Sobocinski's blog post [Crema di Mascarpone and Diagrammatic Reasoning](https://graphicallinearalgebra.net/2015/05/06/crema-di-mascarpone-rules-of-the-game-part-2-and-diagrammatic-reasoning/).\n\n```python\nfrom discopy.symmetric import Ty, Box, Diagram\n\negg, white, yolk = Ty(\"egg\"), Ty(\"white\"), Ty(\"yolk\")\ncrack = Box(\"crack\", egg, white @ yolk)\nmerge = lambda X: Box(\"merge\", X @ X, X)\n\n# DisCoPy allows string diagrams to be defined as Python functions\n\n@Diagram.from_callable(egg @ egg, white @ yolk)\ndef crack_two_eggs(x, y):\n    (a, b), (c, d) = crack(x), crack(y)\n    return (merge(white)(a, c), merge(yolk)(b, d))\n\n# ... or in point-free style using parallel (@) and sequential (\u003e\u003e) composition\n\nassert crack_two_eggs == crack @ crack\\\n  \u003e\u003e white @ Diagram.swap(yolk, white) @ yolk\\\n  \u003e\u003e merge(white) @ merge(yolk)\n\ncrack_two_eggs.draw()\n```\n\n![crack_two_eggs.draw()](https://github.com/discopy/discopy/raw/main/test/drawing/imgs/crack-eggs.png)\n\nBy 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.\nIn more abstract terms, they are arrows in a free [premonoidal category](https://en.wikipedia.org/wiki/Premonoidal_category) where the tensor product is biased to the left, i.e.\n\n```python\nf @ g = f @ g.dom \u003e\u003e f.cod @ g != f.dom @ g \u003e\u003e f @ g.cod\n```\n\nWe can get more general diagrams by specifying the list of layers `inside` manually or by calling the method [`Diagram.foliation`](https://docs.discopy.org/en/main/_api/discopy.monoidal.Diagram.html#discopy.monoidal.Diagram.foliation).\n\n```python\nfrom discopy.monoidal import Layer\n\ncrack_two_eggs_at_once = crack_two_eggs.foliation()\n\nassert crack_two_eggs_at_once == Diagram(\n  dom=egg @ egg, cod=white @ yolk, inside=(\n    Layer(Ty(), crack, Ty(), crack, Ty()),\n    Layer(white, Diagram.swap(yolk, white), yolk),\n    Layer(Ty(), merge(white), Ty(), merge(yolk), Ty())))\n\ncrack_two_eggs_at_once.draw()\n```\n\n![crack_two_eggs_at_once.draw()](https://github.com/discopy/discopy/raw/main/test/drawing/imgs/crack-two-eggs-at-once.png)\n\n## Example: Alice loves Bob\n\n### Snakes \u0026 Sentences\n\nWires can be bent using two special kinds of boxes: **cups** and **caps**, which satisfy the [snake equations](https://ncatlab.org/nlab/show/triangle+identities).\n\n```python\nfrom discopy.drawing import Equation\nfrom discopy.rigid import Ty, Id, Cup, Cap\n\nx = Ty('x')\nleft_snake = x @ Cap(x.r, x) \u003e\u003e Cup(x, x.r) @ x\nright_snake =  Cap(x, x.l) @ x \u003e\u003e x @ Cup(x.l, x)\nassert left_snake.normal_form() == Id(x) == right_snake.normal_form()\n\nEquation(left_snake, Id(x), right_snake).draw()\n```\n\n![Equation(left_snake, Id(x), right_snake).draw()](https://github.com/discopy/discopy/raw/main/test/drawing/imgs/typed-snake-equation.png)\n\nIn particular, DisCoPy can draw the grammatical structure of natural language sentences encoded as reductions in a [pregroup grammar](https://ncatlab.org/nlab/show/pregroup+grammar).\nSee Lambek, [From Word To Sentence (2008)](http://www.math.mcgill.ca/barr/lambek/pdffiles/2008lambek.pdf) for an introduction.\n\n```python\nfrom discopy.grammar.pregroup import Ty, Word, Cup\n\ns, n = Ty('s'), Ty('n')  # sentence and noun\nAlice, Bob = Word('Alice', n), Word('Bob', n)\nloves = Word('loves', n.r @ s @ n.l)\n\nsentence = Alice @ loves @ Bob \u003e\u003e Cup(n, n.r) @ s @ Cup(n.l, n)\nsentence.foliation().draw()\n```\n\n![Alice loves Bob](https://github.com/discopy/discopy/raw/main/test/drawing/imgs/alice-loves-bob.png)\n\nMany other grammatical frameworks can be encoded as diagrams, e.g. [`cfg`](https://docs.discopy.org/en/main/_api/discopy.grammar.cfg.html) (context-free), [`categorial`](https://docs.discopy.org/en/main/_api/discopy.grammar.categorial.html) and [`dependency`](https://docs.discopy.org/en/main/_api/discopy.grammar.dependency.html) grammars.\n\n### Functors \u0026 Rewrites\n\n**Monoidal functors** compute the meaning of a diagram, given an interpretation for each wire and for each box.\nIn particular, **tensor-valued functors** evaluate a diagram as a tensor network using [numpy](https://numpy.org/), [PyTorch](https://pytorch.org/), [TensorFlow](https://www.tensorflow.org/), [TensorNetwork](https://github.com/google/TensorNetwork) or [JAX](https://github.com/google/jax).\n\nApplied to pregroup diagrams, DisCoPy implements the\n**categorical compositional distributional** (_DisCoCat_) models of\n[Clark, Coecke, Sadrzadeh (2008)](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.363.8703\u0026rep=rep1\u0026type=pdf).\n\n```python\nfrom discopy.cat import Category\nfrom discopy.grammar import pregroup\nfrom discopy.tensor import Dim, Tensor\n\nF = pregroup.Functor(\n    ob={s: 1, n: 2},\n    ar={Alice: [1, 0], loves: [[0, 1], [1, 0]], Bob: [0, 1]},\n    cod=Category(Dim, Tensor))\n\nassert F(sentence)\n```\n\n**Diagram-valued functors** can fill each box with a complex diagram.\nThe result can then be simplified using `diagram.normalize()` to remove the snakes, this is called [autonomisation](https://arxiv.org/abs/1411.3827).\n\n```python\nfrom discopy.grammar.pregroup import Cap, Box\n\ndef wiring(word):\n    if word.cod == n:  # word is a noun\n        return word\n    if word.cod == n.r @ s @ n.l:  # word is a transitive verb\n        box = Box(word.name, n @ n, s)\n        return Cap(n.r, n) @ Cap(n, n.l) \u003e\u003e n.r @ box @ n.l\n\nW = pregroup.Functor(ob={s: s, n: n}, ar=wiring)\n\nrewrite_steps = W(sentence).normalize()\nsentence.to_gif(*rewrite_steps)\n```\n\n![sentence.to_gif(*rewrite_steps)](https://github.com/discopy/discopy/raw/main/test/drawing/imgs/autonomisation.gif)\n\n## Geometry of Chatbot Interaction\n\n### From states to processes\n\nThe [`Int`](https://docs.discopy.org/en/main/_api/discopy.interaction.Int.html)-construction of [Joyal, Street \u0026 Verity (1996)](https://doi.org/10.1017/S0305004100074338) is\n\n\u003e a glorification of the construction of the integers from the natural numbers\n\ni.e. the same way we can freely add inverses to a commutative monoid to get a group, e.g. $\\mathbb{N} \\hookrightarrow Int(\\mathbb{N}) = \\mathbb{Z}$ where\n\n$$\nInt(M) \\ = \\ (M \\times M) \\ / \\ \\set{ (x, x') \\sim (y, y') \\ \\vert \\ x + y' = x' + y }\n$$\n\nyou can freely add cups and caps to a [`symmetric`](https://docs.discopy.org/en/main/_api/discopy.symmetric.html) or [`balanced`](https://docs.discopy.org/en/main/_api/discopy.balanced.html) category to get a [`compact`](https://docs.discopy.org/en/main/_api/discopy.compact.html) or [`tortile`](https://docs.discopy.org/en/main/_api/discopy.tortile.html) category.\n\nThe only condition is that the monoid needs to be **cancellative**, i.e. $x + n = y + n \\implies x = y$.\n\nThe [vertical categorification](https://ncatlab.org/nlab/show/vertical+categorification) of a cancellative monoid is called a [`traced`](https://docs.discopy.org/en/main/_api/discopy.traced.html) category, where the diagrams can have feedback loops:\n\n![right trace](https://github.com/discopy/discopy/blob/97c002fa8eaefefc53287d960a54ebd5ac96dedd/docs/_static/traced/right-trace.png)\n\nGiven a traced category $C$, we construct $Int(C)$ with objects given by pairs of objects $Ob(Int(C)) = Ob(C) \\times Ob(C)$, arrows given by $Int(C)((x_0, x_1), (y_0, y_1)) = C(x_0 \\otimes y_1, x_1 \\otimes y_0)$ and the composition is given by **symmetric feedback**:\n\n![symmetric feedback](https://github.com/discopy/discopy/blob/97c002fa8eaefefc53287d960a54ebd5ac96dedd/docs/_static/int/symmetric-feedback.png)\n\nThe structure theorem of Joyal-Street-Verity says that the embedding $C \\hookrightarrow Int(C)$ is fully-faithful, i.e. we can remove all the snakes and replace all the cups and caps with feedback loops.\nWe can use this geometry of interaction to interpret words as processes rather than states:\n\n```python\nfrom discopy.interaction import Ty, Int\nfrom discopy.compact import Ty as T, Diagram as D, Box, Category\n\nN, S = T('N'), T('S')\nA, B = Box('A', N, N), Box('B', N, N)\nL = Box('L', N @ S @ N, N @ S @ N)\nswaps = D.permutation((2, 1, 0), N @ S @ N)\nG = pregroup.Functor(\n    ob={s: Ty[T](S, S), n: Ty[T](N, N)},\n    ar={Alice: A, loves: swaps \u003e\u003e L, Bob: B},\n    cod=Int(Category(T, D)))\n\nALB_trace = (A @ S @ B \u003e\u003e L).trace(left=True).trace(left=False).foliation()\n\nwith D.hypergraph_equality:\n  assert G(sentence).inside == ALB_trace\n\nEquation(sentence.foliation(), ALB_trace, symbol=\"$\\\\mapsto$\").draw()\n```\n\n![Alice loves traces](https://github.com/discopy/discopy/raw/main/docs/_static/int/alice-loves-traces.png)\n\n### Streams and delayed feedback\n\nA key axiom of traced monoidal categories which allows to simplify diagrams is the **yanking equation**:\n\n![yanking](https://github.com/discopy/discopy/raw/main/docs/_static/traced/yanking.png)\n\nIf we relax this assumption we get the concept of a [`feedback`](https://docs.discopy.org/en/main/_api/discopy.feedback.html) category where the objects come with a [`delay`](https://docs.discopy.org/en/main/_api/discopy.feedback.Ob.html#discopy.feedback.Ob.delay) operation and the feedback loops have a more restricted shape:\n\n![feedback operator](https://github.com/discopy/discopy/raw/main/docs/_static/feedback/feedback-operator.png)\n\nGiven a symmetric category $C$, we can construct a feedback category of **monoidal streams** $Stream(C)$ where\n\n- the objects are infinite sequences of objects $Ob(Stream(C)) = C \\times Ob(Stream(C))$,\n- the arrows are infinite sequences of arrows $Stream(C)(X, Y) = \\coprod_{M} Stream(C)(X, Y, M)$ defined by:\n\n$$Stream(C)(X, Y, M) = C(X_0 \\otimes M_0, Y_0 \\otimes M_1)  \\times Stream(C)(X^+, Y^+, M^+)$$\n\nwhere $X_0$ and $X^+$ are the head and the tail of the stream $X$.\n\nThis comes with a delay $d(X) \\in Ob(Stream(C))$ given by the monoidal unit as head $d(X)_0 = I$ and the given object as tail $d(X)^+ = X$.\nThe feedback operation is given by:\n\n![feedback unrolling](https://github.com/discopy/discopy/raw/main/docs/_static/stream/feedback-unrolling.png)\n\nWe can use this to unroll our diagram of the previous section:\n\n```python\nfrom discopy.stream import Ty, Stream\n\nN, S = Ty(\"N\"), Ty(\"S\")\nA, B = [Stream.sequence(f, N, N) for f in \"AB\"]\nL = Stream.sequence('L', S.head @ N.delay() @ N.delay(), N @ N)\nALB = (L \u003e\u003e A @ B).feedback(dom=S.head, cod=Ty(), mem=N @ N)\nALB.unroll(2).now.foliation().draw()\n```\n\n![Alice loves unrolling](https://github.com/discopy/discopy/raw/main/docs/_static/stream/alice-loves-unrolling.png)\n\nNow if we use the [`python`](https://docs.discopy.org/en/main/_api/discopy.python.html) module to interpret each box as a call to a chatbot with the prompt as input, we can get an output along the following lines:\n\n\u003e The play is set in a basement with computers everywhere, Alice and Bob are dressed like hackers with black hoodies and nerdy glasses, they have somewhat of a hipster vibe.\n\u003e \n\u003e Alice: I think I’ve cracked the encryption, but it’s like nothing I’ve seen before. DisCoPy — it’s almost...alive.  \n\u003e \n\u003e Bob: What do you mean, alive? You’re not saying it’s AI, are you? Because if it is, we’re in way over our heads.\n\u003e \n\u003e Alice: It’s not just AI, Bob. It’s adaptive, learning—like it knows we’re here.\n\u003e \n\u003e (Bob takes a step back, his face serious as he considers the implications. He glances at the screens around them, suddenly aware of their presence.)\n\u003e \n\u003e Bob: If that’s true, we’re not just hacking into the system. We’re waking it up. And if it wakes up angry...\n\u003e \n\u003e Alice: Then we’re the ones who let it loose.\n\u003e \n\u003e Bob: We need to find the off switch. Now. Before it finds us.\n\u003e \n\u003e SILENCE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscopy%2Fdiscopy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiscopy%2Fdiscopy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscopy%2Fdiscopy/lists"}