Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/src/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -1209,3 +1209,13 @@ @article{dennis2002topological
year={2002},
publisher={American Institute of Physics}
}

@misc{steffan2025tilecodeshighefficiencyquantum,
title={Tile Codes: High-Efficiency Quantum Codes on a Lattice with Boundary},
author={Vincent Steffan and Shin Ho Choe and Nikolas P. Breuckmann and Francisco Revson Fernandes Pereira and Jens Niklas Eberhardt},
year={2025},
eprint={2504.09171},
archivePrefix={arXiv},
primaryClass={quant-ph},
url={https://arxiv.org/abs/2504.09171},
}
3 changes: 2 additions & 1 deletion lib/QECCore/src/QECCore.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export Perfect5, Cleve8, Gottesman
# CSS Codes
export Toric, Bitflip3, Phaseflip3, Shor9, Steane7, Surface, CSS, QuantumReedMuller, Triangular488, Triangular666,
DelfosseReichardt, DelfosseReichardtRep, DelfosseReichardt823, QuantumTannerGraphProduct, CyclicQuantumTannerGraphProduct,
TillichZemor, random_TillichZemor_code, BivariateBicycleViaCirculantMat
TillichZemor, random_TillichZemor_code, BivariateBicycleViaCirculantMat, Tile2D

# Classical Codes
export RepCode, ReedMuller, RecursiveReedMuller, Golay, Hamming, random_Gallager_ldpc, Goppa, random_Goppa_code
Expand Down Expand Up @@ -52,6 +52,7 @@ include("codes/quantum/color_codes.jl")
include("codes/quantum/quantumtannergraphproduct.jl")
include("codes/quantum/tillichzemor.jl")
include("codes/quantum/generalized_circulant_bivariate_bicycle.jl")
include("codes/quantum/tile2d.jl")

# Reed-Muller Codes
include("codes/classical/reedmuller.jl")
Expand Down
128 changes: 128 additions & 0 deletions lib/QECCore/src/codes/quantum/tile2d.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"""
2D Tile is a generalization of surface codes that offers flexibility in terms of locality and stabilizer check weight
without compromising on the 2D locality of the 2D surface code. It encodes more logical qubits than surface code, and
and provides O(1)-locality.

```jldoctest
julia> using QuantumClifford; using QuantumClifford.ECC; # hide

julia> B = 3;

julia> horizX = [(0,0),(2,1),(2,2)];

julia> vertX = [(0,2),(1,2),(2,0)];

julia> Lx, Ly = 10, 10;

julia> c = Tile2D(B, horizX, vertX, Lx, Ly);

julia> code_n(c), code_k(c)
(288, 8)
```
"""
struct Tile2D <: AbstractCSSCode
"""Size of the tile box ``(B \\times B)`` determining the support of a stabilizer."""
B::Int
"""Positions of horizontal edges within the tile box."""
horiz::Vector{Tuple{Int,Int}}
"""Positions of vertical edges within the tile box."""
vert::Vector{Tuple{Int,Int}}
"""Number of tiles along the x-direction."""
Lx::Int
"""Number of tiles along the y-direction."""
Ly::Int

function Tile2D(B::Int, horiz::Vector{Tuple{Int,Int}}, vert::Vector{Tuple{Int,Int}}, Lx::Int, Ly::Int)
new(B, horiz, vert, Lx, Ly)
end
end

function _rectangular_layout(tile::Tile2D)
black = Set{Tuple{Int,Int}}()
red = Set{Tuple{Int,Int}}()
blue = Set{Tuple{Int,Int}}()
B, Lx, Ly = tile.B, tile.Lx, tile.Ly
for x in 0:Lx-1, y in 0:Ly-1
push!(black, (x,y))
end
for x in 0:Lx-1, t in 1:B-1
push!(red, (x, -t))
push!(red, (x, Ly-1+t))
end
for y in 0:Ly-1, t in 1:B-1
push!(blue, (-t, y))
push!(blue, (Lx-1+t, y))
end
return black, red, blue
end

function _complement_tile(tile::Tile2D)
B = tile.B
horiz_z = [(B-1-x, B-1-y) for (x,y) in tile.vert]
vert_z = [(B-1-x, B-1-y) for (x,y) in tile.horiz]
Tile2D(B, horiz_z, vert_z, tile.Lx, tile.Ly)
end

function _physical_qubits(tile::Tile2D)
qubits = Set{Tuple{Symbol,Int,Int}}()
black, _, _ = _rectangular_layout(tile)
for (vx,vy) in black
for x in 0:tile.B-1, y in 0:tile.B-1
push!(qubits, (:h, vx+x, vy+y))
push!(qubits, (:v, vx+x, vy+y))
end
end
return qubits
end


function _edges((vx,vy)::Tuple{Int,Int}, tile::Tile2D)
edges = Tuple{Symbol,Int,Int}[]
for (x,y) in tile.horiz
push!(edges, (:h, vx+x, vy+y))
end
for (x,y) in tile.vert
push!(edges, (:v, vx+x, vy+y))
end
return edges
end

function parity_matrix_xz(tile::Tile2D)
tileZ = _complement_tile(tile)
# "We will always restrict ourselves to (rotated) rectangular shapes" [steffan2025tilecodeshighefficiencyquantum](@cite).
black, red, blue = _rectangular_layout(tile)
physical = _physical_qubits(tile)
Xrows = Vector{Vector{Tuple{Symbol,Int,Int}}}()
Zrows = Vector{Vector{Tuple{Symbol,Int,Int}}}()
# "We fine-tune the layout to the specific support of the stabilizers. First remove
# all qubits that are not supported in any X-type stabilizer or are not supported
# in any Z-type stabilizer" [steffan2025tilecodeshighefficiencyquantum](@cite).
for v in black
push!(Xrows, filter(in(physical), _edges(v, tile)))
push!(Zrows, filter(in(physical), _edges(v, tileZ)))
end
for v in red
push!(Xrows, filter(in(physical), _edges(v, tile)))
end
for v in blue
push!(Zrows, filter(in(physical), _edges(v, tileZ)))
end
# "Finally, we remove all stabilizers whose support has become empty because of aforementioned procedure" [steffan2025tilecodeshighefficiencyquantum](@cite).
filter!(!isempty, Xrows)
filter!(!isempty, Zrows)
qubits = unique(vcat(Xrows..., Zrows...))
qindex = Dict(q => i for (i,q) in enumerate(qubits))
Hx = spzeros(Int, length(Xrows), length(qubits))
Hz = spzeros(Int, length(Zrows), length(qubits))
for (i,row) in enumerate(Xrows), q in row
Hx[i, qindex[q]] = 1
end
for (i,row) in enumerate(Zrows), q in row
Hz[i, qindex[q]] = 1
end
return Hx, Hz
end

parity_matrix_x(tile::Tile2D) = parity_matrix_xz(tile)[1]

parity_matrix_z(tile::Tile2D) = parity_matrix_xz(tile)[2]
66 changes: 66 additions & 0 deletions lib/QECCore/test/codes/tile2d.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
@testitem "Tile 2D" begin
using Test
using Nemo: matrix, GF, rank
using QECCore: Tile2D
using QuantumClifford: stab_looks_good, stab_to_gf2
using QuantumClifford.ECC: parity_checks, code_n, code_k, parity_matrix_x, parity_matrix_z

@testset "Tile 2D" begin
# from table 1 of https://arxiv.org/pdf/2504.09171
table_I = [
(288, 8, 3, [(0,0),(2,1),(2,2)], [(0,2),(1,2),(2,0)], 10, 10), # [[288, 8, 12]]
(288, 8, 3, [(0,0),(2,0),(0,1),(0,2)], [(0,0),(0,2),(1,1),(2,2)], 10, 10), # [[288, 8, 14]]
(288, 18, 4, [(0,0),(0,3),(2,2),(3,0)], [(0,1),(1,0),(1,1),(3,3)], 9, 9), # [[288, 18, 13]]
(512, 18, 4, [(0,0),(0,3),(2,2),(3,0)], [(0,1),(1,0),(1,1),(3,3)], 13, 13)] # [[512, 18, 19]]

for (n, k, B, horiz, vert, Lx, Ly) in table_I
c = Tile2D(B, horiz, vert, Lx, Ly)
stab = parity_checks(c)
nₛ, kₛ = code_n(stab), code_k(stab)
H = stab_to_gf2(stab)
mat = matrix(GF(2), H)
computed_rank = rank(mat)
@test computed_rank == nₛ - kₛ
@test stab_looks_good(stab, remove_redundant_rows=true)
@test computed_rank == n - k && computed_rank == nₛ - kₛ && n == nₛ && k == kₛ
end

# check-weight tests
# From Table I of https://arxiv.org/pdf/2504.09171v1
# [[288, 8, 12]]
B = 3
horizX = [(0,0),(2,1),(2,2)]
vertX = [(0,2),(1,2),(2,0)]
Lx, Ly = 10, 10
c = Tile2D(B, horizX, vertX, Lx, Ly)
@test all(maximum(sum(Matrix(parity_matrix_z(c)), dims=2)) .== 6)
@test all(maximum(sum(Matrix(parity_matrix_x(c)), dims=2)) .== 6)

# [[288, 8, 14]]
B = 3
horizX = [(0,0),(2,0),(0,1),(0,2)]
vertX = [(0,0),(0,2),(1,1),(2,2)]
Lx, Ly = 10, 10
c = Tile2D(B, horizX, vertX, Lx, Ly)
@test all(maximum(sum(Matrix(parity_matrix_z(c)), dims=2)) .== 8)
@test all(maximum(sum(Matrix(parity_matrix_x(c)), dims=2)) .== 8)

# [[288, 18, 13]]
B = 4
horizX = [(0,0),(0,3),(2,2),(3,0)]
vertX = [(0,1),(1,0),(1,1),(3,3)]
Lx, Ly = 9, 9
c = Tile2D(B, horizX, vertX, Lx, Ly)
@test all(maximum(sum(Matrix(parity_matrix_z(c)), dims=2)) .== 8)
@test all(maximum(sum(Matrix(parity_matrix_x(c)), dims=2)) .== 8)

# [[512, 18, 19]]
B = 4
horizX = [(0,0),(0,3),(2,2),(3,0)]
vertX = [(0,1),(1,0),(1,1),(3,3)]
Lx, Ly = 13, 13
c = Tile2D(B, horizX, vertX, Lx, Ly)
@test all(maximum(sum(Matrix(parity_matrix_z(c)), dims=2)) .== 8)
@test all(maximum(sum(Matrix(parity_matrix_x(c)), dims=2)) .== 8)
end
end
4 changes: 4 additions & 0 deletions lib/QECCore/test/test_codes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,8 @@
@testset "Circulant Bivariate Bicycle Codes" begin
include("codes/generalized_circulant_bivariate_bicycle.jl")
end

@testset "Tile 2D" begin
include("codes/tile2d.jl")
end
end
2 changes: 1 addition & 1 deletion src/ecc/ECC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export parity_checks, parity_matrix_x, parity_matrix_z, iscss,
GeneralizedBicycle, ExtendedGeneralizedBicycle,
HomologicalProduct, DoubleHomologicalProduct,
GeneralizedToric, TrivariateTricycle, BivariateBicycleViaPoly,
MultivariateMulticycle,
MultivariateMulticycle, Tile2D,
evaluate_decoder,
CommutationCheckECCSetup, NaiveSyndromeECCSetup, ShorSyndromeECCSetup,
TableDecoder, CSSTableDecoder,
Expand Down
Loading