Instructions¶
Instructions, also called gates, are used to represent the operations that must be performed in parallel or in sequence to form the desired algorithm. In cQASM 1.x, they follow an assembly-like syntax:
<name> <comma-separated-operands>
Note the lack of parentheses around the operands.
Note
libqasm does not specify an exact instruction set or semantics for instructions. This is to provide compatibility with the configurable instruction set in OpenQL. However, for many of cQASM’s use cases, it makes sense to have a standardized instruction set (historically, this instruction set was in fact baked into the language). This standardized instruction set is specified at the bottom of this section.
Assignment instruction¶
Special syntax is available for the set
instruction, namely:
set <expr> = <expr>
This intends to make variable assignments more readable.
Note
In cQASM 1.0 and 1.1, set
behaves like a normal instruction with two
operands. That means it must be defined as part of the instruction set via
the API prior to parsing if the target supports it. In cQASM 1.2+, set
is a special instruction that requires no definition; cQASM 1.2+ readers
are expected to support set instructions in all cases.
Goto instruction (1.2+)¶
In cQASM 1.2+, unstructured control-flow can be represented using
(non-repeating) subcircuits as labels and goto instructions. The syntax for a
goto
instruction is:
goto <name>
<name>
must match the name of exactly one subcircuit header in the program.
Note
goto
is a special instruction that bypasses the type system in order to
correctly resolve the subcircuit name. It is always defined, regardless of
whether a goto
instruction is added to the instruction set via the API.
In file versions older than 1.2, goto
behaves like a normal
instruction.
Note
Conditional branches can be represented using the notation for conditional execution as defined in the next section.
Conditional instructions¶
Instructions can be made conditional; that is, the instruction should only execute if a certain classical boolean condition evaluates to true at runtime. This can be used to alter the behavior of an algorithm based on previous measurement results, for example to apply error correction. An instruction can be made conditional in two ways:
cond (<condition>) <name> <operands>
c-<name> <condition>, <operands>
Both forms are equivalent. The latter mostly exists for backward-compatibility, as the former is considered more readable.
Whenever multiple measurement bits in the b
register are selected for a
condition simultaneously, the states of these bits must be implicitly combined
using an AND gate at runtime.
Note
You cannot specify multiple condition bits by comma-separating the bits. You have to use the slice notation on the bit register accordingly if you want this. For example,
# c-x b[0], b[1], q[2] <- not legal!
c-x b[0,1], q[2] # <- correct variant.
Note
While syntactically identical, specification of multiple condition bits for a gate is completely unrelated to the single-gate-multiple-qubit notation described in the next subsection. Do not confuse the two! The reason for this oddity is, as usual, a historical one.
Note
Selecting multiple bits at once is only supported within the condition of a gate, or as a gate operand via single-gate-multiple-qubit notation. It is illegal in all other contexts.
Single-gate-multiple-qubit¶
To more ergonomically specify many of the same gate operating in parallel on
multiple qubits, each qubit argument of a gate may be given more than one qubit
through the slice notation for the q
register. The individual qubits are
then broadcast to individual gates. For example,
x q[0:3]
# is functionally equivalent to
x q[0] | x q[1] | x q[2] | x q[3]
For multi-qubit gates, the slice sizes for each qubit operand must match;
# cnot q[0], q[1,2] <- not legal, q[0] is not broadcast
Note that this never makes any sense for qubits, as a qubit can only be used once within a group of parallel gates, and single-gate-multiple-qubit notation asserts that the gates start simultaneously.
Warning
The original libqasm API asserts uniqueness of the qubits in the slices by sorting the list of indices and silently removing duplicates. This is very much a bug:
cnot q[1,2], q[3, 0]
# becomes equivalent to...
cnot q[1], q[0] | cnot q[2], q[3]
# in the old API, but becomes
cnot q[1], q[3] | cnot q[2], q[0]
# in the new API (as you should expect)!
This behavior was kept in place in the original libqasm API for backward compatibility, but the new API doesn’t do the sort. In general, it is best to avoid single-gate-multiple-qubit notation for multi-qubit gates.
Default instruction set¶
Whenever libqasm’s original API is used or the new API is instructed to use the default instruction set, libqasm determines the supported set of instructions and (implicitly) their semantics and, to some extent, timing behavior. The instruction set is as follows.
x <qubit>
¶
The Pauli-X gate is a single-qubit rotation through π radians around the X-axis.
y <qubit>
¶
The Pauli-Y gate is a single-qubit rotation through π radians around the Y-axis.
z <qubit>
¶
The Pauli-Z gate is a single-qubit rotation through π radians around the Z-axis.
i <qubit>
¶
The identity gate leaves the state of a qubit unchanged. It thus acts as a no-operation gate, which may be useful for certain simulation error models.
h <qubit>
¶
The Hadamard gate is used to create a superposition of the two basis states.
x90 <qubit>
¶
The x90 gate is a single-qubit rotation through 1/2 π radians around the X-axis.
mx90 <qubit>
¶
The mx90 gate is a single-qubit rotation through negative 1/2 π radians around the X-axis.
y90 <qubit>
¶
The y90 gate is a single-qubit rotation through 1/2 π radians around the Y-axis.
my90 <qubit>
¶
The my90 gate is a single-qubit rotation through negative 1/2 π radians around the Y-axis.
s <qubit>
¶
The S gate is a single-qubit rotation through 1/2 π radians around the Z-axis.
sdag <qubit>
¶
The S-dagger gate is a single-qubit rotation through negative 1/2 π radians around the Z-axis.
t <qubit>
¶
The T gate is a single-qubit rotation through 1/4 π radians around the Z-axis.
tdag <qubit>
¶
The T-dagger gate is a single-qubit rotation through negative 1/4 π radians around the Z-axis.
rx <qubit>, <angle>
¶
Performs an arbitrary rotation around the X axis on the given qubit. The angle is specified in radians.
ry <qubit>, <angle>
¶
Performs an arbitrary rotation around the Y axis on the given qubit. The angle is specified in radians.
rz <qubit>, <angle>
¶
Performs an arbitrary rotation around the Z axis on the given qubit. The angle is specified in radians.
u <qubit>, <matrix>
¶
The U gate applies an arbitrary single-qubit unitary gate to the given qubit. The matrix must be a complex 2-by-2 unitary matrix, though libqasm does not assert the unitary condition of the matrix.
cnot <qubit>, <qubit>
¶
Applies a CNOT (controlled X) gate on the given qubits. The first qubit is the control, the second qubit is the target.
cz <qubit>, <qubit>
¶
Applies a controlled phase (controlled Z) gate on the given qubit pair.
swap <qubit>, <qubit>
¶
Swaps the state of the given two qubits.
cr <qubit>, <qubit>, <angle>
¶
Applies a controlled phase (controlled Z) gate with the given rotation angle in radians on the given qubit pair. The first qubit is the control qubit, the second is the target.
cr <qubit>, <qubit>, <k>
¶
Applies a controlled phase (controlled Z) gate with the given rotation angle on the given qubit pair. The rotation angle is π/2k radians. The first qubit is the control qubit, the second is the target.
toffoli <qubit>, <qubit>, <qubit>
¶
Applies a Toffoli gate (controlled X with two control qubits) on the given qubits. The first two qubits are the control qubits, the third is the target.
prep <qubit>
¶
Prepares the given qubit in the Z basis (|0>). Synomym for prep_z
.
prep_x <qubit>
¶
Prepares the given qubit in the X basis.
prep_y <qubit>
¶
Prepares the given qubit in the Y basis.
prep_z <qubit>
¶
Prepares the given qubit in the Z basis (|0>). Synomym for prep
.
measure <qubit>
¶
Measures the given qubit in the Z basis. |0> results in false, |1> results in
true. If the qubit is part of the qubit register, the measurement is stored in
the accompanying measurement bit; if it is a variable, the result is discarded.
Synonym for measure_z
.
measure_x <qubit>
¶
Measures the given qubit in the X basis. If the qubit is part of the qubit register, the measurement is stored in the accompanying measurement bit; if it is a variable, the result is discarded.
measure_y <qubit>
¶
Measures the given qubit in the Y basis. If the qubit is part of the qubit register, the measurement is stored in the accompanying measurement bit; if it is a variable, the result is discarded.
measure_z <qubit>
¶
Measures the given qubit in the Z basis. |0> results in false, |1> results in
true. If the qubit is part of the qubit register, the measurement is stored in
the accompanying measurement bit; if it is a variable, the result is discarded.
Synonym for measure
.
measure_all
¶
Measures all qubits in the qubit register in the Z basis, and stores the results in the measurement bit register. |0> results in false, |1> results in true. This instruction cannot share a bundle with other instructions.
measure_parity <qubit>, <axis>, <qubit>, <axis>
¶
Refer to section IV-A of the arXiv paper.
skip <integer>
¶
Skip the specified number of cycles. The bundle following the skip will start the given amount plus one cycle after the bundle preceding the skip. For example:
x q[0] # starts in cycle i
skip 3 # starts in cycle i+1
x q[0] # starts in cycle i+4
This instruction cannot share a bundle with other instructions.
wait <integer>
¶
Wait for all previous instructions to finish, then wait the given number of cycles before starting the next bundle. Also known as a barrier. In essence, this acts as a no-op instruction with the specified duration in cycles, that requires access to all qubits, bits, and variables.
Note
When OpenQL is used, you should use wait
instructions rather than
skip
to introduce delays. The scheduler will ignore any other timing
semantics in your program, including whether you placed instructions in a
bundle or not. The timing of the algorithm after scheduling will be
represented using skip instructions and bundles exclusively. Nevertheless,
the wait
instructions will remain, so the requested (minimum) delays
are also represented, so running the scheduler again would not break the
program. For example,
x q[0]
wait 3
x q[1]
may compile into
x q[0] # starts in cycle 0
wait 3 # starts in cycle 1
skip 2 # starts in cycle 2
x q[1] # starts in cycle 4
not <bit-ref>
¶
Inverts the state of the given measurement bit register or classical bit variable.
display [bit-ref]
¶
Meta-instruction for simulators, telling the simulator to print the bit and qubit state for the given bit reference, or for all qubits if the optional reference is omitted. This instruction cannot share a bundle with other instructions.
display_binary [bit-ref]
¶
Meta-instruction for simulators, telling the simulator to print the given measurement bit state, or the state of all measurement bits in the register if the optional reference is omitted. This instruction cannot share a bundle with other instructions.
reset-averaging [qubit]
¶
Meta-instruction for simulators, telling the simulator to reset internal averaging counters for all measurements performed up to that point for the given qubit(s), or all qubits in the register if no reference is specified. This instruction cannot share a bundle with other instructions.
Historical
This instruction uses a dash in the name instead of an underscore for some
reason, requiring a special case in the tokenizer (after all, it would be
a subtraction otherwise). It is not possible to define custom instructions
with dashes in them other than exactly reset-averaging
.
load_state <filename>
¶
Meta-instruction for simulators, telling the simulator to load the qubit register state from the given filename. The filename is to be specified as a string literal. This instruction cannot share a bundle with other instructions.