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 setting the optimization level (
optimization_level option) and by choosing advanced runtime compilation options.
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 current primitive versions, optimization levels 2 and 3 behave identically to level 1.
|Optimization Level||Estimator & Sampler|
No optimization: typically used for hardware characterization or debugging
|1, 2, 3|
The primitives expect circuits in a form suitable to execute on the target system. You may use the Qiskit transpiler locally to translate abstract circuits into this target circuit form.
At present, the primitives will attempt low-cost transformations if given a circuit that is not already in target form, but in the future, primitives will error on such circuits. It is therefore recommended that users take advantage of the local compilation capabilities of the Qiskit transpiler wherever possible.
For instructions on preparing circuits for primitive queries, see the Submitting user-transpiled circuits using primitives (opens in a new tab) tutorial.
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
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).
from qiskit_ibm_runtime import QiskitRuntimeService, Estimator, Options from qiskit.circuit.library import RealAmplitudes from qiskit.quantum_info import SparsePauliOp service = QiskitRuntimeService() backend = service.backend("ibmq_qasm_simulator") options = Options(optimization_level=1) psi = RealAmplitudes(num_qubits=2, reps=2) H = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)]) theta = [0, 1, 1, 2, 3, 5] estimator = Estimator (options=options, backend=backend) job = estimator.run(circuits=[psi], observables=[H], parameter_values=[theta]) psi1_H1 = job.result()
If the optimization level is not specified, the service uses
optimization_level = 1.
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Options service = QiskitRuntimeService() backend = service.backend("ibmq_qasm_simulator") options = Options(optimization_level=1) sampler = Sampler(options=options, backend=backend)
You also have the ability to tune a variety of advanced options to configure your runtime compilation strategy further. These methods can be used alongside optimization levels. They allow you to change the options of interest and let your optimization level manage the rest.
|options.transpilation.skip_transpilation (bool)||Directs the service to execute the primitive query with the bare minimum about of runtime compilation necessary|
|options.transpilation.initial_layout(Union[dict, List, None])||(Deprecated) Initial position of virtual qubits on physical qubits.|
|options.transpilation.layout_method (Optional[str])||(Deprecated) Name of layout selection pass. One of |
|options.transpilation.routing_method (Optional[str])||(Deprecated) Name of routing pass: |
|options.transpilation.approximation_degree (Optional[float])||(Deprecated) Heuristic dial used for circuit approximation (1.0=no approximation, 0.0=maximal approximation). Defaults to no approximation for all optimization levels|