IBM Circuit function
Qiskit Functions are an experimental feature available only to IBM Quantum™ Premium Plan users. They are in preview release status and subject to change.
Overview
The IBM® Circuit function takes abstract PUBs as inputs, and returns mitigated expectation values as outputs. This circuit function includes an automated and customized pipeline to enable researchers to focus on algorithm and application discovery.
Description
After submitting your PUB, your abstract circuits and observables are automatically transpiled, executed on hardware, and post-processed to return mitigated expectation values. To do so, this combines the following tools:
- Qiskit Transpiler Service, including auto-selection of AI-driven and heuristic transpilation passes to translate your abstract circuits to hardware-optimized ISA circuits
- Error suppression and mitigation required for utility-scale computation, including measurement and gate twirling, dynamical decoupling, Twirled Readout Error eXtinction (TREX), Zero-Noise Extrapolation (ZNE), and Probabilistic Error Amplification (PEA)
- Qiskit Runtime Estimator, to execute ISA PUBs on hardware and return mitigated expectation values
Get started
Authenticate using your IBM Quantum Platform API token, and select the Qiskit Function as follows:
[1] :from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog()
function = catalog.load("ibm/circuit-function")
Example
To get started, try this basic example:
[2] :from qiskit.circuit.random import random_circuit
from qiskit_ibm_runtime import QiskitRuntimeService
# You can skip this step if you have a target backend, e.g.
# backend_name = "ibm_sherbrooke"
# You'll need to specify the credentials when initializing QiskitRuntimeService, if they were not previously saved.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
circuit = random_circuit(num_qubits=2, depth=2, seed=42)
observable = "Z" * circuit.num_qubits
pubs = [(circuit, observable)]
job = function.run(
backend_name=backend.name, # Or `backend=backend_name`, if you didn't initialize a backend object
pubs=pubs
)
Check your Qiskit Function workload's status or return results as follows:
[3] :print(job.status())
result = job.result()
Output:
QUEUED
The results have the same format as an Estimator result:
[4] :print(f'The result of the submitted job had {len(result)} PUB\n')
print(f'The associated PubResult of this job has the following DataBins:\n {result[0].data}\n')
print(f'And this DataBin has attributes: {result[0].data.keys()}')
print(f'The expectation values measured from this PUB are: \n{result[0].data.evs}')
Output:
The result of the submitted job had 1 PUB
The associated PubResult of this job has the following DataBins:
DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(), dtype=float64>))
And this DataBin has attributes: dict_keys(['evs', 'stds', 'ensemble_standard_error'])
The expectation values measured from this PUB are:
0.07302231237322515
Inputs
See the following table for all input parameters the IBM Circuit function accepts. The subsequent Options section goes into more details about the available options
.
Name | Type | Description | Required | Default | Example |
---|---|---|---|---|---|
backend_name | str | Name of the backend to make the query. | Yes | N/A | ibm_fez |
pubs | Iterable[EstimatorPubLike] | An iterable of abstract PUB-like (primitive unified bloc) objects, such as tuples (circuit, observables) or (circuit, observables, parameter_values) . See Overview of PUBs for more information. The circuits can be abstract (non-ISA). | Yes | N/A | (circuit, observables, parameter_values) |
options | dict | Input options. See the Options section for more details. | No | See the Options section for details. | {"optimization_level": 3} |
instance | str | The hub/group/project to use in that format. | No | One is randomly picked if your account has access to multiple instances. | hub1/group1/project1 |
Options
Structure
Similar to Qiskit Runtime primitives, options for IBM Circuit function can be specified as a nested dictionary. Commonly used options, such as optimization_level
and mitigation_level
, are at the first level. Other, more advanced options are grouped into different categories, such as resilience
.
Defaults
If you do not specify a value for an option, the default value specified by the service is used.
Mitigation level
IBM Circuit function also supports mitigation_level
. The mitigation level specifies how much error suppression and mitigation to apply to the job. Higher levels generate more accurate results, at the expense of longer processing times. The degree of error reduction depends on the method applied. The mitigation level abstracts the detailed choice of error mitigation and suppression methods to allow users to reason about the cost/accuracy trade-off appropriate to their application. The following table shows the corresponding methods for each level.
While the names are similar, mitigation_level
applies different techniques than the ones used by Estimator’s resilience_level
.
Similar to resilience_level
in Qiskit Runtime Estimator, mitigation_level
specifies a base set of curated options. Any options you manually specify in addition to the mitigation level are applied on top of the base set of options defined by the mitigation level. Therefore, in principle, you could set the mitigation level to 1, but then turn off measurement mitigation, although this is not advised.
Mitigation Level | Technique |
---|---|
1 [Default] | Dynamical decoupling + measurement twirling + TREX |
2 | Level 1 + gate twirling + ZNE via gate folding |
3 | Level 1 + gate twirling + ZNE via PEA |
The following example demonstrates setting the mitigation level:
[5] :options = {"mitigation_level": 2}
job = function.run(
backend_name=backend.name,
pubs=pubs,
options=options
)
All available options
In addition to mitigation_level
, the IBM Circuit function also provides a select number of advanced options that allow you to fine-tune the cost/accuracy trade-off. The following table shows all the available options:
Option | Sub-option | Sub-sub-option | Description | Choices | Default |
---|---|---|---|---|---|
default_precision | The default precision to use for any PUB or run() call that does not specify one. Each input PUB can specify its own precision. If the run() method is given a precision, then that value is used for all PUBs in the run() call that do not specify their own. | float > 0 | 0.015625 | ||
max_execution_time | Maximum execution time in seconds, which is based on QPU usage (not wall clock time). QPU usage is the amount of time that the QPU is dedicated to processing your job. If a job exceeds this time limit, it is forcibly canceled. | Integer number of seconds in the range [1, 10800] | |||
mitigation_level | How much error suppression and mitigation to apply. Refer to the Mitigation level section for more information about the methods used at each level. | 1 / 2 / 3 | 1 | ||
optimization_level | How much optimization to perform on the circuits. Higher levels generate more optimized circuits, at the expense of longer transpilation time. | 0 / 1 / 2 / 3 | 2 | ||
dynamical_decoupling | enable | Whether to enable dynamical decoupling. Refer to Error suppression and mitigation techniques for the explanation of the method. | True/False | True | |
sequence_type | Which dynamical decoupling sequence to use. * XX : use the sequence tau/2 - (+X) - tau - (+X) - tau/2 * XpXm : use the sequence tau/2 - (+X) - tau - (-X) - tau/2 * XY4 : use the sequencetau/2 - (+X) - tau - (+Y) - tau (-X) - tau - (-Y) - tau/2 | 'XX'/'XpXm'/'XY4' | 'XX' | ||
twirling | enable_gates | Whether to apply 2-qubit Clifford gate twirling. | True/False | False | |
enable_measure | Whether to enable twirling of measurements. | True/False | True | ||
resilience | measure_mitigation | Whether to enable TREX measurement error mitigation method. Refer to Error suppression and mitigation techniques for the explanation of the method. | True/False | True | |
zne_mitigation | Whether to turn on Zero Noise Extrapolation error mitigation method. Refer to Error suppression and mitigation techniques for the explanation of the method. | True/False | False | ||
zne | amplifier | Which technique to use for amplifying noise. One of: - gate_folding (default) uses 2-qubit gate folding to amplify noise. If the noise factor requires amplifying only a subset of the gates, then these gates are chosen randomly.- gate_folding_front uses 2-qubit gate folding to amplify noise. If the noise factor requires amplifying only a subset of the gates, then these gates are selected from the front of the topologically ordered DAG circuit.- gate_folding_back uses 2-qubit gate folding to amplify noise. If the noise factor requires amplifying only a subset of the gates, then these gates are selected from the back of the topologically ordered DAG circuit.- pea uses a technique called Probabilistic error amplification (PEA) to amplify noise. Refer to Error suppression and mitigation techniques for the explanation of the method. | gate_folding / gate_folding_front / gate_folding_back / pea | gate_folding | |
noise_factors | Noise factors to use for noise amplification. | list of floats; each float >= 1 | (1, 1.5, 2) for PEA, and (1, 3, 5) otherwise. | ||
extrapolator | Noise factors to evaluate the fit extrapolation models at. This option does not affect execution or model fitting in any way; it only determines the points at which the extrapolator s are evaluated to be returned in the data fields called evs_extrapolated and stds_extrapolated . | one or more of exponential ,linear , double_exponential ,polynomial_degree_(1 <= k <= 7) | (exponential , linear ) | ||
pec_mitigation | Whether to turn on Probabilistic Error Cancellation error mitigation method. Refer to Error suppression and mitigation techniques for the explanation of the method. | True/False | False | ||
pec | max_overhead | The maximum circuit sampling overhead allowed, or None for no maximum. | None/ integer >1 | 100 |
In the following example, setting the mitigation level to 1 initially turns off ZNE mitigation, but setting zne_mitigation
to True
overrides the relevent setup from mitigation_level
.
options = {
"mitigation_level": 1,
"resilience": {"zne_mitigation": True}
}
Outputs
The output of a Circuit function is a PrimitiveResult, which contains two fields:
-
One or more PubResult objects. These can be indexed directly from the
PrimitiveResult
. -
Job-level metadata.
Each PubResult
contains a data
and a metadata
field.
-
The
data
field contains at least an array of expectation values (PubResult.data.evs
) and an array of standard errors (PubResult.data.stds
). It can also contain more data, depending on the options used. -
The
metadata
field contains PUB-level metadata (PubResult.metadata
).
The following code snippet describes the PrimitiveResult
(and associated PubResult
) format.
print(f'The result of the submitted job had {len(result)} PUB')
print(f'The expectation values measured from this PUB are: \n{result[0].data.evs}')
print(f'And the associated metadata is: \n{result[0].metadata}')
Output:
The result of the submitted job had 1 PUB
The expectation values measured from this PUB are:
0.07302231237322515
And the associated metadata is:
{'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}
Fetching error messages
If your workload status is ERROR
, use job.result()
to fetch the error message to help debug as follows:
job = function.run(
backend_name="bad_backend_name",
pubs=pubs,
options=options
)
print(job.result())
Output:
Traceback (most recent call last):
File "/runner/runner.py", line 10, in run
func = CircuitFunction(**arguments)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/runner/circuit_function/circuit_function.py", line 86, in __init__
self._backend = self._service.backend(
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/qiskit_ibm_runtime/qiskit_runtime_service.py", line 787, in backend
backends = self.backends(name, instance=instance, use_fractional_gates=use_fractional_gates)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/qiskit_ibm_runtime/qiskit_runtime_service.py", line 536, in backends
raise QiskitBackendNotFoundError("No backend matches the criteria.")
qiskit.providers.exceptions.QiskitBackendNotFoundError: 'No backend matches the criteria.'
Get support
Reach out to IBM Quantum support, and include the following information:
- Qiskit Function Job ID (
qiskit-ibm-catalog
),job.job_id
- A detailed description of the issue
- Any relevant error messages or codes
- Steps to reproduce the issue
Next steps
- Try the Building workflows with the IBM Circuit function tutorial.