Quantum Entry Point
A quantum model in Qmod is compiled into a quantum program - a concrete executable
description. You can execute a quantum program any number of times on quantum hardware
or simulators, and specify execution preferences (such as number of shots).
When executing a parametric quantum program you must assign values to its parameters.
Both compilation and execution start from a user-defined quantum function called 'main',
which is the quantum program entry point. Function main
specifies the inputs and outputs
of the quantum program, that is, its interface with the external classical execution logic.
Model Outputs
Function main
can declare quantum output arguments. Upon invocation, the quantum program
executes the specified number-of-shot times, and its outputs are measured each time. When
using the sample
operation, each output variable is measured in the computational (z) basis.
Their names and values, along with the respective counts, are available in the returned result.
The values are interpreted according to their specified types (see Quantum Types).
Function main
cannot declare quantum arguments other than using the output
modifier, since the classical execution logic cannot pass quantum states as arguments.
For example, consider the following model:
qfunc main(output a: qbit, output b: qnum<2, UNSIGNED, 2>) {
allocate(1, a);
H(a);
allocate(2, b);
control (a) {
apply_to_all(lambda(target) {
X(target);
}, b);
}
}
from classiq import qfunc, Output, QBit, QNum, UNSIGNED, allocate, H, control, X
@qfunc
def main(a: Output[QBit], b: Output[QNum[2, UNSIGNED, 2]]) -> None:
allocate(1, a)
H(a)
allocate(2, b)
control(a, lambda: apply_to_all(lambda target: X(target), b))
This model can be synthesized and executed in the SDK with the following code -
model = create_model(main)
qprog = synthesize(model)
job = execute(qprog)
result = job.result()[0]
print(result.value.parsed_counts)
The printout will show the counts of the measured values of a
and b
thus -
[{'a': 1.0, 'b': 0.75}: 503, {'a': 0.0, 'b': 0.0}: 497]
Similarly, the results of the execution job in the Classiq web application show the values as tooltip on the histogram bars.
Model execution parameters
Function main
can declare classical parameters of scalar types (integers and reals)
and arrays thereof with explicitly specified lengths. These are called execution parameters.
They are assigned by the external classical execution logic using arguments to
the execution operations sample
and estimate
. Execution parameters are left in their
symbolic form in the quantum program, so that passing different sets of parameter values
does not require re-synthesis of the model.
Execution parameters can figure in restricted contexts only as rotation angles in
gate-level functions and as the exponent value of the power
operation. They cannot
be used in classical control flow statements (repeat
and if
) or in subscript/slice
expressions.
Below is a full SDK example of a very simple model with an execution parameter.
The quantum program is invoked in a loop using the method sample
of ExecutionSession
.
from math import pi
from classiq import qfunc, Output, QBit, CReal, allocate, RX, create_model, synthesize
from classiq.execution import ExecutionSession
from classiq.interface.executor.execution_preferences import ExecutionPreferences
@qfunc
def main(angle: CReal, res: Output[QBit]) -> None:
allocate(1, res)
RX(angle, res)
model = create_model(main)
qprog = synthesize(model)
es = ExecutionSession(qprog, ExecutionPreferences(num_shots=10000))
for i in range(4):
result = es.sample({"angle": i*pi/4})
print(result.parsed_counts)
Running this script will print, for example -
[{'res': 0.0}: 10000]
[{'res': 0.0}: 8560, {'res': 1.0}: 1440]
[{'res': 0.0}: 5019, {'res': 1.0}: 4981]
[{'res': 1.0}: 8514, {'res': 0.0}: 1486]