Quill is a package for creating quantum circuit diagrams in Typst.
Note, that this package is in beta and may still be undergoing breaking changes. As new features like data types and scoped functions will be added to Typst, this package will be adapted to profit from the new paradigms.
Meanwhile, we suggest importing everything from the package in a local scope to avoid polluting the global namespace (see example below).
- Usage quick introduction
- Cheat sheet gallery for quickly viewing all kinds of gates
- Tequila building (sub-)circuits in a way similar to QASM or Qiskit
- Examples
- Changelog
Basic usage
The function quantum-circuit()
takes any number of positional gates and works somewhat similarly to the built-int Typst functions table()
or grid()
. A variety of different gate and instruction commands are available for adding elements and integers can be used to produce any number of empty cells (filled with the current wire style). A new wire is started by adding a [\ ]
item.
#{
import "@preview/quill:0.5.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 more options, however.
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")
in order to print the signature and description of the gate
command, just where you are currently typing (powered by tidy).
Cheat Sheet
Instead of listing every featured gate (as is done in the user guide), this gallery quickly showcases a large selection of possible gates and decorations that can be added to any quantum circuit.
Tequila
Tequila is a submodule that adds a completely different way of building circuits.
#import "@preview/quill:0.5.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 layed 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 analog 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 subcircuit 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 subcircuits.
#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)
)
Examples
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.
Contribution
If you spot an issue or have a suggestion, you are invited to post it or to contribute. In architecture.md, you can also find a description of the algorithm that forms the base of quantum-circuit()
.
Tests
This package uses typst-test for running tests.
Changelog
v0.5.0
- Added support for multi-controlled gates with Tequila.
- Switched to using
context
instead of the now deprecatedstyle()
for measurement. Note: Starting with this version, Typst 0.11.0 or higher is required.
v0.4.0
- Alternative model for creating and composing circuits: Tequila.
v0.3.0
- New features
- Enable manual placement of gates,
gate($X$, x: 3, y: 1)
, similar to built-intable()
in addition to automatic placement. This works for most elements, not only gates. - Add parameter
pad
tolstick()
andrstick()
. - Add parameter
fill-wires
toquantum-circuit()
. All wires are filled unto the end (determined by the longest wire) by default (breaking change ⚠️). This behavior can be reverted by settingfill-wires: false
. gategroup()
slice()
andannotate()
can now be placed above or below the circuit withz: "above"
andz: "below"
.help()
command for quickly displaying the documentation of a given function, e.g.,help("gate")
. Powered by tidy.
- Enable manual placement of gates,
- Improvements:
- Complete rework of circuit layout implementation
- allows transparent gates since wires are not drawn through gates anymore. The default fill is now
auto
and usingnone
sets the background to transparent. midstick
is now transparent by default.
- allows transparent gates since wires are not drawn through gates anymore. The default fill is now
setwire()
can now be used to override only partial wire settings, such as wire colorsetwire(1, stroke: blue)
, widthsetwire(1, stroke: 1pt)
or wire distance, all separately. Before, some settings were reset.
- Complete rework of circuit layout implementation
- Fixes:
- Fixed
lstick
/rstick
when equation numbering is turned on.
- Fixed
- Removed:
- The already deprecated
scale-factor
(usescale
instead)
- The already deprecated
v0.2.1
- Improvements:
- Add
fill
parameter tomidstick()
. - Add
bend
parameter topermute()
. - Add
separation
parameter topermute()
.
- Add
- Fixes:
- With Typst 0.11.0,
scale()
now takes into account outer alignment. This broke the positioning of centered/right-aligned circuits, e.g., ones put into afigure()
. - Change wires to be drawn all through
ctrl()
, making it consistent toswap()
andtarg()
.
- With Typst 0.11.0,
v0.2.0
- New features:
- Add arbitrary labels to any
gate
(also derived gates such asmeter
,ctrl
, …),gategroup
orslice
that can be anchored to any of the nine 2d alignments. - Add optional gate inputs and outputs for multi-qubit gates (see gallery).
- Implicit gates (breaking change ⚠️): a content item automatically becomes a gate, so you can just type
$H$
instead ofgate($H$)
(of course, thegate()
function is still important in order to use the many available options).
- Add arbitrary labels to any
- Other breaking changes ⚠️:
slice()
has nodx
anddy
parameters anymore. Instead, labels are handled throughlabel
exactly as ingate()
. Also thewires
parameter is replaced withn
for consistency with other multi-qubit gates.- Swap order of row and column parameters in
annotate()
to make it consistent with built-in Typst functions.
- Improvements:
- Improve layout (allow row/column spacing and min lengths to be specified in em-lengths).
- Automatic bounds computation, even for labels.
- Improve meter (allow multi-qubit gate meters and respect global (per-circuit) gate padding).d
- Fixes:
lstick
/rstick
braces broke with Typst 0.7.0.lstick
/rstick
bounds.
- Documentation
- Add section on creating custom gates.
- Add section on using labels.
- Explain usage of
slice()
andgategroup()
.
v0.1.0
Initial Release