Execution Primitives¶
In addition to the design of quantum circuits, the Classiq quantum model contains classical instructions for the execution process.
Note
When designing a model, you must specify classical instructions for the execution process to take part.
sample¶
The sample
execution primitive instructs the execution process to
sample the state of the quantum circuit.
Here is a full example of a simple quantum model (with a single RX gate) and a classical function
definition with the sample
primitive. This example depicts how to use "target_params" to assign
values for a parametric circuit.
{
"functions": [
{
"name": "main",
"param_decls": {
"theta": {
"kind": "real"
}
},
"body": [
{
"function": "RXGate",
"function_params": {
"theta": "theta"
}
}
]
}
],
"classical_functions": [
{
"name": "cmain",
"body": [
{
"name": "result",
"var_type": {
"kind": "histogram"
}
},
{
"invoked_expression": {
"function": "sample",
"target_function": "main",
"target_params": {
"theta": {
"expr": "1"
}
}
},
"assigned_variable": "result"
},
{
"saved_variable": "result"
}
]
}
]
}
The sample
primitive takes only one optional input, execution_params
, which is a dictionary of
values assignments for a parametric circuit.
# Sample the quantum circuit
model.sample()
# Alternatively, if the quantum circuit is parametric, assign values
model.sample(
execution_params={"theta": 1},
)
Upon execution, the results of a program with a sample
primitive are of type
ExecutionDetails
, which describes the measurement results of the quantum circuit.
There are five ways to access these measurements:
- The
counts
attribute allows access to the measurement results of all qubits. The qubit order of each state incounts
is indicated by the Boolean flagcounts_lsb_right
. - The
parsed_counts
attribute contains parsed states according to the arithmetic information of the output registers. - The
counts_of_qubits
method allows access to results of specific qubits. The order of qubits in the measurement result is determined by their order in thequbits
argument of the method. - The
counts_of_output
method is similar tocounts_of_qubits
, but receives an output name as an argument. Note it may only be used if the generated model has outputs. See Model Inputs & Outputs for output setting instructions. - The
counts_of_multiple_outputs
is similar tocounts_of_output
. It receives a tuple of output names, and returns the counts of all specified outputs, keyed by a tuple of states matching the requested outputs. - The
counts_by_endianness
method allows access to thecounts
attribute in the required endianness (qubit order). - The
num_shots
attribute is the sum of all of the resulted counts fields.
iqae¶
The iqae
execution primitive instructs the execution process to perform the
Iterative Quantum Amplitude Estimation algorithm [1].
Given \(A\) such that \(A|0\rangle_n|0\rangle = \sqrt{1-a}|\psi_0\rangle_n|0\rangle + \sqrt{a}|\psi_1\rangle_n|1\rangle\),
the algorithm tries to estimate \(a\) by iteratively sampling \(Q^kA\), where \(Q=AS_0A^{\dagger}S_{\psi_0}\) and \(k\) is an integer variable.
Note
The iqae
primitive assumes the user has correctly defined the quantum model,
i.e. \(Q^kA\), where \(k\) is specified by adding power="k"
to the function
parameters of the desireable function (such as
GroverOperator).
In addition, the only output port should be the last qubit.
There are two parameters to the iqae
primitive: epsilon
specifies the
target accuracy, and alpha
specifies the confidence level (meaning the
precision probability is \(1 - \alpha\)).
In the following example, we define \(A = RY(\theta)\) and \(Q = RY(2\theta)\). In this case, the estimation result should be \(a = \sin^2(\frac{\theta}{2})\), as \(A|0\rangle = \cos\frac{\theta}{2}|0\rangle + \sin\frac{\theta}{2}|1\rangle\).
{
"functions": [
{
"name": "main",
"port_declarations": {
"TARGET": {
"name": "TARGET",
"size": {
"expr": "1"
},
"direction": "output"
}
},
"output_ports_wiring": {
"TARGET": "Q->out"
},
"body": [
{
"function": "RYGate",
"function_params": {
"theta": 0.5
},
"outputs": {
"TARGET[0]": "A->Q"
},
"name": "A"
},
{
"function": "RYGate",
"function_params": {
"theta": 1.0
},
"inputs": {
"TARGET[0]": "A->Q"
},
"outputs": {
"TARGET[0]": "Q->out"
},
"power": "k",
"name": "Q"
}
]
}
],
"classical_functions": [
{
"name": "cmain",
"body": [
{
"name": "result",
"var_type": {
"kind": "iqae_result"
}
},
{
"invoked_expression": {
"function": "iqae",
"params": {
"epsilon": {
"expr": "0.001"
},
"alpha": {
"expr": "0.01"
}
},
"target_function": "main"
},
"assigned_variable": "result"
},
{
"saved_variable": "result"
}
]
}
]
}
from classiq import Model, synthesize, execute
from classiq.builtin_functions import RYGate
from classiq.execution import IQAEResult
THETA = 0.5
# Design the quantum model
model = Model()
mid = model.RYGate(RYGate(theta=THETA))
out = model.RYGate(RYGate(theta=2 * THETA), in_wires=mid, power="k")
model.set_outputs(out)
# Specify iqae execution primitive
model.iqae(epsilon=0.001, alpha=0.01)
# Synthesize and execute
qprog = synthesize(model.get_model())
results = execute(qprog)
iqae_result = results[0].value
The results of a program with a iqae
primitive are of type IQAEResult
, which
describes the algorithm results and contains:
estimation
: The estimated value of \(a\).confidence_interval
: The confidence interval for the value of \(a\).iterations_data
: List of per-iteration information. Each item contains:grover_iterations
: The value of \(k\) for this iteration.sample_results
: The results of sampling \(Q^kA\) in this iteration.
warnings
: List of warnings yielded throughout the algorithm execution, such as reaching the maximum number of iterations.
References¶
[1] Grinko, D., Gacon, J., Zoufal, C. et al. Iterative quantum amplitude estimation. npj Quantum Inf 7, 52 (2021). https://doi.org/10.1038/s41534-021-00379-1