##############################################################################
# Copyright 2016-2019 Rigetti Computing
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##############################################################################
r"""
Standard gate set, as detailed in Quil whitepaper (arXiV:1608:03355v2)
Currently includes:
I - identity :math:`\begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}`
X - Pauli-X :math:`\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}`
Y - Pauli-Y :math:`\begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix}`
Z - Pauli-Z :math:`\begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}`
H - Hadamard
:math:`\frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}`
S - PHASE(pi/2)
:math:`\begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix}`
T - PHASE(pi/4)
:math:`\begin{pmatrix} 1 & 0 \\ 0 & e^{i \pi / 4} \end{pmatrix}`
PHASE(:math:`\phi`) - PHASE
:math:`\begin{pmatrix} 1 & 0 \\ 0 & e^{i \phi} \end{pmatrix}`
RX(:math:`\phi`) - RX
:math:`\begin{pmatrix} \cos(\phi / 2) & -i \sin(\phi/2) \\ -i \sin(\phi/2) & \cos(\phi/2) \end{pmatrix}`
RY(:math:`\phi`) - RY
:math:`\begin{pmatrix} \cos(\phi / 2) & -\sin(\phi / 2) \\ \sin(\phi/2) & \cos(\phi/2) \end{pmatrix}`
RZ(:math:`\phi`) - RZ
:math:`\begin{pmatrix} \cos(\phi/2) - i \sin(\phi/2) & 0 \\ 0 & \cos(\phi/2) + i \sin(\phi/2) \end{pmatrix}`
U(:math:`\theta, \phi, \lambda`) - U3
:math:`\begin{pmatrix} \cos(\theta/2) & - \exp{i\lambda} \sin(\theta/2) \\ \exp{i\phi} \sin(\theta/2) & \exp{i\phi + \lambda} \cos(\theta/2) \end{pmatrix}`
CZ - controlled-Z
:math:`P_0 \otimes I + P_1 \otimes Z = \begin{pmatrix} 1&0&0&0 \\ 0&1&0&0 \\ 0&0&1&0 \\ 0&0&0&-1 \end{pmatrix}`
CNOT - controlled-X / controlled-NOT
:math:`P_0 \otimes I + P_1 \otimes X = \begin{pmatrix} 1&0&0&0 \\ 0&1&0&0 \\ 0&0&0&1 \\ 0&0&1&0 \end{pmatrix}`
CCNOT - double-controlled-X
:math:`P_0 \otimes P_0 \otimes I + P_0 \otimes P_1 \otimes I + P_1 \otimes P_0 \otimes I + P_1 \otimes P_1 \otimes X`
CPHASE00(:math:`\phi`) - controlled-phase-on-\|00\>
:math:`\text{diag}(e^{i \phi}, 1, 1, 1,)`
CPHASE01(:math:`\phi`) - controlled-phase-on-\|01\>
:math:`\text{diag}(1, e^{i \phi}, 1, 1,)`
CPHASE10(:math:`\phi`) - controlled-phase-on-\|10\>
:math:`\text{diag}(1, 1, e^{i \phi}, 1)`
CPHASE(:math:`\phi`) - controlled-phase-on-\|11\>
:math:`\text{diag}(1, 1, 1, e^{i \phi})`
SWAP - swap
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&0&1&0 \\ 0&1&0&0 \\ 0&0&0&1 \end{pmatrix}`
CSWAP - controlled-swap
:math:`P_0 \otimes I_2 + P_1 \otimes \text{SWAP}`
ISWAP - i-phase-swap
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&0&i&0 \\ 0&i&0&0 \\ 0&0&0&1 \end{pmatrix}`
PSWAP(:math:`\phi`) - phi-phase-swap
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&0&e^{i\phi}&0 \\ 0&e^{i\phi}&0&0 \\ 0&0&0&1 \end{pmatrix}`
XY(:math:`\phi`) - XY-interaction
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&\cos(\phi/2)&i\sin(\phi/2)&0 \\ 0&i\sin(\phi/2)&\cos(\phi/2)&0 \\ 0&0&0&1 \end{pmatrix}`
SQISW - XY(:math: `\pi/2`)-interaction
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&\frac{1}{\sqrt{2}}&\frac{i}{\sqrt{2}}&0 \\ \frac{i}{\sqrt{2}}&\frac{1}{\sqrt{2}} \\ 0&0&0&1 \end{pmatrix}`
FSIM(:math:`\theta, \phi`) - XX+YY interaction with conditonal phase on \|11\>
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&\cos(\frac{\theta}{2})&i\sin(\frac{\theta}{2})&0 \\ 0&i\sin(\frac{\theta}{2})&\cos(\frac{\theta}{2})&0 \\ 0&0&0&e^{i \phi} \end{pmatrix}`
PHASEDFSIM(:math:`\theta, \zeta, \chi, \gamma, \phi`) - XX+YY interaction with conditonal phase on \|11\>
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&\ e^{-i(\gamma+\zeta)}\cos(\frac{\theta}{2})&ie^{-i(\gamma-\chi)}\sin(\frac{\theta}{2})&0 \\ 0&ie^{-i(\gamma+\chi)}\sin(\frac{\theta}{2})&e^{-i(\gamma-\zeta)}\cos(\frac{\theta}{2})&0 \\ 0&0&0&e^{ i\phi - 2i\gamma} \end{pmatrix}`
RXX(:math:`\phi`) - XX-interaction
:math:`\begin{pmatrix} \cos(\phi/2)&0&0&-i\sin(\phi/2) \\ 0&\cos(\phi/2)&-i\sin(\phi/2)&0 \\ 0&-i\sin(\phi/2)&\cos(\phi/2)&0 \\ -i\sin(\phi/2)&0&0&cos(\phi/2) \end{pmatrix}`
RYY(:math:`\phi`) - YY-interaction
:math:`\begin{pmatrix} \cos(\phi/2)&0&0&i\sin(\phi/2) \\ 0&\cos(\phi/2)&-i\sin(\phi/2)&0 \\ 0&-i\sin(\phi/2)&\cos(\phi/2)&0 \\ i\sin(\phi/2)&0&0&cos(\phi/2) \end{pmatrix}`
RZZ(:math:`\phi`) - ZZ-interaction
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&\cos(\phi/2)&-i\sin(\phi/2)&0 \\ 0&-i\sin(\phi/2)&\cos(\phi/2)&0 \\ 0&0&0&1 \end{pmatrix}`
Specialized gates / internal utility gates:
BARENCO(:math:`\alpha, \phi, \theta`) - Barenco gate
:math:`\begin{pmatrix} 1&0&0&0 \\ 0&1&0&0 \\ 0&0&e^{i\phi} \cos\theta & -i e^{i(\alpha-\phi)} \sin\theta \\ 0&0&-i e^{i(\alpha+\phi)} \sin\theta & e^{i\alpha} \cos\theta \end{pmatrix}`
P0 - project-onto-zero
:math:`\begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix}`
P1 - project-onto-one
:math:`\begin{pmatrix} 0 & 0 \\ 0 & 1 \end{pmatrix}`
""" # noqa: E501
import cmath
from typing import Tuple
import numpy as np
I = np.array([[1.0, 0.0], [0.0, 1.0]])
X = np.array([[0.0, 1.0], [1.0, 0.0]])
Y = np.array([[0.0, 0.0 - 1.0j], [0.0 + 1.0j, 0.0]])
Z = np.array([[1.0, 0.0], [0.0, -1.0]])
H = (1.0 / np.sqrt(2.0)) * np.array([[1.0, 1.0], [1.0, -1.0]])
S = np.array([[1.0, 0.0], [0.0, 1.0j]])
T = np.array([[1.0, 0.0], [0.0, cmath.exp(1.0j * np.pi / 4.0)]])
[docs]def PHASE(phi: float) -> np.ndarray:
return np.array([[1.0, 0.0], [0.0, np.exp(1j * phi)]])
[docs]def RX(phi: float) -> np.ndarray:
return np.array([[np.cos(phi / 2.0), -1j * np.sin(phi / 2.0)], [-1j * np.sin(phi / 2.0), np.cos(phi / 2.0)]])
[docs]def RY(phi: float) -> np.ndarray:
return np.array([[np.cos(phi / 2.0), -np.sin(phi / 2.0)], [np.sin(phi / 2.0), np.cos(phi / 2.0)]])
[docs]def RZ(phi: float) -> np.ndarray:
return np.array(
[
[np.cos(phi / 2.0) - 1j * np.sin(phi / 2.0), 0],
[0, np.cos(phi / 2.0) + 1j * np.sin(phi / 2.0)],
]
)
[docs]def U(theta: float, phi: float, lam: float) -> np.ndarray:
return np.array(
[
[np.cos(theta / 2.0), -1 * np.exp(1j * lam) * np.sin(theta / 2.0)],
[np.exp(1j * phi) * np.sin(theta / 2.0), np.exp(1j * (phi + lam)) * np.cos(theta / 2.0)],
]
)
CZ = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]])
CNOT = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
CCNOT = np.array(
[
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0],
]
)
[docs]def CPHASE00(phi: float) -> np.ndarray:
return np.diag([np.exp(1j * phi), 1.0, 1.0, 1.0])
[docs]def CPHASE01(phi: float) -> np.ndarray:
return np.diag([1.0, np.exp(1j * phi), 1.0, 1.0])
[docs]def CPHASE10(phi: float) -> np.ndarray:
return np.diag([1.0, 1.0, np.exp(1j * phi), 1.0])
[docs]def CPHASE(phi: float) -> np.ndarray:
return np.diag([1.0, 1.0, 1.0, np.exp(1j * phi)])
SWAP = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])
CSWAP = np.array(
[
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
]
)
ISWAP = np.array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]])
[docs]def PSWAP(phi: float) -> np.ndarray:
return np.array([[1, 0, 0, 0], [0, 0, np.exp(1j * phi), 0], [0, np.exp(1j * phi), 0, 0], [0, 0, 0, 1]])
[docs]def XY(phi: float) -> np.ndarray:
return np.array(
[
[1, 0, 0, 0],
[0, np.cos(phi / 2), 1j * np.sin(phi / 2), 0],
[0, 1j * np.sin(phi / 2), np.cos(phi / 2), 0],
[0, 0, 0, 1],
]
)
[docs]def FSIM(theta: float, phi: float) -> np.ndarray:
return np.array(
[
[1, 0, 0, 0],
[0, np.cos(theta / 2), 1j * np.sin(theta / 2), 0],
[0, 1j * np.sin(theta / 2), np.cos(theta / 2), 0],
[0, 0, 0, np.exp(1j * phi)],
]
)
[docs]def PHASEDFSIM(theta: float, zeta: float, chi: float, gamma: float, phi: float) -> np.ndarray:
return np.array(
[
[1, 0, 0, 0],
[
0,
np.exp(-1j * (gamma + zeta)) * np.cos(theta / 2),
1j * np.exp(-1j * (gamma - chi)) * np.sin(theta / 2),
0,
],
[
0,
1j * np.exp(-1j * (gamma + chi)) * np.sin(theta / 2),
np.exp(-1j * (gamma - zeta)) * np.cos(theta / 2),
0,
],
[0, 0, 0, np.exp(1j * phi - 2j * gamma)],
]
)
[docs]def RZZ(phi: float) -> np.ndarray:
return np.array(
[
[np.exp(-1j * phi / 2), 0, 0, 0],
[0, np.exp(+1j * phi / 2), 0, 0],
[0, 0, np.exp(+1j * phi / 2), 0],
[0, 0, 0, np.exp(-1j * phi / 2)],
]
)
[docs]def RXX(phi: float) -> np.ndarray:
return np.array(
[
[np.cos(phi / 2), 0, 0, -1j * np.sin(phi / 2)],
[0, np.cos(phi / 2), -1j * np.sin(phi / 2), 0],
[0, -1j * np.sin(phi / 2), np.cos(phi / 2), 0],
[-1j * np.sin(phi / 2), 0, 0, np.cos(phi / 2)],
]
)
[docs]def RYY(phi: float) -> np.ndarray:
return np.array(
[
[np.cos(phi / 2), 0, 0, +1j * np.sin(phi / 2)],
[0, np.cos(phi / 2), -1j * np.sin(phi / 2), 0],
[0, -1j * np.sin(phi / 2), np.cos(phi / 2), 0],
[+1j * np.sin(phi / 2), 0, 0, np.cos(phi / 2)],
]
)
SQISW = np.array(
[
[1, 0, 0, 0],
[0, 1 / np.sqrt(2), 1j / np.sqrt(2), 0],
[0, 1j / np.sqrt(2), 1 / np.sqrt(2), 0],
[0, 0, 0, 1],
]
)
# Utility gates for internal QVM use
P0 = np.array([[1, 0], [0, 0]])
P1 = np.array([[0, 0], [0, 1]])
# Specialized useful gates; not officially in standard gate set
[docs]def BARENCO(alpha: float, phi: float, theta: float) -> np.ndarray:
lower_unitary = np.array(
[
[np.exp(1j * phi) * np.cos(theta), -1j * np.exp(1j * (alpha - phi)) * np.sin(theta)],
[-1j * np.exp(1j * (alpha + phi)) * np.sin(theta), np.exp(1j * alpha) * np.cos(theta)],
]
)
return np.kron(P0, np.eye(2)) + np.kron(P1, lower_unitary)
QUANTUM_GATES = {
"RZ": RZ,
"RX": RX,
"RY": RY,
"CZ": CZ,
"XY": XY,
"CPHASE": CPHASE,
"I": I,
"X": X,
"Y": Y,
"Z": Z,
"H": H,
"S": S,
"T": T,
"PHASE": PHASE,
"CNOT": CNOT,
"CCNOT": CCNOT,
"CPHASE00": CPHASE00,
"CPHASE01": CPHASE01,
"CPHASE10": CPHASE10,
"SWAP": SWAP,
"CSWAP": CSWAP,
"ISWAP": ISWAP,
"PSWAP": PSWAP,
"BARENCO": BARENCO,
"FSIM": FSIM,
"PHASEDFSIM": PHASEDFSIM,
"RXX": RXX,
"RYY": RYY,
"RZZ": RZZ,
"U": U,
}
[docs]def relaxation_operators(p: float) -> Tuple[np.ndarray, np.ndarray]:
"""
Return the amplitude damping Kraus operators
"""
k0 = np.array([[1.0, 0.0], [0.0, np.sqrt(1 - p)]])
k1 = np.array([[0.0, np.sqrt(p)], [0.0, 0.0]])
return k0, k1
[docs]def dephasing_operators(p: float) -> Tuple[np.ndarray, np.ndarray]:
"""
Return the phase damping Kraus operators
"""
k0 = np.eye(2) * np.sqrt(1 - p / 2)
k1 = np.sqrt(p / 2) * Z
return k0, k1
[docs]def depolarizing_operators(p: float) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
Return the phase damping Kraus operators
"""
k0 = np.sqrt(1.0 - p) * I
k1 = np.sqrt(p / 3.0) * X
k2 = np.sqrt(p / 3.0) * Y
k3 = np.sqrt(p / 3.0) * Z
return k0, k1, k2, k3
[docs]def phase_flip_operators(p: float) -> Tuple[np.ndarray, np.ndarray]:
"""
Return the phase flip kraus operators
"""
k0 = np.sqrt(1 - p) * I
k1 = np.sqrt(p) * Z
return k0, k1
[docs]def bit_flip_operators(p: float) -> Tuple[np.ndarray, np.ndarray]:
"""
Return the phase flip kraus operators
"""
k0 = np.sqrt(1 - p) * I
k1 = np.sqrt(p) * X
return k0, k1
[docs]def bitphase_flip_operators(p: float) -> Tuple[np.ndarray, np.ndarray]:
"""
Return the bitphase flip kraus operators
"""
k0 = np.sqrt(1 - p) * I
k1 = np.sqrt(p) * Y
return k0, k1
KRAUS_OPS = {
"relaxation": relaxation_operators,
"dephasing": dephasing_operators,
"depolarizing": depolarizing_operators,
"phase_flip": phase_flip_operators,
"bit_flip": bit_flip_operators,
"bitphase_flip": bitphase_flip_operators,
}
SIC0 = np.array([1, 0])
SIC1 = np.array([1, np.sqrt(2)]) / np.sqrt(3)
SIC2 = np.array([1, np.exp(-np.pi * 2j / 3) * np.sqrt(2)]) / np.sqrt(3)
SIC3 = np.array([1, np.exp(np.pi * 2j / 3) * np.sqrt(2)]) / np.sqrt(3)
"""
The symmetric informationally complete POVMs for a qubit.
These can reduce the number of experiments to perform quantum process tomography.
For more information, please see http://info.phys.unm.edu/~caves/reports/infopovm.pdf
"""
STATES = {
"X": [np.array([1, 1]) / np.sqrt(2), np.array([1, -1]) / np.sqrt(2)],
"Y": [np.array([1, 1j]) / np.sqrt(2), np.array([1, -1j]) / np.sqrt(2)],
"Z": [np.array([1, 0]), np.array([0, 1])],
"SIC": [SIC0, SIC1, SIC2, SIC3],
}
__all__ = list(QUANTUM_GATES.keys()) + [
"relaxation_operators",
"dephasing_operators",
"depolarizing_operators",
"phase_flip_operators",
"bit_flip_operators",
"bitphase_flip_operators",
"STATES",
"SIC0",
"SIC1",
"SIC2",
"SIC3",
]