Skip to content

Commit 423fbc6

Browse files
authored
Merge pull request #89 from qutech/bugfix/doc_and_basis
Enhance documentation
2 parents a48ccb0 + a703932 commit 423fbc6

File tree

3 files changed

+82
-16
lines changed

3 files changed

+82
-16
lines changed

filter_functions/basis.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,8 @@ def H(self) -> 'Basis':
318318
@property
319319
def T(self) -> 'Basis':
320320
"""Return the basis transposed element-wise."""
321-
if self.ndim == 3:
322-
return self.transpose(0, 2, 1)
323-
324-
if self.ndim == 2:
325-
return self.transpose(1, 0)
321+
if self.ndim >= 2:
322+
return self.swapaxes(-1, -2)
326323

327324
return self
328325

filter_functions/numeric.py

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,23 +1108,51 @@ def calculate_cumulant_function(
11081108
cumulant_function[..., 1:, 1:] -= frequency_shifts[..., 1:, 1:]
11091109
cumulant_function[..., 1:, 1:] += frequency_shifts[..., 1:, 1:].swapaxes(-1, -2)
11101110
else:
1111-
# Multi qubit case. Use general expression. Drop imaginary part since
1112-
# result is guaranteed to be real (if we didn't do anything wrong)
1111+
# Multi qubit case. Use general expression.
11131112
traces = pulse.basis.four_element_traces
1113+
# g_iklj = (
1114+
# + traces.transpose(0, 1, 2, 3)
1115+
# - traces.transpose(0, 1, 3, 2)
1116+
# - traces.transpose(0, 3, 1, 2)
1117+
# + traces.transpose(0, 3, 2, 1)
1118+
# )
1119+
# g_jikl = (
1120+
# + traces.transpose(3, 0, 1, 2)
1121+
# - traces.transpose(2, 0, 1, 3)
1122+
# - traces.transpose(2, 0, 3, 1)
1123+
# + traces.transpose(1, 0, 3, 2)
1124+
# )
11141125
cumulant_function = - (
11151126
+ oe.contract('...kl,klji->...ij', decay_amplitudes, traces, backend='sparse')
11161127
- oe.contract('...kl,kjli->...ij', decay_amplitudes, traces, backend='sparse')
11171128
- oe.contract('...kl,kilj->...ij', decay_amplitudes, traces, backend='sparse')
11181129
+ oe.contract('...kl,kijl->...ij', decay_amplitudes, traces, backend='sparse')
11191130
) / 2
11201131
if second_order:
1132+
# f_iklj = (
1133+
# + traces.transpose(0, 1, 2, 3)
1134+
# - traces.transpose(0, 2, 1, 3)
1135+
# - traces.transpose(0, 2, 3, 1)
1136+
# + traces.transpose(0, 3, 2, 1)
1137+
# )
1138+
#
1139+
# f_iklj = -g_iljk:
1140+
# f = -g.transpose(0, 2, 3, 1)
1141+
#
1142+
# f_jikl = (
1143+
# + traces.transpose(3, 0, 1, 2)
1144+
# - traces.transpose(3, 0, 2, 1)
1145+
# - traces.transpose(1, 0, 2, 3)
1146+
# + traces.transpose(1, 0, 3, 2)
1147+
# )
11211148
cumulant_function -= (
11221149
+ oe.contract('...kl,klji->...ij', frequency_shifts, traces, backend='sparse')
11231150
- oe.contract('...kl,lkji->...ij', frequency_shifts, traces, backend='sparse')
11241151
- oe.contract('...kl,klij->...ij', frequency_shifts, traces, backend='sparse')
11251152
+ oe.contract('...kl,lkij->...ij', frequency_shifts, traces, backend='sparse')
11261153
) / 2
11271154

1155+
# Drop imaginary part since result is guaranteed to be real (if we didn't do anything wrong)
11281156
return cumulant_function.real
11291157

11301158

@@ -1851,17 +1879,20 @@ def infidelity(
18511879
The ``PulseSequence`` instance for which to calculate the
18521880
infidelity for.
18531881
spectrum: array_like, shape ([[n_nops,] n_nops,] omega) or callable
1854-
The two-sided noise power spectral density in units of inverse
1855-
frequencies as an array of shape (n_omega,), (n_nops, n_omega),
1856-
or (n_nops, n_nops, n_omega). In the first case, the same
1857-
spectrum is taken for all noise operators, in the second, it is
1858-
assumed that there are no correlations between different noise
1859-
sources and thus there is one spectrum for each noise operator.
1882+
The noise power spectral density in units of inverse frequencies
1883+
as an array of shape (n_omega,), (n_nops, n_omega), or
1884+
(n_nops, n_nops, n_omega). In the first case, the same spectrum
1885+
is taken for all noise operators, in the second, it is assumed
1886+
that there are no correlations between different noise sources
1887+
and thus there is one spectrum for each noise operator.
18601888
In the third and most general case, there may be a spectrum for
18611889
each pair of noise operators corresponding to the correlations
18621890
between them. n_nops is the number of noise operators considered
18631891
and should be equal to ``len(n_oper_identifiers)``.
18641892
1893+
See :ref:`Notes <notes>` for a discussion on one- and two-sided
1894+
power spectral densities.
1895+
18651896
If *test_convergence* is ``True``, a function handle to
18661897
compute the power spectral density from a sequence of
18671898
frequencies is expected.
@@ -1946,15 +1977,34 @@ def infidelity(
19461977
infidelities that can be computed by setting
19471978
``which='correlations'``.
19481979
1980+
**One- and two-sided spectral densities**
19491981
1950-
To convert to the average gate infidelity, use the
1951-
following relation given by Horodecki et al. [Hor99]_ and
1952-
Nielsen [Nie02]_:
1982+
Since the real (imaginary) part of filter function :math:`F(\omega)`
1983+
is even (odd), it does not matter for integral whether
1984+
:math:`S(\omega)` is taken to be the one- or two-sided spectral
1985+
density. However, care should be taken that, if it is one or the
1986+
other, the frequencies :math:`\omega` are positive or symmetric
1987+
about zero, respectively.
1988+
1989+
To convert between one- and two-sided PSDs, use the following
1990+
relationship:
1991+
1992+
.. math::
1993+
1994+
S_\mathrm{onesided}(\omega) = 2 S_\mathrm{twosided}(\omega).
1995+
1996+
**Conversion to the Average Gate Infidelity (AGI)**
1997+
1998+
To convert the entanglement infidelity to the average gate
1999+
infidelity, use the following relation given by Horodecki et al.
2000+
[Hor99]_ and Nielsen [Nie02]_:
19532001
19542002
.. math::
19552003
19562004
\mathcal{I}_\mathrm{avg} = \frac{d}{d+1}\mathcal{I}.
19572005
2006+
**Goodness of approximation**
2007+
19582008
The smallness parameter is given by
19592009
19602010
.. math::

tests/test_basis.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,25 @@ def test_basis_properties(self):
156156
self.assertTrue(basis.isorthonorm)
157157
self.assertArrayEqual(basis.T, basis.view(np.ndarray).T)
158158

159+
def test_transpose(self):
160+
arr = rng.normal(size=(2, 3, 3))
161+
b = arr.view(ff.Basis)
162+
self.assertArrayEqual(b.T, arr.transpose(0, 2, 1))
163+
164+
arr = rng.normal(size=(2, 2))
165+
b = arr.view(ff.Basis)
166+
self.assertArrayEqual(b.T, arr.transpose(1, 0))
167+
168+
# Edge cases for not officially intended usage
169+
arr = rng.normal(size=2)
170+
b = arr.view(ff.Basis)
171+
self.assertArrayEqual(b.T, arr)
172+
173+
arr = rng.normal(size=(2, 3, 4, 4))
174+
b = arr.view(ff.Basis)
175+
self.assertArrayEqual(b.T, arr.transpose(0, 1, 3, 2))
176+
177+
159178
def test_basis_expansion_and_normalization(self):
160179
"""Correct expansion of operators and normalization of bases"""
161180
# dtype

0 commit comments

Comments
 (0)