Skip to content

Commit

Permalink
Adding support LayerErrors with unknown error channels (#1942)
Browse files Browse the repository at this point in the history
* restricted option temporarily

* test

* docs

* test

* done

* pylint

* pylint

* mypy

* Update qiskit_ibm_runtime/options/resilience_options.py

* Update qiskit_ibm_runtime/options/resilience_options.py

* Update qiskit_ibm_runtime/options/resilience_options.py

* typo

* CR

* check option

* Update qiskit_ibm_runtime/utils/noise_learner_result.py

Co-authored-by: Christopher J. Wood <[email protected]>

* docs

---------

Co-authored-by: Christopher J. Wood <[email protected]>
  • Loading branch information
SamFerracin and chriseclectic authored Sep 23, 2024
1 parent af979cd commit 825b994
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 16 deletions.
2 changes: 1 addition & 1 deletion qiskit_ibm_runtime/options/resilience_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def _validate_options(self) -> "ResilienceOptionsV2":
# Validate not ZNE+PEC
if self.pec_mitigation is True and self.zne_mitigation is True:
raise ValueError(
"pec_mitigation and zne_mitigation`options cannot be "
"'pec_mitigation' and 'zne_mitigation' options cannot be "
"simultaneously enabled. Set one of them to False."
)

Expand Down
23 changes: 16 additions & 7 deletions qiskit_ibm_runtime/utils/noise_learner_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from __future__ import annotations

from typing import Any, Iterator, Sequence, Union, TYPE_CHECKING
from typing import Any, Iterator, Optional, Sequence, Union, TYPE_CHECKING
from numpy.typing import NDArray
import numpy as np

Expand Down Expand Up @@ -139,21 +139,29 @@ class LayerError:
Args:
circuit: A circuit whose noise has been learnt.
qubits: The labels of the qubits in the ``circuit``.
error: The Pauli Lindblad error channel affecting the ``circuit``.
error: The Pauli Lindblad error channel affecting the ``circuit``, or ``None`` if the error
channel is either unknown or explicitly disabled.
Raises:
ValueError: If ``circuit``, ``qubits``, and ``error`` have mismatching number of qubits.
"""

def __init__(
self, circuit: QuantumCircuit, qubits: Sequence[int], error: PauliLindbladError
self,
circuit: QuantumCircuit,
qubits: Sequence[int],
error: Optional[PauliLindbladError] = None,
) -> None:

self._circuit = circuit
self._qubits = list(qubits)
self._error = error

if len({self.circuit.num_qubits, len(self.qubits), self.error.num_qubits}) != 1:
raise ValueError("Mistmatching numbers of qubits.")
err = ValueError("Mistmatching numbers of qubits.")
if len(self.qubits) != self.circuit.num_qubits:
raise err
if self.error is not None and len(self.qubits) != self.error.num_qubits:
raise err

@property
def circuit(self) -> QuantumCircuit:
Expand All @@ -170,9 +178,10 @@ def qubits(self) -> list[int]:
return self._qubits

@property
def error(self) -> PauliLindbladError:
def error(self) -> Union[PauliLindbladError, None]:
r"""
The error channel in this :class:`.~LayerError`.
The error channel in this :class:`.~LayerError`, or ``None`` if the error channel is either
unknown or explicitly disabled.
"""
return self._error

Expand Down
14 changes: 8 additions & 6 deletions test/unit/test_data_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,9 @@ def assert_primitive_results_equal(self, primitive_result1, primitive_result2):

def assert_pauli_lindblad_error_equal(self, error1, error2):
"""Tests that two PauliLindbladError objects are equal"""
self.assertEqual(error1.generators, error2.generators)
self.assertEqual(error1.rates.tolist(), error2.rates.tolist())
if error1 or error2:
self.assertEqual(error1.generators, error2.generators)
self.assertEqual(error1.rates.tolist(), error2.rates.tolist())

def assert_layer_errors_equal(self, layer_error1, layer_error2):
"""Tests that two LayerError objects are equal"""
Expand Down Expand Up @@ -459,13 +460,13 @@ def make_test_primitive_results(self):
primitive_results.append(result)
return primitive_results

def make_test_noise_learner_results(self):
def make_test_noise_learner_results(self, unknown_err=False):
"""Generates test data for NoiseLearnerResult test"""
noise_learner_results = []
circuit = QuantumCircuit(2)
circuit.cx(0, 1)
circuit.measure_all()
error = PauliLindbladError(PauliList(["XX", "ZZ"]), [0.1, 0.2])
error = None if unknown_err else PauliLindbladError(PauliList(["XX", "ZZ"]), [0.1, 0.2])
layer_error = LayerError(circuit, [3, 5], error)

noise_learner_result = NoiseLearnerResult([layer_error])
Expand Down Expand Up @@ -596,9 +597,10 @@ def test_primitive_result(self):
self.assertIsInstance(decoded, PrimitiveResult)
self.assert_primitive_results_equal(primitive_result, decoded)

def test_noise_learner_result(self):
@data(True, False)
def test_noise_learner_result(self, unknown_err):
"""Test encoding and decoding NoiseLearnerResult"""
for noise_learner_result in self.make_test_noise_learner_results():
for noise_learner_result in self.make_test_noise_learner_results(unknown_err):
payload = {"noise_learner_result": noise_learner_result}
encoded = json.dumps(payload, cls=RuntimeEncoder)
decoded = json.loads(encoded, cls=RuntimeDecoder)["noise_learner_result"]
Expand Down
2 changes: 1 addition & 1 deletion test/unit/test_estimator_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class TestEstimatorOptions(IBMTestCase):
({"noise_factors": [1, 3, 5]}, "Unexpected keyword argument"),
(
{"resilience": {"zne_mitigation": True, "pec_mitigation": True}},
"pec_mitigation and zne_mitigation`options cannot be simultaneously enabled",
"'pec_mitigation' and 'zne_mitigation' options cannot be simultaneously enabled",
),
(
{"simulator": {"noise_model": "foo"}},
Expand Down
3 changes: 2 additions & 1 deletion test/unit/test_noise_learner_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ def setUp(self):
# A set of errors
error1 = PauliLindbladError(PauliList(["XX", "ZZ"]), [0.1, 0.2])
error2 = PauliLindbladError(PauliList(["XXX", "ZZZ", "YIY"]), [0.3, 0.4, 0.5])
self.errors = [error1, error2]
error3 = None
self.errors = [error1, error2, error3]

# Another set of errors used in the visualization tests
circuit = QuantumCircuit(4)
Expand Down

0 comments on commit 825b994

Please sign in to comment.