"""Python classes for Quest functions"""
# Copyright 2019 HQS Quantum Simulations GmbH
#
# 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.
from pyquest_cffi.questlib import (
quest, _PYQUEST, ffi_quest, qreal, tqureg, tquestenv, paulihamil
)
import numpy as np
from typing import Sequence, Optional, Tuple
from pyquest_cffi import cheat
[docs]class hadamard(_PYQUEST):
r"""Implements Hadamard gate
.. math::
U = \frac{1}{\sqrt{2}} \begin{pmatrix}
1 & 1\\
1 & -1
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
quest.hadamard(qureg, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = 1 / np.sqrt(2) * np.array([[1, 1], [1, -1]], dtype=complex)
return matrix
[docs]class pauliX(_PYQUEST):
r"""Implements Pauli X gate
.. math::
U = \begin{pmatrix}
0 & 1\\
1 & 0
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
quest.pauliX(qureg, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[0, 1], [1, 0]], dtype=complex)
return matrix
[docs]class pauliY(_PYQUEST):
r"""Implements Pauli Y gate
.. math::
U = \begin{pmatrix}
0 & -i\\
i & 0
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
quest.pauliY(qureg, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[0, -1j], [1j, 0]], dtype=complex)
return matrix
[docs]class pauliZ(_PYQUEST):
r"""Implements Pauli Z gate
.. math::
U = \begin{pmatrix}
1 & 0\\
0 & -1
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
quest.pauliZ(qureg, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0], [0, -1]], dtype=complex)
return matrix
[docs]class sGate(_PYQUEST):
r"""Implements S gate
.. math::
U = \begin{pmatrix}
1 & 0\\
0 & i
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
quest.sGate(qureg, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0], [0, 1j]], dtype=complex)
return matrix
[docs]class tGate(_PYQUEST):
r"""Implements T gate
.. math::
U = \begin{pmatrix}
1 & 0\\
0 & e^{i \frac{\pi}{4}}
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
"""
quest.tGate(qureg, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0], [0, np.exp(1j * np.pi / 4)]], dtype=complex)
return matrix
[docs]class compactUnitary(_PYQUEST):
r"""Implements general unitary gate U in compact notation
.. math::
U = \begin{pmatrix}
\alpha & -\beta^{*}\\
\beta & \alpha^{*}
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
alpha: complex parameter :math:`\alpha` of the unitary matrix
beta: complex parameter :math:`\beta` of the unitary matrix
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, alpha: complex, beta: complex) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
alpha: complex parameter :math:`\alpha` of the unitary matrix
beta: complex parameter :math:`\beta` of the unitary matrix
Raises:
RuntimeError: compactUnitary needs parameters |alpha|**2+|beta|**2 == 1
"""
if not np.isclose(np.abs(alpha)**2 + np.abs(beta)**2, 1):
raise RuntimeError("compactUnitary needs parameters |alpha|**2+|beta|**2 == 1")
else:
calpha = ffi_quest.new("Complex *")
calpha.real = np.real(alpha)
calpha.imag = np.imag(alpha)
cbeta = ffi_quest.new("Complex *")
cbeta.real = np.real(beta)
cbeta.imag = np.imag(beta)
quest.compactUnitary(qureg, qubit, calpha[0], cbeta[0])
[docs] def matrix(self, alpha: complex, beta: complex, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
alpha: complex parameter :math:`\alpha` of the unitary matrix
beta: complex parameter :math:`\beta` of the unitary matrix
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[alpha, -np.conj(beta)], [beta, np.conj(alpha)]], dtype=complex)
return matrix
[docs]class phaseShift(_PYQUEST):
r"""Implements pure :math:`\left|1 \right\rangle` phase shift gate
.. math::
U = \begin{pmatrix}
1 & 0\\
0 & e^{i \theta}
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the ro
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the ro
"""
if not (0 <= theta and theta <= 2 * np.pi):
theta = np.mod(theta, 2 * np.pi)
quest.phaseShift(qureg, qubit, theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
theta: Angle theta of the ro
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0], [0, np.exp(1j * theta)]], dtype=complex)
return matrix
[docs]class rotateAroundAxis(_PYQUEST):
r"""Implements rotation around arbitraty axis on Bloch sphere
.. math::
U = \begin{pmatrix}
\cos(\frac{\theta}{2}) & 0\\
0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
-i \sin(\frac{\theta}{2}) v_z & \sin(\frac{\theta}{2}) \left(-i v_x - v_y \right) \\
\sin(\frac{\theta}{2}) \left(-i v_x + v_y \right) & i \sin(\frac{\theta}{2}) v_z)
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
vector: Direction of the rotation axis, unit-vector
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, theta: float, vector: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
vector: Direction of the rotation axis, unit-vector
Raises:
RuntimeError: vector needs to be a three component numpy array and unit-vector
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
if not (vector.shape == (3,) and np.isclose(np.linalg.norm(vector), 1)):
raise RuntimeError("vector needs to be a three component numpy array and unit-vector")
else:
vec = ffi_quest.new("Vector *")
vec.x = vector[0]
vec.y = vector[1]
vec.z = vector[2]
quest.rotateAroundAxis(qureg,
qubit,
theta,
vec[0])
[docs] def matrix(self, theta: float, vector: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
theta: Angle theta of the rotation
vector: Direction of the rotation axis, unit-vector
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
vx = vector[0]
vy = vector[1]
vz = vector[2]
matrix = np.array([[c - 1j * s * vz, s * (-1j * vx - vy)],
[s * (-1j * vx + vy), c + 1j * s * vz]], dtype=complex)
return matrix
[docs]class rotateAroundSphericalAxis(_PYQUEST):
r"""Implements rotation around an axis given in spherical coordinates
.. math::
U &= \begin{pmatrix}
\cos(\frac{\theta}{2}) & 0\\
0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
-i \sin(\frac{\theta}{2}) v_z & \sin(\frac{\theta}{2}) \left(-i v_x - v_y \right) \\
\sin(\frac{\theta}{2}) \left(-i v_x + v_y \right) & i \sin(\frac{\theta}{2}) v_z)
\end{pmatrix}\\
v_x &= \sin(\theta_{sph}) \cos(\phi_{sph})\\
v_y &= \sin(\theta_{sph}) \sin(\phi_{sph})\\
v_z &= \cos(\theta_{sph})
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
spherical_theta: Rotation axis, unit-vector spherical coordinates theta
spherical_phi: Rotation axis, unit-vector spherical coordinates phi
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, theta: float,
spherical_theta: float, spherical_phi: float,) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
spherical_theta: Rotation axis, unit-vector spherical coordinates theta
spherical_phi: Rotation axis, unit-vector spherical coordinates phi
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
vec = ffi_quest.new("Vector *")
vec.x = np.sin(spherical_theta) * np.cos(spherical_phi)
vec.y = np.sin(spherical_theta) * np.sin(spherical_phi)
vec.z = np.cos(spherical_theta)
quest.rotateAroundAxis(qureg,
qubit,
theta,
vec[0])
[docs] def matrix(self, theta: float, vector: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
theta: Angle theta of the rotation
vector: Direction of the rotation axis, unit-vector
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
vx = vector[0]
vy = vector[1]
vz = vector[2]
matrix = np.array([[c - 1j * s * vz, s * (-1j * vx - vy)],
[s * (-1j * vx + vy), c + 1j * s * vz]], dtype=complex)
return matrix
[docs]class rotateX(_PYQUEST):
r"""Implements :math:`e^{-i \frac{\theta}{2} \sigma^x}` XPower gate
.. math::
U = \begin{pmatrix}
\cos(\frac{\theta}{2}) & 0\\
0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
0 & -i \sin(\frac{\theta}{2}) \\
-i \sin(\frac{\theta}{2}) & 0
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
quest.rotateX(qureg,
qubit,
theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
matrix = np.array([[c, -1j * s], [-1j * s, c]], dtype=complex)
return matrix
[docs]class rotateY(_PYQUEST):
r"""Implements :math:`e^{-i \frac{\theta}{2} \sigma^y}` XPower gate
.. math::
U = \begin{pmatrix}
\cos(\frac{\theta}{2}) & 0\\
0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
0 & - \sin(\frac{\theta}{2}) \\
\sin(\frac{\theta}{2}) & 0
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
quest.rotateY(qureg,
qubit,
theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
matrix = np.array([[c, -s], [s, c]], dtype=complex)
return matrix
[docs]class rotateZ(_PYQUEST):
r"""Implements :math:`e^{-i \frac{\theta}{2} \sigma^z}` XPower gate
.. math::
U = \begin{pmatrix}
\cos(\frac{\theta}{2}) & 0\\
0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
- i \sin(\frac{\theta}{2}) & 0 \\
0 & i \sin(\frac{\theta}{2})
\end{pmatrix}
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
quest.rotateZ(qureg,
qubit,
theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
theta: Angle theta of the rotation, in interval 0 to 2 :math:`2 \pi`
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
matrix = np.array([[c - 1j * s, 0], [0, c + 1j * s]], dtype=complex)
return matrix
[docs]class unitary(_PYQUEST):
r"""Implements an arbitraty one-qubit gate given by a unitary matrix
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
matrix: Unitary matrix of the one qubit gate
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
matrix: Unitary matrix of the one qubit gate
Raises:
RuntimeError: matrix needs to be a (2, 2) unitary numpy array
"""
if not (matrix.shape == (2, 2) and np.all(np.isclose(matrix.conj().T @ matrix, np.eye(2)))):
raise RuntimeError("matrix needs to be a (2, 2) unitary numpy array")
else:
mat = ffi_quest.new("ComplexMatrix2 *")
for i in range(2):
for j in range(2):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.unitary(qureg,
qubit,
mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: Unitary matrix of the one qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
return matrix
# Controlled and other Two-Qubit Operations
[docs]class twoQubitUnitary(_PYQUEST):
r"""General two qubit unitary gate
Implements a general two-qubit gate defined by a matrix
If the matrix basis states are given by 0=|00> 1=|01> 2=|10> 3=|11>
the least significant qubit is the right qubit and the most
significant qubit is the left qubit
Args:
qureg: quantum register
target_qubit_1: least significant qubit
target_qubit_2: most sifnificant qubit
matrix: 4 by 4 matrix that defines the two qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg,
target_qubit_1: int,
target_qubit_2: int,
matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
target_qubit_1: least significant qubit
target_qubit_2: most sifnificant qubit
matrix: 4 by 4 matrix that defines the two qubit gate
"""
mat = ffi_quest.new("ComplexMatrix4 *")
for i in range(4):
for j in range(4):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.twoQubitUnitary(qureg,
target_qubit_1,
target_qubit_2,
mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
return matrix
[docs]class controlledTwoQubitUnitary(_PYQUEST):
r"""Controlled two qubit unitary gate
Implements a general two-qubit gate defined by a matrix controlled by a third qubit
If the matrix basis states are given by 0=|00> 1=|01> 2=|10> 3=|11>
the least significant qubit is the right qubit and the most
significant qubit is the left qubit
Args:
qureg: quantum register
control: controll qubit
target_qubit_1: least significant qubit
target_qubit_2: most sifnificant qubit
matrix: 4 by 4 matrix that defines the two qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg, control: int,
target_qubit_1: int,
target_qubit_2: int,
matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: controll qubit
target_qubit_1: least significant qubit
target_qubit_2: most sifnificant qubit
matrix: 4 by 4 matrix that defines the two qubit gate
"""
mat = ffi_quest.new("ComplexMatrix4 *")
for i in range(4):
for j in range(4):
mat[0].real[i][j] = np.real(matrix[i, j])
mat[0].imag[i][j] = np.imag(matrix[i, j])
quest.controlledTwoQubitUnitary(qureg,
control,
target_qubit_1,
target_qubit_2,
mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|xy> |1xy> -> |1> U |xy>
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
dim = matrix.shape[0]
return np.block([[np.eye(dim), np.zeros((dim, dim))],
[np.zeros((dim, dim)), matrix]])
[docs]class controlledCompactUnitary(_PYQUEST):
r"""Implements a controlled general unitary gate U in compact notation
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & \alpha & -\beta^{*}\\
0 & 0 & \beta & \alpha^{*}
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
alpha: complex parameter :math:`\alpha` of the unitary matrix
beta: complex parameter :math:`\beta` of the unitary matrix
"""
[docs] def call_interactive(self,
qureg: tqureg,
control: int,
qubit: int,
alpha: complex,
beta: complex) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
alpha: complex parameter :math:`\alpha` of the unitary matrix
beta: complex parameter :math:`\beta` of the unitary matrix
Raises:
RuntimeError: compactUnitary needs parameters |alpha|**2+|beta|**2 == 1
"""
if not np.isclose(np.abs(alpha)**2 + np.abs(beta)**2, 1):
raise RuntimeError("compactUnitary needs parameters |alpha|**2+|beta|**2 == 1")
else:
calpha = ffi_quest.new("Complex *")
calpha.real = np.real(alpha)
calpha.imag = np.imag(alpha)
cbeta = ffi_quest.new("Complex *")
cbeta.real = np.real(beta)
cbeta.imag = np.imag(beta)
quest.controlledCompactUnitary(qureg, control, qubit, calpha[0], cbeta[0])
[docs] def matrix(self, alpha: complex, beta: complex, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
alpha: complex parameter :math:`\alpha` of the unitary matrix
beta: complex parameter :math:`\beta` of the unitary matrix
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, alpha, -np.conj(beta)],
[0, 0, beta, np.conj(alpha)]], dtype=complex)
return matrix
[docs]class controlledNot(_PYQUEST):
r"""Implements a controlled NOT gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 0 & 1\\
0 & 0 & 1 & 0
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
quest.controlledNot(qureg, control, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0x> -> |0>|x> |1x> -> |1> NOT |x>
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0]], dtype=complex)
return matrix
[docs]class controlledPauliY(_PYQUEST):
r"""Implements a controlled PauliY gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 0 & -i\\
0 & 0 & i & 0
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
quest.controlledPauliY(qureg, control, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, -1j],
[0, 0, 1j, 0]], dtype=complex)
return matrix
[docs]class controlledPhaseFlip(_PYQUEST):
r"""Implements a controlled phase flip gate also known as controlled Z gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 0 & 0 & -1
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
quest.controlledPhaseFlip(qureg, control, qubit)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, -1]], dtype=complex)
return matrix
[docs]class swapGate(_PYQUEST):
r"""Implements a SWAP gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 0 & 1
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
quest.swapGate(qureg,
control,
qubit,
)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, 0, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 1]], dtype=complex)
return matrix
[docs]class sqrtSwapGate(_PYQUEST):
r"""Implements a square root SWAP gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & \frac{1}{2}(1+i) & \frac{1}{2}(1-i) & 0\\
0 & \frac{1}{2}(1-i) & \frac{1}{2}(1+i) & 0\\
0 & 0 & 0 & 1
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
quest.sqrtSwapGate(qureg,
control,
qubit,
)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, (1 + 1j) / 2, (1 - 1j) / 2, 0],
[0, (1 - 1j) / 2, (1 + 1j) / 2, 0],
[0, 0, 0, 1]], dtype=complex)
return matrix
[docs]class sqrtISwap(_PYQUEST):
r"""Implements a square root ISwap gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & \frac{1}{\sqrt{2}} & \frac{i}{\sqrt{2}} & 0\\
0 & \frac{i}{\sqrt{2}} & \frac{1}{\sqrt{2}} & 0\\
0 & 0 & 0 & 1
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
matrix = self.matrix()
mat = ffi_quest.new("ComplexMatrix4 *")
for i in range(4):
for j in range(4):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.twoQubitUnitary(qureg,
control,
qubit,
mat[0])
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = 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]], dtype=complex)
return matrix
[docs]class invSqrtISwap(_PYQUEST):
r"""Implements inverse square root ISwap gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & \frac{1}{\sqrt{2}} & \frac{-i}{\sqrt{2}} & 0\\
0 & \frac{-i}{\sqrt{2}} & \frac{1}{\sqrt{2}} & 0\\
0 & 0 & 0 & 1
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
matrix = self.matrix()
mat = ffi_quest.new("ComplexMatrix4 *")
for i in range(4):
for j in range(4):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.twoQubitUnitary(qureg,
control,
qubit,
mat[0])
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = 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]], dtype=complex)
return matrix
[docs]class controlledPhaseShift(_PYQUEST):
r"""Implements a controlled phase flip shift also known as controlled Z power gate
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 0 & 0 & e^{i\theta}
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: The angle of the controlled Z-rotation
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: The angle of the controlled Z-rotation
"""
if not (0 <= theta and theta <= 2 * np.pi):
theta = np.mod(theta, 2 * np.pi)
quest.controlledPhaseShift(qureg, control, qubit, theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
theta: The angle of the controlled Z-rotation
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, np.exp(1j * theta)]], dtype=complex)
return matrix
[docs]class controlledRotateAroundAxis(_PYQUEST):
r"""Rotation around a general axis.
Implements a controlled rotation around a vector :math:`\vec{v}`
:math:`e^{-i \frac{\theta}{2} \vec{v} \vec{\sigma}}`
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & \cos(\frac{\theta}{2}) & 0\\
0 & 0 & 0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
0 & 0 & 0 & 0\\
0 & 0 & 0 & 0\\
0 & 0 & -i \sin(\frac{\theta}{2}) v_z & \sin(\frac{\theta}{2}) \left(-i v_x - v_y \right)\\
0 & 0 & \sin(\frac{\theta}{2}) \left(-i v_x + v_y \right) & i \sin(\frac{\theta}{2}) v_z)
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
vector: Direction of the rotation axis, unit-vector
"""
[docs] def call_interactive(self,
qureg: tqureg,
control: int,
qubit: int,
theta: float,
vector: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
vector: Direction of the rotation axis, unit-vector
Raises:
RuntimeError: vector needs to be a three component numpy array and unit-vector
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
if not (vector.shape == (3,) and np.isclose(np.linalg.norm(vector), 1)):
raise RuntimeError("vector needs to be a three component numpy array and unit-vector")
else:
vec = ffi_quest.new("Vector *")
vec.x = vector[0]
vec.y = vector[1]
vec.z = vector[2]
quest.controlledRotateAroundAxis(qureg, control,
qubit,
theta,
vec[0])
[docs] def matrix(self, theta: float, vector: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
theta: Angle theta of the rotation
vector: Direction of the rotation axis, unit-vector
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
vx = vector[0]
vy = vector[1]
vz = vector[2]
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, c - 1j * s * vz, s * (-1j * vx - vy)],
[0, 0, s * (-1j * vx + vy), c + 1j * s * vz]], dtype=complex)
return matrix
[docs]class controlledRotateX(_PYQUEST):
r"""Implements a controlled rotation around the X axis
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & \cos(\frac{\theta}{2}) & 0\\
0 & 0 & 0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
0 & 0 & 0 & 0\\
0 & 0 & 0 & 0\\
0 & 0 & 0 & -i \sin(\frac{\theta}{2}) \\
0 & 0 & -i \sin(\frac{\theta}{2}) & 0
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
quest.controlledRotateX(qureg, control,
qubit,
theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
theta: Angle theta of the rotation
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, c, -1j * s],
[0, 0, -1j * s, c]], dtype=complex)
return matrix
[docs]class controlledRotateY(_PYQUEST):
r"""Implements a controlled rotation around the Y axis `
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & \cos(\frac{\theta}{2}) & 0\\
0 & 0 & 0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
0 & 0 & 0 & 0\\
0 & 0 & 0 & 0\\
0 & 0 & 0 & - \sin(\frac{\theta}{2}) \\
0 & 0 & \sin(\frac{\theta}{2}) & 0
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
quest.controlledRotateY(qureg, control,
qubit,
theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
theta: Angle theta of the rotation
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, c, -s],
[0, 0, s, c]], dtype=complex)
return matrix
[docs]class controlledRotateZ(_PYQUEST):
r"""Implements a controlled rotation around the Y axis `
.. math::
U = \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & \cos(\frac{\theta}{2}) & 0\\
0 & 0 & 0 & \cos(\frac{\theta}{2})
\end{pmatrix}
+ \begin{pmatrix}
0 & 0 & 0 & 0\\
0 & 0 & 0 & 0\\
0 & 0 & - i \sin(\frac{\theta}{2}) & 0 \\
0 & 0 & 0 & i \sin(\frac{\theta}{2})
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int, theta: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
theta: Angle theta of the rotation
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
quest.controlledRotateZ(qureg, control,
qubit,
theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
theta: Angle theta of the rotation
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
c = np.cos(theta / 2)
s = np.sin(theta / 2)
matrix = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, c - 1j * s, 0],
[0, 0, 0, c + 1j * s]], dtype=complex)
return matrix
[docs]class controlledUnitary(_PYQUEST):
r"""Implements a controlled arbitraty one-qubit gate given by a unitary matrix
Args:
qureg: quantum register
control: qubit that controls the unitary
qubit: qubit the unitary gate is applied to
matrix: Unitary matrix of the one qubit gate
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int, matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the unitary
qubit: qubit the unitary gate is applied to
matrix: Unitary matrix of the one qubit gate
Raises:
RuntimeError: vector needs to be a (2, 2) unitary numpy array
"""
if not (matrix.shape == (2, 2) and np.all(np.isclose(matrix.conj().T @ matrix, np.eye(2)))):
raise RuntimeError("vector needs to be a (2, 2) unitary numpy array")
else:
mat = ffi_quest.new("ComplexMatrix2 *")
for i in range(2):
for j in range(2):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.controlledUnitary(qureg, control,
qubit,
mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|x> |1x> -> |1> U |x>
Args:
matrix: Unitary matrix of the one qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
mat = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, matrix[0, 0], matrix[0, 1]],
[0, 0, matrix[1, 0], matrix[1, 1]]], dtype=complex)
return mat
# Multi-controlled and mutli-qubit Operations
[docs]class multiControlledTwoQubitUnitary(_PYQUEST):
r"""Two qubit unitary gate controlled by multiple qubits
Implements a general two-qubit gate defined by a matrix controlled by multipe qubits
If the matrix basis states are given by 0=|00> 1=|01> 2=|10> 3=|11>
the least significant qubit is the right qubit and the most
significant qubit is the left qubit
Args:
qureg: quantum register
control: controll qubit
target_qubit_1: least significant qubit
target_qubit_2: most sifnificant qubit
matrix: 4 by 4 matrix that defines the two qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg,
controls: Sequence[int],
target_qubit_1: int,
target_qubit_2: int,
matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
controls: control qubits
target_qubit_1: least significant qubit
target_qubit_2: most sifnificant qubit
matrix: 4 by 4 matrix that defines the two qubit gate
"""
mat = ffi_quest.new("ComplexMatrix4 *")
for i in range(4):
for j in range(4):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer = ffi_quest.new("int[{}]".format(len(controls)))
number_controls = len(controls)
for co, control in enumerate(controls):
pointer[co] = control
quest.multiControlledTwoQubitUnitary(qureg,
pointer,
number_controls,
target_qubit_1,
target_qubit_2,
mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class multiControlledPhaseFlip(_PYQUEST):
r"""Phase Flip controlled by multipe qubits
Implements a multi controlled phase flip gate also known as controlled Z gate.
If all qubits in the controls are :math:`\left|1\right\rangle` the sign is flipped.
No change occurs otherwise
Args:
qureg: quantum register
controls: qubits that control the application of the unitary
number_controls: number of the control qubits
"""
[docs] def call_interactive(self,
qureg: tqureg,
controls: Sequence[int],
number_controls: Optional[int] = None) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
controls: qubits that control the application of the unitary
number_controls: number of the control qubits
"""
pointer = ffi_quest.new("int[{}]".format(len(controls)))
if number_controls is None:
number_controls = len(controls)
for co, control in enumerate(controls):
pointer[co] = control
quest.multiControlledPhaseFlip(qureg, pointer, number_controls)
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError
[docs]class multiControlledPhaseShift(_PYQUEST):
r"""Phase Shift controlled by multiple qubits
Implements a multi controlled phase flip gate also known as controlled Z power gate.
If all qubits in the controls are :math:`\left|1\right\rangle` the phase is shifter by theta.
No change occurs otherwise
Args:
qureg: quantum register
controls: qubits that control the application of the unitary
number_controls: number of the control qubits
theta: Angle of the rotation around Z-axis
"""
[docs] def call_interactive(self, qureg: tqureg, controls: Sequence[int],
number_controls: Optional[int] = None, theta: float = 0) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
controls: qubits that control the application of the unitary
number_controls: number of the control qubits
theta: Angle of the rotation around Z-axis
"""
if not (0 <= theta and theta <= 4 * np.pi):
theta = np.mod(theta, 4 * np.pi)
pointer = ffi_quest.new("int[{}]".format(len(controls)))
for co, control in enumerate(controls):
pointer[co] = control
if number_controls is None:
number_controls = len(controls)
quest.multiControlledPhaseShift(qureg, pointer, number_controls, theta)
[docs] def matrix(self, theta: float, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
theta: Angle of the rotation around Z-axis
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError
[docs]class multiControlledUnitary(_PYQUEST):
r"""Generic unitary gate controlled by multiple qubits
Implements a multi-controlled arbitraty one-qubit gate given by a unitary matrix
Args:
qureg: quantum register
controls: qubits that control the application of the unitary
qubit: qubit the unitary gate is applied to
matrix: Unitary matrix of the one qubit gate
"""
[docs] def call_interactive(self, qureg: tqureg,
controls: Sequence[int],
qubit: int, matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
controls: qubits that control the application of the unitary
qubit: qubit the unitary gate is applied to
matrix: Unitary matrix of the one qubit gate
Raises:
RuntimeError: vector needs to be a (2, 2) unitary numpy array
"""
if not (matrix.shape == (2, 2) and np.all(np.isclose(matrix.conj().T @ matrix, np.eye(2)))):
raise RuntimeError("vector needs to be a (2, 2) unitary numpy array")
else:
mat = ffi_quest.new("ComplexMatrix2 *")
for i in range(2):
for j in range(2):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer = ffi_quest.new("int[{}]".format(len(controls)))
for co, control in enumerate(controls):
pointer[co] = control
number_controls = len(controls)
quest.multiControlledUnitary(qureg, pointer,
number_controls,
qubit,
mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: Unitary matrix of the one qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError
[docs]class controlledMultiQubitUnitary(_PYQUEST):
r"""Controlled general unitary gate acting on N qubits
Implements a general N-qubit gate defined by a matrix and controlled by a third qubit
If the matrix basis states are given by 0=|00> 1=|01> 2=|10> 3=|11>
the least significant qubit is the right qubit and the most
significant qubit is the left qubit
Args:
qureg: quantum register
control: controll qubit
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg, control: int,
targets: Sequence[int],
matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: controll qubit
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
Raises:
RuntimeError: Shape of matrix and length of targets are different
"""
if 2**len(targets) != matrix.shape[0] or 2**len(targets) != matrix.shape[1]:
raise RuntimeError("Shape of matrix and length of targets are different")
dim = matrix.shape[0]
mat = quest.createComplexMatrixN(len(targets))
for i in range(dim):
for j in range(dim):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer = ffi_quest.new("int[{}]".format(len(targets)))
for co, target in enumerate(targets):
pointer[co] = target
quest.controlledMultiQubitUnitary(qureg,
control,
pointer,
len(targets),
mat)
quest.destroyComplexMatrixN(mat)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
The control qubit is always assumed to be the most relevant
qubit |0xy> -> |0>|xy> |1xy> -> |1> U |xy>
Args:
matrix: N by N matrix that defines the N qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
dim = matrix.shape[0]
return np.block([[np.eye(dim), np.zeros((dim, dim))],
[np.zeros((dim, dim)), matrix]])
[docs]class multiControlledMultiQubitUnitary(_PYQUEST):
r"""General N-qubit unitary gate controlled by multiple qubits
Implements a general N-qubit gate defined by a matrix controlled by multipe qubits
If the matrix basis states are given by 0=|00> 1=|01> 2=|10> 3=|11>
the least significant qubit is the right qubit and the most
significant qubit is the left qubit
Args:
qureg: quantum register
controls: controll qubits
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg,
controls: Sequence[int],
targets: Sequence[int],
matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
controls: controll qubits
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
Raises:
RuntimeError: Shape of matrix and length of targets are different
"""
if 2**len(targets) != matrix.shape[0] or 2**len(targets) != matrix.shape[1]:
raise RuntimeError("Shape of matrix and length of targets are different")
dim = matrix.shape[0]
mat = quest.createComplexMatrixN(len(targets))
for i in range(dim):
for j in range(dim):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer_c = ffi_quest.new("int[{}]".format(len(controls)))
for co, control in enumerate(controls):
pointer_c[co] = control
number_controls = len(controls)
pointer = ffi_quest.new("int[{}]".format(len(targets)))
for co, t in enumerate(targets):
pointer[co] = t
quest.multiControlledMultiQubitUnitary(qureg,
pointer_c,
number_controls,
pointer,
len(targets),
mat)
quest.destroyComplexMatrixN(mat)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class multiQubitUnitary(_PYQUEST):
r"""General unitary gate acting on N qubits
Implements a general N-qubit gate defined by a matrix
If the matrix basis states are given by 0=|00> 1=|01> 2=|10> 3=|11>
the least significant qubit is the right qubit and the most
significant qubit is the left qubit
Args:
qureg: quantum register
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
"""
[docs] def call_interactive(self, qureg: tqureg, targets: Sequence[int], matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
Raises:
RuntimeError: Shape of matrix and length of targets are different
"""
if 2**len(targets) != matrix.shape[0] or 2**len(targets) != matrix.shape[1]:
raise RuntimeError("Shape of matrix and length of targets are different")
dim = matrix.shape[0]
mat = quest.createComplexMatrixN(len(targets))
for i in range(dim):
for j in range(dim):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer = ffi_quest.new("int[{}]".format(len(targets)))
for co, target in enumerate(targets):
pointer[co] = target
quest.multiQubitUnitary(qureg,
pointer,
len(targets),
mat)
quest.destroyComplexMatrixN(mat)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: N by N matrix that defines the N qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
return matrix
[docs]class multiRotateZ(_PYQUEST):
r"""Applying a Z-Rotation to multiple qubits
A Z-Rotation with a given angle is applyied to multiple qubits
Args:
qureg: quantum register
qubits: target qubits
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg,
qubits: Sequence[int],
angle: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubits: target qubits
angle: Angle of rotation of the RotateZ gate
"""
number_qubits = len(qubits)
pointer = ffi_quest.new("int[{}]".format(len(qubits)))
for co, q in enumerate(qubits):
pointer[co] = q
quest.multiRotateZ(qureg,
pointer,
number_qubits,
angle)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class multiRotatePauli(_PYQUEST):
r"""Applying a set of different Pauli rotations to multiple qubits
A set of Pauli rotations with a given angle is applied to multiple qubits
Args:
qureg: quantum register
qubits: target qubits
paulis: Pauli operators encoded as int via IDENTITY=0, PAULI_X=1, PAULI_Y=2, PAULI_Z=3
matrix: N by N matrix that defines the N qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg,
qubits: Sequence[int],
paulis: Sequence[int],
angle: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubits: target qubits
paulis: Pauli operators encoded as int via IDENTITY=0, PAULI_X=1, PAULI_Y=2, PAULI_Z=3
angle: Angle of rotation of paulis
Raises:
RuntimeError: Number of qubits different from number of applied Paulis
"""
if len(qubits) != len(paulis):
raise RuntimeError("Number of qubits different from number of applied Paulis")
number_qubits = len(qubits)
pointer = ffi_quest.new("int[{}]".format(len(qubits)))
for co, q in enumerate(qubits):
pointer[co] = q
pointer_paulis = ffi_quest.new("enum pauliOpType[{}]".format(len(qubits)))
for co, p in enumerate(paulis):
pointer_paulis[co] = p
quest.multiRotatePauli(qureg,
pointer,
pointer_paulis,
number_qubits,
angle)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class multiStateControlledUnitary(_PYQUEST):
r"""One qubit unitary controlled by multiple states
Implements a general one-qubit gate defined by a matrix controlled by
the state of multiple qubits
Contrary to the multiControlled function the unitary operation here can be executed
either when the controlling qubit is in state |0> or in state |1> depending
on the control_states
Args:
qureg: quantum register
controls: controll qubits
controll_states: list of ints defining if the controlling gate acts like a
a normal control or anti-control (unitary is applied when state is |0>)
For each entry: 1 -> normal controlled, 0 -> anti-controlled
qubit: The qubit the unitary is acting on
matrix: 2 by 2 matrix that defines the one qubit gate
"""
[docs] def call_interactive(self,
qureg: tqureg,
controls: Sequence[int],
control_states: Sequence[int],
qubit: int,
matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
controls: controll qubits
control_states: list of ints defining if the controlling gate acts like a
a normal control or anti-control (unitary is applied when state is |0>)
For each entry: 1 -> normal controlled, 0 -> anti-controlled
qubit: The qubit the unitary is acting on
matrix: 2 by 2 matrix that defines the one qubit gate
Raises:
RuntimeError: Different Number of controls and control states
"""
if len(controls) != len(control_states):
raise RuntimeError("Different Number of controls and control states")
mat = ffi_quest.new("ComplexMatrix2 *")
for i in range(2):
for j in range(2):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer_controls = ffi_quest.new("int[{}]".format(len(controls)))
for co, control in enumerate(controls):
pointer_controls[co] = control
number_controls = len(controls)
pointer_states = ffi_quest.new("int[{}]".format(len(control_states)))
for co, state in enumerate(control_states):
pointer_states[co] = state
quest.multiStateControlledUnitary(qureg,
pointer_controls,
pointer_states,
number_controls,
qubit,
mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
# Extra gates
[docs]class MolmerSorensenXX(_PYQUEST):
r"""Molmer Sorensen gate
Implements a fixed phase MolmerSorensen XX gate (http://arxiv.org/abs/1705.02771)
Uses decomposition according to http://arxiv.org/abs/quant-ph/0507171
.. math::
U = \frac{1}{\sqrt{2}} \begin{pmatrix}
1 & 0 & 0 & i\\
0 & 1 & i & 0\\
0 & i & 1 & 0\\
i & 0 & 0 & 1
\end{pmatrix}
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
[docs] def call_interactive(self, qureg: tqureg, control: int, qubit: int) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the unitary
qubit: qubit the unitary gate is applied to
"""
matrix = self.matrix()
mat = ffi_quest.new("ComplexMatrix4 *")
for i in range(4):
for j in range(4):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.twoQubitUnitary(qureg,
control,
qubit,
mat[0])
[docs] def matrix(self, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 1j],
[0, 1, 1j, 0],
[0, 1j, 1, 0],
[1j, 0, 0, 1]], dtype=complex) * (1 - 1j) / 2
return matrix
# Apply operations
[docs]class applyDiagonalOp(_PYQUEST):
r"""Applying a diagonal operator to state
Apply a diagonal complex operator, which is possibly non-unitary
and non-Hermitian, on the entire quantum register.
Args:
qureg: quantum register input, is not changed
operator: operator acting on a certain number of qubits (operator[0]: int)
and in a certain QuEST environment (operator[1]: tquestenv)
"""
[docs] def call_interactive(self,
qureg: tqureg,
operator: Tuple[int, tquestenv],
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
operator: operator acting on a certain number of qubits (operator[0]: int)
and in a certain QuEST environment (operator[1]: tquestenv)
Raises:
RuntimeError: Qureg and DiagonalOp must be defined for the same number of qubits
"""
diagonal_op = quest.createDiagonalOp(operator[0], operator[1])
if not (cheat.getNumQubits()(qureg=qureg) == diagonal_op.numQubits):
raise RuntimeError("Qureg and DiagonalOp must be defined for the "
+ "same number of qubits")
quest.applyDiagonalOp(qureg, diagonal_op)
quest.destroyDiagonalOp(diagonal_op, operator[1])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class applyMatrix2(_PYQUEST):
r"""Applying a general 2-by-2 matrix, which may be non-unitary
The matrix is left-multiplied onto the state, for both
state-vectors and density matrices. Hence, this function differs
from unitary() by more than just permitting a non-unitary matrix.
Args:
qureg: quantum register input, is not changed
qubit: qubit to operate the matrix upon
matrix: matrix to apply
Warning:
After applyMatrix2 the quantum register is in general no longer normalised
and does no longer represent a physical valid state without normalisation.
"""
[docs] def call_interactive(self,
qureg: tqureg,
qubit: int,
matrix: np.ndarray,
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit to operate the matrix upon
matrix: matrix to apply
"""
mat = ffi_quest.new("ComplexMatrix2 *")
for i in range(2):
for j in range(2):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.applyMatrix2(qureg, qubit, mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 2 by 2 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
return matrix
[docs]class applyMatrix4(_PYQUEST):
r"""Applying a general 4-by-4 matrix, which may be non-unitary
The matrix is left-multiplied onto the state, for both
state-vectors and density matrices. Hence, this function differs from
twoQubitUnitary() by more than just permitting a non-unitary matrix.
Args:
qureg: quantum register input, is not changed
control: qubit that controls the application of the matrix
qubit: qubit to operate the matrix upon
matrix: matrix to apply
Warning:
After applyMatrix2 the quantum register is in general no longer normalised
and does no longer represent a physical valid state without normalisation.
"""
[docs] def call_interactive(self,
qureg: tqureg,
control: int,
qubit: int,
matrix: np.ndarray,
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
control: qubit that controls the application of the matrix
qubit: qubit to operate the matrix upon
matrix: matrix to apply
"""
mat = ffi_quest.new("ComplexMatrix4 *")
for i in range(4):
for j in range(4):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
quest.applyMatrix4(qureg, control, qubit, mat[0])
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
return matrix
[docs]class applyMatrixN(_PYQUEST):
r"""Applying a general N-by-N matrix, which may be non-unitary, on any number of target qubits
The matrix is left-multiplied onto the state, for both
state-vectors and density matrices. Hence, this function differs
from multiQubitUnitary() by more than just permitting a non-unitary matrix.
Args:
qureg: quantum register input, is not changed
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
Warning:
After applyMatrixN the quantum register is in general no longer normalised
and does no longer represent a physical valid state without normalisation.
"""
[docs] def call_interactive(self,
qureg: tqureg,
targets: Sequence[int],
matrix: np.ndarray,
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
Raises:
RuntimeError: Shape of matrix and length of targets are different
"""
if 2**len(targets) != matrix.shape[0] or 2**len(targets) != matrix.shape[1]:
raise RuntimeError("Shape of matrix and length of targets are different")
dim = matrix.shape[0]
mat = quest.createComplexMatrixN(len(targets))
for i in range(dim):
for j in range(dim):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer = ffi_quest.new("int[{}]".format(len(targets)))
for co, target in enumerate(targets):
pointer[co] = target
quest.applyMatrixN(qureg,
pointer,
len(targets),
mat)
quest.destroyComplexMatrixN(mat)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: N by N matrix that defines the N qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
return matrix
[docs]class applyMultiControlledMatrixN(_PYQUEST):
r"""Apply a general N-by-N matrix, which may be non-unitary, with additional controlled qubits
A sum of products of Pauli operators (including Identity) is applied to a state.
The state is not changed but the corresponding copy with the Pauli sum applied is
written to qureg_out
For each qubit a Pauli operator must be given in each sum term (can be identity)
Args:
qureg: quantum register
controls: controll qubits
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
Warning:
After applyMultiControlledMatrixN the quantum register is in general no longer normalised
and does no longer represent a physical valid state without normalisation.
"""
[docs] def call_interactive(self,
qureg: tqureg,
controls: Sequence[int],
targets: Sequence[int],
matrix: np.ndarray) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
controls: controll qubits
targets: list of target qubits of the N qubit gate
the first qubit in targets is treated as the least significant one
the second as the second least significant one etc.
matrix: N by N matrix that defines the N qubit gate
Raises:
RuntimeError: Shape of matrix and length of targets are different
"""
if 2**len(targets) != matrix.shape[0] or 2**len(targets) != matrix.shape[1]:
raise RuntimeError("Shape of matrix and length of targets are different")
dim = matrix.shape[0]
mat = quest.createComplexMatrixN(len(targets))
for i in range(dim):
for j in range(dim):
mat.real[i][j] = np.real(matrix[i, j])
mat.imag[i][j] = np.imag(matrix[i, j])
pointer_c = ffi_quest.new("int[{}]".format(len(controls)))
for co, control in enumerate(controls):
pointer_c[co] = control
pointer = ffi_quest.new("int[{}]".format(len(targets)))
for co, target in enumerate(targets):
pointer[co] = target
quest.applyMultiControlledMatrixN(qureg,
pointer_c,
len(controls),
pointer,
len(targets),
mat)
quest.destroyComplexMatrixN(mat)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: N by N matrix that defines the N qubit gate
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
return matrix
[docs]class applyPauliHamil(_PYQUEST):
r"""Applying PauliHamil (a Hermitian but not necessarily unitary operator) to state
This is merely an encapsulation of applyPauliSum(), which can refer to for elaborated doc.
Applies each Pauli product in pauli_hamil to qureg in turn, and adding the resulting
state to the initially-blanked qureg_out. Ergo it should scale with the total number
of Pauli operators specified (excluding identities), and the qureg dimension.
Args:
qureg: quantum register input, is not changed
paulis: List of Lists of Pauli operators in each product
encoded as int via IDENTITY=0, PAULI_X=1, PAULI_Y=2, PAULI_Z=3
matrix: N by N matrix that defines the N qubit gate
qureg_out: quantum register after application of Pauli sum
Warning:
After applyPauliHamil the output quantum register is in general no longer normalised
and does no longer represent a physical valid state without normalisation.
"""
[docs] def call_interactive(self,
qureg: tqureg,
pauli_hamil: paulihamil,
qureg_out: tqureg
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
pauli_hamil: PauliHamil instance to be applied
qureg_out: quantum register after application of Pauli sum
Raises:
RuntimeError: Qureg and PauliHamil must be defined for the same number of qubits
"""
if not (cheat.getNumQubits()(qureg=qureg) == pauli_hamil.numQubits):
raise RuntimeError("Qureg and PauliHamil must be defined for the "
+ "same number of qubits")
quest.applyPauliHamil(qureg,
pauli_hamil,
qureg_out)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class applyPauliSum(_PYQUEST):
r"""Applying a sum of Products of Pauli operators to state
A sum of products of Pauli operators (including Identity) is applied to a state.
The state is not changed but the corresponding copy with the Pauli sum applied is
written to qureg_out
For each qubit a Pauli operator must be given in each sum term (can be identity)
Args:
qureg: quantum register input, is not changed
paulis: List of Lists of Pauli operators in each product
encoded as int via IDENTITY=0, PAULI_X=1, PAULI_Y=2, PAULI_Z=3
coefficients: coefficients of the paulis to be summed
qureg_out: quantum register after application of Pauli sum
Warning:
After applyPauliSum the quantum register is in general no longer normalised
and does no longer represent a physical valid state without normalisation.
"""
[docs] def call_interactive(self,
qureg: tqureg,
paulis: Sequence[Sequence[int]],
coefficients: Sequence[float],
qureg_out: tqureg
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
paulis: List of Lists of Pauli operators in each product
encoded as int via IDENTITY=0, PAULI_X=1, PAULI_Y=2, PAULI_Z=3
coefficients: coefficients of the paulis to be summed
qureg_out: quantum register after application of Pauli sum
Raises:
RuntimeError: Size of Qureg and number of lenght of PauliProduct does not match
ValueError: Pauli arrays need to only have values in [0, 1, 2, 3]
"""
for product in paulis:
if qureg.numQubitsRepresented != len(product):
raise RuntimeError(
"Size of Qureg and number of lenght of PauliProduct does not match")
if not all((pauli in [0, 1, 2, 3]) for pauli in product):
raise ValueError("Pauli arrays need to only have values in [0, 1, 2, 3]")
if qureg.numQubitsRepresented != qureg_out.numQubitsRepresented:
raise RuntimeError("Size of Qureg and output QuregS does not match")
flat_list = [p for product in paulis for p in product]
pointer_paulis = ffi_quest.new("enum pauliOpType[{}]".format(len(flat_list)))
for co, p in enumerate(flat_list):
pointer_paulis[co] = p
pointer = ffi_quest.new("{}[{}]".format(qreal, len(coefficients)))
for co, c in enumerate(coefficients):
pointer[co] = float(c)
quest.applyPauliSum(qureg,
pointer_paulis,
pointer,
len(coefficients),
qureg_out)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class applyTrotterCircuit(_PYQUEST):
r"""Applying a trotterisation of unitary evolution exp(-i*pauli_hamil*time) to qureg
This is a sequence of unitary operators, effected by multiRotatePauli(), which together
approximate the action of full unitary-time evolution under the given Hamiltonian.
These formulations are taken from 'Finding Exponential Product Formulas of Higher Orders',
Naomichi Hatano and Masuo Suzuki (2005).
Args:
qureg: the register to modify under the approximate unitary-time evolution
pauli_hamil: PauliHamil under which to approxiamte unitary-time evolution
time: the target evolution time, which is permitted to be both positive and negative
order: the order of Trotter-Suzuki decomposition to use
repetitions: the number of repetitions of the decomposition of the given order
"""
[docs] def call_interactive(self,
qureg: tqureg,
pauli_hamil: paulihamil,
time: float,
order: int,
repetitions: int
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: the register to modify under the approximate unitary-time evolution
pauli_hamil: PauliHamil under which to approxiamte unitary-time evolution
time: the target evolution time, which is permitted to be both positive and negative
order: the order of Trotter-Suzuki decomposition to use
repetitions: the number of repetitions of the decomposition of the given order
"""
quest.applyTrotterCircuit(qureg,
pauli_hamil,
time,
order,
repetitions)
[docs] def matrix(self, matrix: np.ndarray, **kwargs) -> np.ndarray:
r"""The definition of the gate as a unitary matrix
Args:
matrix: 4 by 4 matrix that defines the two qubit gate
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
# Measurement
[docs]class measure(_PYQUEST):
r"""Implements a one-qubit Measurement operation
Args:
qureg: quantum register
qubit: the measured qubit
readout: The readout register for static compilation
readout_index: The index in the readout register for static compilation
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int) -> int:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
Returns:
int
"""
return quest.measure(qureg, qubit)
[docs]class measureWithStats(_PYQUEST):
r"""Measures a single qubit and gives the probability of that outcome.
Args:
qureg: quantum register
qubit: the measured qubit
outcome_proba: where to set the probability of the occurred outcome
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, outcome_proba: float) -> int:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
outcome_proba: where to set the probability of the occurred outcome
Returns:
int
"""
outcome_pointer = ffi_quest.new("{}[{}]".format(qreal, 1))
outcome_pointer[0] = outcome_proba
return quest.measureWithStats(qureg, qubit, outcome_pointer)
[docs]class collapseToOutcome(_PYQUEST):
r"""Updates qureg to be consistent with measuring measureQubit and returns the probability.
Args:
qureg: quantum register
qubit: the measured qubit
outcome: where to set the probability of the occurred outcome
"""
[docs] def call_interactive(self, qureg: tqureg, qubit: int, outcome: int) -> float:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register
qubit: qubit the unitary gate is applied to
outcome: where to set the probability of the occurred outcome
Returns:
float
"""
return quest.collapseToOutcome(qureg, qubit, outcome)