Skip to content

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:

  1. The counts attribute allows access to the measurement results of all qubits. The qubit order of each state in counts is indicated by the Boolean flag counts_lsb_right.
  2. The parsed_counts attribute contains parsed states according to the arithmetic information of the output registers.
  3. 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 the qubits argument of the method.
  4. The counts_of_output method is similar to counts_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.
  5. The counts_of_multiple_outputs is similar to counts_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.
  6. The counts_by_endianness method allows access to the counts attribute in the required endianness (qubit order).
  7. 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