Skip to content
4 changes: 2 additions & 2 deletions src/QuantumExpanders.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ using QuantumClifford: Stabilizer, comm
using QuantumClifford.ECC: DistanceMIPAlgorithm
using LinearAlgebra
using Random
using Random: AbstractRNG, GLOBAL_RNG
using Random: AbstractRNG, GLOBAL_RNG, shuffle
using Graphs
using Graphs: add_edge!, nv, ne, neighbors, Graphs, edges, Edge, src, dst, degree, adjacency_matrix, add_vertex!, has_edge,
vertices, induced_subgraph, AbstractGraph, is_bipartite, bipartite_map, has_edge
Expand Down Expand Up @@ -51,6 +51,6 @@ export
parity_matrix, parity_matrix_x, parity_matrix_z, parity_matrix_xz, code_n, code_k,
# tensor codes
uniformly_random_code_checkmatrix, dual_code, good_css,
normal_cayley_subset, GeneralizedQuantumTannerCode
normal_cayley_subset, GeneralizedQuantumTannerCode, find_random_generating_sets

end #module
171 changes: 171 additions & 0 deletions src/quantum_tanner_codes.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,174 @@
"""
Generate a pair of symmetric generating sets for group G of sizes δ_A and δ_B.

Returns a pair of symmetric generating sets (A, B) that generate G and satisfy the non-conjugacy condition.

Both A and B are symmetric (closed under inversion), the union A ∪ B generates G, A and B are disjoint,
and the pair (A, B) satisfies the total non-conjugacy condition: for all a ∈ A, b ∈ B, g ∈ G, a ≠ gbg⁻¹.

```jldoctest examples
julia> using QuantumExpanders; using Oscar; using Random;

julia> G = symmetric_group(4);

julia> rng = MersenneTwister(68);

julia> A, B = find_random_generating_sets(G, 3, 2; rng=deepcopy(rng))
2-element Vector{Vector{PermGroupElem}}:
[(1,3)(2,4), (1,2,4,3), (1,3,4,2)]
[(2,4), (2,3)]

julia> A, B = find_random_generating_sets(G, 3; rng=deepcopy(rng))
2-element Vector{Vector{PermGroupElem}}:
[(1,2,4,3), (1,3,4,2), (1,4)(2,3)]
[(1,4,3), (1,3,4), (1,2)]
```

Here is a new `[[108, 11, 6]]` quantum Tanner code generated using these symmetric generating sets, A and B, as follows:

```jldoctest examples
julia> H_A = [1 0 1; 1 1 0];

julia> G_A = [1 1 1];

julia> H_B = [1 1 1; 1 1 0];

julia> G_B = [1 1 0];

julia> classical_code_pair = ((H_A, G_A), (H_B, G_B));

julia> c = QuantumTannerCode(G, A, B, classical_code_pair);

julia> code_n(c), code_k(c)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
(108, 11)

julia> import JuMP; import HiGHS;

julia> distance(c, DistanceMIPAlgorithm(solver=HiGHS))
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
[ Info: Left-right Cayley complex Γ(G,A,B) square enumeration complete
[ Info: Group order |G| = 24, |A| = 3, |B| = 3
[ Info: Physical qubits: 108
[ Info: Left-right Cayley complex Γ(G,A,B): enumerated 108 faces placed on 4-cycles {gᵢ, (a·g)ⱼ, (g·b)ⱼ, (a·g·b)ᵢ} where i,j ∈ {0,1}, i≠j [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₀ vertices (Z-type stabilizers) [radebold2025explicit](@cite)
[ Info: Squares incident to vertices: 216 at V₁ vertices (X-type stabilizers) [radebold2025explicit](@cite)
6
```

### Arguments
- `G`: A finite group
- `δ_A`: The size of the first symmetric generating set
- `δ_B`: The size of the second symmetric generating set (defaults to δ_A)
"""
function find_random_generating_sets(G::Group, δ_A::Int, δ_B::Int=δ_A; rng::AbstractRNG=GLOBAL_RNG)
elems = collect(G)
non_identity = [g for g in elems if g != one(G)]
ord2 = [g for g in non_identity if order(g) == 2]
pairs = []
used = Set{elem_type(G)}()
for g in non_identity
if order(g) > 2 && !(g in used)
inv_g = inv(g)
if g != inv_g
push!(pairs, (g, inv_g))
push!(used, g, inv_g)
end
end
end
total_symmetric_elements = length(ord2)+2*length(pairs)
if δ_A+δ_B > total_symmetric_elements
@info "Requested δ_A=$δ_A and δ_B=$δ_B require $((δ_A + δ_B)) symmetric elements, but only $total_symmetric_elements available"
return false
end
for attempt in 1:10000
A = elem_type(G)[]
B = elem_type(G)[]
shuffled = shuffle(rng, elems)
for elem in shuffled
elem == one(G) && continue
if order(elem) == 2
if !(elem in A) && !(elem in B) && length(A) < δ_A
push!(A, elem)
elseif !(elem in A) && !(elem in B) && length(B) < δ_B
push!(B, elem)
end
else
inv_elem = inv(elem)
if elem != inv_elem
if !(elem in A) && !(elem in B) && !(inv_elem in A) && !(inv_elem in B) &&
length(A) < δ_A-1
push!(A, elem, inv_elem)
elseif !(elem in A) && !(elem in B) && !(inv_elem in A) && !(inv_elem in B) &&
length(B) < δ_B-1
push!(B, elem, inv_elem)
end
end
end
if length(A) == δ_A && length(B) == δ_B
break
end
end
if length(A) == δ_A && length(B) == δ_B
if is_symmetric_gen(A) &&
is_symmetric_gen(B) && isempty(intersect(Set(A), Set(B))) && is_nonconjugate(G, A, B)
all_gens = vcat(A, B)
H, emb = sub(G, all_gens)
if order(H) == order(G)
return [A, B]
end
end
end
end
return false
end

"""
Generate a pair of random classical codes (C_A, C_B) for quantum Tanner code construction [radebold2025explicit](@cite)

Expand Down
17 changes: 17 additions & 0 deletions test/test_quantum_tanner_codes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -697,4 +697,21 @@
@test code_k(c) == 96
@test distance(c, DistanceMIPAlgorithm(solver=HiGHS, time_limit=120)) == 5
end

@testset "Random Symmetric Generating Tests" begin
for seed in 1:50
for o in 4:5
G = symmetric_group(o)
rng = MersenneTwister(seed)
A, B = find_random_generating_sets(G, 3; rng=deepcopy(rng))
H_A = [1 0 1; 1 1 0]
G_A = [1 1 1]
H_B = [1 1 1; 1 1 0]
G_B = [1 1 0]
classical_code_pair = ((H_A, G_A), (H_B, G_B))
c = QuantumTannerCode(G, A, B, classical_code_pair)
@test stab_looks_good(parity_checks(c), remove_redundant_rows=true)
end
end
end
end
Loading