diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 0410b5a60..903fba255 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -2,6 +2,8 @@ module ECC using QuantumClifford using QuantumClifford: AbstractOperation +using LinearAlgebra +using Nemo import QuantumClifford: Stabilizer, MixedDestabilizer abstract type AbstractECC end @@ -397,5 +399,200 @@ end include("./bitflipcode.jl") include("./shorcode.jl") include("./steanecode.jl") +include("./cleavecode.jl") +include("./fiveonethreecode.jl") +include("./fivetwotwocode.jl") + +function canonicalize_cleve97(checks::Stabilizer) + d, n = size(checks) + X0 = (checks |> stab_to_gf2)[:,1:n]' + Z0 = (checks |> stab_to_gf2)[:,n+1:2n]' + + # Now let's work on getting X1 and Z1 + Z2field = Nemo.ResidueRing(ZZ, 2) + b = rank(Nemo.matrix(Z2field, X0)) + + r = d-b + k = n-d + + # First let's move the 0 columns to the left: + nullColumns = [] + notNullColumns = [] + for j in 1:d + if count(X0[:,j])==0 # TODO make sure this is condition -> null generator + push!(nullColumns, j) + else + push!(notNullColumns, j) + end + end + + # Reorder the generators/columns so 0 vectors are in front of X0: + column_order = vcat(nullColumns, notNullColumns) + X0_5 = X0[:, column_order] + Z0_5 = Z0[:, column_order] + + # Second let's perform Gaussian elimination to arrive at X1 and Z1 + bank = [] + for j in (r+1):(r+b) + i = 1 + STOP = false + while !STOP + if X0_5[i, j] != 1 + i+=1 + if i > n + print("ERROR") + STOP = true + end + else + STOP = true + end + end + push!(bank, i) + for a in (r+1):(r+b) + if a == j + continue + end + if X0_5[i,a] == 1 + X0_5[:,a] = (X0_5[:,j]+X0_5[:,a]).%2 + Z0_5[:,a] = (Z0_5[:,j]+Z0_5[:,a]).%2 + end + end + end + + qubit_order = [] + for i in 1:n + if i ∉ bank + push!(qubit_order, i) + end + end + append!(qubit_order, bank) + X1 = X0_5[qubit_order, :] + Z1 = Z0_5[qubit_order, :] + println("Qubit order 1", qubit_order) + checks = checks[:, qubit_order] + + # Now begins the march towards X2 and Z2, starting with B' + r1 = rank(Nemo.matrix(Z2field, Z1[1:r+k,1:r])) + r2 = r - r1 + + # First let's move the 0 columns of B to the left: + nullColumns = [] + notNullColumns = [] + for j in 1:r + if count(Z1[:,j])==0 # TODO make sure this is condition <-> null generator + push!(nullColumns, j) + else + push!(notNullColumns, j) + end + end + for j in r+1:d + push!(notNullColumns, j) + end + + # Reorder the generators/columns so 0 vectors are in front of B: + column_order = vcat(nullColumns, notNullColumns) + Z1_5 = Z1[:, column_order] + + # Now Gaussian elimination again, this time over B' + bank = [] + for j in (r2+1):(r2+r1) + i = 1 + STOP = false + while !STOP + if Z1_5[i, j] != 1 + i+=1 + if i > n + print("ERROR") + STOP = true + end + else + STOP = true + end + end + push!(bank, i) + for a in (r2+1):(r2+r1) + if a == j + continue + end + if Z1_5[i,a] == 1 + Z1_5[:,a] = (Z1_5[:,j]+Z1_5[:,a]).%2 + end + end + end + + qubit_order = [] + for i in 1:n + if i ∉ bank && i<= k+r + push!(qubit_order, i) + end + end + for i in k+r+1:n # rows not in B + push!(bank, i) + end + append!(qubit_order, bank) + Z2 = Z1_5[qubit_order, :] + X2 = X1[qubit_order, :] # X is unchanged by operations on b, except for reindexing of qubits + println("Qubit order 2", qubit_order) + checks = checks[:, qubit_order] + + # Now time for the final steps before arriving at Xstar Zstar + B1 = Z2[1:k,1+r2:r2+r1] + + XI = zeros(Bool, k , k) + for i in 1:k + XI[i,i] = 1 + end + Xs = (vcat(XI, zeros(Bool,r2, k), B1', zeros(Bool, b, k))) + Zs = zeros(Bool, n, k) + + println("k, r2, r1, b: ", k, " ", r2, " ", r1, " ", b) + Xstar = hcat(Xs,X2) + Zstar = hcat(Zs,Z2) + + #return X0, X0_5, X1, X2, Xstar, Z0, Z0_5, Z1, Z1_5, Z2, Zstar + return Xstar, Zstar, Stabilizer(X2', Z2')# TODO Return reordered checks or Stab(X2', Z2')? +end + +""" The naive implementation of the encoding circuit by arXiv:quant-ph/9607030 """ +function naive_encoding_circuit(checks::Stabilizer) + d, n = size(checks) + X0 = (checks |> stab_to_gf2)[:,1:n]' + + Z2field = Nemo.ResidueRing(ZZ, 2) + b = rank(Nemo.matrix(Z2field, X0)) + + r = d-b + k = n-d + + Xstar, Zstar, standard_tab = canonicalize_cleve97(checks) + + naive_ec = AbstractOperation[] + for i in (r+k+1):(r+k+b) + push!(naive_ec, sHadamard(i)) + end + + for j in 1:n + if count(Xstar[:,j]) == 0 # Secondary generators are ignored + continue + end + if Zstar[j,j]==1 + push!(naive_ec, sZ(j)) + end + for i in 1:n + if i == j + continue + end + if Xstar[i,j] == 1 && Zstar[i,j] == 0 + push!(naive_ec, sZCX(j,i)) + elseif Xstar[i,j] == 0 && Zstar[i,j] == 1 + push!(naive_ec, sZCZ(j,i)) + elseif Xstar[i,j] == 1 && Zstar[i,j] == 1 + push!(naive_ec, sZCY(j,i)) + end + end + end + + return naive_ec, standard_tab +end end #module diff --git a/src/ecc/cleavecode.jl b/src/ecc/cleavecode.jl new file mode 100644 index 000000000..9006827b0 --- /dev/null +++ b/src/ecc/cleavecode.jl @@ -0,0 +1,55 @@ +"""A pedagogical example of a quantum error correcting [8,3] code used in [cleve1997efficient](@cite).""" +struct Cleve8 <: AbstractECC end + +code_n(c::Cleve8) = 8 +code_k(c::Cleve8) = 3 + +parity_checks(c::Cleve8) = S"XXXXXXXX + ZZZZZZZZ + XIXIZYZY + XIYZXIYZ + XZIYIYXZ" + +function encoding_circuit(c::Cleve8) + c1 = sCNOT(1,4) + c2 = sCNOT(2,4) + c3 = sCNOT(3,4) + h1 = sHadamard(5) + z1 = sZ(5) + h2 = sHadamard(6) + h3 = sHadamard(7) + z3 = sZ(7) + h4 = sHadamard(8) + z4 = sZ(8) + first_part = [c1,c2,c3,h1,z1,h2,h3,z3,h4,z4] + + c1 = sZCX(5, 1) + c2 = sZCX(5, 2) + c3 = sZCY(5, 3) + c4 = sZCZ(5, 4) + c5 = sZCZ(5, 6) + column1 = [c1,c2,c3,c4,c5] # 1st non null column of Zstar + + c1 = sZCX(6, 1) + c2 = sZCY(6, 2) + c3 = sZCY(6, 4) + c4 = sZCZ(6, 5) + c5 = sZCZ(6, 7) + column2 = [c1,c2,c3,c4,c5] + + c1 = sZCX(7, 1) + c2 = sZCY(7, 3) + c3 = sZCX(7, 4) + c4 = sZCZ(7, 5) + c5 = sZCZ(7, 8) + column3 = [c1,c2,c3,c4,c5] + + c1 = sZCY(8, 2) + c2 = sZCX(8, 3) + c3 = sZCX(8, 4) + c4 = sZCZ(8, 5) + c5 = sZCZ(8, 6) + column4 = [c1,c2,c3,c4,c5] + + return vcat(first_part, column1, column2, column3, column4) +end \ No newline at end of file diff --git a/src/ecc/fiveonethreecode.jl b/src/ecc/fiveonethreecode.jl new file mode 100644 index 000000000..6b2d089d3 --- /dev/null +++ b/src/ecc/fiveonethreecode.jl @@ -0,0 +1,9 @@ +"""http://www.codetables.de/QECC.php?q=4&n=5&k=1""" +struct FiveOneThree <: AbstractECC end + +code_n(c::FiveOneThree) = 8 + +parity_checks(c::FiveOneThree) = S"YIZXY + ZXIZY + ZIXYZ + IZZZZ" \ No newline at end of file diff --git a/src/ecc/fivetwotwocode.jl b/src/ecc/fivetwotwocode.jl new file mode 100644 index 000000000..dc36721de --- /dev/null +++ b/src/ecc/fivetwotwocode.jl @@ -0,0 +1,8 @@ +"""http://www.codetables.de/QECC.php?q=4&n=5&k=2""" +struct FiveTwoTwo <: AbstractECC end + +code_n(c::FiveTwoTwo) = 8 + +parity_checks(c::FiveTwoTwo) = S"XXXXI + IIIIX + ZZZZI" \ No newline at end of file