diff --git a/qiskit_ibm_runtime/options/resilience_options.py b/qiskit_ibm_runtime/options/resilience_options.py index 6f07cc937..c086dda73 100644 --- a/qiskit_ibm_runtime/options/resilience_options.py +++ b/qiskit_ibm_runtime/options/resilience_options.py @@ -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." ) diff --git a/qiskit_ibm_runtime/utils/noise_learner_result.py b/qiskit_ibm_runtime/utils/noise_learner_result.py index e7965eaec..aa799953f 100644 --- a/qiskit_ibm_runtime/utils/noise_learner_result.py +++ b/qiskit_ibm_runtime/utils/noise_learner_result.py @@ -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 @@ -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: @@ -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 diff --git a/test/unit/test_data_serialization.py b/test/unit/test_data_serialization.py index 5e89a68a4..cc7bdca65 100644 --- a/test/unit/test_data_serialization.py +++ b/test/unit/test_data_serialization.py @@ -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""" @@ -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]) @@ -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"] diff --git a/test/unit/test_estimator_options.py b/test/unit/test_estimator_options.py index 3b039f118..4ebfc03fb 100644 --- a/test/unit/test_estimator_options.py +++ b/test/unit/test_estimator_options.py @@ -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"}}, diff --git a/test/unit/test_noise_learner_result.py b/test/unit/test_noise_learner_result.py index cd76000f4..022995a4f 100644 --- a/test/unit/test_noise_learner_result.py +++ b/test/unit/test_noise_learner_result.py @@ -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)