Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions qiskit/providers/aer/noise/device/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
5 changes: 0 additions & 5 deletions qiskit/providers/aer/noise/device/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 5 additions & 3 deletions qiskit/providers/aer/noise/noise_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions releasenotes/notes/fix-invalid-t2-error-a3685e4a3ad0a1e7.yaml
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/Qiskit/qiskit-aer/issues/1464>`__
for details.
67 changes: 64 additions & 3 deletions test/terra/noise/test_noise_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -229,6 +230,66 @@ 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

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()
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=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=[
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=u3_time_ns),
],
),
],
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):
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)
new_error = pauli_error([("I", 0.5), ("Z", 0.5)])
Expand Down