From 10e093abdf668972acae6b5dac54c65081c4486e Mon Sep 17 00:00:00 2001 From: Toshinari Itoko Date: Tue, 22 Feb 2022 15:12:07 +0900 Subject: [PATCH 1/5] Change not to fail to run noisy simulation with T2 > 2 * T1 --- qiskit/providers/aer/noise/device/models.py | 12 ++++++++++++ qiskit/providers/aer/noise/noise_model.py | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/qiskit/providers/aer/noise/device/models.py b/qiskit/providers/aer/noise/device/models.py index daa6c1ab96..c6ec388ec1 100644 --- a/qiskit/providers/aer/noise/device/models.py +++ b/qiskit/providers/aer/noise/device/models.py @@ -245,6 +245,7 @@ def _device_thermal_relaxation_error(qubits, error = None for qubit in qubits: t1, t2, freq = relax_params[qubit] + t2 = _truncate_t2_value(t1, t2) population = _excited_population(freq, temperature) if first: error = thermal_relaxation_error(t1, t2, gate_time, population) @@ -255,6 +256,17 @@ def _device_thermal_relaxation_error(qubits, return error +def _truncate_t2_value(t1, t2): + """Return t2 value truncated to 2 * t1 (for t2 > 2 * t1)""" + new_t2 = t2 + if t2 > 2 * t1: + new_t2 = 2 * t1 + warn("Device model returned an invalid T_2 relaxation time greater than" + f" the theoretical maximum value 2 * T_1 ({t2} > 2 * {t1})." + " Truncating to maximum value.", UserWarning) + return new_t2 + + def _excited_population(freq, temperature): """Return excited state population""" population = 0 diff --git a/qiskit/providers/aer/noise/noise_model.py b/qiskit/providers/aer/noise/noise_model.py index 6bcf58d265..082ec62e1a 100644 --- a/qiskit/providers/aer/noise/noise_model.py +++ b/qiskit/providers/aer/noise/noise_model.py @@ -25,7 +25,7 @@ from qiskit.providers.exceptions import BackendPropertyError from qiskit.providers.models import BackendProperties from qiskit.transpiler import PassManager -from .device.models import _excited_population +from .device.models import _excited_population, _truncate_t2_value from .device.models import basic_device_gate_errors from .device.models import basic_device_readout_errors from .errors.quantum_error import QuantumError @@ -373,9 +373,11 @@ def from_backend(cls, backend, except BackendPropertyError: excited_state_populations = None try: + t1s = [properties.t1(q) for q in range(num_qubits)] + t2s = [properties.t2(q) for q in range(num_qubits)] delay_pass = RelaxationNoisePass( - t1s=[properties.t1(q) for q in range(num_qubits)], - t2s=[properties.t2(q) for q in range(num_qubits)], + t1s=t1s, + t2s=[_truncate_t2_value(t1, t2) for t1, t2 in zip(t1s, t2s)], dt=dt, op_types=Delay, excited_state_populations=excited_state_populations From 4b9c2720bb892d25aa7263abe283de02b582a004 Mon Sep 17 00:00:00 2001 From: Toshinari Itoko Date: Wed, 2 Mar 2022 00:32:05 +0900 Subject: [PATCH 2/5] remove silent t2 truncation --- qiskit/providers/aer/noise/device/parameters.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/qiskit/providers/aer/noise/device/parameters.py b/qiskit/providers/aer/noise/device/parameters.py index ead1fa1836..7468e526d4 100644 --- a/qiskit/providers/aer/noise/device/parameters.py +++ b/qiskit/providers/aer/noise/device/parameters.py @@ -180,11 +180,6 @@ def thermal_relaxation_values(properties): # Convert to Gigahertz freq *= _GHZ_UNITS.get(freq_params.unit, 1) - # NOTE: T2 cannot be larger than 2 * T1 for a physical noise - # channel, however if a backend erroneously reports such a value we - # truncated it here: - t2 = min(2 * t1, t2) - values.append((t1, t2, freq)) return values From 5c8d728954b47d5556e400ac0dc27b04a94cd408 Mon Sep 17 00:00:00 2001 From: Toshinari Itoko Date: Wed, 2 Mar 2022 00:46:15 +0900 Subject: [PATCH 3/5] add a test Co-authored-by: Hiroshi Horii --- test/terra/noise/test_noise_model.py | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/terra/noise/test_noise_model.py b/test/terra/noise/test_noise_model.py index 24f05e1bfc..2ebbd6b15f 100644 --- a/test/terra/noise/test_noise_model.py +++ b/test/terra/noise/test_noise_model.py @@ -229,6 +229,55 @@ def test_noise_model_from_mumbai(self): result = AerSimulator().run(circ, noise_model=noise_model).result() self.assertTrue(result.success) + def test_noise_model_from_invalid_t2_backend(self): + """Test if issue user warning when creating a noise model from invalid t2 backend""" + from qiskit.providers.models.backendproperties import BackendProperties, Gate, Nduv + import datetime + + class InvalidT2Fake1Q(mock.FakeBackend): + def __init__(self): + mock_time = datetime.datetime.now() + dt = 1.3333 + configuration = BackendProperties( + backend_name="invalid_t2", + backend_version="0.0.0", + num_qubits=1, + basis_gates=["u3"], + qubits=[ + [ + Nduv(date=mock_time, name="T1", unit="µs", value=71.9500421005539), + Nduv(date=mock_time, name="T2", unit="µs", value=200), + Nduv(date=mock_time, name="frequency", unit="MHz", value=4919.96800692), + ], + ], + gates=[ + Gate( + gate="u3", + name="u3_0", + qubits=[0], + parameters=[ + Nduv(date=mock_time, name="gate_error", unit="", value=0.001), + Nduv(date=mock_time, name="gate_length", unit="ns", value=2 * dt), + ], + ), + ], + last_update_date=mock_time, + general=[], + ) + super().__init__(configuration) + + def defaults(self): + """defaults == configuration""" + return self._configuration + + def properties(self): + """properties == configuration""" + return self._configuration + + backend = InvalidT2Fake1Q() + with self.assertWarns(UserWarning): + NoiseModel.from_backend(backend) + def test_transform_noise(self): org_error = reset_error(0.2) new_error = pauli_error([("I", 0.5), ("Z", 0.5)]) From cd564960737dd6da8571c8a5429018f368f9026a Mon Sep 17 00:00:00 2001 From: Toshinari Itoko Date: Wed, 2 Mar 2022 14:26:00 +0900 Subject: [PATCH 4/5] add one more check in a test --- test/terra/noise/test_noise_model.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/test/terra/noise/test_noise_model.py b/test/terra/noise/test_noise_model.py index 2ebbd6b15f..9abd2af487 100644 --- a/test/terra/noise/test_noise_model.py +++ b/test/terra/noise/test_noise_model.py @@ -19,17 +19,18 @@ import numpy as np from qiskit.providers.aer.backends import AerSimulator from qiskit.providers.aer.noise import NoiseModel -from qiskit.providers.aer.utils.noise_transformation import transform_noise_model +from qiskit.providers.aer.noise.device.models import _excited_population from qiskit.providers.aer.noise.errors.standard_errors import amplitude_damping_error from qiskit.providers.aer.noise.errors.standard_errors import kraus_error from qiskit.providers.aer.noise.errors.standard_errors import pauli_error from qiskit.providers.aer.noise.errors.standard_errors import reset_error -from test.terra.common import QiskitAerTestCase +from qiskit.providers.aer.noise.errors.standard_errors import thermal_relaxation_error +from qiskit.providers.aer.utils.noise_transformation import transform_noise_model from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.compiler import transpile -from qiskit.transpiler import TranspilerError from qiskit.test import mock +from test.terra.common import QiskitAerTestCase class TestNoiseModel(QiskitAerTestCase): @@ -234,6 +235,10 @@ def test_noise_model_from_invalid_t2_backend(self): from qiskit.providers.models.backendproperties import BackendProperties, Gate, Nduv import datetime + t1_ns, invalid_t2_ns = 75_1000, 200_1000 + u3_time_ns = 320 + frequency = 4919.96800692 + class InvalidT2Fake1Q(mock.FakeBackend): def __init__(self): mock_time = datetime.datetime.now() @@ -245,9 +250,9 @@ def __init__(self): basis_gates=["u3"], qubits=[ [ - Nduv(date=mock_time, name="T1", unit="µs", value=71.9500421005539), - Nduv(date=mock_time, name="T2", unit="µs", value=200), - Nduv(date=mock_time, name="frequency", unit="MHz", value=4919.96800692), + Nduv(date=mock_time, name="T1", unit="µs", value=t1_ns/1000), + Nduv(date=mock_time, name="T2", unit="µs", value=invalid_t2_ns/1000), + Nduv(date=mock_time, name="frequency", unit="MHz", value=frequency), ], ], gates=[ @@ -257,7 +262,7 @@ def __init__(self): qubits=[0], parameters=[ Nduv(date=mock_time, name="gate_error", unit="", value=0.001), - Nduv(date=mock_time, name="gate_length", unit="ns", value=2 * dt), + Nduv(date=mock_time, name="gate_length", unit="ns", value=u3_time_ns), ], ), ], @@ -276,7 +281,14 @@ def properties(self): backend = InvalidT2Fake1Q() with self.assertWarns(UserWarning): - NoiseModel.from_backend(backend) + noise_model = NoiseModel.from_backend(backend, gate_error=False) + expected = thermal_relaxation_error( + t1=t1_ns, + t2=2*t1_ns, + time=u3_time_ns, + excited_state_population=_excited_population(frequency, temperature=0) + ) + self.assertEqual(expected, noise_model._local_quantum_errors["u3"][(0, )]) def test_transform_noise(self): org_error = reset_error(0.2) From 9b5159ba552f23aa340d4aa204bfe3373ae425af Mon Sep 17 00:00:00 2001 From: Toshinari Itoko Date: Wed, 2 Mar 2022 14:26:20 +0900 Subject: [PATCH 5/5] add reno --- .../notes/fix-invalid-t2-error-a3685e4a3ad0a1e7.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 releasenotes/notes/fix-invalid-t2-error-a3685e4a3ad0a1e7.yaml diff --git a/releasenotes/notes/fix-invalid-t2-error-a3685e4a3ad0a1e7.yaml b/releasenotes/notes/fix-invalid-t2-error-a3685e4a3ad0a1e7.yaml new file mode 100644 index 0000000000..cb1abebbe7 --- /dev/null +++ b/releasenotes/notes/fix-invalid-t2-error-a3685e4a3ad0a1e7.yaml @@ -0,0 +1,12 @@ +--- +fixes: + - | + Fixes a bug in ``NoiseModel.from_backend()`` that raised an error when + T2 value greater than 2 * T1 was supplied by the backend. + After this fix, it becomes to truncate T2 value up to 2 * T1 and + issue a user warning if truncates. + The bug was introduced at #1391 and, before that, ``NoiseModel.from_backend()`` had + truncated the T2 value up to 2 * T1 silently. + + See `Issue 1464 `__ + for details.