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
  • Loading branch information
kt474 authored Sep 12, 2023
1 parent ea1145a commit 76603f2
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 6 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 @@ -181,6 +181,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
12 changes: 6 additions & 6 deletions qiskit_ibm_runtime/options/resilience_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ResilienceOptions:
noise_factors: 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 @@ -58,12 +58,12 @@ 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.
"""

noise_amplifier: NoiseAmplifierType = None
noise_factors: Sequence[float] = (1, 3, 5)
extrapolator: ExtrapolatorType = "LinearExtrapolator"
noise_factors: Sequence[float] = None
extrapolator: ExtrapolatorType = None

@staticmethod
def validate_resilience_options(resilience_options: dict) -> None:
Expand All @@ -90,13 +90,13 @@ def validate_resilience_options(resilience_options: dict) -> None:
if not opt in get_args(ResilienceSupportedOptions):
raise ValueError(f"Unsupported value '{opt}' for resilience.")
noise_amplifier = resilience_options.get("noise_amplifier") or "TwoQubitAmplifier"
if not noise_amplifier in get_args(NoiseAmplifierType):
if noise_amplifier not in get_args(NoiseAmplifierType):
raise ValueError(
f"Unsupported value {noise_amplifier} for noise_amplifier. "
f"Supported values are {get_args(NoiseAmplifierType)}"
)
extrapolator = resilience_options.get("extrapolator")
if not extrapolator in get_args(ExtrapolatorType):
if extrapolator and extrapolator not in get_args(ExtrapolatorType):
raise ValueError(
f"Unsupported value {extrapolator} for extrapolator. "
f"Supported values are {get_args(ExtrapolatorType)}"
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 76603f2

Please sign in to comment.