diff --git a/qiskit_aer/noise/device/models.py b/qiskit_aer/noise/device/models.py index 4be3bf7283..adc5927bae 100644 --- a/qiskit_aer/noise/device/models.py +++ b/qiskit_aer/noise/device/models.py @@ -171,12 +171,15 @@ def basic_device_gate_errors( ) # Generate custom gate time dict + # Units used in the following computation: ns (time), Hz (frequency), mK (temperature). custom_times = {} relax_params = [] if thermal_relaxation: # If including thermal relaxation errors load - # T1, T2, and frequency values from properties + # T1 [ns], T2 [ns], and frequency [GHz] values from properties relax_params = thermal_relaxation_values(properties) + # Unit conversion: GHz -> Hz + relax_params = [(t1, t2, freq * 1e9) for t1, t2, freq in relax_params] # If we are specifying custom gate times include # them in the custom times dict if gate_lengths: @@ -207,7 +210,7 @@ def basic_device_gate_errors( # Get relaxation error if thermal_relaxation: relax_error = _device_thermal_relaxation_error( - qubits, relax_time, relax_params, temperature, thermal_relaxation + qubits, relax_time, relax_params, temperature ) # Get depolarizing error channel @@ -239,6 +242,8 @@ def _basic_device_target_gate_errors( Note that, in the resulting error list, non-Gate instructions (e.g. Reset) will have no gate errors while they may have thermal relaxation errors. Exceptionally, Measure instruction will have no errors, neither gate errors nor relaxation errors. + + Note: Units in use: Time [s], Frequency [Hz], Temperature [mK] """ errors = [] for op_name, inst_prop_dic in target.items(): @@ -329,12 +334,14 @@ def _device_depolarizing_error(qubits, error_param, relax_error=None): return None -def _device_thermal_relaxation_error( - qubits, gate_time, relax_params, temperature, thermal_relaxation=True -): - """Construct a thermal_relaxation_error for device""" +def _device_thermal_relaxation_error(qubits, gate_time, relax_params, temperature): + """Construct a thermal_relaxation_error for device. + + Expected units: frequency in relax_params [Hz], temperature [mK]. + Note that gate_time and T1/T2 in relax_params must be in the same time unit. + """ # Check trivial case - if not thermal_relaxation or gate_time is None or gate_time == 0: + if gate_time is None or gate_time == 0: return None # Construct a tensor product of single qubit relaxation errors @@ -368,7 +375,7 @@ def _truncate_t2_value(t1, t2): def _excited_population(freq, temperature): - """Return excited state population from freq [GHz] and temperature [mK].""" + """Return excited state population from freq [Hz] and temperature [mK].""" if freq is None or temperature is None: return 0 population = 0 @@ -379,10 +386,10 @@ def _excited_population(freq, temperature): # Boltzman constant kB = 8.617333262e-5 (eV/K) # Planck constant h = 4.135667696e-15 (eV.s) # qubit temperature temperatue = T (mK) - # qubit frequency frequency = f (GHz) - # excited state population = 1/(1+exp((h*f*1e9)/(kb*T*1e-3))) + # qubit frequency frequency = f (Hz) + # excited state population = 1/(1+exp((h*f)/(kb*T*1e-3))) # See e.g. Phys. Rev. Lett. 114, 240501 (2015). - exp_param = exp((47.99243 * freq) / abs(temperature)) + exp_param = exp((47.99243 * 1e-9 * freq) / abs(temperature)) population = 1 / (1 + exp_param) if temperature < 0: # negative temperate implies |1> is thermal ground diff --git a/releasenotes/notes/fix-excitation-population-6af281a61f659dda.yaml b/releasenotes/notes/fix-excitation-population-6af281a61f659dda.yaml new file mode 100644 index 0000000000..874f9b3455 --- /dev/null +++ b/releasenotes/notes/fix-excitation-population-6af281a61f659dda.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed a bug where :meth:`~.NoiseModel.from_backend` with ``BackendV2`` and non-zero ``temperature`` + produces relaxation noises with incorrect excitation population. + Fixed `#1937 `__. diff --git a/test/terra/noise/test_device_models.py b/test/terra/noise/test_device_models.py index c31b6090e7..0035f38bdb 100644 --- a/test/terra/noise/test_device_models.py +++ b/test/terra/noise/test_device_models.py @@ -13,12 +13,14 @@ """ Tests for utility functions to create device noise model. """ - +import numpy as np from test.terra.common import QiskitAerTestCase -from qiskit.providers import QubitProperties +from qiskit.circuit.library.standard_gates import XGate from qiskit.providers.fake_provider import FakeNairobi, FakeNairobiV2 +from qiskit.transpiler import Target, QubitProperties, InstructionProperties from qiskit_aer.noise.device.models import basic_device_gate_errors +from qiskit_aer.noise.errors.standard_errors import thermal_relaxation_error class TestDeviceNoiseModel(QiskitAerTestCase): @@ -70,3 +72,16 @@ def test_basic_device_gate_errors_from_target_with_no_t2_value(self): target = FakeNairobiV2().target target.qubit_properties[0].t2 = None basic_device_gate_errors(target=target) + + def test_non_zero_temperature(self): + """Test if non-zero excited_state_population is obtained when positive temperature is supplied. + See https://github.com/Qiskit/qiskit-aer/issues/1937 for the details.""" + t1, t2, frequency, duration = 1e-4, 1e-4, 5e9, 5e-8 + target = Target(qubit_properties=[QubitProperties(t1=t1, t2=t2, frequency=frequency)]) + target.add_instruction(XGate(), {(0,): InstructionProperties(duration=duration)}) + errors = basic_device_gate_errors(target=target, gate_error=False, temperature=100) + _, _, x_error = errors[0] + no_excitation_error = thermal_relaxation_error(t1, t2, duration, excited_state_population=0) + x_error_matrix = x_error.to_quantumchannel().data + no_excitation_error_matrix = no_excitation_error.to_quantumchannel().data + self.assertFalse(np.allclose(x_error_matrix, no_excitation_error_matrix)) diff --git a/tox.ini b/tox.ini index 725e45bbc2..5b5a17c4ef 100644 --- a/tox.ini +++ b/tox.ini @@ -32,6 +32,7 @@ commands = [testenv:lint] envdir = .tox/lint basepython = python3 +allowlist_externals = sh commands = sh tools/clang-format.sh --Werror -n black --check {posargs} qiskit_aer test tools setup.py