Quantum Functions¶
Quantum functions are operations that modify the state of quantum object. The quantum objects are passed to the function as arguments of quantum types. In addition, quantum functions can take classical arguments and function arguments.
The following example demonstrates how to define a Qmod function. Function rotate
applies
a some given phase to a qubit.
qfunc rotate<r: real>(qv: qbit) {
PHASE<r * pi>(qv);
}
from classiq import CReal, qfunc, QBit
from classiq.qmod.symbolic import pi
@qfunc
def rotate(r: CReal, qv: QBit) -> None:
PHASE(theta=r * pi, target=qv)
Syntax¶
The signature of a function determines the function's name and the arguments it expects. The body of a function is the specification of its implementation as a sequence of statements.
qfunc name [ < classical-args > ] ( quantum-args ) { statements }
classical-args is a list of zero-or-more comma-separated declarations in the form:
name : classical-type
quantum-args is a list of zero-or-more comma-separated declarations in the form:
[ output | input ] name : quantum-type
A quantum function is defined with a regular Python function decorated with @qfunc
.
The @qfunc
decorator relies on Python's type-hint mechanism to extract the Qmod argument
declarations from the Python argument list. Type-hints for aguments are mandatory,
and they can only be of Qmod types. In Python there is no separation or ordering
requirement between classical and quantum arguments.
Direction modifiers for quantum arguments are represented with the generic classes Input
and Output
.
Semantics¶
- A function definition introduces a new function symbol into the global namespace.
- Arguments can be used as variables in the body of the function.
- Classical arguments can be used as variables in the declaration of subsequent argument types in the signature of the function.
- The direction modifiers
input
andouput
may be used to specify input-only and output-only quantum arguments respectively.
Statements can do one of the following:
- Call other quantum functions
- Declare local quantum variables
- Assign expressions to quantum variables
- Bind quantum variables to other quantum variables
Qmod functions can also take functions as arguments. For details on this capability, see Operators.
Examples¶
Example 1 - Function Declarations¶
The following example demonstrates function declarations:
qfunc foo<n: int>(qba: qbit[2*n]) {
// ...
}
qfunc bar(x: qnum, y: qnum, output res: qnum) {
// ...
}
from classiq import CInt, QArray, QBit, QNum, Output, qfunc
@qfunc
def foo(n: CInt, qba: QArray[QBit, "2*n"]) -> None:
pass
@qfunc
def bar(x: QNum, y: QNum, res: Output[QNum]) -> None:
pass
Note that when classical arguments are used to specify subsequent arguments, as in
the case of qba
being a qubit array of size 2*n, the expression is specified
as a string literal because the Python variable n
is not in scope.
Example 2 - Function Definitions¶
The following example demonstrates a simple function definition. In its body it calls
the built-in function H()
and then iteratively under repeat
the function PHASE()
(for more on repeat
see Classical Control Flow)
qfunc foo<n: int>(qv: qbit) {
H(qv);
repeat (index: n) {
PHASE<(index / n) * pi>(qv);
}
}
A function decorated with @qfunc
is executed by the Python interpreter to construct
the body of the Qmod function. Python functions corresponding to Qmod statements
inject the respective statements into the constructed function.
from classiq import CInt, QBit, H, PHASE, allocate, repeat, qfunc
from classiq.qmod.symbolic import pi
@qfunc
def foo(n: CInt, qv: QBit) -> None:
H(qv)
repeat(3, lambda i: PHASE(theta=(i / n) * pi, target=qv))