Skip to content
2 changes: 1 addition & 1 deletion ext/QuantumCliffordGPUExt/fastmemlayout.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ TableauAdj is the type of Tableau with its data stored in an adjoint of a CUDA a
rest of the fastrow, fastcolumn functions are implemented in QuantumClifford.jl
"""

# todo when we use to_gpu, to_cpu the efffect of fastrow, fastcolumn disappears
# todo when we use to_gpu, to_cpu the effect of fastrow, fastcolumn disappears
fastrow(t::TableauCUDA) = t
fastrow(t::TableauAdj) = Tableau(t.phases, t.nqubits, CuArray(t.xzs))
fastcolumn(t::TableauCUDA) = Tableau(t.phases, t.nqubits, CuArray(t.xzs')')
Expand Down
4 changes: 3 additions & 1 deletion ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import Oscar: free_group, small_group_identification, describe, order, FPGroupEl
base_ring, ComplexOfMorphisms, coefficients, zero_matrix, hcat, circshift, size, zeros, enumerate,
kronecker_product, FqMatrix, identity_matrix, iszero, FqPolyRingElem, laurent_polynomial_ring,
hnf_with_transform, ideal, intersect, ==, is_coprime, quo, groebner_basis, length, FqMPolyRingElem,
first, length, MPolyQuoRingElem, FqMPolyRingElem, modulus, ideal, monomials, terms, coeff, degree, mod
first, MPolyQuoRingElem, FqMPolyRingElem, modulus, ideal, monomials, terms, coeff, degree, mod,
monomial, exponent_vector, nvars
import Oscar.Generic.MatSpaceElem
import Oscar.Generic.DirectSumModule
import Oscar.Generic.LaurentMPolyWrap
Expand All @@ -37,6 +38,7 @@ export twobga_from_direct_product, twobga_from_fp_group, DDimensionalSurfaceCode

include("types.jl")
include("direct_product.jl")
include("bivariate_bicycle.jl")
include("generalized_toric.jl")
include("group_presentation.jl")
include("d_dimensional_codes.jl")
Expand Down
182 changes: 182 additions & 0 deletions ext/QuantumCliffordOscarExt/bivariate_bicycle.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
"""
$TYPEDEF

Bivariate Bicycle codes are CSS codes constructed using the *quotient ring*
``R = \\mathbb{F}_2[x, y] / \\langle x^\\ell - 1, y^m - 1 \\rangle``.

There is an injective ring homomorphism from ``R`` to ``\\mathbb{F}_2^{\\ell m \\times \\ell m}``
given by ``x \\mapsto S_\\ell \\otimes I_m`` and ``y \\mapsto I_k \\otimes S_m``,
where ``S_k`` is the cyclic shift matrix of size ``k \\times k`` [eberhardt2024logical](@cite).

This homomorphism allows us to work with either the polynomial quotient ring
or explicit circulant matrix formulation. We implement the polynomial quotient ring formalism.

#### Examples

Here is the `[[54, 8, 6]]` from Table 1 [wang2024coprime](@cite)

```jldoctest
julia> using Oscar; using QuantumClifford.ECC;

julia> l=3; m=9;

julia> R, (x, y) = polynomial_ring(GF(2), [:x, :y]);

julia> I = ideal(R, [x^l-1, y^m-1]);

julia> S, _ = quo(R, I);

julia> A = S(1 + y^2 + y^4);

julia> B = S(y^3 + x + x^2);

julia> c = BivariateBicycleCode(l, m, A, B);

julia> code_n(c), code_k(c)
(54, 8)
```

Here is the `[[72, 12, 6]]` from Table 3 of [bravyi2024high](@cite)

```jldoctest
julia> using Oscar; using QuantumClifford.ECC;

julia> l=6; m=6;

julia> R, (x, y) = polynomial_ring(GF(2), [:x, :y]);

julia> I = ideal(R, [x^l-1, y^m-1]);

julia> S, _ = quo(R, I);

julia> A = S(x^3 + y + y^2);

julia> B = S(y^3 + x + x^2);

julia> c = BivariateBicycleCode(l, m, A, B);

julia> code_n(c), code_k(c)
(72, 12)
```

Here is the `[[756, 16, ≤ 34]]` from Table 3 of [bravyi2024high](@cite)

