Skip to content

Commit

Permalink
enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
Fe-r-oz committed Dec 1, 2024
1 parent 683c969 commit d58e094
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ even overlap with each X-check of the stabilizer binary representation `stab`.
an odd overlap with logical-X operator `logicOp` on the i-th logical qubit.
Specifically, it calculates the minimum Hamming weight \$d_{Z}\$ for the Z-type
logical operator, and the minimum distance for X-type logical operators is the same.
logical operator. The minimum distance for X-type logical operators is the same.
### Background on Minimum Distance
Expand Down Expand Up @@ -59,9 +59,9 @@ julia> distance(Steane7())
3
```
The minimum distance problem for quantum codes is *NP-hard*, and this hardness extends
to multiplicative and additive approximations, even when restricted to stabilizer or
CSS codes, with the result established through a reduction from classical problems in
!!! note The minimum distance problem for quantum codes is *NP-hard*, and this hardness
extends to multiplicative and additive approximations, even when restricted to stabilizer
or CSS codes, with the result established through a reduction from classical problems in
the CWS framework using a 4-cycle free graph [kapshikar2023hardness](@cite). Despite
this, methods that improve on brute-force approaches are actively explored.
Expand Down Expand Up @@ -136,6 +136,22 @@ julia> code_n(c1), code_k(c1), distance(c1)
(48, 6, 8)
```
!!!Since the [[48, 6, 8]] GB code does not have specific lower and upper bounds
(e.g., consider [[48, 6, 5 ≤ d ≤ 8]]), the minimum distance for all `Z`-type and
`X`-type logical qubits remains the same. In this context, the *exact* minimum
distance is provided.
```jldoctest examples
julia> distance(c1, all_logical_qubits=true)
Dict{Int64, Int64} with 6 entries:
5 => 8
4 => 8
6 => 8
2 => 8
3 => 8
1 => 8
```
### Applications
- The first usecase of the MIP approach was the code capacity Most Likely
Expand All @@ -147,25 +163,23 @@ to a mixed integer linear program and using the GNU Linear Programming Kit.
the code distance was calculated using the mixed integer programming approach.
"""
function distance(c::Stabilizer; num_logical_qubits=code_k(c), upper_bound=false)
lx, _ = get_lx_lz(c)
H = stab_to_gf2(parity_checks(c))
H = SparseMatrixCSC{Int, Int}(H)
hx = get_stab_hx(H)
1 <= num_logical_qubits < code_k(c) && return _minimum_distance(hx, lx[num_logical_qubits, :]) # for large instances
1 <= num_logical_qubits <= code_k(c) || throw(ArgumentError("The number of logical qubits must be between 1 and $(code_k(c)) inclusive"))
if num_logical_qubits == code_k(c)
weights = []
for i in 1:num_logical_qubits
w = _minimum_distance(hx, lx[num_logical_qubits, :])
push!(weights, w)
end
if upper_bound
return minimum(weights), maximum(weights) # return upper bound of minimum distance if required.
else
return minimum(weights)
end
function distance(c::Stabilizer; upper_bound=false, logical_qubit=code_k(c), all_logical_qubits=false, logical_operator_type=:X)
1 <= logical_qubit <= code_k(c) || throw(ArgumentError("The number of logical qubit must be between 1 and $(code_k(c)) inclusive"))
logical_operator_type == :X || logical_operator_type == :Z || throw(ArgumentError("Invalid type of logical operator: Use :X or :Z"))
l = get_lx_lz(c)[1]
H = SparseMatrixCSC{Int, Int}(stab_to_gf2(parity_checks(c)))
h = get_stab(H, :X)
if logical_operator_type == :Z
l = get_lx_lz(c)[2]
H = SparseMatrixCSC{Int, Int}(stab_to_gf2(parity_checks(c)))
h = get_stab(H, :Z)
end
weights = Dict{Int, Int}()
for i in 1:logical_qubit
w = _minimum_distance(h, l[i, :])
weights[i] = w
end
return upper_bound ? maximum(values(weights)) : (all_logical_qubits ? weights : minimum(values(weights)))
end

# Computing minimum distance for quantum LDPC codes is a NP-Hard problem,
Expand Down
16 changes: 10 additions & 6 deletions ext/QuantumCliffordJuMPExt/util.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
function get_stab_hx(matrix::SparseMatrixCSC{Int, Int})
function get_stab(matrix::SparseMatrixCSC{Int, Int}, logical_operator_type::Symbol)
rows, cols = size(matrix)
rhs_start = div(cols, 2) + 1
rhs_cols = matrix[:, rhs_start:cols]
non_zero_rows_rhs = unique(rhs_cols.rowval)
zero_rows_rhs = setdiff(1:rows, non_zero_rows_rhs)
return matrix[zero_rows_rhs, :]
if logical_operator_type == :Z
col_range = 1:div(cols, 2)
else logical_operator_type == :X
col_range = div(cols, 2) + 1:cols
end
submatrix = matrix[:, col_range]
non_zero_rows = unique(submatrix.rowval)
zero_rows = setdiff(1:rows, non_zero_rows)
return matrix[zero_rows, :]
end

function get_lx_lz(c::Stabilizer)
Expand Down
7 changes: 6 additions & 1 deletion test/test_ecc_coprime_bivaraite_bicycle.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using Nemo
using Nemo: gcd
using Hecke
using JuMP
using GLPK
using Hecke: group_algebra, GF, abelian_group, gens
using QuantumClifford.ECC: two_block_group_algebra_codes, code_k, code_n
using QuantumClifford.ECC: two_block_group_algebra_codes, code_k, code_n, distance

@testset "Reproduce Table 2 wang2024coprime" begin
# [[30,4,6]]
Expand All @@ -14,6 +16,7 @@
B = 𝜋 + 𝜋^3 + 𝜋^8
c = two_block_group_algebra_codes(A, B)
@test gcd([l,m]) == 1
@test distance(c) == 6
@test code_n(c) == 30 && code_k(c) == 4

# [[42,6,6]]
Expand All @@ -24,6 +27,7 @@
B = 𝜋 + 𝜋^3 + 𝜋^11
c = two_block_group_algebra_codes(A, B)
@test gcd([l,m]) == 1
@test distance(c) == 6
@test code_n(c) == 42 && code_k(c) == 6

# [[70,6,8]]
Expand All @@ -34,6 +38,7 @@
B = 1 + 𝜋 + 𝜋^12;
c = two_block_group_algebra_codes(A, B)
@test gcd([l,m]) == 1
@test distance(c) == 8
@test code_n(c) == 70 && code_k(c) == 6

# [[108,12,6]]
Expand Down
36 changes: 25 additions & 11 deletions test/test_ecc_generalized_bicycle_codes.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
@testitem "ECC GB" begin
using Hecke
using QuantumClifford.ECC: generalized_bicycle_codes, code_k, code_n
using JuMP
using GLPK
using QuantumClifford.ECC: generalized_bicycle_codes, code_k, code_n, distance

# codes taken from Table 1 of [lin2024quantum](@cite)
# Abelian 2BGA codes can be viewed as GB codes.
@test code_n(generalized_bicycle_codes([0 , 15, 16, 18], [0 , 1, 24, 27], 35)) == 70
@test code_k(generalized_bicycle_codes([0 , 15, 16, 18], [0 , 1, 24, 27], 35)) == 8
@test code_n(generalized_bicycle_codes([0 , 1, 3, 7], [0 , 1, 12, 19], 27)) == 54
@test code_k(generalized_bicycle_codes([0 , 1, 3, 7], [0 , 1, 12, 19], 27)) == 6
@test code_n(generalized_bicycle_codes([0 , 10, 6, 13], [0 , 25, 16, 12], 30)) == 60
@test code_k(generalized_bicycle_codes([0 , 10, 6, 13], [0 , 25, 16, 12], 30)) == 6
@test code_n(generalized_bicycle_codes([0 , 9, 28, 31], [0 , 1, 21, 34], 36)) == 72
@test code_k(generalized_bicycle_codes([0 , 9, 28, 31], [0 , 1, 21, 34], 36)) == 8
@test code_n(generalized_bicycle_codes([0 , 9, 28, 13], [0 , 1, 21, 34], 36)) == 72
@test code_k(generalized_bicycle_codes([0 , 9, 28, 13], [0 , 1, 3, 22], 36)) == 10

codes = [generalized_bicycle_codes([0 , 1, 3, 7], [0 , 1, 12, 19], 27), # [[54, 6, 9]]
generalized_bicycle_codes([0 , 10, 6, 13], [0 , 25, 16, 12], 30), # [[60, 6, 10]]
generalized_bicycle_codes([0 , 15, 16, 18], [0 , 1, 24, 27], 35), # [[70, 8, 10]]
generalized_bicycle_codes([0 , 9, 28, 31], [0 , 1, 21, 34], 36), # [[72, 8, 10]]
generalized_bicycle_codes([0 , 9, 28, 13], [0 , 1, 3, 22], 36)] # [[72, 8, 9]]

n_values = [54, 60, 70, 72, 72]
k_values = [6 , 6 , 8 , 8 , 10]
d_values = [9 , 10, 10, 10, 9]

for i in 1:length(n_values)
@test code_n(codes[i]) == n_values[i]
end

for i in 1:length(n_values)
@test code_k(codes[i]) == k_values[i]
end

for i in 1:length(d_values)
j = rand(1:code_k(codes[i]))
@test distance(codes[i], logical_qubit=j) == d_values[i]
end
end

0 comments on commit d58e094

Please sign in to comment.