Expressions
Expressions in Qmod have syntax, semantics, and use, similar to expressions in
conventional programming languages.
They comprise literal values, variables, and operators applied to them.
However, Qmod is unique in that variables can be of either classical or
quantum types, and quantum variables have states that can be a
superposition of values, entangled with the states of other variables.
Expressions over quantum variables evaluate to a superposition of correlated
values.
For example, if x is a classical variable
of type CInt (an integer), then x + 1 is a classical expression of type
CInt comprising the operator + (plus) applied to x and the literal 1.
Similarly, if qarr is a quantum variable
of type QArray[QNum[3]], then qarr[0] > x is a quantum expression of type
QBit.
Unary operators are applied to a single operand. For instance, you can apply
the unary operator ~ (bitwise-invert) to variable x and get the expression
~x.
Binary operators are applied to two operands. For example, the operator >
(greater-than) in the expression qarr[0] > x is applied to two operands,
qarr[0] and variable x.
The expression qarr[0] comprises the subscript operator [] applied to
variable qarr and the literal 0.
Applications of subscript ([]) and field-access (.) operators to classical
and quantum variables are called path expressions, since they point to a
partial section of the variable along a certain access path.
In our case, for instance, qarr[0] represents the first (0) element of the
array qarr.
Qmod Operators
You can apply operators to operand expressions to create composite expressions. If at least one of the operands is quantum then the expression is quantum as well; Otherwise, it is classical.
Qmod supports the following operators:
Arithmetic operators
You can apply arithmetic operators to classical numbers (CInt and CReal) and
quantum scalars (QBit and QNum) to create numeric expressions.
- Add: +
- Subtract: - (binary)
- Negate: - (unary)
- Multiply: *
- Power ** (quantum base, positive classical integer exponent)
- Modulo: % limited for power of 2
- Max: max (n>=2 arguments)
- Min: min (n>=2 arguments)
Bitwise operators
You can apply bitwise operators to classical numbers (CInt and CReal) and
quantum scalars (QBit and QNum) to create numeric expressions.
- Bitwise Or: |
- Bitwise And: &
- Bitwise Xor: ^
- Bitwise Invert: ~
Relational operators
You can apply relational operators to classical numbers (CInt and CReal) and
quantum scalars (QBit and QNum) to create Boolean expressions (of types
CBool and QBit).
- Equal: ==
- Not Equal: !=
- Greater Than: >
- Greater Or Equal: >=
- Less Than: <
- Less Or Equal: <=
Logic operators
You can apply logical operators to Boolean expressions (CBool, QBit, and
QNum[1]) to create Boolean expressions (of types CBool and QBit).
- Logical And:
logical_and()(in Qmod Native: and) - Logical Or:
logical_or()(in Qmod Native: or) - Logical Not:
logical_not()(in Qmod Native: not)
Path operators
You can use path operators to access parts of classical and quantum variables of aggregate types, namely, structs and arrays.
- Field Access: struct . field-name
- Array Slice: array [ start-index : stop-index ]
- In Python, start-index and stop-index may be omitted.
If start-index is omitted, a
0will be placed in its stead. If stop-index is omitted,array.lenwill be placed in its stead.
- In Python, start-index and stop-index may be omitted.
If start-index is omitted, a
- Array Subscript: array [ index ]
- The index of a quantum subscript expression must be an unsigned quantum integer variable.
- In Python, if array is a Python list and index is a quantum variable, use the alternative syntax: subscript( array , index )
- Currently, quantum subscript expressions are not supported in phase statements.
Quantum Expressions
Quantum expressions are expressions that involve one or more quantum variables. Quantum expressions can occur in the following contexts:
- The right-value in assignment statements
- The condition in control statements
- The expression argument in phase statements
During computation, the value(s) of an expression are coherently correlated to the evaluation of the operators over the computational-basis values of the quantum variables it comprises, which may be in any specific superpositions and entanglement. Quantum expressions may include any combination of operators on any classical and quantum variables and literals, with the following exceptions:
- All classical variables must be compile-time.
- The right-hand side of the division (
/) and power (**) operators must be a classical expression.
Examples
The following model includes qubit q and quantum numeric n of size three.
It uses a control statement with a quantum expression n > 4 to apply
X to q only when n is greater than four.
from classiq import qfunc, Output, QBit, QNum, allocate, control, hadamard_transform
@qfunc
def main(n: Output[QNum[3]], q: Output[QBit]):
allocate(n)
hadamard_transform(n)
allocate(q)
control(n > 4, lambda: X(q))
qfunc main(output n: qnum<3>, output q: qbit) {
allocate(n);
hadamard_transform(n);
allocate(q);
control(n > 4) {
X(q);
}
}
After executing this model, you get \(q=0\) for \(n\in\{0, 1, 2, 3, 4\}\) and \(q=1\) for \(n\in\{5, 6, 7\}\).
See additional examples on the Assignment documentation page.
Classical Expressions
Classical expressions are expressions that involve classical variables and
constant literals, but no quantum variables.
Classical variables may have known values at [compile time, link time, or runtime]](https://docs.classiq.io/latest/qmod-reference/language-reference/classical-variables/#semantics).
Classical expressions with only compile-time variables are evaluated and
simplified during compilation.
This applies sub-expressions of quantum expressions too.
Qmod supports several built-in classical constants and functions,
such as pi and sin.
Example
In the following model, function foo accepts quantum numeric n and a
classical integer x, and perform the in-place xor operation n ^= x + 1.
Function foo is called twice, once with x=1 and once with x=-1.
from classiq import qfunc, CInt, Output, QNum
@qfunc
def foo(n: QNum, x: CInt):
n ^= x + 1
@qfunc
def main(n: Output[QNum]):
n |= 1
foo(n, 1) # n ^= 2
foo(n, -1) # n ^= 0
qfunc foo(n: qnum, x: int) {
n ^= x + 1;
}
qfunc main(output n: qnum) {
n = 1;
foo(n, 1); // n ^= 2;
foo(n, -1); // n ^= 0;
}
On the first call to foo, the Qmod compiler assigns x=1 and simplifies the
expression x + 1 into 2.
Therefore, the first foo call applies a constant-value xor n ^= 2.
On the second call to foo, the expression x + 1 is simplified to 0.
Since the assignment n ^= 0 has no effect, the Qmod compiler removes it from
the model.