Skip to content

Classical Types

Classical types in Qmod are not very different from classical types in conventional programming languages. There are scalar types like int and bool, and aggregate types, such as arrays and structs.

Classical types are used to declare classical function arguments, and global constants. Variables and literal values of classical types can be used in expressions, and support the conventional set of operators commonly available in conventional programming languages.

Scalar Types

In Qmod, scalar types represent numeric values, Boolean values, and Pauli base elements.

Syntax

  • int represents integers
  • real represents real numbers (using floating point encoding)
  • bool represents the Boolean values false and true
  • Pauli represents the Pauli base elements using the symbols Pauli::I, Pauli::X, Pauli::Y, and Pauli::Z (with the integer values 0, 1, 2, 3 respectively)

Python Classes are used to represent scalar types

  • CInt represents integers
  • CReal represents real numbers (using floating point encoding)
  • CBool represents the Boolean values False and True
  • Pauli represents the Pauli base elements using the symbols Pauli.I, Pauli.X, Pauli.Y, and Pauli.Z (with the integer values 0, 1, 2, 3 respectively)

Arrays

Arrays are homogenous collections of scalars or structs with random access.

Syntax

Array types have the form - element-type [ [ length_expression ] ]

Array types are represented with the generic class CArray. Arguments are declared with the type hint in the form:

name : CArray [ [ element-type [ , length_expression ] ] ]

Semantics

element-type is any scalar, array, or struct type. length_expression is optional, determining the length of the array. When left out, the length is determined upon variable initialization.

Expressions of array type support the following operations:

  • Subscript: array-expression [ index-expression ]
  • Slice: array-expression [ from-index-expression : to-index-expression ]
  • Length: array-expression . len

Literal array values are expressed in the form - [ values ], where values is a list of zero-or-more comma-separated expressions of the same type.

Example

The following example demonstrates the use of classical arrays in Qmod. Function foo takes an array of reals, and uses the .len attribute and array subscripting to access the elements of the array. Note that index -1 signifies the last element in an array (similar to Python).

qfunc foo<arr: real[]>(qb: qbit) {
  if (arr.len > 2) {
    RX<arr[-1]>(qb);
  } else {
    RX<arr[0]>(qb);
  }
}

qfunc main() {
  q0: qbit;
  allocate<1>(q0);
  foo<[0.5, 1.0, 1.5]>(q0);
}
from classiq import qfunc, CArray, CReal, QBit, RX, allocate, if_


@qfunc
def foo(arr: CArray[CReal], qb: QBit) -> None:
    if_(arr.len > 2, lambda: RX(arr[-1], qb), lambda: RX(arr[0], qb))


@qfunc
def main() -> None:
    q0 = QBit("q0")
    allocate(1, q0)
    foo([0.5, 1.0, 1.5], q0)

Structs

Structs are aggregates of variables, called fields, each with its own name and type.

Structs are declared in the form - struct { field-declarations }, where field-declarations is a list of zero-or-more field declarations in the form - name : type ;.

Expressions of struct type support the field-access operation in the form - struct-expression . field-name.

Literal struct values are expressed in the form - struct-name { field-value-list }. where field-value-list is a list of zero-or-more comma-separated field initializations in the form - name = expression.

A Qmod struct is defined with a regular Python class decorated with @struct. The use of a this class is similar to (and based on) Python's dataclasses.dataclass.

Fields need to be declared with type-hints like classical arguments of functions. Fields are initialized and accessed like attributes of Python object.

Example

In the following example a struct type called MyStruct is defined. Function foo takes an argument of this type and accesses its fields. Function main instantiates and populates MyStruct in its call to foo.

struct MyStruct {
  loop_counts: int[];
  angle: real;
}

qfunc foo<ms: MyStruct>(qv: qbit[2]) {
  H(qv[0]);
  repeat (index: ms.loop_counts[1]) {
    PHASE<ms.angle + 0.5>(qv[1]);
  }
}

qfunc main() {
  qba: qbit[];
  allocate<2>(qba);
  foo<MyStruct {
    loop_counts = [1, 2],
    angle = 0.1
  }>(qba);
}
from classiq import (
    CArray,
    CInt,
    CReal,
    struct,
    qfunc,
    QArray,
    QBit,
    H,
    repeat,
    PHASE,
    allocate,
)


@struct
class MyStruct:
    loop_counts: CArray[CInt]
    angle: CReal


@qfunc
def foo(ms: MyStruct, qv: QArray[QBit, 2]) -> None:
    H(qv[0])
    repeat(
        count=ms.loop_counts[1],
        iteration=lambda index: PHASE(ms.angle + 0.5, qv[1]),
    )


@qfunc
def main() -> None:
    qba = QArray("qba")
    allocate(2, qba)
    foo(MyStruct(loop_counts=[1, 2], angle=0.1), qba)