r"""Quantum gates required for Weyl chamber calculations
**Module data:**
.. data:: Qmagic
Transformation matrix to the "magic" Bell basis:
.. math::
\Op{Q} = \frac{1}{\sqrt{2}} \begin{pmatrix}
1 & 0 & 0 & i \\
0 & i & 1 & 0 \\
0 & i & -1 & 0 \\
1 & 0 & 0 & -i
\end{pmatrix}
See "Theorem 1" in Y. Makhlin, Quantum Inf. Process. 1, 243 (2002)
.. data:: SxSx
:math:`\Op{\sigma}_x \otimes \Op{\sigma}_x` gate
.. data:: SySy
:math:`\Op{\sigma}_y \otimes \Op{\sigma}_y` gate
.. data:: SzSz
:math:`\Op{\sigma}_z \otimes \Op{\sigma}_z` gate
"""
import qutip
import numpy as np
__all__ = [
'Qmagic',
'SxSx',
'SySy',
'SzSz',
'bell_basis',
'gate',
'mapped_basis',
]
Qmagic = (1.0 / np.sqrt(2.0)) * qutip.Qobj(
np.array(
[[1, 0, 0, 1j], [0, 1j, 1, 0], [0, 1j, -1, 0], [1, 0, 0, -1j]],
dtype=np.complex128,
),
dims=[[2, 2], [2, 2]],
)
SxSx = qutip.Qobj(
np.array(
[[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]],
dtype=np.complex128,
),
dims=[[2, 2], [2, 2]],
)
SySy = qutip.Qobj(
np.array(
[[+0, 0, 0, -1], [+0, 0, 1, 0], [+0, 1, 0, 0], [-1, 0, 0, 0]],
dtype=np.complex128,
),
dims=[[2, 2], [2, 2]],
)
SzSz = qutip.Qobj(
np.array(
[[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]],
dtype=np.complex128,
),
dims=[[2, 2], [2, 2]],
)
[docs]def bell_basis(canonical_basis):
"""Two-qubit Bell basis associated with the given canonical basis
Example:
>>> from qutip import ket
>>> canonical_basis = [
... ket(nums) for nums in [(0, 0), (0, 1), (1, 0), (1, 1)]
... ]
>>> bell = bell_basis(canonical_basis)
>>> _bell = [
... ( ket((0, 0)) + ket((1, 1))) / np.sqrt(2),
... (1j * ket((0, 1)) + 1j * ket((1, 0))) / np.sqrt(2),
... ( ket((0, 1)) - ket((1, 0))) / np.sqrt(2),
... (1j * ket((0, 0)) - 1j * ket((1, 1))) / np.sqrt(2),
... ]
>>> assert (bell[0] - _bell[0]).norm() < 1e-15
>>> assert (bell[1] - _bell[1]).norm() < 1e-15
>>> for (a, b) in zip(bell, _bell):
... assert (a - b).norm() < 1e-15, (a - b).norm()
"""
return mapped_basis(Qmagic, canonical_basis)
[docs]def gate(basis, states):
"""Two-qubit gate that maps `basis` to `states`
Example:
>>> from qutip import ket
>>> basis = [ket(nums) for nums in [(0, 0), (0, 1), (1, 0), (1, 1)]]
>>> states = mapped_basis(qutip.qip.operations.cnot(), basis)
>>> U = gate(basis, states)
>>> assert (U - qutip.qip.operations.cnot()).norm() < 1e-15
"""
if not (len(basis) == len(states) == 4):
raise ValueError(
"Both `basis` and `states` must be a list of four states"
)
U = np.zeros((4, 4), dtype=np.complex128)
for j in range(4):
for i in range(4):
U[i, j] = basis[i].overlap(states[j])
return qutip.Qobj(U, dims=[[2, 2], [2, 2]])
[docs]def mapped_basis(gate, basis):
"""Result of applying `gate` to `basis`
Example:
>>> from qutip import ket
>>> basis = [ket(nums) for nums in [(0, 0), (0, 1), (1, 0), (1, 1)]]
>>> states = mapped_basis(qutip.qip.operations.cnot(), basis)
>>> assert (states[0] - ket((0,0))).norm() < 1e-15
>>> assert (states[1] - ket((0,1))).norm() < 1e-15
>>> assert (states[2] - ket((1,1))).norm() < 1e-15 # swap (1, 1) ...
>>> assert (states[3] - ket((1,0))).norm() < 1e-15 # ... and (1, 0)
"""
return tuple(
[
sum([complex(gate[i, j]) * basis[i] for i in range(gate.shape[0])])
for j in range(gate.shape[1])
]
)