From 7f5bfbbe89fc1c36c35cd1929c7aea4692ea3245 Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Thu, 6 Jul 2023 23:56:55 +0700 Subject: [PATCH 01/18] is_degenerate, is_degen tests, and naive implementation of encoding circuit --- src/ecc/ECC.jl | 107 +++++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 54 ++++++++++++------------ test/test_ecc.jl | 21 ++++++++++ 3 files changed, 155 insertions(+), 27 deletions(-) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 770bdf335..8a2be264e 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -88,6 +88,113 @@ function logz_ops(c::AbstractECC) logicalzview(MixedDest) end +""" The bimatrix representation of a code""" +function tableau_representation(c::AbstractECC) + n, s = code_n(c), code_s(c) + tableau = zeros(s, 2 * n) + parity_check_tableau = parity_checks(c) + for check in 1:s + for qubit in 1: n + tableau[check, qubit], tableau[check, qubit + n] = parity_check_tableau[check, qubit] + end + end + + return tableau +end +""" Check if the code is degenerate or not """ +function is_degenerate(c::AbstractECC) + tableau = tableau_representation(c) + n = code_n(c) + dictionary = Set() + for column in 1:2*n + temp = tableau[:, column] + if temp in dictionary + return true + else + push!(dictionary, temp) + end + end + return false +end + +""" Canonicalize the logicals x operators of a code by @gottesman1997 https://arxiv.org/pdf/quant-ph/9705052.pdf """ # TODO: Implement the same code for the Z operators +function canonicalize_logicals(c::AbstractECC) + n, s, k = code_n(c), code_s(c), code_k(c) + logx = logx_ops(c) + tabx = tableau_representation(logx) + tab = tableau_representation(canonicalize_gott!(parity_checks(c))) + # Finding the rank r of the logical X + r =0 + for i in 1: n + pivot =findfirst(tab[:, i]) + if pivot !== nothing + r += 1 + end + end + # standardize u1 and v2 for each element of logX (u1u2u3|v1v2v3) + for i in 1:k + op = tabx[i, :] + # standardize the first n-k qubits (the u1 and v2 component) + for j in 1:n-k + if (j <= r && op[j] == 1) || (j >= r+1 && op[j+n] ==1) + tabx[i] += tab[j] # TODO: fix this xor plus + end + end + end + # setting u3 = I and v3 = 0 + for i in 1:k + op = tabx[i, :] + for j in n-k+1:n + if j - (n-k) == i + op[j]=1 + else + op[j]=0 + end + op[j+n] = 0 + end + end + + return tabx +end + +""" The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ +function naive_encoding_circuit(c::AbstractECC) + n, k, s = code_n(c), code_k(c), code_s(c) + naive_ec = AbstractOperation[] + # Applying the hadamard gate to the last r qubits + for i in n: -1: n-r+1 + push!(naive_ec, sHadamard(i)) + end + # The standard form is + # I A1 A2 | B C1 C2 + # 0 0 0 | D I E + + # and we augment the following third line (for logical qubits) + + # 0 E^T I | 0 0 0 + + # Then we apply the gates line by line bottom up in accordance with the formalisms here: arXiv:quant-ph/9607030 + standard_tab = canonicalize_gott!(parity_checks(c)) + push!(standard_tab, the_augmented_part) # can we use canonicalize_gott for the entire mixedDestabilizer? (i.e. the stab + log parts = n rows) + for i in n: -1: 1 + if standard_tab[i, i] ==1 + for j in n: -1: 1 + if j == i continue end + gate = (standard_tab[i,j], standard_tab[i,j+n]) + if gate == (1,0) + push!(naive_ec, sXCX(j, i)) + elseif gate == (0,1) + push!(naive_ec, sCNOT(j, i)) + elseif gate == (1,1) + push!(naive_ec, sYCX(j, i)) + end + end + end + end + return naive_ec +end + + # TODO implement isdegenerate include("./bitflipcode.jl") diff --git a/test/runtests.jl b/test/runtests.jl index e29164b17..59e27567d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -25,31 +25,31 @@ end println("Starting tests with $(Threads.nthreads()) threads out of `Sys.CPU_THREADS = $(Sys.CPU_THREADS)`...") -@doset "paulis" -@doset "stabs" -@doset "stabcanon" -@doset "mul_leftright" -@doset "inner" -@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 "graphs" -@doset "hash" -@doset "entanglement" -@doset "enumerate" +# @doset "paulis" +# @doset "stabs" +# @doset "stabcanon" +# @doset "mul_leftright" +# @doset "inner" +# @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 "graphs" +# @doset "hash" +# @doset "entanglement" +# @doset "enumerate" @doset "ecc" -@doset "precompile" -@doset "pauliframe" -@doset "allocations" -VERSION >= v"1.9" && @doset "doctests" -get(ENV,"JET_TEST","")=="true" && @doset "jet" -VERSION >= v"1.9" && @doset "aqua" +# @doset "precompile" +# @doset "pauliframe" +# @doset "allocations" +# VERSION >= v"1.9" && @doset "doctests" +# get(ENV,"JET_TEST","")=="true" && @doset "jet" +# VERSION >= v"1.9" && @doset "aqua" diff --git a/test/test_ecc.jl b/test/test_ecc.jl index eec808bca..cdc60b405 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -1,6 +1,7 @@ using Test using QuantumClifford using QuantumClifford.ECC: AbstractECC, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops +include("../src/ecc/ECC.jl") codes = [ Bitflip3(), @@ -105,3 +106,23 @@ end test_with_pframes(c) end end + + +## + + +function test_is_degenerate(c::AbstractECC) + if c == Shor9() + @test is_degenerate(c) == true + elseif c == Steane7() + @test is_degenerate(c) == false + elseif c== Bitflip3() + @test is_degenerate(c) == true + end +end + +@testset "is degenerate function - test on popular codes" begin + for c in codes + test_is_degenerate(c) + end +end \ No newline at end of file From 36d813374344bbec423f0326ca43700cd45017cf Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Fri, 7 Jul 2023 00:27:00 +0700 Subject: [PATCH 02/18] augment bimatrix in naive_encoding_circuit --- src/ecc/ECC.jl | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 8a2be264e..619dd72c9 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -101,6 +101,7 @@ function tableau_representation(c::AbstractECC) return tableau end + """ Check if the code is degenerate or not """ function is_degenerate(c::AbstractECC) tableau = tableau_representation(c) @@ -117,7 +118,7 @@ function is_degenerate(c::AbstractECC) return false end -""" Canonicalize the logicals x operators of a code by @gottesman1997 https://arxiv.org/pdf/quant-ph/9705052.pdf """ # TODO: Implement the same code for the Z operators +""" Canonicalize the logicals x operators of a code by @gottesman1997 arxiv:quant-ph/9705052 """ # TODO: Implement the same code for the Z operators function canonicalize_logicals(c::AbstractECC) n, s, k = code_n(c), code_s(c), code_k(c) logx = logx_ops(c) @@ -168,15 +169,24 @@ function naive_encoding_circuit(c::AbstractECC) # The standard form is # I A1 A2 | B C1 C2 # 0 0 0 | D I E - # and we augment the following third line (for logical qubits) - # 0 E^T I | 0 0 0 - # Then we apply the gates line by line bottom up in accordance with the formalisms here: arXiv:quant-ph/9607030 standard_tab = canonicalize_gott!(parity_checks(c)) - push!(standard_tab, the_augmented_part) # can we use canonicalize_gott for the entire mixedDestabilizer? (i.e. the stab + log parts = n rows) - for i in n: -1: 1 + for i in 1: k + # can we use canonicalize_gott for the entire mixedDestabilizer? (i.e. the stab + log parts = n rows) + augment = zeros(2*n) + for j in 1:n + if j > r && j <= n - k + augment[j] = standard_tab[r+j, 2*n-k+i] # the corresponding column of E in E^T + elseif j == n-k+i + augment[j] = 1 + end + end + push!(standard_tab, augment) + end + + for i in n: -1: 1 # implement the decoder from the augmented bimatrix bottom up and from right to left if standard_tab[i, i] ==1 for j in n: -1: 1 if j == i continue end @@ -195,8 +205,6 @@ function naive_encoding_circuit(c::AbstractECC) end -# TODO implement isdegenerate - include("./bitflipcode.jl") include("./shorcode.jl") include("./steanecode.jl") From e6dbb95da7fdfdb8ecc54f5e9243132e6c71ff67 Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Fri, 7 Jul 2023 00:35:18 +0700 Subject: [PATCH 03/18] uncomment tests --- test/runtests.jl | 54 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 59e27567d..e29164b17 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -25,31 +25,31 @@ end println("Starting tests with $(Threads.nthreads()) threads out of `Sys.CPU_THREADS = $(Sys.CPU_THREADS)`...") -# @doset "paulis" -# @doset "stabs" -# @doset "stabcanon" -# @doset "mul_leftright" -# @doset "inner" -# @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 "graphs" -# @doset "hash" -# @doset "entanglement" -# @doset "enumerate" +@doset "paulis" +@doset "stabs" +@doset "stabcanon" +@doset "mul_leftright" +@doset "inner" +@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 "graphs" +@doset "hash" +@doset "entanglement" +@doset "enumerate" @doset "ecc" -# @doset "precompile" -# @doset "pauliframe" -# @doset "allocations" -# VERSION >= v"1.9" && @doset "doctests" -# get(ENV,"JET_TEST","")=="true" && @doset "jet" -# VERSION >= v"1.9" && @doset "aqua" +@doset "precompile" +@doset "pauliframe" +@doset "allocations" +VERSION >= v"1.9" && @doset "doctests" +get(ENV,"JET_TEST","")=="true" && @doset "jet" +VERSION >= v"1.9" && @doset "aqua" From 05e3c566d5e12c72078f14d64f98d1663f98b7d0 Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Thu, 13 Jul 2023 23:17:26 +0700 Subject: [PATCH 04/18] minor --- src/ecc/ECC.jl | 99 ++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 619dd72c9..3464cbbd8 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -89,22 +89,11 @@ function logz_ops(c::AbstractECC) end """ The bimatrix representation of a code""" -function tableau_representation(c::AbstractECC) - n, s = code_n(c), code_s(c) - tableau = zeros(s, 2 * n) - parity_check_tableau = parity_checks(c) - for check in 1:s - for qubit in 1: n - tableau[check, qubit], tableau[check, qubit + n] = parity_check_tableau[check, qubit] - end - end - - return tableau -end +# stab_to_gf2(parity_checks(c)) """ Check if the code is degenerate or not """ function is_degenerate(c::AbstractECC) - tableau = tableau_representation(c) + tableau = stab_to_gf2(parity_checks(c)) n = code_n(c) dictionary = Set() for column in 1:2*n @@ -119,48 +108,54 @@ function is_degenerate(c::AbstractECC) end """ Canonicalize the logicals x operators of a code by @gottesman1997 arxiv:quant-ph/9705052 """ # TODO: Implement the same code for the Z operators -function canonicalize_logicals(c::AbstractECC) - n, s, k = code_n(c), code_s(c), code_k(c) - logx = logx_ops(c) - tabx = tableau_representation(logx) - tab = tableau_representation(canonicalize_gott!(parity_checks(c))) - # Finding the rank r of the logical X - r =0 - for i in 1: n - pivot =findfirst(tab[:, i]) - if pivot !== nothing - r += 1 - end - end - # standardize u1 and v2 for each element of logX (u1u2u3|v1v2v3) - for i in 1:k - op = tabx[i, :] - # standardize the first n-k qubits (the u1 and v2 component) - for j in 1:n-k - if (j <= r && op[j] == 1) || (j >= r+1 && op[j+n] ==1) - tabx[i] += tab[j] # TODO: fix this xor plus - end - end - end - # setting u3 = I and v3 = 0 - for i in 1:k - op = tabx[i, :] - for j in n-k+1:n - if j - (n-k) == i - op[j]=1 - else - op[j]=0 - end - op[j+n] = 0 - end - end - - return tabx -end +#MixedDestabilizer(parity_checks(c), undoperm=false) +#getx: logicalxview +#gety: logicalzview +#getstab: stabilizerview +#getdestab: destabilizerview +# function canonicalize_logicals(c::AbstractECC) +# n, s, k = code_n(c), code_s(c), code_k(c) +# logx = logx_ops(c) +# tabx = tableau_representation(logx) +# tab = tableau_representation(canonicalize_gott!(parity_checks(c))) +# # Finding the rank r of the logical X +# r =0 +# for i in 1: n +# pivot =findfirst(tab[:, i]) +# if pivot !== nothing +# r += 1 +# end +# end +# # standardize u1 and v2 for each element of logX (u1u2u3|v1v2v3) +# for i in 1:k +# op = tabx[i, :] +# # standardize the first n-k qubits (the u1 and v2 component) +# for j in 1:n-k +# if (j <= r && op[j] == 1) || (j >= r+1 && op[j+n] ==1) +# tabx[i] += tab[j] # TODO: fix this xor plus +# end +# end +# end +# # setting u3 = I and v3 = 0 +# for i in 1:k +# op = tabx[i, :] +# for j in n-k+1:n +# if j - (n-k) == i +# op[j]=1 +# else +# op[j]=0 +# end +# op[j+n] = 0 +# end +# end + +# return tabx +# end """ The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ function naive_encoding_circuit(c::AbstractECC) n, k, s = code_n(c), code_k(c), code_s(c) + r = naive_ec = AbstractOperation[] # Applying the hadamard gate to the last r qubits for i in n: -1: n-r+1 @@ -172,7 +167,7 @@ function naive_encoding_circuit(c::AbstractECC) # and we augment the following third line (for logical qubits) # 0 E^T I | 0 0 0 # Then we apply the gates line by line bottom up in accordance with the formalisms here: arXiv:quant-ph/9607030 - standard_tab = canonicalize_gott!(parity_checks(c)) + standard_tab = stab_to_gf2(canonicalize_gott!(parity_checks(c))[1]) for i in 1: k # can we use canonicalize_gott for the entire mixedDestabilizer? (i.e. the stab + log parts = n rows) augment = zeros(2*n) From cd05fffafd5ec05dbd086b7a0d9778c040f78691 Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Fri, 14 Jul 2023 22:00:45 +0700 Subject: [PATCH 05/18] encoding circuit -split --- src/ecc/ECC.jl | 117 +++++++++++++++++++------------------------ src/ecc/papercode.jl | 9 ++++ test/test_ecc.jl | 22 +++++--- 3 files changed, 76 insertions(+), 72 deletions(-) create mode 100644 src/ecc/papercode.jl diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 3464cbbd8..c85d229c3 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -88,10 +88,8 @@ function logz_ops(c::AbstractECC) logicalzview(MixedDest) end -""" The bimatrix representation of a code""" -# stab_to_gf2(parity_checks(c)) -""" Check if the code is degenerate or not """ +""" Check if the code is degenerate or not.""" function is_degenerate(c::AbstractECC) tableau = stab_to_gf2(parity_checks(c)) n = code_n(c) @@ -107,91 +105,77 @@ function is_degenerate(c::AbstractECC) return false end -""" Canonicalize the logicals x operators of a code by @gottesman1997 arxiv:quant-ph/9705052 """ # TODO: Implement the same code for the Z operators -#MixedDestabilizer(parity_checks(c), undoperm=false) -#getx: logicalxview -#gety: logicalzview -#getstab: stabilizerview -#getdestab: destabilizerview -# function canonicalize_logicals(c::AbstractECC) -# n, s, k = code_n(c), code_s(c), code_k(c) -# logx = logx_ops(c) -# tabx = tableau_representation(logx) -# tab = tableau_representation(canonicalize_gott!(parity_checks(c))) -# # Finding the rank r of the logical X -# r =0 -# for i in 1: n -# pivot =findfirst(tab[:, i]) -# if pivot !== nothing -# r += 1 -# end -# end -# # standardize u1 and v2 for each element of logX (u1u2u3|v1v2v3) -# for i in 1:k -# op = tabx[i, :] -# # standardize the first n-k qubits (the u1 and v2 component) -# for j in 1:n-k -# if (j <= r && op[j] == 1) || (j >= r+1 && op[j+n] ==1) -# tabx[i] += tab[j] # TODO: fix this xor plus -# end -# end -# end -# # setting u3 = I and v3 = 0 -# for i in 1:k -# op = tabx[i, :] -# for j in n-k+1:n -# if j - (n-k) == i -# op[j]=1 -# else -# op[j]=0 -# end -# op[j+n] = 0 -# end -# end - -# return tabx -# end - -""" The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ -function naive_encoding_circuit(c::AbstractECC) - n, k, s = code_n(c), code_k(c), code_s(c) - r = - naive_ec = AbstractOperation[] - # Applying the hadamard gate to the last r qubits - for i in n: -1: n-r+1 - push!(naive_ec, sHadamard(i)) +"""The rank of the bimatrix of a code.""" +function rank(c::AbstractECC) + destab_gott = MixedDestabilizer(parity_checks(c), undoperm=false) + bimat = stab_to_gf2(stabilizerview(destab_gott)) + rank = 0 + for i in 1:code_s(c) + if bimat[i, i] == 1 + rank +=1 + end end + return rank +end + +"""The standardized logical tableau of a code by [PhysRevA.56.76](@cite)""" +function standard_tab_gott(c::AbstractECC) + n, s, k, r = code_n(c), code_s(c), code_k(c), rank(c) # The standard form is # I A1 A2 | B C1 C2 # 0 0 0 | D I E # and we augment the following third line (for logical qubits) # 0 E^T I | 0 0 0 # Then we apply the gates line by line bottom up in accordance with the formalisms here: arXiv:quant-ph/9607030 - standard_tab = stab_to_gf2(canonicalize_gott!(parity_checks(c))[1]) + standard_tab = stab_to_gf2(stabilizerview(MixedDestabilizer(parity_checks(c), undoperm=false))) for i in 1: k # can we use canonicalize_gott for the entire mixedDestabilizer? (i.e. the stab + log parts = n rows) - augment = zeros(2*n) + augment = zeros(Int8, (1, 2*n)) for j in 1:n if j > r && j <= n - k - augment[j] = standard_tab[r+j, 2*n-k+i] # the corresponding column of E in E^T + augment[j] = standard_tab[j, 2*n-k+i] # the corresponding column of E in E^T elseif j == n-k+i augment[j] = 1 end end - push!(standard_tab, augment) + standard_tab = vcat(standard_tab, augment) + end + # Flipping the table so it has the same format as the papercode + res = zeros(Int8, (n, 2n)) + for i in 1:n + for j in 1:n + res[i, j] = standard_tab[n+1-j, n+1-i] + end + for j in n+1:2*n + res[i,j] = standard_tab[2*n+1-j, n+1-i] + end end + return res +end - for i in n: -1: 1 # implement the decoder from the augmented bimatrix bottom up and from right to left + +""" The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ +function naive_encoding_circuit(c::AbstractECC) + n, k, s, r = code_n(c), code_k(c), code_s(c), rank(c) + naive_ec = AbstractOperation[] + # Applying the hadamard gate to the last r qubits + for i in n: -1: n-r+1 + push!(naive_ec, sHadamard(i)) + end + + standard_tab = standard_tab_gott(c) + + for i in 1 : n if standard_tab[i, i] ==1 - for j in n: -1: 1 + for j in 1:n if j == i continue end - gate = (standard_tab[i,j], standard_tab[i,j+n]) + gate = (standard_tab[j, i], standard_tab[j, i+n]) if gate == (1,0) - push!(naive_ec, sXCX(j, i)) - elseif gate == (0,1) push!(naive_ec, sCNOT(j, i)) + elseif gate == (0,1) + push!(naive_ec, sXCZ(j, i)) elseif gate == (1,1) - push!(naive_ec, sYCX(j, i)) + push!(naive_ec, sXCY(j, i)) end end end @@ -203,5 +187,6 @@ end include("./bitflipcode.jl") include("./shorcode.jl") include("./steanecode.jl") +include("./papercode.jl") end #module diff --git a/src/ecc/papercode.jl b/src/ecc/papercode.jl new file mode 100644 index 000000000..08ecfdd3c --- /dev/null +++ b/src/ecc/papercode.jl @@ -0,0 +1,9 @@ +struct Paper8 <: AbstractECC end + +code_n(c::Paper8) = 8 + +parity_checks(c::Paper8) = S"XXXXXXXX + ZZZZZZZZ + XIXIZYZY + XIYZXIYZ + XZIYIYXZ" \ No newline at end of file diff --git a/test/test_ecc.jl b/test/test_ecc.jl index cdc60b405..5d15bdf8a 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -1,7 +1,6 @@ using Test using QuantumClifford -using QuantumClifford.ECC: AbstractECC, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops -include("../src/ecc/ECC.jl") +using QuantumClifford.ECC: AbstractECC, Paper8, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops, naive_encoding_circuit, is_degenerate, rank codes = [ Bitflip3(), @@ -58,12 +57,17 @@ end ## -function test_naive_syndrome(c::AbstractECC) +function test_naive_syndrome(c::AbstractECC, e::Bool=false) # create a random logical state unencoded_qubits = random_stabilizer(code_k(c)) bufferqubits = one(Stabilizer,code_s(c)) logicalqubits = unencoded_qubits⊗bufferqubits mctrajectory!(logicalqubits, encoding_circuit(c)) + if e + #add some noise to logicalqubits + apply!(logicalqubits, P"X", rand(1:code_n(c))) + apply!(logicalqubits, P"Z", rand(1:code_n(c))) + end # measure using `project!` s1 = copy(logicalqubits) syndrome1 = [project!(s1, check)[3] for check in parity_checks(c)] @@ -73,8 +77,10 @@ function test_naive_syndrome(c::AbstractECC) s2 = copy(logicalqubits) syndrome2 = Register(s2⊗ancillaryqubits, falses(code_s(c))) mctrajectory!(syndrome2, naive_circuit) - @test all(syndrome1 .== 0) - @test all(bitview(syndrome2) .== 0) + if !e + @test all(syndrome1 .== 0) + @test all(bitview(syndrome2) .== 0) + end @test bitview(syndrome2) == syndrome1.÷2 # TODO test when there is potential for errors / non-commuting operators @@ -83,6 +89,7 @@ end @testset "naive syndrome circuits - zero syndrome for logical states" begin for c in codes, _ in 1:2 test_naive_syndrome(c) + test_naive_syndrome(c, true) end end @@ -125,4 +132,7 @@ end for c in codes test_is_degenerate(c) end -end \ No newline at end of file +end + +## + From 365553a80e63aaa2d672141307742d81036bfd13 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sun, 16 Jul 2023 12:17:49 -0400 Subject: [PATCH 06/18] Slightly better docstring for is_degenerate -- please report in the docstring where this algorithm is from --- src/ecc/ECC.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index c85d229c3..51a33ee68 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -88,13 +88,12 @@ function logz_ops(c::AbstractECC) logicalzview(MixedDest) end - -""" Check if the code is degenerate or not.""" +"""Check if the code is degenerate with respect to single-qubit physical errors.""" function is_degenerate(c::AbstractECC) tableau = stab_to_gf2(parity_checks(c)) n = code_n(c) dictionary = Set() - for column in 1:2*n + for column in 1:2*n temp = tableau[:, column] if temp in dictionary return true From 14604ebdae2091ad18674defe3a3deb24bae7d80 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sun, 16 Jul 2023 12:23:43 -0400 Subject: [PATCH 07/18] a simplified version of your `standard_tab_gott` - should be doing the same, but it is reusing MixedDestabilizer for all steps --- src/ecc/ECC.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 51a33ee68..b499ae014 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -152,6 +152,22 @@ function standard_tab_gott(c::AbstractECC) return res end +function standard_code_tab(c::AbstractECC) + n, s, k = code_n(c), code_s(c), code_k(c) + standard_tab = stab_to_gf2(stabilizerview(MixedDestabilizer(parity_checks(c), undoperm=false))) + md = MixedDestabilizer(parity_checks(c), undoperm=false) + XZᵗ = stab_to_gf2(stabilizerview(md)) + X₂ = reverse(XZᵗ[1:s,1:n]', dims=(1,2)) + Z₂ = reverse(XZᵗ[1:s,n+1:2n]', dims=(1,2)) + X = falses(n, n) + Z = falses(n, n) + X[:, k+1:end] .= X₂ + Z[:, k+1:end] .= Z₂ + X[:, 1:k] .= Xˡ + return X, Z + # TODO The permutations need to be reverted at some point, otherwise the generated circuit will have permuted qubits. It is not clear to me whether it is more convenient to revert the permutation here or in naive_encoding_circuit + # TODO This function does not seem to actually be necessary. It seems like iterating over the `MixedDestabilizer` object is enough. Out of convenience, let's keep if for the moment, but also keep this TODO +end """ The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ function naive_encoding_circuit(c::AbstractECC) From 2a0c94fd4b8a95a75ab392efdc8891f8dba796d6 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sun, 16 Jul 2023 12:42:11 -0400 Subject: [PATCH 08/18] provide a `reportperm` keyword argument to the `MixedDestabilizer` constructor --- src/QuantumClifford.jl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index efbc87a14..fe28476d1 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -629,6 +629,11 @@ operators are tracked as well. When the constructor is called on an incomplete [`Stabilizer`](@ref) it automatically calculates the destabilizers and logical operators, following chapter 4 of [gottesman1997stabilizer](@cite). +Under the hood the conversion uses the [`canonicalize_gott!`](@ref) canonicalization. +That canonicalization permutes the columns of the tableau, but we automatically undo the +column permutation in the preparation of a `MixedDestabilizer` so that qubits are not reindexed. +The boolean keyword arguments `undoperm` and `reportperm` can be used to control this behavior +and to report the permutations explicitly. See also: [`stabilizerview`](@ref), [`destabilizerview`](@ref), [`logicalxview`](@ref), [`logicalzview`](@ref) """ @@ -638,7 +643,7 @@ mutable struct MixedDestabilizer{T<:Tableau} <: AbstractStabilizer end # Added a lot of type assertions to help Julia infer types -function MixedDestabilizer(stab::Stabilizer{T}; undoperm=true) where {T} +function MixedDestabilizer(stab::Stabilizer{T}; undoperm=true, reportperm=false) where {T} rows,n = size(stab) stab, r, s, permx, permz = canonicalize_gott!(copy(stab)) t = zero(T, n*2, n) @@ -675,8 +680,13 @@ function MixedDestabilizer(stab::Stabilizer{T}; undoperm=true) where {T} end if undoperm t = t[:,invperm(permx[permz])]::T + return MixedDestabilizer(t, r+s)::MixedDestabilizer{T} + end + if reportperm + return (permx, permz, MixedDestabilizer(t, r+s)::MixedDestabilizer{T}) + else + return MixedDestabilizer(t, r+s)::MixedDestabilizer{T} end - MixedDestabilizer(t, r+s)::MixedDestabilizer{T} end function MixedDestabilizer(d::Destabilizer, r::Int) From 8f6265a24f9da85489340155cc440f317ae86211 Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Sat, 22 Jul 2023 00:20:58 +0700 Subject: [PATCH 09/18] streamlined standard_tab_gott and added reference --- docs/src/references.bib | 11 ++++++ src/ecc/ECC.jl | 50 +++++++++++--------------- src/ecc/{papercode.jl => clevecode.jl} | 6 ++-- test/test_ecc.jl | 7 ++-- 4 files changed, 39 insertions(+), 35 deletions(-) rename src/ecc/{papercode.jl => clevecode.jl} (61%) diff --git a/docs/src/references.bib b/docs/src/references.bib index d522b3ffc..02e29aa2b 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -193,3 +193,14 @@ @article{nahum2017quantum author = {Nahum, Adam and Ruhman, Jonathan and Vijay, Sagar and Haah, Jeongwan}, year = {2017} } + +@article{cleve1997efficient, + title={Efficient computations of encodings for quantum error correction}, + author={Cleve, Richard and Gottesman, Daniel}, + journal={Physical Review A}, + volume={56}, + number={1}, + pages={76}, + year={1997}, + publisher={APS} +} \ No newline at end of file diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 5267eb8a9..fb148b724 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -1,5 +1,6 @@ module ECC +using LinearAlgebra using QuantumClifford using QuantumClifford: AbstractOperation import QuantumClifford: Stabilizer, MixedDestabilizer @@ -288,10 +289,11 @@ end """ Check if the code is degenerate or not.""" function is_degenerate(c::AbstractECC) + # By quantum stackexchange: https://quantumcomputing.stackexchange.com/questions/27279 tableau = stab_to_gf2(parity_checks(c)) n = code_n(c) dictionary = Set() - for column in 1:2*n + for column in 1:2*n temp = tableau[:, column] if temp in dictionary return true @@ -315,38 +317,28 @@ function rank(c::AbstractECC) return rank end -"""The standardized logical tableau of a code by [PhysRevA.56.76](@cite)""" +"""The standardized logical tableau of a code by [PhysRevA.56.76](@cleve1997efficient)""" function standard_tab_gott(c::AbstractECC) n, s, k, r = code_n(c), code_s(c), code_k(c), rank(c) - # The standard form is + + # The standard form is # I A1 A2 | B C1 C2 - # 0 0 0 | D I E + # 0 0 0 | D I E # and we augment the following third line (for logical qubits) # 0 E^T I | 0 0 0 # Then we apply the gates line by line bottom up in accordance with the formalisms here: arXiv:quant-ph/9607030 + standard_tab = stab_to_gf2(stabilizerview(MixedDestabilizer(parity_checks(c), undoperm=false))) - for i in 1: k - # can we use canonicalize_gott for the entire mixedDestabilizer? (i.e. the stab + log parts = n rows) - augment = zeros(Int8, (1, 2*n)) - for j in 1:n - if j > r && j <= n - k - augment[j] = standard_tab[j, 2*n-k+i] # the corresponding column of E in E^T - elseif j == n-k+i - augment[j] = 1 - end - end - standard_tab = vcat(standard_tab, augment) - end + + # Initialize augment to be E^T, then pad the zeros to the left, then pad the identity matrix to the mul_right + augment = transpose(standard_tab[r+1:s, 2*n-k+1:2*n]) + zero_left = zeros(Int8, (k, r)) + identity = Matrix(1I, k, k) + zero_right = zeros(Int8, (k, n)) # padding all zeros to the right + augment = hcat(zero_left, augment, identity, zero_right) + standard_tab = vcat(standard_tab, augment) # Flipping the table so it has the same format as the papercode - res = zeros(Int8, (n, 2n)) - for i in 1:n - for j in 1:n - res[i, j] = standard_tab[n+1-j, n+1-i] - end - for j in n+1:2*n - res[i,j] = standard_tab[2*n+1-j, n+1-i] - end - end + res = hcat(transpose(reverse(standard_tab[1:n, 1:n])), transpose(reverse(standard_tab[1:n, n+1:2*n]))) return res end @@ -361,7 +353,7 @@ function naive_encoding_circuit(c::AbstractECC) end standard_tab = standard_tab_gott(c) - + for i in 1 : n if standard_tab[i, i] ==1 for j in 1:n @@ -375,15 +367,15 @@ function naive_encoding_circuit(c::AbstractECC) push!(naive_ec, sXCY(j, i)) end end - end + end end return naive_ec -end +end include("./bitflipcode.jl") include("./shorcode.jl") include("./steanecode.jl") -include("./papercode.jl") +include("./clevecode.jl") end #module diff --git a/src/ecc/papercode.jl b/src/ecc/clevecode.jl similarity index 61% rename from src/ecc/papercode.jl rename to src/ecc/clevecode.jl index 08ecfdd3c..0dacfc33e 100644 --- a/src/ecc/papercode.jl +++ b/src/ecc/clevecode.jl @@ -1,8 +1,8 @@ -struct Paper8 <: AbstractECC end +struct Cleve8 <: AbstractECC end -code_n(c::Paper8) = 8 +code_n(c::Cleve8) = 8 -parity_checks(c::Paper8) = S"XXXXXXXX +parity_checks(c::Cleve8) = S"XXXXXXXX ZZZZZZZZ XIXIZYZY XIYZXIYZ diff --git a/test/test_ecc.jl b/test/test_ecc.jl index 5d15bdf8a..46b97147e 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -1,11 +1,12 @@ using Test using QuantumClifford -using QuantumClifford.ECC: AbstractECC, Paper8, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops, naive_encoding_circuit, is_degenerate, rank +using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops, naive_encoding_circuit, is_degenerate, rank, standard_tab_gott codes = [ Bitflip3(), Steane7(), Shor9(), + # Cleve8(), ] ## @@ -80,7 +81,7 @@ function test_naive_syndrome(c::AbstractECC, e::Bool=false) if !e @test all(syndrome1 .== 0) @test all(bitview(syndrome2) .== 0) - end + end @test bitview(syndrome2) == syndrome1.÷2 # TODO test when there is potential for errors / non-commuting operators @@ -134,5 +135,5 @@ end end end -## +## From 4cdd2a62c104de57c387194ca34ee778726e15a6 Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Sat, 29 Jul 2023 14:59:13 +0700 Subject: [PATCH 10/18] streamlined standard_tab_gott and allowed undoperm and applied to nec --- src/QuantumClifford.jl | 2 +- src/ecc/ECC.jl | 51 +++++++++++------------------------------- 2 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index 5b7905331..dab8d553c 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -556,7 +556,7 @@ function MixedDestabilizer(stab::Stabilizer{T}; undoperm=true, reportperm=false) return MixedDestabilizer(t, r+s)::MixedDestabilizer{T} end if reportperm - return (permx, permz, MixedDestabilizer(t, r+s)::MixedDestabilizer{T}) + return (r, permx, permz, MixedDestabilizer(t, r+s)::MixedDestabilizer{T}) else return MixedDestabilizer(t, r+s)::MixedDestabilizer{T} end diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index d6004c09c..178cd516d 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -303,42 +303,18 @@ function is_degenerate(c::AbstractECC) return false end -"""The rank of the bimatrix of a code.""" -function rank(c::AbstractECC) - destab_gott = MixedDestabilizer(parity_checks(c), undoperm=false) - bimat = stab_to_gf2(stabilizerview(destab_gott)) - rank = 0 - for i in 1:code_s(c) - if bimat[i, i] == 1 - rank +=1 - end - end - return rank -end """The standardized logical tableau of a code by [PhysRevA.56.76](@cleve1997efficient)""" -function standard_tab_gott(c::AbstractECC) - n, s, k, r = code_n(c), code_s(c), code_k(c), rank(c) - - # The standard form is - # I A1 A2 | B C1 C2 - # 0 0 0 | D I E - # and we augment the following third line (for logical qubits) - # 0 E^T I | 0 0 0 - # Then we apply the gates line by line bottom up in accordance with the formalisms here: arXiv:quant-ph/9607030 - - standard_tab = stab_to_gf2(stabilizerview(MixedDestabilizer(parity_checks(c), undoperm=false))) - - # Initialize augment to be E^T, then pad the zeros to the left, then pad the identity matrix to the mul_right - augment = transpose(standard_tab[r+1:s, 2*n-k+1:2*n]) - zero_left = zeros(Int8, (k, r)) - identity = Matrix(1I, k, k) - zero_right = zeros(Int8, (k, n)) # padding all zeros to the right - augment = hcat(zero_left, augment, identity, zero_right) - standard_tab = vcat(standard_tab, augment) - # Flipping the table so it has the same format as the papercode - res = hcat(transpose(reverse(standard_tab[1:n, 1:n])), transpose(reverse(standard_tab[1:n, n+1:2*n]))) - return res +function standard_tab_gott(c::AbstractECC; undoperm= true) + r, permx, permz, destab = MixedDestabilizer(parity_checks(c); undoperm=undoperm, reportperm=true) # originally undoperm here = false and the comment below is uncommented + n, k = code_n(c),code_k(c) + standard_tab = vcat(stabilizerview(destab), logicalxview(destab)) + # if undoperm + # standard_tab = standard_tab[:,invperm(permx[permz])] + # end + standard_tab = stab_to_gf2(standard_tab) + standard_tab = hcat(transpose(reverse(standard_tab[1:n, 1:n])), transpose(reverse(standard_tab[1:n, n+1:2*n]))) + return r, standard_tab end function standard_code_tab(c::AbstractECC) @@ -360,15 +336,14 @@ end """ The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ function naive_encoding_circuit(c::AbstractECC) - n, k, s, r = code_n(c), code_k(c), code_s(c), rank(c) + n= code_n(c) + r, standard_tab = standard_tab_gott(c) + naive_ec = AbstractOperation[] # Applying the hadamard gate to the last r qubits for i in n: -1: n-r+1 push!(naive_ec, sHadamard(i)) end - - standard_tab = standard_tab_gott(c) - for i in 1 : n if standard_tab[i, i] ==1 for j in 1:n From 18d505e35db6ed2db8b3ff3df36a2f8d332ed8e1 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Fri, 4 Aug 2023 00:06:45 -0400 Subject: [PATCH 11/18] clean up and add tests --- src/ecc/ECC.jl | 95 ++++++++++++++++++++++++------------------ src/ecc/bitflipcode.jl | 6 --- src/ecc/clevecode.jl | 9 ++-- src/ecc/shorcode.jl | 21 ---------- src/ecc/steanecode.jl | 21 ---------- test/test_ecc.jl | 88 +++++++++++++++++++++++++++++--------- 6 files changed, 128 insertions(+), 112 deletions(-) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 5f2bec59e..a172d1d35 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -2,11 +2,18 @@ module ECC using LinearAlgebra using QuantumClifford -using QuantumClifford: AbstractOperation +using QuantumClifford: AbstractOperation, AbstractStabilizer import QuantumClifford: Stabilizer, MixedDestabilizer +using DocStringExtensions +using Combinatorics: combinations abstract type AbstractECC end +export Shor9, Steane7, Steane5, Cleve8, + parity_checks, naive_syndrome_circuit, encoding_circuit, + code_n, code_s, code_k, rate, distance, + isdegenerate, faults_matrix + """The encoding circuit of a given code.""" function encoding_circuit end @@ -290,26 +297,49 @@ function faults_matrix(c::AbstractECC) return faults_matrix(parity_checks(c)) end -"""Check if the code is degenerate with respect to single-qubit physical errors.""" -function is_degenerate(c::AbstractECC) - # By quantum stackexchange: https://quantumcomputing.stackexchange.com/questions/27279 - tableau = stab_to_gf2(parity_checks(c)) - n = code_n(c) - dictionary = Set() - for column in 1:2*n - temp = tableau[:, column] - if temp in dictionary - return true - else - push!(dictionary, temp) - end - end - return false +""" +$TYPEDSIGNATURES + +Check if the code is degenerate with respect to a given set of error or with respect to all +"up to d physical-qubit" errors (defaulting to d=1). + +```jldoctest +julia> using QuantumClifford.ECC + +julia> isdegenerate(Shor9(), [single_z(9,1), single_z(9,2)]) +true + +julia> isdegenerate(Shor9(), [single_z(9,1), single_x(9,1)]) +false + +julia> isdegenerate(Steane7(), 1) +false + +julia> isdegenerate(Steane7(), 2) +true +``` +""" +function isdegenerate end + +isdegenerate(c::AbstractECC, args...) = isdegenerate(parity_checks(c), args...) +isdegenerate(c::AbstractStabilizer, args...) = isdegenerate(stabilizerview(c), args...) + +function isdegenerate(H::Stabilizer, errors) # Described in https://quantumcomputing.stackexchange.com/questions/27279 + syndromes = comm.((H,), errors) # TODO This can be optimized by having something that always returns bitvectors + return length(Set(syndromes)) != length(errors) +end + +function isdegenerate(H::Stabilizer, d::Int=1) + n = nqubits(H) + errors = [begin p=zero(PauliOperator,n); for i in bits; p[i]=op; end; p end for bits in combinations(1:n, d) for op in ((true,false), (false,true))] + return isdegenerate(H, errors) end """The standardized logical tableau of a code by [PhysRevA.56.76](@cleve1997efficient)""" -function standard_tab_gott(c::AbstractECC; undoperm= true) - r, permx, permz, destab = MixedDestabilizer(parity_checks(c); undoperm=undoperm, reportperm=true) # originally undoperm here = false and the comment below is uncommented +function standard_tab_gott(c::AbstractECC) + r, permx, permz, destab = MixedDestabilizer(parity_checks(c); undoperm=false, reportperm=true) # originally undoperm here = false and the comment below is uncommented + @show permx + @show permz n, k = code_n(c),code_k(c) standard_tab = vcat(stabilizerview(destab), logicalxview(destab)) # if undoperm @@ -317,37 +347,20 @@ function standard_tab_gott(c::AbstractECC; undoperm= true) # end standard_tab = stab_to_gf2(standard_tab) standard_tab = hcat(transpose(reverse(standard_tab[1:n, 1:n])), transpose(reverse(standard_tab[1:n, n+1:2*n]))) - return r, standard_tab -end - -function standard_code_tab(c::AbstractECC) - n, s, k = code_n(c), code_s(c), code_k(c) - standard_tab = stab_to_gf2(stabilizerview(MixedDestabilizer(parity_checks(c), undoperm=false))) - md = MixedDestabilizer(parity_checks(c), undoperm=false) - XZᵗ = stab_to_gf2(stabilizerview(md)) - X₂ = reverse(XZᵗ[1:s,1:n]', dims=(1,2)) - Z₂ = reverse(XZᵗ[1:s,n+1:2n]', dims=(1,2)) - X = falses(n, n) - Z = falses(n, n) - X[:, k+1:end] .= X₂ - Z[:, k+1:end] .= Z₂ - X[:, 1:k] .= Xˡ - return X, Z - # TODO The permutations need to be reverted at some point, otherwise the generated circuit will have permuted qubits. It is not clear to me whether it is more convenient to revert the permutation here or in naive_encoding_circuit - # TODO This function does not seem to actually be necessary. It seems like iterating over the `MixedDestabilizer` object is enough. Out of convenience, let's keep if for the moment, but also keep this TODO + return r, standard_tab, permx[permz] end """ The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ -function naive_encoding_circuit(c::AbstractECC) - n= code_n(c) - r, standard_tab = standard_tab_gott(c) +function encoding_circuit(c::AbstractECC) + n = code_n(c) + r, standard_tab, perm = standard_tab_gott(c) naive_ec = AbstractOperation[] # Applying the hadamard gate to the last r qubits - for i in n: -1: n-r+1 + for i in n:-1:n-r+1 push!(naive_ec, sHadamard(i)) end - for i in 1 : n + for i in 1:n if standard_tab[i, i] ==1 for j in 1:n if j == i continue end diff --git a/src/ecc/bitflipcode.jl b/src/ecc/bitflipcode.jl index ec48ffffc..bdf132aa1 100644 --- a/src/ecc/bitflipcode.jl +++ b/src/ecc/bitflipcode.jl @@ -4,9 +4,3 @@ code_n(c::Bitflip3) = 3 parity_checks(c::Bitflip3) = S"_ZZ Z_Z" - -function encoding_circuit(c::Bitflip3) - c1 = sCNOT(1,2) - c2 = sCNOT(1,3) - return [c1,c2] -end diff --git a/src/ecc/clevecode.jl b/src/ecc/clevecode.jl index 0dacfc33e..6e784ff92 100644 --- a/src/ecc/clevecode.jl +++ b/src/ecc/clevecode.jl @@ -1,9 +1,10 @@ +"""A pedagogical example of a quantum error correcting [8,3] code used in [cleve1997efficient](@cite).""" struct Cleve8 <: AbstractECC end code_n(c::Cleve8) = 8 parity_checks(c::Cleve8) = S"XXXXXXXX - ZZZZZZZZ - XIXIZYZY - XIYZXIYZ - XZIYIYXZ" \ No newline at end of file + ZZZZZZZZ + XIXIZYZY + XIYZXIYZ + XZIYIYXZ" diff --git a/src/ecc/shorcode.jl b/src/ecc/shorcode.jl index 0c9d9f508..4b540d676 100644 --- a/src/ecc/shorcode.jl +++ b/src/ecc/shorcode.jl @@ -11,25 +11,4 @@ parity_checks(c::Shor9) = S"ZZ_______ XXXXXX___ ___XXXXXX" -function encoding_circuit(c::Shor9) - c1 = sCNOT(1,4) - c2 = sCNOT(1,7) - - h1 = sHadamard(1) - h2 = sHadamard(4) - h3 = sHadamard(7) - - c3 = sCNOT(1,2) - c4 = sCNOT(4,5) - c5 = sCNOT(7,8) - - c6 = sCNOT(1,3) - c7 = sCNOT(4,6) - c8 = sCNOT(7,9) - - # XXX: The extra sHadamard(1) at the start is due to a popular mismatch in - # conventions for which logical operator is the X one and which is the Z one - return [sHadamard(1),c1,c2,h1,h2,h3,c3,c4,c5,c6,c7,c8] -end - distance(c::Shor9) = 3 diff --git a/src/ecc/steanecode.jl b/src/ecc/steanecode.jl index 013b36aa2..0f4b09199 100644 --- a/src/ecc/steanecode.jl +++ b/src/ecc/steanecode.jl @@ -11,25 +11,4 @@ parity_checks(c::Steane7) = S"___XXXX code_n(c::Steane7) = 7 -function encoding_circuit(c::Steane7) - sc1 = sCNOT(1,2) - sc2 = sCNOT(1,3) - - sh1 = sHadamard(5) - sh2 = sHadamard(6) - sh3 = sHadamard(7) - - sc3 = sCNOT(7,4) - sc4 = sCNOT(7,2) - sc5 = sCNOT(7,1) - sc6 = sCNOT(6,4) - sc7 = sCNOT(6,3) - sc8 = sCNOT(6,1) - sc9 = sCNOT(5,4) - sc10 = sCNOT(5,3) - sc11 = sCNOT(5,2) - - return [sc1,sc2,sh1,sh2,sh3,sc3,sc4,sc5,sc6,sc7,sc8,sc9,sc10,sc11] -end - distance(c::Steane7) = 3 diff --git a/test/test_ecc.jl b/test/test_ecc.jl index 46b97147e..8b3826a07 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -1,6 +1,6 @@ using Test using QuantumClifford -using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops, naive_encoding_circuit, is_degenerate, rank, standard_tab_gott +using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops, isdegenerate, rank, standard_tab_gott codes = [ Bitflip3(), @@ -11,6 +11,70 @@ codes = [ ## +# These are the old, manually written encoding circuits. They are used to test whether the new algorithmically constructed encoding circuit function works. + +function manual_encoding_circuit(c::Bitflip3) + c1 = sCNOT(1,2) + c2 = sCNOT(1,3) + return [c1,c2] +end + +function manual_encoding_circuit(c::Shor9) + c1 = sCNOT(1,4) + c2 = sCNOT(1,7) + + h1 = sHadamard(1) + h2 = sHadamard(4) + h3 = sHadamard(7) + + c3 = sCNOT(1,2) + c4 = sCNOT(4,5) + c5 = sCNOT(7,8) + + c6 = sCNOT(1,3) + c7 = sCNOT(4,6) + c8 = sCNOT(7,9) + + # XXX: The extra sHadamard(1) at the start is due to a popular mismatch in + # conventions for which logical operator is the X one and which is the Z one + return [sHadamard(1),c1,c2,h1,h2,h3,c3,c4,c5,c6,c7,c8] +end + +function manual_encoding_circuit(c::Steane7) + sc1 = sCNOT(1,2) + sc2 = sCNOT(1,3) + + sh1 = sHadamard(5) + sh2 = sHadamard(6) + sh3 = sHadamard(7) + + sc3 = sCNOT(7,4) + sc4 = sCNOT(7,2) + sc5 = sCNOT(7,1) + sc6 = sCNOT(6,4) + sc7 = sCNOT(6,3) + sc8 = sCNOT(6,1) + sc9 = sCNOT(5,4) + sc10 = sCNOT(5,3) + sc11 = sCNOT(5,2) + + return [sc1,sc2,sh1,sh2,sh3,sc3,sc4,sc5,sc6,sc7,sc8,sc9,sc10,sc11] +end + +@testset "encoding circuits - manual vs algorithmic" begin + for c in codes + manual = manual_encoding_circuit(c) + algorithmic, perm = encoding_circuit(c) + # init = random_stabilizer(code_k(c))⊗one(Stabilizer,code_s(c)) + init = one(Stabilizer, code_k(c))⊗one(Stabilizer,code_s(c)) + fin_m = mctrajectory!(copy(init), manual)[1] |> canonicalize! + fin_a = mctrajectory!(copy(init), algorithmic)[1] |> canonicalize! + @test fin_m == fin_a + end +end + +## + function test_phys_log_op_encoding(c::AbstractECC) # encode k physical qubits into n physical qubits (turning them into k logical qubits) # apply operations in an encoded or unencoded fashion @@ -115,25 +179,11 @@ end end end - ## - -function test_is_degenerate(c::AbstractECC) - if c == Shor9() - @test is_degenerate(c) == true - elseif c == Steane7() - @test is_degenerate(c) == false - elseif c== Bitflip3() - @test is_degenerate(c) == true - end -end - @testset "is degenerate function - test on popular codes" begin - for c in codes - test_is_degenerate(c) - end + @test isdegenerate(Shor9()) == true + @test isdegenerate(Steane7()) == false + @test isdegenerate(Steane7(), 2) == true + @test isdegenerate(Bitflip3()) == true end - -## - From abba3b201d24babe2de9881b87f2bf25a128b442 Mon Sep 17 00:00:00 2001 From: dmtrung14 Date: Fri, 4 Aug 2023 11:13:38 +0700 Subject: [PATCH 12/18] temporarry changes --- src/ecc/ECC.jl | 18 +++++++++--------- test/test_ecc.jl | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 178cd516d..f6f2c53d8 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -305,16 +305,13 @@ end """The standardized logical tableau of a code by [PhysRevA.56.76](@cleve1997efficient)""" -function standard_tab_gott(c::AbstractECC; undoperm= true) - r, permx, permz, destab = MixedDestabilizer(parity_checks(c); undoperm=undoperm, reportperm=true) # originally undoperm here = false and the comment below is uncommented - n, k = code_n(c),code_k(c) +function standard_tab_gott(c::AbstractECC) + r, permx, permz, destab = MixedDestabilizer(parity_checks(c); undoperm=false, reportperm=true) # originally undoperm here = false and the comment below is uncommented + n = code_n(c) standard_tab = vcat(stabilizerview(destab), logicalxview(destab)) - # if undoperm - # standard_tab = standard_tab[:,invperm(permx[permz])] - # end standard_tab = stab_to_gf2(standard_tab) standard_tab = hcat(transpose(reverse(standard_tab[1:n, 1:n])), transpose(reverse(standard_tab[1:n, n+1:2*n]))) - return r, standard_tab + return r, permx, permz, standard_tab end function standard_code_tab(c::AbstractECC) @@ -335,9 +332,9 @@ function standard_code_tab(c::AbstractECC) end """ The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ -function naive_encoding_circuit(c::AbstractECC) +function naive_encoding_circuit(c::AbstractECC, undoperm = true) n= code_n(c) - r, standard_tab = standard_tab_gott(c) + r, permx, permz, standard_tab = standard_tab_gott(c) naive_ec = AbstractOperation[] # Applying the hadamard gate to the last r qubits @@ -359,6 +356,9 @@ function naive_encoding_circuit(c::AbstractECC) end end end + # if undoperm + # standard_tab = standard_tab[:,invperm(permx[permz])] + # end return naive_ec end diff --git a/test/test_ecc.jl b/test/test_ecc.jl index 46b97147e..691733f32 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -63,7 +63,7 @@ function test_naive_syndrome(c::AbstractECC, e::Bool=false) unencoded_qubits = random_stabilizer(code_k(c)) bufferqubits = one(Stabilizer,code_s(c)) logicalqubits = unencoded_qubits⊗bufferqubits - mctrajectory!(logicalqubits, encoding_circuit(c)) + mctrajectory!(logicalqubits, naive_encoding_circuit(c)) if e #add some noise to logicalqubits apply!(logicalqubits, P"X", rand(1:code_n(c))) From 9939e6a150fc7e61b4c6ebc1f3225b6818e66ef4 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sat, 16 Sep 2023 22:43:14 -0400 Subject: [PATCH 13/18] finally implement it, and a bunch of cleanup --- CHANGELOG.md | 2 + src/QuantumClifford.jl | 1 + src/affectedqubits.jl | 4 +- src/canonicalization.jl | 1 + src/ecc/ECC.jl | 142 +++++------------------------ src/ecc/circuits.jl | 107 ++++++++++++++++++++++ src/ecc/{ => codes}/bitflipcode.jl | 0 src/ecc/{ => codes}/clevecode.jl | 0 src/ecc/codes/fivequbit.jl | 8 ++ src/ecc/{ => codes}/shorcode.jl | 0 src/ecc/{ => codes}/steanecode.jl | 0 src/symbolic_cliffords.jl | 21 ++++- test/test_ecc.jl | 113 +---------------------- test/test_ecc_encoding.jl | 52 +++++++++++ 14 files changed, 212 insertions(+), 239 deletions(-) create mode 100644 src/ecc/circuits.jl rename src/ecc/{ => codes}/bitflipcode.jl (100%) rename src/ecc/{ => codes}/clevecode.jl (100%) create mode 100644 src/ecc/codes/fivequbit.jl rename src/ecc/{ => codes}/shorcode.jl (100%) rename src/ecc/{ => codes}/steanecode.jl (100%) create mode 100644 test/test_ecc_encoding.jl diff --git a/CHANGELOG.md b/CHANGELOG.md index f0066e174..1b5f53aa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ## v0.8.15 - dev - Initial support for GPU accelerated circuit simulation (with CUDA). +- **(fix)** Some `affectedqubits` methods were returning single integers instead of a one-tuple. +- The non-public `ECC` module has seen a few improvements (a `naive_encoding_circuit` implementation and a few new codes), as well as some breaking changes to API. ## v0.8.14 - 2023-07-19 diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index 9cd693c21..7822f8256 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -50,6 +50,7 @@ export sHadamard, sPhase, sInvPhase, SingleQubitOperator, sId1, sX, sY, sZ, sCNOT, sCPHASE, sSWAP, sXCX, sXCY, sXCZ, sYCX, sYCY, sYCZ, sZCX, sZCY, sZCZ, + sZCrY, # Misc Ops SparseGate, sMX, sMY, sMZ, PauliMeasurement, Reset, sMRX, sMRY, sMRZ, diff --git a/src/affectedqubits.jl b/src/affectedqubits.jl index c5ff21299..09c9217e6 100644 --- a/src/affectedqubits.jl +++ b/src/affectedqubits.jl @@ -1,8 +1,8 @@ """A method giving the qubits acted upon by a given operation. Part of the Noise interface.""" function affectedqubits end -affectedqubits(g::AbstractSingleQubitOperator) = (g.q) +affectedqubits(g::AbstractSingleQubitOperator) = (g.q,) affectedqubits(g::AbstractTwoQubitOperator) = (g.q1, g.q2) -affectedqubits(g::NoisyGate) = affectedqubits(g.gate) +affectedqubits(g::NoisyGate) = affectedqubits(g.gate,) affectedqubits(g::SparseGate) = g.indices affectedqubits(b::BellMeasurement) = map(m->m.qubit, b.measurements) affectedqubits(r::Reset) = r.indices diff --git a/src/canonicalization.jl b/src/canonicalization.jl index 49b8cc729..907121744 100644 --- a/src/canonicalization.jl +++ b/src/canonicalization.jl @@ -258,5 +258,6 @@ function _canonicalize_gott!(stabilizer::Stabilizer; phases::Val{B}=Val(true)) w end zperm, s = gott_standard_form_indices((@view xzs[end÷2+1:end,:]),rows,columns,skip=r) permute!(stabilizer,zperm) + # we have r+s==rows (or we have trailing rows that are zeroed) stabilizer, r, s, xperm, zperm end diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 14e14a456..4c0d9f349 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -20,77 +20,32 @@ function encoding_circuit end """Parity check tableau of a code.""" function parity_checks end +parity_checks(s::Stabilizer) = s Stabilizer(c::AbstractECC) = parity_checks(c) -MixedDestabilizer(c::AbstractECC) = MixedDestabilizer(Stabilizer(c)) +MixedDestabilizer(c::AbstractECC; kwarg...) = MixedDestabilizer(Stabilizer(c); kwarg...) """The number of physical qubits in a code.""" function code_n end +code_n(c::AbstractECC) = code_n(parity_checks(c)) + +code_n(s::Stabilizer) = nqubits(s) + """The number of stabilizer checks in a code.""" -function code_s(c::AbstractECC) - s = length(parity_checks(c)) - return s -end +function code_s end + +code_s(c::AbstractECC) = code_s(parity_checks(c)) +code_s(s::Stabilizer) = length(s) """The number of logical qubits in a code.""" -function code_k(c::AbstractECC) - k = code_n(c) - code_s(c) - return k -end +code_k(c) = code_n(c) - code_s(c) """The rate of a code.""" -function rate(c::AbstractECC) - rate = code_k(c)//code_s(c) +function rate(c) + rate = code_k(c)//code_n(c) return rate end -"""Number of physical qubits for a given parity check tableau""" -function code_n(parity_check_tableau) - return size(parity_check_tableau)[2] -end - -"""Generate the non-fault-tolerant stabilizer measurement cicuit for a given code instance or parity check tableau. - -Use the `ancillary_index` and `bit_index` arguments to offset where the corresponding part the circuit starts. -""" -function naive_syndrome_circuit end - -function naive_syndrome_circuit(code_type::AbstractECC, ancillary_index=1, bit_index=1) - naive_syndrome_circuit(parity_checks(code_type), ancillary_index, bit_index) -end - -"""Circuit that measures the corresponding PauliOperator by using conditional gates into an ancillary -qubit at index `nqubits(p)+ancillary_index` and stores the measurement result into classical bit `bit_index`.""" -function naive_ancillary_paulimeasurement(p::PauliOperator, ancillary_index=1, bit_index=1) - circuit = AbstractOperation[] - numQubits = nqubits(p) - for qubit in 1:numQubits - if p[qubit] == (1,0) - push!(circuit, sXCX(qubit, numQubits + ancillary_index)) - elseif p[qubit] == (0,1) - push!(circuit, sCNOT(qubit, numQubits + ancillary_index)) - elseif p[qubit] == (1,1) - push!(circuit, sYCX(qubit, numQubits + ancillary_index)) - end - end - mz = sMRZ(numQubits + ancillary_index, bit_index) - push!(circuit, mz) - - return circuit -end - -function naive_syndrome_circuit(parity_check_tableau, ancillary_index=1, bit_index=1) - naive_sc = AbstractOperation[] - - for check in parity_check_tableau - naive_sc = append!(naive_sc,naive_ancillary_paulimeasurement(check, ancillary_index, bit_index)) - ancillary_index +=1 - bit_index +=1 - end - - return naive_sc -end - """The distance of a code.""" function distance end @@ -101,13 +56,13 @@ function parity_matrix(c::AbstractECC) end """Logical X operations of a code.""" -function logx_ops(c::AbstractECC) +function logx_ops(c) md = MixedDestabilizer(parity_checks(c)) logicalxview(md) end """Logical Z operations of a code.""" -function logz_ops(c::AbstractECC) +function logz_ops(c) md = MixedDestabilizer(parity_checks(c)) logicalzview(md) end @@ -335,67 +290,12 @@ function isdegenerate(H::Stabilizer, d::Int=1) return isdegenerate(H, errors) end -"""The standardized logical tableau of a code by [PhysRevA.56.76](@cleve1997efficient)""" -function standard_tab_gott(c::AbstractECC; undoperm= true) - r, permx, permz, destab = MixedDestabilizer(parity_checks(c); undoperm=undoperm, reportperm=true) # originally undoperm here = false and the comment below is uncommented - n, k = code_n(c),code_k(c) - standard_tab = vcat(stabilizerview(destab), logicalxview(destab)) - standard_tab = stab_to_gf2(standard_tab) - standard_tab = hcat(transpose(reverse(standard_tab[1:n, 1:n])), transpose(reverse(standard_tab[1:n, n+1:2*n]))) - return r, standard_tab -end - -function standard_code_tab(c::AbstractECC) - n, s, k = code_n(c), code_s(c), code_k(c) - standard_tab = stab_to_gf2(stabilizerview(MixedDestabilizer(parity_checks(c), undoperm=false))) - md = MixedDestabilizer(parity_checks(c), undoperm=false) - XZᵗ = stab_to_gf2(stabilizerview(md)) - X₂ = reverse(XZᵗ[1:s,1:n]', dims=(1,2)) - Z₂ = reverse(XZᵗ[1:s,n+1:2n]', dims=(1,2)) - X = falses(n, n) - Z = falses(n, n) - X[:, k+1:end] .= X₂ - Z[:, k+1:end] .= Z₂ - X[:, 1:k] .= Xˡ - return X, Z - # TODO The permutations need to be reverted at some point, otherwise the generated circuit will have permuted qubits. It is not clear to me whether it is more convenient to revert the permutation here or in naive_encoding_circuit - # TODO This function does not seem to actually be necessary. It seems like iterating over the `MixedDestabilizer` object is enough. Out of convenience, let's keep if for the moment, but also keep this TODO -end - -""" The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ -function naive_encoding_circuit(c::AbstractECC) - n= code_n(c) - r, standard_tab = standard_tab_gott(c) - - naive_ec = AbstractOperation[] - # Applying the hadamard gate to the last r qubits - for i in n:-1:n-r+1 - push!(naive_ec, sHadamard(i)) - end - for i in 1:n - if standard_tab[i, i] ==1 - for j in 1:n - if j == i continue end - gate = (standard_tab[j, i], standard_tab[j, i+n]) - if gate == (1,0) - push!(naive_ec, sCNOT(j, i)) - elseif gate == (0,1) - push!(naive_ec, sXCZ(j, i)) - elseif gate == (1,1) - push!(naive_ec, sXCY(j, i)) - end - end - end - end - # if undoperm - # standard_tab = standard_tab[:,invperm(permx[permz])] - # end - return naive_ec -end +include("circuits.jl") -include("./bitflipcode.jl") -include("./shorcode.jl") -include("./steanecode.jl") -include("./clevecode.jl") +include("codes/bitflipcode.jl") +include("codes/fivequbit.jl") +include("codes/steanecode.jl") +include("codes/shorcode.jl") +include("codes/clevecode.jl") end #module diff --git a/src/ecc/circuits.jl b/src/ecc/circuits.jl new file mode 100644 index 000000000..ef306ee6c --- /dev/null +++ b/src/ecc/circuits.jl @@ -0,0 +1,107 @@ +"""Encoding physical qubits into a larger logical code. + +Based on [gottesman1997stabilizer](@cite) and [cleve1997efficient](@cite). + +The initial physical qubits to be encoded have to be at indices `n-k+1:n`. + +!!! info "Encoding circuits are not fault-tolerant" + Encoding circuits are not fault-tolerant, and thus should not be used in practice. + Instead, you should measure the stabilizers of the code and the logical observables, + thus projecting into the code space (which can be fault-tolerant). + +!!! warning "Implicit permutation of qubits" + The canonicalization operation performed on the code may permute the qubits. + You might need to correct other parts of your code to account for this or + set `undoperm=true` to add the necessary SWAP gates to undo the permutation. +""" +function naive_encoding_circuit(code; undoperm=false, reportperm=false) + n = code_n(code) + k = code_k(code) + r, permx, permz, md = MixedDestabilizer(code, undoperm=false, reportperm=true); + circ = QuantumClifford.AbstractOperation[] + X = logicalxview(md) + Z = logicalzview(md) + S = stabilizerview(md) + for i in 1:k + for t in 1:n-k + if X[i,t][1] == true + push!(circ, sCNOT(n-k+i, t)) + end + end + end + for i in 1:r + push!(circ, sHadamard(i)) + if S[i,i][2] == true + push!(circ, sPhase(i)) + end + for t in 1:n + if i!=t + xz = S[i,t] + g = if xz == (true, true) # Y + sZCY + elseif xz == (true, false) # X + sZCX + elseif xz == (false, true) && !(i canonicalize! - fin_a = mctrajectory!(copy(init), algorithmic)[1] |> canonicalize! - @test fin_m == fin_a - end -end - -## - -function test_phys_log_op_encoding(c::AbstractECC) - # encode k physical qubits into n physical qubits (turning them into k logical qubits) - # apply operations in an encoded or unencoded fashion - # compare results - physicalqubit = random_stabilizer(code_k(c)) - - gate = rand((:x,:z)) - target = rand(1:code_k(c)) - - physicalgate, logicalgate = - if gate==:x - P"X",logx_ops(c)[target] - elseif gate == :z - P"Z",logz_ops(c)[target] - end - - #run 1 - #start physical state - physicalqubit1 = copy(physicalqubit) - #apply physical gate - apply!(physicalqubit1,physicalgate) - #encode into logical state - bufferqubits1 = one(Stabilizer,code_s(c)) - logicalqubit1 = physicalqubit1⊗bufferqubits1 # pad up the k physical qubits into a state of n physical qubits - mctrajectory!(logicalqubit1, encoding_circuit(c)) - - #run 2 - #start same physical state - physicalqubit2 = copy(physicalqubit) - #encode logical state - bufferqubits2 = one(Stabilizer,code_s(c)) - logicalqubit2 = physicalqubit2⊗bufferqubits2 - mctrajectory!(logicalqubit2, encoding_circuit(c)) - #apply logical gate - apply!(logicalqubit2,logicalgate) - - @test canonicalize!(logicalqubit1) == canonicalize!(logicalqubit2) -end - -@testset "physical vs optical operators - check of encoding circuit" begin - for c in codes, _ in 1:2 - test_phys_log_op_encoding(c) - end -end - -## - function test_naive_syndrome(c::AbstractECC, e::Bool=false) # create a random logical state unencoded_qubits = random_stabilizer(code_k(c)) diff --git a/test/test_ecc_encoding.jl b/test/test_ecc_encoding.jl new file mode 100644 index 000000000..756a172e5 --- /dev/null +++ b/test/test_ecc_encoding.jl @@ -0,0 +1,52 @@ +using Test +using QuantumClifford +using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, Perfect5, + naive_syndrome_circuit, naive_encoding_circuit, code_n, parity_checks, code_s, code_k + +## + +@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. + for codeexpr in [ + :(Cleve8()), + :(Steane7()), + :(Shor9()), + :(Perfect5()), + :(Bitflip3()), + :(S"Y_"), + :(S"Z_"), + :(S"X_"), + fill(:(random_stabilizer(5,7)), 100)... + ] + + # pre-process the tableau to remove permutations and negative phases + code = eval(codeexpr) + stab, r, s, xperm, zperm = canonicalize_gott!(parity_checks(code)) + code = stab # using this tableau guarantees we do not need to worry about permutations of the qubits + + circ = naive_encoding_circuit(code) + #display(circ) + + # the state to be encoded (k physical qubits) + pre_encₖ = one(Stabilizer, code_k(code)) + + # n-k ancillary qubits in state zero prepended + pre_encₙ = one(Stabilizer, code_s(code)) ⊗ pre_encₖ + + # running the encoding circuit + encodedₙ = mctrajectory!(pre_encₙ, circ)[1] |> canonicalize! + + # creating a valid state purely algebraically + algebraicₙ = MixedDestabilizer(code) + algebraicₙ.rank = nqubits(algebraicₙ) + algebraicₙ = stabilizerview(algebraicₙ) |> canonicalize! + + @test (encodedₙ == algebraicₙ) + + @show affectedqubits.(circ) + @show circ + #println("$codeexpr, $(encodedₙ == algebraicₙ)") + end +end From 5b9b0ef73357e903b33953f3d362e9217f26fed6 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sat, 16 Sep 2023 22:47:56 -0400 Subject: [PATCH 14/18] ammend --- src/ecc/circuits.jl | 115 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 6 deletions(-) diff --git a/src/ecc/circuits.jl b/src/ecc/circuits.jl index ef306ee6c..a716dd844 100644 --- a/src/ecc/circuits.jl +++ b/src/ecc/circuits.jl @@ -67,6 +67,10 @@ end """Generate the non-fault-tolerant stabilizer measurement cicuit for a given code instance or parity check tableau. Use the `ancillary_index` and `bit_index` arguments to offset where the corresponding part the circuit starts. + +Returns the circuit, the number of ancillary qubits that were added, and a list of bit indices that will store the measurement results. + +See also: [`shor_syndrome_circuit`](@ref) """ function naive_syndrome_circuit end @@ -74,8 +78,15 @@ function naive_syndrome_circuit(code_type::AbstractECC, ancillary_index=1, bit_i naive_syndrome_circuit(parity_checks(code_type), ancillary_index, bit_index) end -"""Circuit that measures the corresponding PauliOperator by using conditional gates into an ancillary -qubit at index `nqubits(p)+ancillary_index` and stores the measurement result into classical bit `bit_index`.""" +"""Naive Pauli measurement circuit using a single ancillary qubit. + +Not a fault-tolerant circuit, but useful for testing purposes. + +Measures the corresponding `PauliOperator` by using conditional gates into an ancillary +qubit at index `nqubits(p)+ancillary_index` and stores the measurement result +into classical bit `bit_index`. + +See also: [`naive_syndrome_circuit`](@ref), [`shor_ancillary_paulimeasurement`](@ref)""" function naive_ancillary_paulimeasurement(p::PauliOperator, ancillary_index=1, bit_index=1) circuit = AbstractOperation[] numQubits = nqubits(p) @@ -96,12 +107,104 @@ end function naive_syndrome_circuit(parity_check_tableau, ancillary_index=1, bit_index=1) naive_sc = AbstractOperation[] + ancillaries = 0 + bits = 0 + for check in parity_check_tableau + append!(naive_sc,naive_ancillary_paulimeasurement(check, ancillary_index+ancillaries, bit_index+bits)) + ancillaries +=1 + bits +=1 + end + + return naive_sc, ancillaries, bit_index:bit_index+bits-1 +end + +"""Generate the Shor fault-tolerant stabilizer measurement cicuit for a given code instance or parity check tableau. + +Use the `ancillary_index` and `bit_index` arguments to offset where the corresponding part the circuit starts. +Ancillary qubits + +Returns: + - The cat state preparation circuit. + - The Shor syndrome measurement circuit. + - The number of ancillary qubits that were added. + - The list of bit indices that store the final measurement results. + +See also: [`naive_syndrome_circuit`](@ref) +""" +function shor_syndrome_circuit end + +function shor_syndrome_circuit(code_type::AbstractECC, ancillary_index=1, bit_index=1) + shor_syndrome_circuit(parity_checks(code_type), ancillary_index, bit_index) +end + +"""Shor's Pauli measurement circuit using a multiple entangled ancillary qubits. + +A fault-tolerant circuit. + +Measures the corresponding PauliOperator by using conditional gates into multiple ancillary +entangled qubits starting at index `nqubits(p)+ancillary_index` +and stores the measurement result into classical bits starting at `bit_index`. +The final measurement result is the XOR of all the bits. + +Returns: + - The cat state preparation circuit. + - The Shor syndrome measurement circuit. + - One more than the index of the last added ancillary qubit. + - One more than the index of the last added classical bit. + +See also: [`naive_syndrome_circuit`](@ref), [`naive_ancillary_paulimeasurement`](@ref)""" +function shor_ancillary_paulimeasurement(p::PauliOperator, ancillary_index=1, bit_index=1) + init_ancil_index = ancillary_index + circuit = AbstractOperation[] + measurements = AbstractOperation[] + numQubits = nqubits(p) + for qubit in 1:numQubits + if p[qubit] == (1,0) + push!(circuit, sXCZ(qubit, numQubits + ancillary_index)) + elseif p[qubit] == (0,1) + push!(circuit, sZCZ(qubit, numQubits + ancillary_index)) + elseif p[qubit] == (1,1) + push!(circuit, sYCZ(qubit, numQubits + ancillary_index)) + end + if p[qubit] != (0,0) + push!(measurements, sMRX(numQubits + ancillary_index, bit_index)) + ancillary_index +=1 + bit_index +=1 + end + end + circuit = vcat(circuit,measurements) + + cat_state_circuit = AbstractOperation[] + push!(cat_state_circuit, sHadamard(numQubits + init_ancil_index)) + for i in (init_ancil_index+1):(ancillary_index -1) + push!(cat_state_circuit, sCNOT(numQubits + (i - 1), numQubits + i)) + end + + return cat_state_circuit, circuit, ancillary_index, bit_index +end + +function shor_syndrome_circuit(parity_check_tableau, ancillary_index=1, bit_index=1) + shor_sc = AbstractOperation[] + xor_indices = [] + cat_circuit = AbstractOperation[] + initial_ancillary_index = ancillary_index for check in parity_check_tableau - naive_sc = append!(naive_sc,naive_ancillary_paulimeasurement(check, ancillary_index, bit_index)) - ancillary_index +=1 - bit_index +=1 + cat_circ, circ, new_ancillary_index, new_bit_index = shor_ancillary_paulimeasurement(check, ancillary_index, bit_index) + push!(xor_indices, collect(bit_index:new_bit_index-1)) + + append!(shor_sc, circ) + append!(cat_circuit, cat_circ) + + ancillary_index = new_ancillary_index + bit_index = new_bit_index + end + + final_bits = 0 + for indices in xor_indices + push!(shor_sc, QuantumClifford.ClassicalXOR(indices, bit_index+final_bits)) + final_bits += 1 end - return naive_sc + return cat_circuit, shor_sc, ancillary_index-initial_ancillary_index, bit_index:bit_index+final_bits-1 end From 4db5e8e96ef5cfc98743d8d7ad0cac04db72e30b Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sun, 17 Sep 2023 16:02:14 -0400 Subject: [PATCH 15/18] fix tests --- Project.toml | 2 +- docs/src/ecc_example_sim.md | 4 ++-- src/ecc/ECC.jl | 7 ++----- src/ecc/circuits.jl | 20 ++++++++++++-------- test/runtests.jl | 1 + test/test_ecc.jl | 17 +++++++++-------- test/test_ecc_encoding.jl | 2 -- test/test_ecc_syndromes.jl | 7 +++++-- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/Project.toml b/Project.toml index 3ae3fc876..3ee2bd84d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "QuantumClifford" uuid = "0525e862-1e90-11e9-3e4d-1b39d7109de1" authors = ["Stefan Krastanov "] -version = "0.8.16" +version = "0.8.17" [deps] Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" diff --git a/docs/src/ecc_example_sim.md b/docs/src/ecc_example_sim.md index e20f66703..5ee627ca8 100644 --- a/docs/src/ecc_example_sim.md +++ b/docs/src/ecc_example_sim.md @@ -12,7 +12,7 @@ Consider Steane 7-qubit code: ```@example 1 using QuantumClifford -using QuantumClifford.ECC: Steane7, naive_syndrome_circuit, encoding_circuit, parity_checks, code_s, code_n +using QuantumClifford.ECC: Steane7, naive_syndrome_circuit, naive_encoding_circuit, parity_checks, code_s, code_n using Quantikz code = Steane7() @@ -21,7 +21,7 @@ H = parity_checks(code) ... and the corresponding encoding circuit ```@example 1 -ecirc = encoding_circuit(code) +ecirc = naive_encoding_circuit(code) ``` ... and the corresponding syndrome measurement circuit (the non-fault tolerant one) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 263346d8c..b83f4e793 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -9,14 +9,11 @@ using Combinatorics: combinations abstract type AbstractECC end -export Shor9, Steane7, Steane5, Cleve8, - parity_checks, naive_syndrome_circuit, encoding_circuit, +export Shor9, Steane7, Cleve8, Perfect5, Bitflip3, + parity_checks, naive_syndrome_circuit, shor_syndrome_circuit, naive_encoding_circuit, code_n, code_s, code_k, rate, distance, isdegenerate, faults_matrix -"""The encoding circuit of a given code.""" -function encoding_circuit end - """Parity check tableau of a code.""" function parity_checks end diff --git a/src/ecc/circuits.jl b/src/ecc/circuits.jl index a716dd844..52745a378 100644 --- a/src/ecc/circuits.jl +++ b/src/ecc/circuits.jl @@ -1,7 +1,5 @@ """Encoding physical qubits into a larger logical code. -Based on [gottesman1997stabilizer](@cite) and [cleve1997efficient](@cite). - The initial physical qubits to be encoded have to be at indices `n-k+1:n`. !!! info "Encoding circuits are not fault-tolerant" @@ -13,6 +11,11 @@ The initial physical qubits to be encoded have to be at indices `n-k+1:n`. The canonicalization operation performed on the code may permute the qubits. You might need to correct other parts of your code to account for this or set `undoperm=true` to add the necessary SWAP gates to undo the permutation. + +Based on [gottesman1997stabilizer](@cite) and [cleve1997efficient](@cite), +however it seems the published algorithm has some errors. +Consult the erratum, and be aware that this implementation also uses H instead of Z gates. + """ function naive_encoding_circuit(code; undoperm=false, reportperm=false) n = code_n(code) @@ -89,17 +92,18 @@ into classical bit `bit_index`. See also: [`naive_syndrome_circuit`](@ref), [`shor_ancillary_paulimeasurement`](@ref)""" function naive_ancillary_paulimeasurement(p::PauliOperator, ancillary_index=1, bit_index=1) circuit = AbstractOperation[] - numQubits = nqubits(p) - for qubit in 1:numQubits + n = nqubits(p) + for qubit in 1:n if p[qubit] == (1,0) - push!(circuit, sXCX(qubit, numQubits + ancillary_index)) + push!(circuit, sXCX(qubit, n + ancillary_index)) elseif p[qubit] == (0,1) - push!(circuit, sCNOT(qubit, numQubits + ancillary_index)) + push!(circuit, sCNOT(qubit, n + ancillary_index)) elseif p[qubit] == (1,1) - push!(circuit, sYCX(qubit, numQubits + ancillary_index)) + push!(circuit, sYCX(qubit, n + ancillary_index)) end end - mz = sMRZ(numQubits + ancillary_index, bit_index) + p.phase[] == 0 || push!(circuit, sX(n + ancillary_index)) + mz = sMRZ(n + ancillary_index, bit_index) push!(circuit, mz) return circuit diff --git a/test/runtests.jl b/test/runtests.jl index 5230826d0..ef17e4860 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -61,6 +61,7 @@ end @doset "enumerate" @doset "quantumoptics" @doset "ecc" +@doset "ecc_encoding" @doset "ecc_syndromes" @doset "precompile" @doset "pauliframe" diff --git a/test/test_ecc.jl b/test/test_ecc.jl index b2aa2c96b..54ce128d8 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -1,21 +1,23 @@ using Test using QuantumClifford -using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, code_n, parity_checks, encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops, isdegenerate, rank, standard_tab_gott +using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, Perfect5, naive_syndrome_circuit, code_n, parity_checks, naive_encoding_circuit, code_s, code_k, rate, distance,logx_ops, logz_ops, isdegenerate codes = [ Bitflip3(), Steane7(), Shor9(), + Perfect5(), Cleve8(), ] ## -function test_naive_syndrome(c::AbstractECC, e::Bool=false) +function test_naive_syndrome(code::AbstractECC, e::Bool) + c = canonicalize_gott!(parity_checks(code))[1] # TODO - this line is there to make sure we do not permute qubits - remove it when we fix the naive_encoding_circuit function # create a random logical state unencoded_qubits = random_stabilizer(code_k(c)) bufferqubits = one(Stabilizer,code_s(c)) - logicalqubits = unencoded_qubits⊗bufferqubits + logicalqubits = bufferqubits⊗unencoded_qubits mctrajectory!(logicalqubits, naive_encoding_circuit(c)) if e #add some noise to logicalqubits @@ -36,13 +38,11 @@ function test_naive_syndrome(c::AbstractECC, e::Bool=false) @test all(bitview(syndrome2) .== 0) end @test bitview(syndrome2) == syndrome1.÷2 - - # TODO test when there is potential for errors / non-commuting operators end @testset "naive syndrome circuits - zero syndrome for logical states" begin - for c in codes, _ in 1:2 - test_naive_syndrome(c) + for c in codes, _ in 1:10 + test_naive_syndrome(c, false) test_naive_syndrome(c, true) end end @@ -50,7 +50,8 @@ end ## function test_with_pframes(code) - ecirc = encoding_circuit(code) + code = canonicalize_gott!(parity_checks(code))[1] # TODO - this line is there to make sure we do not permute qubits - remove it when we fix the naive_encoding_circuit function + ecirc = naive_encoding_circuit(code) scirc, _ = naive_syndrome_circuit(code) nframes = 10 dataqubits = code_n(code) diff --git a/test/test_ecc_encoding.jl b/test/test_ecc_encoding.jl index 756a172e5..51a6c9c33 100644 --- a/test/test_ecc_encoding.jl +++ b/test/test_ecc_encoding.jl @@ -45,8 +45,6 @@ using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, Perfec @test (encodedₙ == algebraicₙ) - @show affectedqubits.(circ) - @show circ #println("$codeexpr, $(encodedₙ == algebraicₙ)") end end diff --git a/test/test_ecc_syndromes.jl b/test/test_ecc_syndromes.jl index 851f95157..6510c9825 100644 --- a/test/test_ecc_syndromes.jl +++ b/test/test_ecc_syndromes.jl @@ -1,18 +1,21 @@ using Test using QuantumClifford using QuantumClifford: mul_left! -using QuantumClifford.ECC: AbstractECC, Steane7, Shor9, Bitflip3, naive_syndrome_circuit, encoding_circuit, shor_syndrome_circuit, code_n, code_s +using QuantumClifford.ECC: AbstractECC, Steane7, Shor9, Perfect5, Bitflip3, Cleve8, naive_syndrome_circuit, naive_encoding_circuit, shor_syndrome_circuit, code_n, code_s, parity_checks codes = [ Bitflip3(), Steane7(), Shor9(), + Perfect5(), + Cleve8() ] ## function pframe_naive_vs_shor_syndrome(code) - ecirc = encoding_circuit(code) + code = canonicalize_gott!(parity_checks(code))[1] # TODO - this line is there to make sure we do not permute qubits - remove it when we fix the naive_encoding_circuit function + 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 From 00a14652baf69992722a75cd7c14379a42eee997 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sun, 17 Sep 2023 17:07:04 -0400 Subject: [PATCH 16/18] correct for qubit permutations --- src/QuantumClifford.jl | 2 +- src/ecc/circuits.jl | 34 ++++++++++++++++++++++++---------- test/test_ecc.jl | 4 +--- test/test_ecc_encoding.jl | 16 ++++++++++------ test/test_ecc_syndromes.jl | 1 - 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index 2ecfc0306..d4ac9ba26 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -559,7 +559,7 @@ function MixedDestabilizer(stab::Stabilizer{T}; undoperm=true, reportperm=false) return MixedDestabilizer(t, r+s)::MixedDestabilizer{T} end if reportperm - return (r, permx, permz, MixedDestabilizer(t, r+s)::MixedDestabilizer{T}) + return (MixedDestabilizer(t, r+s)::MixedDestabilizer{T}, r, permx, permz) else return MixedDestabilizer(t, r+s)::MixedDestabilizer{T} end diff --git a/src/ecc/circuits.jl b/src/ecc/circuits.jl index 52745a378..e39457e71 100644 --- a/src/ecc/circuits.jl +++ b/src/ecc/circuits.jl @@ -7,20 +7,18 @@ The initial physical qubits to be encoded have to be at indices `n-k+1:n`. Instead, you should measure the stabilizers of the code and the logical observables, thus projecting into the code space (which can be fault-tolerant). -!!! warning "Implicit permutation of qubits" - The canonicalization operation performed on the code may permute the qubits. - You might need to correct other parts of your code to account for this or - set `undoperm=true` to add the necessary SWAP gates to undo the permutation. +The canonicalization operation performed on the code may permute the qubits (see [canonicalize_gott!](@ref)). +That permutation is corrected for with SWAP gates by default (controlled by the `undoperm` keyword argument). Based on [gottesman1997stabilizer](@cite) and [cleve1997efficient](@cite), however it seems the published algorithm has some errors. Consult the erratum, and be aware that this implementation also uses H instead of Z gates. """ -function naive_encoding_circuit(code; undoperm=false, reportperm=false) +function naive_encoding_circuit(code; undoperm=true) n = code_n(code) k = code_k(code) - r, permx, permz, md = MixedDestabilizer(code, undoperm=false, reportperm=true); + md, r, permx, permz = MixedDestabilizer(code, undoperm=false, reportperm=true); circ = QuantumClifford.AbstractOperation[] X = logicalxview(md) Z = logicalzview(md) @@ -60,11 +58,27 @@ function naive_encoding_circuit(code; undoperm=false, reportperm=false) end end end - if reportperm - return circ, permx, permz - else - return circ + if undoperm + perm = permx[permz] + transpositions = perm_to_transpositions(perm) + for (i,j) in transpositions + push!(circ, sSWAP(i,j)) + end + end + circ +end + +function perm_to_transpositions(perm) + n = length(perm) + transpositions = Tuple{Int, Int}[] + for i in n:-1:1 + if perm[i]!=i + j = findfirst(==(i), perm) + push!(transpositions, (i, j)) + perm[j] = perm[i] + end end + return transpositions end """Generate the non-fault-tolerant stabilizer measurement cicuit for a given code instance or parity check tableau. diff --git a/test/test_ecc.jl b/test/test_ecc.jl index 54ce128d8..3b7ac29c6 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -12,8 +12,7 @@ codes = [ ## -function test_naive_syndrome(code::AbstractECC, e::Bool) - c = canonicalize_gott!(parity_checks(code))[1] # TODO - this line is there to make sure we do not permute qubits - remove it when we fix the naive_encoding_circuit function +function test_naive_syndrome(c::AbstractECC, e::Bool) # create a random logical state unencoded_qubits = random_stabilizer(code_k(c)) bufferqubits = one(Stabilizer,code_s(c)) @@ -50,7 +49,6 @@ end ## function test_with_pframes(code) - code = canonicalize_gott!(parity_checks(code))[1] # TODO - this line is there to make sure we do not permute qubits - remove it when we fix the naive_encoding_circuit function ecirc = naive_encoding_circuit(code) scirc, _ = naive_syndrome_circuit(code) nframes = 10 diff --git a/test/test_ecc_encoding.jl b/test/test_ecc_encoding.jl index 51a6c9c33..12e693347 100644 --- a/test/test_ecc_encoding.jl +++ b/test/test_ecc_encoding.jl @@ -9,7 +9,8 @@ using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, Perfec # 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. - for codeexpr in [ + for undoperm in [true, false], + codeexpr in [ :(Cleve8()), :(Steane7()), :(Shor9()), @@ -21,12 +22,15 @@ using QuantumClifford.ECC: AbstractECC, Cleve8, Steane7, Shor9, Bitflip3, Perfec fill(:(random_stabilizer(5,7)), 100)... ] - # pre-process the tableau to remove permutations and negative phases code = eval(codeexpr) - stab, r, s, xperm, zperm = canonicalize_gott!(parity_checks(code)) - code = stab # using this tableau guarantees we do not need to worry about permutations of the qubits - - circ = naive_encoding_circuit(code) + if undoperm==false + # Pre-process the tableau to remove permutations and negative phases. + # Usually that is handled by `naive_encoding_circuit`, but we just want to check both branches for its `undoperm` kwarg. + stab, r, s, xperm, zperm = canonicalize_gott!(parity_checks(code)) + code = stab # using this tableau guarantees we do not need to worry about permutations of the qubits + end + + circ = naive_encoding_circuit(code; undoperm=true) #display(circ) # the state to be encoded (k physical qubits) diff --git a/test/test_ecc_syndromes.jl b/test/test_ecc_syndromes.jl index 6510c9825..fd89a2262 100644 --- a/test/test_ecc_syndromes.jl +++ b/test/test_ecc_syndromes.jl @@ -14,7 +14,6 @@ codes = [ ## function pframe_naive_vs_shor_syndrome(code) - code = canonicalize_gott!(parity_checks(code))[1] # TODO - this line is there to make sure we do not permute qubits - remove it when we fix the naive_encoding_circuit function 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) From eb224c9517726b75f66abd952c751a817156f1f9 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sun, 17 Sep 2023 17:19:05 -0400 Subject: [PATCH 17/18] references --- docs/src/references.bib | 42 ++++++++++++++++++++++++++++++----------- src/ecc/circuits.jl | 4 ++-- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/docs/src/references.bib b/docs/src/references.bib index 02e29aa2b..1514cf4e7 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -166,6 +166,37 @@ @misc{hein2006entanglement year = {2006}, } +% Encoding circuits + +@article{cleve1997efficient, + title={Efficient computations of encodings for quantum error correction}, + author={Cleve, Richard and Gottesman, Daniel}, + journal={Physical Review A}, + volume={56}, + number={1}, + pages={76}, + year={1997}, + publisher={APS} +} + +@inproceedings{grassl2011variations, + title={Variations on encoding circuits for stabilizer quantum codes}, + author={Grassl, Markus}, + booktitle={International Conference on Coding and Cryptology}, + pages={142--158}, + year={2011}, + organization={Springer} +} + +@article{grassl2002algorithmic, + title={Algorithmic aspects of quantum error-correcting codes}, + author={Grassl, Markus}, + journal={Mathematics of Quantum Computation}, + pages={223--252}, + year={2002}, + publisher={CRC Press Boca Raton, FL} +} + % Examples of results that employ the tableaux formalism @article{gullans2020quantum, @@ -192,15 +223,4 @@ @article{nahum2017quantum journal = {Physical Review X}, author = {Nahum, Adam and Ruhman, Jonathan and Vijay, Sagar and Haah, Jeongwan}, year = {2017} -} - -@article{cleve1997efficient, - title={Efficient computations of encodings for quantum error correction}, - author={Cleve, Richard and Gottesman, Daniel}, - journal={Physical Review A}, - volume={56}, - number={1}, - pages={76}, - year={1997}, - publisher={APS} } \ No newline at end of file diff --git a/src/ecc/circuits.jl b/src/ecc/circuits.jl index e39457e71..0f62a7057 100644 --- a/src/ecc/circuits.jl +++ b/src/ecc/circuits.jl @@ -12,8 +12,8 @@ That permutation is corrected for with SWAP gates by default (controlled by the Based on [gottesman1997stabilizer](@cite) and [cleve1997efficient](@cite), however it seems the published algorithm has some errors. -Consult the erratum, and be aware that this implementation also uses H instead of Z gates. - +Consult the erratum, as well as the more recent [grassl2002algorithmic](@cite) and [grassl2011variations](@cite), +and be aware that this implementation also uses H instead of Z gates. """ function naive_encoding_circuit(code; undoperm=true) n = code_n(code) From ed698f3d7f5f91e137c1536f4851eabf0f124242 Mon Sep 17 00:00:00 2001 From: Stefan Krastanov Date: Sun, 17 Sep 2023 19:09:13 -0400 Subject: [PATCH 18/18] fix documenter --- docs/make.jl | 6 +++--- docs/src/references.bib | 15 ++++++++------- src/entanglement.jl | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index b706a6153..48920028c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -15,13 +15,13 @@ ENV["COLUMNS"] = 80 bib = CitationBibliography(joinpath(@__DIR__,"src/references.bib"),style=:authoryear) makedocs( -bib, +plugins = [bib], doctest = false, clean = true, sitename = "QuantumClifford.jl", -format = Documenter.HTML(), +format = Documenter.HTML(size_threshold_ignore = ["API.md"]), modules = [QuantumClifford, QuantumClifford.Experimental.NoisyCircuits, QuantumInterface], -strict = Documenter.except(:missing_docs), +warnonly = [:missing_docs], authors = "Stefan Krastanov", pages = [ "QuantumClifford.jl" => "index.md", diff --git a/docs/src/references.bib b/docs/src/references.bib index 1514cf4e7..d260be4d7 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -158,12 +158,13 @@ @article{gullans2020dynamical publisher={APS} } -@misc{hein2006entanglement, - title = {Entanglement in Graph States and its Applications}, - url = {http://arxiv.org/abs/quant-ph/0602096}, - journaltitle = {arXiv preprint arXiv:quant-ph/0602096}, - author = {Hein, M. and Dür, W. and Eisert, J. and Raussendorf, R. and Nest, M. Van den and Briegel, H.-J.}, - year = {2006}, +@article{hein2006entanglement, + title={Entanglement in graph states and its applications}, + author={Hein, Marc and D{\"u}r, Wolfgang and Eisert, Jens and Raussendorf, Robert and Nest, M and Briegel, H-J}, + journal={arXiv preprint quant-ph/0602096}, + url={https://arxiv.org/abs/quant-ph/0602096}, + doi={10.48550/arXiv.quant-ph/0602096}, + year={2006} } % Encoding circuits @@ -223,4 +224,4 @@ @article{nahum2017quantum journal = {Physical Review X}, author = {Nahum, Adam and Ruhman, Jonathan and Vijay, Sagar and Haah, Jeongwan}, year = {2017} -} \ No newline at end of file +} diff --git a/src/entanglement.jl b/src/entanglement.jl index 78f48612c..fafeec4dd 100644 --- a/src/entanglement.jl +++ b/src/entanglement.jl @@ -195,8 +195,8 @@ end """ Get bipartite entanglement entropy by first converting the state to a graph and computing the rank of the adjacency matrix. -Based on [hein2006entanglement](@cite). -""" +Based on "Entanglement in graph states and its applications". +""" # TODO you should use [hein2006entanglement](@cite) instead of "Entanglement in graph states and its applications", but Documenter is giving the weirdest error if you do so... function entanglement_entropy(state::AbstractStabilizer, subsystem::AbstractVector, algorithm::Val{:graph}) graph = Graphs.Graph(state) adjmat = Graphs.adjacency_matrix(graph)