Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Benzillaist committed Dec 30, 2023
2 parents c8d531f + bd823ef commit 295ed67
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"julia.environmentPath": "c:\\Users\\benku\\Desktop\\College Documents\\Krastanov Independent Study\\QuantumClifford.jl-CSS_Builder"
}
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
QuantumInterface = "5717a53b-5d69-4fa3-b976-0bf2f97ca1e5"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SIMD = "fdea26ae-647d-5447-a871-4b548cad5224"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
SumTypes = "8e1ec7a9-0e02-4297-b0fe-6433085c89f2"

[weakdeps]
Expand Down
13 changes: 10 additions & 3 deletions src/ecc/ECC.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
module ECC

using LinearAlgebra
using QuantumClifford
using QuantumClifford: AbstractOperation, AbstractStabilizer
using QuantumClifford, SparseArrays
using QuantumClifford: AbstractOperation, AbstractStabilizer, Stabilizer
import QuantumClifford: Stabilizer, MixedDestabilizer
using DocStringExtensions
using Combinatorics: combinations
using Statistics: std
using Nemo: ZZ, residue_ring, matrix

abstract type AbstractECC end

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
isdegenerate, faults_matrix,
Unicycle, Bicycle,
CSS

"""Parity check tableau of a code."""
function parity_checks end
Expand Down Expand Up @@ -298,4 +302,7 @@ include("codes/steanecode.jl")
include("codes/shorcode.jl")
include("codes/clevecode.jl")

include("codes/css.jl")
include("codes/simple_sparse_codes.jl")

end #module
37 changes: 37 additions & 0 deletions src/ecc/codes/css.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""An arbitrary CSS error correcting code defined by its X and Z checks."""
struct CSS <: AbstractECC
Hx
Hz
"""Creates a CSS code using the two provided matrices where Hx contains the X checks and Hz contains the Z checks."""
function CSS(Hx, Hz)
n = size(Hx, 2)
if n != size(Hz, 2) error("When constructing a CSS quantum code, the two classical codes are required to have the same block size") end
if size(Hx,1)+size(Hz,1) >= n error("When constructing a CSS quantum code, the total number of checks (rows) in the parity checks of the two classical codes have to be lower than the block size (the number of columns).") end
return new(Hx, Hz)
end
end

function boolean_tableau(c::CSS)
Hx_height, Hx_width = size(c.Hx)
Hz_height, Hz_width = size(x.Hz)
checks_matrix = falses(Hx_height + Hz_height, Hx_width + Hz_width)
checks_matrix[1:Hx_height, 1:Hx_width] = c.Hx
checks_matrix[Hx_height+1:end, Hx_width+1:end] = c.Hz
return CSS(checks_matrix)
end

"""Returns the stabilizer making up the parity check tableau."""
function parity_checks(c::CSS)
extended_Hx = Matrix{Bool}(vcat(c.Hx, zeros(size(c.Hz))))
extended_Hz = Matrix{Bool}(vcat(zeros(size(c.Hx)), c.Hz))
Stabilizer(fill(0x0, size(c.Hx, 2) + size(c.Hz, 2)), extended_Hx, extended_Hz)
end

"""Returns the block length of the code."""
code_n(c::CSS) = size(c.Hx,2)

"""Returns the depth of the parity check matrix"""
code_m(c::CSS) = size(c.Hx, 1) + size(c.Hz, 1)

"""Returns the number of encoded qubits"""
code_k(c::CSS) = (2 * size(c.Hx,2)) - code_m(c)
231 changes: 231 additions & 0 deletions src/ecc/codes/simple_sparse_codes.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# Currently just has Bicycle and Unicycle codes, but open to all types of rudimentary sparse codes

"""Takes a height and width of matrix and generates a bicycle code to the specified height and width.
Parameters:
- n: width of array, should be >= 2
- m: height of array, should be >= 2 and a multiple of 2"""
function Bicycle(n::Int, m::Int)
if m%2 == 1
throw(DomainError(m, " M should be a multiple for 2 for bicycle codes."))
end
if m < 2
throw(DomainError(m, " M is too small, make it greater than 1."))
end
bs = bicycle_set_gen(Int(n/2))
bsc = circ_to_bicycle_h0(bs, Int(n/2))
while size(bsc)[1] > m/2
bsc = reduce_bicycle(bsc)
end
return CSS(bsc, bsc)
end

"""Takes a height and width of matrix and generates a bicycle code to the specified height and width.
Parameters:
- n: width of array, should be >= 1
- set: array of indices that are 'active' checks in the circulant code"""
function Unicycle(n::Int, set)
usc = circ_to_unicycle_h0(set, n)
rusc = reduce_unicycle(usc)
return CSS(rusc, rusc)
end

"""Takes an untrimmed bicycle matrix and removes the row which keeps the spread of the column weights minimal.
Required before the bicycle code can be used.
Typical usage:
ReduceBicycle(Circ2BicycleH0(array_indices, (block length / 2) ) )"""
function reduce_bicycle(H0::Matrix{Bool})
m, n = size(H0)
r_i = 0
std_min = Inf
for i in 1:m
t_H0 = vcat(H0[1:i-1, :], H0[i+1:end, :])
std_temp = std(convert(Array, sum(t_H0, dims = 1)))
if std_temp < std_min
std_min = std_temp
r_i = i
end
end
return vcat(H0[1:r_i-1, :], H0[r_i+1:end, :])
end

"""Takes a list of indices and creates the base of the bicycle matrix.
For example:
Circ2BicycleH0([1, 2, 4], 7)
See https://arxiv.org/abs/quant-ph/0304161 for more details"""
function circ_to_bicycle_h0(circ_indices::Array{Int}, n::Int)
circ_arr = Array{Bool}(undef, n)
circ_matrix = Matrix{Bool}(undef, n, n)
comp_matrix = Matrix{Bool}(undef, n, 2*n)
for i = 1:n
if Int(i-1) in circ_indices
circ_arr[i] = true
else
circ_arr[i] = false
end
end
for i = 1:n
circ_matrix[i,1:n] = circ_arr
li = circ_arr[end]
circ_arr[2:end] = circ_arr[1:end-1]
circ_arr[1] = li
end
comp_matrix[1:n,1:n] = circ_matrix
comp_matrix[1:n,n+1:2*n] = transpose(circ_matrix)
return comp_matrix
end

