Skip to content

Commit 4fdbb18

Browse files
YipiaoWuYipiaoKrastanov
authored
define BellSwap, NoisyBellSwap and T1NoiseOp (#23)
Co-authored-by: Yipiao <[email protected]> Co-authored-by: Stefan Krastanov <[email protected]>
1 parent cf6575d commit 4fdbb18

File tree

12 files changed

+311
-38
lines changed

12 files changed

+311
-38
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ LocalPreferences.toml
44
*/.*swp
55
scratch/
66
*.cov
7+
.history
8+
.vscode

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## v1.2.0 - 2024-11-04
2+
3+
- Implementing convenience constructors for T1 and T2 noise (`T1NoiseOp` and `T2NoiseOp`)
4+
- Implementing a bilateral swap gate `BellSwap`
5+
6+
## Older - before 2024-11-04 unrecorded

Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "BPGates"
22
uuid = "2c1a90cd-bec4-4415-ae35-245016909a8f"
3-
authors = ["Shu Ge <[email protected]>", "Stefan Krastanov <[email protected]>"]
4-
version = "1.1.0"
3+
authors = ["Shu Ge <[email protected]>", "Stefan Krastanov <[email protected]>", "BPGates contributors"]
4+
version = "1.2.0"
55

66
[deps]
77
QuantumClifford = "0525e862-1e90-11e9-3e4d-1b39d7109de1"
@@ -15,6 +15,6 @@ BPGatesQuantikzExt = "Quantikz"
1515

1616
[compat]
1717
Quantikz = "1.3.1"
18-
QuantumClifford = "0.8, 0.9"
18+
QuantumClifford = "0.9"
1919
Random = "1"
2020
julia = "1.9"

src/BPGates.jl

Lines changed: 142 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@ export BellState,
99
BellSinglePermutation, BellDoublePermutation, BellPauliPermutation,
1010
BellMeasure, bellmeasure!,
1111
BellGate, CNOTPerm, GoodSingleQubitPerm,
12-
PauliNoiseOp, PauliNoiseBellGate, NoisyBellMeasure, NoisyBellMeasureNoisyReset
12+
PauliNoiseOp, PauliNoiseBellGate, NoisyBellMeasure, NoisyBellMeasureNoisyReset,
13+
BellSwap, NoisyBellSwap
1314

14-
function int_to_bit(int,digits)
15+
const IT = Union{Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64}
16+
17+
function int_to_bit(int::IT,digits)
1518
int = int - 1 # -1 so that we use julia indexing conventions
1619
Bool[int>>shift&0x1 for shift in 0:digits-1]
1720
end
18-
@inline function int_to_bit(int,::Val{2}) # faster if we know we need only two bits
21+
@inline function int_to_bit(int::IT,::Val{2}) # faster if we know we need only two bits
1922
int = int - 1 # -1 so that we use julia indexing conventions
2023
int & 0x1, int>>1 & 0x1
2124
end
22-
@inline function int_to_bit(int,::Val{4}) # faster if we know we need only two bits
25+
@inline function int_to_bit(int::IT,::Val{4}) # faster if we know we need only two bits
2326
int = int - 1 # -1 so that we use julia indexing conventions
2427
int & 0x1, int>>1 & 0x1, int>>2 & 0x1, int>>3 & 0x1
2528
end
@@ -367,6 +370,27 @@ function QuantumClifford.apply!(state::BellState, g::BellGate)
367370
return state
368371
end
369372

373+
##############################
374+
# SWAP gate
375+
##############################
376+
377+
"""SWAP gate"""
378+
struct BellSwap <: BellOp
379+
idx1::Int
380+
idx2::Int
381+
end
382+
383+
function QuantumClifford.apply!(state::BellState, op::BellSwap)
384+
phase = state.phases
385+
@inbounds temp1 = phase[op.idx1*2-1]
386+
@inbounds temp2 = phase[op.idx1*2]
387+
@inbounds phase[op.idx1*2-1] = phase[op.idx2*2-1]
388+
@inbounds phase[op.idx1*2] = phase[op.idx2*2]
389+
@inbounds phase[op.idx2*2-1] = temp1
390+
@inbounds phase[op.idx2*2] = temp2
391+
return state
392+
end
393+
370394
##############################
371395
# Typically good operations
372396
##############################
@@ -518,6 +542,112 @@ function QuantumClifford.apply!(state::BellState, g::PauliNoiseOp)
518542
return state
519543
end
520544

545+
"""Simulates bilateral twirled T1 noise with per-qubit Kraus ops `|0⟩⟨0| + √(1-λ) |1⟩⟨1|` and `√λ |0⟩⟨1|`"""
546+
struct T1NoiseOp <: BellOp
547+
idx::Int
548+
λ₁::Float64
549+
end
550+
551+
function QuantumClifford.apply!(state::BellState, g::T1NoiseOp)
552+
phase = state.phases
553+
input_state = bit_to_int(phase[g.idx*2-1],phase[g.idx*2]) # this is my initial state
554+
555+
r = rand()
556+
λ₁ = g.λ₁
557+
558+
output_state = if input_state==1
559+
if r < 0.5*λ₁^2 - λ₁ + 1
560+
1
561+
elseif r < 0.5*λ₁^2 - λ₁ + 1 + 0.5*λ₁^2
562+
2 # XXX
563+
elseif r < 0.5*λ₁^2 - λ₁ + 1 + 0.5*λ₁^2 + 0.5*λ₁*(1-λ₁)
564+
3 # XXX
565+
else # r < 1 = 0.5*λ₁^2 - λ₁ + 1 + 0.5*λ₁*(1-λ₁) + 0.5*λ₁^2 + 0.5*λ₁*(1-λ₁)
566+
4
567+
end
568+
elseif input_state==2
569+
if r < 0.5*λ₁^2
570+
1
571+
elseif r < 0.5*λ₁^2 + 0.5*λ₁^2 -λ₁ + 1
572+
2 # XXX
573+
elseif r < 0.5*λ₁^2 + 0.5*λ₁^2 -λ₁ + 1 + 0.5*λ₁*(1-λ₁)
574+
3 # XXX
575+
else # r < 1 = 0.5*λ₁^2 + 0.5*λ₁^2 -λ₁ + 1 + 0.5*λ₁*(1-λ₁) + 0.5*λ₁*(1-λ₁)
576+
4
577+
end
578+
elseif input_state==3
579+
if r < 0.5*λ₁
580+
1
581+
elseif r < 0.5*λ₁ + 0.5*λ₁
582+
2 # XXX
583+
elseif r < 0.5*λ₁ + 0.5*λ₁ + (1-λ₁)
584+
3 # XXX
585+
else # r < 1 = 0.5*λ₁ + 0.5*λ₁ + (1-λ₁) + 0
586+
4
587+
end
588+
else # input_state==4
589+
if r < 0.5*λ₁
590+
1
591+
elseif r < 0.5*λ₁ + 0.5*λ₁
592+
2 # XXX
593+
# elseif r < 0.5*λ₁ + 0.5*λ₁ + 0 # output_state 3 is never reached
594+
# 3 # XXX
595+
else # r < 1 = 0.5*λ₁ + 0.5*λ₁ + 0 + 1-λ₁
596+
4
597+
end
598+
end
599+
600+
bit1, bit2 = int_to_bit(output_state, Val(2))
601+
@inbounds phase[g.idx*2-1] = bit1
602+
@inbounds phase[g.idx*2] = bit2
603+
return state
604+
end
605+
606+
"""Simulates bilateral T2 noise with per-qubit Kraus ops `√(1-λ/2) I` and `√(λ/2) Z`"""
607+
struct T2NoiseOp <: BellOp
608+
idx::Int
609+
λ₂::Float64
610+
end
611+
612+
function QuantumClifford.apply!(state::BellState, g::T2NoiseOp)
613+
phase = state.phases
614+
input_state = bit_to_int(phase[g.idx*2-1],phase[g.idx*2]) # this is my initial state
615+
616+
r = rand()
617+
λ₂ = g.λ₂
618+
619+
output_state = if input_state==1
620+
if r < 0.5*λ₂^2 - λ₂ + 1
621+
1
622+
else # r < 1 = 0.5*λ₂^2 - λ₂ + 1 + 0.5*λ₂*(2-λ₂)
623+
2
624+
end
625+
elseif input_state==2
626+
if r < 0.5*λ₂^2 - λ₂ + 1
627+
2
628+
else # r < 1 = 0.5*λ₂^2 - λ₂ + 1 + 0.5*λ₂*(2-λ₂)
629+
1
630+
end
631+
elseif input_state==3
632+
if r < 0.5*λ₂^2 - λ₂ + 1
633+
3
634+
else # r < 1 = 0.5*λ₂^2 - λ₂ + 1 + 0.5*λ₂*(2-λ₂)
635+
4
636+
end
637+
else # input_state==4
638+
if r < 0.5*λ₂^2 - λ₂ + 1
639+
4
640+
else # r < 1 = 0.5*λ₂^2 - λ₂ + 1 + 0.5*λ₂*(2-λ₂)
641+
3
642+
end
643+
end
644+
645+
bit1, bit2 = int_to_bit(output_state, Val(2))
646+
@inbounds phase[g.idx*2-1] = bit1
647+
@inbounds phase[g.idx*2] = bit2
648+
return state
649+
end
650+
521651
"""A wrapper for [`BellMeasure`](@ref) that implements measurement noise."""
522652
struct NoisyBellMeasure <: BellOp # TODO make it work with the QuantumClifford noise ops
523653
m::BellMeasure
@@ -545,6 +675,11 @@ function QuantumClifford.applywstatus!(state::BellState, op::NoisyBellMeasureNoi
545675
state, cont ? continue_stat : failure_stat
546676
end
547677

678+
function NoisyBellSwap(idx1,idx2,px,py,pz)
679+
return PauliNoiseBellGate(BellSwap(idx1,idx2), px,py,pz)
680+
end
681+
682+
548683
##############################
549684
# Random
550685
##############################
@@ -703,12 +838,12 @@ function toBPpermutation1(circ) # this one works only on single pair mappings th
703838
end
704839

705840
function BellState(s::Stabilizer)
706-
r, c = size(s)
841+
r, c = size(s)::Tuple{Int, Int}
707842
r==c || throw(ArgumentError("Conversion to `BellState` failed. The stabilizer state has to be square in order to be convertible to a `BellState`."))
708-
s = canonicalize_rref!(copy(s))[1][end:-1:1]
843+
s = canonicalize_rref!(copy(s))[1][end:-1:1]::Stabilizer
709844
bits = Bool[]
710845
for i in 1:r÷2
711-
j = 2i-1
846+
j = (2i-1)
712847
s[j ,j] == s[j ,j+1] == (true, false) && all(==((false,false)), (s[j ,k] for k in 1:c if k!=j && k!=j+1)) || throw(ArgumentError(lazy"Conversion to `BellState` failed. Row $(j ) of the stabilizer state has to be of the form `..._XX_...` for it to be a valid `BellState`"))
713848
s[j+1,j] == s[j+1,j+1] == (false, true) && all(==((false,false)), (s[j+1,k] for k in 1:c if k!=j && k!=j+1)) || throw(ArgumentError(lazy"Conversion to `BellState` failed. Row $(j+1) row of the stabilizer state has to be of the form `..._ZZ_...` for it to be a valid `BellState`"))
714849
push!(bits, s.tab.phases[j]÷2)

test/Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
88
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
99
Quantikz = "b0d11df0-eea3-4d79-b4a5-421488cbf74b"
1010
QuantumClifford = "0525e862-1e90-11e9-3e4d-1b39d7109de1"
11+
QuantumOpticsBase = "4f57444f-1401-5e15-980d-4471b28d5678"
1112
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
12-
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
1313
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
1414
Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
1515
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
16+
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"

test/runtests.jl

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,20 @@
1-
using SafeTestsets
21
using BPGates
2+
using TestItemRunner
33

4-
function doset(descr)
5-
if length(ARGS) == 0
6-
return true
7-
end
8-
for a in ARGS
9-
if occursin(lowercase(a), lowercase(descr))
10-
return true
11-
end
12-
end
13-
return false
14-
end
4+
# filter for the test
5+
testfilter = ti -> begin
6+
exclude = Symbol[]
7+
if get(ENV,"JET_TEST","")!="true"
8+
push!(exclude, :jet)
9+
end
10+
if !(VERSION >= v"1.10")
11+
push!(exclude, :doctests)
12+
push!(exclude, :aqua)
13+
end
1514

16-
macro doset(descr)
17-
quote
18-
if doset($descr)
19-
@safetestset $descr begin include("test_"*$descr*".jl") end
20-
end
21-
end
15+
return all(!in(exclude), ti.tags)
2216
end
2317

2418
println("Starting tests with $(Threads.nthreads()) threads out of `Sys.CPU_THREADS = $(Sys.CPU_THREADS)`...")
2519

26-
@doset "quantumclifford"
27-
@doset "quantikz"
28-
get(ENV,"JET_TEST","")=="true" && @doset "jet"
29-
@doset "doctests"
30-
31-
using Aqua
32-
doset("aqua") && begin
33-
Aqua.test_all(BPGates)
34-
end
20+
@run_package_tests filter=testfilter

test/test_aqua.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@testitem "Aqua analysis" begin
2+
3+
using Aqua, BPGates
4+
5+
Aqua.test_all(BPGates)
6+
7+
end

test/test_doctests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
@testitem "doctests" begin
2+
13
using Documenter
24
using BPGates
35

46
DocMeta.setdocmeta!(BPGates, :DocTestSetup, :(using QuantumClifford, BPGates); recursive=true)
57
doctest(BPGates)
8+
9+
end

test/test_jet.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@testitem "JET analysis" tags=[:jet] begin
2+
13
using JET
24
using Test
35
using BPGates
@@ -9,3 +11,5 @@ rep = report_package("BPGates";
911
)
1012
@show rep
1113
@test length(JET.get_reports(rep)) == 0
14+
15+
end

test/test_quantikz.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@testitem "Quantikz circuit plotting" begin
2+
13
using BPGates
24
using Quantikz
35
using Test
@@ -6,3 +8,5 @@ using Test
68
quantikz_circ = Quantikz.QuantikzOp.([BellSinglePermutation(2,2), BellDoublePermutation(1,2,3), BellPauliPermutation(4,1), BellMeasure(3,1), BellGate(1,1,1,1,1,1,2), CNOTPerm(1,2,3,4), GoodSingleQubitPerm(1,2), PauliNoiseOp(1,0.0,0.0,0.0), PauliNoiseBellGate(CNOTPerm(1,2,3,4),0.0,0.0,0.0), NoisyBellMeasure(BellMeasure(1,2),0.0), NoisyBellMeasureNoisyReset(BellMeasure(1,2),0.0,0.0,0.0,0.0)])
79
img = Quantikz.circuit2image(quantikz_circ)
810
end
11+
12+
end

0 commit comments

Comments
 (0)