Specify options
You can use options to customize the Estimator and Sampler primitives. This section focuses on how to specify Qiskit Runtime primitive options. While the interface of the primitives' run()
method is common across all implementations, their options are not. Consult the corresponding API references for information about the qiskit.primitives
and qiskit_aer.primitives
(opens in a new tab) options.
Options are specified differently depending on whether you are using the V1 or V2 interface.
V2 primitives
Options are specified differently in the V2 primitives in these ways:
SamplerV2
andEstimatorV2
have separate options classes. You can see the available options and update option values during or after primitive initialization.- Instead of the
set_options()
method, V2 primitive options have theupdate()
method that applies changes to theoptions
attribute. - If you do not specify a value for an option, it is given a special value of
Unset
and the server defaults are used. - For V2 primitives, the
options
attribute is thedataclass
Python type. You can use the built-inasdict
method to convert it to a dictionary.
Set primitive options
You can set options when initializing the primitive, after initializing the primitive, or in the run()
method. See the precedence rules section to understand what happens when the same option is specified in multiple places.
Primitive initialization
You can pass in an instance of the options class or a dictionary when initializing a primitive, which then makes a copy of those options. Thus, changing the original dictionary or options instance doesn't affect the options owned by the primitives.
Options class
When creating an instance of the Estimator
or Sampler
class, you can pass in an instance of the options class. Those options will then be applied when you use run()
to perform the calculation. Specify the options in this format: options.option.sub-option.sub-sub-option = choice
. For example: options.dynamical_decoupling.enable = True
Example:
SamplerV2
and EstimatorV2
have separate options classes (EstimatorOptions
and SamplerOptions
).
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime.options import EstimatorOptions
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
options = EstimatorOptions(resilience_level=2, resilience={"zne_mitigation": True, "zne": {"noise_factors": [1, 3, 5]}})
# or...
options = EstimatorOptions()
options.resilience_level = 2
options.resilience.zne_mitigation = True
options.resilience.zne.noise_factors = [1, 3, 5]
estimator = Estimator(mode=backend, options=options)
from qiskit_ibm_runtime import Estimator, Options
options = Options(resilience_level = 2)
# or...
options = Options()
options.resilience_level = 2
estimator = Estimator(session=backend, options=options)
Dictionary
You can specify options as a dictionary when initializing the primitive.
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Setting options during primitive initialization
estimator = Estimator(backend, options={"resilience_level": 2, "resilience": {"zne_mitigation": True, "zne": {"noise_factors": [1, 3, 5]}}})
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Estimator
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Setting options during primitive initialization
estimator = Estimator(backend, options={"resilience_level": 2})
Update options after initialization
You can specify the options in this format: primitive.options.option.sub-option.sub-sub-option = choice
to take advantage of auto-complete, or use the update()
method to make bulk updates.
The SamplerV2
and EstimatorV2
options classes (EstimatorOptions
and SamplerOptions
) do not need to be instantiated if you are setting options after initializing the primitive.
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
estimator = Estimator(mode=backend)
# Setting options after primitive initialization
# This uses auto-complete.
estimator.options.default_shots = 4000
# This does bulk update.
estimator.options.update(default_shots=4000, resilience={"zne_mitigation": True})
# Setting options after primitive initialization
# This uses auto-complete.
options.resilience_level = 2
estimator = Estimator(backend=backend, options=options)
# Setting options after primitive initialization.
# This does bulk update.
estimator.set_options(shots=4000)
Run() method
The run() method accepts options in V1 only.
In V2, the only values you can pass to run()
are those defined in the interface. That is, shots
for Sampler and precision
for Estimator. This overwrites any value set for default_shots
or default_precision
for the current run.
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(mode=backend)
# Default shots to use if not specified in run()
sampler.options.default_shots = 500
# Sample two circuits at 128 shots each.
sampler.run([circuit1, circuit2], shots=128)
# Sample two circuits with different numbers of shots.
# 100 shots is used for circuit1 and 200 for circuit2.
sampler.run([(circuit1, None, 100), (circuit2, None, 200)])
You can pass any options to run()
. Because most users will only overwrite a few options at the job level, it is not necessary to specify the options category. The code below, for example, specifies shots=1024
instead of execution={"shots": 1024}
(which is also valid).
estimator = Estimator(backend=backend, options=options)
result = estimator.run(circuit, observable, shots=1024).result()
print(f">>> Metadata: {result.metadata[0]}")
Special cases (V2 only)
Resilience level (Estimator only)
The resilience level is not actually an option that directly impacts the primitive query, but specifies a base set of curated options to build off of. In general, level 0 turns off all error mitigation, level 1 turns on options for measurement error mitigation, and level 2 turns on options for gate and measurement error mitigation.
Any options you manually specify in addition to the resilience level are applied on top of the base set of options defined by the resilience level. Therefore, in principle, you could set the resilience level to 1, but then turn off measurement mitigation, although this is not advised.
In the following example, setting the resilience level to 0 initially turns off zne_mitigation
, but estimator.options.resilience.zne_mitigation = True
overrides the relevent setup from estimator.options.resilience_level = 0
.
from qiskit_ibm_runtime import EstimatorV2, QiskitRuntimeService
from qiskit import QuantumCircuit
service = QiskitRuntimeService()
backend = service.backend("ibm_auckland")
estimator = EstimatorV2(backend)
estimator.options.default_shots = 100
estimator.options.resilience_level = 0
estimator.options.resilience.zne_mitigation = True
Shots (Sampler only)
The SamplerV2.run
method accepts two arguments: a list of PUBs, each of which can specify a PUB-specific value for shots, and a shots keyword argument. These shot values are a part of the Sampler execution interface, and are independent of the Runtime Sampler's options. They take precedence over any values specified as options in order to comply with the Sampler abstraction.
However, if shots
is not specified by any PUB or in the run keyword argument (equivalently, if they are all None
), then the shots value from the options is used, most notably default_shots
. To summarize, this is the order of precedence for specifying shots in the Sampler, for any particular PUB:
- If the PUB specifies shots, use that value.
- If the shots keyword argument is specified in
run
, use that value. - If
sampler.options.default_shots
is specified, use that value.
For example, if shots are specified in all three places, the one with highest precedence (shots specified in the PUB) is used.
Precision (Estimator only)
Precision is analogous to shots, described in the previous section, except that the Estimator options contains both default_shots
and default_precision
. Specifically, for any particular Estimator PUB:
- If the PUB specifies precision, use that value.
- If the precision keyword argument is specified in
run
, use that value. - If
estimator.options.default_shots
is specified, use that value to control the amount of data. - If
estimator.options.default_precision
is specified, use that value.
For example, if precision is specified in all four places, the one with highest precedence (precision specified in the PUB) is used.
Commonly used options
There are many available options, but the following are the most commonly used:
Shots
For some algorithms, setting a specific number of shots is a core part of their routines. There are several ways to set and update shots with the primitives.
Shots (or precision) can be specified in multiple places in V2. They are prioritized as follows:
For any Sampler PUB:
- Integer-valued shots contained in the PUB
- The
run(...,shots=val)
value - The
options.default_shots
value
For any Estimator PUB:
- Float-valued precision contained in the PUB
- The
run(...,precision=val)
value - The
options.default_shots
value - The
options.default_precision
value
Example:
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Setting shots during primitive initialization
sampler = Sampler(mode=backend, options={"default_shots": 4096})
# Setting options after primitive initialization
# This uses auto-complete.
sampler.options.default_shots=2000
# This does bulk update. The value for default_shots is overridden if you specify shots with run() or in the PUB.
sampler.options.update(default_shots=1024, dynamical_decoupling={"sequence_type": "XpXm"})
# Sample two circuits at 128 shots each.
sampler.run([circuit1, circuit2], shots=128)
Previously, shots could be set during the call to backend.run()
. For example, backend.run(shots=1024)
. Now, that setting is part of the execution
options ("second level option"). This can be done during the primitive setup:
from qiskit_ibm_runtime import Estimator, Options
options = Options()
options.execution.shots = 1024
estimator = Estimator(session=backend, options=options)
If you need to modify the number of shots set between iterations (primitive calls), you can set the
shots directly in the run()
method. This overwrites the initial shots
setting.
from qiskit_ibm_runtime import Estimator
estimator = Estimator(session=backend)
estimator.run(circuits=circuits, observables=observables, shots=50)
# other logic
estimator.run(circuits=circuits, observables=observables, shots=100)
For more information about the primitive options, refer to the Options class API reference.
Maximum execution time
The maximum execution time (max_execution_time
) limits how long a job can run. If a job exceeds this time limit, it is forcibly canceled. This value applies to single jobs, whether they are run in job, session, or batch mode.
The value is set in seconds, based on quantum time (not wall clock time), which is the amount of time that the QPU is dedicated to processing your job. It is ignored when using local testing mode because that mode does not use quantum time.
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
estimator = Estimator(mode=backend)
estimator.options.max_execution_time = 2500
options = Options()
estimator.options.max_execution_time = 2500
estimator = Estimator(backend=backend)
Turn off all error mitigation and error suppression
You can turn off all error mitigation and suppression if you are, for example, doing research on your own mitigation techniques. To accomplish this, for EstimatorV2, set resilience_level = 0
. For SamplerV2, no changes are necessary because no error mitigation or suppression options are enabled by default.
Example:
Turn off all error mitigation and suppression in EstimatorV2.
from qiskit_ibm_runtime import EstimatorV2 as Estimator, Options, QiskitRuntimeService
# Define the service. This allows you to access IBM QPU.
service = QiskitRuntimeService()
# Get a backend
backend = service.least_busy(operational=True, simulator=False)
# Define Estimator
estimator = Estimator(backend)
options = estimator.options
# Turn off all error mitigation and suppression
options.resilience_level = 0
Next steps
- Find more details about the
Estimator
methods in the Estimator API reference. - Find more details about the
Sampler
methods in the Sampler API reference. - Find all available options in the Options API reference.
- Find details about how to configure error suppression and error mitigation.
- Decide what execution mode to run your job in.