"""Takes an untrimmed unicycle matrix and removes linearly dependent rows.
Required before the unicycle code can be used.
Typical usage:
`ReduceUnicycle(Circ2UnicycleH0(array_indices, block length) )`"""
function reduce_unicycle(m::Matrix{Bool})
rrzz = residue_ring(ZZ, 2)
nm = matrix(rrzz, m)
r = LinearAlgebra.rank(nm)
for i in 1:size(m)[1]
tm = vcat(m[1:i-1,:], m[i+1:end,:])
tr = LinearAlgebra.rank(matrix(rrzz, tm))
if(tr == r)
m = tm
i -= 1
if(size(m)[1] == r)
break
end
end
end
return m
end

"""Takes a list of indices and creates the base of the unicycle matrix.
For example:
`Circ2UnicycleH0([1, 2, 4], 7)`
See https://arxiv.org/abs/quant-ph/0304161 for more details"""
function circ_to_unicycle_h0(circ_indices::Array{Int}, n::Int)
circ_arr = fill(false, n)
one_col = transpose(fill(true, n))
circ_matrix = Matrix{Bool}(undef, n, n)
comp_matrix = Matrix{Bool}(undef, n, n+1)
for i = 1:n
if i in circ_indices
circ_arr[i] = true
else
circ_arr[i] = false
end
end
for i = 1:n
circ_matrix[i,1:n] = circ_arr
li = circ_arr[end]
circ_arr[2:end] = circ_arr[1:end-1]
circ_arr[1] = li
end
comp_matrix[1:n,1:n] = circ_matrix
comp_matrix[1:n,n+1] = one_col
return comp_matrix
end

"""Attempts to generate a list of indices to be used in a bicycle code using a search method"""
function bicycle_set_gen(N::Int)
circ_arr::Array{Int} = [0]
diff_arr::Array{Int} = []
circ_arr[1] = 0
# test new elements
for add_i = (circ_arr[end] + 1):N - 1
valid = true
temp_circ_arr = copy(circ_arr)
temp_diff_arr::Array{Int} = []
push!(temp_circ_arr, add_i)
for j = 1:size(temp_circ_arr)[1]
temp_arr = copy(temp_circ_arr)
# add lesser elements + N to temp_arr
for k = 1:size(temp_circ_arr)[1]
if k < j
push!(temp_arr, temp_circ_arr[k] + N)
else
break
end
end
# test if new index is valid
for k = 1:(size(temp_circ_arr)[1] - 2)
t_diff = (temp_arr[j + k] - temp_arr[j]) % N
if ((t_diff) in temp_diff_arr)
valid = false
break
else
push!(temp_diff_arr, t_diff)
end
end
if !valid
break
end
end
if valid
circ_arr = copy(temp_circ_arr)
diff_arr = copy(temp_diff_arr)
end
end
return circ_arr
end

"""Attempts to generate a list of indices to be used in a bicycle code using a randomized check method
Note: This is very slow for large N"""
function bicycle_set_gen_rand(N::Int, d::Int)
circ_arr::Array{Int} = [0]
diff_arr::Array{Int} = []
atmp_add::Array{Int} = [0]
circ_arr[1] = 0
# test new elements
for i = (circ_arr[end] + 1):(N^2)
valid = true
temp_circ_arr = copy(circ_arr)
temp_diff_arr::Array{Int} = []
add_i = rand(1: N-1)
atmp_add = push!(atmp_add, add_i)
if add_i in circ_arr
continue
end
push!(temp_circ_arr, add_i)
for j = 1:size(temp_circ_arr)[1]
temp_arr = copy(temp_circ_arr)
# add lesser elements + N to temp_arr
for k = 1:size(temp_circ_arr)[1]
if k < j
push!(temp_arr, temp_circ_arr[k] + N)
else
break
end
end
# test if new index is valid
for k = 1:(size(temp_circ_arr)[1] - 2)
t_diff = (temp_arr[j + k] - temp_arr[j]) % N
if ((t_diff) in temp_diff_arr)
valid = false
break
else
push!(temp_diff_arr, t_diff)
end
end
if !valid
break
end
end
if valid
circ_arr = copy(temp_circ_arr)
diff_arr = copy(temp_diff_arr)
if (size(atmp_add)[1] == N) || (size(circ_arr)[1] == d)
break
end
end
end
return circ_arr
end

0 comments on commit 295ed67

Please sign in to comment.