Source code for pyquest_cffi.ops.ops

"""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)