Skip to main contentIBM Quantum Documentation

Configure runtime compilation for Qiskit Runtime

Runtime compilation techniques optimize and transform your circuit to minimize errors. Runtime compilation adds some classical pre-processing overhead to your overall runtime. Therefore, it is important to achieve a balance between perfecting your results and ensuring that your job completes in a reasonable amount of time.

Primitives let you employ runtime compilation by choosing advanced runtime compilation options and, for Estimator V2, by setting the optimization level (optimization_level) option. If you don't want any processing done to minimize errors, follow the instructions in the Turn off all error mitigation and error suppression section.

Estimator V2 supports optimization levels 0 and 1 only. Sampler V2 does not support setting the optimization level.
Important

To ensure faster and more efficient results, as of 1 March 2024, circuits and observables need to be transformed to only use instructions supported by the system (referred to as instruction set architecture (ISA) circuits and observables) before being submitted to the Qiskit Runtime primitives. See the transpilation documentation for instructions to transform circuits. Due to this change, the primitives will no longer perform layout or routing operations. Consequently, transpilation options referring to those tasks will no longer have any effect. By default, all primitives except Sampler V2 still optimize the input circuits. To bypass all optimization, set optimization_level=0.

Exception: When you initialize the Qiskit Runtime Service with the Q-CTRL channel strategy (example below), abstract circuits are still supported.

service = QiskitRuntimeService(channel="ibm_cloud", channel_strategy="q-ctrl")

Set the optimization level

The optimization_level setting specifies how much optimization to perform on the circuits. Higher levels generate more optimized circuits, at the expense of longer compile times.

In primitive version 1, optimization levels 2 and 3 behave identically to level 1. Estimator V2 does not accept levels higher than 1 and Sampler V2 does not support setting the optimization level.

Optimization LevelEstimator & Sampler (V1)
0

No optimization: typically used for hardware characterization or debugging

1, 2, 3

Light optimization:

  • Single-qubit gate optimization
  • Two-qubit gate optimization
  • Error suppression: dynamical decoupling (V1 primitives only. For V2 primitives, you can enable it by using the dynamical_decoupling option.)
Note

If using an IBM Cloud® Qiskit Runtime service instance with Q-CTRL performance management enabled, there is no need to specify runtime optimization or resilience levels, as the strategy includes an automatic preset.

Q-CTRL defaults to optimization_level=3 and resilience_level=1. Setting optimization_level or resilience_level equal to 0 will result in an execution error. Levels 1, 2, and 3 are permitted but will not impact performance. Setting other options will likewise not impact performance, and it may result in a runtime warning. For more information visit the Q-CTRL documentation(opens in a new tab).

Example: configure Estimator with optimization levels

from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.circuit.library import RealAmplitudes
from qiskit.quantum_info import SparsePauliOp
 
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
 
psi = RealAmplitudes(num_qubits=2, reps=2)
H = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
theta = [0, 1, 1, 2, 3, 5]
 
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
psi = pm.run(psi)
H = H.apply_layout(psi.layout)
 
estimator = Estimator(backend=backend)
 
estimator.options.optimization_level = 1
 
job = estimator.run([(psi, H, theta)])
 
psi1_H1 = job.result()[0]
Note

If the optimization level is not specified, the service uses optimization_level = 1.


Advanced runtime compilation options

In the V2 primitives, you can explicitly enable and disable individual error mitigation/suppression methods, such as dynamical decoupling.

Note

Dynamical decoupling is not supported when the input circuits are dynamic.

 
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler
 
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
 
sampler = Sampler(backend)
 
# Turn on dynamical decoupling with sequence XpXm.
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"
 
print(f">>> dynamical decoupling sequence to use: {sampler.options.dynamical_decoupling.sequence_type}")

Next steps

Recommendations
Was this page helpful?
Report a bug or request content on GitHub.