Prev Tutorial: State Vector
Next Tutorial: Choi
Introduction
Kraus representation of a quantum channel.
For a quantum channel
\[
\mathcal{E}(\rho)=\sum_{i=0}^{K-1} A_{i} \rho A_{i}^{\dagger}
\]
, the Kraus representation is given by a set of matrices
\[
\left[A_{0}, \ldots, A_{K-1}\right]
\]
such that the evolution of a DensityMatrix \( \rho\) is given by
\[
\mathcal{E}(\rho)=\sum_{i=0}^{K-1} A_{i} \rho A_{i}^{\dagger}
\]
A general operator map \(\mathcal{G}\) can also be written using the generalized Kraus representation which is given by two sets of matrices \(
\left[A_{0}, \ldots, A_{K-1}\right]
\) , \(\left[B_{0}, \ldots, B_{B-1}\right]
\) such that
\[
\mathcal{G}(\rho)=\sum_{i=0}^{K-1} A_{i} \rho B_{i}^{\dagger}
\]
Please refer: C.J. Wood, J.D. Biamonte, D.G. Cory, Tensor networks and graphical calculus for open quantum systems, Quant. Inf. Comp. 15, 0579-0811 (2015).arXiv:1111.6950 [quant-ph]
In QPanda3 Quantum Information
Constructing a Kraus object
Here is API doc
Default constructor
Generate a Kraus object without elements
Python
Kra1 = Kraus()
print("Kra1:", Kra1)
Output
Kra1: {Kraus:
{Kraus_left:
}
,
{Kraus_right:
}
}
From 2D matrix array
Construct a Kraus object from the array of the 2-dimensional matrix of the operator list.
The left operator list of the generated Kraus object is constructed from the input matrix array, and the right operator list is empty
Python
import numpy as np
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Kra2 = Kraus(Ks1)
print("Kra2:", Kra2)
Output
Kra2: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
}
,
{Kraus_right:
}
}
From 2 operator lists
Construct a Kraus object from the array of two operator lists in a 2-dimensional matrix
The left operator list of the generated Kraus object is constructed from the first input array
The right operator list of the generated Kraus object is constructed from the second input array
Python
import numpy as np
def test_construct():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
print("Kra3:", Kra3)
if __name__ == "__main__":
test_construct()
Output
Kra3: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
}
,
{Kraus_right:
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
}
From 2D matrix
Construct Kraus objects from a 2-dimensional matrix of operators
The left operator list of the generated Kraus object is constructed from the input
The right operator list of the generated Kraus object is empty
Python
import numpy as np
def test_construct():
K0 = np.array([[0, 1], [1+0.j, 0]])
Kra4 = Kraus(K0)
print("Kra4:", Kra4)
if __name__ == "__main__":
test_construct()
Output
Kra4: {Kraus:
{Kraus_left:
{
{
{(0,0)},
}
{
{(1,0)},
}
}
,
{
{
{(1,0)},
}
{
{(0,0)},
}
}
}
,
{Kraus_right:
}
}
From Kraus
Generate another Kraus object from a Kraus object using the copy constructor
Python
import numpy as np
def test_construct():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
Kra5 = Kra3
print("Kra5:", Kra5)
if __name__ == "__main__":
test_construct()
Output
Kra5: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
}
,
{Kraus_right:
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
}
Python
import numpy as np
def test_construct():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
Kra5 = Kraus(Kra3)
print("Kra5:", Kra5)
if __name__ == "__main__":
test_construct()
Output
Kra5: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
}
,
{Kraus_right:
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
}
From Choi
Generate another Kraus object from a Choi object
Please refer to Choi
Python
import numpy as np
def test_construct_from_choi():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K1]
Kra3 = Kraus(Ks1, Ks2)
choi = Choi(Kra3)
Kra4= Kraus(choi)
print("Kra4:",Kra4)
if __name__ == "__main__":
test_construct_from_choi()
Output
Kra4: {Kraus:
{Kraus_left:
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1.41421,0)},
}
{
{(0,0)},{(0,0)},
}
}
,
{
{
{(0,0)},{(0,0)},
}
{
{(1.41421,0)},{(0,0)},
}
}
}
,
{Kraus_right:
}
}
From Chi
Generate another Kraus object from a Chi object
Please refer to Chi
Python
import numpy as np
def test_construct_from_chi():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K1]
Kra3 = Kraus(Ks1, Ks2)
chi = Chi(Kra3)
Kra4= Kraus(chi)
print("Kra4:",Kra4)
if __name__ == "__main__":
test_construct_from_chi()
Output
Kra4: {Kraus:
{Kraus_left:
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1.41421,0)},
}
{
{(0,0)},{(0,0)},
}
}
,
{
{
{(0,0)},{(0,0)},
}
{
{(1.41421,0)},{(0,0)},
}
}
}
,
{Kraus_right:
}
}
From SuperOp
Generate another Kraus object from a SuperOp object
Please refer to SuperOp
Python
import numpy as np
def test_construct_from_superop():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K1]
Kra3 = Kraus(Ks1, Ks2)
sop = SuperOp(Kra3)
Kra4= Kraus(sop)
print("Kra4:",Kra4)
if __name__ == "__main__":
test_construct_from_superop()
Output
Kra4: {Kraus:
{Kraus_left:
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1.41421,0)},
}
{
{(0,0)},{(0,0)},
}
}
,
{
{
{(0,0)},{(0,0)},
}
{
{(1.41421,0)},{(0,0)},
}
}
}
,
{Kraus_right:
}
}
From PTM
Generate another Kraus object from a PTM object
Please refer to PTM
Python
import numpy as np
def test_construct_from_ptm():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K1]
Kra3 = Kraus(Ks1, Ks2)
ptm = PTM(Kra3)
Kra4= Kraus(ptm)
print("Kra4:",Kra4)
if __name__ == "__main__":
test_construct_from_ptm()
Output
Kra4: {Kraus:
{Kraus_left:
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1.41421,0)},
}
{
{(0,0)},{(0,0)},
}
}
,
{
{
{(0,0)},{(0,0)},
}
{
{(1.41421,0)},{(0,0)},
}
}
}
,
{Kraus_right:
}
}
Obtain internal data
Input and output dim
Get the input dimension input_dim and output dimension output_dim corresponding to the Kraus object
The output dimension should be equal to the number of rows in the matrix
The input dimension should be equal to the number of columns in the matrix
Currently, the implementation requires that the matrix must be a square matrix, so the input and output dimensions should be equal
Here is API doc for Kraus.get_input_dim
Here is API doc for Kraus.get_output_dim
Python
import numpy as np
def test_dim():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
print("Kra3:", Kra3)
input_dim = Kra3.get_input_dim()
output_dim = Kra3.get_output_dim()
print("input_dim:",input_dim)
print("output_dim:",output_dim)
if __name__ == "__main__":
test_dim()
Output
Kra3: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
}
,
{Kraus_right:
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
}
input_dim: 2
output_dim: 2
Left operators
Get the list of left operators inside the Kraus object
The result is returned in the form of list[pyqpanda3.quantum_info.Matrix]
Here is API doc for Kraus.left
Python
import numpy as np
def test_left():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
left = Kra3.left()
for v in left:
print(v)
if __name__ == "__main__":
test_left()
Output
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
Right operators
Get the list of right operators inside the Kraus object
The result is returned in the form of list[pyqpanda3.quantum_info.Matrix]
Here is API doc for Kraus.right
Python
import numpy as np
def test_right():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
right = Kra3.right()
for v in right:
print(v)
if __name__ == "__main__":
test_right()
Output
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
Modify internal data
Clear internal data
Here is API doc for Kraus.clear
Python
import numpy as np
def test_clear():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
Kra3.clear()
print("Kra3:",Kra3)
if __name__ == "__main__":
test_clear()
Output
Kra3: {Kraus:
{Kraus_left:
}
,
{Kraus_right:
}
}
Append Kraus
Append the internal data of another Kraus object to the end of the internal data of the current Kraus object
The matrix inside the other Kraus object should have the same shape as the current Kraus object's internal matrix
Here is API doc for Kraus.append
Python
import numpy as np
def test_append():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
Kra3.append(Kra3)
print("Kra3:",Kra3)
if __name__ == "__main__":
test_append()
Output
Kra3: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
,
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
}
,
{Kraus_right:
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
,
{
{
{(0,0)},{(-0,-1)},
}
{
{(0,1)},{(0,0)},
}
}
,
{
{
{(1,0)},{(0,0)},
}
{
{(0,0)},{(-1,0)},
}
}
,
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
}
Add Matrix object to left
Add the data in the Matrix object to the end of the internal left operator list of the Kraus object
The Matrix object should have the same shape as the internal matrix of the current Kraus object
Here is API doc for Kraus.left_push_back
Python
import numpy as np
def test_push_back():
K0 = np.array([[0, 1], [1+0.j, 0]])
Kra3 = Kraus()
Kra3.left_push_back(Matrix(K0))
print("Kra3:",Kra3)
if __name__ == "__main__":
test_push_back()
Output
Kra3: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
,
{Kraus_right:
}
}
Add Matrix object to right
Add the data in the Matrix object to the end of the internal right operator list of the Kraus object
The Matrix object should have the same shape as the internal matrix of the current Kraus object
Here is API doc for Kraus.right_push_back
Python
import numpy as np
def test_push_back():
K0 = np.array([[0, 1], [1+0.j, 0]])
Kra3 = Kraus()
Kra3.right_push_back(Matrix(K0))
print("Kra3:",Kra3)
if __name__ == "__main__":
test_push_back()
Output
Kra3: {Kraus:
{Kraus_left:
}
,
{Kraus_right:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
}
Append numpy.ndarray to left
Append the data from the numpy.ndarray object representing a two-dimensional array to the end of the internal left operator list within the Kraus object
The numpy.ndarray object representing a two-dimensional array should have the same shape as the internal matrix of the current Kraus object
Here is API doc for Kraus.left_push_back
Python
import numpy as np
def test_push_back2():
K0 = np.array([[0, 1], [1+0.j, 0]])
Kra3 = Kraus()
Kra3.left_push_back(K0)
print("Kra3:",Kra3)
if __name__ == "__main__":
test_push_back2()
Output
Kra3: {Kraus:
{Kraus_left:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
,
{Kraus_right:
}
}
Append numpy.ndarray to right
Append the data from the numpy.ndarray object representing a two-dimensional array to the end of the internal right operator list within the Kraus object
The numpy.ndarray object representing a two-dimensional array should have the same shape as the internal matrix of the current Kraus object
Here is API doc for Kraus.right_push_back
Python
import numpy as np
def test_push_back2():
K0 = np.array([[0, 1], [1+0.j, 0]])
Kra3 = Kraus()
Kra3.right_push_back(K0)
print("Kra3:",Kra3)
if __name__ == "__main__":
test_push_back2()
Output
Kra3: {Kraus:
{Kraus_left:
}
,
{Kraus_right:
{
{
{(0,0)},{(1,0)},
}
{
{(1,0)},{(0,0)},
}
}
}
}
Evolution of quantum states
Here is API doc for Kraus.evolve
DensityMatrix
Evolution of a DensityMatrix object, and the evolution result is returned as a DensityMatrix object
The dimension of the density matrix is obtained by the member method dim() and should be equal to the input dimension of the Kraus object
Please refer to DensityMatrix.
Python
import numpy as np
import math
def test_evolve():
data = np.array(
[[0.69272168 + 0.j, 0.38338527 - 0.17772383j],
[0.38338527 + 0.17772383j, 0.30727832 + 0.j]]
)
dm = DensityMatrix(data)
K0 = np.array([[0, 1 + 0.j], [1, 0]])
K1 = np.array([[0, 0. - 1.j], [0. + 1.j, 0]])
K2 = np.array([[1, 1], [1, -1 + 0.j]]) / math.sqrt(2)
Ks1 = [K0, K1, K2]
Kra3 = Kraus(Ks1)
res = Kra3.evolve(dm)
print("res:", res)
if __name__ == "__main__":
test_evolve()
Output
res: {
{
{(1.49794,0)},{(0.192722,0.177724)},
}
{
{(0.192722,-0.177724)},{(1.50206,0)},
}
}
StateVector
Evolution of the StateVector object is performed, and the result is returned as a DensityMatrix object
The dimension of the StateVector object is obtained by the member method dim() and should be equal to the input dimension of the Kraus object
Please refer to DensityMatrix.
Please refer to StateVector
Python
import numpy as np
import math
def test_evolve():
stv = StateVector()
K0 = np.array([[0, 1+0.j], [1, 0]])
K1 = np.array([[0, 0.-1.j], [0.+1.j, 0]])
K2 = np.array([[1, 1], [1, -1+0.j]])/math.sqrt(2)
Ks1 = [K0, K1, K2]
Kra3 = Kraus(Ks1)
res = Kra3.evolve(stv)
print("res:",res)
if __name__ == "__main__":
test_evolve()
Output
res: {
{
{(0.5,0)},{(0.5,0)},
}
{
{(0.5,0)},{(2.5,0)},
}
}
Boolean function
Equal
Determine whether the internal data of two Kraus objects are equal
Here is API doc
Python
import numpy as np
def test_equal():
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
Ks2 = [K2, K1, K0]
Kra3 = Kraus(Ks1, Ks2)
Kra4 = Kra3
print(Kra4 == Kra3)
if __name__ == "__main__":
test_equal()
Output