mirror of
https://github.com/qwjyh/QuantumLegos.jl.git
synced 2024-11-22 07:00:12 +09:00
406 lines
16 KiB
Julia
406 lines
16 KiB
Julia
|
# for language server completion
|
||
|
# must be removed for test
|
||
|
true || include("../src/QuantumLegos.jl")
|
||
|
|
||
|
using QuantumLegos
|
||
|
using Test
|
||
|
using Documenter
|
||
|
using Aqua
|
||
|
using JET
|
||
|
|
||
|
@testset "QuantumLegos.jl" begin
|
||
|
@testset "PauliOps" begin
|
||
|
include("pauliops.jl")
|
||
|
end
|
||
|
|
||
|
@testset "Lego" begin
|
||
|
stabilizers = pauliop.(["II", "XX"])
|
||
|
wrong_stabilizers = pauliop.(["I", "XX"]) # not SVector
|
||
|
@info stabilizers
|
||
|
@test_throws ArgumentError QuantumLegos.Lego(3, stabilizers)
|
||
|
@test_throws MethodError QuantumLegos.Lego(2, wrong_stabilizers)
|
||
|
end
|
||
|
|
||
|
@testset "CheckMatrix" begin
|
||
|
@test_throws ArgumentError QuantumLegos.CheckMatrix([true false; false true], 2, 2)
|
||
|
@test_throws ArgumentError QuantumLegos.CheckMatrix([true false; false true], 1, 1)
|
||
|
@test QuantumLegos.CheckMatrix([true false; false true]) ==
|
||
|
QuantumLegos.CheckMatrix(Bool[1 0; 0 1], 1, 2)
|
||
|
@test_throws ArgumentError QuantumLegos.CheckMatrix([true false true; false true true])
|
||
|
|
||
|
@test_throws MethodError QuantumLegos.checkmatrix(pauliop.(["I", "IX"]))
|
||
|
@test_throws ArgumentError QuantumLegos.checkmatrix(PauliOps.PauliOp[])
|
||
|
@test QuantumLegos.checkmatrix(pauliop.(["IIXX", "IZZI"])) ==
|
||
|
QuantumLegos.CheckMatrix(Bool[0 0 1 1 0 0 0 0; 0 0 0 0 0 1 1 0])
|
||
|
@test QuantumLegos.checkmatrix(pauliop.(["YIXX", "IZYI"])) ==
|
||
|
QuantumLegos.CheckMatrix(Bool[1 0 1 1 1 0 0 0; 0 0 1 0 0 1 1 0])
|
||
|
|
||
|
let
|
||
|
gens = pauliop.(["IIXX", "IZZI"])
|
||
|
cmat_1 = QuantumLegos.checkmatrix(gens)
|
||
|
@test QuantumLegos.xpart(cmat_1) == Bool[0 0 1 1; 0 0 0 0]
|
||
|
@test QuantumLegos.zpart(cmat_1) == Bool[0 0 0 0; 0 1 1 0]
|
||
|
@test generators(cmat_1) == gens
|
||
|
end
|
||
|
let
|
||
|
gens = pauliop.(["YIXX", "IZYI"])
|
||
|
cmat_2 = QuantumLegos.checkmatrix(gens)
|
||
|
@test QuantumLegos.xpart(cmat_2) == Bool[1 0 1 1; 0 0 1 0]
|
||
|
@test QuantumLegos.zpart(cmat_2) == Bool[1 0 0 0; 0 1 1 0]
|
||
|
@test generators(cmat_2) == gens
|
||
|
end
|
||
|
|
||
|
@testset "eliminate_column!" begin
|
||
|
let
|
||
|
cmat = QuantumLegos.CheckMatrix(Bool[
|
||
|
1 0 0 1
|
||
|
1 0 1 1
|
||
|
])
|
||
|
@test QuantumLegos.eliminate_column!(cmat, 1, Int64[]) == 1
|
||
|
@test cmat.cmat == Bool[
|
||
|
1 0 0 1
|
||
|
0 0 1 0
|
||
|
]
|
||
|
end
|
||
|
let
|
||
|
cmat = QuantumLegos.CheckMatrix(Bool[
|
||
|
1 0 0 1
|
||
|
1 0 1 1
|
||
|
])
|
||
|
@test QuantumLegos.eliminate_column!(cmat, 1, Int64[1]) == 2
|
||
|
@test cmat.cmat == Bool[
|
||
|
0 0 1 0
|
||
|
1 0 1 1
|
||
|
]
|
||
|
end
|
||
|
let
|
||
|
cmat = QuantumLegos.CheckMatrix(
|
||
|
Bool[
|
||
|
1 1 0 1 0 0 1 1
|
||
|
0 0 1 1 0 1 0 1
|
||
|
0 1 1 0 1 0 1 1
|
||
|
0 1 0 1 0 1 0 1
|
||
|
],
|
||
|
)
|
||
|
@test QuantumLegos.eliminate_column!(cmat, 2, [1]) == 3
|
||
|
@test cmat.cmat == Bool[
|
||
|
1 0 1 1 1 0 0 0
|
||
|
0 0 1 1 0 1 0 1
|
||
|
0 1 1 0 1 0 1 1
|
||
|
0 0 1 1 1 1 1 0
|
||
|
]
|
||
|
end
|
||
|
let
|
||
|
cmat = QuantumLegos.CheckMatrix(
|
||
|
Bool[
|
||
|
1 1 0 1 0 0 1 1
|
||
|
0 0 1 1 0 1 0 1
|
||
|
0 1 1 0 1 0 1 1
|
||
|
0 1 0 1 0 1 0 1
|
||
|
],
|
||
|
)
|
||
|
@test QuantumLegos.eliminate_column!(cmat, 2, [1, nothing]) == 3
|
||
|
@test cmat.cmat == Bool[
|
||
|
1 0 1 1 1 0 0 0
|
||
|
0 0 1 1 0 1 0 1
|
||
|
0 1 1 0 1 0 1 1
|
||
|
0 0 1 1 1 1 1 0
|
||
|
]
|
||
|
end
|
||
|
let
|
||
|
cmat = QuantumLegos.CheckMatrix(
|
||
|
Bool[
|
||
|
1 0 0 0 1 1 0 1
|
||
|
0 1 0 1 0 1 1 0
|
||
|
0 1 0 0 0 1 0 0
|
||
|
1 1 0 1 0 0 0 1
|
||
|
],
|
||
|
)
|
||
|
@test QuantumLegos.eliminate_column!(cmat, 3, Int[]) === nothing
|
||
|
end
|
||
|
let
|
||
|
# random test (robustness)
|
||
|
function random_test()::Bool
|
||
|
test_mat = rand(Bool, (8, 16))
|
||
|
cmat = QuantumLegos.CheckMatrix(copy(test_mat))
|
||
|
keep_indices = (1:8)[rand(1:8, rand(0:8))]
|
||
|
keep_index = rand(1:16)
|
||
|
try
|
||
|
QuantumLegos.eliminate_column!(cmat, keep_index, keep_indices)
|
||
|
return true
|
||
|
catch e
|
||
|
# unexpected error
|
||
|
@error "Error on eliminate_column! with keep_index: $(keep_index), avoid: $(keep_indices), matrix:" cmat
|
||
|
@error "error: " e
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
for i in 1:100
|
||
|
# @info i
|
||
|
@test random_test()
|
||
|
end
|
||
|
end
|
||
|
@testset "ArgumentError" begin
|
||
|
cmat = CheckMatrix(rand(Bool, (6, 12)))
|
||
|
@test_throws ArgumentError QuantumLegos.eliminate_column!(cmat, 3, [1, 7])
|
||
|
end
|
||
|
end
|
||
|
@testset "swap_row!" begin
|
||
|
let
|
||
|
m = rand(Bool, (10, 10))
|
||
|
m_copy = copy(m)
|
||
|
QuantumLegos.swap_row!(m, 3, 7)
|
||
|
QuantumLegos.swap_row!(m, 3, 7)
|
||
|
@test m == m_copy
|
||
|
end
|
||
|
let
|
||
|
m = rand(Bool, (10, 10))
|
||
|
m = BitMatrix(m)
|
||
|
m_copy = copy(m)
|
||
|
QuantumLegos.swap_row!(m, 4, 2)
|
||
|
QuantumLegos.swap_row!(m, 4, 2)
|
||
|
@test m == m_copy
|
||
|
end
|
||
|
end
|
||
|
@testset "align_row!" begin
|
||
|
mat = Bool[
|
||
|
1 0 1 1 0 0 1 0
|
||
|
0 1 0 1 0 1 0 0
|
||
|
1 1 1 0 0 1 0 0
|
||
|
1 0 0 1 0 1 0 0
|
||
|
]
|
||
|
mat_1 = copy(mat)
|
||
|
@test 1 == QuantumLegos.align_row!(mat_1, 3, Int64[])
|
||
|
@test mat_1 == Bool[
|
||
|
1 1 1 0 0 1 0 0
|
||
|
0 1 0 1 0 1 0 0
|
||
|
1 0 1 1 0 0 1 0
|
||
|
1 0 0 1 0 1 0 0
|
||
|
]
|
||
|
mat_1 = copy(mat)
|
||
|
@test 1 == QuantumLegos.align_row!(mat_1, 3, [nothing])
|
||
|
@test mat_1 == Bool[
|
||
|
1 1 1 0 0 1 0 0
|
||
|
0 1 0 1 0 1 0 0
|
||
|
1 0 1 1 0 0 1 0
|
||
|
1 0 0 1 0 1 0 0
|
||
|
]
|
||
|
mat_2 = copy(mat)
|
||
|
@test 2 == QuantumLegos.align_row!(mat_2, 3, [1])
|
||
|
@test mat_2 == Bool[
|
||
|
1 0 1 1 0 0 1 0
|
||
|
1 1 1 0 0 1 0 0
|
||
|
0 1 0 1 0 1 0 0
|
||
|
1 0 0 1 0 1 0 0
|
||
|
]
|
||
|
mat_3 = copy(mat)
|
||
|
@test 3 == QuantumLegos.align_row!(mat_3, 3, [1, nothing, 3])
|
||
|
@test mat_3 == Bool[
|
||
|
1 0 1 1 0 0 1 0
|
||
|
0 1 0 1 0 1 0 0
|
||
|
1 1 1 0 0 1 0 0 # 3
|
||
|
1 0 0 1 0 1 0 0 # 4
|
||
|
]
|
||
|
mat_3_2 = copy(mat_3)
|
||
|
@test 4 == QuantumLegos.align_row!(mat_3, 4, [1, nothing, 3])
|
||
|
@test mat_3 == mat_3_2
|
||
|
@test nothing === QuantumLegos.align_row!(mat_3, nothing, [1, 2])
|
||
|
@test nothing === QuantumLegos.align_row!(mat_3, nothing, [1, 2, nothing])
|
||
|
@test nothing === QuantumLegos.align_row!(mat_3, nothing, [nothing])
|
||
|
end
|
||
|
@testset "ref!" begin
|
||
|
@testset "compare with AbstractAlgebra" begin
|
||
|
# test using existing package
|
||
|
using AbstractAlgebra
|
||
|
F₂ = GF(2) # finite field
|
||
|
|
||
|
"""
|
||
|
Compare self-implemented `ref!` with AbstractAlgebra's `rref!` or `rank`.
|
||
|
"""
|
||
|
function random_test(size::Tuple{T, T}) where {T <: Integer}
|
||
|
mat = rand(Bool, size)
|
||
|
cmat = CheckMatrix(mat)
|
||
|
S = matrix_space(F₂, size...)
|
||
|
cmat_aa = S(F₂.(mat))
|
||
|
# r_aa, A_aa = AbstractAlgebra.rref(cmat_aa)
|
||
|
# cmat_aa = A_aa.entries .|> ==(1) |> Matrix{Bool} |> CheckMatrix
|
||
|
r_aa = rank(cmat_aa)
|
||
|
r = QuantumLegos.ref!(cmat)
|
||
|
# @info "compare cmat" cmat cmat_aa
|
||
|
@test r == r_aa
|
||
|
end
|
||
|
for _ in 1:10
|
||
|
random_test((2, 4))
|
||
|
random_test((4, 8))
|
||
|
random_test((100, 200))
|
||
|
end
|
||
|
end
|
||
|
@testset "manual sample" begin
|
||
|
import LinearAlgebra
|
||
|
mat =
|
||
|
Bool[1 0 0 1 1 0 0 0; 0 1 0 0 1 1 0 1; 0 0 1 1 0 1 0 1; 0 1 0 0 1 0 0 1]
|
||
|
cmat = CheckMatrix(mat)
|
||
|
@test QuantumLegos.ref!(cmat) == LinearAlgebra.rank(mat)
|
||
|
@test cmat == CheckMatrix(
|
||
|
Bool[
|
||
|
1 0 0 1 1 0 0 0
|
||
|
0 1 0 0 1 1 0 1
|
||
|
0 0 1 1 0 1 0 1
|
||
|
0 0 0 0 0 1 0 0
|
||
|
],
|
||
|
4,
|
||
|
4,
|
||
|
)
|
||
|
let
|
||
|
mat = copy(mat)
|
||
|
dependent_row = reduce(.⊻, eachrow(mat)[[1, 2]])
|
||
|
mat[4, :] = dependent_row
|
||
|
cmat = CheckMatrix(mat)
|
||
|
@test QuantumLegos.ref!(cmat) == LinearAlgebra.rank(mat) == 3
|
||
|
end
|
||
|
let
|
||
|
mat = copy(mat)
|
||
|
dependent_row = reduce(.⊻, eachrow(mat)[[1, 2]])
|
||
|
mat = vcat(mat, dependent_row')
|
||
|
dependent_row = reduce(.⊻, eachrow(mat)[[1, 2, 3]])
|
||
|
mat = vcat(mat, dependent_row')
|
||
|
dependent_row = reduce(.⊻, eachrow(mat)[[2, 4]])
|
||
|
mat = vcat(mat, dependent_row')
|
||
|
cmat = CheckMatrix(mat)
|
||
|
@test QuantumLegos.ref!(cmat) == rank(mat) == 3
|
||
|
end
|
||
|
end
|
||
|
@testset "generated group is invariant under ref!" begin
|
||
|
for _ in 1:10
|
||
|
cmat = CheckMatrix(rand(Bool, (8, 12)))
|
||
|
before = cmat |> generators |> GeneratedPauliGroup |> Set
|
||
|
QuantumLegos.ref!(cmat)
|
||
|
@test cmat |> generators |> GeneratedPauliGroup |> Set |> ==(before)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
@testset "eliminate_dependent_row!" begin
|
||
|
@testset "trivial" begin
|
||
|
cmat = CheckMatrix(
|
||
|
Bool[
|
||
|
1 0 0 1 0 1 0 1
|
||
|
0 1 1 0 0 1 1 0
|
||
|
0 0 0 1 1 0 1 0
|
||
|
0 0 0 0 0 0 0 0
|
||
|
],
|
||
|
)
|
||
|
@test QuantumLegos.eliminate_dependent_row!(cmat) == CheckMatrix(
|
||
|
Bool[1 0 0 1 0 1 0 1; 0 1 1 0 0 1 1 0; 0 0 0 1 1 0 1 0],
|
||
|
4,
|
||
|
3,
|
||
|
)
|
||
|
end
|
||
|
@testset "less trivial" begin
|
||
|
cmat = CheckMatrix(
|
||
|
Bool[
|
||
|
1 0 0 1 0 1 0 1
|
||
|
0 1 1 0 0 1 1 0
|
||
|
0 0 0 1 1 0 1 0
|
||
|
1 1 1 1 0 0 1 1
|
||
|
],
|
||
|
)
|
||
|
@test QuantumLegos.eliminate_dependent_row!(cmat) == CheckMatrix(
|
||
|
Bool[1 0 0 1 0 1 0 1; 0 1 1 0 0 1 1 0; 0 0 0 1 1 0 1 0],
|
||
|
4,
|
||
|
3,
|
||
|
)
|
||
|
end
|
||
|
# TODO: add more?
|
||
|
end
|
||
|
@testset "self_trace!" begin
|
||
|
cmat = CheckMatrix(rand(Bool, (8, 16)))
|
||
|
@test_throws ArgumentError QuantumLegos.self_trace!(cmat, 16, 17)
|
||
|
@test_throws ArgumentError QuantumLegos.self_trace!(cmat, 18, 17)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
@testset "State" begin
|
||
|
@testset "LegoLeg" begin
|
||
|
@test LegoLeg(0, 1) < LegoLeg(1, 0)
|
||
|
@test LegoLeg(2, 1) > LegoLeg(1, 0)
|
||
|
@test LegoLeg(1, 0) < LegoLeg(1, 1)
|
||
|
@test LegoLeg(1, 1) == LegoLeg(1, 1)
|
||
|
|
||
|
@test sort(LegoLeg.([(1, 2), (2, 3), (0, 2), (0, 1)])) ==
|
||
|
LegoLeg[LegoLeg(0, 1), LegoLeg(0, 2), LegoLeg(1, 2), LegoLeg(2, 3)]
|
||
|
end
|
||
|
@testset "edge" begin
|
||
|
@test edge(1, 2, 3, 4) == (LegoLeg(1, 2), LegoLeg(3, 4))
|
||
|
@test edge((1, 2, 3, 4)) == (LegoLeg(1, 2), LegoLeg(3, 4))
|
||
|
@test edge(((1, 2), (3, 4))) == (LegoLeg(1, 2), LegoLeg(3, 4))
|
||
|
end
|
||
|
@testset "0 lego, 0 leg" begin
|
||
|
@test_throws ArgumentError QuantumLegos.State(Lego{6}[], Tuple{LegoLeg, LegoLeg}[])
|
||
|
end
|
||
|
@testset "1 lego, 0 leg" begin
|
||
|
stabgens = pauliop.(["IIXX", "XXII", "IZZI", "ZIIZ"])
|
||
|
lego = QuantumLegos.Lego(stabgens)
|
||
|
state = QuantumLegos.State([lego], Tuple{LegoLeg, LegoLeg}[])
|
||
|
cmat = QuantumLegos.checkmatrix(stabgens)
|
||
|
@test state == QuantumLegos.State([lego], Tuple{LegoLeg, LegoLeg}[])
|
||
|
@test state.legos == [lego]
|
||
|
@test state.edges == Tuple{LegoLeg, LegoLeg}[]
|
||
|
@test state.cmat == cmat
|
||
|
end
|
||
|
@testset "2+ legos, 0 leg" begin
|
||
|
stabgens = pauliop.(["IIXX", "XXII", "IZZI", "ZIIZ"])
|
||
|
lego = QuantumLegos.Lego(stabgens)
|
||
|
state_1 = QuantumLegos.State([lego], Tuple{LegoLeg, LegoLeg}[])
|
||
|
add_lego!(state_1, lego)
|
||
|
@test state_1.legos == [lego, lego]
|
||
|
@test state_1.edges == Tuple{LegoLeg, LegoLeg}[]
|
||
|
@test state_1.cmat.ngens == 8
|
||
|
@test state_1.cmat.nlegs == 8
|
||
|
state_2 = QuantumLegos.State([lego, lego], Tuple{LegoLeg, LegoLeg}[])
|
||
|
@test state_1 == state_2
|
||
|
@test all(state_2.cmat.cmat[5:8, 1:4] .== false) # block diagonal
|
||
|
end
|
||
|
@testset "2+ legos, 1+ legs" begin
|
||
|
stabgens = pauliop.(["IIXX", "XXII", "IZZI", "ZIIZ"])
|
||
|
lego = QuantumLegos.Lego(stabgens)
|
||
|
@test_throws ArgumentError State([lego, lego], edge.([(1, 1, 1, 1)]))
|
||
|
end
|
||
|
@testset "is_connected_to_firstlego" begin
|
||
|
stabilizers = pauliop.(["IIXXXX", "IIZZZZ", "ZIZIZI", "IZIZIZ", "IXIIXX", "XIXXII"])
|
||
|
lego = Lego(stabilizers)
|
||
|
let
|
||
|
state =
|
||
|
State(fill(lego, 6), edge.([(3, 2, 1, 5), (5, 2, 3, 3), (4, 1, 5, 1)]))
|
||
|
@test QuantumLegos.is_connected_to_firstlego(state) ==
|
||
|
BitVector([1, 0, 1, 1, 1, 0])
|
||
|
end
|
||
|
let
|
||
|
state = State(
|
||
|
fill(lego, 7),
|
||
|
edge.([(3, 2, 1, 5), (5, 2, 3, 3), (4, 1, 5, 1), (2, 2, 3, 1)]),
|
||
|
)
|
||
|
@test QuantumLegos.is_connected_to_firstlego(state) ==
|
||
|
BitVector([1, 1, 1, 1, 1, 0, 0])
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
@testset "Doctest" begin
|
||
|
DocMeta.setdocmeta!(
|
||
|
QuantumLegos,
|
||
|
:DocTestSetup,
|
||
|
:(using QuantumLegos; ENV["JULIA_DEBUG"] = "");
|
||
|
recursive = true,
|
||
|
)
|
||
|
doctest(QuantumLegos)
|
||
|
end
|
||
|
|
||
|
# @testset "Code quality (Aqua.jl)" begin
|
||
|
# Aqua.test_all(QuantumLegos)
|
||
|
# end
|
||
|
# @testset "Code linting (JET.jl)" begin
|
||
|
# JET.test_package(QuantumLegos; target_defined_modules = true)
|
||
|
# end
|
||
|
end
|