Skip to content

Commit

Permalink
Update default resilience options (Qiskit#1062)
Browse files Browse the repository at this point in the history
* remove default resilience options

* add reno

* add logic to override default

* add test

* purge None values from options

(cherry picked from commit 76603f2)
  • Loading branch information
kt474 authored and jyu00 committed Sep 14, 2023
1 parent 228b7ad commit 179678e
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 2 deletions.
4 changes: 4 additions & 0 deletions qiskit_ibm_runtime/base_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo
combined["resilience_level"] = Options._DEFAULT_RESILIENCE_LEVEL

self._validate_options(combined)

combined = Options._set_default_resilience_options(combined)
combined = Options._remove_none_values(combined)

primitive_inputs.update(Options._get_program_inputs(combined))

if self._backend and combined["transpilation"]["skip_transpilation"]:
Expand Down
28 changes: 28 additions & 0 deletions qiskit_ibm_runtime/options/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,34 @@ def validate_options(options: dict) -> None:
ExecutionOptions.validate_execution_options(options.get("execution"))
SimulatorOptions.validate_simulator_options(options.get("simulator"))

@staticmethod
def _remove_none_values(options: dict) -> dict:
"""Remove `None` values from the options dictionary."""
new_options = {}
for key, value in options.items():
if value is not None:
if isinstance(value, dict):
new_suboptions = {}
for subkey, subvalue in value.items():
if subvalue is not None:
new_suboptions[subkey] = subvalue
new_options[key] = new_suboptions
else:
new_options[key] = value

return new_options

@staticmethod
def _set_default_resilience_options(options: dict) -> dict:
"""Set default resilience options for resilience level 2."""
if options["resilience_level"] == 2:
if not options["resilience"]["noise_factors"]:
options["resilience"]["noise_factors"] = (1, 3, 5)
if not options["resilience"]["extrapolator"]:
options["resilience"]["extrapolator"] = "LinearExtrapolator"

return options

@staticmethod
def _get_runtime_options(options: dict) -> dict:
"""Extract runtime options.
Expand Down
5 changes: 3 additions & 2 deletions qiskit_ibm_runtime/options/resilience_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class ResilienceOptions:
noise_factors (DEPRECATED): An list of real valued noise factors that determine
by what amount the circuits' noise is amplified.
Only applicable for ``resilience_level=2``.
Default: (1, 3, 5).
Default: ``None``, and (1, 3, 5) if resilience level is 2.
noise_amplifier (DEPRECATED): A noise amplification strategy. One of ``"TwoQubitAmplifier"``,
``"GlobalFoldingAmplifier"``, ``"LocalFoldingAmplifier"``, ``"CxAmplifier"``.
Expand All @@ -69,7 +69,7 @@ class ResilienceOptions:
Note that ``"CubicExtrapolator"`` and ``"QuarticExtrapolator"`` require more
noise factors than the default.
Only applicable for ``resilience_level=2``.
Default: "LinearExtrapolator".
Default: ``None``, and ``LinearExtrapolator`` if resilience level is 2.
measure_noise_mitigation: Whether to enable measurement error mitigation method.
By default, this is enabled for resilience level 1, 2, and 3 (when applicable).
Expand Down Expand Up @@ -166,6 +166,7 @@ def validate_resilience_options(resilience_options: dict) -> None:
f"Supported values are {get_args(NoiseAmplifierType)}"
)
extrapolator = resilience_options.get("extrapolator")
if extrapolator and extrapolator not in get_args(ExtrapolatorType):
if extrapolator and extrapolator not in get_args(ExtrapolatorType):
raise ValueError(
f"Unsupported value {extrapolator} for extrapolator. "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
fixes:
- |
The ``noise_factors`` and ``extrapolator`` options in :class:`qiskit_ibm_runtime.options.ResilienceOptions`
will now default to ``None`` unless ``resilience_level`` is set to 2.
Only options relevant to the resilience level will be set, so when using ``resilience_level``
2, ``noise_factors`` will still default to ``(1, 3, 5)`` and ``extrapolator`` will default to
``LinearExtrapolator``. Additionally, options with a value of ``None`` will no longer be sent to
the server.
22 changes: 22 additions & 0 deletions test/integration/test_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,28 @@ def test_unsupported_input_combinations(self, service):
inst.run(circ, observables=obs)
self.assertIn("a coupling map is required.", str(exc.exception))

@run_integration_test
def test_default_resilience_settings(self, service):
"""Test that correct default resilience settings are used."""
circ = QuantumCircuit(1)
obs = SparsePauliOp.from_list([("I", 1)])
options = Options(resilience_level=2)
backend = service.backends(simulator=True)[0]
with Session(service=service, backend=backend) as session:
inst = Estimator(session=session, options=options)
job = inst.run(circ, observables=obs)
self.assertEqual(job.inputs["resilience_settings"]["noise_factors"], [1, 3, 5])
self.assertEqual(
job.inputs["resilience_settings"]["extrapolator"], "LinearExtrapolator"
)

options = Options(resilience_level=1)
with Session(service=service, backend=backend) as session:
inst = Estimator(session=session, options=options)
job = inst.run(circ, observables=obs)
self.assertIsNone(job.inputs["resilience_settings"]["noise_factors"])
self.assertIsNone(job.inputs["resilience_settings"]["extrapolator"])

@production_only
@run_integration_test
def test_all_resilience_levels(self, service):
Expand Down

0 comments on commit 179678e

Please sign in to comment.