Skip to content

Commit 03d130c

Browse files
committed
Extend coherence limit error computation to three or more qubits
1 parent 8628f23 commit 03d130c

File tree

3 files changed

+123
-5
lines changed

3 files changed

+123
-5
lines changed

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme
119119
# op = operation iterator
120120
# b = basis iterator
121121
good-names=a,b,i,j,k,d,n,m,ex,v,w,x,y,z,Run,_,logger,q,c,r,qr,cr,qc,nd,pi,op,b,ar,br,p,cp,dt,
122-
__unittest,iSwapGate,mu
122+
__unittest,iSwapGate,mu,t1,t2
123123

124124
# Bad variable names which should always be refused, separated by a comma
125125
bad-names=foo,bar,toto,tutu,tata

qiskit_experiments/library/randomized_benchmarking/rb_utils.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@
1313
"""
1414
RB Helper functions
1515
"""
16+
import functools
17+
import operator
1618
from typing import Tuple, Dict, Optional, List, Union, Sequence
1719

1820
import numpy as np
1921
import uncertainties
22+
23+
import qiskit.quantum_info as qi
2024
from qiskit import QiskitError, QuantumCircuit
2125
from qiskit.providers.backend import Backend
22-
2326
from qiskit_experiments.database_service.device_component import Qubit
2427
from qiskit_experiments.framework import DbAnalysisResultV1, AnalysisResultData
2528
from qiskit_experiments.warnings import deprecated_function
@@ -138,6 +141,10 @@ def gates_per_clifford(
138141
return {key: value[0] / value[1] for (key, value) in result.items()}
139142

140143
@staticmethod
144+
@deprecated_function(
145+
last_version="0.4",
146+
msg="Please use coherence_limit_error function that can handle three or more qubits instead.",
147+
)
141148
def coherence_limit(nQ=2, T1_list=None, T2_list=None, gatelen=0.1):
142149
"""
143150
The error per gate (1-average_gate_fidelity) given by the T1,T2 limit.
@@ -199,6 +206,79 @@ def coherence_limit(nQ=2, T1_list=None, T2_list=None, gatelen=0.1):
199206

200207
return coherence_limit_err
201208

209+
@staticmethod
210+
def coherence_limit_error(
211+
num_qubits: int, gate_length: float, t1s: Sequence, t2s: Optional[Sequence] = None
212+
):
213+
r"""
214+
The error per gate (1 - average_gate_fidelity) given by the T1,T2 limit
215+
assuming qubit-wise gate-independent amplitude damping error
216+
(or thermal relaxation error with no excitation).
217+
218+
That means, suppose the gate length $t$, the Choi matrix of the amplitude damping channel
219+
$\Lambda_q$ for a single qubit $q$ with $T_1$ and $T_2$ is give by
220+
$$
221+
\begin{bmatrix}
222+
1 & 0 & 0 & e^{-\frac{t}{T_2}} \\
223+
0 & 0 & 0 & 0 \\
224+
0 & 0 & 1-e^{-\frac{t}{T_1}} & 0 \\
225+
e^{-\frac{t}{T_2}} & 0 & 0 & e^{-\frac{t}{T_1}} \\
226+
\end{bmatrix}
227+
$$.
228+
The coherence limit error computed by this function is $1 - F_{\text{ave}}(\mathcal{E}, U)$
229+
where
230+
And the following equality holds.
231+
$$
232+
\begin{align}
233+
1 - F_{\text{ave}}(\mathcal{E}, U)
234+
&= \frac{d}{d+1} \left(1 - F_{\text{pro}}(\mathcal{E}, U)\right) \\
235+
&= \frac{d}{d+1} \left(1 - \frac{Tr[S_U^\dagger S_{\mathcal{E}}]}{d^2}\right) \\
236+
&= \frac{d}{d+1} \left(1 - \frac{Tr[S_{\Lambda}]}{d^2}\right)
237+
\end{align}
238+
$$
239+
where $F_{\text{avg}}(\mathcal{E}, U)$ and $F_{\text{pro}}(\mathcal{E}, U)$ are
240+
the average gate fidelity and the process fidelity of a quantum channel $\mathcal{E}$
241+
with a target unitary $U$, respectively, and $d$ is the dimension of Hilbert space of
242+
the considering qubit system.
243+
244+
Args:
245+
num_qubits: Number of qubits.
246+
gate_length: Duration of the gate in seconds.
247+
t1s: List of T1's from qubit 0 to num_qubits-1.
248+
t2s: List of T2's (as measured, not Tphi). If not given, assume T2 = 2 * T1.
249+
Each T2 value is truncated down to 2 * T1 if T2 > 2 * T1.
250+
251+
Returns:
252+
float: coherence limited error per gate.
253+
Raises:
254+
ValueError: if there are invalid inputs
255+
"""
256+
t1s = np.array(t1s)
257+
if t2s is None:
258+
t2s = 2 * t1s
259+
else:
260+
t2s = np.array([min(t2, 2 * t1) for t1, t2 in zip(t1s, t2s)])
261+
262+
if len(t1s) != num_qubits or len(t2s) != num_qubits:
263+
raise ValueError("Length of t1s/t2s must equal num_qubits")
264+
265+
def amplitude_damping_choi(t1, t2, time):
266+
return qi.Choi(
267+
np.array(
268+
[
269+
[1, 0, 0, np.exp(-time / t2)],
270+
[0, 0, 0, 0],
271+
[0, 0, 1 - np.exp(-time / t1), 0],
272+
[np.exp(-time / t2), 0, 0, np.exp(-time / t1)],
273+
]
274+
)
275+
)
276+
277+
chois = [amplitude_damping_choi(t1, t2, gate_length) for t1, t2 in zip(t1s, t2s)]
278+
traces = [np.real(np.trace(np.array(qi.SuperOp(choi)))) for choi in chois]
279+
d = 2**num_qubits
280+
return d / (d + 1) * (1 - functools.reduce(operator.mul, traces) / (d * d))
281+
202282
@staticmethod
203283
@deprecated_function(
204284
last_version="0.4",

test/randomized_benchmarking/test_rb_utils.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,52 @@ def test_coherence_limit(self):
167167
t2 = 100.0
168168
gate_2_qubits = 0.5
169169
gate_1_qubit = 0.1
170-
twoq_coherence_err = rb.RBUtils.coherence_limit(2, [t1, t1], [t2, t2], gate_2_qubits)
171170

172-
oneq_coherence_err = rb.RBUtils.coherence_limit(1, [t1], [t2], gate_1_qubit)
171+
with self.assertWarns(DeprecationWarning):
172+
oneq_coherence_err = rb.RBUtils.coherence_limit(1, [t1], [t2], gate_1_qubit)
173+
twoq_coherence_err = rb.RBUtils.coherence_limit(2, [t1, t1], [t2, t2], gate_2_qubits)
174+
# random test to ensure ole and new coherence_limit yield the same value for 1q and 2q cases
175+
import random
173176

174-
self.assertAlmostEqual(oneq_coherence_err, 0.00049975, 6, "Error: 1Q Coherence Limit")
177+
random.seed(123)
178+
for num_qubits in [1, 2]:
179+
for _ in range(100):
180+
t1s = [random.randint(100, 200) for _ in range(num_qubits)]
181+
t2s = [random.randint(100, 200) for _ in range(num_qubits)]
182+
time = random.randint(1, 10)
183+
self.assertAlmostEqual(
184+
rb.RBUtils.coherence_limit(num_qubits, t1s, t2s, time),
185+
rb.RBUtils.coherence_limit_error(num_qubits, time, t1s, t2s),
186+
)
175187

188+
self.assertAlmostEqual(oneq_coherence_err, 0.00049975, 6, "Error: 1Q Coherence Limit")
176189
self.assertAlmostEqual(twoq_coherence_err, 0.00597, 5, "Error: 2Q Coherence Limit")
177190

191+
def test_coherence_limit_error(self):
192+
"""Test coherence_limit_error."""
193+
t1 = 100.0
194+
t2 = 150.0
195+
coherence_err_1q = rb.RBUtils.coherence_limit_error(1, 0.1, [t1], [t2])
196+
coherence_err_2q = rb.RBUtils.coherence_limit_error(2, 0.5, [t1] * 2, [t2] * 2)
197+
coherence_err_9q = rb.RBUtils.coherence_limit_error(9, 0.9, [t1] * 9, [t2] * 9)
198+
self.assertAlmostEqual(coherence_err_1q, 0.00038873, 6, "Error: 1Q Coherence Limit")
199+
self.assertAlmostEqual(coherence_err_2q, 0.00465046, 6, "Error: 2Q Coherence Limit")
200+
self.assertAlmostEqual(coherence_err_9q, 0.04601531, 6, "Error: 9Q Coherence Limit")
201+
202+
self.assertAlmostEqual(
203+
rb.RBUtils.coherence_limit_error(num_qubits=1, gate_length=0.1, t1s=[10], t2s=[50]),
204+
rb.RBUtils.coherence_limit_error(num_qubits=1, gate_length=0.1, t1s=[10], t2s=[20]),
205+
"T2 value must be truncated down to 2 * T1",
206+
)
207+
self.assertAlmostEqual(
208+
rb.RBUtils.coherence_limit_error(num_qubits=1, gate_length=0.1, t1s=[10]),
209+
rb.RBUtils.coherence_limit_error(num_qubits=1, gate_length=0.1, t1s=[10], t2s=[20]),
210+
"If T2 values are not given, assume 2 * T1",
211+
)
212+
213+
with self.assertRaises(ValueError):
214+
rb.RBUtils.coherence_limit_error(num_qubits=2, gate_length=0.1, t1s=[10])
215+
178216
def test_clifford_1_qubit_generation(self):
179217
"""Verify 1-qubit clifford indeed generates the correct group"""
180218
clifford_dicts = [

0 commit comments

Comments
 (0)