```jldoctest
julia> using Oscar; using QuantumClifford.ECC;

julia> l=21; m=18;

julia> R, (x, y) = polynomial_ring(GF(2), [:x, :y]);

julia> I = ideal(R, [x^l-1, y^m-1]);

julia> S, _ = quo(R, I);

julia> A = S(x^3 + y^10 + y^17);

julia> B = S(y^5 + x^3 + x^19);

julia> c = BivariateBicycleCode(l, m, A, B);

julia> code_n(c), code_k(c)
(756, 16)
```

Here is the `[[128, 14, 12]]` from Table 1 [eberhardt2024logical](@cite)

```jldoctest
julia> using Oscar; using QuantumClifford.ECC;

julia> l=8; m=8;

julia> R, (x, y) = polynomial_ring(GF(2), [:x, :y]);

julia> I = ideal(R, [x^l-1, y^m-1]);

julia> S, _ = quo(R, I);

julia> A = S(x^2 + y + y^3 + y^4);

julia> B = S(y^2 + x + x^3 + x^4);

julia> c = BivariateBicycleCode(l, m, A, B);

julia> code_n(c), code_k(c)
(128, 14)
```

See also: [`GeneralizedCirculantBivariateBicycle`](@ref)

### Fields
$TYPEDFIELDS
"""
struct BivariateBicycleCode <: AbstractCSSCode
"""Order of the first abelian group in ``\\mathbb{F}_2[\\mathbb{Z}_\\ell \\times \\mathbb{Z}_m]``"""
ℓ::Int
"""Order of the second abelian group in ``\\mathbb{F}_2[\\mathbb{Z}_\\ell \\times \\mathbb{Z}_m]``"""
m::Int
"""First bivariate polynomial in quotient ring ``\\frac{\\mathbb{F}_2[x, y]}{\\langle x^\\ell-1, y^m-1 \\rangle}``"""
c::MPolyQuoRingElem
"""Second bivariate polynomial in quotient ring ``\\frac{\\mathbb{F}_2[x, y]}{\\langle x^\\ell-1, y^m-1 \\rangle}``"""
d::MPolyQuoRingElem

function BivariateBicycleCode(ℓ::Int, m::Int, c::MPolyQuoRingElem, d::MPolyQuoRingElem)
ℓ > 0 || throw(ArgumentError("ℓ must be positive"))
m > 0 || throw(ArgumentError("m must be positive"))
parent(c) == parent(d) || throw(ArgumentError("Polynomials must be in the same quotient ring"))
Q = parent(c)
R = base_ring(Q)
base_ring(R) == GF(2) || throw(ArgumentError("Base ring must be GF(2)"))
nvars(R) == 2 || throw(ArgumentError("Must be bivariate polynomials"))
new(ℓ, m, c, d)
end
end

function _poly_to_coeff_mat(poly::MPolyQuoRingElem, ℓ::Int, m::Int)
mat = zeros(Int, ℓ, m)
for term in terms(lift(poly))
coeffᵥₐₗ = coeff(term, 1)
coeffᵢₙₜ = iszero(coeffᵥₐₗ) ? 0 : 1
monom = monomial(term, 1)
exps = exponent_vector(monom, 1)
i = length(exps) >= 1 ? exps[1] : 0
j = length(exps) >= 2 ? exps[2] : 0
i = mod(i, ℓ)
j = mod(j, m)
if i < ℓ && j < m
mat[i+1, j+1] = coeffᵢₙₜ
end
end
return mat
end

function _bivariate_circulant(coeff_mat::Matrix{Int})
ℓ, m = size(coeff_mat)
n = ℓ*m
circ_mat = zeros(Int, n, n)
for i₁ in 0:ℓ-1, j₁ in 0:m-1
row_idx = i₁*m+j₁+1
for i₂ in 0:ℓ-1, j₂ in 0:m-1
i_mod = mod(i₁+i₂, ℓ)
j_mod = mod(j₁+j₂, m)
col_idx = i_mod*m+j_mod+1
circ_mat[row_idx, col_idx] += coeff_mat[i₂+1, j₂+1]
end
end
return circ_mat
end

function parity_matrix_xz(c::BivariateBicycleCode)
A_coeff = _poly_to_coeff_mat(c.c, c.ℓ, c.m)
B_coeff = _poly_to_coeff_mat(c.d, c.ℓ, c.m)
A = _bivariate_circulant(A_coeff)
B = _bivariate_circulant(B_coeff)
hx, hz = hcat(A, B), hcat(transpose(B), transpose(A))
return hx, hz
end

parity_matrix_x(c::BivariateBicycleCode) = parity_matrix_xz(c)[1]

parity_matrix_z(c::BivariateBicycleCode) = parity_matrix_xz(c)[2]

code_n(c::BivariateBicycleCode) = 2*c.ℓ*c.m
2 changes: 1 addition & 1 deletion src/ecc/ECC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export parity_checks, parity_matrix_x, parity_matrix_z, iscss,
GeneralizedCirculantBivariateBicycle, GeneralizedHyperGraphProductCode,
GeneralizedBicycleCode, ExtendedGeneralizedBicycleCode,
HomologicalProductCode, DoubleHomologicalProductCode,
GeneralizedToricCode, TrivariateTricycleCode,
GeneralizedToricCode, TrivariateTricycleCode, BivariateBicycleCode,
evaluate_decoder,
CommutationCheckECCSetup, NaiveSyndromeECCSetup, ShorSyndromeECCSetup,
TableDecoder,
Expand Down
2 changes: 1 addition & 1 deletion src/ecc/codes/concat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function parity_checks(c::Concat)
phases_logx₁ = phases(logx_ops(c₁))
h_logz₁ = stab_to_gf2(logz_ops(c₁))
phases_logz₁ = phases(logz_ops(c₁))
# parity checks of c₂ with qubits repalced with logical qubits of c₁
# parity checks of c₂ with qubits replaced with logical qubits of c₁
outer_check_h = transpose(hcat([vcat(
kron(h₂[i, 1:end÷2], h_logx₁[j, 1:end÷2]) .⊻ kron(h₂[i, end÷2+1:end], h_logz₁[j, 1:end÷2]), # X part
kron(h₂[i, 1:end÷2], h_logx₁[j, end÷2+1:end]) .⊻ kron(h₂[i, end÷2+1:end], h_logz₁[j, end÷2+1:end]) # Z part
Expand Down
10 changes: 10 additions & 0 deletions src/ecc/codes/qeccs_using_oscar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,13 @@ function TrivariateTricycleCode(args...; kwargs...)
end
return ext.TrivariateTricycleCode(args...; kwargs...)
end

"""Bivariate Bicycle codes ([jacob2025singleshotdecodingfaulttolerantgates](@cite))
Implemented as a package extension with `Oscar`. Check the [QuantumClifford documentation](http://qc.quantumsavory.org/stable/ECC_API/) for more details on that extension."""
function BivariateBicycleCode(args...; kwargs...)
ext = Base.get_extension(QuantumClifford, :QuantumCliffordOscarExt)
if isnothing(ext)
throw("The `BivariateBicycleCode` depends on the package `Oscar` but you have not installed or imported it yet. Immediately after you import `Oscar`, the `BivariateBicycleCode` will be available.")
end
return ext.BivariateBicycleCode(args...; kwargs...)
end
2 changes: 1 addition & 1 deletion src/randoms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ function _reset!(memory::RandDestabMemory)
end
end

# Allocation free inverse of upper trinagular int matrix with 1 on diagonal.
# Allocation free inverse of upper triangular int matrix with 1 on diagonal.
function _inv!(inverse, A)
for i in 2:size(A, 2)
for j in 1:i-1
Expand Down
2 changes: 1 addition & 1 deletion src/sumtypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ end


##
# `concrete_typeparams` annotations for the parameteric types we care about
# `concrete_typeparams` annotations for the parametric types we care about
##

function concrete_typeparams(t::Type{ClassicalXOR})
Expand Down
44 changes: 43 additions & 1 deletion test/test_ecc_base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -523,13 +523,55 @@ const code_instance_args = Dict(
α1₆ = (0, 3)
α2₆ = (19, 1)

# Bivariate Bicycle codes using polynomial quotient ring
# [[72, 12, 6]]
l_bb₁=6; m_bb₁=6
R_bb₁, (x, y) = polynomial_ring(GF(2), [:x, :y])
I_bb₁ = ideal(R_bb₁, [x^l-1, y^m-1])
S_bb₁, _ = quo(R_bb₁, I_bb₁)
A_bb₁ = S_bb₁(x^3 + y + y^2)
B_bb₁ = S_bb₁(y^3 + x + x^2)

# [[90, 8, 10]]
l_bb₂=15; m_bb₂=3
R_bb₂, (x, y) = polynomial_ring(GF(2), [:x, :y])
I_bb₂ = ideal(R_bb₂, [x^l-1, y^m-1])
S_bb₂, _ = quo(R_bb₂, I_bb₂)
A_bb₂ = S_bb₂(x^9 + y + y^2)
B_bb₂ = S_bb₂(1 + x^2 + x^7)

# [[108, 8, 10]]
l_bb₃=9; m_bb₃=6
R_bb₃, (x, y) = polynomial_ring(GF(2), [:x, :y])
I_bb₃ = ideal(R_bb₃, [x^l-1, y^m-1])
S_bb₃, _ = quo(R_bb₃, I_bb₃)
A_bb₃ = S_bb₃(x^3 + y + y^2)
B_bb₃ = S_bb₃(y^3 + x + x^2)

# [[54, 8, 6]]
l_bb₄=3; m_bb₄=9
R_bb₄, (x, y) = polynomial_ring(GF(2), [:x, :y])
I_bb₄ = ideal(R_bb₄, [x^l-1, y^m-1])
S_bb₄, _ = quo(R_bb₄, I_bb₄)
A_bb₄ = S_bb₄(1 + y^2 + y^4)
B_bb₄ = S_bb₄(y^3 + x + x^2)

# [[98, 6, 12]]
l_bb₅=7; m_bb₅=7
R_bb₅, (x, y) = polynomial_ring(GF(2), [:x, :y])
I_bb₅ = ideal(R_bb₅, [x^l-1, y^m-1])
S_bb₅, _ = quo(R_bb₅, I_bb₅)
A_bb₅ = S_bb₅(x^3 + y^5 + y^6)
B_bb₅ = S_bb₅(y^2 + x^3 + x^5)

oscar_code_instance_args = Dict(
:DDimensionalSurfaceCode => [(2, 3), (3, 2), (3, 3), (4, 2)],
:DDimensionalToricCode => [(2, 3), (3, 2), (3, 3), (4, 2)],
:GeneralizedToricCode => [(f₁, g₁, α1₁, α2₁), (f₂, g₂, α1₂, α2₂), (f₃, g₃, α1₃, α2₃), (f₄, g₄, α1₄, α2₄), (f₅, g₅, α1₅, α2₅), (f₆, g₆, α1₆, α2₆)],
:HomologicalProductCode => [([H₁, transpose(H₁)], l₁), ([H₂, transpose(H₂)], l₂), ([H₃, transpose(H₃)],), ([δ₄, δ₄, δ₄],)],
:DoubleHomologicalProductCode => [(δ₁,), (δ₂,)],
:TrivariateTricycleCode => [(ℓ₁, m₁, p₁, A₁, B₁, C₁), (ℓ₂, m₂, p₂, A₂, B₂, C₂), (ℓ₃, m₃, p₃, A₃, B₃, C₃), (ℓ₄, m₄, p₄, A₄, B₄, C₄)]
:TrivariateTricycleCode => [(ℓ₁, m₁, p₁, A₁, B₁, C₁), (ℓ₂, m₂, p₂, A₂, B₂, C₂), (ℓ₃, m₃, p₃, A₃, B₃, C₃), (ℓ₄, m₄, p₄, A₄, B₄, C₄)],
:BivariateBicycleCode => [(l_bb₁, m_bb₁, A_bb₁, B_bb₁), (l_bb₂, m_bb₂, A_bb₂, B_bb₂), (l_bb₃, m_bb₃, A_bb₃, B_bb₃), (l_bb₄, m_bb₄, A_bb₄, B_bb₄), (l_bb₅, m_bb₅, A_bb₅, B_bb₅)]
)
merge!(code_instance_args, oscar_code_instance_args)
end
Expand Down
Loading
Loading