"""Error operation in PyQuest-cffi"""
# 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, tqureg, ffi_quest
import numpy as np
from typing import Tuple, Sequence, List
import warnings
from pyquest_cffi import cheat
[docs]class mixDensityMatrix(_PYQUEST):
r"""Modifies qureg to become (1-probability)*qureg + probability*qureg_other
Both registers must be equal-dimension density matrices, and prob must be in [0, 1].
Args:
qureg: quantum register to be modified
probability: the probability of qureg_other in the modified qureg
qureg_other: the quantum register to be mixed into qureg
"""
[docs] def call_interactive(self, qureg: tqureg,
probability: float,
qureg_other: tqureg) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: quantum register to be modified
probability: the probability of qureg_other in the modified qureg
qureg_other: the quantum register to be mixed into qureg
Raises:
RuntimeError: Both quregs must be density matrix,
but at least one of them is a wavefunction
RuntimeError: Qureg and Qureg_other must be defined for the same number of qubits
"""
if not qureg.isDensityMatrix or not qureg_other.isDensityMatrix:
raise RuntimeError("Both quregs must be density matrix, "
+ "but at least one of them is a wavefunction")
elif not (cheat.getNumQubits()(qureg=qureg) == cheat.getNumQubits()(qureg=qureg_other)):
raise RuntimeError("Qureg and Qureg_other must be defined "
+ "for the same number of qubits")
else:
quest.mixDensityMatrix(qureg, probability, qureg_other)
[docs] def Kraus_matrices(self, probability: float, **kwargs) -> Tuple[np.ndarray, np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs] def superoperator_matrix(self, probability: float, **kwargs) -> np.ndarray:
r"""The definition of the superoperator acting on the density matrix written as a vector
.. math::
\rho = A \rho B \\
\vec{\rho} = \mathcal{L} \vec{\rho}
where A and B are arbitrary matrices
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class mixDephasing(_PYQUEST):
r"""One qubit dephasing error
Apply the dephasing :math:`\sigma^z` operator to a qubit q with probability p
Can also be expressed as a Kraus operator :math:`\mathcal{K}`
.. math::
\rho &= (1-p) \rho + p \sigma^z_q \rho \sigma^z_q \\
\rho &= \mathcal{K} \rho \mathcal{K} \\
\vec{\rho} &= \mathcal{L} \vec{\rho} \\
\mathcal{L} &= \begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1-2p & 0 & 0\\
0 & 0 & 1-2p & 0 \\
0 & 0 & 0 & 1
\end{pmatrix}
"""
[docs] def call_interactive(self, qureg: tqureg,
qubit: int,
probability: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubit: The qubit dephasing
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
Raises:
RuntimeError: Probability of mixDephasing needs to be smaller that 1/2
RuntimeError: Qureg has to be a density matrix qureg but wavefunction qureg was used
"""
if probability > 1 / 2:
raise RuntimeError(
"Probability of mixDephasing needs to be smaller that 1/2")
if qureg.isDensityMatrix:
quest.mixDephasing(qureg, qubit, probability)
else:
raise RuntimeError("Qureg has to be a density matrix qureg but "
+ "wavefunction qureg was used")
[docs] def Kraus_matrices(self, probability: float, **kwargs) -> Tuple[np.ndarray, np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
sqp = np.sqrt(probability)
sqmp = np.sqrt(1 - probability)
dephasing = np.array([[sqp, 0], [0, -sqp]], dtype=complex)
residual = np.array([[sqmp, 0], [0, sqmp]], dtype=complex)
return (residual, dephasing)
[docs] def superoperator_matrix(self, probability: float, **kwargs) -> np.ndarray:
r"""The definition of the superoperator acting on the density matrix written as a vector
.. math::
\rho = A \rho B \\
\vec{\rho} = \mathcal{L} \vec{\rho}
where A and B are arbitrary matrices
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.array([[1, 0, 0, 0],
[0, 1 - 2 * probability, 0, 0],
[0, 0, 1 - 2 * probability, 0],
[0, 0, 0, 1]], dtype=complex)
return matrix
[docs]class mixDepolarising(_PYQUEST):
r"""One qubit depolarisation error
Apply the depolarisation operators :math:`\sigma^x`, :math:`\sigma^y` and :math:`\sigma^z`
to a qubit q with an evenly distributed probability p`
.. math::
\rho = (1-p) \rho + \frac{p}{3} \left( \sigma^x_q \rho \sigma^x_q
+ \sigma^y_q \rho \sigma^y_q + \sigma^z_q \rho \sigma^z_q \right)
Args:
qureg: a qureg containing a density matrix
qubit: The qubit depolarising
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 3/4
"""
[docs] def call_interactive(self, qureg: tqureg,
qubit: int,
probability: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubit: The qubit depolarising
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
Raises:
RuntimeError: Probability of mixDepolarising needs to be smaller that 3/4
RuntimeError: Qureg has to be a density matrix qureg but wavefunction qureg was used
"""
if probability > 3 / 4:
raise RuntimeError(
"Probability of mixDepolarising needs to be smaller that 3/4")
if qureg.isDensityMatrix:
quest.mixDepolarising(qureg, qubit, probability)
else:
raise RuntimeError("Qureg has to be a density matrix qureg but "
+ "wavefunction qureg was used")
[docs] def Kraus_matrices(self,
probability: float,
**kwargs
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
sqp = np.sqrt(probability / 3)
sqmp = np.sqrt(1 - probability)
residual = np.array([[sqmp, 0],
[0, sqmp]], dtype=complex)
depol1 = np.array([[0, sqp],
[sqp, 0]], dtype=complex)
depol2 = np.array([[0, -1j * sqp],
[1j * sqp, 0]], dtype=complex)
depol3 = np.array([[sqp, 0],
[0, -sqp]], dtype=complex)
return (residual, depol1, depol2, depol3)
[docs] def superoperator_matrix(self, probability: float, **kwargs) -> np.ndarray:
r"""The definition of the Superoperator acting on the density matrix written as a vector
.. math::
\rho = A \rho B \\
\vec{\rho} = \mathcal{L} \vec{\rho}
where A and B are arbitrary matrices
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
one_plus = 1 - 2 / 3 * probability
one_minus = 1 - 4 / 3 * probability
two_three = 2 / 3 * probability
matrix = np.array([[one_plus, 0, 0, two_three],
[0, one_minus, 0, 0],
[0, 0, one_minus, 0],
[two_three, 0, 0, one_plus]], dtype=complex)
return matrix
[docs]class mixDamping(_PYQUEST):
r"""One qubit damping error
Apply a pure damping error corresponding to zero temperature environments
.. math::
\rho &= \mathcal{K} \rho \mathcal{K}\\
Args:
qureg: a qureg containing a density matrix
qubit: The damped qubit
probability: The probability/ relative amplitude with which the dephasing occurs
"""
[docs] def call_interactive(self, qureg: tqureg,
qubit: int,
probability: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubit: The damped qubit
probability: The probability/relative amplitude with which the dephasing occurs
Raises:
RuntimeError: Qureg has to be a density matrix qureg but wavefunction qureg was used
"""
if qureg.isDensityMatrix:
quest.mixDamping(qureg, qubit, probability)
else:
raise RuntimeError("Qureg has to be a density matrix qureg but "
+ "wavefunction qureg was used")
[docs] def Kraus_matrices(self, probability: float, **kwargs) -> Tuple[np.ndarray, np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
sqp = np.sqrt(probability)
sqmp = np.sqrt(1 - probability)
damping = np.array([[0, sqp], [0, 0]], dtype=complex)
residual = np.array([[1, 0], [0, sqmp]], dtype=complex)
return (residual, damping)
[docs] def superoperator_matrix(self, probability: float, **kwargs) -> np.ndarray:
r"""The definition of the Superoperator acting on the density matrix written as a vector
.. math::
\rho = A \rho B \\
\vec{\rho} = \mathcal{L} \vec{\rho}
where A and B are arbitrary matrices
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
sqmp = np.sqrt(1 - probability)
matrix = np.zeros((16, 16), dtype=complex)
matrix = np.array([[1, 0, 0, probability],
[0, sqmp, 0, 0],
[0, 0, sqmp, 0],
[0, 0, 0, 1 - probability]], dtype=complex)
return matrix
[docs]class mixTwoQubitDepolarising(_PYQUEST):
r"""Two qubit depolarisation error
Apply any tensor product of two operators :math:`U` :math:`\sigma^x`, :math:`\sigma^y`
and :math:`\sigma^z` to two qubits q1 and q2 with an evenly distributed probability p`
.. math::
\rho &= (1-p) \rho + \frac{p}{15} \sum_{A, B \in \{ I, \sigma^x, \sigma^y, \sigma^z\}}
A_{q1}B_{q2} \rho B_{q2}A_{q1} \\
\rho &= \mathcal{K} \rho \mathcal{K}
Args:
qureg: a qureg containing a density matrix
qubit1: The first qubit dephasing
qubit2: The second qubit dephasing
probability: The probability/ relative amplitude with which the depolarisation occurs.
Needs to be smaller than :math:`\frac{15}{16}`
"""
[docs] def call_interactive(self, qureg: tqureg,
qubit1: int,
qubit2: int,
probability: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubit1: The first qubit dephasing
qubit2: The second qubit dephasing
probability: The probability/ relative amplitude with which the depolarisation occurs.
Needs to be smaller than :math:`\frac{15}{16}`
Raises:
RuntimeError: Probability of twoQubitDepolariseErrors needs to be smaller that 15/16
RuntimeError: Qureg has to be a density matrix qureg but wavefunction qureg was used
"""
if probability > 15 / 16:
raise RuntimeError(
"Probability of twoQubitDepolariseErrors needs to be smaller that 15/16")
if qureg.isDensityMatrix:
quest.mixTwoQubitDepolarising(qureg, qubit1, qubit2, probability)
else:
raise RuntimeError("Qureg has to be a density matrix qureg but "
+ "wavefunction qureg was used")
[docs] def superoperator_matrix(self, probability: float, **kwargs) -> None:
r"""The definition of the superoperator acting on the density matrix written as a vector
.. math::
\rho = A \rho B \\
\vec{\rho} = \mathcal{L} \vec{\rho}
where A and B are arbitrary matrices
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
[docs]class mixTwoQubitDephasing(_PYQUEST):
r"""Two qubit dephasing error
Apply the dephasing :math:`\sigma^z` operator to two qubits q1 and q2 with probability p
Can also be expressed as a Kraus operator :math:`\mathcal{K}`
.. math::
\rho &= (1-p) \rho + \frac{p}{3} \left( \sigma^z_{q1} \rho \sigma^z_{q1}
+ \sigma^z_{q2} \rho \sigma^z_{q2}
+ \sigma^z_{q1}\sigma^z_{q2} \rho \sigma^z_{q2} \sigma^z_{q1} \right)\\
\rho &= \mathcal{K} \rho \mathcal{K}
Args:
qureg: a qureg containing a density matrix
qubit1: The first qubit dephasing
qubit2: The second qubit dephasing
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 3/4
"""
[docs] def call_interactive(self, qureg: tqureg,
qubit1: int,
qubit2: int,
probability: float) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubit1: The first qubit dephasing
qubit2: The second qubit dephasing
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 3/4
Raises:
RuntimeError: Probability of twoQubitDepolariseErrors needs to be smaller that 3/4
RuntimeError: Qureg has to be a density matrix qureg but wavefunction qureg was used
"""
if probability > 3 / 4:
raise RuntimeError(
"Probability of twoQubitDepolariseErrors needs to be smaller that 3/4")
if qureg.isDensityMatrix:
quest.mixTwoQubitDephasing(qureg, qubit1, qubit2, probability)
else:
raise RuntimeError("Qureg has to be a density matrix qureg but "
+ "wavefunction qureg was used")
[docs] def Kraus_matrices(self,
probability: float,
**kwargs
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
sqp = np.sqrt(probability / 3)
sqmp = np.sqrt(1 - probability)
residual = np.array([[sqmp, 0, 0, 0],
[0, sqmp, 0, 0],
[0, 0, sqmp, 0],
[0, 0, 0, sqmp]], dtype=complex)
dephasing1 = np.array([[sqp, 0, 0, 0],
[0, 0, sqp, 0],
[0, 0, -sqp, 0],
[0, 0, 0, -sqp]], dtype=complex)
dephasing2 = np.array([[sqp, 0, 0, 0],
[0, 0, -sqp, 0],
[0, 0, sqp, 0],
[0, 0, 0, -sqp]], dtype=complex)
dephasing3 = np.array([[-sqp, 0, 0, 0],
[0, 0, sqp, 0],
[0, 0, sqp, 0],
[0, 0, 0, -sqp]], dtype=complex)
return (residual, dephasing1, dephasing2, dephasing3)
[docs] def superoperator_matrix(self, probability: float, **kwargs) -> np.ndarray:
r"""The definition of the superoperator acting on the density matrix written as a vector
.. math::
\rho = A \rho B \\
\vec{\rho} = \mathcal{L} \vec{\rho}
where A and B are arbitrary matrices
Args:
probability: The probability/ relative amplitude with which the dephasing occurs,
probability needs to be smaller than 1/2
**kwargs: Additional keyword arguments
Returns:
np.ndarray
Raises:
NotImplementedError: not implemented
"""
raise NotImplementedError()
matrix = np.zeros((16, 16), dtype=complex)
for ci in range(0, 16):
matrix[ci, ci] = 1 if (ci % 4) == 1 else 1 - 2 * (probability)
return matrix
[docs]class applyOneQubitDephaseError(mixDephasing):
r"""One Qubit Dephasing - deprecated"""
def __init__(self, *args, **kwargs) -> None:
r"""Initialisation
Args:
*args: Arguments
**kwargs: Additional keyword arguments
"""
warnings.warn(
"applyOneQubitDephaseError will be removed in future versions, use mixDephasing",
DeprecationWarning)
super().__init__(*args, **kwargs)
[docs]class applyOneQubitDepolariseError(mixDepolarising):
r"""One Qubit Depolarisation - deprecated"""
def __init__(self, *args, **kwargs) -> None:
r"""Initialisation
Args:
*args: Arguments
**kwargs: Additional keyword arguments
"""
warnings.warn(
"applyOneQubitDepolariseError will be removed in future versions, use mixDepolarising",
DeprecationWarning)
super().__init__(*args, **kwargs)
[docs]class applyOneQubitDampingError(mixDamping):
r"""One Qubit Damping - deprecated"""
def __init__(self, *args, **kwargs) -> None:
r"""Initialisation
Args:
*args: Arguments
**kwargs: Additional keyword arguments
"""
warnings.warn(
"applyOneQubitDampingError will be removed in future versions, use mixDamping",
DeprecationWarning)
super().__init__(*args, **kwargs)
[docs]class applyTwoQubitDephaseError(mixTwoQubitDephasing):
r"""Two Qubit Dephasing - deprecated"""
def __init__(self, *args, **kwargs) -> None:
r"""Initialisation
Args:
*args: Arguments
**kwargs: Additional keyword arguments
"""
warnings.warn(
"applyTwoQubitDephaseError will be removed in future versions,"
+ " use mixTwoQubitDephasing",
DeprecationWarning)
super().__init__(*args, **kwargs)
[docs]class applyTwoQubitDepolariseError(mixTwoQubitDepolarising):
r"""Two Qubit Depolarisation - deprecated"""
def __init__(self, *args, **kwargs) -> None:
r"""Initialisation
Args:
*args: Arguments
**kwargs: Additional keyword arguments
"""
warnings.warn(
"applyTwoQubitDepolariseError will be removed in future versions,"
+ " use mixTwoQubitDepolarising",
DeprecationWarning)
super().__init__(*args, **kwargs)
[docs]class mixMultiQubitKrausMap(_PYQUEST):
r"""Error affecting multiple qubits
An error acting on multiple qubtis simultaneously is defined by a set of Kraus operators
Args:
qureg: a qureg containing a density matrix
qubits: The qubits the Kraus operators are acting on
operators: The Kraus operators
"""
[docs] def call_interactive(self, qureg: tqureg,
qubits: Sequence[int],
operators: Sequence[np.ndarray],
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubits: The qubits the Kraus operators are acting on
operators: The Kraus operators
Raises:
RuntimeError: Number of target qubits and dimension of Kraus operators mismatch
RuntimeError: Not a valid Kraus map
"""
for op in operators:
if 2**len(qubits) != op.shape[0] or 2**len(qubits) != op.shape[1]:
raise RuntimeError("Number of target qubits"
+ " and dimension of Kraus operators mismatch")
operator_sum = np.sum([op.conjugate().T @ op for op in operators], axis=0)
if not np.isclose(operator_sum, np.eye(operators[0].shape[0])).all():
raise RuntimeError("Not a valid Kraus map")
operator_pointers = ffi_quest.new("ComplexMatrixN[{}]".format(len(operators)))
for co, op in enumerate(operators):
operator_pointers[co] = quest.createComplexMatrixN(qureg.numQubitsRepresented)
for i in range(op.shape[0]):
for j in range(op.shape[0]):
operator_pointers[co].real[i][j] = np.real(op[i, j])
operator_pointers[co].imag[i][j] = np.imag(op[i, j])
pointer_q = ffi_quest.new("int[{}]".format(len(qubits)))
for co, qubit in enumerate(qubits):
pointer_q[co] = qubit
quest.mixMultiQubitKrausMap(
qureg,
pointer_q,
len(qubits),
operator_pointers,
len(operators))
for p in operator_pointers:
quest.destroyComplexMatrixN(p)
[docs] def Kraus_matrices(self, operators: Sequence[np.ndarray], **kwargs) -> Sequence[np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
operators: The Kraus operators
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
return operators
[docs] def superoperator_matrix(self, operators: Sequence[np.ndarray], **kwargs) -> np.ndarray:
r"""The definition of the superoperator acting on the density matrix written as a vector
Args:
operators: The Kraus operators
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.zeros((2 * operators[0].shape[0], 2 * operators[0].shape[0]), dtype=complex)
for op in operators:
matrix += np.kron(op, op.conjugate().T)
return matrix
[docs]class mixTwoQubitKrausMap(_PYQUEST):
r"""Error affecting two qubits
An error acting on two qubtis simultaneously is defined by a set of Kraus operators
Args:
qureg: a qureg containing a density matrix
target_qubit_1: The least significant qubit the Kraus operators are acting on
target_qubit_2: The most significant qubit the Kraus operators are acting on
operators: The Kraus operators
"""
[docs] def call_interactive(self, qureg: tqureg,
target_qubit_1: Sequence[int],
target_qubit_2: Sequence[int],
operators: Sequence[np.ndarray],
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
target_qubit_1: The least significant qubit the Kraus operators are acting on
target_qubit_2: The most significant qubit the Kraus operators are acting on
operators: The Kraus operators
Raises:
RuntimeError: Number of target qubits and dimension of Kraus operators mismatch
RuntimeError: Not a valid Kraus map
"""
for op in operators:
if op.shape[0] != 4 or op.shape[1] != 4:
raise RuntimeError("Number of target qubits"
+ " and dimension of Kraus operators mismatch")
operator_sum = np.sum([op.conjugate().T @ op for op in operators], axis=0)
if not np.isclose(operator_sum, np.eye(4)).all():
raise RuntimeError("Not a valid Kraus map")
operator_pointers = ffi_quest.new("ComplexMatrix4[{}]".format(len(operators)))
for co, op in enumerate(operators):
for i in range(4):
for j in range(4):
operator_pointers[co].real[i][j] = np.real(op[i, j])
operator_pointers[co].imag[i][j] = np.imag(op[i, j])
quest.mixTwoQubitKrausMap(
qureg,
target_qubit_1,
target_qubit_2,
operator_pointers,
len(operators))
[docs] def Kraus_matrices(self, operators: Sequence[np.ndarray], **kwargs) -> Sequence[np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
operators: The Kraus operators
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
return operators
[docs] def superoperator_matrix(self, operators: Sequence[np.ndarray], **kwargs) -> np.ndarray:
r"""The definition of the superoperator acting on the density matrix written as a vector
Args:
operators: The Kraus operators
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.zeros((2 * operators[0].shape[0], 2 * operators[0].shape[0]), dtype=complex)
for op in operators:
matrix += np.kron(op, op.conjugate().T)
return matrix
[docs]class mixKrausMap(_PYQUEST):
r"""General error affecting one qubit
An error acting on one qubit is defined by a set of Kraus operators
Args:
qureg: a qureg containing a density matrix
qubit: The qubit the Kraus operators are acting on
operators: The Kraus operators
"""
[docs] def call_interactive(self, qureg: tqureg,
qubit: int,
operators: Sequence[np.ndarray],
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubit: The qubit the Kraus operators are acting on
operators: The Kraus operators
Raises:
RuntimeError: Qureg has to be a density matrix qureg but wavefunction qureg was used
RuntimeError: Target qubit is not in the Qureg
RuntimeError: Too many operators given, must be in [1, 4]
RuntimeError: Number of target qubits and dimension of Kraus operators mismatch
RecursionError: Not a valid Kraus map
"""
if not qureg.isDensityMatrix:
raise RuntimeError("Qureg has to be a density matrix qureg but "
+ "wavefunction qureg was used")
if qubit not in list(range(qureg.numQubitsRepresented)):
raise RuntimeError("Target qubit is not in the Qureg")
if len(operators) < 1 or len(operators) > 4:
raise RuntimeError("Too many operators given, must be in [1, 4]")
for op in operators:
if op.shape[0] != 2 or op.shape[1] != 2:
raise RuntimeError("Number of target qubits"
+ " and dimension of Kraus operators mismatch")
operator_sum = np.sum([op.conjugate().T @ op for op in operators], axis=0)
if not np.isclose(operator_sum, np.eye(2)).all():
raise RecursionError("Not a valid Kraus map")
operator_pointers = ffi_quest.new("ComplexMatrix2[{}]".format(len(operators)))
for co, op in enumerate(operators):
for i in range(2):
for j in range(2):
operator_pointers[co].real[i][j] = float(np.real(op[i][j]))
operator_pointers[co].imag[i][j] = float(np.imag(op[i][j]))
quest.mixKrausMap(
qureg,
qubit,
operator_pointers,
len(operators))
[docs] def Kraus_matrices(self, operators: Sequence[np.ndarray], **kwargs) -> Sequence[np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
operators: The Kraus operators
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
return operators
[docs] def superoperator_matrix(self, operators: Sequence[np.ndarray], **kwargs) -> np.ndarray:
r"""The definition of the superoperator acting on the density matrix written as a vector
Args:
operators: The Kraus operators
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
matrix = np.zeros((2 * operators[0].shape[0], 2 * operators[0].shape[0]), dtype=complex)
for op in operators:
matrix += np.kron(op, op.conjugate().T)
return matrix
[docs]class mixPauli(_PYQUEST):
r"""Error on qubit defined by three Pauli operator weights
Args:
qureg: a qureg containing a density matrix
qubit: The qubit the Pauli operators are acting on
probX: The probability that Pauli X is acting on qubit as Kraus operator
probY: The probability that Pauli Y is acting on qubit as Kraus operator
probZ: The probability that Pauli Z is acting on qubit as Kraus operator
"""
[docs] def call_interactive(self, qureg: tqureg,
qubit: int,
probX: float,
probY: float,
probZ: float,
) -> None:
r"""Interactive call of PyQuest-cffi
Args:
qureg: a qureg containing a density matrix
qubit: The qubit the Pauli operators are acting on
probX: The probability that Pauli X is acting on qubit as Kraus operator
probY: The probability that Pauli Y is acting on qubit as Kraus operator
probZ: The probability that Pauli Z is acting on qubit as Kraus operator
"""
quest.mixPauli(
qureg,
qubit,
probX,
probY,
probZ)
[docs] def Kraus_matrices(self,
probX: float,
probY: float,
probZ: float,
**kwargs) -> List[np.ndarray]:
r"""The definition of the Kraus Operator as a matrix
Args:
probX: The probability that Pauli X is acting on qubit as Kraus operator
probY: The probability that Pauli Y is acting on qubit as Kraus operator
probZ: The probability that Pauli Z is acting on qubit as Kraus operator
**kwargs: Additional keyword arguments
Returns:
Tuple[np.ndarray]
"""
operators = [None, None, None]
operators[0] = probX * np.array([[0, 1], [1, 0]], dtype=complex)
operators[1] = probY * np.array([[0, -1j], [1j, 0]], dtype=complex)
operators[2] = probZ * np.array([[1, 0], [0, -1]], dtype=complex)
return operators
[docs] def superoperator_matrix(self,
probX: float,
probY: float,
probZ: float,
**kwargs) -> np.ndarray:
r"""The definition of the superoperator acting on the density matrix written as a vector
Args:
probX: The probability that Pauli X is acting on qubit as Kraus operator
probY: The probability that Pauli Y is acting on qubit as Kraus operator
probZ: The probability that Pauli Z is acting on qubit as Kraus operator
**kwargs: Additional keyword arguments
Returns:
np.ndarray
"""
operators = self.Kraus_matrices(probX, probY, probZ)
matrix = np.zeros((2 * operators[0].shape[0], 2 * operators[0].shape[0]), dtype=complex)
for op in operators:
matrix += np.kron(op, op.conjugate().T)
return matrix