Expressions¶
All operands in cQASM 1.x can in principle be arbitrary expressions, as long as the type system (explained in the next section) considers them valid within context. The primary use cases of expressions in cQASM are indexing into the qubit and measurement bit registers, writing things more intuitively through constant propagation (for instance by scaling a matrix using scalar-matrix multiplication to make it unitary), and combining measurement results together for gate conditions. This chapter lists the available types of expressions.
Number literals¶
cQASM 1.x supports unsigned integer literals in decimal format only. Floating
point literals use a period (.
) decimal separator. The integer part may be
omitted if zero, but the fractional part may not be; for example, .1
is
legal, but 0.
is not. Power-of-ten exponent notation is supported; for
example, 1.0e3
is the same as 1000.0
.
Negative numbers are expressed by applying the unary negation operator on a
positive number literal (this of course looks the same as a negative number
literal, but this is how it works internally). Complex numbers are expressed
using sums and products of real numbers and the imaginary unit (im
, a named
constant).
Matrix literals¶
Matrix literals are lists of (constant) numbers enclosed within square brackets
([
and ]
). Separation of elements along the minor axis is done using
commas (,
), while separation of elements along the major axis is done using
newlines or semicolons. An optional newline (or semicolon) may appear between
the opening bracket and the first element, and/or between the last element and
the closing bracket.
[1, 2, 3] # 3-entry row vector
[1; 2; 3] # 3-entry column vector
[1, 2; 3, 4] # 2x2 matrix
[
1, 2
3, 4
] # alternative notation for the same 2x2 matrix
cQASM 1.x only supports real- and complex-valued matrices.
String and JSON literals¶
String literals are enclosed in double quotation marks on either end ("
) as
in C. Newlines embedded in the string become part of the string unless escaped
with a backslash (\
). Escape sequences exist for tab (\t
), newline
(\n
), single quote (\'
), double quote (\"
) and backslash (\\
).
JSON objects can be represented as-is, except the outermost curly brackets must
be replaced by {|
and |}
to disambiguate between bundle notation and a
JSON literal. The contents of the JSON object support everything that the JSON
specification supports, but libqasm makes no attempt to parse or validate the
contents as such.
Note that these types of literals are primarily intended for use in annotations and meta-instructions such as a print statement for simulation, as they don’t map cleanly to hardware.
Mappings, references, and named literals¶
Any word consisting of letters, numbers, and/or underscores (_
) and not
starting with a number that appears where an expression is expected and isn’t
a function name, may be any of the following things:
- a user-specified mapping, defined by a preceding
map
statement; - a reference to the qubit register, defined by the
qubits
statement to the letterq
; - a reference to the measurement bit register, defined by the
qubits
statement to the letterb
; - a reference to a user-specific variable, defined by a
var
statement (if supported by the target); - one of the following named constants:
-
pi
for 3.1415…, -eu
for 2.7182…, -im
for the imaginary unit, -true
andfalse
for booleans, and -x
,y
, andz
for axes; - a target-specific reference.
Internally, all these things are actually mappings. The latter two are called “initial mappings;” they are defined using libqasm’s API during construction of the parser object.
Indexation and slicing¶
The qubit and measurement bit registers behave like one-dimensional vectors
that can be indexed and sliced. The notation is <register>[<index-list>]
,
where <index-list>>
is a comma-separated list of integer indices or ranges.
Range notation specifically consists of a colon-separated (:
) pair of
integers representing the lower and upper limit of an inclusive, ascending
range; 1:4
is for instance equivalent to 1,2,3,4
.
The result of the index operator behaves as a new reference to a qubit or bit register, but of the size equal to the number of indices in the slice (it can thus also be larger than the original register if indices are repeated) and with the elements in a potentially different order. The indices must be constant, and indexation/slicing is only supported on qubit and measurement bit registers (not on matrices).
Functions¶
Functions have the form <name>(<comma-separated-arguments>)
; you should
recognize this notation from basically every other programming language out
there. They can be used for constant propagation, or (when supported by the
target) to describe classical operation on data. cQASM 1.x does not provide a
way to define functions in the cQASM file; instead, they are defined by the
program or library using libqasm prior to parsing. This program or library is
free to define whatever functions they want, but a default set is provided by
libqasm as a sort of standard library. This library currently includes the
following:
sqrt(x)
: returns the square root ofx
, wherex
is a real or complex number.exp(x)
: returns ex, wherex
is a real or complex number.log(x)
: returns the natural logarithm ofx
, wherex
is a real or complex number.sin(x)
: returns the sine ofx
, wherex
is a real or complex number.cos(x)
: returns the cosine ofx
, wherex
is a real or complex number.tan(x)
: returns the tangent ofx
, wherex
is a real or complex number.asin(x)
: returns the arcsine ofx
, wherex
is a real or complex number.acos(x)
: returns the arccosine ofx
, wherex
is a real or complex number.atan(x)
: returns the arctangent ofx
, wherex
is a real or complex number.sinh(x)
: returns the hyperbolic sine ofx
, wherex
is a real or complex number.cosh(x)
: returns the hyperbolic cosine ofx
, wherex
is a real or complex number.tanh(x)
: returns the hyperbolic tangent ofx
, wherex
is a real or complex number.asinh(x)
: returns the hyperbolic arcsine ofx
, wherex
is a real or complex number.acosh(x)
: returns the hyperbolic arccosine ofx
, wherex
is a real or complex number.atanh(x)
: returns the hyperbolic arctangent ofx
, wherex
is a real or complex number.abs(x)
: returns the absolute value ofx
, wherex
is an integer or a real number.complex(r, i)
: returns the complex number with real partr
and imaginary parti
, wherer
andi
are real numbers.polar(norm, arg)
: returns the complex number with magnitudenorm
and anglearg
(in radians), wherenorm
andarg
are real numbers.real(c)
: returns the real part of the given complex number.imag(c)
: returns the imaginary part of the given complex number.arg(c)
: returns the argument of the given complex number in radians.norm(c)
: returns the norm of the given complex number.conj(c)
: returns the conjugate of the given complex number.
Functions operating on matrices are not yet part of the standard library, because there’s quite a bit of manual labor involved with implementing those. Please make an issue in the libqasm GitHub project if you would like to have them.
cQASM 1.0 does not support functions evaluated at runtime; only constant propagation is supported. cQASM 1.1 adds support for such dynamic expressions, but the default set of functions is still constant-propagation-only.
Unary, binary, and ternary operators¶
cQASM 1.x supports various unary and binary operators, as well as the ternary
conditional operator from C. Internally, these are just syntactic sugar for
functions named operator
followed by the prefix or infix symbols
representing the operator. The full list, along with precedence rules, is
listed below. Deviations from the C standard are specified.
Operator | Description | Precedence and associativity |
---|---|---|
-x |
Negation | 1, ← |
!x |
Logical NOT | |
~x |
Bitwise NOT | |
x ** y |
Exponentiation (Python) | 2, ← |
x * y |
Multiplication | 3, → |
x / y |
True division (Python) | |
x // y |
Flooring division (Python) | |
x % y |
Modulo (Python) | |
x + y |
Addition | 4, → |
x - y |
Subtraction | |
x << y |
Shift left | 5, → |
x >> y |
Arithmetic shift right (Java) | |
x >>> y |
Logical shift right (Java) | |
x < y |
Less than | 6, → |
x <= y |
Less than or equal | |
x > y |
Greater than | |
x >= y |
Greater than or equal | |
x == y |
Equality | 7, → |
x != y |
Inequality | |
x & y |
Bitwise AND | 8, → |
x ^ y |
Bitwise XOR | 9, → |
x \| y |
Bitwise OR (*) | 10, → |
x && y |
Logical AND | 11, → |
x ^^ y |
Logical XOR (*) | 12, → |
x \|\| y |
Logical OR | 13, → |
x ? y : z |
Ternary conditional | 14, ← |
The arithmetic operators deviating from C were taken from Python because Python’s behavior is more intuitive when doing high-level math. Integer division and accompanying modulo/remainder follow Python’s behavior as well (sign of remainder = sign of divider), because the round-to-zero behavior in the C standard is more historical than it is useful.
The right-shift operators follow Java, because (like Java) cQASM doesn’t have unsigned integers. Therefore, disambiguation of logical (shift in zeros) vs. arithmetic (shift in sign bit) for right-shift has to be done using the operator rather than the operand types.
The | operator (bitwise OR) requires further explanation in cQASM 1.x, because it conflicts with the | separator in bundle notation. To avoid breaking anything, the | operator is illegal as argument to a gate without at least one level of parentheses surrounding it; | always defaults to separating gates in a bundle otherwise. This applies even when the resulting parse tree would be invalid; this is a limitation of LALR(1) parsers such as Bison, the one used by libqasm.
The ^^ operator is typically missing from languages, because one of the primary purposes of it is “short-circuiting” of operand evaluation, and an XOR gate always requires both operands to be evaluated. Nevertheless, there are several arguments for including it anyway, even in C. Not mentioned there is that it is also a natural expansion of the operator precedence table. Worth noting also is that side effects of expressions are not first-class citizens in cQASM as they are in C (libqasm makes no assertion about whether they can have side effects or not), so the short-circuiting argument is moot anyway. Finally, the existence of the expression doesn’t hurt anyone; it would be invalid syntax would it not exist, and the program/library using libqasm is free to not register any implementation for operator^^, thus disabling it entirely.
cQASM 1.0 does not support operations evaluated at runtime; only constant propagation is supported. cQASM 1.1 adds support for such dynamic expressions, but the default set of operations is still constant-propagation-only.
Grouping parentheses¶
Parentheses ((
and )
) may be placed around expressions to order expressions
differently than what the precedence rules would result in, or to disambiguate
between the pipe (|
) used for separating instructions in bundle notation
and the bitwise OR operator.