Quantum kernel function conversion¶
quantum_kernel
functions can be converted to a quantum kernel expression using three methods. If the quantum
kernel function is already written and one does not want to modify or copy it, one can use the
following template function:
template<auto qk_function> QExpr qexpr::convert(Args... args)
where qk_function
is any quantum_kernel
function with arbitrary parameters, so long as it has a void
return type. The argument type list Args
must be the same as that of qk_function
and the argument list args
is subject to the same constraints as those imposed on
qk_function
as a quantum_kernel
function (see the Developers Guide and Reference). An exception is that qbit
arguments to converted quantum_kernel
functions are allowed, so long as they are compile-time resolvable when evaluated; see
Local qubits. For example:
const int N = 4;
qbit qs[N];
void quantum_kernel prepAll() {
for (int i=0; i<N; i++) {
PrepZ(qs[i]);
}
}
void quantum_kernel bell00(qbit& a, qbit& b) {
PrepZ(a);
PrepZ(b);
H(a);
CNOT(a,b);
}
int main() {
...
qexpr::eval_hold(qexpr::convert<prepAll>());
qexpr::eval_hold(qexpr::convert<bell00>(qs[2], qs[3]));
...
}
This kind of conversion can be useful for debugging quantum_kernel
functions;
see Debugging.
Alternatively, a quantum_kernel
function can be modified directly to return a quantum kernel expression by adding a return statement using the keyword this_as_expr
.
For reasons outlined in Overview of FLEQ compilation, any function which returns
this_as_expr
must have the added attribute PROTECT
as enforced by the FLEQ compilation
stage of IQC. For example:
PROTECT QExpr prepAll_qexpr() {
for (int i=0; i<N; i++) {
PrepZ(qs[i]);
}
return this_as_expr;
}
Functions returning this_as_expr
are subject to the constraints of both
quantum_kernel
functions and QExpr
-returning functions.
It is valid to mix this_as_expr
with other QExpr
expressions, but care has to be taken that the outcome ordering is as
expected: this_as_expr
represents the gate sequence present in the body
of the function. For example, the following two functions are logically equivalent:
PROTECT QExpr myRX1(qbit &q, double angle) {
H(q);
RZ(q, angle);
H(q);
return this_as_expr;
}
PROTECT QExpr myRX2(qbit &q, double angle) {
RZ(q, angle);
return qexpr::_H(q) + this_as_expr + qexpr::_H(q);
}
The final method is to construct a new function that returns a QExpr
value
made up of the same primitive gates as the target quantum_kernel
function.
Note that this kind of translation looks slightly different for
quantum_kernel
functions that use C++ loops and branches; equivalent results
can be achieved using Branching and Recursion.