DisCoPy: Python library for computing with string diagrams - monoidal categories, quantum circuits, QNLP, operads, and tensor networks.
"String diagrams are the syntax, functors are the semantics."
DisCoPy is a Python library for computing with string diagrams - the graphical language of monoidal categories. It provides:
Category
├── ob: Ob (objects/systems)
└── ar: Arrow (morphisms/processes)
Ob → Ty (monoidal: tuple of objects, tensor = concatenation)
Arrow → Diagram (monoidal: boxes + offsets, parallel composition)
└── Box (atomic operations with dom/cod)
| Operator | Method | Description |
|----------|--------|-------------|
| >> | then | Sequential: f >> g (f.cod == g.dom) |
| @ | tensor | Parallel: f @ g (side-by-side) |
| [::-1] | dagger | Adjoint/reverse |
from discopy.monoidal import Ty, Box, Diagram
x, y, z = Ty('x'), Ty('y'), Ty('z')
f = Box('f', x, y)
g = Box('g', y, z)
# Sequential: x → y → z
sequential = f >> g
# Parallel: x ⊗ y → y ⊗ z
parallel = f @ g
# Both: (f ⊗ id) >> (id ⊗ g)
mixed = f @ Diagram.id(y) >> Diagram.id(y) @ g
DisCoPy implements operads via discopy.grammar.cfg:
Ty objects (types of operations)Tree objects (composable rules)Functor from free operad to target operadfrom discopy.grammar.cfg import Ty, Rule, Word, Tree
# Define colors (types)
n, v, s = Ty('N'), Ty('V'), Ty('S')
vp, np = Ty('VP'), Ty('NP')
# Define operations (rules)
Caesar = Word('Caesar', n)
crossed = Word('crossed', v)
VP = Rule(n @ v, vp)
NP = Rule(Ty('D') @ n, np)
S = Rule(vp @ np, s)
# Build tree (operadic composition)
sentence = S(VP(Caesar, crossed), NP(Word('the', Ty('D')), Word('Rubicon', n)))
# Axioms of multicategories (operads) hold on the nose
Types (Ty) act as colors - operations can have different input/output colors:
x, y = Ty('x'), Ty('y')
f = Rule(x @ x, x, name='f') # x ⊗ x → x
g = Rule(x @ y, x, name='g') # x ⊗ y → x
h = Rule(y @ x, x, name='h') # y ⊗ x → x
# Operadic composition
assert f(g, h) == Tree(f, *[g, h])
from discopy.config import COLORS
COLORS = {
"white": "#ffffff",
"red": "#e8a5a5",
"green": "#d8f8d8",
"blue": "#776ff3",
"yellow": "#f7f700",
"black": "#000000"
}
from discopy.quantum.zx import Z, X, Y
# Z spiders: GREEN
Z(1, 1, phase=0.5).color # "green"
# X spiders: RED
X(1, 1, phase=0.25).color # "red"
# Y spiders: BLUE
Y(1, 1).color # "blue"
from discopy.monoidal import Ty, Box
x = Ty('x')
blue_box = Box('f', x, x, color="blue")
blue_box.draw()
# Spider with custom color
from discopy.frobenius import Spider
spider = Spider(2, 3, x)
spider.color = "red"
spider.draw_as_spider = True
diagram.draw(
figsize=(8, 6),
color="blue", # Default box color
draw_as_nodes=True, # Draw boxes as nodes
wire_labels=True, # Show type labels on wires
draw_box_labels=True, # Show box names
path="output.png", # Save to file
to_tikz=True # Output TikZ code
)
from discopy.quantum import qubit, H, X, CX, Ket, Bra, Measure
# Bell state preparation
bell = Ket(0, 0) >> H @ qubit >> CX
# Evaluation
state_vector = bell.eval() # Returns Tensor[complex]
# Measurement probability
experiment = Ket(0, 0) >> bell >> Bra(0, 0)
amplitude = experiment.eval().array
probability = abs(amplitude) ** 2
| Gate | Description | Code |
|------|-------------|------|
| H | Hadamard | H |
| X, Y, Z | Pauli | X, Y, Z |
| CX, CZ | Controlled | CX, CZ |
| Rx, Ry, Rz | Rotation | Rx(phase), Ry(phase), Rz(phase) |
| Ket, Bra | State prep/measure | Ket(0, 1), Bra(0, 0) |
# pytket integration
from discopy.quantum.tk import mockBackend
circuit = H @ qubit >> CX >> Measure() @ Measure()
tk_circuit = circuit.to_tk() # Convert to pytket
# Run on backend
backend = mockBackend({(0, 1): 512, (1, 0): 512})
counts = circuit.eval(backend=backend, n_shots=1024)
# PennyLane integration
pennylane_qnode = circuit.to_pennylane()
from discopy.quantum.zx import Z, X, circuit2zx
# Convert circuit to ZX diagram
zx_diagram = circuit2zx(circuit)
# Z spider (green) with phase
z_spider = Z(2, 1, phase=0.5)
# X spider (red) with phase
x_spider = X(1, 2, phase=0.25)
# PyZX integration for optimization
pyzx_graph = zx_diagram.to_pyzx()
# Apply PyZX simplification algorithms
simplified = pyzx_graph.simplify()
from discopy.grammar.pregroup import Ty, Word, Cup, Diagram
s, n = Ty('s'), Ty('n')
Alice = Word('Alice', n)
loves = Word('loves', n.r @ s @ n.l)
Bob = Word('Bob', n)
# Parse sentence
sentence = Alice @ loves @ Bob >> Cup(n, n.r) @ s @ Cup(n.l, n)
sentence.draw()
from discopy.quantum import circuit, qubit, Ket, H, CX
from discopy.cat import Category
# Define semantic functor
F = circuit.Functor(
ob={s: qubit ** 0, n: qubit ** 1}, # Type → Qubits
ar={
Alice: Ket(0),
loves: sqrt(2) @ Ket(0, 0) >> H @ X >> CX,
Bob: Ket(1)
}
)
F.dom = Category(Ty, Diagram)
# Apply functor to get quantum circuit
quantum_sentence = F(sentence)
quantum_sentence.draw()
Parameterized quantum circuits for word meanings:
from discopy.quantum.ansatze import IQPAnsatz, Sim14Ansatz
# IQP ansatz for nouns
noun_ansatz = IQPAnsatz(n_qubits=2, n_layers=3)
# Sim14 ansatz for verbs
verb_ansatz = Sim14Ansatz(n_qubits=4, n_layers=2)
from discopy.tensor import Tensor, backend
import jax.numpy
import torch
# Default: NumPy
assert isinstance(Tensor.id().array, np.ndarray)
# JAX backend
with backend('jax'):
assert isinstance(Tensor.id().array, jax.numpy.ndarray)
# PyTorch backend
with backend('pytorch'):
assert isinstance(Tensor.id().array, torch.Tensor)
from discopy.tensor import Dim, Tensor, Functor
from discopy.cat import Category
# Define tensor functor
F = Functor(
ob={n: Dim(2), s: Dim(1)},
ar={
Alice: [1, 0],
loves: [[0, 1], [1, 0]],
Bob: [0, 1]
},
cod=Category(Dim, Tensor)
)
result = F(sentence)
import tensornetwork as tn
from discopy.tensor import Box, Dim
vector = Box('v', Dim(1), Dim(2), [0, 1])
contracted = (vector >> vector[::-1]).eval(contractor=tn.contractors.auto)
from discopy.hypergraph import Hypergraph
# Canonical form for diagram equality
hyp = diagram.to_hypergraph()
# Composition via pushouts
from discopy.frobenius import Spider, Diagram
x = Ty('x')
# Special commutative Frobenius algebra
spider = Spider(n_legs_in=2, n_legs_out=3, typ=x)
# Unfuse to canonical primitives
primitives = diagram.unfuse()
from discopy.markov import Copy, Merge, Discard, Diagram
x = Ty('x')
# Copy wire n times
copy = Diagram.copy(x, n=2)
# Merge n wires to one
merge = Diagram.merge(x, n=2)
# Discard wire
discard = Diagram.copy(x, n=0) # Copy with n=0
from discopy.traced import Diagram
# Feedback loop: output fed back to input
traced = diagram.trace()
DisCoPy as ERGODIC coordinator (trit 0):
three-match (-1) ⊗ discopy (0) ⊗ gay-mcp (+1) = 0 ✓ [Diagram Coloring]
sheaf-cohomology (-1) ⊗ discopy (0) ⊗ operad-compose (+1) = 0 ✓ [Operadic]
proofgeneral-narya (-1) ⊗ discopy (0) ⊗ rubato-composer (+1) = 0 ✓ [Music]
persistent-homology (-1) ⊗ discopy (0) ⊗ gay-mcp (+1) = 0 ✓ [Quantum]
from discopy.monoidal import Box, Ty
# Use Gay.jl deterministic colors for boxes
def gay_colored_box(name, dom, cod, seed, index):
"""Create box with deterministic color from Gay.jl"""
# Gay.jl: golden angle dispersion
hue = ((seed * 0x9E3779B97F4A7C15 + index) >> 16) % 360
hex_color = hsl_to_hex(hue, 0.7, 0.55)
return Box(name, dom, cod, color=hex_color)
# Example: colored diagram
x = Ty('x')
boxes = [gay_colored_box(f'f{i}', x, x, 0x42D, i) for i in range(5)]
just discopy-demo # Run DisCoPy demonstration
just discopy-quantum # Quantum circuit examples
just discopy-qnlp # QNLP parsing examples
just discopy-zx # ZX-calculus optimization
just discopy-tensor # Tensor network contraction
just discopy-operad # Operad composition examples
| Query Topic | Key Insight | |-------------|-------------| | Core Architecture | Ty→Ob→Arrow→Diagram hierarchy, >> and @ operators | | Operads | CFG as free operads, Tree = operations, Algebra = functor | | Colors | COLORS dict, ZX: Z=green, X=red, Y=blue | | Quantum | Circuit.eval(), pytket/PennyLane integration | | QNLP | Pregroup → Diagram → Functor → Quantum Circuit | | Tensor Networks | backend() context, tensornetwork contractors | | Hypergraph | Canonical form via cospans, equality checking | | ZX-Calculus | circuit2zx, PyZX optimization, phase gates |
DeepWiki URL: https://deepwiki.com/discopy/discopy
Version: 2.0.0 Trit: 0 (ERGODIC - coordinates categorical computation) GF(3): Substitutes for other ERGODIC skills in triads Qualified: 2025-12-22 (8 DeepWiki interactions)
Part of: para-mensch-commons.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer