Using QMOD Classical Types¶
QMOD functions may take classical parameters of different types - scalars, lists, and
structs. When declaring and calling QMOD functions in Python, the builtin Python scalar
types are used -
int is also used to represent QMOD enumerated
types. The builtin Python
typing.List) is used for QMOD lists. Each QMOD struct
type has a corresponding Python class definition.
Defining and using structs¶
QMOD struct types can be declared by writing a Python class and decorating it with
QStruct decorator. With this decorator, a class behaves like a Python data-class
(i.e. a class decorated with
dataclasses.dataclass). Note that subclassing is not
supported for QMOD structs.
In the following example a struct with two scalar fields is declared and used by a function:
from classiq import QStruct, QFunc, QParam, QBit, repeat, PHASE @QStruct class MyStruct: count: int angle: float @QFunc def foo(ms: QParam[MyStruct], qv: QBit) -> None: repeat( count=ms.count, iteration=lambda index, qbv: PHASE(ms.angle + index, qbv), qbv=qv, )
Using aggregate types¶
QMOD lists can store elements of any QMOD type, as long as they are of the same
type. List elements are accessed with the native Python subscript (
and list literals are specified using native Python constructs.
QMOD structs can have fields of any QMOD types. Struct fields are accessed with the
native Python dot (
.) operator. Native class constructor is used to specify the
literal value of a struct. Note that recursive struct definition is not allowed.
Here is a more elaborate example, in which structs and lists are aggregated to form a
data-structure. An instances of the struct is created in function
main and queried in
different contexts within function
from typing import List from classiq import QStruct, QFunc, QParam, QBit, QArray, Output, PHASE, allocate @QStruct class MyStruct: position: List[int] angle: float @QStruct class YourStruct: msl: List[MyStruct] @QFunc def foo(ys: QParam[YourStruct], index: QParam[int], qbv: QArray[QBit, 5]) -> None: PHASE(ys.msl[index].angle + 0.5, qbv[ys.msl[index].position]), @QFunc def main(res: Output[QArray[QBit]]) -> None: ys = YourStruct( msl=[ MyStruct(position=[1, 2], angle=0.1), MyStruct(position=[0, 3, 4], angle=0.2), ], ) allocate(5, res) H(res) foo(ys, 0, res)
In addition to lists, QMOD supports array types, which declare both the element type and number of elements. The main application of array types is to define execution parameters of a model, typically in hybrid algorithms.
Array parameters are declared with type hint of the form
<array>.len() apply to arrays in the same way as lists.
In the example below function
main expects an array of 6 angle values, and applies
an X rotation to the respective qubit in its output.
from classiq import ( QFunc, QParam, QBit, Array, Output, QArray, RX, allocate, repeat, ) @QFunc def main(angle: QParam[Array[float, 6]], res: Output[QArray[QBit, 6]]) -> None: allocate(6, res) repeat( count=angle.len(), iteration=lambda index, qbv: RX(angle[index], qbv[index]), qbv=res, )
Struct types required for builtin functions are available for use (see the full list
of builtin structs under
classiq/qmod/builtins.py). In the following example the
suzuki_trotter is used, which in turn takes a list of struct type
PauliTerm as parameter.
from classiq import ( Output, QArray, QBit, allocate, suzuki_trotter, PauliTerm, QFunc, Pauli, ) @QFunc def main(res: Output[QArray[QBit]]) -> None: allocate(3, res) suzuki_trotter( pauli_operator=[ PauliTerm(pauli=[Pauli.X, Pauli.X, Pauli.Z], coefficient=1), PauliTerm(pauli=[Pauli.Y, Pauli.X, Pauli.Y], coefficient=0.5), ], evolution_coefficient=0.7, order=4, repetitions=2, qbv=res, )
Note that a native Python enum class
Pauli can be used for
the corresponding QMOD enumerated type.