Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exposing layer_noise_model option #1858

Merged
merged 34 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9729d3a
added classes and json
SamFerracin Aug 6, 2024
7fa5d7f
added tests
SamFerracin Aug 6, 2024
14b6bb5
reverting json
SamFerracin Aug 6, 2024
47c4b14
Merge branch 'main' of https://github.com/Qiskit/qiskit-ibm-runtime i…
SamFerracin Aug 6, 2024
7fafc35
lint
SamFerracin Aug 6, 2024
b091e49
json
SamFerracin Aug 6, 2024
6f9c8f9
some progress
SamFerracin Aug 6, 2024
d309399
CR
SamFerracin Aug 6, 2024
cda7631
Update qiskit_ibm_runtime/utils/noise_learner_result.py
SamFerracin Aug 6, 2024
6a37ffa
Merge branch 'noise-learner-phase2' of https://github.com/SamFerracin…
SamFerracin Aug 6, 2024
2ca74f6
len
SamFerracin Aug 6, 2024
7724023
Merge branch 'noise-learner-phase2' of https://github.com/SamFerracin…
SamFerracin Aug 6, 2024
081b79c
option
SamFerracin Aug 6, 2024
97d33a9
errors
SamFerracin Aug 6, 2024
5b241fd
conflict
SamFerracin Aug 9, 2024
0e5a2e8
integration tests
SamFerracin Aug 12, 2024
59e5b71
docs
SamFerracin Aug 12, 2024
2fbd179
Merge branch 'main' of https://github.com/Qiskit/qiskit-ibm-runtime i…
SamFerracin Aug 13, 2024
7ce463b
revert
SamFerracin Aug 13, 2024
a7f7b4a
revert
SamFerracin Aug 13, 2024
adace06
revert
SamFerracin Aug 13, 2024
90e9001
Merge branch 'main' of https://github.com/Qiskit/qiskit-ibm-runtime i…
SamFerracin Aug 13, 2024
1eefce3
lint
SamFerracin Aug 13, 2024
fdc707b
some progress
SamFerracin Aug 13, 2024
5901649
Merge branch 'main' of https://github.com/Qiskit/qiskit-ibm-runtime i…
SamFerracin Aug 14, 2024
6255ac3
unit
SamFerracin Aug 14, 2024
d2736c7
black
SamFerracin Aug 15, 2024
9ca85bf
conflict
SamFerracin Aug 15, 2024
e9311e9
lint
SamFerracin Aug 15, 2024
73414a1
release note
SamFerracin Aug 15, 2024
0a7d88a
image
SamFerracin Aug 15, 2024
2ad80e7
empty
SamFerracin Aug 15, 2024
b9d36f0
integration
SamFerracin Aug 15, 2024
318ef5a
remove redundant test as session is already tested elsewhere
SamFerracin Aug 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/apidocs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ qiskit-ibm-runtime API reference

runtime_service
noise_learner
noise_learner_result
options
transpiler
qiskit_ibm_runtime.transpiler.passes.scheduling
Expand Down
4 changes: 4 additions & 0 deletions docs/apidocs/noise_learner_result.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.. automodule:: qiskit_ibm_runtime.utils.noise_learner_result
:no-members:
:no-inherited-members:
:no-special-members:
10 changes: 9 additions & 1 deletion qiskit_ibm_runtime/options/resilience_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@

"""Resilience options."""

from typing import Literal, Union
from typing import List, Literal, Union
from dataclasses import asdict

from pydantic import model_validator, Field

from ..utils.noise_learner_result import LayerError
from .utils import Unset, UnsetType, Dict, primitive_dataclass
from .measure_noise_learning_options import MeasureNoiseLearningOptions
from .zne_options import ZneOptions
Expand Down Expand Up @@ -65,6 +66,12 @@ class ResilienceOptionsV2:

layer_noise_learning: Layer noise learning options.
See :class:`LayerNoiseLearningOptions` for all options.

layer_noise_model: A list of :class:`LayerError` objects.
If set, all the mitigation strategies that require noise data (e.g., PEC and PEA)
skip the noise learning stage, and instead gather the required information from
``layer_noise_model``. Layers whose information is missing in ``layer_noise_model``
are treated as noiseless and their noise is not mitigated.
"""

measure_mitigation: Union[UnsetType, bool] = Unset
Expand All @@ -78,6 +85,7 @@ class ResilienceOptionsV2:
layer_noise_learning: Union[LayerNoiseLearningOptions, Dict] = Field(
default_factory=LayerNoiseLearningOptions
)
layer_noise_model: Union[UnsetType, List[LayerError]] = Unset

@model_validator(mode="after")
def _validate_options(self) -> "ResilienceOptionsV2":
Expand Down
12 changes: 11 additions & 1 deletion qiskit_ibm_runtime/utils/noise_learner_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,17 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""NoiseLearner result class"""
"""
==================================================================================
NoiseLearner result classes (:mod:`qiskit_ibm_runtime.utils.noise_learner_result`)
==================================================================================

.. autosummary::
:toctree: ../stubs/

PauliLindbladError
LayerError
"""

from __future__ import annotations

Expand Down
3 changes: 3 additions & 0 deletions release-notes/unreleased/1858.feat.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
``ResilienceOptionsV2`` has a new field ``layer_noise_model``. When this field is set, all the
mitigation strategies that require noise data skip the noise learning stage, and instead gather
the required information from ``layer_noise_model``.
93 changes: 46 additions & 47 deletions test/integration/test_noise_learner.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@

