/
error_channel.jl
111 lines (89 loc) · 2.74 KB
/
error_channel.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""
pauli_error_channel(; px::Real, py::Real=px, pz::Real=px)
Create the Pauli error channel as a [`UnitaryChannel`](@ref)
```math
(1 - (p_x + p_y + p_z))⋅ρ + p_x⋅XρX + p_y⋅YρY + p_z⋅ZρZ
```
"""
function pauli_error_channel(; px::Real, py::Real=px, pz::Real=px)
pz + px + py ≤ 1 || throw(ArgumentError("sum of error probability is larger than 1"))
return UnitaryChannel(
[I2, X, Y, Z],
[1-(px+py+pz), px, py, pz],
)
end
"""
bit_flip_channel(p::Real)
Create a bit flip channel as a [`UnitaryChannel`](@ref).
```math
(1-p)⋅ρ + p⋅XρX
```
"""
function bit_flip_channel(p::Real)
return unitary_channel([I2, X], [1-p, p])
end
"""
phase_flip_channel(::Real)
Create a phase flip channel as [`UnitaryChannel`](@ref).
```math
(1-p)⋅ρ + p⋅ZρZ
```
"""
function phase_flip_channel(p::Real)
return UnitaryChannel([I2, Z], [1-p, p])
end
struct DepolarizingChannel{T} <: PrimitiveBlock{2}
n::Int # n is not necessary but this is required by a block
p::T
end
YaoAPI.nqudits(ch::DepolarizingChannel) = ch.n
function YaoAPI.unsafe_apply!(dm::DensityMatrix, ch::DepolarizingChannel)
regscale!(dm, 1 - ch.p)
dm.state .+= ch.p/(2^nqubits(dm)) * IMatrix(size(dm.state, 1))
return dm
end
"""
depolarizing_channel(n::Int; p::Real)
Create a global depolarizing channel.
### Arguments
- `n`: number of qubits.
### Keyword Arguments
- `p`: probability of this error to occur.
### See also
[`single_qubit_depolarizing_channel`](@ref) and [`two_qubit_depolarizing_channel`](@ref)
for depolarizing channels acting on only one or two qubits.
"""
function depolarizing_channel(n::Int; p::Real)
return DepolarizingChannel(n, p)
end
"""
single_qubit_depolarizing_channel(p::Real)
Create a single-qubit depolarizing channel.
The factor of 3/4 in front of p ensures that
`single_qubit_depolarizing_channel(p) == depolarizing_channel(1, p)`
```math
(1 - 3p/4 ⋅ρ) + p/4⋅(XρX + YρY + ZρZ)
```
"""
function single_qubit_depolarizing_channel(p::Real)
return pauli_error_channel(px=p/4, py=p/4, pz=p/4)
end
"""
two_qubit_depolarizing_channel(p::Real)
Create a two-qubit depolarizing channel. Note that this is not the same
as `kron(single_qubit_depolarizing_channel(p), single_qubit_depolarizing_channel(p))`.
"""
function two_qubit_depolarizing_channel(p::Real)
return UnitaryChannel(
[kron(I2, I2), kron(I2, X), kron(I2, Y), kron(I2, Z),
kron(X, I2), kron(X, X), kron(X, Y), kron(X, Z),
kron(Y, I2), kron(Y, X), kron(Y, Y), kron(Y, Z),
kron(Z, I2), kron(Z, X), kron(Z, Y), kron(Z, Z),
],
[1-15p/16, p/16, p/16, p/16,
p/16, p/16, p/16, p/16,
p/16, p/16, p/16, p/16,
p/16, p/16, p/16, p/16,
],
)
end