From 5acfeb6d515cb549625332855a0c14c686ef7717 Mon Sep 17 00:00:00 2001 From: Tommy Hofmann Date: Sat, 3 Aug 2024 19:54:47 +0200 Subject: [PATCH] Move the test runner to use TestItems.jl (#329) Co-authored-by: Stefan Krastanov --- test/Project.toml | 2 +- test/runtests.jl | 88 +---- test/test_allocations.jl | 6 +- test/test_aqua.jl | 7 +- test/test_bitpack.jl | 81 +++-- test/test_classicalreg.jl | 48 +-- test/test_cliff.jl | 182 +++++----- test/test_doctests.jl | 19 +- test/test_ecc.jl | 118 +++--- test/test_ecc_bch.jl | 150 ++++---- test/test_ecc_codeproperties.jl | 62 ++-- test/test_ecc_decoder_all_setups.jl | 170 ++++----- test/test_ecc_encoding.jl | 10 +- test/test_ecc_gottesman.jl | 11 +- test/test_ecc_reedmuller.jl | 122 +++---- test/test_ecc_syndromes.jl | 80 ++-- test/test_ecc_throws.jl | 14 +- test/test_embed.jl | 5 +- test/test_entanglement.jl | 75 ++-- test/test_enumerate.jl | 4 +- test/test_expect.jl | 50 ++- test/test_gf2.jl | 47 +-- test/test_gpu.jl | 238 ++++++------ test/test_graphs.jl | 9 +- test/test_hash.jl | 4 +- test/test_inner.jl | 14 +- test/test_jet.jl | 4 +- test/test_memorylayout.jl | 7 +- test/test_mul_leftright.jl | 61 ++-- test/test_noisycircuits.jl | 522 +++++++++++++-------------- test/test_nonclifford.jl | 74 ++-- test/test_pauliframe.jl | 161 ++++----- test/test_paulis.jl | 9 +- test/test_precompile.jl | 6 +- test/test_projections.jl | 59 ++- test/test_quantumoptics.jl | 172 ++++----- test/test_random.jl | 102 +++--- test/test_stabcanon.jl | 12 +- test/test_stabs.jl | 166 ++++----- test/test_sumtypecompactification.jl | 5 +- test/test_symcliff.jl | 142 ++++---- test/test_symcontrolled.jl | 200 +++++----- test/test_syndromemeas.jl | 6 +- test/test_throws.jl | 93 +++-- test/test_trace.jl | 197 +++++----- 45 files changed, 1761 insertions(+), 1853 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index aad3cdc34..67977b460 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -22,8 +22,8 @@ QuantumOpticsBase = "4f57444f-1401-5e15-980d-4471b28d5678" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" SIMD = "fdea26ae-647d-5447-a871-4b548cad5224" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" StridedViews = "4db3bf67-4bd7-4b4e-b153-31dc3fb37143" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a" diff --git a/test/runtests.jl b/test/runtests.jl index f274479a4..9d1ee89e9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,76 +1,28 @@ -using SafeTestsets using QuantumClifford +using TestItemRunner -function doset(descr) - if length(ARGS) == 0 - return true - end - for a in ARGS - if occursin(lowercase(a), lowercase(descr)) - return true - end - end - return false -end - -macro doset(descr) - quote - if doset($descr) - @safetestset $descr begin - include("test_"*$descr*".jl") - end - end - end +if get(ENV, "GPU_TESTS", "") != "true" + println("skipping gpu tests (set GPU_TESTS=true to test gpu)") end -println("Starting tests with $(Threads.nthreads()) threads out of `Sys.CPU_THREADS = $(Sys.CPU_THREADS)`...") +# filter for the test +testfilter = ti -> begin + exclude = Symbol[] + if get(ENV,"JET_TEST","")!="true" + push!(exclude, :jet) + end + if !(VERSION >= v"1.10") + push!(exclude, :doctests) + push!(exclude, :aqua) + end + if get(ENV, "GPU_TESTS", "")!="true" + push!(exclude, :gpu) + end -# in order to run the gpu tests automatically set GPU_TESTS to true in the .env file -if get(ENV, "GPU_TESTS", "") == "true" - @doset "gpu" -else - println("skipping gpu tests (set GPU_TESTS=true to test gpu)") + return all(!in(exclude), ti.tags) end -@doset "throws" -@doset "paulis" -@doset "stabs" -@doset "stabcanon" -@doset "mul_leftright" -@doset "inner" -@doset "embed" -@doset "gf2" -@doset "projections" -@doset "expect" -@doset "trace" -@doset "cliff" -@doset "symcliff" -@doset "symcontrolled" -@doset "classicalreg" -@doset "random" -@doset "noisycircuits" -@doset "syndromemeas" -@doset "bitpack" -@doset "memorylayout" -@doset "graphs" -@doset "hash" -@doset "entanglement" -@doset "enumerate" -@doset "quantumoptics" -@doset "ecc" -@doset "ecc_codeproperties" -@doset "ecc_decoder_all_setups" -@doset "ecc_encoding" -@doset "ecc_gottesman" -@doset "ecc_reedmuller" -@doset "ecc_bch" -@doset "ecc_syndromes" -@doset "ecc_throws" -@doset "precompile" -@doset "pauliframe" -@doset "sumtypecompactification" -@doset "allocations" -VERSION >= v"1.10" && @doset "doctests" -get(ENV,"JET_TEST","")=="true" && @doset "jet" -VERSION >= v"1.10" && @doset "aqua" +println("Starting tests with $(Threads.nthreads()) threads out of `Sys.CPU_THREADS = $(Sys.CPU_THREADS)`...") + +@run_package_tests filter=testfilter diff --git a/test/test_allocations.jl b/test/test_allocations.jl index 29784fa93..51a432d21 100644 --- a/test/test_allocations.jl +++ b/test/test_allocations.jl @@ -1,7 +1,5 @@ -using QuantumClifford -using QuantumClifford: mul_left! - -@testset "Allocation checks" begin +@testitem "Allocation checks" begin + using QuantumClifford: mul_left! n = Threads.nthreads() allocated(f::F) where {F} = @allocated f() @testset "apply! mul_left! canonicalize!" begin diff --git a/test/test_aqua.jl b/test/test_aqua.jl index 1032c34f3..93c2b43be 100644 --- a/test/test_aqua.jl +++ b/test/test_aqua.jl @@ -1,3 +1,4 @@ -using Aqua -using QuantumClifford -Aqua.test_all(QuantumClifford) +@testitem "Aqua" tags=[:aqua] begin + using Aqua + Aqua.test_all(QuantumClifford) +end diff --git a/test/test_bitpack.jl b/test/test_bitpack.jl index 4b9ab5d12..d56056d61 100644 --- a/test/test_bitpack.jl +++ b/test/test_bitpack.jl @@ -1,49 +1,50 @@ -using Random -using QuantumClifford -using QuantumClifford: Tableau +@testitem "Alternative bit packing" begin + using Random + using QuantumClifford: Tableau -@testset "Alternative bit packing" begin - for n in [1,3] # can not go higher than 4 (limitation from SIMD acting on transposed/strided arrays) - N = 64*n-2 - s64 = random_stabilizer(N,N); - _phases = phases(s64); - xzs64 = tab(s64).xzs; - xzs64T = collect(xzs64')'; - p64 = random_pauli(N;nophase=true); - c64_stab = tab(random_destabilizer(N;phases=false)); + @testset "alternative bit packing" begin + for n in [1,3] # can not go higher than 4 (limitation from SIMD acting on transposed/strided arrays) + N = 64*n-2 + s64 = random_stabilizer(N,N); + _phases = phases(s64); + xzs64 = tab(s64).xzs; + xzs64T = collect(xzs64')'; + p64 = random_pauli(N;nophase=true); + c64_stab = tab(random_destabilizer(N;phases=false)); - _after_p = p64*s64 - after_p = stab_to_gf2(_after_p); - after_p_phases = phases(_after_p); - after_can = stab_to_gf2(canonicalize!(copy(s64))); - _after_clif = apply!(copy(s64),CliffordOperator(c64_stab)); - after_cliff = stab_to_gf2(_after_clif); - after_cliff_phases = phases(_after_clif); + _after_p = p64*s64 + after_p = stab_to_gf2(_after_p); + after_p_phases = phases(_after_p); + after_can = stab_to_gf2(canonicalize!(copy(s64))); + _after_clif = apply!(copy(s64),CliffordOperator(c64_stab)); + after_cliff = stab_to_gf2(_after_clif); + after_cliff_phases = phases(_after_clif); - for int in [UInt8, UInt16, UInt32, UInt64] - p = PauliOperator(p64.phase, N, collect(reinterpret(int,p64.xz))); - xzs = collect(reinterpret(int, collect(xzs64))); - xzsT = collect(xzs')'; - _s = Stabilizer(_phases,N,xzs); - _sT = Stabilizer(_phases,N,xzsT); + for int in [UInt8, UInt16, UInt32, UInt64] + p = PauliOperator(p64.phase, N, collect(reinterpret(int,p64.xz))); + xzs = collect(reinterpret(int, collect(xzs64))); + xzsT = collect(xzs')'; + _s = Stabilizer(_phases,N,xzs); + _sT = Stabilizer(_phases,N,xzsT); - for trans in (true, false) - s = trans ? _sT : _s - apply_pauli = p*s - @test after_p_phases == phases(apply_pauli) - canon = canonicalize!(deepcopy(s)) - @test after_can == stab_to_gf2(canon) + for trans in (true, false) + s = trans ? _sT : _s + apply_pauli = p*s + @test after_p_phases == phases(apply_pauli) + canon = canonicalize!(deepcopy(s)) + @test after_can == stab_to_gf2(canon) - cxzs = collect(reinterpret(int, collect(c64_stab.xzs))); - cxzsT = collect(cxzs')'; - _c = CliffordOperator(Tableau(zeros(UInt8,2N),N,cxzs)); - _cT = CliffordOperator(Tableau(zeros(UInt8,2N),N,cxzsT)); + cxzs = collect(reinterpret(int, collect(c64_stab.xzs))); + cxzsT = collect(cxzs')'; + _c = CliffordOperator(Tableau(zeros(UInt8,2N),N,cxzs)); + _cT = CliffordOperator(Tableau(zeros(UInt8,2N),N,cxzsT)); - for ctrans in (true, false) - c = ctrans ? _c : _cT - after_clifford = apply!(deepcopy(s),c) - @test after_cliff == stab_to_gf2(after_clifford) - @test after_cliff_phases == phases(after_clifford) + for ctrans in (true, false) + c = ctrans ? _c : _cT + after_clifford = apply!(deepcopy(s),c) + @test after_cliff == stab_to_gf2(after_clifford) + @test after_cliff_phases == phases(after_clifford) + end end end end diff --git a/test/test_classicalreg.jl b/test/test_classicalreg.jl index 18530fc4f..473da4109 100644 --- a/test/test_classicalreg.jl +++ b/test/test_classicalreg.jl @@ -1,27 +1,27 @@ -using Random -using QuantumClifford +@testitem "Classical" begin + using Random + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good - -n=5 -stab = random_stabilizer(n) -mdstab = MixedDestabilizer(stab) -_ = Register(stab) -reg = Register(stab, [0,0,0,0]) -regmd = Register(mdstab, [0,0,0,0]) -@test reg==regmd -@test stabilizerview(reg) == stabilizerview(mdstab) -@test destabilizerview(reg) == destabilizerview(mdstab) -@test logicalxview(reg) == logicalxview(mdstab) -@test logicalzview(reg) == logicalzview(mdstab) -@test bitview(reg) == bitview(regmd) -@test quantumstate(reg) == mdstab -for state in [mdstab,reg,regmd] - for op in [sMX(1,1),sMY(2,2),sMZ(3,3),PauliMeasurement(P"XYZZZ",4),sCNOT(1,2),sCPHASE(2,3),sCNOT(3,4),NoiseOpAll(UnbiasedUncorrelatedNoise(0.1))] - apply!(state,op) - end - for (i,proj) in enumerate([projectXrand!, projectYrand!, projectZrand!]) - proj(state, i) + n=5 + stab = random_stabilizer(n) + mdstab = MixedDestabilizer(stab) + _ = Register(stab) + reg = Register(stab, [0,0,0,0]) + regmd = Register(mdstab, [0,0,0,0]) + @test reg==regmd + @test stabilizerview(reg) == stabilizerview(mdstab) + @test destabilizerview(reg) == destabilizerview(mdstab) + @test logicalxview(reg) == logicalxview(mdstab) + @test logicalzview(reg) == logicalzview(mdstab) + @test bitview(reg) == bitview(regmd) + @test quantumstate(reg) == mdstab + for state in [mdstab,reg,regmd] + for op in [sMX(1,1),sMY(2,2),sMZ(3,3),PauliMeasurement(P"XYZZZ",4),sCNOT(1,2),sCPHASE(2,3),sCNOT(3,4),NoiseOpAll(UnbiasedUncorrelatedNoise(0.1))] + apply!(state,op) + end + for (i,proj) in enumerate([projectXrand!, projectYrand!, projectZrand!]) + proj(state, i) + end end + @test tab(canonicalize!(stabilizerview(reg))).xzs == tab(canonicalize!(stabilizerview(mdstab))).xzs end -@test tab(canonicalize!(stabilizerview(reg))).xzs == tab(canonicalize!(stabilizerview(mdstab))).xzs diff --git a/test/test_cliff.jl b/test/test_cliff.jl index 1a47e7ac5..74b1a1a46 100644 --- a/test/test_cliff.jl +++ b/test/test_cliff.jl @@ -1,107 +1,107 @@ -using Random -using QuantumClifford +@testitem "Clifford" begin + using Random + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + using QuantumClifford: mul_left! -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: mul_left! + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Low-level tableaux ops" begin - for n in test_sizes - p1 = random_pauli(n) - p11 = copy(p1) - p2 = random_pauli(n) - p3 = p2*p1 - s = Stabilizer([p1,p2]) - @test QuantumClifford._mul_left_nonvec!(copy(p1).xz,p2.xz)&3 == mul_left!(copy(p1).xz,p2.xz)&3 - @test prodphase(p2,p1) == mul_left!(p1,p2).phase[] - mul_left!(p11,s,2) - mul_left!(s,1,2) - @test p1 == p11 == p3 == s[1] - end -end -@testset "Clifford Operators" begin - @testset "Constructors" begin - @test_throws DimensionMismatch CliffordOperator(T"X") + @testset "Low-level tableaux ops" begin + for n in test_sizes + p1 = random_pauli(n) + p11 = copy(p1) + p2 = random_pauli(n) + p3 = p2*p1 + s = Stabilizer([p1,p2]) + @test QuantumClifford._mul_left_nonvec!(copy(p1).xz,p2.xz)&3 == mul_left!(copy(p1).xz,p2.xz)&3 + @test prodphase(p2,p1) == mul_left!(p1,p2).phase[] + mul_left!(p11,s,2) + mul_left!(s,1,2) + @test p1 == p11 == p3 == s[1] + end end - @testset "Permutations of qubits" begin - for c in [tCNOT, tId1⊗tHadamard, tCNOT⊗tCNOT, tensor_pow(tCNOT,6), tensor_pow(tCNOT,7), tensor_pow(tCNOT,6)⊗tPhase, tensor_pow(tCNOT,7)⊗tPhase] - for rep in 1:5 - p = randperm(nqubits(c)) - s = random_stabilizer(nqubits(c)) - @test permute(c,p)*s[:,p] == (c*s)[:,p] - end + @testset "Clifford Operators" begin + @testset "Constructors" begin + @test_throws DimensionMismatch CliffordOperator(T"X") end - for i in 1:5 - p = randperm(125) - c = rand([tId1, tHadamard, tPhase], 125) - @test ⊗(c[p]...) == permute(⊗(c...), p) + @testset "Permutations of qubits" begin + for c in [tCNOT, tId1⊗tHadamard, tCNOT⊗tCNOT, tensor_pow(tCNOT,6), tensor_pow(tCNOT,7), tensor_pow(tCNOT,6)⊗tPhase, tensor_pow(tCNOT,7)⊗tPhase] + for rep in 1:5 + p = randperm(nqubits(c)) + s = random_stabilizer(nqubits(c)) + @test permute(c,p)*s[:,p] == (c*s)[:,p] + end + end + for i in 1:5 + p = randperm(125) + c = rand([tId1, tHadamard, tPhase], 125) + @test ⊗(c[p]...) == permute(⊗(c...), p) + end end - end - @testset "Tensor products" begin - for n in test_sizes - for np in [2,3,4] - for pow in [1,2,10] - s1 = random_stabilizer(n) - sps = [random_stabilizer(np) for i in 1:pow] - ss = [s1, sps...] - c1 = random_clifford(n) - cps = repeat([random_clifford(np)],pow) - cs = [c1, cps...] - res1 = ⊗([c*s for (c,s) in zip(cs,ss)]...) - res2 = ⊗(cs...)*⊗(ss...) - res3 = (c1*s1) ⊗ (⊗(tensor_pow(cps[1],pow)) * ⊗(sps...)) - @test res1==res2==res3 + @testset "Tensor products" begin + for n in test_sizes + for np in [2,3,4] + for pow in [1,2,10] + s1 = random_stabilizer(n) + sps = [random_stabilizer(np) for i in 1:pow] + ss = [s1, sps...] + c1 = random_clifford(n) + cps = repeat([random_clifford(np)],pow) + cs = [c1, cps...] + res1 = ⊗([c*s for (c,s) in zip(cs,ss)]...) + res2 = ⊗(cs...)*⊗(ss...) + res3 = (c1*s1) ⊗ (⊗(tensor_pow(cps[1],pow)) * ⊗(sps...)) + @test res1==res2==res3 + end end end end - end - @testset "Clifford acting on Stabilizer" begin - for size in test_sizes - size < 5 && continue - s = random_stabilizer(size) - gates = vcat([tCNOT, tHadamard, tPhase], repeat([tId1],size-4)) - gates_perm = randperm(size-1) - gates = gates[gates_perm] - big_gate = reduce(⊗,gates) + @testset "Clifford acting on Stabilizer" begin + for size in test_sizes + size < 5 && continue + s = random_stabilizer(size) + gates = vcat([tCNOT, tHadamard, tPhase], repeat([tId1],size-4)) + gates_perm = randperm(size-1) + gates = gates[gates_perm] + big_gate = reduce(⊗,gates) - s1 = apply!(copy(s),big_gate) - @test stab_looks_good(s1) + s1 = apply!(copy(s),big_gate) + @test stab_looks_good(s1) - igates_perm = invperm(gates_perm) - s2 = copy(s) - canonicalize!(s2) - s2 = apply!(s2, tCNOT, [igates_perm[1],igates_perm[1]+1]) - canonicalize!(s2) - s2 = apply!(s2, tHadamard, [igates_perm[2]+(igates_perm[1]PyBeliefPropOSDecoder(c, maxiter=10)] + e = evaluate_decoder(d(c), s, 100000) + @show c + @show s + @show e + @assert max(e...) < noise/4 + end + end + end + end + + ## -include("test_ecc_base.jl") + using Test + using QuantumClifford + using QuantumClifford.ECC -@testset "table decoder, good for small codes" begin - codes = [ - all_testablable_code_instances(;maxn=10)... - ] + import PyQDecoders + import LDPCDecoders - noise = 0.001 + @testset "matching decoder, good as long as column weight of the code is limited" begin + codes = [ + Toric(8,8), + Toric(9,9), + Surface(8,8), + Surface(9,9) + ] - setups = [ - CommutationCheckECCSetup(noise), - NaiveSyndromeECCSetup(noise, 0), - ShorSyndromeECCSetup(noise, 0), - ] + noise = 0.01 - for c in codes - for s in setups - for d in [TableDecoder] - e = evaluate_decoder(d(c), s, 100000) + setups = [ + CommutationCheckECCSetup(noise), + NaiveSyndromeECCSetup(noise, 0), + ShorSyndromeECCSetup(noise, 0), + ] + + for c in codes + for s in setups + e = evaluate_decoder(PyMatchingDecoder(c), s, 10000) #@show c #@show s #@show e - @assert max(e...) < noise/4 + @assert max(e...) < noise/5 end end end end - -## - -@testset "belief prop decoders, good for sparse codes" begin - codes = [ - # TODO - ] - - noise = 0.001 - - setups = [ - CommutationCheckECCSetup(noise), - NaiveSyndromeECCSetup(noise, 0), - ShorSyndromeECCSetup(noise, 0), - ] - - for c in codes - for s in setups - for d in [c->PyBeliefPropOSDecoder(c, maxiter=10)] - e = evaluate_decoder(d(c), s, 100000) - @show c - @show s - @show e - @assert max(e...) < noise/4 - end - end - end -end - -## - -using Test -using QuantumClifford -using QuantumClifford.ECC - -import PyQDecoders -import LDPCDecoders - -@testset "matching decoder, good as long as column weight of the code is limited" begin - codes = [ - Toric(8,8), - Toric(9,9), - Surface(8,8), - Surface(9,9) - ] - - noise = 0.01 - - setups = [ - CommutationCheckECCSetup(noise), - NaiveSyndromeECCSetup(noise, 0), - ShorSyndromeECCSetup(noise, 0), - ] - - for c in codes - for s in setups - e = evaluate_decoder(PyMatchingDecoder(c), s, 10000) - #@show c - #@show s - #@show e - @assert max(e...) < noise/5 - end - end -end diff --git a/test/test_ecc_encoding.jl b/test/test_ecc_encoding.jl index ed16947de..cab0562ff 100644 --- a/test/test_ecc_encoding.jl +++ b/test/test_ecc_encoding.jl @@ -1,10 +1,10 @@ -using Test -using QuantumClifford -using QuantumClifford.ECC +@testitem "encoding circuits - compare to algebraic construction of encoded state" begin + using QuantumClifford + using QuantumClifford.ECC + + include("test_ecc_base.jl") -include("test_ecc_base.jl") -@testset "encoding circuits - compare to algebraic construction of encoded state" begin # This test verifies that logical measurements on an encoded state match the physical pre-encoded state. # This test skips verifying the permutations of qubits during canonicalization are properly undone, # i.e. we modify the code we are testing so that the canonicalization does not need any permutations. diff --git a/test/test_ecc_gottesman.jl b/test/test_ecc_gottesman.jl index e290a87f4..6f31a993c 100644 --- a/test/test_ecc_gottesman.jl +++ b/test/test_ecc_gottesman.jl @@ -1,11 +1,8 @@ -using Test -using QuantumClifford -using QuantumClifford: mul_left! -using QuantumClifford.ECC -using QuantumClifford.ECC: AbstractECC +@testitem "Gottesman codes should correct all single-qubit errors" begin + using QuantumClifford: mul_left! + using QuantumClifford.ECC + using QuantumClifford.ECC: AbstractECC - -@testset "Gottesman codes should correct all single-qubit errors" begin for j in 3:12 H = parity_checks(Gottesman(j)) syndromes = Set([]) # the set automatically removes repeated entries diff --git a/test/test_ecc_reedmuller.jl b/test/test_ecc_reedmuller.jl index 7f148a2d2..12031d71f 100644 --- a/test/test_ecc_reedmuller.jl +++ b/test/test_ecc_reedmuller.jl @@ -1,68 +1,68 @@ -using Test -using Nemo -using Combinatorics -using LinearAlgebra -using QuantumClifford -using QuantumClifford.ECC -using QuantumClifford.ECC: AbstractECC, ReedMuller +@testitem "Reed-Muller" begin + using Nemo + using Combinatorics + using LinearAlgebra + using QuantumClifford.ECC + using QuantumClifford.ECC: AbstractECC, ReedMuller -function binomial_coeff_sum(r, m) - total = 0 - for i in 0:r - total += length(combinations(1:m, i)) + function binomial_coeff_sum(r, m) + total = 0 + for i in 0:r + total += length(combinations(1:m, i)) + end + return total end - return total -end -@testset "Test RM(r, m) Matrix Rank" begin - for m in 2:5 - for r in 0:m - 1 - H = parity_checks(ReedMuller(r, m)) - mat = Nemo.matrix(Nemo.GF(2), H) - computed_rank = LinearAlgebra.rank(mat) - expected_rank = binomial_coeff_sum(r, m) - @test computed_rank == expected_rank + @testset "Test RM(r, m) Matrix Rank" begin + for m in 2:5 + for r in 0:m - 1 + H = parity_checks(ReedMuller(r, m)) + mat = Nemo.matrix(Nemo.GF(2), H) + computed_rank = LinearAlgebra.rank(mat) + expected_rank = binomial_coeff_sum(r, m) + @test computed_rank == expected_rank + end end end -end -@testset "Testing common examples of RM(r,m) codes [raaphorst2003reed](@cite), [djordjevic2021quantum](@cite), [abbe2020reed](@cite)" begin - - #RM(0,3) - @test parity_checks(ReedMuller(0,3)) == [1 1 1 1 1 1 1 1] - - #RM(1,3) - @test parity_checks(ReedMuller(1,3)) == [1 1 1 1 1 1 1 1; - 1 1 1 1 0 0 0 0; - 1 1 0 0 1 1 0 0; - 1 0 1 0 1 0 1 0] - #RM(2,3) - @test parity_checks(ReedMuller(2,3)) == [1 1 1 1 1 1 1 1; - 1 1 1 1 0 0 0 0; - 1 1 0 0 1 1 0 0; - 1 0 1 0 1 0 1 0; - 1 1 0 0 0 0 0 0; - 1 0 1 0 0 0 0 0; - 1 0 0 0 1 0 0 0] - #RM(3,3) - @test parity_checks(ReedMuller(3,3)) == [1 1 1 1 1 1 1 1; - 1 1 1 1 0 0 0 0; - 1 1 0 0 1 1 0 0; - 1 0 1 0 1 0 1 0; - 1 1 0 0 0 0 0 0; - 1 0 1 0 0 0 0 0; - 1 0 0 0 1 0 0 0; - 1 0 0 0 0 0 0 0] - #RM(2,4) - @test parity_checks(ReedMuller(2,4)) == [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1; - 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0; - 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0; - 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0; - 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0; - 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0; - 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0; - 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0; - 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0; - 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0; - 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0] + @testset "Testing common examples of RM(r,m) codes [raaphorst2003reed](@cite), [djordjevic2021quantum](@cite), [abbe2020reed](@cite)" begin + + #RM(0,3) + @test parity_checks(ReedMuller(0,3)) == [1 1 1 1 1 1 1 1] + + #RM(1,3) + @test parity_checks(ReedMuller(1,3)) == [1 1 1 1 1 1 1 1; + 1 1 1 1 0 0 0 0; + 1 1 0 0 1 1 0 0; + 1 0 1 0 1 0 1 0] + #RM(2,3) + @test parity_checks(ReedMuller(2,3)) == [1 1 1 1 1 1 1 1; + 1 1 1 1 0 0 0 0; + 1 1 0 0 1 1 0 0; + 1 0 1 0 1 0 1 0; + 1 1 0 0 0 0 0 0; + 1 0 1 0 0 0 0 0; + 1 0 0 0 1 0 0 0] + #RM(3,3) + @test parity_checks(ReedMuller(3,3)) == [1 1 1 1 1 1 1 1; + 1 1 1 1 0 0 0 0; + 1 1 0 0 1 1 0 0; + 1 0 1 0 1 0 1 0; + 1 1 0 0 0 0 0 0; + 1 0 1 0 0 0 0 0; + 1 0 0 0 1 0 0 0; + 1 0 0 0 0 0 0 0] + #RM(2,4) + @test parity_checks(ReedMuller(2,4)) == [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1; + 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0; + 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0; + 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0; + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0; + 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0; + 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0; + 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0; + 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0; + 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0; + 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0] + end end diff --git a/test/test_ecc_syndromes.jl b/test/test_ecc_syndromes.jl index f58402656..45f4e0f89 100644 --- a/test/test_ecc_syndromes.jl +++ b/test/test_ecc_syndromes.jl @@ -1,49 +1,49 @@ -using Test -using QuantumClifford -using QuantumClifford: mul_left!, embed -using QuantumClifford.ECC -using QuantumClifford.ECC: AbstractECC +@testitem "ECC Syndromes" begin + using QuantumClifford: mul_left!, embed + using QuantumClifford.ECC + using QuantumClifford.ECC: AbstractECC -include("test_ecc_base.jl") + include("test_ecc_base.jl") -function pframe_naive_vs_shor_syndrome(code) - ecirc = naive_encoding_circuit(code) - naive_scirc, naive_ancillaries = naive_syndrome_circuit(code) - shor_cat_scirc, shor_scirc, shor_ancillaries, shor_bits = shor_syndrome_circuit(code) - nframes = 10 - dataqubits = code_n(code) - syndromebits = code_s(code) - naive_qubits = dataqubits + syndromebits - shor_qubits = dataqubits + shor_ancillaries - # no noise - naive_frames = PauliFrame(nframes, naive_qubits, syndromebits) - shor_frames = PauliFrame(nframes, shor_qubits, last(shor_bits)) - naive_circuit = [ecirc..., naive_scirc...] - shor_circuit = [ecirc..., shor_cat_scirc..., shor_scirc...] - pftrajectories(naive_frames, naive_circuit) - pftrajectories(shor_frames, shor_circuit) - @test pfmeasurements(naive_frames) == pfmeasurements(shor_frames)[:,shor_bits] - # with errors - for _ in 1:10 + function pframe_naive_vs_shor_syndrome(code) + ecirc = naive_encoding_circuit(code) + naive_scirc, naive_ancillaries = naive_syndrome_circuit(code) + shor_cat_scirc, shor_scirc, shor_ancillaries, shor_bits = shor_syndrome_circuit(code) + nframes = 10 + dataqubits = code_n(code) + syndromebits = code_s(code) + naive_qubits = dataqubits + syndromebits + shor_qubits = dataqubits + shor_ancillaries + # no noise naive_frames = PauliFrame(nframes, naive_qubits, syndromebits) shor_frames = PauliFrame(nframes, shor_qubits, last(shor_bits)) - pftrajectories(naive_frames, ecirc) - pftrajectories(shor_frames, [ecirc..., shor_cat_scirc...]) - # manually injecting the same type of noise in the frames -- not really a user accessible API - p = random_pauli(dataqubits, realphase=true) - pₙ = embed(naive_qubits, 1:dataqubits, p) - pₛ = embed(shor_qubits, 1:dataqubits, p) - mul_left!(naive_frames.frame, pₙ) - mul_left!(shor_frames.frame, pₛ) - # run the syndrome circuits using the public API - pftrajectories(naive_frames, naive_scirc) - pftrajectories(shor_frames, shor_scirc) + naive_circuit = [ecirc..., naive_scirc...] + shor_circuit = [ecirc..., shor_cat_scirc..., shor_scirc...] + pftrajectories(naive_frames, naive_circuit) + pftrajectories(shor_frames, shor_circuit) @test pfmeasurements(naive_frames) == pfmeasurements(shor_frames)[:,shor_bits] + # with errors + for _ in 1:10 + naive_frames = PauliFrame(nframes, naive_qubits, syndromebits) + shor_frames = PauliFrame(nframes, shor_qubits, last(shor_bits)) + pftrajectories(naive_frames, ecirc) + pftrajectories(shor_frames, [ecirc..., shor_cat_scirc...]) + # manually injecting the same type of noise in the frames -- not really a user accessible API + p = random_pauli(dataqubits, realphase=true) + pₙ = embed(naive_qubits, 1:dataqubits, p) + pₛ = embed(shor_qubits, 1:dataqubits, p) + mul_left!(naive_frames.frame, pₙ) + mul_left!(shor_frames.frame, pₛ) + # run the syndrome circuits using the public API + pftrajectories(naive_frames, naive_scirc) + pftrajectories(shor_frames, shor_scirc) + @test pfmeasurements(naive_frames) == pfmeasurements(shor_frames)[:,shor_bits] + end end -end -@testset "naive and shor measurement circuits" begin - for c in all_testablable_code_instances() - pframe_naive_vs_shor_syndrome(c) + @testset "naive and shor measurement circuits" begin + for c in all_testablable_code_instances() + pframe_naive_vs_shor_syndrome(c) + end end end diff --git a/test/test_ecc_throws.jl b/test/test_ecc_throws.jl index 19468e1ad..bd648327b 100644 --- a/test/test_ecc_throws.jl +++ b/test/test_ecc_throws.jl @@ -1,9 +1,9 @@ -using Test -using QuantumClifford -using QuantumClifford.ECC: ReedMuller, BCH +@testitem "ECC throws" begin + using QuantumClifford.ECC: ReedMuller, BCH -@test_throws ArgumentError ReedMuller(-1, 3) -@test_throws ArgumentError ReedMuller(1, 0) + @test_throws ArgumentError ReedMuller(-1, 3) + @test_throws ArgumentError ReedMuller(1, 0) -@test_throws ArgumentError BCH(2, 2) -@test_throws ArgumentError BCH(3, 4) + @test_throws ArgumentError BCH(2, 2) + @test_throws ArgumentError BCH(3, 4) +end diff --git a/test/test_embed.jl b/test/test_embed.jl index a4c6e39e6..37d5c0df7 100644 --- a/test/test_embed.jl +++ b/test/test_embed.jl @@ -1,7 +1,4 @@ -using Test -using QuantumClifford - -@testset "embed PauliOperator" begin +@testitem "embed PauliOperator" begin @test embed(5,3,P"-Y") == P"-__Y__" @test embed(5,(3,5),P"-YZ") == P"-__Y_Z" @test embed(5,[3,5],P"-YZ") == P"-__Y_Z" diff --git a/test/test_entanglement.jl b/test/test_entanglement.jl index 7441b638c..fa50fb369 100644 --- a/test/test_entanglement.jl +++ b/test/test_entanglement.jl @@ -1,54 +1,53 @@ -using Test +@testitem "Entanglement" begin + using Graphs -using Graphs -using QuantumClifford + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good - -@testset "Clipped gauge of stabilizer states" begin - for n in test_sizes - s = random_stabilizer(n) - s_clipped = copy(s) - canonicalize_clip!(s_clipped) - @test logdot(s, s_clipped)==0 - @test stab_looks_good(s_clipped) - @test canonicalize!(copy(s_clipped))==canonicalize!(copy(s)) - bg = bigram(s_clipped; clip=false) - rows, columns = size(stabilizerview(s_clipped)) - @test all(count(==(j), bg)==2 for j in 1:columns) + @testset "Clipped gauge of stabilizer states" begin + for n in test_sizes + s = random_stabilizer(n) + s_clipped = copy(s) + canonicalize_clip!(s_clipped) + @test logdot(s, s_clipped)==0 + @test stab_looks_good(s_clipped) + @test canonicalize!(copy(s_clipped))==canonicalize!(copy(s)) + bg = bigram(s_clipped; clip=false) + rows, columns = size(stabilizerview(s_clipped)) + @test all(count(==(j), bg)==2 for j in 1:columns) + end end -end -@testset "Entanglement calculated from clipped/rref for mixed states" begin - for n in test_sizes - s = random_destabilizer(rand(1:n), n) - endpoints = rand(1:n, 2) - subsystem_range = min(endpoints...):max(endpoints...) - @test entanglement_entropy(copy(s), subsystem_range, Val(:clip)) == entanglement_entropy(copy(s), subsystem_range, Val(:rref)) + @testset "Entanglement calculated from clipped/rref for mixed states" begin + for n in test_sizes + s = random_destabilizer(rand(1:n), n) + endpoints = rand(1:n, 2) + subsystem_range = min(endpoints...):max(endpoints...) + @test entanglement_entropy(copy(s), subsystem_range, Val(:clip)) == entanglement_entropy(copy(s), subsystem_range, Val(:rref)) + end end -end -@testset "Entanglement calculated from clipped/graph/rref for pure states" begin - for n in test_sizes - s = random_stabilizer(n) - endpoints = rand(1:n, 2) - subsystem_range = min(endpoints...):max(endpoints...) - @test entanglement_entropy(copy(s), subsystem_range, Val(:clip)) == entanglement_entropy(copy(s), subsystem_range, Val(:graph)) == entanglement_entropy(copy(s), subsystem_range, Val(:rref)) + @testset "Entanglement calculated from clipped/graph/rref for pure states" begin + for n in test_sizes + s = random_stabilizer(n) + endpoints = rand(1:n, 2) + subsystem_range = min(endpoints...):max(endpoints...) + @test entanglement_entropy(copy(s), subsystem_range, Val(:clip)) == entanglement_entropy(copy(s), subsystem_range, Val(:graph)) == entanglement_entropy(copy(s), subsystem_range, Val(:rref)) + end end -end -@testset "Entanglement of special cases" begin - s = S" + @testset "Entanglement of special cases" begin + s = S" + XZZ_ZZ + ZX_ZZ_ + Z_XZ_Z + _ZZXZZ + ZZ_ZXZ + Z_ZZZX" - subsystem = 1:3 - @test entanglement_entropy(copy(s), subsystem, Val(:clip))==2 - @test entanglement_entropy(copy(s), subsystem, Val(:graph))==2 - @test entanglement_entropy(copy(s), subsystem, Val(:rref))==2 + subsystem = 1:3 + @test entanglement_entropy(copy(s), subsystem, Val(:clip))==2 + @test entanglement_entropy(copy(s), subsystem, Val(:graph))==2 + @test entanglement_entropy(copy(s), subsystem, Val(:rref))==2 + end end diff --git a/test/test_enumerate.jl b/test/test_enumerate.jl index b3a424337..b1c0ac932 100644 --- a/test/test_enumerate.jl +++ b/test/test_enumerate.jl @@ -1,6 +1,4 @@ -using QuantumClifford - -@testset "Enumeration" begin +@testitem "Enumeration" begin @test Set([copy(op) for op in enumerate_cliffords(1)]) == Set((random_clifford(1,phases=false) for i in 1:70)) @test Set([copy(op) for op in enumerate_phases(enumerate_cliffords(1))]) == Set((random_clifford(1,phases=true) for i in 1:300)) @test length(collect(enumerate_cliffords(2))) == length(collect(enumerate_phases(enumerate_cliffords(2))))/2^4 == 720 diff --git a/test/test_expect.jl b/test/test_expect.jl index 6efdf280f..8f1ff9836 100644 --- a/test/test_expect.jl +++ b/test/test_expect.jl @@ -1,35 +1,33 @@ -using QuantumClifford +@testite "Expectation of Pauli strings on stabilizer states" begin + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + using QuantumClifford: projectremoverand! -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: projectremoverand! + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -function alter_expect(p::PauliOperator, s::Stabilizer) - nqubits(p) == nqubits(s) || error("The number of qubits does not match") - n = nqubits(p) - s_anc = s ⊗ one(Stabilizer, n) - p_anc = zero(PauliOperator, 2n) - for i = 1:n - if p[i] != (false, false) - if p[i][1] - apply!(s_anc, sHadamard(i)) - p[i][2] && apply!(s_anc, sInvPhase(i)) + function alter_expect(p::PauliOperator, s::Stabilizer) + nqubits(p) == nqubits(s) || error("The number of qubits does not match") + n = nqubits(p) + s_anc = s ⊗ one(Stabilizer, n) + p_anc = zero(PauliOperator, 2n) + for i = 1:n + if p[i] != (false, false) + if p[i][1] + apply!(s_anc, sHadamard(i)) + p[i][2] && apply!(s_anc, sInvPhase(i)) + end + apply!(s_anc, sCNOT(i, i+n)) + p_anc[i+n] = (false, true) end - apply!(s_anc, sCNOT(i, i+n)) - p_anc[i+n] = (false, true) end + p_anc.phase[] = p.phase[] + _, _, result = project!(s_anc, p_anc) + result === nothing && return 0 + result === 0x00 && return 1 + result === 0x01 && return im + result === 0x02 && return -1 + result === 0x03 && return -im end - p_anc.phase[] = p.phase[] - _, _, result = project!(s_anc, p_anc) - result === nothing && return 0 - result === 0x00 && return 1 - result === 0x01 && return im - result === 0x02 && return -1 - result === 0x03 && return -im -end -@testset "Expectation of Pauli strings on stabilizer states" begin st = bell() apply!(st, sX(2)) @test expect(P"XX", st) == alter_expect(P"XX", st) == 1 diff --git a/test/test_gf2.jl b/test/test_gf2.jl index 35c3f580a..45aa6701b 100644 --- a/test/test_gf2.jl +++ b/test/test_gf2.jl @@ -1,34 +1,27 @@ -using Random -using QuantumClifford +@testitem "GF(2) representations" begin + using Random + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good - -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -function test_gf2() - @testset "GF(2) representations" begin - @testset "Equivalence of GF(2) Gaussian elimination and Stabilizer canonicalization" begin - for n in test_sizes - for rep in 1:5 - s = random_stabilizer(n)[randperm(n)[1:rand(n÷2+1:n)]] - cs = canonicalize!(copy(s)); - H = stab_to_gf2(cs); - cH = gf2_gausselim!(stab_to_gf2(s)); - @test H==cH - end + @testset "Equivalence of GF(2) Gaussian elimination and Stabilizer canonicalization" begin + for n in test_sizes + for rep in 1:5 + s = random_stabilizer(n)[randperm(n)[1:rand(n÷2+1:n)]] + cs = canonicalize!(copy(s)); + H = stab_to_gf2(cs); + cH = gf2_gausselim!(stab_to_gf2(s)); + @test H==cH end end - @testset "GF(2) H and G matrices" begin - for n in test_sizes - for rep in 1:5 - H = random_invertible_gf2(n)[randperm(n)[1:rand(n÷2+1:n)],:] - H = gf2_gausselim!(H) - G = gf2_H_to_G(H) - @test sum(G*H' .%2)==0; - end + end + @testset "GF(2) H and G matrices" begin + for n in test_sizes + for rep in 1:5 + H = random_invertible_gf2(n)[randperm(n)[1:rand(n÷2+1:n)],:] + H = gf2_gausselim!(H) + G = gf2_H_to_G(H) + @test sum(G*H' .%2)==0; end end end end - -test_gf2() diff --git a/test/test_gpu.jl b/test/test_gpu.jl index 042d94b45..3a819cf40 100644 --- a/test/test_gpu.jl +++ b/test/test_gpu.jl @@ -1,147 +1,147 @@ -using Test -using QuantumClifford -using QuantumClifford: to_cpu, to_gpu -using CUDA +@testitem "GPU" tags=[:gpu] begin + using QuantumClifford: to_cpu, to_gpu + using CUDA -function apply_single_qubit_and_compare(n, s, s_gpu) - qbitidx = (((rand(Int) % n) + n) %n) + 1 - op = random_clifford1(qbitidx) - apply!(s_gpu, op) - apply!(s, op) - if to_cpu(s_gpu) != s - throw("result of cpu and gpu differ in single qubit operation. n=$n iteration=$iteration operation=$op") - end -end - -function apply_single_or_double_qubit_and_compare(n, s, s_gpu) - op = if rand(Int) % 2 == 0 + function apply_single_qubit_and_compare(n, s, s_gpu) qbitidx = (((rand(Int) % n) + n) %n) + 1 - random_clifford1(qbitidx) - else - # todo what other gates can we use? how to randomly generate two qubit operation? - # can we use random_clifford(2) with this function? - qbitidx1 = (((rand(Int) % n) + n) %n) + 1 - qbitidx2 = (((rand(Int) % n) + n) %n) + 1 - if qbitidx1 == qbitidx2 - qbitidx2 = (qbitidx1 % n) + 1 + op = random_clifford1(qbitidx) + apply!(s_gpu, op) + apply!(s, op) + if to_cpu(s_gpu) != s + throw("result of cpu and gpu differ in single qubit operation. n=$n iteration=$iteration operation=$op") end - sCNOT(qbitidx1, qbitidx2) - end - apply!(s_gpu, op) - apply!(s, op) - if to_cpu(s_gpu) != s - throw("result of cpu and gpu differ in single qubit operation. n=$n iteration=$iteration operation=$op") end -end -function approx(a, b, threshold) - maximum(abs.(a - b)) <= threshold -end + function apply_single_or_double_qubit_and_compare(n, s, s_gpu) + op = if rand(Int) % 2 == 0 + qbitidx = (((rand(Int) % n) + n) %n) + 1 + random_clifford1(qbitidx) + else + # todo what other gates can we use? how to randomly generate two qubit operation? + # can we use random_clifford(2) with this function? + qbitidx1 = (((rand(Int) % n) + n) %n) + 1 + qbitidx2 = (((rand(Int) % n) + n) %n) + 1 + if qbitidx1 == qbitidx2 + qbitidx2 = (qbitidx1 % n) + 1 + end + sCNOT(qbitidx1, qbitidx2) + end + apply!(s_gpu, op) + apply!(s, op) + if to_cpu(s_gpu) != s + throw("result of cpu and gpu differ in single qubit operation. n=$n iteration=$iteration operation=$op") + end + end + function approx(a, b, threshold) + maximum(abs.(a - b)) <= threshold + end -@testset "GPU" begin - CUDA.allowscalar(false) # make sure we are using GPU kernels and not iterating on indices - @test begin - p = random_pauli(3) - p_gpu = to_gpu(p) - typeof(p_gpu.xz) <: CUDA.CuArray # todo this is a bad test because it depends on representation of data in QuantumClifford. Change later... - end - @test begin - s = random_stabilizer(3) - s_gpu = to_gpu(s) - typeof(tab(s_gpu).xzs) <: CUDA.CuArray # todo this is a bad test because it depends on representation of data in QuantumClifford. Change later... - end + @testset "GPU" begin + CUDA.allowscalar(false) # make sure we are using GPU kernels and not iterating on indices - @test begin - for n in [2, 4, 8, 100, 500] - s = random_stabilizer(n) + @test begin + p = random_pauli(3) + p_gpu = to_gpu(p) + typeof(p_gpu.xz) <: CUDA.CuArray # todo this is a bad test because it depends on representation of data in QuantumClifford. Change later... + end + @test begin + s = random_stabilizer(3) s_gpu = to_gpu(s) - for iteration in 1:100 - apply_single_qubit_and_compare(n, s, s_gpu) - end + typeof(tab(s_gpu).xzs) <: CUDA.CuArray # todo this is a bad test because it depends on representation of data in QuantumClifford. Change later... end - true - end - @test begin - for n in [2, 4, 8, 100, 500] - s = random_stabilizer(n) - s_gpu = to_gpu(s) - for iteration in 1:100 - apply_single_or_double_qubit_and_compare(n, s, s_gpu) + @test begin + for n in [2, 4, 8, 100, 500] + s = random_stabilizer(n) + s_gpu = to_gpu(s) + for iteration in 1:100 + apply_single_qubit_and_compare(n, s, s_gpu) + end end + true end - true - end - @test begin - # todo test MRZ and other random gates statistically - circuit = [sHadamard(2), sHadamard(5), sCNOT(1, 2), sCNOT(2, 5), sMZ(1), sMZ(2), sMZ(4), sMZ(5)] - ccircuit = if eltype(circuit) <: QuantumClifford.CompactifiedGate - circuit - else - compactify_circuit(circuit) + @test begin + for n in [2, 4, 8, 100, 500] + s = random_stabilizer(n) + s_gpu = to_gpu(s) + for iteration in 1:100 + apply_single_or_double_qubit_and_compare(n, s, s_gpu) + end + end + true end - for func in [identity, fastcolumn, fastrow] - frames = QuantumClifford._create_pauliframe(ccircuit; trajectories=10) - cpu_frames = func(to_cpu(frames)) - gpu_frames = func(to_gpu(frames)) - cpu_result = pftrajectories(cpu_frames, ccircuit) - gpu_result = pftrajectories(gpu_frames, ccircuit) - check = (cpu_result.frame == to_cpu(gpu_result.frame)) && (cpu_result.measurements == to_cpu(gpu_result.measurements)) - if !check - throw("pftrajectories produce wrong result after applying $func") + @test begin + # todo test MRZ and other random gates statistically + circuit = [sHadamard(2), sHadamard(5), sCNOT(1, 2), sCNOT(2, 5), sMZ(1), sMZ(2), sMZ(4), sMZ(5)] + ccircuit = if eltype(circuit) <: QuantumClifford.CompactifiedGate + circuit + else + compactify_circuit(circuit) end + + for func in [identity, fastcolumn, fastrow] + frames = QuantumClifford._create_pauliframe(ccircuit; trajectories=10) + cpu_frames = func(to_cpu(frames)) + gpu_frames = func(to_gpu(frames)) + cpu_result = pftrajectories(cpu_frames, ccircuit) + gpu_result = pftrajectories(gpu_frames, ccircuit) + check = (cpu_result.frame == to_cpu(gpu_result.frame)) && (cpu_result.measurements == to_cpu(gpu_result.measurements)) + if !check + throw("pftrajectories produce wrong result after applying $func") + end + end + true end - true - end - @test begin - # test fastrow - for n in [2, 4, 8, 100, 500] - s = fastrow(random_stabilizer(n)) - s_gpu = fastrow(to_gpu(s)) - for iteration in 1:100 - # how to check if after each iteration we are still fastrow - apply_single_or_double_qubit_and_compare(n, s, s_gpu) + @test begin + # test fastrow + for n in [2, 4, 8, 100, 500] + s = fastrow(random_stabilizer(n)) + s_gpu = fastrow(to_gpu(s)) + for iteration in 1:100 + # how to check if after each iteration we are still fastrow + apply_single_or_double_qubit_and_compare(n, s, s_gpu) + end end + true end - true - end - @test begin - # test fastcolumn - for n in [2, 4, 8, 100, 500] - s = fastcolumn(random_stabilizer(n)) - s_gpu = fastcolumn(to_gpu(s)) - for iteration in 1:100 - # how to check if after each iteration we are still fastrow - apply_single_or_double_qubit_and_compare(n, s, s_gpu) + @test begin + # test fastcolumn + for n in [2, 4, 8, 100, 500] + s = fastcolumn(random_stabilizer(n)) + s_gpu = fastcolumn(to_gpu(s)) + for iteration in 1:100 + # how to check if after each iteration we are still fastrow + apply_single_or_double_qubit_and_compare(n, s, s_gpu) + end end + true end - true - end - @test begin - # test applynoise - N = 4 - trajectories = 10000 - f = PauliFrame(trajectories, N, N); - f = to_gpu(f) - p = 0.1 - measurements = pftrajectories(f, [ - sMZ(1, 1), - sHadamard(2), - sMZ(2, 2), - NoiseOp(UnbiasedUncorrelatedNoise(p), [3, 4]), - sMZ(3, 3), - sHadamard(4), - sMZ(4, 4) - ]).measurements - avg_result = to_cpu(sum(measurements, dims=1) / trajectories) - error_threshold = 0.02 - approx(vec(avg_result), [0, .5, 2p/3, .5], error_threshold) + @test begin + # test applynoise + N = 4 + trajectories = 10000 + f = PauliFrame(trajectories, N, N); + f = to_gpu(f) + p = 0.1 + measurements = pftrajectories(f, [ + sMZ(1, 1), + sHadamard(2), + sMZ(2, 2), + NoiseOp(UnbiasedUncorrelatedNoise(p), [3, 4]), + sMZ(3, 3), + sHadamard(4), + sMZ(4, 4) + ]).measurements + avg_result = to_cpu(sum(measurements, dims=1) / trajectories) + error_threshold = 0.02 + approx(vec(avg_result), [0, .5, 2p/3, .5], error_threshold) + end end end diff --git a/test/test_graphs.jl b/test/test_graphs.jl index ce7e0cb20..3f21b7583 100644 --- a/test/test_graphs.jl +++ b/test/test_graphs.jl @@ -1,10 +1,9 @@ -using Graphs -using Random -using QuantumClifford +@testitem "Graph states" begin + using Graphs + using Random -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -@testset "Graph states" begin for n in [1,test_sizes...] s = random_stabilizer(n) g, h_idx, ip_idx, z_idx = graphstate(s) diff --git a/test/test_hash.jl b/test/test_hash.jl index bbad9757e..621e7b42f 100644 --- a/test/test_hash.jl +++ b/test/test_hash.jl @@ -1,6 +1,4 @@ -using QuantumClifford - -@testset "Hashing" begin +@testitem "Hashing" begin @test hash(P"X") == hash(P"X") @test hash(S"X") == hash(S"X") @test hash(C"X Z") == hash(C"X Z") diff --git a/test/test_inner.jl b/test/test_inner.jl index a9b6dd9a2..fb61f3f71 100644 --- a/test/test_inner.jl +++ b/test/test_inner.jl @@ -1,9 +1,7 @@ -using LinearAlgebra -using QuantumClifford +@testitem "Inner product between stabilizer states" begin + using LinearAlgebra + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Inner product between stabilizer states" begin for n in rand(test_sizes) s1 = one(Stabilizer, n, basis=:X) s2 = one(MixedDestabilizer, n, n) @@ -14,11 +12,11 @@ test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off @test logdot(s3,s4)==logdot(c*s3,c*s4) end sa = S" XX - ZZ" + ZZ" sb = S" XZ - ZX" + ZX" sc = S" XX - -ZZ" + -ZZ" @test isnothing(logdot(sa,sb)) @test isnothing(logdot(S"Y",S"-Y")) @test logdot(S"Z",S"X") == 1 diff --git a/test/test_jet.jl b/test/test_jet.jl index 8b4f0c330..ca8e8d9b1 100644 --- a/test/test_jet.jl +++ b/test/test_jet.jl @@ -1,5 +1,4 @@ -using Test -using QuantumClifford +@testitem "JET checks" tags=[:jet] begin using JET using ArrayInterface using Static @@ -23,7 +22,6 @@ function (::MayThrowIsOk)(report_type::Type{<:InferenceErrorReport}, @nospeciali BasicPass()(report_type, args...) end -@testset "JET checks" begin rep = report_package("QuantumClifford"; report_pass=MayThrowIsOk(), ignored_modules=( diff --git a/test/test_memorylayout.jl b/test/test_memorylayout.jl index e0319ff35..1c6d1aeb0 100644 --- a/test/test_memorylayout.jl +++ b/test/test_memorylayout.jl @@ -1,8 +1,5 @@ -using Random -using QuantumClifford -using Test - -@testset "Column-fast vs row-fast operations" begin +@testitem "Column-fast vs row-fast operations" begin + using Random for n in [3, 300] for T in (Stabilizer, Destabilizer, MixedStabilizer, MixedDestabilizer) s = T(random_stabilizer(n,n)) diff --git a/test/test_mul_leftright.jl b/test/test_mul_leftright.jl index 1d7c14e45..1883d6789 100644 --- a/test/test_mul_leftright.jl +++ b/test/test_mul_leftright.jl @@ -1,39 +1,38 @@ -using QuantumClifford -using QuantumClifford: mul_left!, mul_right! +@testitem "Mul leftright" begin + @testset "Pauli string multiplication" begin + using QuantumClifford: mul_left!, mul_right! + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -using Test -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Pauli string multiplication" begin for n in test_sizes - for _ in 1:20 - p1 = random_pauli(n) - p2 = random_pauli(n) - s = random_stabilizer(n) - i = rand(1:n) - @test p1*p2 == mul_left!(copy(p2), p1) - @test p1*p2 == mul_right!(copy(p1), p2) - @test mul_left!(copy(p2), p1) == (-1)^comm(p1,p2) * mul_right!(copy(p2), p1) - @test mul_left!(copy(p2), s[i]) == mul_left!(copy(p2), s, i) == s[i]*p2 - @test mul_right!(copy(p2), s[i]) == mul_right!(copy(p2), s, i) == p2*s[i] - @test mul_left!(copy(s), p2)[i] == p2*s[i] - @test mul_right!(copy(s), p2)[i] == s[i]*p2 - end + for _ in 1:20 + p1 = random_pauli(n) + p2 = random_pauli(n) + s = random_stabilizer(n) + i = rand(1:n) + @test p1*p2 == mul_left!(copy(p2), p1) + @test p1*p2 == mul_right!(copy(p1), p2) + @test mul_left!(copy(p2), p1) == (-1)^comm(p1,p2) * mul_right!(copy(p2), p1) + @test mul_left!(copy(p2), s[i]) == mul_left!(copy(p2), s, i) == s[i]*p2 + @test mul_right!(copy(p2), s[i]) == mul_right!(copy(p2), s, i) == p2*s[i] + @test mul_left!(copy(s), p2)[i] == p2*s[i] + @test mul_right!(copy(s), p2)[i] == s[i]*p2 + end end -end + end -# test for #320 -@testset "verify SIMD implementation" begin + # test for #320 + @testset "verify SIMD implementation" begin for i in 1:10, - n in 1:30, - T in [UInt8, UInt16, UInt32, UInt64] - a = rand(T, n) - b = rand(T, n) - c1,c2 = QuantumClifford.mul_ordered!(copy(a),copy(b)) - n1,n2 = QuantumClifford._mul_ordered_nonvec!(copy(a),copy(b)) - np = ((n1 ⊻ (n2<<1))&0x3) - cp = ((c1 ⊻ (c2<<1))&0x3) - @test np==cp + n in 1:30, + T in [UInt8, UInt16, UInt32, UInt64] + a = rand(T, n) + b = rand(T, n) + c1,c2 = QuantumClifford.mul_ordered!(copy(a),copy(b)) + n1,n2 = QuantumClifford._mul_ordered_nonvec!(copy(a),copy(b)) + np = ((n1 ⊻ (n2<<1))&0x3) + cp = ((c1 ⊻ (c2<<1))&0x3) + @test np==cp end + end end diff --git a/test/test_noisycircuits.jl b/test/test_noisycircuits.jl index 8ba7a3a60..22a4b09bf 100644 --- a/test/test_noisycircuits.jl +++ b/test/test_noisycircuits.jl @@ -1,284 +1,284 @@ # TODO split in separate files -using Test -using Random -using QuantumClifford +@testitem "Noisy" begin + using Random -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -using QuantumClifford.Experimental.NoisyCircuits -import AbstractAlgebra + using QuantumClifford.Experimental.NoisyCircuits + import AbstractAlgebra -@testset "Noisy Gates" begin - g1 = SparseGate(tId1, [1]) - g2 = SparseGate(tCNOT, [2,3]) - g3 = sCNOT(4,5) - g4 = sHadamard(6) - n = UnbiasedUncorrelatedNoise(1) - ng1 = NoisyGate(g1, n) - ng2 = NoisyGate(g2, n) - ng3 = NoisyGate(g3, n) - ng4 = NoisyGate(g4, n) - ng5 = NoiseOp(n,[7]) - state = ghz(7) - res1, _ = mctrajectory!(copy(state), [ng1,ng2,ng3,ng4,ng5]) - res2, _ = mctrajectory!(copy(state), [g1,g2,g3,g4]) - @test res1 != res2 # has a very small chance of failing - resp = petrajectories(copy(state), [ng1,ng2,ng3,ng4,ng5]) - @test all(values(resp).==0) -end -@testset "Monte Carlo Purification examples" begin - g1 = SparseGate(tCNOT, [1,3]) - g2 = SparseGate(tCNOT, [2,4]) - m = BellMeasurement([sMX(3),sMX(4)]) - good_bell_state = S"XX - ZZ" - canonicalize_rref!(good_bell_state) - v = VerifyOp(good_bell_state,[1,2]) - n = NoiseOpAll(UnbiasedUncorrelatedNoise(0.03)) - init = Register(MixedDestabilizer(good_bell_state⊗good_bell_state)) - with_purification = mctrajectories(init, [n,g1,g2,m,v], trajectories=500) - @test with_purification[failure_stat] > 5 - @test with_purification[false_success_stat] > 10 - @test with_purification[true_success_stat] > 420 - without_purification = mctrajectories(init, [n,v], trajectories=500) - @test get(without_purification,failure_stat,0) == 0 - @test without_purification[false_success_stat] > 10 - @test without_purification[true_success_stat] > 450 - nonoise = mctrajectories(init, [g1,g2,m,v], trajectories=10) - @test get(nonoise,failure_stat,0) == 0 - @test get(nonoise,false_success_stat,0) == 0 - @test nonoise[true_success_stat] == 10 -end - - - -@testset "Perturbative expansion Purification examples" begin - @testset "Comparison to MC" begin - compare(a,b, symbol) = abs(a[symbol]/500-b[symbol]) / (a[symbol]/500+b[symbol]+1e-5) < 0.3 + @testset "Noisy Gates" begin + g1 = SparseGate(tId1, [1]) + g2 = SparseGate(tCNOT, [2,3]) + g3 = sCNOT(4,5) + g4 = sHadamard(6) + n = UnbiasedUncorrelatedNoise(1) + ng1 = NoisyGate(g1, n) + ng2 = NoisyGate(g2, n) + ng3 = NoisyGate(g3, n) + ng4 = NoisyGate(g4, n) + ng5 = NoiseOp(n,[7]) + state = ghz(7) + res1, _ = mctrajectory!(copy(state), [ng1,ng2,ng3,ng4,ng5]) + res2, _ = mctrajectory!(copy(state), [g1,g2,g3,g4]) + @test res1 != res2 # has a very small chance of failing + resp = petrajectories(copy(state), [ng1,ng2,ng3,ng4,ng5]) + @test all(values(resp).==0) + end + @testset "Monte Carlo Purification examples" begin g1 = SparseGate(tCNOT, [1,3]) g2 = SparseGate(tCNOT, [2,4]) m = BellMeasurement([sMX(3),sMX(4)]) good_bell_state = S"XX - ZZ" + ZZ" canonicalize_rref!(good_bell_state) v = VerifyOp(good_bell_state,[1,2]) n = NoiseOpAll(UnbiasedUncorrelatedNoise(0.03)) init = Register(MixedDestabilizer(good_bell_state⊗good_bell_state)) - mc = mctrajectories(init, [n,g1,g2,m,v], trajectories=500) - pe = petrajectories(init, [n,g1,g2,m,v]) - @test compare(mc,pe,failure_stat) - @test compare(mc,pe,false_success_stat) - @test compare(mc,pe,true_success_stat) - mc = mctrajectories(init, [n,v], trajectories=500) - pe = petrajectories(init, [n,v]) - @test compare(mc,pe,failure_stat) - @test compare(mc,pe,false_success_stat) - @test compare(mc,pe,true_success_stat) - mc = mctrajectories(init, [g1,g2,m,v], trajectories=500) - pe = petrajectories(init, [g1,g2,m,v]) - @test compare(mc,pe,failure_stat) - @test compare(mc,pe,false_success_stat) - @test compare(mc,pe,true_success_stat) - end - @testset "Symbolic" begin - R, (e,) = AbstractAlgebra.polynomial_ring(AbstractAlgebra.RealField, ["e"]) - unity = R(1); - good_bell_state = Register(MixedDestabilizer(S"XX ZZ")) - initial_state = good_bell_state⊗good_bell_state - g1 = SparseGate(tCNOT, [1,3]) # CNOT between qubit 1 and qubit 3 (both with Alice) - g2 = SparseGate(tCNOT, [2,4]) # CNOT between qubit 2 and qubit 4 (both with Bob) - m = BellMeasurement([sMX(3),sMX(4)]) # Bell measurement on qubit 3 and 4 - v = VerifyOp(good_bell_state,[1,2]) # Verify that qubit 1 and 2 indeed form a good Bell pair - epsilon = e # The X or Y or Z error rate - n = NoiseOpAll(UnbiasedUncorrelatedNoise(3epsilon)) - circuit = [n,g1,g2,m,v] - pe_symbolic = petrajectories(initial_state, circuit, branch_weight=unity) # perturbative expansion - @test pe_symbolic[false_success_stat] == -162.0*e^4 + 162.0*e^3 + -54.0*e^2 + 6.0*e - @test pe_symbolic[failure_stat] == -108.0*e^4 + 108.0*e^3 + -36.0*e^2 + 4.0*e - @test pe_symbolic[true_success_stat] == 27.0*e^4 + -54.0*e^3 + 36.0*e^2 + -10.0*e + 1.0 + with_purification = mctrajectories(init, [n,g1,g2,m,v], trajectories=500) + @test with_purification[failure_stat] > 5 + @test with_purification[false_success_stat] > 10 + @test with_purification[true_success_stat] > 420 + without_purification = mctrajectories(init, [n,v], trajectories=500) + @test get(without_purification,failure_stat,0) == 0 + @test without_purification[false_success_stat] > 10 + @test without_purification[true_success_stat] > 450 + nonoise = mctrajectories(init, [g1,g2,m,v], trajectories=10) + @test get(nonoise,failure_stat,0) == 0 + @test get(nonoise,false_success_stat,0) == 0 + @test nonoise[true_success_stat] == 10 end -end -@testset "Measurements" begin - @testset "BellMeasurements" begin - stateX = S"X" - mX = BellMeasurement([sMX(1)]) - vX = VerifyOp(S"X", [1]) - determinate1 = mctrajectories(Register(MixedDestabilizer(stateX)), [mX,vX], trajectories=10) - @test determinate1[failure_stat] == 0 - @test determinate1[false_success_stat] == 0 - @test determinate1[true_success_stat] == 10 - determinate1_pe = petrajectories(Register(MixedDestabilizer(copy(stateX))), [mX,vX]) - @test determinate1_pe[failure_stat] == 0 - @test determinate1_pe[false_success_stat] == 0 - @test determinate1_pe[true_success_stat] == 1 - stateZ = S"Z" - random1 = mctrajectories(Register(MixedDestabilizer(stateZ)), [mX,vX], trajectories=500) - @test random1[failure_stat] > 200 - @test random1[false_success_stat] == 0 - @test random1[true_success_stat] > 200 - random1_pe = petrajectories(Register(MixedDestabilizer(copy(stateZ))), [mX,vX]) - @test random1_pe[failure_stat] > 0.4 - @test random1_pe[false_success_stat] == 0 - @test random1_pe[true_success_stat] > 0.4 - bell_state = S" XX - ZZ" - m1 = BellMeasurement([sMX(1),sMX(2)]) - determinate2 = mctrajectories(Register(bell_state), [m1], trajectories=10) - @test determinate2[failure_stat] == 0 - @test determinate2[false_success_stat] == 0 - @test determinate2[continue_stat] == 10 - determinate2_pe = petrajectories(Register(copy(bell_state)), [m1]) - @test determinate2_pe[failure_stat] == 0 - @test determinate2_pe[false_success_stat] == 0 - m2 = BellMeasurement([sMX(1),sMZ(2)]) - v = VerifyOp(bell_state, [1,2]) - random2 = mctrajectories(Register(bell_state), [m2,v], trajectories=500) - @test random2[failure_stat]+random2[false_success_stat] == 500 - @test random2[true_success_stat] == 0 - random2_pe = petrajectories(Register(copy(bell_state)), [m2,v]) - @test random2_pe[failure_stat]+random2_pe[false_success_stat] == 1 - @test random2_pe[true_success_stat] == 0 - end - @testset "PauliMeasurements" begin - ghzState = S"XXX - ZZI - IZZ" - m1 = PauliMeasurement(P"ZZI", 1) - v = VerifyOp(ghzState, [1,2,3]) - register1 = Register(ghzState, zeros(Bool, 1)) - determinate1 = mctrajectories(register1, [m1,v], trajectories=10) - @test determinate1[failure_stat] == 0 - @test determinate1[false_success_stat] == 0 - @test determinate1[true_success_stat] == 10 - determinate1_pe = petrajectories(register1, [m1,v]) - @test determinate1_pe[failure_stat] == 0 - @test determinate1_pe[false_success_stat] == 0 - @test determinate1_pe[true_success_stat] == 1 - m2 = PauliMeasurement(P"ZII", 1) - register1 = Register(ghzState, zeros(Bool, 1)) - random1 = mctrajectories(register1, [m2,v], trajectories=50) - @test random1[failure_stat] == 0 - @test random1[false_success_stat] == 50 - @test random1[true_success_stat] == 0 - random1_pe = petrajectories(register1, [m2,v]) - @test random1_pe[failure_stat] == 0 - @test random1_pe[false_success_stat] == 1 - @test random1_pe[true_success_stat] == 0 - m3 = PauliMeasurement(P"XII", 1) - register1 = Register(ghzState, zeros(Bool, 1)) - random2 = mctrajectories(register1, [m3,v], trajectories=50) - @test random2[failure_stat] == 0 - @test random2[false_success_stat] == 50 - @test random2[true_success_stat] == 0 - random2_pe = petrajectories(register1, [m3,v]) - @test random2_pe[failure_stat] == 0 - @test random2_pe[false_success_stat] == 1 - @test random2_pe[true_success_stat] == 0 - end - @testset "Sparse Measurements" begin - ghzState = S"XXX - ZZI - IZZ" - v = VerifyOp(ghzState, [1,2,3]) - #= TODO reintroduce this type of SparseMeasurement (more than one qubit (so not sMZ), but not all qubits (so not DenseMeasurement)) - m1 = SparseMeasurement(P"ZZ", [1,2], 1) - register1 = Register(ghzState, zeros(Bool, 1)) - determinate1 = mctrajectories(register1, [m1,v], trajectories=10) - @test determinate1[failure_stat] == 0 - @test determinate1[false_success_stat] == 0 - @test determinate1[true_success_stat] == 10 - determinate1_pe = petrajectories(register1, [m1,v]) - @test determinate1_pe[failure_stat] == 0 - @test determinate1_pe[false_success_stat] == 0 - @test determinate1_pe[true_success_stat] == 1 - =# - m2 = sMZ(1, 1) - register1 = Register(ghzState, zeros(Bool, 1)) - random1 = mctrajectories(register1, [m2,v], trajectories=50) - @test random1[failure_stat] == 0 - @test random1[false_success_stat] == 50 - @test random1[true_success_stat] == 0 - random1_pe = petrajectories(register1, [m2,v]) - @test random1_pe[failure_stat] == 0 - @test random1_pe[false_success_stat] == 1 - @test random1_pe[true_success_stat] == 0 - m3 = sMX(1, 1) - register1 = Register(ghzState, zeros(Bool, 1)) - random2 = mctrajectories(register1, [m3,v], trajectories=50) - @test random2[failure_stat] == 0 - @test random2[false_success_stat] == 50 - @test random2[true_success_stat] == 0 - random2_pe = petrajectories(register1, [m3,v]) - @test random2_pe[failure_stat] == 0 - @test random2_pe[false_success_stat] == 1 - @test random2_pe[true_success_stat] == 0 + + + + @testset "Perturbative expansion Purification examples" begin + @testset "Comparison to MC" begin + compare(a,b, symbol) = abs(a[symbol]/500-b[symbol]) / (a[symbol]/500+b[symbol]+1e-5) < 0.3 + g1 = SparseGate(tCNOT, [1,3]) + g2 = SparseGate(tCNOT, [2,4]) + m = BellMeasurement([sMX(3),sMX(4)]) + good_bell_state = S"XX + ZZ" + canonicalize_rref!(good_bell_state) + v = VerifyOp(good_bell_state,[1,2]) + n = NoiseOpAll(UnbiasedUncorrelatedNoise(0.03)) + init = Register(MixedDestabilizer(good_bell_state⊗good_bell_state)) + mc = mctrajectories(init, [n,g1,g2,m,v], trajectories=500) + pe = petrajectories(init, [n,g1,g2,m,v]) + @test compare(mc,pe,failure_stat) + @test compare(mc,pe,false_success_stat) + @test compare(mc,pe,true_success_stat) + mc = mctrajectories(init, [n,v], trajectories=500) + pe = petrajectories(init, [n,v]) + @test compare(mc,pe,failure_stat) + @test compare(mc,pe,false_success_stat) + @test compare(mc,pe,true_success_stat) + mc = mctrajectories(init, [g1,g2,m,v], trajectories=500) + pe = petrajectories(init, [g1,g2,m,v]) + @test compare(mc,pe,failure_stat) + @test compare(mc,pe,false_success_stat) + @test compare(mc,pe,true_success_stat) + end + @testset "Symbolic" begin + R, (e,) = AbstractAlgebra.polynomial_ring(AbstractAlgebra.RealField, ["e"]) + unity = R(1); + good_bell_state = Register(MixedDestabilizer(S"XX ZZ")) + initial_state = good_bell_state⊗good_bell_state + g1 = SparseGate(tCNOT, [1,3]) # CNOT between qubit 1 and qubit 3 (both with Alice) + g2 = SparseGate(tCNOT, [2,4]) # CNOT between qubit 2 and qubit 4 (both with Bob) + m = BellMeasurement([sMX(3),sMX(4)]) # Bell measurement on qubit 3 and 4 + v = VerifyOp(good_bell_state,[1,2]) # Verify that qubit 1 and 2 indeed form a good Bell pair + epsilon = e # The X or Y or Z error rate + n = NoiseOpAll(UnbiasedUncorrelatedNoise(3epsilon)) + circuit = [n,g1,g2,m,v] + pe_symbolic = petrajectories(initial_state, circuit, branch_weight=unity) # perturbative expansion + @test pe_symbolic[false_success_stat] == -162.0*e^4 + 162.0*e^3 + -54.0*e^2 + 6.0*e + @test pe_symbolic[failure_stat] == -108.0*e^4 + 108.0*e^3 + -36.0*e^2 + 4.0*e + @test pe_symbolic[true_success_stat] == 27.0*e^4 + -54.0*e^3 + 36.0*e^2 + -10.0*e + 1.0 + end end - @testset "Conforming to the project! interface" begin - state = Register(MixedDestabilizer(S"ZZ"), zeros(Bool, 1)) - meas = PauliMeasurement(P"ZI", 1) - state, flag = applywstatus!(state, meas) - @test state.stab.rank == 2 - tab(state.stab).phases .= 0 - @test stabilizerview(state.stab) == S"ZZ - ZI" + @testset "Measurements" begin + @testset "BellMeasurements" begin + stateX = S"X" + mX = BellMeasurement([sMX(1)]) + vX = VerifyOp(S"X", [1]) + determinate1 = mctrajectories(Register(MixedDestabilizer(stateX)), [mX,vX], trajectories=10) + @test determinate1[failure_stat] == 0 + @test determinate1[false_success_stat] == 0 + @test determinate1[true_success_stat] == 10 + determinate1_pe = petrajectories(Register(MixedDestabilizer(copy(stateX))), [mX,vX]) + @test determinate1_pe[failure_stat] == 0 + @test determinate1_pe[false_success_stat] == 0 + @test determinate1_pe[true_success_stat] == 1 + stateZ = S"Z" + random1 = mctrajectories(Register(MixedDestabilizer(stateZ)), [mX,vX], trajectories=500) + @test random1[failure_stat] > 200 + @test random1[false_success_stat] == 0 + @test random1[true_success_stat] > 200 + random1_pe = petrajectories(Register(MixedDestabilizer(copy(stateZ))), [mX,vX]) + @test random1_pe[failure_stat] > 0.4 + @test random1_pe[false_success_stat] == 0 + @test random1_pe[true_success_stat] > 0.4 + bell_state = S" XX + ZZ" + m1 = BellMeasurement([sMX(1),sMX(2)]) + determinate2 = mctrajectories(Register(bell_state), [m1], trajectories=10) + @test determinate2[failure_stat] == 0 + @test determinate2[false_success_stat] == 0 + @test determinate2[continue_stat] == 10 + determinate2_pe = petrajectories(Register(copy(bell_state)), [m1]) + @test determinate2_pe[failure_stat] == 0 + @test determinate2_pe[false_success_stat] == 0 + m2 = BellMeasurement([sMX(1),sMZ(2)]) + v = VerifyOp(bell_state, [1,2]) + random2 = mctrajectories(Register(bell_state), [m2,v], trajectories=500) + @test random2[failure_stat]+random2[false_success_stat] == 500 + @test random2[true_success_stat] == 0 + random2_pe = petrajectories(Register(copy(bell_state)), [m2,v]) + @test random2_pe[failure_stat]+random2_pe[false_success_stat] == 1 + @test random2_pe[true_success_stat] == 0 + end + @testset "PauliMeasurements" begin + ghzState = S"XXX + ZZI + IZZ" + m1 = PauliMeasurement(P"ZZI", 1) + v = VerifyOp(ghzState, [1,2,3]) + register1 = Register(ghzState, zeros(Bool, 1)) + determinate1 = mctrajectories(register1, [m1,v], trajectories=10) + @test determinate1[failure_stat] == 0 + @test determinate1[false_success_stat] == 0 + @test determinate1[true_success_stat] == 10 + determinate1_pe = petrajectories(register1, [m1,v]) + @test determinate1_pe[failure_stat] == 0 + @test determinate1_pe[false_success_stat] == 0 + @test determinate1_pe[true_success_stat] == 1 + m2 = PauliMeasurement(P"ZII", 1) + register1 = Register(ghzState, zeros(Bool, 1)) + random1 = mctrajectories(register1, [m2,v], trajectories=50) + @test random1[failure_stat] == 0 + @test random1[false_success_stat] == 50 + @test random1[true_success_stat] == 0 + random1_pe = petrajectories(register1, [m2,v]) + @test random1_pe[failure_stat] == 0 + @test random1_pe[false_success_stat] == 1 + @test random1_pe[true_success_stat] == 0 + m3 = PauliMeasurement(P"XII", 1) + register1 = Register(ghzState, zeros(Bool, 1)) + random2 = mctrajectories(register1, [m3,v], trajectories=50) + @test random2[failure_stat] == 0 + @test random2[false_success_stat] == 50 + @test random2[true_success_stat] == 0 + random2_pe = petrajectories(register1, [m3,v]) + @test random2_pe[failure_stat] == 0 + @test random2_pe[false_success_stat] == 1 + @test random2_pe[true_success_stat] == 0 + end + @testset "Sparse Measurements" begin + ghzState = S"XXX + ZZI + IZZ" + v = VerifyOp(ghzState, [1,2,3]) + #= TODO reintroduce this type of SparseMeasurement (more than one qubit (so not sMZ), but not all qubits (so not DenseMeasurement)) + m1 = SparseMeasurement(P"ZZ", [1,2], 1) + register1 = Register(ghzState, zeros(Bool, 1)) + determinate1 = mctrajectories(register1, [m1,v], trajectories=10) + @test determinate1[failure_stat] == 0 + @test determinate1[false_success_stat] == 0 + @test determinate1[true_success_stat] == 10 + determinate1_pe = petrajectories(register1, [m1,v]) + @test determinate1_pe[failure_stat] == 0 + @test determinate1_pe[false_success_stat] == 0 + @test determinate1_pe[true_success_stat] == 1 + =# + m2 = sMZ(1, 1) + register1 = Register(ghzState, zeros(Bool, 1)) + random1 = mctrajectories(register1, [m2,v], trajectories=50) + @test random1[failure_stat] == 0 + @test random1[false_success_stat] == 50 + @test random1[true_success_stat] == 0 + random1_pe = petrajectories(register1, [m2,v]) + @test random1_pe[failure_stat] == 0 + @test random1_pe[false_success_stat] == 1 + @test random1_pe[true_success_stat] == 0 + m3 = sMX(1, 1) + register1 = Register(ghzState, zeros(Bool, 1)) + random2 = mctrajectories(register1, [m3,v], trajectories=50) + @test random2[failure_stat] == 0 + @test random2[false_success_stat] == 50 + @test random2[true_success_stat] == 0 + random2_pe = petrajectories(register1, [m3,v]) + @test random2_pe[failure_stat] == 0 + @test random2_pe[false_success_stat] == 1 + @test random2_pe[true_success_stat] == 0 + end + @testset "Conforming to the project! interface" begin + state = Register(MixedDestabilizer(S"ZZ"), zeros(Bool, 1)) + meas = PauliMeasurement(P"ZI", 1) + state, flag = applywstatus!(state, meas) + @test state.stab.rank == 2 + tab(state.stab).phases .= 0 + @test stabilizerview(state.stab) == S"ZZ + ZI" + end end -end -@testset "Classical Bits" begin - @testset "DecisionGate" begin - X_error = CliffordOperator([P"X", P"-Z"]) - # testing single digit return value from decision function - for s in [S"Z", S"-Z", S"X", S"-X", S"Y", S"-Y"] + @testset "Classical Bits" begin + @testset "DecisionGate" begin + X_error = CliffordOperator([P"X", P"-Z"]) + # testing single digit return value from decision function + for s in [S"Z", S"-Z", S"X", S"-X", S"Y", S"-Y"] + r = Register(s, [false]) + applywstatus!(r, PauliMeasurement(P"Z", 1)) + correctiveGate = SparseGate(X_error, [1]) + decisionFunction = syndrome -> syndrome[1] ? 1 : nothing + applywstatus!(r, DecisionGate([correctiveGate], decisionFunction)) + @test stabilizerview(r) == S"Z" + end + + # testing an array return from decision function + expectedFinalState = S"ZI + IZ" + s = QuantumClifford.bell() r = Register(s, [false]) - applywstatus!(r, PauliMeasurement(P"Z", 1)) - correctiveGate = SparseGate(X_error, [1]) - decisionFunction = syndrome -> syndrome[1] ? 1 : nothing - applywstatus!(r, DecisionGate([correctiveGate], decisionFunction)) - @test stabilizerview(r) == S"Z" - end + applywstatus!(r, PauliMeasurement(P"ZI", 1)) + correctiveGates = [SparseGate(X_error, [1]), SparseGate(X_error, [2])] + decisionFunction = syndrome -> syndrome[1] ? [1,2] : nothing + applywstatus!(r, DecisionGate(correctiveGates, decisionFunction)) + canonicalize!(quantumstate(r)) + @test stabilizerview(r) == expectedFinalState - # testing an array return from decision function - expectedFinalState = S"ZI - IZ" - s = QuantumClifford.bell() - r = Register(s, [false]) - applywstatus!(r, PauliMeasurement(P"ZI", 1)) - correctiveGates = [SparseGate(X_error, [1]), SparseGate(X_error, [2])] - decisionFunction = syndrome -> syndrome[1] ? [1,2] : nothing - applywstatus!(r, DecisionGate(correctiveGates, decisionFunction)) - canonicalize!(quantumstate(r)) - @test stabilizerview(r) == expectedFinalState + s = QuantumClifford.bell((false, true)) # |01>+|10> + r = Register(s, [false]) + applywstatus!(r, sMZ(1, 1)) + # we use the same corrective gates, with a different decision function + decisionFunction = syndrome -> syndrome[1] ? [1] : 2 # both [1] and 1 should work + applywstatus!(r, DecisionGate(correctiveGates, decisionFunction)) + canonicalize!(quantumstate(r)) + @test stabilizerview(r) == expectedFinalState + end + @testset "ConditionalGate" begin + id_op = CliffordOperator([P"X", P"Z"]) + X_error = CliffordOperator([P"X", P"-Z"]) - s = QuantumClifford.bell((false, true)) # |01>+|10> - r = Register(s, [false]) - applywstatus!(r, sMZ(1, 1)) - # we use the same corrective gates, with a different decision function - decisionFunction = syndrome -> syndrome[1] ? [1] : 2 # both [1] and 1 should work - applywstatus!(r, DecisionGate(correctiveGates, decisionFunction)) - canonicalize!(quantumstate(r)) - @test stabilizerview(r) == expectedFinalState - end - @testset "ConditionalGate" begin - id_op = CliffordOperator([P"X", P"Z"]) - X_error = CliffordOperator([P"X", P"-Z"]) + for s in [S"Z", S"-Z", S"X", S"-X", S"Y", S"-Y"] + r = Register(s, [false]) + applywstatus!(r, PauliMeasurement(P"Z", 1)) + correctiveGate = SparseGate(X_error, [1]) + identityGate = SparseGate(id_op, [1]) + applywstatus!(r, ConditionalGate(correctiveGate, identityGate, 1)) + @test stabilizerview(r) == S"Z" + end - for s in [S"Z", S"-Z", S"X", S"-X", S"Y", S"-Y"] + expectedFinalState = S"ZI + IZ" + s = QuantumClifford.bell((false, true)) r = Register(s, [false]) - applywstatus!(r, PauliMeasurement(P"Z", 1)) - correctiveGate = SparseGate(X_error, [1]) - identityGate = SparseGate(id_op, [1]) - applywstatus!(r, ConditionalGate(correctiveGate, identityGate, 1)) - @test stabilizerview(r) == S"Z" + applywstatus!(r, PauliMeasurement(P"ZI", 1)) + correctiveGate1 = SparseGate(X_error, [1]) + correctiveGate2 = SparseGate(X_error, [2]) + applywstatus!(r, ConditionalGate(correctiveGate1, correctiveGate2, 1)) + canonicalize!(quantumstate(r)) + @test stabilizerview(r) == expectedFinalState end - - expectedFinalState = S"ZI - IZ" - s = QuantumClifford.bell((false, true)) - r = Register(s, [false]) - applywstatus!(r, PauliMeasurement(P"ZI", 1)) - correctiveGate1 = SparseGate(X_error, [1]) - correctiveGate2 = SparseGate(X_error, [2]) - applywstatus!(r, ConditionalGate(correctiveGate1, correctiveGate2, 1)) - canonicalize!(quantumstate(r)) - @test stabilizerview(r) == expectedFinalState end end diff --git a/test/test_nonclifford.jl b/test/test_nonclifford.jl index 292aaac8d..0bf14682e 100644 --- a/test/test_nonclifford.jl +++ b/test/test_nonclifford.jl @@ -1,46 +1,44 @@ -using QuantumClifford -using QuantumClifford: StabMixture, rowdecompose, PauliChannel, mul_left!, mul_right! -using Test -using InteractiveUtils -using Random - -## - -@testset "Pauli decomposition into destabilizers" begin - for n in [1,2,63,64,65,66,300] - p = random_pauli(n; nophase=true) - s = random_destabilizer(n) - phase, b, c = rowdecompose(p,s) - p0 = zero(p) - for (i,f) in pairs(b) - f && mul_right!(p0, destabilizerview(s), i) +@testitem "NonClifford" begin + using QuantumClifford: StabMixture, rowdecompose, PauliChannel, mul_left!, mul_right! + using InteractiveUtils + using Random + + @testset "Pauli decomposition into destabilizers" begin + for n in [1,2,63,64,65,66,300] + p = random_pauli(n; nophase=true) + s = random_destabilizer(n) + phase, b, c = rowdecompose(p,s) + p0 = zero(p) + for (i,f) in pairs(b) + f && mul_right!(p0, destabilizerview(s), i) + end + for (i,f) in pairs(c) + f && mul_right!(p0, stabilizerview(s), i) + end + @test (im)^phase*p0 == p end - for (i,f) in pairs(c) - f && mul_right!(p0, stabilizerview(s), i) - end - @test (im)^phase*p0 == p end -end -## + ## -@testset "PauliChannel T gate ^4 = Id" begin - tgate = pcT - state = StabMixture(S"X") + @testset "PauliChannel T gate ^4 = Id" begin + tgate = pcT + state = StabMixture(S"X") - apply!(state, tgate) - apply!(state, tgate) - apply!(state, tgate) - apply!(state, tgate) + apply!(state, tgate) + apply!(state, tgate) + apply!(state, tgate) + apply!(state, tgate) - @test state.destabweights |> values |> collect == [1] - @test state.destabweights |> keys |> collect == [([1],[1])] -end + @test isapprox(state.destabweights |> values |> collect, [1]) + @test state.destabweights |> keys |> collect == [([1],[1])] + end -## + ## -@test_throws ArgumentError StabMixture(S"XX") -@test_throws ArgumentError PauliChannel(((P"X", P"Z"), (P"X", P"ZZ")), (1,2)) -@test_throws ArgumentError PauliChannel(((P"X", P"Z"), (P"X", P"Z")), (1,)) -@test_throws ArgumentError UnitaryPauliChannel((P"X", P"ZZ"), (1,2)) -@test_throws ArgumentError UnitaryPauliChannel((P"X", P"Z"), (1,)) + @test_throws ArgumentError StabMixture(S"XX") + @test_throws ArgumentError PauliChannel(((P"X", P"Z"), (P"X", P"ZZ")), (1,2)) + @test_throws ArgumentError PauliChannel(((P"X", P"Z"), (P"X", P"Z")), (1,)) + @test_throws ArgumentError UnitaryPauliChannel((P"X", P"ZZ"), (1,2)) + @test_throws ArgumentError UnitaryPauliChannel((P"X", P"Z"), (1,)) +end diff --git a/test/test_pauliframe.jl b/test/test_pauliframe.jl index 0669f2ac2..cc335934c 100644 --- a/test/test_pauliframe.jl +++ b/test/test_pauliframe.jl @@ -1,92 +1,91 @@ -using QuantumClifford -using Test - -@testset "syndrome measurement of 3 qubit repetition code" begin - circuit = [ - sX(1), - sCNOT(1,2), sCNOT(1,3), # encode - PauliError(2,0.75), # error - sCNOT(1,4), sCNOT(2,4), sCNOT(2,5), sCNOT(3,5), sMZ(4,1), sMZ(5,2) # syndrome measurement - ] - frame = PauliFrame(100, 5, 2) - frame = pftrajectories(frame, circuit) - frame1 = pftrajectories(circuit; trajectories=100, threads=false) - frame2 = pftrajectories(circuit; trajectories=100, threads=true) - # If the x component is set on the second qubit, then the fourth and fifth qubits should also have it set - for f in [frame, frame1, frame2] - m = pfmeasurements(f) - for (i, row) in enumerate(f.frame) - if row[2] == (true, false) - @test row[4][1] && row[5][1] && m[i,1] && m[i,2] +@testitem "Pauli frame" begin + @testset "syndrome measurement of 3 qubit repetition code" begin + circuit = [ + sX(1), + sCNOT(1,2), sCNOT(1,3), # encode + PauliError(2,0.75), # error + sCNOT(1,4), sCNOT(2,4), sCNOT(2,5), sCNOT(3,5), sMZ(4,1), sMZ(5,2) # syndrome measurement + ] + frame = PauliFrame(100, 5, 2) + frame = pftrajectories(frame, circuit) + frame1 = pftrajectories(circuit; trajectories=100, threads=false) + frame2 = pftrajectories(circuit; trajectories=100, threads=true) + # If the x component is set on the second qubit, then the fourth and fifth qubits should also have it set + for f in [frame, frame1, frame2] + m = pfmeasurements(f) + for (i, row) in enumerate(f.frame) + if row[2] == (true, false) + @test row[4][1] && row[5][1] && m[i,1] && m[i,2] + end end end end -end -@testset "GHZ correlations" begin - ghz_circuit = [ - sHadamard(1), sCNOT(1,2), sCNOT(1,3), # prepare a GHZ state - sMZ(1,1), sMZ(2,2), sMZ(3,3) # measure each qubit - ] - n = 10^6 - frame = PauliFrame(n, 3, 3) - f = pftrajectories(frame, ghz_circuit) - m = pfmeasurements(f) - frame1 = pftrajectories(ghz_circuit; trajectories=n, threads=false) - m1 = pfmeasurements(frame1) - frame2 = pftrajectories(ghz_circuit; trajectories=n, threads=true) - m2 = pfmeasurements(frame2) - for _m in [m, m1, m2] - rowtotal_1s = sum(m, dims=2)[:,1] - @test all(rowtotal_1s .% 3 .== 0) - fractotal_1s = sum(rowtotal_1s)/3 / n - @test (fractotal_1s > 0.49) && (fractotal_1s < 0.51) + @testset "GHZ correlations" begin + ghz_circuit = [ + sHadamard(1), sCNOT(1,2), sCNOT(1,3), # prepare a GHZ state + sMZ(1,1), sMZ(2,2), sMZ(3,3) # measure each qubit + ] + n = 10^6 + frame = PauliFrame(n, 3, 3) + f = pftrajectories(frame, ghz_circuit) + m = pfmeasurements(f) + frame1 = pftrajectories(ghz_circuit; trajectories=n, threads=false) + m1 = pfmeasurements(frame1) + frame2 = pftrajectories(ghz_circuit; trajectories=n, threads=true) + m2 = pfmeasurements(frame2) + for _m in [m, m1, m2] + rowtotal_1s = sum(m, dims=2)[:,1] + @test all(rowtotal_1s .% 3 .== 0) + fractotal_1s = sum(rowtotal_1s)/3 / n + @test (fractotal_1s > 0.49) && (fractotal_1s < 0.51) + end end -end -@testset "sMZ vs sMRZ - mctrajectories vs pftrajectories" begin - n = 2000 - state = Register(one(MixedDestabilizer, 3), 6) - frame = PauliFrame(n, 3, 6) + @testset "sMZ vs sMRZ - mctrajectories vs pftrajectories" begin + n = 2000 + state = Register(one(MixedDestabilizer, 3), 6) + frame = PauliFrame(n, 3, 6) - ghz_circuit1 = [ - sHadamard(1), sCNOT(1,2), sCNOT(1,3), # prepare a GHZ state - sMZ(1,1), sMZ(2,2), sMZ(3,3), # measure each qubit - sMZ(1,4), sMZ(2,5), sMZ(3,6) # measure each qubit again - ] - for m in [ - stack([bitview(mctrajectory!(copy(state), ghz_circuit1)[1]) for i in 1:n], dims=1), - pfmeasurements(pftrajectories(copy(frame), ghz_circuit1)), - pfmeasurements(pftrajectories(ghz_circuit1;trajectories=n,threads=false)), - pfmeasurements(pftrajectories(ghz_circuit1;trajectories=n,threads=true)), - ] - @test all(0.25 .< sum(m, dims=1)./n .< 0.75) - end + ghz_circuit1 = [ + sHadamard(1), sCNOT(1,2), sCNOT(1,3), # prepare a GHZ state + sMZ(1,1), sMZ(2,2), sMZ(3,3), # measure each qubit + sMZ(1,4), sMZ(2,5), sMZ(3,6) # measure each qubit again + ] + for m in [ + stack([bitview(mctrajectory!(copy(state), ghz_circuit1)[1]) for i in 1:n], dims=1), + pfmeasurements(pftrajectories(copy(frame), ghz_circuit1)), + pfmeasurements(pftrajectories(ghz_circuit1;trajectories=n,threads=false)), + pfmeasurements(pftrajectories(ghz_circuit1;trajectories=n,threads=true)), + ] + @test all(0.25 .< sum(m, dims=1)./n .< 0.75) + end - ghz_circuit2 = [ - sHadamard(1), sCNOT(1,2), sCNOT(1,3), # prepare a GHZ state - sMRZ(1,1), sMZ(2,2), sMZ(3,3), # measure and reset each qubit - sMZ(1,4), sMZ(2,5), sMZ(3,6) # measure each qubit again - ] - for m in [ - stack([bitview(mctrajectory!(copy(state), ghz_circuit2)[1]) for i in 1:n], dims=1), - pfmeasurements(pftrajectories(copy(frame), ghz_circuit2)), - pfmeasurements(pftrajectories(ghz_circuit2;trajectories=n,threads=false)), - pfmeasurements(pftrajectories(ghz_circuit2;trajectories=n,threads=true)), - ] - @test all(0.25.*[1 1 1 0 1 1] .<= sum(m, dims=1)./n .<= 0.75.*[1 1 1 0 1 1]) - end + ghz_circuit2 = [ + sHadamard(1), sCNOT(1,2), sCNOT(1,3), # prepare a GHZ state + sMRZ(1,1), sMZ(2,2), sMZ(3,3), # measure and reset each qubit + sMZ(1,4), sMZ(2,5), sMZ(3,6) # measure each qubit again + ] + for m in [ + stack([bitview(mctrajectory!(copy(state), ghz_circuit2)[1]) for i in 1:n], dims=1), + pfmeasurements(pftrajectories(copy(frame), ghz_circuit2)), + pfmeasurements(pftrajectories(ghz_circuit2;trajectories=n,threads=false)), + pfmeasurements(pftrajectories(ghz_circuit2;trajectories=n,threads=true)), + ] + @test all(0.25.*[1 1 1 0 1 1] .<= sum(m, dims=1)./n .<= 0.75.*[1 1 1 0 1 1]) + end - noncom_circuit = [ - sHadamard(1), sMRZ(1,1), sX(1), sMZ(1,2), sMRZ(1,3), sMRZ(1,4), sHadamard(1), sMZ(1,5) - ] - ms3 = stack([bitview(mctrajectory!(copy(state), noncom_circuit)[1]) for i in 1:n], dims=1) - @test all(0.25.*[1 4 4 0 1 0] .<= sum(ms3, dims=1)./n .<= 0.75.*[1 2 2 0 1 0]) - for m in [ - pfmeasurements(pftrajectories(copy(frame), noncom_circuit)), - pfmeasurements(pftrajectories(noncom_circuit;trajectories=n,threads=false)), - pfmeasurements(pftrajectories(noncom_circuit;trajectories=n,threads=true)), - ] - @test all(0.25.*[1 0 0 0 1] .<= (sum(m, dims=1)[:,1:5])./n .<= 0.75.*[1 0 0 0 1]) + noncom_circuit = [ + sHadamard(1), sMRZ(1,1), sX(1), sMZ(1,2), sMRZ(1,3), sMRZ(1,4), sHadamard(1), sMZ(1,5) + ] + ms3 = stack([bitview(mctrajectory!(copy(state), noncom_circuit)[1]) for i in 1:n], dims=1) + @test all(0.25.*[1 4 4 0 1 0] .<= sum(ms3, dims=1)./n .<= 0.75.*[1 2 2 0 1 0]) + for m in [ + pfmeasurements(pftrajectories(copy(frame), noncom_circuit)), + pfmeasurements(pftrajectories(noncom_circuit;trajectories=n,threads=false)), + pfmeasurements(pftrajectories(noncom_circuit;trajectories=n,threads=true)), + ] + @test all(0.25.*[1 0 0 0 1] .<= (sum(m, dims=1)[:,1:5])./n .<= 0.75.*[1 0 0 0 1]) + end end end diff --git a/test/test_paulis.jl b/test/test_paulis.jl index d39ac2cfd..778282706 100644 --- a/test/test_paulis.jl +++ b/test/test_paulis.jl @@ -1,10 +1,7 @@ -using QuantumClifford +@testitem "Pauli Operators" begin + using QuantumClifford: apply_single_x!, apply_single_y!, apply_single_z! + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -using QuantumClifford: apply_single_x!, apply_single_y!, apply_single_z! - -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Pauli Operators" begin @testset "Parsing, constructors, and properties" begin @test P"-iXYZ" == PauliOperator(0x3, 3, vcat(BitArray([1,1,0]).chunks, BitArray([0,1,1]).chunks)) @test P"-iXYZ" == PauliOperator(0x3, Bool[1,1,0], Bool[0,1,1]) diff --git a/test/test_precompile.jl b/test/test_precompile.jl index 92bd82a6a..e43e99a4b 100644 --- a/test/test_precompile.jl +++ b/test/test_precompile.jl @@ -1,3 +1,3 @@ -using QuantumClifford - -QuantumClifford._precompile_() +@testitem "Precompile" begin + QuantumClifford._precompile_() +end diff --git a/test/test_projections.jl b/test/test_projections.jl index e121d2abf..03d56e1e2 100644 --- a/test/test_projections.jl +++ b/test/test_projections.jl @@ -1,20 +1,19 @@ -using QuantumClifford +@testitem "Projective measurements" begin + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + using QuantumClifford: projectremoverand! -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: projectremoverand! + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -@testset "Projective measurements" begin @testset "Stabilizer representation" begin s = S"XXX - ZZI - IZZ" + ZZI + IZZ" ps, anticom, res = project!(copy(s), P"ZII") ps = canonicalize!(ps) @test anticom==1 && isnothing(res) && ps == S"ZII - IZI - IIZ" + IZI + IIZ" @test stab_looks_good(ps) ps, anticom, res = project!(copy(s), P"-XXX") @@ -65,7 +64,7 @@ test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off end @testset "Anticommutation indices and NA results" begin s = S" XXX - -ZZI" + -ZZI" ds = Destabilizer(copy(s)) ms = MixedStabilizer(copy(s)) mds = MixedDestabilizer(copy(s)) @@ -125,21 +124,21 @@ test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off s, a, r = project!(copy(stab), projzl) @test mixed_destab_looks_good(s) @test a==0 && r==0x0 && stabilizerview(s)==S"Z___ - _Z__" + _Z__" s, a, r = project!(copy(stab), projxl) @test mixed_destab_looks_good(s) @test a==1 && isnothing(r) && stabilizerview(s)==S"X___ - _Z__" + _Z__" s, a, r = project!(copy(stab), projzr) @test mixed_destab_looks_good(s) @test a==3 && isnothing(r) && stabilizerview(s)==S"Z___ - _Z__ - ___Z" + _Z__ + ___Z" s, a, r = project!(copy(stab), projxr) @test mixed_destab_looks_good(s) @test a==3 && isnothing(r) && stabilizerview(s)==S"Z___ - _Z__ - ___X" + _Z__ + ___X" end @testset "Interface Particularities" begin s = S"ZII IZI" @@ -349,21 +348,21 @@ test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off @testset "Redundant row permutations in `project!(::MixedDestabilizer)`" begin # Fixed in 41ed1d3c destab = T"+ ZX_Y_YXZ - + XY_Y____ - + _Z_XXY__ - + _ZYXXY__ - + X__Y_ZXZ - + X__YXZXZ - + ___YXXZZ - + _______Z" + + XY_Y____ + + _Z_XXY__ + + _ZYXXY__ + + X__Y_ZXZ + + X__YXZXZ + + ___YXXZZ + + _______Z" stab = T"+ X_______ - + _X_Y____ - + __ZY____ - + __Z_____ - + ___YZY__ - + X__YZYZZ - + X____YZZ - + ______YX" + + _X_Y____ + + __ZY____ + + __Z_____ + + ___YZY__ + + X__YZYZZ + + X____YZZ + + ______YX" t = MixedDestabilizer(vcat(destab,stab), 8) @test mixed_destab_looks_good(t) c = copy(stabilizerview(t)[[1,3,5,7]]) diff --git a/test/test_quantumoptics.jl b/test/test_quantumoptics.jl index 9637daba4..5372a6e0c 100644 --- a/test/test_quantumoptics.jl +++ b/test/test_quantumoptics.jl @@ -1,109 +1,109 @@ -using Test -using QuantumClifford -using QuantumOpticsBase -using QuantumClifford: @S_str, random_stabilizer -using LinearAlgebra -#using QuantumCliffordQOpticsExt: _l0, _l1, _s₊, _s₋, _i₊, _i₋ -const qo = Base.get_extension(QuantumClifford, :QuantumCliffordQOpticsExt) -const _l0 = qo._l0 -const _l1 = qo._l1 -const _s₊ = qo._s₊ -const _s₋ = qo._s₋ -const _i₊ = qo._i₊ -const _i₋ = qo._i₋ +@testitem "Quantum optics" begin + using QuantumOpticsBase + using QuantumClifford: @S_str, random_stabilizer + using LinearAlgebra + #using QuantumCliffordQOpticsExt: _l0, _l1, _s₊, _s₋, _i₊, _i₋ + const qo = Base.get_extension(QuantumClifford, :QuantumCliffordQOpticsExt) + const _l0 = qo._l0 + const _l1 = qo._l1 + const _s₊ = qo._s₊ + const _s₋ = qo._s₋ + const _i₊ = qo._i₊ + const _i₋ = qo._i₋ -@testset "conversion from Stabilizer to Ket" begin - for n in 1:5 - stabs = [random_stabilizer(1) for _ in 1:n] - stab = tensor(stabs...) - translate = Dict(S"X"=>_s₊,S"-X"=>_s₋,S"Z"=>_l0,S"-Z"=>_l1,S"Y"=>_i₊,S"-Y"=>_i₋) - kets = [translate[s] for s in stabs] - ket = tensor(kets...) - @test ket.data ≈ Ket(stab).data + @testset "conversion from Stabilizer to Ket" begin + for n in 1:5 + stabs = [random_stabilizer(1) for _ in 1:n] + stab = tensor(stabs...) + translate = Dict(S"X"=>_s₊,S"-X"=>_s₋,S"Z"=>_l0,S"-Z"=>_l1,S"Y"=>_i₊,S"-Y"=>_i₋) + kets = [translate[s] for s in stabs] + ket = tensor(kets...) + @test ket.data ≈ Ket(stab).data - rstab = random_stabilizer(n) - lstab = random_stabilizer(n) - lket = Ket(rstab) - rket = Ket(lstab) - dotket = abs(lket'*rket) - dotstab = abs(dot(lstab,rstab)) - @test (dotket<=1e-10 && dotstab==0) || dotket≈dotstab + rstab = random_stabilizer(n) + lstab = random_stabilizer(n) + lket = Ket(rstab) + rket = Ket(lstab) + dotket = abs(lket'*rket) + dotstab = abs(dot(lstab,rstab)) + @test (dotket<=1e-10 && dotstab==0) || dotket≈dotstab + end end -end -@testset "conversion from CliffordOperator to Operator" begin - for n in 1:3 - for _c in 1:5 - cliff = random_clifford(n) - U = Operator(cliff) + @testset "conversion from CliffordOperator to Operator" begin + for n in 1:3 for _c in 1:5 - stab = random_stabilizer(n) - ψ₁ = Ket(stab) - ψ₂ = Ket(apply!(stab,cliff)) - # test they are equal up to a phase - @test all(x->isnan(x)||abs(x)≈1 , (U*ψ₁).data ./ ψ₂.data) - @test abs(det(U.data))≈1 + cliff = random_clifford(n) + U = Operator(cliff) + for _c in 1:5 + stab = random_stabilizer(n) + ψ₁ = Ket(stab) + ψ₂ = Ket(apply!(stab,cliff)) + # test they are equal up to a phase + @test all(x->isnan(x)||abs(x)≈1 , (U*ψ₁).data ./ ψ₂.data) + @test abs(det(U.data))≈1 + end end end end -end -@testset "conversion from StabMixture to Operator" begin - for n in 1:5 - stab = random_stabilizer(n) - @test dm(Ket(stab)) == Operator(StabMixture(stab)) + @testset "conversion from StabMixture to Operator" begin + for n in 1:5 + stab = random_stabilizer(n) + @test dm(Ket(stab)) == Operator(StabMixture(stab)) + end end -end -@testset "conversion from PauliOperator to Operator" begin - for n in 1:5 - for _ in 1:10 - p = random_pauli(n) - q = random_pauli(n) - p̃ = Operator(p) - q̃ = Operator(q) - @test Operator(p*q) == p̃*q̃ - @test Operator(q*p) == q̃*p̃ + @testset "conversion from PauliOperator to Operator" begin + for n in 1:5 + for _ in 1:10 + p = random_pauli(n) + q = random_pauli(n) + p̃ = Operator(p) + q̃ = Operator(q) + @test Operator(p*q) == p̃*q̃ + @test Operator(q*p) == q̃*p̃ + end end end -end -tgate = sparse(identityoperator(SpinBasis(1//2))) -tgate.data[2,2] = exp(im*pi/4) + tgate = sparse(identityoperator(SpinBasis(1//2))) + tgate.data[2,2] = exp(im*pi/4) -@testset "StabMixture/PauliChannel to QuantumOptics - explicit single-qubit Pauli channels" begin - # manual checks - @test Operator(pcT)≈tgate + @testset "StabMixture/PauliChannel to QuantumOptics - explicit single-qubit Pauli channels" begin + # manual checks + @test Operator(pcT)≈tgate - # single qubit checks - for single_qubit_explicit_channel in [pcT] - qo_gate = Operator(single_qubit_explicit_channel) - for single_qubit_tableau in [S"X", S"Y", S"Z", S"-X", S"-Y", S"-Z"] - sm = StabMixture(single_qubit_tableau) - ψ = Ket(single_qubit_tableau) - for rep in 1:8 - apply!(sm, single_qubit_explicit_channel) - ψ = qo_gate*ψ - @test expect(Operator(sm), ψ) ≈ 1 + # single qubit checks + for single_qubit_explicit_channel in [pcT] + qo_gate = Operator(single_qubit_explicit_channel) + for single_qubit_tableau in [S"X", S"Y", S"Z", S"-X", S"-Y", S"-Z"] + sm = StabMixture(single_qubit_tableau) + ψ = Ket(single_qubit_tableau) + for rep in 1:8 + apply!(sm, single_qubit_explicit_channel) + ψ = qo_gate*ψ + @test expect(Operator(sm), ψ) ≈ 1 + end end end - end - # embedded checks - for single_qubit_explicit_channel in [pcT] - for n in 2:5 - i = rand(1:n) - channel = embed(n,i,single_qubit_explicit_channel) - qo_gate1 = Operator(single_qubit_explicit_channel) - qo_gate = embed(basis(qo_gate1)^n, i, qo_gate1) - stab = random_stabilizer(n) - sm = StabMixture(stab) - ψ = Ket(stab) - for rep in 1:8 - apply!(sm, channel) - ψ = qo_gate*ψ - @test expect(Operator(sm), ψ) ≈ 1 + # embedded checks + for single_qubit_explicit_channel in [pcT] + for n in 2:5 + i = rand(1:n) + channel = embed(n,i,single_qubit_explicit_channel) + qo_gate1 = Operator(single_qubit_explicit_channel) + qo_gate = embed(basis(qo_gate1)^n, i, qo_gate1) + stab = random_stabilizer(n) + sm = StabMixture(stab) + ψ = Ket(stab) + for rep in 1:8 + apply!(sm, channel) + ψ = qo_gate*ψ + @test expect(Operator(sm), ψ) ≈ 1 + end end end end diff --git a/test/test_random.jl b/test/test_random.jl index ee97ffaf8..185de0d22 100644 --- a/test/test_random.jl +++ b/test/test_random.jl @@ -1,58 +1,58 @@ -using QuantumClifford -using Test +@testitem "Random" begin + using QuantumClifford + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Random sampling of operators" begin - for n in [1, test_sizes..., 200,500] - p = random_pauli(n) - s = random_stabilizer(n) - ss = random_stabilizer(rand(1:n),n) - ms = MixedDestabilizer(ss) - d = random_destabilizer(n) - c = random_clifford(n) - sq = random_clifford1(n÷2+1) - @test stab_looks_good(s) - @test stab_looks_good(ss) - @test destab_looks_good(d) - @test mixed_destab_looks_good(ms) - @test stab_looks_good(c*s) - @test stab_looks_good(c*ss) - @test destab_looks_good(c*d) - @test mixed_destab_looks_good(c*ms) - @test stab_looks_good(p*s) - @test stab_looks_good(p*ss) - @test destab_looks_good(p*d) - @test mixed_destab_looks_good(p*ms) - @test stab_looks_good(apply!(s,sq,phases=false)) - @test stab_looks_good(apply!(ss,sq,phases=false)) - @test destab_looks_good(apply!(d,sq,phases=false)) - @test mixed_destab_looks_good(apply!(ms,sq,phases=false)) + @testset "Random sampling of operators" begin + for n in [1, test_sizes..., 200,500] + p = random_pauli(n) + s = random_stabilizer(n) + ss = random_stabilizer(rand(1:n),n) + ms = MixedDestabilizer(ss) + d = random_destabilizer(n) + c = random_clifford(n) + sq = random_clifford1(n÷2+1) + @test stab_looks_good(s) + @test stab_looks_good(ss) + @test destab_looks_good(d) + @test mixed_destab_looks_good(ms) + @test stab_looks_good(c*s) + @test stab_looks_good(c*ss) + @test destab_looks_good(c*d) + @test mixed_destab_looks_good(c*ms) + @test stab_looks_good(p*s) + @test stab_looks_good(p*ss) + @test destab_looks_good(p*d) + @test mixed_destab_looks_good(p*ms) + @test stab_looks_good(apply!(s,sq,phases=false)) + @test stab_looks_good(apply!(ss,sq,phases=false)) + @test destab_looks_good(apply!(d,sq,phases=false)) + @test mixed_destab_looks_good(apply!(ms,sq,phases=false)) + end end -end -@testset "Random Paulis" begin - for n in [1, test_sizes..., 200,500] - @test all((random_pauli(n).phase[] == 0 for _ in 1:100)) - @test all((random_pauli(n, 0.1).phase[] == 0 for _ in 1:100)) - @test any((random_pauli(n; nophase=false, realphase=false).phase[] == 1 for _ in 1:100)) - @test any((random_pauli(n, 0.1; nophase=false, realphase=false).phase[] == 1 for _ in 1:100)) - @test any((random_pauli(n; nophase=false).phase[] ∈ [0,2] for _ in 1:100)) - @test any((random_pauli(n, 0.1; nophase=false).phase[] ∈ [0,2] for _ in 1:100)) - end - for i in 1:10 - e = 0.2 - n = 10000 - expected = 2/3*e * 2 * n - bound = 1/sqrt(n) - @test expected * (1-10bound) <= sum(count_ones.(random_pauli(10000,0.2).xz)) <= expected * (1+10bound) - e = 0.75 - n = 10000 - expected = 2/3*e * 2 * n - bound = 1/sqrt(n) - @test expected * (1-10bound) <= sum(count_ones.(random_pauli(10000).xz)) <= expected * (1+10bound) + @testset "Random Paulis" begin + for n in [1, test_sizes..., 200,500] + @test all((random_pauli(n).phase[] == 0 for _ in 1:100)) + @test all((random_pauli(n, 0.1).phase[] == 0 for _ in 1:100)) + @test any((random_pauli(n; nophase=false, realphase=false).phase[] == 1 for _ in 1:100)) + @test any((random_pauli(n, 0.1; nophase=false, realphase=false).phase[] == 1 for _ in 1:100)) + @test any((random_pauli(n; nophase=false).phase[] ∈ [0,2] for _ in 1:100)) + @test any((random_pauli(n, 0.1; nophase=false).phase[] ∈ [0,2] for _ in 1:100)) + end + for i in 1:10 + e = 0.2 + n = 10000 + expected = 2/3*e * 2 * n + bound = 1/sqrt(n) + @test expected * (1-10bound) <= sum(count_ones.(random_pauli(10000,0.2).xz)) <= expected * (1+10bound) + e = 0.75 + n = 10000 + expected = 2/3*e * 2 * n + bound = 1/sqrt(n) + @test expected * (1-10bound) <= sum(count_ones.(random_pauli(10000).xz)) <= expected * (1+10bound) + end end end diff --git a/test/test_stabcanon.jl b/test/test_stabcanon.jl index 5c113c69b..9db49ba8a 100644 --- a/test/test_stabcanon.jl +++ b/test/test_stabcanon.jl @@ -1,10 +1,6 @@ -using QuantumClifford - -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good - -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Stabilizer canonicalization" begin +@testitem "Stabilizer canonicalization" begin + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. @testset "Default canonicalization" begin s = S"- XZZZZ_____ - _YZY___YX_ @@ -75,7 +71,7 @@ test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off end end -@testset "canonicalization invariants" begin +@testitem "canonicalization invariants" begin s = random_stabilizer(40,100) ss = tensor_pow(s,20) sa1 = canonicalize!(canonicalize_rref!(copy(ss))[1]) diff --git a/test/test_stabs.jl b/test/test_stabs.jl index 59a81d441..63a5c562e 100644 --- a/test/test_stabs.jl +++ b/test/test_stabs.jl @@ -1,93 +1,93 @@ -using Test -using QuantumClifford +@testitem "Stabilizers" begin + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. + @testset "Pure and Mixed state initialization" begin -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good - -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Pure and Mixed state initialization" begin - @testset "Destabilizer initialization" begin - for n in test_sizes - s = random_stabilizer(n) - d = Destabilizer(s) - @test destab_looks_good(d) - canonicalize!(s) - s1 = copy(stabilizerview(d)) - canonicalize!(s1) - @test s1 == s + @testset "Destabilizer initialization" begin + for n in test_sizes + s = random_stabilizer(n) + d = Destabilizer(s) + @test destab_looks_good(d) + canonicalize!(s) + s1 = copy(stabilizerview(d)) + canonicalize!(s1) + @test s1 == s + end + end + @testset "Mixed destabilizer initialization" begin + for n in test_sizes + n<10 && continue + s = random_stabilizer(rand(n÷2+1:n-4),n) + md = MixedDestabilizer(s) + ms = MixedStabilizer(s) + @test mixed_stab_looks_good(ms) + @test mixed_destab_looks_good(md) + canonicalize!(s) + s1 = copy(stabilizerview(md)) + canonicalize!(s1) + @test s1 == s == stabilizerview(canonicalize!(ms)) + end + # Test initialization out of overdetermined stabs + stabs = [S"XX + II", + S"XX + XX", + S"ZZ + ZZ"] + for s in stabs + md = MixedDestabilizer(s[1:1]) + @test MixedDestabilizer(s) == md + end end end - @testset "Mixed destabilizer initialization" begin + + @testset "Tensor products over stabilizers" begin for n in test_sizes n<10 && continue - s = random_stabilizer(rand(n÷2+1:n-4),n) - md = MixedDestabilizer(s) - ms = MixedStabilizer(s) - @test mixed_stab_looks_good(ms) - @test mixed_destab_looks_good(md) + l = random_stabilizer(rand(n÷2+1:n-2),n) + r = random_stabilizer(rand(n÷3:n÷2),rand(n÷2:n)) + s = l⊗r + ds = MixedDestabilizer(l)⊗MixedDestabilizer(r) + @test mixed_destab_looks_good(ds) canonicalize!(s) - s1 = copy(stabilizerview(md)) - canonicalize!(s1) - @test s1 == s == stabilizerview(canonicalize!(ms)) - end - # Test initialization out of overdetermined stabs - stabs = [S"XX - II", - S"XX - XX", - S"ZZ - ZZ"] - for s in stabs - md = MixedDestabilizer(s[1:1]) - @test MixedDestabilizer(s) == md + dss = canonicalize!(copy(stabilizerview(ds))) + @test s == dss + stabs = [s[1:i] for s in [random_stabilizer(n) for n in [32,16,16,64,63,65,129,128,127]] for i in rand(1:10)]; + mdstabs = MixedDestabilizer.(stabs); + @test canonicalize!(⊗(stabs...)) == canonicalize!(stabilizerview(⊗(mdstabs...))) end end -end -@testset "Tensor products over stabilizers" begin - for n in test_sizes - n<10 && continue - l = random_stabilizer(rand(n÷2+1:n-2),n) - r = random_stabilizer(rand(n÷3:n÷2),rand(n÷2:n)) - s = l⊗r - ds = MixedDestabilizer(l)⊗MixedDestabilizer(r) - @test mixed_destab_looks_good(ds) - canonicalize!(s) - dss = canonicalize!(copy(stabilizerview(ds))) - @test s == dss - stabs = [s[1:i] for s in [random_stabilizer(n) for n in [32,16,16,64,63,65,129,128,127]] for i in rand(1:10)]; - mdstabs = MixedDestabilizer.(stabs); - @test canonicalize!(⊗(stabs...)) == canonicalize!(stabilizerview(⊗(mdstabs...))) - end -end -@testset "Stabilizer indexing" begin - s = random_stabilizer(9,10) - @test s[1,1] == s[[1,3,4],[1,3,5]][1,1] - @test s[1,1] == s[:,[1,3,5]][1,1] - @test s[1,1] == s[1,[1,3,5]][1] - @test s[1,1] == s[[1,3,5],:][1,1] - @test s[1,1] == s[[1,3,5],1][1,1] - @test s[1,1] == s[:,1][1,1] - @test s[1,1] == s[1,:][1] - @test s[1,1] == s[:,:][1,1] - @test isa(s[1], PauliOperator) - @test isa(s[1,:], PauliOperator) - @test isa(s[1,[1,2,3]], PauliOperator) - @test axes(s) == (axes(s,1), axes(s,2)) == (Base.OneTo(9),Base.OneTo(10)) - ms = MixedStabilizer(s) - mds = MixedStabilizer(s) - @test length(mds) == length(ms) == 10 - @test length(s) == 9 - for n in test_sizes - s = random_stabilizer(n) - r1 = rand(1:n) - ri1 = deleteat!(collect(1:n),r1) - s1a = QuantumClifford.remove_column!(copy(s),r1) - s1b = copy(s)[:,ri1] - r2 = min(n,rand([63,64,65])) - ri2 = deleteat!(collect(1:n),r2) - s2a = QuantumClifford.remove_column!(copy(s),r2) - s2b = copy(s)[:,ri2] - @test stab_to_gf2(s1a) == stab_to_gf2(s1b) - @test stab_to_gf2(s2a) == stab_to_gf2(s2b) + + @testset "Stabilizer indexing" begin + s = random_stabilizer(9,10) + @test s[1,1] == s[[1,3,4],[1,3,5]][1,1] + @test s[1,1] == s[:,[1,3,5]][1,1] + @test s[1,1] == s[1,[1,3,5]][1] + @test s[1,1] == s[[1,3,5],:][1,1] + @test s[1,1] == s[[1,3,5],1][1,1] + @test s[1,1] == s[:,1][1,1] + @test s[1,1] == s[1,:][1] + @test s[1,1] == s[:,:][1,1] + @test isa(s[1], PauliOperator) + @test isa(s[1,:], PauliOperator) + @test isa(s[1,[1,2,3]], PauliOperator) + @test axes(s) == (axes(s,1), axes(s,2)) == (Base.OneTo(9),Base.OneTo(10)) + ms = MixedStabilizer(s) + mds = MixedStabilizer(s) + @test length(mds) == length(ms) == 10 + @test length(s) == 9 + for n in test_sizes + s = random_stabilizer(n) + r1 = rand(1:n) + ri1 = deleteat!(collect(1:n),r1) + s1a = QuantumClifford.remove_column!(copy(s),r1) + s1b = copy(s)[:,ri1] + r2 = min(n,rand([63,64,65])) + ri2 = deleteat!(collect(1:n),r2) + s2a = QuantumClifford.remove_column!(copy(s),r2) + s2b = copy(s)[:,ri2] + @test stab_to_gf2(s1a) == stab_to_gf2(s1b) + @test stab_to_gf2(s2a) == stab_to_gf2(s2b) + end end end diff --git a/test/test_sumtypecompactification.jl b/test/test_sumtypecompactification.jl index 11c902d4e..63974bed8 100644 --- a/test/test_sumtypecompactification.jl +++ b/test/test_sumtypecompactification.jl @@ -1,7 +1,4 @@ -using Test -using QuantumClifford - -@testset "SumTypes compactification" begin +@testitem "SumTypes compactification" begin @test_warn "Could not compactify the circuit" QuantumClifford.pftrajectories([ClassicalXOR{17}((65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81), 282)]) QuantumClifford.compactify_circuit([ClassicalXOR{3}((65, 66, 67), 282)]) end diff --git a/test/test_symcliff.jl b/test/test_symcliff.jl index 2af1fd538..66ea60154 100644 --- a/test/test_symcliff.jl +++ b/test/test_symcliff.jl @@ -1,80 +1,80 @@ -using Random -using QuantumClifford -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: apply_single_x!, apply_single_y!, apply_single_z! -using InteractiveUtils -using Test -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. +@testitem "Symbolic Clifford" begin + using Random + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good + using QuantumClifford: apply_single_x!, apply_single_y!, apply_single_z! + using InteractiveUtils + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. -@testset "Small symbolic operators" begin - for n in test_sizes - for i in 1:6 - op = enumerate_single_qubit_gates(i, qubit=n, phases=(rand(Bool),rand(Bool))) - op0 = enumerate_single_qubit_gates(i, qubit=n) - op_cc = CliffordOperator(op, 1, compact=true) - op_c = CliffordOperator(op, n) - @test SingleQubitOperator(op)==SingleQubitOperator(op_cc, n) - op0_c = CliffordOperator(op0, n) + @testset "Small symbolic operators" begin + for n in test_sizes + for i in 1:6 + op = enumerate_single_qubit_gates(i, qubit=n, phases=(rand(Bool),rand(Bool))) + op0 = enumerate_single_qubit_gates(i, qubit=n) + op_cc = CliffordOperator(op, 1, compact=true) + op_c = CliffordOperator(op, n) + @test SingleQubitOperator(op)==SingleQubitOperator(op_cc, n) + op0_c = CliffordOperator(op0, n) + s = random_stabilizer(n) + @test apply!(copy(s),op)==apply!(copy(s),SingleQubitOperator(op))==apply!(copy(s),op_cc,[n])==apply!(copy(s),op_c) + @test ==(apply!(copy(s),op,phases=false),apply!(copy(s),op_cc,[n],phases=false), phases=false) + @test apply!(copy(s),op0)==apply!(copy(s),op0_c) + end + i = n÷2+1 + @test apply!(copy(s),sX(i)) == apply_single_x!(copy(s),i) + @test apply!(copy(s),sY(i)) == apply_single_y!(copy(s),i) + @test apply!(copy(s),sZ(i)) == apply_single_z!(copy(s),i) + n==1 && continue s = random_stabilizer(n) - @test apply!(copy(s),op)==apply!(copy(s),SingleQubitOperator(op))==apply!(copy(s),op_cc,[n])==apply!(copy(s),op_c) - @test ==(apply!(copy(s),op,phases=false),apply!(copy(s),op_cc,[n],phases=false), phases=false) - @test apply!(copy(s),op0)==apply!(copy(s),op0_c) + i1,i2 = randperm(n)[1:2] + @test apply!(copy(s),tCNOT,[i1,i2]) == apply!(copy(s),sCNOT(i1,i2)) + @test apply!(copy(s),tSWAP,[i1,i2]) == apply!(copy(s),sSWAP(i1,i2)) + @test apply!(copy(s),tCPHASE,[i1,i2]) == apply!(copy(s),sCPHASE(i1,i2)) end - i = n÷2+1 - @test apply!(copy(s),sX(i)) == apply_single_x!(copy(s),i) - @test apply!(copy(s),sY(i)) == apply_single_y!(copy(s),i) - @test apply!(copy(s),sZ(i)) == apply_single_z!(copy(s),i) - n==1 && continue - s = random_stabilizer(n) - i1,i2 = randperm(n)[1:2] - @test apply!(copy(s),tCNOT,[i1,i2]) == apply!(copy(s),sCNOT(i1,i2)) - @test apply!(copy(s),tSWAP,[i1,i2]) == apply!(copy(s),sSWAP(i1,i2)) - @test apply!(copy(s),tCPHASE,[i1,i2]) == apply!(copy(s),sCPHASE(i1,i2)) + @test_throws DimensionMismatch SingleQubitOperator(tCNOT,1) + @test_throws DimensionMismatch CliffordOperator(sHadamard(5),2) + @test_throws ArgumentError CliffordOperator(sHadamard(5),6,compact=true) end - @test_throws DimensionMismatch SingleQubitOperator(tCNOT,1) - @test_throws DimensionMismatch CliffordOperator(sHadamard(5),2) - @test_throws ArgumentError CliffordOperator(sHadamard(5),6,compact=true) -end -@testset "Convert between small ops" begin - for op in subtypes(QuantumClifford.AbstractSingleQubitOperator) - op == SingleQubitOperator && continue - sop = op(1) - sqsop = SingleQubitOperator(sop) - cop = CliffordOperator(sop,1) - csqop = CliffordOperator(sqsop,1) - tcop = CliffordOperator(op) - stcop = SingleQubitOperator(tcop) - s = random_destabilizer(1) - @test sop*s == sqsop*s == cop*s == csqop*s == tcop*s == stcop*s - end - for op in subtypes(QuantumClifford.AbstractTwoQubitOperator) - sop = op(1,2) - cop = CliffordOperator(sop,2) - ccop = CliffordOperator(sop,2; compact=true) - @test_throws DimensionMismatch CliffordOperator(op(1,4),3) - @test_throws ArgumentError CliffordOperator(sop,3; compact=true) - tcop = CliffordOperator(op) - s = random_destabilizer(2) - @test sop*s == cop*s == tcop*s == ccop*s - end - for op in subtypes(QuantumClifford.AbstractTwoQubitOperator) - sop = op(1,10) - op1 = CliffordOperator(sop,20) - op2 = sSWAP(2,10)*(CliffordOperator(sop,2; compact=true)⊗tensor_pow(tId1, 18))*CliffordOperator(sSWAP(2,10),20) - @test op1 == op2 + @testset "Convert between small ops" begin + for op in subtypes(QuantumClifford.AbstractSingleQubitOperator) + op == SingleQubitOperator && continue + sop = op(1) + sqsop = SingleQubitOperator(sop) + cop = CliffordOperator(sop,1) + csqop = CliffordOperator(sqsop,1) + tcop = CliffordOperator(op) + stcop = SingleQubitOperator(tcop) + s = random_destabilizer(1) + @test sop*s == sqsop*s == cop*s == csqop*s == tcop*s == stcop*s + end + for op in subtypes(QuantumClifford.AbstractTwoQubitOperator) + sop = op(1,2) + cop = CliffordOperator(sop,2) + ccop = CliffordOperator(sop,2; compact=true) + @test_throws DimensionMismatch CliffordOperator(op(1,4),3) + @test_throws ArgumentError CliffordOperator(sop,3; compact=true) + tcop = CliffordOperator(op) + s = random_destabilizer(2) + @test sop*s == cop*s == tcop*s == ccop*s + end + for op in subtypes(QuantumClifford.AbstractTwoQubitOperator) + sop = op(1,10) + op1 = CliffordOperator(sop,20) + op2 = sSWAP(2,10)*(CliffordOperator(sop,2; compact=true)⊗tensor_pow(tId1, 18))*CliffordOperator(sSWAP(2,10),20) + @test op1 == op2 + end end -end -@testset "SingleQubitOperator inv methods" begin - for gate_type in [sHadamard, sX, sY, sZ, sId1 , sPhase, sInvPhase] - n = rand(1:10) - @test CliffordOperator(inv(SingleQubitOperator(gate_type(n))), n) == inv(CliffordOperator(gate_type(n), n)) - @test CliffordOperator(inv(gate_type(n)), n) == inv(CliffordOperator(gate_type(n), n)) - end - for i in 1:10 - random_op = random_clifford1(i) - @test CliffordOperator(inv(random_op), i) == inv(CliffordOperator(random_op, i)) - @test CliffordOperator(inv(SingleQubitOperator(random_op)), i) == inv(CliffordOperator(random_op, i)) + @testset "SingleQubitOperator inv methods" begin + for gate_type in [sHadamard, sX, sY, sZ, sId1 , sPhase, sInvPhase] + n = rand(1:10) + @test CliffordOperator(inv(SingleQubitOperator(gate_type(n))), n) == inv(CliffordOperator(gate_type(n), n)) + @test CliffordOperator(inv(gate_type(n)), n) == inv(CliffordOperator(gate_type(n), n)) + end + for i in 1:10 + random_op = random_clifford1(i) + @test CliffordOperator(inv(random_op), i) == inv(CliffordOperator(random_op, i)) + @test CliffordOperator(inv(SingleQubitOperator(random_op)), i) == inv(CliffordOperator(random_op, i)) + end end end diff --git a/test/test_symcontrolled.jl b/test/test_symcontrolled.jl index e69553ed4..256f62be3 100644 --- a/test/test_symcontrolled.jl +++ b/test/test_symcontrolled.jl @@ -1,128 +1,128 @@ -using Test -using QuantumClifford -using QuantumOpticsBase +@testitem "Controlled" begin + using QuantumOpticsBase -function transform_Zbasis(qubit) - transformations = Dict(:X => [sHadamard(qubit),], :Y => [sInvPhase(qubit),sHadamard(qubit)], :Z => [sHadamard(qubit), sHadamard(qubit)]) - inverse_transformations = Dict(:X => [sHadamard(qubit),], :Y => [sHadamard(qubit), sPhase(qubit)], :Z => [sHadamard(qubit), sHadamard(qubit)]) - return transformations, inverse_transformations -end + function transform_Zbasis(qubit) + transformations = Dict(:X => [sHadamard(qubit),], :Y => [sInvPhase(qubit),sHadamard(qubit)], :Z => [sHadamard(qubit), sHadamard(qubit)]) + inverse_transformations = Dict(:X => [sHadamard(qubit),], :Y => [sHadamard(qubit), sPhase(qubit)], :Z => [sHadamard(qubit), sHadamard(qubit)]) + return transformations, inverse_transformations + end -function transform_Xbasis(qubit) - transformations = Dict(:Z => [sHadamard(qubit),], :Y => [sInvPhase(qubit),], :X => [sHadamard(qubit), sHadamard(qubit)]) - inverse_transformations = Dict(:Z => [sHadamard(qubit)], :Y => [sPhase(qubit),], :X => [sHadamard(qubit), sHadamard(qubit)]) - return transformations, inverse_transformations -end + function transform_Xbasis(qubit) + transformations = Dict(:Z => [sHadamard(qubit),], :Y => [sInvPhase(qubit),], :X => [sHadamard(qubit), sHadamard(qubit)]) + inverse_transformations = Dict(:Z => [sHadamard(qubit)], :Y => [sPhase(qubit),], :X => [sHadamard(qubit), sHadamard(qubit)]) + return transformations, inverse_transformations + end -function get_gates(control, target) - transform1, inverse1 = transform_Zbasis(1) - transform2, inverse2 = transform_Xbasis(2) - return [transform1[control]..., transform2[target]...], [inverse2[target]..., inverse1[control]...] -end + function get_gates(control, target) + transform1, inverse1 = transform_Zbasis(1) + transform2, inverse2 = transform_Xbasis(2) + return [transform1[control]..., transform2[target]...], [inverse2[target]..., inverse1[control]...] + end -@testset "Controlled gates" begin - for i in 1:10 - for control in (:X, :Y, :Z) - for target in (:X, :Y, :Z) - random_state = random_destabilizer(2) - implemented_gate = eval(Symbol(:s,control,:C,target))(1,2) + @testset "Controlled gates" begin + for i in 1:10 + for control in (:X, :Y, :Z) + for target in (:X, :Y, :Z) + random_state = random_destabilizer(2) + implemented_gate = eval(Symbol(:s,control,:C,target))(1,2) - tr, inv = get_gates(control, target) - test_gates = [tr..., sCNOT(1,2), inv...] - @test apply!(copy(random_state), implemented_gate) == mctrajectory!(copy(random_state), test_gates)[1] + tr, inv = get_gates(control, target) + test_gates = [tr..., sCNOT(1,2), inv...] + @test apply!(copy(random_state), implemented_gate) == mctrajectory!(copy(random_state), test_gates)[1] + end end end end -end -transforms = Dict(:X => transform_Xbasis(1), :Z => transform_Zbasis(1)) + transforms = Dict(:X => transform_Xbasis(1), :Z => transform_Zbasis(1)) -@testset "Change of basis" begin - for to_basis in (:X, :Y, :Z) - for from_basis in (:X, :Z) - start_state = Stabilizer(QuantumClifford._T_str(string(from_basis))) - forward, backward = transforms[from_basis][1][to_basis], transforms[from_basis][2][to_basis] - mid_state = mctrajectory!(copy(start_state), backward)[1] - end_state = mctrajectory!(copy(mid_state), forward)[1] - @test start_state == end_state - @test mid_state == Stabilizer(QuantumClifford._T_str(string(to_basis))) + @testset "Change of basis" begin + for to_basis in (:X, :Y, :Z) + for from_basis in (:X, :Z) + start_state = Stabilizer(QuantumClifford._T_str(string(from_basis))) + forward, backward = transforms[from_basis][1][to_basis], transforms[from_basis][2][to_basis] + mid_state = mctrajectory!(copy(start_state), backward)[1] + end_state = mctrajectory!(copy(mid_state), forward)[1] + @test start_state == end_state + @test mid_state == Stabilizer(QuantumClifford._T_str(string(to_basis))) + end end end -end -@testset "Explicit control" begin - for control in (:X, :Z, :Y) - for target in (:X, :Z, :Y) - for targetstate in ("X","Y","Z") - twoqgate = eval(Symbol(:s,control,:C,target))(1,2) - oneqgate = eval(Symbol(:s,target))(2) - state0str = string(control)*"I I"*targetstate - state1str = "-"*string(control)*"I I"*targetstate - state0 = Stabilizer(QuantumClifford._T_str(string(state0str))) - state1 = Stabilizer(QuantumClifford._T_str(string(state1str))) - @test canonicalize!(twoqgate*state0) == canonicalize!(state0) - @test canonicalize!(twoqgate*state1) == canonicalize!(oneqgate*state1) + @testset "Explicit control" begin + for control in (:X, :Z, :Y) + for target in (:X, :Z, :Y) + for targetstate in ("X","Y","Z") + twoqgate = eval(Symbol(:s,control,:C,target))(1,2) + oneqgate = eval(Symbol(:s,target))(2) + state0str = string(control)*"I I"*targetstate + state1str = "-"*string(control)*"I I"*targetstate + state0 = Stabilizer(QuantumClifford._T_str(string(state0str))) + state1 = Stabilizer(QuantumClifford._T_str(string(state1str))) + @test canonicalize!(twoqgate*state0) == canonicalize!(state0) + @test canonicalize!(twoqgate*state1) == canonicalize!(oneqgate*state1) + end end end end -end -@testset "Control-Target swap" begin - for control in (:X, :Z, :Y) - for target in (:X, :Z, :Y) - forwgate = eval(Symbol(:s,control,:C,target))(1,2) - backgate = eval(Symbol(:s,target,:C,control))(1,2) - forwgatedense = CliffordOperator(forwgate, 2) - backgatedense = CliffordOperator(backgate, 2) - @test forwgatedense == tSWAP*backgatedense*tSWAP + @testset "Control-Target swap" begin + for control in (:X, :Z, :Y) + for target in (:X, :Z, :Y) + forwgate = eval(Symbol(:s,control,:C,target))(1,2) + backgate = eval(Symbol(:s,target,:C,control))(1,2) + forwgatedense = CliffordOperator(forwgate, 2) + backgatedense = CliffordOperator(backgate, 2) + @test forwgatedense == tSWAP*backgatedense*tSWAP + end end - end - for control in (:X, :Z, :Y) - for target in (:X, :Z, :Y) - forwgate = eval(Symbol(:s,control,:C,target))(1,2) - backgate = eval(Symbol(:s,target,:C,control))(2,1) - forwgatedense = CliffordOperator(forwgate, 2) - backgatedense = CliffordOperator(backgate, 2) - @test forwgatedense == backgatedense + for control in (:X, :Z, :Y) + for target in (:X, :Z, :Y) + forwgate = eval(Symbol(:s,control,:C,target))(1,2) + backgate = eval(Symbol(:s,target,:C,control))(2,1) + forwgatedense = CliffordOperator(forwgate, 2) + backgatedense = CliffordOperator(backgate, 2) + @test forwgatedense == backgatedense + end end - end - for (gate1,gate2) in ( - (sCNOT(1,2), sZCX(1,2)), - (sCPHASE(1,2), sZCZ(1,2)), - ) - gate1dense = CliffordOperator(gate1, 2) - gate2dense = CliffordOperator(gate2, 2) - @test gate1dense == gate2dense + for (gate1,gate2) in ( + (sCNOT(1,2), sZCX(1,2)), + (sCPHASE(1,2), sZCZ(1,2)), + ) + gate1dense = CliffordOperator(gate1, 2) + gate2dense = CliffordOperator(gate2, 2) + @test gate1dense == gate2dense + end end -end -@testset "Ket-based definition" begin - for control in (:X, :Y, :Z) - for target in (:X, :Y, :Z) - s = Stabilizer(QuantumClifford._T_str(string(control))) - k1 = Ket(s) - s.tab.phases[1] = 0x2 - k2 = Ket(s) - i = Operator(tId1) - o = Operator(CliffordOperator(eval(Symbol(:s,target,))(1),1)) - gate = projector(k1)⊗i + (target==:Y ? -im : 1) * projector(k2)⊗o - implemented_gate = Operator(CliffordOperator(eval(Symbol(:s,control,:C,target))(1,2),2)) - @test gate≈implemented_gate + @testset "Ket-based definition" begin + for control in (:X, :Y, :Z) + for target in (:X, :Y, :Z) + s = Stabilizer(QuantumClifford._T_str(string(control))) + k1 = Ket(s) + s.tab.phases[1] = 0x2 + k2 = Ket(s) + i = Operator(tId1) + o = Operator(CliffordOperator(eval(Symbol(:s,target,))(1),1)) + gate = projector(k1)⊗i + (target==:Y ? -im : 1) * projector(k2)⊗o + implemented_gate = Operator(CliffordOperator(eval(Symbol(:s,control,:C,target))(1,2),2)) + @test gate≈implemented_gate - target, control = control, target - s = Stabilizer(QuantumClifford._T_str(string(control))) - k1 = Ket(s) - s.tab.phases[1] = 0x2 - k2 = Ket(s) - i = Operator(tId1) - o = Operator(CliffordOperator(eval(Symbol(:s,target,))(1),1)) - gate_perm = projector(k1)⊗i + (target==:Y ? -im : 1) * projector(k2)⊗o - implemented_gate_perm = Operator(CliffordOperator(eval(Symbol(:s,control,:C,target))(1,2),2)) - @test gate_perm≈implemented_gate_perm + target, control = control, target + s = Stabilizer(QuantumClifford._T_str(string(control))) + k1 = Ket(s) + s.tab.phases[1] = 0x2 + k2 = Ket(s) + i = Operator(tId1) + o = Operator(CliffordOperator(eval(Symbol(:s,target,))(1),1)) + gate_perm = projector(k1)⊗i + (target==:Y ? -im : 1) * projector(k2)⊗o + implemented_gate_perm = Operator(CliffordOperator(eval(Symbol(:s,control,:C,target))(1,2),2)) + @test gate_perm≈implemented_gate_perm - @test permutesystems(gate_perm,[2,1])≈gate + @test permutesystems(gate_perm,[2,1])≈gate + end end end end diff --git a/test/test_syndromemeas.jl b/test/test_syndromemeas.jl index 23526250d..3e6ef06b9 100644 --- a/test/test_syndromemeas.jl +++ b/test/test_syndromemeas.jl @@ -1,7 +1,5 @@ -using QuantumClifford -using QuantumClifford: AbstractOperation - -@testset "Syndrome Measurements with mctrajectory!" begin # TODO this is a rather old test that is now done in a few other places, e.g. the ECC module -- double check and consider deleting +@testitem "Syndrome Measurements with mctrajectory!" begin # TODO this is a rather old test that is now done in a few other places, e.g. the ECC module -- double check and consider deleting + using QuantumClifford: AbstractOperation codeˢᵗᵉᵃⁿᵉ = S"Z__Z_ZZ _Z_ZZ_Z __Z_ZZZ diff --git a/test/test_throws.jl b/test/test_throws.jl index 724cc7de5..2c67f4f4a 100644 --- a/test/test_throws.jl +++ b/test/test_throws.jl @@ -1,67 +1,66 @@ -using Test -using QuantumClifford -using QuantumClifford: rank, mul_left!, mul_right! -using InteractiveUtils: subtypes +@testitem "throws" begin + using QuantumClifford: rank, mul_left!, mul_right! + using InteractiveUtils: subtypes + @test_throws DimensionMismatch CliffordOperator(T"XXX ZZ_") -@test_throws DimensionMismatch CliffordOperator(T"XXX ZZ_") + @test_throws DimensionMismatch tCNOT*S"X" -@test_throws DimensionMismatch tCNOT*S"X" + #@test_throws DomainError bigram(random_stabilizer(50), clip=false) -#@test_throws DomainError bigram(random_stabilizer(50), clip=false) + @test_throws DomainError logdot(S"XX", S"XX ZZ") + @test_throws DimensionMismatch logdot(S"X", S"XX ZZ") -@test_throws DomainError logdot(S"XX", S"XX ZZ") -@test_throws DimensionMismatch logdot(S"X", S"XX ZZ") + @test_throws BadDataStructure rank(S"X") + @test_throws BadDataStructure rank(Destabilizer(S"X")) -@test_throws BadDataStructure rank(S"X") -@test_throws BadDataStructure rank(Destabilizer(S"X")) + @test_throws DimensionMismatch mul_left!(P"X", P"XX") + @test_throws DimensionMismatch mul_right!(P"X", P"XX") -@test_throws DimensionMismatch mul_left!(P"X", P"XX") -@test_throws DimensionMismatch mul_right!(P"X", P"XX") + @test_throws ArgumentError StabMixture(S"XX") -@test_throws ArgumentError StabMixture(S"XX") + @test_throws ArgumentError UnitaryPauliChannel([P"X"], [1,2]) + @test_throws ArgumentError UnitaryPauliChannel([P"X",P"XX"], [1,2]) -@test_throws ArgumentError UnitaryPauliChannel([P"X"], [1,2]) -@test_throws ArgumentError UnitaryPauliChannel([P"X",P"XX"], [1,2]) + @test_throws ArgumentError embed(10,2,P"XX") + @test_throws ArgumentError embed(10,[2,3],P"X") -@test_throws ArgumentError embed(10,2,P"XX") -@test_throws ArgumentError embed(10,[2,3],P"X") + struct A <: QuantumClifford.AbstractOperation end + @test_throws ArgumentError applybranches(S"X",A()) -struct A <: QuantumClifford.AbstractOperation end -@test_throws ArgumentError applybranches(S"X",A()) + @test_throws BadDataStructure project!(Destabilizer(S"XX"), P"ZZ") -@test_throws BadDataStructure project!(Destabilizer(S"XX"), P"ZZ") + @test_throws DimensionMismatch reset_qubits!(ghz(4), ghz(3), [1,2]) + @test_throws DimensionMismatch reset_qubits!(ghz(3), ghz(4), [1,2,3,4]) + @test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(4)), MixedStabilizer(ghz(3)), [1,2]) + @test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(3)), MixedStabilizer(ghz(4)), [1,2,3,4]) + @test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(4)), MixedDestabilizer(ghz(3)), [1,2]) + @test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(3)), MixedDestabilizer(ghz(4)), [1,2,3,4]) -@test_throws DimensionMismatch reset_qubits!(ghz(4), ghz(3), [1,2]) -@test_throws DimensionMismatch reset_qubits!(ghz(3), ghz(4), [1,2,3,4]) -@test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(4)), MixedStabilizer(ghz(3)), [1,2]) -@test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(3)), MixedStabilizer(ghz(4)), [1,2,3,4]) -@test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(4)), MixedDestabilizer(ghz(3)), [1,2]) -@test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(3)), MixedDestabilizer(ghz(4)), [1,2,3,4]) + #TODO broken in other ways @test_throws DomainError MixedDestabilizer(Destabilizer(S"XX")) -#TODO broken in other ways @test_throws DomainError MixedDestabilizer(Destabilizer(S"XX")) + @test_throws DomainError 2*P"X" -@test_throws DomainError 2*P"X" + @test_throws DimensionMismatch P"X" * S"XX" -@test_throws DimensionMismatch P"X" * S"XX" + @test_throws ArgumentError one(typeof(T"X"), 1, basis=:U) -@test_throws ArgumentError one(typeof(T"X"), 1, basis=:U) + for gt in subtypes(QuantumClifford.AbstractSingleQubitOperator) + gt == SingleQubitOperator && continue + @test_throws ArgumentError gt(0) + @test_throws ArgumentError gt(-1) + end -for gt in subtypes(QuantumClifford.AbstractSingleQubitOperator) - gt == SingleQubitOperator && continue - @test_throws ArgumentError gt(0) - @test_throws ArgumentError gt(-1) -end - -for gt in subtypes(QuantumClifford.AbstractTwoQubitOperator) - @test_throws ArgumentError gt(0,1) - @test_throws ArgumentError gt(-1,1) - @test_throws ArgumentError gt(2,2) -end + for gt in subtypes(QuantumClifford.AbstractTwoQubitOperator) + @test_throws ArgumentError gt(0,1) + @test_throws ArgumentError gt(-1,1) + @test_throws ArgumentError gt(2,2) + end -for m in [sMX,sMZ,sMY,sMRX,sMRZ,sMRY] - @test_throws ArgumentError m(0) - @test_throws ArgumentError m(-1) - @test_throws ArgumentError m(0,1) - @test_throws ArgumentError m(-1,0) + for m in [sMX,sMZ,sMY,sMRX,sMRZ,sMRY] + @test_throws ArgumentError m(0) + @test_throws ArgumentError m(-1) + @test_throws ArgumentError m(0,1) + @test_throws ArgumentError m(-1,0) + end end diff --git a/test/test_trace.jl b/test/test_trace.jl index bb74dd77f..424399ce1 100644 --- a/test/test_trace.jl +++ b/test/test_trace.jl @@ -1,109 +1,108 @@ -using Random -using QuantumClifford +@testitem "Trace" begin + using Random + using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good -using QuantumClifford: stab_looks_good, destab_looks_good, mixed_stab_looks_good, mixed_destab_looks_good - -test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. - -@testset "Partial traces" begin - @testset "RREF canonicalization vs manual traceout" begin - for N in test_sizes - for n in [N,rand(N÷4:N÷2)] - to_delete = randperm(N)[1:rand(N÷4:N÷2)] - stab0 = random_stabilizer(n, N) - id_paulis = zero(PauliOperator, N) - # Trace out by doing projective measurements - naive_stab = copy(stab0) - for i in to_delete - naive_stab, anticom_index, result = project!(naive_stab, single_x(N,i)) - if anticom_index!=0 && anticom_index<=length(naive_stab) - naive_stab[anticom_index] = id_paulis + test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding. + @testset "Partial traces" begin + @testset "RREF canonicalization vs manual traceout" begin + for N in test_sizes + for n in [N,rand(N÷4:N÷2)] + to_delete = randperm(N)[1:rand(N÷4:N÷2)] + stab0 = random_stabilizer(n, N) + id_paulis = zero(PauliOperator, N) + # Trace out by doing projective measurements + naive_stab = copy(stab0) + for i in to_delete + naive_stab, anticom_index, result = project!(naive_stab, single_x(N,i)) + if anticom_index!=0 && anticom_index<=length(naive_stab) + naive_stab[anticom_index] = id_paulis + end + naive_stab, anticom_index, result = project!(naive_stab, single_z(N,i)) + if anticom_index!=0 && anticom_index<=length(naive_stab) + naive_stab[anticom_index] = id_paulis + end end - naive_stab, anticom_index, result = project!(naive_stab, single_z(N,i)) - if anticom_index!=0 && anticom_index<=length(naive_stab) - naive_stab[anticom_index] = id_paulis + canonicalize!(naive_stab) + # Trace out by using the RREF canonical form + stab = copy(stab0) + stab, last_row = canonicalize_rref!(stab, to_delete) + for i in last_row+1:n + stab[i] = id_paulis end + canonicalize!(stab) + # Confirm the results are the same + @test stab == naive_stab + @test mixed_stab_looks_good(stab[1:last_row]) + # Check the built-in traceout! functions for this + s = traceout!(copy(stab0), to_delete) + canonicalize!(s) + @test stab == s + # On MixedStabilizer instances + s = traceout!(MixedStabilizer(copy(stab0), n), to_delete) + canonicalize!(s) + @test stab[1:last_row] == stabilizerview(s) + @test mixed_stab_looks_good(s) + # On MixedDestabilizer instances + s = traceout!(MixedDestabilizer(copy(stab0)), to_delete) + @test mixed_destab_looks_good(s) + s = canonicalize!(stabilizerview(s)) + @test stab[1:last_row] == s end - canonicalize!(naive_stab) - # Trace out by using the RREF canonical form - stab = copy(stab0) - stab, last_row = canonicalize_rref!(stab, to_delete) - for i in last_row+1:n - stab[i] = id_paulis - end - canonicalize!(stab) - # Confirm the results are the same - @test stab == naive_stab - @test mixed_stab_looks_good(stab[1:last_row]) - # Check the built-in traceout! functions for this - s = traceout!(copy(stab0), to_delete) - canonicalize!(s) - @test stab == s - # On MixedStabilizer instances - s = traceout!(MixedStabilizer(copy(stab0), n), to_delete) - canonicalize!(s) - @test stab[1:last_row] == stabilizerview(s) - @test mixed_stab_looks_good(s) - # On MixedDestabilizer instances - s = traceout!(MixedDestabilizer(copy(stab0)), to_delete) - @test mixed_destab_looks_good(s) - s = canonicalize!(stabilizerview(s)) - @test stab[1:last_row] == s end end end -end -@testset "Qubit resets" begin - @test_throws DimensionMismatch reset_qubits!(S"XX YY",S"X",[1,2]) - @test_throws DimensionMismatch reset_qubits!(S"X",S"XX YY",[1,2]) - @test_throws DimensionMismatch reset_qubits!(MixedStabilizer(S"XX YY"),S"X",[1,2]) - @test_throws DimensionMismatch reset_qubits!(MixedStabilizer(S"X"),S"XX YY",[1,2]) - @test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(S"XX YY"),S"X",[1,2]) - @test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(S"X"),S"XX YY",[1,2]) - for N in test_sizes - for R in [rand(N÷2:N*2÷3), N] - R > 0 || continue - s = random_stabilizer(R,N) - nnew = rand(N÷4:N*2÷3) - nnew > 0 || continue - newstate = random_stabilizer(nnew) - perm = randperm(N)[1:nqubits(newstate)] - to_trace = setdiff(1:N,perm) - resetop = Reset(newstate, perm) - # Testing MixedDestabilizer - md = MixedDestabilizer(s) - mdr1 = reset_qubits!(copy(md), newstate,perm) - @test mixed_destab_looks_good(mdr1) - mdr2 = reset_qubits!(copy(mdr1),newstate,perm) - mdro = apply!(copy(md), resetop) - @test canonicalize!(copy(stabilizerview(mdr1)))==canonicalize!(copy(stabilizerview(mdr2)))==canonicalize!(copy(stabilizerview(mdro))) - traceout!(mdr2,to_trace) - mdr2v = stabilizerview(mdr2) - @test canonicalize!(copy(mdr2v)[:,perm]) == canonicalize!(copy(newstate)) - # Testing MixedStabilizer - ms = MixedStabilizer(s) - msr1 = reset_qubits!(copy(ms), newstate,perm) - @test mixed_stab_looks_good(msr1) - msr2 = reset_qubits!(copy(msr1),newstate,perm) - msro = apply!(copy(ms), resetop) - @test msr1==msr2==msro - traceout!(msr2,to_trace) - msr2v = stabilizerview(msr2) - @test canonicalize!(copy(msr2v)[:,perm]) == canonicalize!(copy(newstate)) - @test canonicalize!(msr2v) == canonicalize!(mdr2v) - # Testing Stabilizer - ss = R==N ? s : Stabilizer(tab(MixedStabilizer(s))) # Ensure the tableau is padded with Is - ssr1 = reset_qubits!(copy(ss), newstate,perm) - ssr2 = reset_qubits!(copy(ssr1),newstate,perm) - ssro = apply!(copy(ss), resetop) - @test canonicalize!(ssr1)==canonicalize!(ssr2)==canonicalize!(ssro) - traceout!(ssr2,to_trace) - ssr2v = stabilizerview(ssr2) - c, x, z = canonicalize!(ssr2v, ranks=true) - @test canonicalize!(copy(ssr2v)[:,perm])[1:z] == canonicalize!(copy(newstate)) - @test canonicalize!(msr2v) == c[1:z] - # Compare different datastractures - @test canonicalize!(copy(stabilizerview(mdr1)))==canonicalize!(copy(stabilizerview(msr1)))==canonicalize!(ssr1[1:mdr1.rank]) + @testset "Qubit resets" begin + @test_throws DimensionMismatch reset_qubits!(S"XX YY",S"X",[1,2]) + @test_throws DimensionMismatch reset_qubits!(S"X",S"XX YY",[1,2]) + @test_throws DimensionMismatch reset_qubits!(MixedStabilizer(S"XX YY"),S"X",[1,2]) + @test_throws DimensionMismatch reset_qubits!(MixedStabilizer(S"X"),S"XX YY",[1,2]) + @test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(S"XX YY"),S"X",[1,2]) + @test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(S"X"),S"XX YY",[1,2]) + for N in test_sizes + for R in [rand(N÷2:N*2÷3), N] + R > 0 || continue + s = random_stabilizer(R,N) + nnew = rand(N÷4:N*2÷3) + nnew > 0 || continue + newstate = random_stabilizer(nnew) + perm = randperm(N)[1:nqubits(newstate)] + to_trace = setdiff(1:N,perm) + resetop = Reset(newstate, perm) + # Testing MixedDestabilizer + md = MixedDestabilizer(s) + mdr1 = reset_qubits!(copy(md), newstate,perm) + @test mixed_destab_looks_good(mdr1) + mdr2 = reset_qubits!(copy(mdr1),newstate,perm) + mdro = apply!(copy(md), resetop) + @test canonicalize!(copy(stabilizerview(mdr1)))==canonicalize!(copy(stabilizerview(mdr2)))==canonicalize!(copy(stabilizerview(mdro))) + traceout!(mdr2,to_trace) + mdr2v = stabilizerview(mdr2) + @test canonicalize!(copy(mdr2v)[:,perm]) == canonicalize!(copy(newstate)) + # Testing MixedStabilizer + ms = MixedStabilizer(s) + msr1 = reset_qubits!(copy(ms), newstate,perm) + @test mixed_stab_looks_good(msr1) + msr2 = reset_qubits!(copy(msr1),newstate,perm) + msro = apply!(copy(ms), resetop) + @test msr1==msr2==msro + traceout!(msr2,to_trace) + msr2v = stabilizerview(msr2) + @test canonicalize!(copy(msr2v)[:,perm]) == canonicalize!(copy(newstate)) + @test canonicalize!(msr2v) == canonicalize!(mdr2v) + # Testing Stabilizer + ss = R==N ? s : Stabilizer(tab(MixedStabilizer(s))) # Ensure the tableau is padded with Is + ssr1 = reset_qubits!(copy(ss), newstate,perm) + ssr2 = reset_qubits!(copy(ssr1),newstate,perm) + ssro = apply!(copy(ss), resetop) + @test canonicalize!(ssr1)==canonicalize!(ssr2)==canonicalize!(ssro) + traceout!(ssr2,to_trace) + ssr2v = stabilizerview(ssr2) + c, x, z = canonicalize!(ssr2v, ranks=true) + @test canonicalize!(copy(ssr2v)[:,perm])[1:z] == canonicalize!(copy(newstate)) + @test canonicalize!(msr2v) == c[1:z] + # Compare different datastractures + @test canonicalize!(copy(stabilizerview(mdr1)))==canonicalize!(copy(stabilizerview(msr1)))==canonicalize!(ssr1[1:mdr1.rank]) + end end end end