From 303e216c5026edd3a77070a73a83dc4dfb7a9e0e Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 10:19:19 -0500 Subject: [PATCH 1/8] symmetric generating sets A, B for finitely presented group G for bipartite LRCC --- src/QuantumExpanders.jl | 2 +- src/quantum_tanner_codes.jl | 75 +++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/QuantumExpanders.jl b/src/QuantumExpanders.jl index 069ac09..e009d88 100644 --- a/src/QuantumExpanders.jl +++ b/src/QuantumExpanders.jl @@ -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 diff --git a/src/quantum_tanner_codes.jl b/src/quantum_tanner_codes.jl index 859f5c4..342eec5 100644 --- a/src/quantum_tanner_codes.jl +++ b/src/quantum_tanner_codes.jl @@ -1,3 +1,78 @@ +""" +Generate a pair of symmetric generating sets for group G of sizes δ_A and δ_B. + +Returns a pair of symmetric 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⁻¹. + +### 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::Iny, δ_B::Int=δ_A) + 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(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) From 535bbd0be89196b8892de58c8015a0a20dda12da Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 10:29:16 -0500 Subject: [PATCH 2/8] add doctests --- src/QuantumExpanders.jl | 2 +- src/quantum_tanner_codes.jl | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/QuantumExpanders.jl b/src/QuantumExpanders.jl index e009d88..70e4313 100644 --- a/src/QuantumExpanders.jl +++ b/src/QuantumExpanders.jl @@ -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 diff --git a/src/quantum_tanner_codes.jl b/src/quantum_tanner_codes.jl index 342eec5..f3bf9eb 100644 --- a/src/quantum_tanner_codes.jl +++ b/src/quantum_tanner_codes.jl @@ -6,12 +6,25 @@ Returns a pair of symmetric sets (A, B) that generate G and satisfy the non-conj 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 +julia> using QuantumExpanders; using Oscar; using Random; + +julia> G = symmetric_group(4); + +julia> rng = MersenneTwister(42); + +julia> find_random_generating_sets(G, 3, 2; rng=deepcopy(rng)) +2-element Vector{Vector{PermGroupElem}}: + [(2,4,3), (2,3,4), (2,3)] + [(1,3,4,2), (1,2,4,3)] +``` + ### 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::Iny, δ_B::Int=δ_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] @@ -34,7 +47,7 @@ function find_random_generating_sets(G::Group, δ_A::Iny, δ_B::Int=δ_A) for attempt in 1:10000 A = elem_type(G)[] B = elem_type(G)[] - shuffled = shuffle(elems) + shuffled = shuffle(rng, elems) for elem in shuffled elem == one(G) && continue if order(elem) == 2 From 19415ec955883239e351788f765d78f8ec54b4c4 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 10:32:03 -0500 Subject: [PATCH 3/8] more doctest --- src/quantum_tanner_codes.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/quantum_tanner_codes.jl b/src/quantum_tanner_codes.jl index f3bf9eb..3449645 100644 --- a/src/quantum_tanner_codes.jl +++ b/src/quantum_tanner_codes.jl @@ -17,6 +17,11 @@ julia> find_random_generating_sets(G, 3, 2; rng=deepcopy(rng)) 2-element Vector{Vector{PermGroupElem}}: [(2,4,3), (2,3,4), (2,3)] [(1,3,4,2), (1,2,4,3)] + +julia> find_random_generating_sets(G, 3; rng=deepcopy(rng)) +2-element Vector{Vector{PermGroupElem}}: + [(2,4,3), (2,3,4), (2,3)] + [(1,3,4,2), (1,2,4,3), (1,3)(2,4)] ``` ### Arguments From 740c7d3e4ef02903e79f4431a32ddd60cef2e054 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 11:30:46 -0500 Subject: [PATCH 4/8] showcase quantum Tanner codes constructed from this method in doctests --- src/quantum_tanner_codes.jl | 94 +++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 8 deletions(-) diff --git a/src/quantum_tanner_codes.jl b/src/quantum_tanner_codes.jl index 3449645..4285fca 100644 --- a/src/quantum_tanner_codes.jl +++ b/src/quantum_tanner_codes.jl @@ -6,22 +6,100 @@ Returns a pair of symmetric sets (A, B) that generate G and satisfy the non-conj 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 +```jldoctest examples julia> using QuantumExpanders; using Oscar; using Random; julia> G = symmetric_group(4); -julia> rng = MersenneTwister(42); +julia> rng = MersenneTwister(68); -julia> find_random_generating_sets(G, 3, 2; rng=deepcopy(rng)) +julia> A, B = find_random_generating_sets(G, 3, 2; rng=deepcopy(rng)) 2-element Vector{Vector{PermGroupElem}}: - [(2,4,3), (2,3,4), (2,3)] - [(1,3,4,2), (1,2,4,3)] + [(1,3)(2,4), (1,2,4,3), (1,3,4,2)] + [(2,4), (2,3)] -julia> find_random_generating_sets(G, 3; rng=deepcopy(rng)) +julia> A, B = find_random_generating_sets(G, 3; rng=deepcopy(rng)) 2-element Vector{Vector{PermGroupElem}}: - [(2,4,3), (2,3,4), (2,3)] - [(1,3,4,2), (1,2,4,3), (1,3)(2,4)] + [(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 can now be 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 From 22411cf84d3ab9a56cea24038f9e5dcee43f2624 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 11:31:51 -0500 Subject: [PATCH 5/8] polish --- src/quantum_tanner_codes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quantum_tanner_codes.jl b/src/quantum_tanner_codes.jl index 4285fca..8ff4450 100644 --- a/src/quantum_tanner_codes.jl +++ b/src/quantum_tanner_codes.jl @@ -24,7 +24,7 @@ julia> A, B = find_random_generating_sets(G, 3; rng=deepcopy(rng)) [(1,4,3), (1,3,4), (1,2)] ``` -Here is a new `[[108, 11, 6]]` quantum Tanner code can now be generated using these symmetric generating sets, A and B, as follows: +Here is a new `[[108, 11, 6]]` quantum Tanner code be generated using these symmetric generating sets, A and B, as follows: ```jldoctest examples julia> H_A = [1 0 1; 1 1 0]; From 44036bf5021b2862e324c01df842de4237b85ba2 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 11:46:00 -0500 Subject: [PATCH 6/8] add tests --- test/test_quantum_tanner_codes.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_quantum_tanner_codes.jl b/test/test_quantum_tanner_codes.jl index aeea4cc..dee8813 100644 --- a/test/test_quantum_tanner_codes.jl +++ b/test/test_quantum_tanner_codes.jl @@ -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:100 + for o in 4:6 + 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 From 0a6c22519fdbcf590f7a882b88aea8451ab29552 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 12:52:14 -0500 Subject: [PATCH 7/8] polish doctests --- src/quantum_tanner_codes.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quantum_tanner_codes.jl b/src/quantum_tanner_codes.jl index 8ff4450..dacca90 100644 --- a/src/quantum_tanner_codes.jl +++ b/src/quantum_tanner_codes.jl @@ -1,7 +1,7 @@ """ Generate a pair of symmetric generating sets for group G of sizes δ_A and δ_B. -Returns a pair of symmetric sets (A, B) that generate G and satisfy the non-conjugacy condition. +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⁻¹. @@ -24,7 +24,7 @@ julia> A, B = find_random_generating_sets(G, 3; rng=deepcopy(rng)) [(1,4,3), (1,3,4), (1,2)] ``` -Here is a new `[[108, 11, 6]]` quantum Tanner code be generated using these symmetric generating sets, A and B, as follows: +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]; From a04526bd7773cc43256e900c08b434bcd2036ca9 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 30 Nov 2025 13:53:22 -0500 Subject: [PATCH 8/8] use small instances of QT codes in tests --- test/test_quantum_tanner_codes.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_quantum_tanner_codes.jl b/test/test_quantum_tanner_codes.jl index dee8813..5a34f4e 100644 --- a/test/test_quantum_tanner_codes.jl +++ b/test/test_quantum_tanner_codes.jl @@ -699,8 +699,8 @@ end @testset "Random Symmetric Generating Tests" begin - for seed in 1:100 - for o in 4:6 + 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))