-
Notifications
You must be signed in to change notification settings - Fork 370
/
Copy pathmodels.py
286 lines (256 loc) · 11.6 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=invalid-name
"""
Simplified noise models for devices backends.
"""
import logging
from warnings import warn, catch_warnings, filterwarnings
from numpy import inf, exp, allclose
import qiskit.quantum_info as qi
from .parameters import readout_error_values
from .parameters import gate_param_values
from .parameters import thermal_relaxation_values
from .parameters import _NANOSECOND_UNITS
from ..errors.readout_error import ReadoutError
from ..errors.standard_errors import depolarizing_error
from ..errors.standard_errors import thermal_relaxation_error
logger = logging.getLogger(__name__)
def basic_device_readout_errors(properties):
"""
Return readout error parameters from a devices BackendProperties.
Args:
properties (BackendProperties): device backend properties
Returns:
list: A list of pairs ``(qubits, ReadoutError)`` for qubits with
non-zero readout error values.
"""
errors = []
for qubit, value in enumerate(readout_error_values(properties)):
if value is not None and not allclose(value, [0, 0]):
probabilities = [[1 - value[0], value[0]], [value[1], 1 - value[1]]]
errors.append(([qubit], ReadoutError(probabilities)))
return errors
def basic_device_gate_errors(properties,
gate_error=True,
thermal_relaxation=True,
gate_lengths=None,
gate_length_units='ns',
temperature=0,
standard_gates=None,
warnings=True):
"""
Return QuantumErrors derived from a devices BackendProperties.
If non-default values are used gate_lengths should be a list
of tuples ``(name, qubits, value)`` where ``name`` is the gate
name string, ``qubits`` is either a list of qubits or ``None``
to apply gate time to this gate one any set of qubits,
and ``value`` is the gate time in nanoseconds.
Args:
properties (BackendProperties): device backend properties
gate_error (bool): Include depolarizing gate errors (Default: True).
thermal_relaxation (Bool): Include thermal relaxation errors
(Default: True).
gate_lengths (list): Override device gate times with custom
values. If None use gate times from
backend properties. (Default: None).
gate_length_units (str): Time units for gate length values in gate_lengths.
Can be 'ns', 'ms', 'us', or 's' (Default: 'ns').
temperature (double): qubit temperature in milli-Kelvin (mK)
(Default: 0).
standard_gates (bool): DEPRECATED, If true return errors as standard
qobj gates. If false return as unitary
qobj instructions (Default: None).
warnings (bool): Display warnings (Default: True).
Returns:
list: A list of tuples ``(label, qubits, QuantumError)``, for gates
with non-zero quantum error terms, where `label` is the label of the
noisy gate, `qubits` is the list of qubits for the gate.
"""
if standard_gates is not None:
warn(
'"standard_gates" option has been deprecated as of qiskit-aer 0.10.0'
' and will be removed no earlier than 3 months from that release date.',
DeprecationWarning, stacklevel=2)
# Initilize empty errors
depol_error = None
relax_error = None
# Generate custom gate time dict
custom_times = {}
relax_params = []
if thermal_relaxation:
# If including thermal relaxation errors load
# T1, T2, and frequency values from properties
relax_params = thermal_relaxation_values(properties)
# If we are specifying custom gate times include
# them in the custom times dict
if gate_lengths:
for name, qubits, value in gate_lengths:
# Convert all gate lengths to nanosecond units
time = value * _NANOSECOND_UNITS[gate_length_units]
if name in custom_times:
custom_times[name].append((qubits, time))
else:
custom_times[name] = [(qubits, time)]
# Get the device gate parameters from properties
device_gate_params = gate_param_values(properties)
# Construct quantum errors
errors = []
for name, qubits, gate_length, error_param in device_gate_params:
# Check for custom gate time
relax_time = gate_length
# Override with custom value
if name in custom_times:
filtered = [
val for q, val in custom_times[name]
if q is None or q == qubits
]
if filtered:
# get first value
relax_time = filtered[0]
# Get relaxation error
if thermal_relaxation:
relax_error = _device_thermal_relaxation_error(
qubits, relax_time, relax_params, temperature,
thermal_relaxation)
# Get depolarizing error channel
if gate_error:
with catch_warnings():
filterwarnings(
"ignore",
category=DeprecationWarning,
module="qiskit.providers.aer.noise.errors.errorutils"
)
depol_error = _device_depolarizing_error(
qubits, error_param, relax_error, standard_gates, warnings=warnings)
# Combine errors
if depol_error is None and relax_error is None:
# No error for this gate
pass
elif depol_error is not None and relax_error is None:
# Append only the depolarizing error
errors.append((name, qubits, depol_error))
# Append only the relaxation error
elif relax_error is not None and depol_error is None:
errors.append((name, qubits, relax_error))
else:
# Append a combined error of depolarizing error
# followed by a relaxation error
combined_error = depol_error.compose(relax_error)
errors.append((name, qubits, combined_error))
return errors
def _device_depolarizing_error(qubits,
error_param,
relax_error=None,
standard_gates=True,
warnings=True):
"""Construct a depolarizing_error for device"""
# We now deduce the depolarizing channel error parameter in the
# presence of T1/T2 thermal relaxation. We assume the gate error
# parameter is given by e = 1 - F where F is the average gate fidelity,
# and that this average gate fidelity is for the composition
# of a T1/T2 thermal relaxation channel and a depolarizing channel.
# For the n-qubit depolarizing channel E_dep = (1-p) * I + p * D, where
# I is the identity channel and D is the completely depolarizing
# channel. To compose the errors we solve for the equation
# F = F(E_dep * E_relax)
# = (1 - p) * F(I * E_relax) + p * F(D * E_relax)
# = (1 - p) * F(E_relax) + p * F(D)
# = F(E_relax) - p * (dim * F(E_relax) - 1) / dim
# Hence we have that the depolarizing error probability
# for the composed depolarization channel is
# p = dim * (F(E_relax) - F) / (dim * F(E_relax) - 1)
if relax_error is not None:
relax_fid = qi.average_gate_fidelity(relax_error)
relax_infid = 1 - relax_fid
else:
relax_fid = 1
relax_infid = 0
if error_param is not None and error_param > relax_infid:
num_qubits = len(qubits)
dim = 2 ** num_qubits
error_max = dim / (dim + 1)
# Check if reported error param is un-physical
# The minimum average gate fidelity is F_min = 1 / (dim + 1)
# So the maximum gate error is 1 - F_min = dim / (dim + 1)
if error_param > error_max:
if warnings:
logger.warning(
'Device reported a gate error parameter greater'
' than maximum allowed value (%f > %f). Truncating to'
' maximum value.', error_param, error_max)
error_param = error_max
# Model gate error entirely as depolarizing error
num_qubits = len(qubits)
dim = 2 ** num_qubits
depol_param = dim * (error_param - relax_infid) / (dim * relax_fid - 1)
max_param = 4**num_qubits / (4**num_qubits - 1)
if depol_param > max_param:
if warnings:
logger.warning(
'Device model returned a depolarizing error parameter greater'
' than maximum allowed value (%f > %f). Truncating to'
' maximum value.', depol_param, max_param)
depol_param = min(depol_param, max_param)
return depolarizing_error(
depol_param, num_qubits, standard_gates=standard_gates)
return None
def _device_thermal_relaxation_error(qubits,
gate_time,
relax_params,
temperature,
thermal_relaxation=True):
"""Construct a thermal_relaxation_error for device"""
# Check trivial case
if not thermal_relaxation or gate_time is None or gate_time == 0:
return None
# Construct a tensor product of single qubit relaxation errors
# for any multi qubit gates
first = True
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)
first = False
else:
single = thermal_relaxation_error(t1, t2, gate_time, population)
error = error.expand(single)
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
if freq != inf and temperature != 0:
# Compute the excited state population from qubit
# frequency and temperature
# Boltzman constant kB = 8.617333262-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((2*h*f*1e9)/(kb*T*1e-3)))
exp_param = exp((95.9849 * freq) / abs(temperature))
population = 1 / (1 + exp_param)
if temperature < 0:
# negative temperate implies |1> is thermal ground
population = 1 - population
return population