Skip to content

Commit f5b8b47

Browse files
amiccicheKrastanov
andauthored
beginning of biased pauli noise for PF sim (#295)
Co-authored-by: Stefan Krastanov <[email protected]> Co-authored-by: Stefan Krastanov <[email protected]>
1 parent 314c0bf commit f5b8b47

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55

66
# News
77

8+
## v0.9.8 - 2024-07-24
9+
10+
- `PauliError` can now encode biased noise during Pauli frame simulation, i.e. one can simulate only X errors, or only Y errors, or only Z errors, or some weighted combination of these.
11+
812
## v0.9.7 - 2024-07-23
913

1014
- **(fix `#320`)** Fix a serious correctness bug in the SIMD implementation of Pauli string multiplication (affects the correctness of canonicalization and traceout for tableaux bigger than ~500 qubits; does not affect symbolic gates or Pauli frame simulations of any scale)
15+
1116
## v0.9.6 - 2024-07-12
1217

1318
- `inv` implementation for single-qubit "symbolic" Clifford operators (subtypes of `AbstractSingleQubitOperator`).

src/noise.jl

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ struct UnbiasedUncorrelatedNoise{T} <: AbstractNoise
2828
end
2929
UnbiasedUncorrelatedNoise(p::Integer) = UnbiasedUncorrelatedNoise(float(p))
3030

31+
"""Pauli noise model with probabilities `px`, `py`, and `pz` respectively for the three types of Pauli errors."""
32+
struct PauliNoise{T} <: AbstractNoise
33+
px::T
34+
py::T
35+
pz::T
36+
end
37+
function PauliNoise(px::Real, py::Real, pz::Real)
38+
px, py, pz = float.((px, py, pz))
39+
px, py, pz = promote(px, py, pz)
40+
T = typeof(px)
41+
return PauliNoise{T}(px, py, pz)
42+
end
43+
3144
"""A convenient constructor for various types of Pauli noise models.
3245
Returns more specific types when necessary."""
3346
function PauliNoise end
@@ -38,7 +51,6 @@ function PauliNoise(p)
3851
end
3952

4053
function applynoise!(s::AbstractStabilizer,noise::UnbiasedUncorrelatedNoise,i::Int)
41-
n = nqubits(s)
4254
infid = noise.p/3
4355
r = rand()
4456
if r<infid
@@ -51,6 +63,18 @@ function applynoise!(s::AbstractStabilizer,noise::UnbiasedUncorrelatedNoise,i::I
5163
s
5264
end
5365

66+
function applynoise!(s::AbstractStabilizer,noise::PauliNoise,i::Int)
67+
r = rand()
68+
if r<noise.px
69+
apply_single_x!(s,i)
70+
elseif r<noise.px+noise.pz
71+
apply_single_z!(s,i)
72+
elseif r<noise.px+noise.pz+noise.py
73+
apply_single_y!(s,i)
74+
end
75+
s
76+
end
77+
5478
"""An operator that applies the given `noise` model to the qubits at the selected `indices`."""
5579
struct NoiseOp{N, Q} <: AbstractNoiseOp where {N, Q}
5680
noise::N #<:AbstractNoise
@@ -74,6 +98,22 @@ function PauliError(qubits,p)
7498
NoiseOp(PauliNoise(p), qubits)
7599
end
76100

101+
""""Construct a gate operation that applies a biased Pauli error on qubit `q` with independent probabilities `px`, `py`, `pz`.
102+
Note that the probability of any error occurring is `px+py+pz`. Because of this, `PauliError(1, p)` is equivalent to `PauliError(1,p/3,p/3,p/3)`.
103+
Similarly, if one wanted to exclude Z errors from `PauliError(1,p/3,p/3,p/3)` while mainting the same rate of X errors, one could write
104+
`PauliError(1, p*2/3, 0, 0)` (in the sense that Y errors can be interpreted as an X and a Z happening at the same time)."""
105+
function PauliError(q::Int, px, py, pz)
106+
NoiseOp(PauliNoise(px,py,pz), (q,))
107+
end
108+
109+
""""Construct a gate operation that applies a biased Pauli error on all `qubits` independently, each with probabilities `px`, `py`, `pz`.
110+
Note that the probability of any error occurring is `px+py+pz`. Because of this, `PauliError(1, p)` is equivalent to `PauliError(1,p/3,p/3,p/3)`.
111+
Similarly, if one wanted to exclude Z errors from `PauliError(1,p/3,p/3,p/3)` while mainting the same rate of X errors, one could write
112+
`PauliError(1, p*2/3, 0, 0)` (in the sense that Y errors can be interpreted as an X and a Z happening at the same time)."""
113+
function PauliError(qubits, px, py, pz)
114+
NoiseOp(PauliNoise(px,py,pz), qubits)
115+
end
116+
77117
"""An operator that applies the given `noise` model to all qubits."""
78118
struct NoiseOpAll <: AbstractNoiseOp
79119
noise::AbstractNoise

src/pauli_frames.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,28 @@ function applynoise!(frame::PauliFrame,noise::UnbiasedUncorrelatedNoise,i::Int)
144144
return frame
145145
end
146146

147+
function applynoise!(frame::PauliFrame,noise::PauliNoise,i::Int)
148+
T = eltype(frame.frame.tab.xzs)
149+
150+
lowbit = T(1)
151+
ibig = _div(T,i-1)+1
152+
ismall = _mod(T,i-1)
153+
ismallm = lowbit<<(ismall)
154+
155+
@inbounds @simd for f in eachindex(frame)
156+
r = rand()
157+
if r < noise.px # X error
158+
frame.frame.tab.xzs[ibig,f] ⊻= ismallm
159+
elseif r < noise.px+noise.pz # Z error
160+
frame.frame.tab.xzs[end÷2+ibig,f] ⊻= ismallm
161+
elseif r < noise.px+noise.pz+noise.py # Y error
162+
frame.frame.tab.xzs[ibig,f] ⊻= ismallm
163+
frame.frame.tab.xzs[end÷2+ibig,f] ⊻= ismallm
164+
end
165+
end
166+
return frame
167+
end
168+
147169
"""
148170
Perform a "Pauli frame" style simulation of a quantum circuit.
149171
"""

src/sumtypes.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,10 @@ function concrete_typeparams(t::Type{ClassicalXOR})
217217
end
218218

219219
function concrete_typeparams(t::Type{NoiseOp})
220-
return [(UnbiasedUncorrelatedNoise{Float64}, i) for i in 1:8]
220+
return [
221+
[(UnbiasedUncorrelatedNoise{Float64}, i) for i in 1:8];
222+
[(PauliNoise{Float64}, i) for i in 1:8];
223+
]
221224
end
222225

223226

0 commit comments

Comments
 (0)