Statements¶
A cQASM 1.x file ultimately consists of a number of statements. Several kinds of statements are defined. They are all listed in this section.
Version statement¶
The first statement in every cQASM file must be a version statement. It specifies which version of the cQASM language is to be used when parsing. It has the form
version <period-separated-integers>
For example, the version statement for a cQASM 1.0 file must be
version 1.0
cQASM 1.1 adds support for variables and dynamic expressions. In order to use these features, you have to select at least version 1.1:
version 1.1
cQASM 1.2 adds support for assignment statements and structured control-flow. In order to use these features, you have to select at least version 1.2:
version 1.2
Qubits statement¶
This statement declares the desired size of the qubit register (q
) and
associated measurement bit register (b
). It has the form:
qubits <positive-integer-constant>
It must be the second statement in the cQASM file if specified. The statement
is mandatory in cQASM 1.0, but optional for cQASM 1.1+. The latter allows
variables to be used to replace the qubits
statement, avoiding the implicit
link between qubits and measurement bit storage that is not universal among
control architectures.
Error model statement¶
Optionally, an error model statement may be used to select and configure an error model for the targeted simulator. It has the following form:
error_model <name>, <comma-separated-operands>
Available error models must be registered with libqasm while the parser is
constructed when using the new API, but for the old API, QX’s error models is
built in. In this case, the only value for <name>
is
depolarizing_channel
, and zero or more real numbers may be specified as
arguments. Refer to QX’s documentation for information about what these
arguments do.
Historical
The original API of libqasm allowed the user to specify the error model anywhere in the program, and performed no check to ensure that it would only be specified once. Ultimately, the final error model specified determines the error model for the program. For backward-compatibility reasons, this behavior is mimicked by the new API.
Error model definitions may be annotated.
Variable statement (1.1+)¶
This statement declares one or more variables. It is only supported for targets that actually support variables. It has the following form:
var <comma-separated-names>: <type>
where <type>
may be qubit
, bool
, bit
(synonym for bool),
int
, real
, or complex
.
Variable statements may appear anywhere in the program. the variable will be usable from its declaration onwards. It is legal, if perhaps ill-advised, to make multiple variables of the same name; they will be interpreted as distinct variables, where references to that variable name simply refer to the latest declaration.
The initial value of a variable is undefined.
Note
Because variables can be declared anywhere, they can also be declared within the code blocks of cQASM 1.2+’s structured control-flow statements. In this case, the variable can only be accessed from within the code block. Typically, the variable will behave like a global, i.e. it will retain the value of the previous loop iteration for instance, but implementations are not required to do this! Again: the initial value of a variable is undefined.
Variable statements can be annotated.
Map statement¶
This statement maps an expression to a word, allowing the expression to be used later by simply using the word, like an alias or a macro. It has the following equivalent forms:
map <expression>, <alias>
map <alias> = <expression>
Here, <alias>
is a word consisting of letters, digits, and underscores, not
starting with a digit. <expression>
is any expression of any data type.
Name resolution for any mappings in the expression occurs in the context of the
map
statement, but the expression itself is only evaluated when the alias is
used.
Map statements can be annotated.
Note
Map statements are NOT assignment statements. They are functionally equivalent to a lambda without arguments in Python or (more or less) preprocessor definitions in C; the expression is not evaluated by the map statement, but where the mapping is used. For example, in the following algorithm (assuming perfect qubits and measurement),
prep_z q[0]
measure q[0]
map q0_measured_zero = !b[0]
cond (q0_measured_zero) x q[0]
measure q[0]
cond (q0_measured_zero) x q[0]
the first X gate would be executed, because b[0]
is false/zero, thus
!b[0]
is true. But q0_measured_zero
has not assumed the value
true
; it retains the complete expression. Therefore, the second X gate
would NOT be executed, as the second measurement flips the state of
b[0]
. The position of the map statement doesn’t matter, as long as it’s
before the first line where q0_measured_zero
is used.
Historical
Mappings are called such because originally they were only used to allow users to rename the numbered qubits and measurement bits in the qubit register to some user-specified name to make programming algorithms in cQASM more ergonomic. When expressions were added however, it made sense to extend the definition to any kind of expression, allowing it to be reused for all the things listed above.
Subcircuit headers¶
Subcircuit header statements can be used to divide an algorithm up into logical subsections, and may also be used to specify that a part of the algorithm must be repeated a constant number of times. They have the following forms:
.<name>
.<name>(<repeat-count>)
Here, <name>
is a word consisting of letters, digits, and underscores, not
starting with a digit. <repeat-count>
is a constant positive integer. The
subcircuit header signifies that all bundles up to the next subcircuit header
or the end of the file belong to a subcircuit named <name>
, and that that
subcircuit must be evaluated <repeat-count>
times. The repeat count is
implicitly one when not specified.
Subcircuit headers may be annotated.
Bundles and instructions¶
The algorithm is ultimately described using bundles, defined to be one or more
instructions issued simultaneously. They are either specified using a
pipe-separated list (|
) of one or more instructions on a single line, or
using a multiline curly-bracket-delimited list ({
and }
) of one or more
pipe-separated lists of one or more instructions. For example,
<insn-a> | <insn-b> | <insn-c>
# In both the above and below case, all three instructions start simultaneously.
{
<insn-a> | <insn-b>
<insn-c>
}
The instruction format is documented in the next section.
Note
Instructions are not statements; only bundles are. A single instruction on its own line is simply a bundle with only one instruction in it.
Both the individual instructions in a bundle and the bundle as a whole can be annotated. The former takes precedence; therefore, annotating a bundle can only be done using the curly-bracket notation.
If-else chain (1.2+)¶
In cQASM 1.2+, branch-based conditional blocks can be constructed using if-else chains. They have the following syntax.
# Simple if statement.
if (<condition>) {
<statements>
}
# If-else statement.
if (<condition>) {
<statements>
} else {
<statements>
}
# If-elif-else statement. You can repeat as many "else if" blocks as you
# like.
if (<condition>) {
<statements>
} else if (<condition>) {
<statements>
} else {
<statements>
}
The shown newlines are optional. The {
s and }
s surrounding the
code blocks are mandatory.
Note
The {}
blocks do not imply parallel execution in this context.
The conditions must evaluate to a boolean.
C-style for loop (1.2+)¶
In cQASM 1.2+, C-style for loops can be written as follows.
for (<initialize>; <condition>; <update>) {
<statements>
}
<initialize>
is optional. If specified, it must be of the form
<name> = <expression>
, representing an initializing assignment statement.
It is executed at the start of the loop.
Note
Unlike C, it is not possible to declare a new variable as part of
<initialize>
.
<condition>
must be an expression that evaluates to a single boolean. It is
evaluated at the start of each loop iteration. If it yields true, iteration
continues; if it yields false, execution continues after the for loop.
<update>
is optional. If specified, it must be of the form
<name> = <expression>
, representing an assignment statement. It is executed
at the end of each loop iteration. It is intended to be used to update the loop
variable.
The loop body may include continue
and break
statements.
Note
The {}
block for the loop body does not imply parallel execution.
Foreach loop (1.2+)¶
In cQASM 1.2+, a loop that iterates over a range of integer values can be written as follows.
foreach (<name> = <from> .. <to>) {
<statements>
}
<name>
must be an integer variable, and <from>
and <to>
must
constant-propagate to integer literals; that is, both integers must be
known at compile-time. The loop body will be executed for all values in
the specified inclusive range. If <from>
is less than <to>
, <name>
will be incremented by one after each iteration. If <from>
is greater than
<to>
, <name>
will be decremented by one after each iteration.
Behavior is undefined if <name>
is reassigned from within the loop body.
The loop body may include continue
and break
statements.
Note
The {}
block for the loop body does not imply parallel execution.
While loop (1.2+)¶
In cQASM 1.2+, a loop that iterates while a condition is true can be written as follows.
while (<condition>) {
<statements>
}
<condition>
must be an expression that evaluates to a boolean. It is
evaluated at the before a new iteration. If it evaluates to true, iteration
will continue. Otherwise, execution will continue after the while loop.
The loop body may include continue
and break
statements.
Note
The {}
block for the loop body does not imply parallel execution.
Repeat-until loop (1.2+)¶
In cQASM 1.2+, a loop that iterates until a condition is true can be written as follows.
repeat {
<statements>
} until (<condition>)
<condition>
must be an expression that evaluates to a boolean. It is
evaluated at the end of each iteration. If it evaluates to false, iteration
will continue. Otherwise, execution will continue after the repeat-until
loop.
The loop body may include continue
and break
statements.
Note
The {}
block for the loop body does not imply parallel execution.
Break statement (1.2+)¶
In cQASM 1.2+, the innermost loop can be terminated at any time by means of a
break
statement. The syntax is simply:
break
It is illegal to use a break
statement outside of the context of a
structured loop (for
, foreach
, while
, or repeat
-until
).
A subcircuit with a repetition count does not qualify as a loop in this
context.
Continue statement (1.2+)¶
In cQASM 1.2+, the current loop iteration can be stopped at any time by means
of a continue
statement. Execution will continue as if the end of the loop
body had been reached. The syntax is simply:
continue
It is illegal to use a continue
statement outside of the context of a
structured loop (for
, foreach
, while
, or repeat
-until
).
A subcircuit with a repetition count does not qualify as a loop in this
context.