Effortlessly create quantum circuit diagrams in Typst.
See the codeQuill is a package for creating quantum circuit diagrams in Typst. It features two distinct creation models:
Outline:
The function quantum-circuit() takes any number of positional gates and works similar to the built-in Typst functions table() and grid().
[\ ] item.#{
import "@preview/quill:0.8.0": *
quantum-circuit(
lstick($|0〉$), $H$, ctrl(1), rstick($(|00〉+|11〉)/√2$, n: 2), [\ ],
lstick($|0〉$), 1, targ(), 1
)
}
Plain quantum gates — such as a Hadamard gate — can be written with the shorthand notation $H$ instead of the more lengthy gate($H$). The latter offers additional styling options.
Refer to the user guide for a full documentation of this package. You can also look up the documentation of any function by calling the help module, e.g., #help("gate") just where you are currently typing (powered by tidy).
This gallery quickly showcases a large selection of possible gates and decorations that can be added to any quantum circuit.
Tequila is a submodule that adds a completely different way of building circuits.
#import "@preview/quill:0.8.0" as quill: tequila as tq
#quill.quantum-circuit(
..tq.build(
tq.h(0),
tq.cx(0, 1),
tq.cx(0, 2),
),
quill.gategroup(x: 2, y: 0, 3, 2)
)
This is similar to how QASM and Qiskit work: gates are successively applied to the circuit which is then laid out automatically by packing gates as tightly as possible. We start by calling the tq.build() function and filling it with quantum operations. This returns a collection of gates which we expand into the circuit with the .. syntax.
Now, we still have the option to add annotations, groups, slices, or even more gates via manual placement.
The syntax works analogously to Qiskit. Available gates are x, y, z, h, s, sdg, sx, sxdg, t, tdg, p, rx, ry, rz, u, cx, cz, and swap. With barrier, an invisible barrier can be inserted to prevent gates on different qubits to be packed tightly. Finally, with tq.gate and tq.mqgate, a generic gate can be created. These two accept the same styling arguments as the normal gate (or mqgate).
Also like Qiskit, all qubit arguments support ranges, e.g., tq.h(range(5)) adds a Hadamard gate on the first five qubits and tq.cx((0, 1), (1, 2)) adds two CX gates: one from qubit 0 to 1 and one from qubit 1 to 2.
With Tequila, it is easy to build templates for quantum circuits and to compose circuits of various building blocks. For this purpose, tq.build() and the built-in templates all feature optional x and y arguments to allow placing a sub-circuit at an arbitrary position of the circuit.
As an example, Tequila provides a tq.graph-state() template for quickly drawing graph state preparation circuits.
The following example demonstrates how to compose multiple sub-circuits.
#import tequila as tq
#quantum-circuit(
..tq.graph-state((0, 1), (1, 2)),
..tq.build(y: 3,
tq.p($pi$, 0),
tq.cx(0, (1, 2)),
),
..tq.graph-state(x: 6, y: 2, invert: true, (0, 1), (0, 2)),
gategroup(x: 1, 3, 3),
gategroup(x: 1, y: 3, 3, 3),
gategroup(x: 6, y: 2, 3, 3),
slice(x: 5)
)
Some show-off examples, loosely replicating figures from Quantum Computation and Quantum Information by M. Nielsen and I. Chuang. The code for these examples can be found in the example folder or in the user guide.
If you spot an issue or have a suggestion, you are invited to post it or to contribute to this package. In architecture.md, you can also find a description of the algorithm that forms the base of quantum-circuit().
This package uses tytanic for running tests.
repeat-block.targ-y gate for controlled-Y gates.break-line for marking the omission of wires.lstick/rstick braces that broke with Typst 0.15 (again).quantum-circuit.color. It was not even really used.math.lr are created anymore with lstick and rstick.swap.stroke, targ.stroke, ctrl.stroke, phase.stroke, meter.stroke, lstick.fill, and rstick.fill.permute.x and permute.y being ignored.wire-stroke to all controlled gates such as mqgate, ctrl, targ, swap, and meter that gives control over the stroke of the control wire(s).tequila.measure.meter.gategroup with two new parameter gategroup.right and gategroup.bottom.wires to quantum-circuit that allows defining the number of (qu)bits explicitly. This parameter also accepts an array of wire counts, e.g., wires: (1,) * qubits + (2,) * clbits which is useful to avoid having to many setwire commands.pass-through parameter to mqgate that enables wires to pass through a multi-qubit gate instead of attaching themselves as in- and outputs.wire-count and stroke to permute, allowing classical or even mixed permutation gates.tequila.ca gate for arbitrary single-qubit controlled gates.tequila.measure to replace tequila.meter. The new gate can also receive an index of a wire to send the result to via a classical wire.start and end parameters to tequila.barrier that allow local barriers.multi-controlled-gate.targ can now take a "target" qubit as in targ(2) to produce a vertical wire, just like ctrl and swap.ctrl and swap can now be used without target argument like ctrl(). This can replace usage like ctrl(0) for gates without a control wire.x and y to the phantom gate.path element with the new curve element.targX: use swap(0) instead.stroke for the plain gate command.context instead of the now deprecated style() for measurement.
Note: Starting with this version, Typst 0.11.0 or higher is required.gate($X$, x: 3, y: 1), similar to built-in table() in addition to automatic placement. This works for most elements, not only gates.pad to lstick() and rstick().fill-wires to quantum-circuit(). All wires are filled unto the end (determined by the longest wire) by default (breaking change ⚠️). This behavior can be reverted by setting fill-wires: false.gategroup() slice() and annotate() can now be placed above or below the circuit with z: "above" and z: "below".help() command for quickly displaying the documentation of a given function, e.g., help("gate"). Powered by tidy.auto and using none sets the background to transparent.midstick is now transparent by default.setwire() can now be used to override only partial wire settings, such as wire color setwire(1, stroke: blue), width setwire(1, stroke: 1pt) or wire distance, all separately. Before, some settings were reset.lstick/rstick when equation numbering is turned on.scale-factor (use scale instead)fill parameter to midstick().bend parameter to permute().separation parameter to permute().scale() now takes into account outer alignment. This broke the positioning of centered/right-aligned circuits, e.g., ones put into a figure().ctrl(), making it consistent to swap() and targ().gate (also derived gates such as meter, ctrl, ...), gategroup or slice that can be anchored to any of the nine 2d alignments.$H$ instead of gate($H$) (of course, the gate() function is still important in order to use the many available options).slice() has no dx and dy parameters anymore. Instead, labels are handled through label exactly as in gate(). Also the wires parameter is replaced with n for consistency with other multi-qubit gates.annotate() to make it consistent with built-in Typst functions.lstick/rstick braces broke with Typst 0.7.0.lstick/rstick bounds.slice() and gategroup().Initial Release
Typst
100.0%
Effortlessly create quantum circuit diagrams in Typst.
See the codeQuill is a package for creating quantum circuit diagrams in Typst. It features two distinct creation models:
Outline:
The function quantum-circuit() takes any number of positional gates and works similar to the built-in Typst functions table() and grid().
[\ ] item.#{
import "@preview/quill:0.8.0": *
quantum-circuit(
lstick($|0〉$), $H$, ctrl(1), rstick($(|00〉+|11〉)/√2$, n: 2), [\ ],
lstick($|0〉$), 1, targ(), 1
)
}
Plain quantum gates — such as a Hadamard gate — can be written with the shorthand notation $H$ instead of the more lengthy gate($H$). The latter offers additional styling options.
Refer to the user guide for a full documentation of this package. You can also look up the documentation of any function by calling the help module, e.g., #help("gate") just where you are currently typing (powered by tidy).
This gallery quickly showcases a large selection of possible gates and decorations that can be added to any quantum circuit.
Tequila is a submodule that adds a completely different way of building circuits.
#import "@preview/quill:0.8.0" as quill: tequila as tq
#quill.quantum-circuit(
..tq.build(
tq.h(0),
tq.cx(0, 1),
tq.cx(0, 2),
),
quill.gategroup(x: 2, y: 0, 3, 2)
)
This is similar to how QASM and Qiskit work: gates are successively applied to the circuit which is then laid out automatically by packing gates as tightly as possible. We start by calling the tq.build() function and filling it with quantum operations. This returns a collection of gates which we expand into the circuit with the .. syntax.
Now, we still have the option to add annotations, groups, slices, or even more gates via manual placement.
The syntax works analogously to Qiskit. Available gates are x, y, z, h, s, sdg, sx, sxdg, t, tdg, p, rx, ry, rz, u, cx, cz, and swap. With barrier, an invisible barrier can be inserted to prevent gates on different qubits to be packed tightly. Finally, with tq.gate and tq.mqgate, a generic gate can be created. These two accept the same styling arguments as the normal gate (or mqgate).
Also like Qiskit, all qubit arguments support ranges, e.g., tq.h(range(5)) adds a Hadamard gate on the first five qubits and tq.cx((0, 1), (1, 2)) adds two CX gates: one from qubit 0 to 1 and one from qubit 1 to 2.
With Tequila, it is easy to build templates for quantum circuits and to compose circuits of various building blocks. For this purpose, tq.build() and the built-in templates all feature optional x and y arguments to allow placing a sub-circuit at an arbitrary position of the circuit.
As an example, Tequila provides a tq.graph-state() template for quickly drawing graph state preparation circuits.
The following example demonstrates how to compose multiple sub-circuits.
#import tequila as tq
#quantum-circuit(
..tq.graph-state((0, 1), (1, 2)),
..tq.build(y: 3,
tq.p($pi$, 0),
tq.cx(0, (1, 2)),
),
..tq.graph-state(x: 6, y: 2, invert: true, (0, 1), (0, 2)),
gategroup(x: 1, 3, 3),
gategroup(x: 1, y: 3, 3, 3),
gategroup(x: 6, y: 2, 3, 3),
slice(x: 5)
)
Some show-off examples, loosely replicating figures from Quantum Computation and Quantum Information by M. Nielsen and I. Chuang. The code for these examples can be found in the example folder or in the user guide.
If you spot an issue or have a suggestion, you are invited to post it or to contribute to this package. In architecture.md, you can also find a description of the algorithm that forms the base of quantum-circuit().
This package uses tytanic for running tests.
repeat-block.targ-y gate for controlled-Y gates.break-line for marking the omission of wires.lstick/rstick braces that broke with Typst 0.15 (again).quantum-circuit.color. It was not even really used.math.lr are created anymore with lstick and rstick.swap.stroke, targ.stroke, ctrl.stroke, phase.stroke, meter.stroke, lstick.fill, and rstick.fill.permute.x and permute.y being ignored.wire-stroke to all controlled gates such as mqgate, ctrl, targ, swap, and meter that gives control over the stroke of the control wire(s).tequila.measure.meter.gategroup with two new parameter gategroup.right and gategroup.bottom.wires to quantum-circuit that allows defining the number of (qu)bits explicitly. This parameter also accepts an array of wire counts, e.g., wires: (1,) * qubits + (2,) * clbits which is useful to avoid having to many setwire commands.pass-through parameter to mqgate that enables wires to pass through a multi-qubit gate instead of attaching themselves as in- and outputs.wire-count and stroke to permute, allowing classical or even mixed permutation gates.tequila.ca gate for arbitrary single-qubit controlled gates.tequila.measure to replace tequila.meter. The new gate can also receive an index of a wire to send the result to via a classical wire.start and end parameters to tequila.barrier that allow local barriers.multi-controlled-gate.targ can now take a "target" qubit as in targ(2) to produce a vertical wire, just like ctrl and swap.ctrl and swap can now be used without target argument like ctrl(). This can replace usage like ctrl(0) for gates without a control wire.x and y to the phantom gate.path element with the new curve element.targX: use swap(0) instead.stroke for the plain gate command.context instead of the now deprecated style() for measurement.
Note: Starting with this version, Typst 0.11.0 or higher is required.gate($X$, x: 3, y: 1), similar to built-in table() in addition to automatic placement. This works for most elements, not only gates.pad to lstick() and rstick().fill-wires to quantum-circuit(). All wires are filled unto the end (determined by the longest wire) by default (breaking change ⚠️). This behavior can be reverted by setting fill-wires: false.gategroup() slice() and annotate() can now be placed above or below the circuit with z: "above" and z: "below".help() command for quickly displaying the documentation of a given function, e.g., help("gate"). Powered by tidy.auto and using none sets the background to transparent.midstick is now transparent by default.setwire() can now be used to override only partial wire settings, such as wire color setwire(1, stroke: blue), width setwire(1, stroke: 1pt) or wire distance, all separately. Before, some settings were reset.lstick/rstick when equation numbering is turned on.scale-factor (use scale instead)fill parameter to midstick().bend parameter to permute().separation parameter to permute().scale() now takes into account outer alignment. This broke the positioning of centered/right-aligned circuits, e.g., ones put into a figure().ctrl(), making it consistent to swap() and targ().gate (also derived gates such as meter, ctrl, ...), gategroup or slice that can be anchored to any of the nine 2d alignments.$H$ instead of gate($H$) (of course, the gate() function is still important in order to use the many available options).slice() has no dx and dy parameters anymore. Instead, labels are handled through label exactly as in gate(). Also the wires parameter is replaced with n for consistency with other multi-qubit gates.annotate() to make it consistent with built-in Typst functions.lstick/rstick braces broke with Typst 0.7.0.lstick/rstick bounds.slice() and gategroup().Initial Release
Typst
100.0%