Skip to content

Quantum Types and Expressions in QMOD

In QMOD quantum variables can be assigned the result of expressions over other quantum variables. Expressions can be arithmetic, relational, or bitwise. The quantum variables in the expression have to be of one of the following numeric quantum types:

  • QInt: A quantum (signed) integer. The constructor QInt(size) can be used to declare a QInt of a particular size (in qubits).
  • QFixed: A quantum (signed) fixed-point fractional number. The constructor QFixed(size, fraction_places) can be used to declare a QFixed of a particular size and fractional places (in qubits).

Expression assignment constructs

The assignment of quantum expressions takes one of the following forms:

  • <qvar> |= <expression> - allocate a storage for the result of <expression> and associate it <qvar>, which has not been allocated
  • <qvar> ^= <expression> - xor the result of <expression> in-place with the value of <qvar> that has already been allocated/initialized
  • <qvar> *= <expression> - encode the result of f(x) = <expression> into the amplitude of <qvar>, such that for an input quantum variable in the state \(|x\rangle\), you obtain an output qubit in the state \(\sqrt{1-f(x)^2}ֿ|0\rangle+f(x)ֿ|1\rangle\)

The expression itself is composed of quantum variables, native Python constants, and (in most cases) native Python operators. The expression language is based on the Python package Sympy, and conforms to its construction rules. See more under Sympy Docs.

Notes:

  • The size of the newly allocated quantum variable in the |= form is calculated to tightly fit the possible result value, based on the expression variable sizes, constants, and operators.
  • The variables occurring in the expression can subsequently be used, with value unmodified.
  • For equality (==), inequality (!=), conjunction (and) and disjunction (or) use the respective Sympy classes Eq, Ne, And, and Or.
  • Currently only single-bit variables can be used with the ^= form, corresponding to the result of a relational expressions, or bitwise expressions over single-qubit variables
  • For the *= operator, several conditions have to be satisfied:
    1. The <expression> should contain only a single variable.
    2. The input variable should be a QFixed number between 0 and 1.

Examples

The following is a model that computes the result of the expression a + 2 * b + 3, with a initialized to 3 and b initialized to equal superposition of 1 and 2. The output is superposition of 8 and 10.

from classiq import Output, QBit, QInt, QArray, QFunc, prepare_int


@QFunc
def main(res: Output[QInt]) -> None:
    a = QInt("a")
    b = QInt("b")
    prepare_int(3, a)
    prepare_state([0, 0.5, 0.5, 0], 1e-4, b)  # b = superposition of 1 and 2
    res |= a + 2 * b + 3  # should be 8

Note that the size of the output is 4 qubits, since the maximum value of this expression is 15, given a and b are two qubit variables. Any other size declared for res will result in an error.

In the next example the relational expression a + 2 * b + 3 == 8 is computed, with a initialized to 3 and b initialized to 1. Calling function foo will flip the single variable res, because the expression evaluates to 1, that is, true.

from sympy import Eq

from classiq import QBit, QInt, QFunc, prepare_int


@QFunc
def foo(res: QBit) -> None:
    a = QInt("a")
    b = QInt("b")
    prepare_int(3, a)
    prepare_int(1, b)
    res ^= Eq(a + 2 * b + 3, 8)  # should be 1..

In the next example function my_oracle serves as a quantum oracle that marks all states satisfying the expression x0 & x1 ^ x2 & x3 with a minus phase.

from classiq import QBit, QFunc, allocate, X, H, free


@QFunc
def my_oracle(x0: QBit, x1: QBit, x2: QBit, x3: QBit) -> None:
    aux = QBit("aux")
    allocate(1, aux)
    X(aux)
    H(aux)
    aux ^= x0 & x1 ^ x2 & x3
    H(aux)
    X(aux)
    free(aux)