from qiskit.circuit import QuantumCircuit
from qiskit.providers.jobstatus import JobStatus
from qiskit.compiler import transpile

from qiskit_ibm_runtime import RuntimeJob, Session
from qiskit_ibm_runtime import RuntimeJob, Session, EstimatorV2
from qiskit_ibm_runtime.noise_learner import NoiseLearner
from qiskit_ibm_runtime.utils.noise_learner_result import PauliLindbladError, LayerError
from qiskit_ibm_runtime.options import NoiseLearnerOptions
from qiskit_ibm_runtime.options import NoiseLearnerOptions, EstimatorOptions

from ..decorators import run_integration_test
from ..ibm_test_case import IBMIntegrationTestCase
Expand All @@ -39,12 +38,12 @@ def setUp(self) -> None:
raise SkipTest("test_eagle not available in this environment")

c1 = QuantumCircuit(2)
c1.cx(0, 1)
c1.ecr(0, 1)

c2 = QuantumCircuit(3)
c2.cx(0, 1)
c2.cx(1, 2)
c2.cx(0, 1)
c2.ecr(0, 1)
c2.ecr(1, 2)
c2.ecr(0, 1)

self.circuits = [c1, c2]

Expand All @@ -65,10 +64,9 @@ def test_with_default_options(self, service): # pylint: disable=unused-argument
options = NoiseLearnerOptions()
learner = NoiseLearner(mode=backend, options=options)

circuits = transpile(self.circuits, backend=backend)
job = learner.run(circuits)
job = learner.run(self.circuits)

self._verify(job, self.default_input_options)
self._verify(job, self.default_input_options, 3)

@run_integration_test
def test_with_non_default_options(self, service): # pylint: disable=unused-argument
Expand All @@ -80,43 +78,12 @@ def test_with_non_default_options(self, service): # pylint: disable=unused-argu
options.layer_pair_depths = [0, 1]
learner = NoiseLearner(mode=backend, options=options)

circuits = transpile(self.circuits, backend=backend)
job = learner.run(circuits)
job = learner.run(self.circuits)

input_options = deepcopy(self.default_input_options)
input_options["max_layers_to_learn"] = 1
input_options["layer_pair_depths"] = [0, 1]
self._verify(job, input_options)

@run_integration_test
def test_in_session(self, service):
"""Test noise learner when used within a session."""
backend = self.backend

options = NoiseLearnerOptions()
options.max_layers_to_learn = 1
options.layer_pair_depths = [0, 1]

input_options = deepcopy(self.default_input_options)
input_options["max_layers_to_learn"] = 1
input_options["layer_pair_depths"] = [0, 1]

circuits = transpile(self.circuits, backend=backend)

with Session(service, backend) as session:
options.twirling_strategy = "all"
learner1 = NoiseLearner(mode=session, options=options)
job1 = learner1.run(circuits)

input_options["twirling_strategy"] = "all"
self._verify(job1, input_options)

options.twirling_strategy = "active-circuit"
learner2 = NoiseLearner(mode=session, options=options)
job2 = learner2.run(circuits)

input_options["twirling_strategy"] = "active-circuit"
self._verify(job2, input_options)
self._verify(job, input_options, 1)

@run_integration_test
def test_with_no_layers(self, service): # pylint: disable=unused-argument
Expand All @@ -127,20 +94,52 @@ def test_with_no_layers(self, service): # pylint: disable=unused-argument
options.max_layers_to_learn = 0
learner = NoiseLearner(mode=backend, options=options)

circuits = transpile(self.circuits, backend=backend)
job = learner.run(circuits)
job = learner.run(self.circuits)

self.assertEqual(job.result().data, [])

input_options = deepcopy(self.default_input_options)
input_options["max_layers_to_learn"] = 0
self._verify(job, input_options)
self._verify(job, input_options, 0)

@run_integration_test
def test_learner_plus_estimator(self, service): # pylint: disable=unused-argument
"""Test feeding noise learner data to estimator."""
backend = self.backend

options = EstimatorOptions()
options.resilience.zne_mitigation = True # pylint: disable=assigning-non-slot
options.resilience.zne.amplifier = "pea"
options.resilience.layer_noise_learning.layer_pair_depths = [0, 1]

def _verify(self, job: RuntimeJob, expected_input_options: dict) -> None:
pubs = [(c, "Z" * c.num_qubits) for c in self.circuits]

with Session(service, backend) as session:
learner = NoiseLearner(mode=session, options=options)
learner_job = learner.run(self.circuits)
noise_model = learner_job.result()
self.assertEqual(len(noise_model), 3)

estimator = EstimatorV2(mode=session, options=options)
estimator.options.resilience.layer_noise_model = noise_model

estimator_job = estimator.run(pubs)
result = estimator_job.result()

noise_model_metadata = result.metadata["resilience"]["layer_noise_model"]
for x, y in zip(noise_model, noise_model_metadata):
self.assertEqual(x.circuit, y.circuit)
self.assertEqual(x.qubits, y.qubits)
self.assertEqual(x.error.generators, y.error.generators)
self.assertEqual(x.error.rates.tolist(), y.error.rates.tolist())

def _verify(self, job: RuntimeJob, expected_input_options: dict, n_results: int) -> None:
job.wait_for_final_state()
self.assertEqual(job.status(), JobStatus.DONE, job.error_message())

result = job.result()
self.assertEqual(len(result), n_results)

for datum in result.data:
circuit = datum.circuit
qubits = datum.qubits
Expand Down