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 integersreal
represents real numbers (using floating point encoding)bool
represents the Boolean valuesfalse
andtrue
Pauli
represents the Pauli base elements using the symbolsPauli::I
,Pauli::X
,Pauli::Y
, andPauli::Z
(with the integer values 0, 1, 2, 3 respectively)
Python Classes are used to represent scalar types
CInt
represents integersCReal
represents real numbers (using floating point encoding)CBool
represents the Boolean valuesFalse
andTrue
Pauli
represents the Pauli base elements using the symbolsPauli.I
,Pauli.X
,Pauli.Y
, andPauli.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 one or more field declarations in the form - name : classical-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 classical struct is defined with a Python data class: A class decorated with
@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 *
from dataclasses import dataclass
@dataclass
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)