Full ECC API (autogenerated)

QuantumClifford.ECC.CSSType

An arbitrary CSS error correcting code defined by its X and Z checks.

julia> CSS([0 1 1 0; 1 1 0 0], [1 1 1 1]) |> parity_checks
+ _XX_
+ XX__
+ ZZZZ
source
QuantumClifford.ECC.ConcatType

Concat(c₁, c₂) is a code concatenation of two quantum codes (Knill and Laflamme, 1996).

The inner code c₁ and the outer code c₂. The construction is the following: replace each qubit in code c₂ with logical qubits encoded by code c₁. The resulting code will have n = n₁ × n₂ qubits and k = k₁ × k₂ logical qubits.

source
QuantumClifford.ECC.QuantumReedMullerType

The family of [[2ᵐ - 1, 1, 3]] CSS Quantum-Reed-Muller codes, as discovered by Steane in his 1999 paper (Steane, 1999).

Quantum codes are constructed from shortened Reed-Muller codes RM(1, m), by removing the first row and column of the generator matrix Gₘ. Similarly, we can define truncated dual codes RM(m - 2, m) using the generator matrix Hₘ (Anderson et al., 2014). The quantum Reed-Muller codes QRM(m) derived from RM(1, m) are CSS codes.

Given that the stabilizers of the quantum code are defined through the generator matrix of the classical code, the minimum distance of the quantum code corresponds to the minimum distance of the dual classical code, which is d = 3, thus it can correct any single qubit error. Since one stabilizer from the original and one from the dual code are removed in the truncation process, the code parameters are [[2ᵐ - 1, 1, 3]].

You might be interested in consulting (Anderson et al., 2014) and (Campbell et al., 2012) as well.

The ECC Zoo has an entry for this family.

source
QuantumClifford.ECC.ShorSyndromeECCSetupType

Configuration for ECC evaluators that simulate the Shor-style syndrome measurement (without a flag qubit).

The simulated circuit includes:

  • perfect noiseless encoding (encoding and its fault tolerance are not being studied here)
  • one round of "memory noise" after the encoding but before the syndrome measurement
  • perfect preparation of entangled ancillary qubits
  • noisy Shor-style syndrome measurement (only two-qubit gate noise)
  • noiseless "logical state measurement" (providing the comparison data when evaluating the decoder)

See also: CommutationCheckECCSetup, NaiveSyndromeECCSetup

source
QuantumClifford.ECC.SurfaceType

The planar surface code refers to the code (Kitaev, 2003) in a 2D lattice with open boundaries.

Illustration of a 3×2 surface code, where qubits are located on the edges:

|---1--(Z)--2---|---3---|
|  (X)  7       8       o
|---4---|---5---|---6---|
|       o       o       o
|       |       |       |

The surface code has open boundary conditions, unlike the toric code. To this end, we remove qubits (denoted by "o") and parity checks on the right and bottom sides.

Faces like (1,4,7) have X checks, and crosses like (1,2,7) have Z checks. Due to the removal of the bottom and right sides, we have some 3-qubit checks on the boundaries.

julia> parity_checks(Surface(3,2))
+ X__X__X_
+ _X__X_XX
+ __X__X_X
+ ZZ____Z_
+ _ZZ____Z
+ ___ZZ_Z_
+ ____ZZ_Z

More information can be seen in (Fowler et al., 2012).

source
QuantumClifford.ECC.TableDecoderType

A simple look-up table decoder for error correcting codes.

The lookup table contains only weight=1 errors, thus it is small, but at best it provides only for distance=3 decoding.

The size of the lookup table would grow exponentially quickly for higher distances.

source
QuantumClifford.ECC.ToricType

The Toric code (Kitaev, 2003).

Illustration of a 2x2 toric code, where qubits are located on the edges:

|--1-(Z)-2--|
| (X) 5     6
|--3--|--4--|
|     7     8
|     |     |

It is important to note that the toric code has periodic boundary conditions, which means that the top and bottom sides are essentially glued together, as are the left and right sides.

Faces like (1,3,5,6) have X checks, and crosses like (1,2,5,7) have Z checks.

julia> parity_checks(Toric(2,2))
+ X_X_XX__
+ _X_XXX__
+ X_X___XX
+ ZZ__Z_Z_
+ ZZ___Z_Z
+ __ZZZ_Z_
source
QuantumClifford.ECC.code_kMethod

The number of logical qubits in a code.

Note that when redundant rows exist in the parity check matrix, the number of logical qubits code_k(c) will be greater than code_n(c) - code_s(c), where the difference equals the redundancy.

source
QuantumClifford.ECC.code_sFunction

The number of stabilizer checks in a code. They might not be all linearly independent, thus code_s >= code_n-code_k. For the number of linearly independent checks you can use LinearAlgebra.rank.

source
QuantumClifford.ECC.evaluate_decoderMethod

Evaluate the performance of an error-correcting circuit.

This method requires you give the circuit that performs both syndrome measurements and (probably noiseless) logical state measurements. The faults matrix that translates an error vector into corresponding logical errors is necessary as well.

This is a relatively barebones method that assumes the user prepares necessary circuits, etc. It is a method that is used internally by more user-frienly methods providing automatic conversion of codes and noise models to the necessary noisy circuits.

source
QuantumClifford.ECC.faults_matrixMethod

Error-to-logical-observable map (a.k.a. fault matrix) of a code.

For a code with n physical qubits and k logical qubits this function returns a 2k × 2n binary matrix O such that O[i,j] is true if the logical observable of index i is flipped by the single physical qubit error of index j. Indexing is such that:

  • O[1:k,:] is the error-to-logical-X-observable map (logical X observable, i.e. triggered by logical Z errors)
  • O[k+1:2k,:] is the error-to-logical-Z-observable map
  • O[:,1:n] is the X-physical-error-to-logical-observable map
  • O[n+1:2n,:] is the Z-physical-error-to-logical-observable map

E.g. for k=1, n=10, then if O[2,5] is true, then the logical Z observable is flipped by a X₅ error; and if O[1,12] is true, then the logical X observable is flipped by a Z₂ error.

Of note is that there is a lot of freedom in choosing the logical operations! A logical operator multiplied by a stabilizer operator is still a logical operator. Similarly there is a different fault matrix for each choice of logical operators. But once the logical operators are picked, the fault matrix is fixed.

Below we show an example that uses the Shor code. While it is not the smallest code, it is a convenient choice to showcase the importance of the fault matrix when dealing with degenerate codes where a correction operation and an error do not need to be the same.

First, consider a single-qubit error, potential correction operations, and their effect on the Shor code:

julia> using QuantumClifford.ECC: faults_matrix, Shor9

julia> state = MixedDestabilizer(Shor9())
𝒟ℯ𝓈𝓉𝒶𝒷━━━━━
+ Z________
+ ___Z_____
+ _X_______
+ __X______
+ ____X____
+ _____X___
+ ______X__
+ _______X_
𝒳ₗ━━━━━━━━━
+ ______XXX
𝒮𝓉𝒶𝒷━━━━━━━
+ XXX___XXX
+ ___XXXXXX
+ ZZ_______
+ Z_Z______
+ ___ZZ____
+ ___Z_Z___
+ ______Z_Z
+ _______ZZ
𝒵ₗ━━━━━━━━━
+ Z__Z____Z

julia> err_Z₁ = single_z(9,1) # the error we will simulate
+ Z________

julia> cor_Z₂ = single_z(9,2) # the correction operation we will perform
+ _Z_______

julia> err_Z₁ * state # observe that one of the syndrome bits is now flipped
𝒟ℯ𝓈𝓉𝒶𝒷━━━━━
+ Z________
+ ___Z_____
+ _X_______
+ __X______
+ ____X____
+ _____X___
+ ______X__
+ _______X_
𝒳ₗ━━━━━━━━━
+ ______XXX
𝒮𝓉𝒶𝒷━━━━━━━
- XXX___XXX
+ ___XXXXXX
+ ZZ_______
+ Z_Z______
+ ___ZZ____
+ ___Z_Z___
+ ______Z_Z
+ _______ZZ
𝒵ₗ━━━━━━━━━
+ Z__Z____Z

julia> cor_Z₂ * err_Z₁ * state # we are back to a good code state
𝒟ℯ𝓈𝓉𝒶𝒷━━━━━
+ Z________
+ ___Z_____
- _X_______
+ __X______
+ ____X____
+ _____X___
+ ______X__
+ _______X_
𝒳ₗ━━━━━━━━━
+ ______XXX
𝒮𝓉𝒶𝒷━━━━━━━
+ XXX___XXX
+ ___XXXXXX
+ ZZ_______
+ Z_Z______
+ ___ZZ____
+ ___Z_Z___
+ ______Z_Z
+ _______ZZ
𝒵ₗ━━━━━━━━━
+ Z__Z____Z

julia> bad_Z₆Z₉ = single_z(9,6) * single_z(9,9) # a different "correction" operation
+ _____Z__Z

julia> bad_Z₆Z₉ * err_Z₁ * state # the syndrome is trivial, but now we have a logical error
𝒟ℯ𝓈𝓉𝒶𝒷━━━━━
+ Z________
+ ___Z_____
+ _X_______
+ __X______
+ ____X____
- _____X___
+ ______X__
+ _______X_
𝒳ₗ━━━━━━━━━
- ______XXX
𝒮𝓉𝒶𝒷━━━━━━━
+ XXX___XXX
+ ___XXXXXX
+ ZZ_______
+ Z_Z______
+ ___ZZ____
+ ___Z_Z___
+ ______Z_Z
+ _______ZZ
𝒵ₗ━━━━━━━━━
+ Z__Z____Z

The success of cor_Z₂ and the failure of bad_Z₆Z₉ can be immediately seen through the fault matrix, as the wrong "correction" does not result in the same logical flips ad the error:

julia> O = faults_matrix(Shor9())
2×18 BitMatrix:
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  1
 1  0  0  1  0  0  0  0  1  0  0  0  0  0  0  0  0  0

julia> O * stab_to_gf2(err_Z₁)
2-element Vector{Int64}:
 0
 0

julia> O * stab_to_gf2(cor_Z₂)
2-element Vector{Int64}:
 0
 0

julia> O * stab_to_gf2(bad_Z₆Z₉)
2-element Vector{Int64}:
 1
 0

While its use in this situation is rather contrived, the fault matrix is incredibly useful when running large scale simulations in which we want a separate fast error sampling process, (e.g. with Pauli frames) and a syndrome decoding process, without coupling between them. We just gather all our syndrome measurement and logical observables from the Pauli frame simulations, and then use them with the fault matrix in the syndrome decoding simulation.

source
QuantumClifford.ECC.isdegenerateFunction

Check if the code is degenerate with respect to a given set of error or with respect to all "up to d physical-qubit" errors (defaulting to d=1).

julia> using QuantumClifford.ECC

julia> isdegenerate(Shor9(), [single_z(9,1), single_z(9,2)])
true

julia> isdegenerate(Shor9(), [single_z(9,1), single_x(9,1)])
false

julia> isdegenerate(Steane7(), 1)
false

julia> isdegenerate(Steane7(), 2)
true
source
QuantumClifford.ECC.naive_encoding_circuitMethod

Encoding physical qubits into a larger logical code.

The initial physical qubits to be encoded have to be at indices n-k+1:n.

Encoding circuits are not fault-tolerant

Encoding circuits are not fault-tolerant, and thus should not be used in practice. Instead, you should measure the stabilizers of the code and the logical observables, thus projecting into the code space (which can be fault-tolerant).

The canonicalization operation performed on the code may permute the qubits (see canonicalize_gott!). That permutation is corrected for with SWAP gates by default (controlled by the undoperm keyword argument).

Based on (Cleve and Gottesman, 1997) and (Gottesman, 1997), however it seems the published algorithm has some errors. Consult the erratum, as well as the more recent (Grassl, 2002) and (Grassl, 2011), and be aware that this implementation also uses H instead of Z gates.

source
QuantumClifford.ECC.naive_syndrome_circuitFunction

Generate the non-fault-tolerant stabilizer measurement cicuit for a given code instance or parity check tableau.

Use the ancillary_index and bit_index arguments to offset where the corresponding part the circuit starts.

Returns the circuit, the number of ancillary qubits that were added, and a list of bit indices that will store the measurement results.

See also: shor_syndrome_circuit

source
QuantumClifford.ECC.shor_syndrome_circuitFunction

Generate the Shor fault-tolerant stabilizer measurement cicuit for a given code instance or parity check tableau.

Use the ancillary_index and bit_index arguments to offset where the corresponding part the circuit starts. Ancillary qubits

Returns:

  • The ancillary cat state preparation circuit.
  • The Shor syndrome measurement circuit.
  • The number of ancillary qubits that were added.
  • The list of bit indices that store the final measurement results.

See also: naive_syndrome_circuit

source

Implemented in an extension requiring Hecke.jl

QuantumCliffordHeckeExt.LPCodeType
struct LPCode <: QuantumClifford.ECC.AbstractECC

Lifted product codes ((Panteleev and Kalachev, 2021), (Panteleev and Kalachev, Jun 2022))

A lifted product code is defined by the hypergraph product of a base matrices A and the conjugate of another base matrix B'. Here, the hypergraph product is taken over a group algebra, of which the base matrices are consisting.

The binary parity check matrix is obtained by applying repr to each element of the matrix resulted from the hypergraph product, which is mathematically a linear map from each group algebra element to a binary matrix.

Constructors

Multiple constructors are available:

  1. Two base matrices of group algebra elements.

  2. Two lifted codes, whose base matrices are for quantum code construction.

  3. Two base matrices of group elements, where each group element will be considered as a group algebra element by assigning a unit coefficient.

  4. Two base matrices of integers, where each integer represent the shift of a cyclic permutation. The order of the cyclic permutation should be specified.

Examples

A [[882, 24, d ≤ 24]] code from Appendix B of (Roffe et al., 2023). We use the 1st constructor to generate the code and check its length and dimension. During the construction, we do arithmetic operations to get the group algebra elements in base matrices A and B. Here x is the generator of the group algebra, i.e., offset-1 cyclic permutation, and GA(1) is the unit element.

julia> import Hecke: group_algebra, GF, abelian_group, gens; import LinearAlgebra: diagind;

julia> l = 63; GA = group_algebra(GF(2), abelian_group(l)); x = gens(GA)[];

julia> A = zeros(GA, 7, 7);

julia> A[diagind(A)] .= x^27;

julia> A[diagind(A, -1)] .= x^54;

julia> A[diagind(A, 6)] .= x^54;

julia> A[diagind(A, -2)] .= GA(1);

julia> A[diagind(A, 5)] .= GA(1);

julia> B = reshape([1 + x + x^6], (1, 1));

julia> c1 = LPCode(A, B);

julia> code_n(c1), code_k(c1)
(882, 24)

A [[175, 19, d ≤ 0]] code from Eq. (18) in Appendix A of (Raveendran et al., 2022), following the 4th constructor.

julia> base_matrix = [0 0 0 0; 0 1 2 5; 0 6 3 1]; l = 7;

julia> c2 = LPCode(base_matrix, l .- base_matrix', l);

julia> code_n(c2), code_k(c2)
(175, 19)

Code subfamilies and convenience constructors for them

  • When the base matrices of the LPCode are 1×1, the code is called a two-block group-algebra code two_block_group_algebra_codes.
  • When the base matrices of the LPCode are 1×1 and their elements are sums of cyclic permutations, the code is called a generalized bicycle code generalized_bicycle_codes.
  • When the two matrices are adjoint to each other, the code is called a bicycle code bicycle_codes.

The representation function

We use the default representation function Hecke.representation_matrix to convert a GF(2)-group algebra element to a binary matrix. The default representation, provided by Hecke, is the permutation representation.

We also accept a custom representation function as detailed in LiftedCode.

See also: LiftedCode, two_block_group_algebra_codes, generalized_bicycle_codes, bicycle_codes.

  • A::Union{LinearAlgebra.Adjoint{<:Hecke.GroupAlgebraElem, <:Matrix{<:Hecke.GroupAlgebraElem}}, Matrix{<:Hecke.GroupAlgebraElem}}: the first base matrix of the code, whose elements are in a group algebra.

  • B::Union{LinearAlgebra.Adjoint{<:Hecke.GroupAlgebraElem, <:Matrix{<:Hecke.GroupAlgebraElem}}, Matrix{<:Hecke.GroupAlgebraElem}}: the second base matrix of the code, whose elements are in the same group algebra as A.

  • GA::Hecke.GroupAlgebra: the group algebra for which elements in A and B are from.

  • repr::Function: a function that converts a group algebra element to a binary matrix; default to be the permutation representation for GF(2)-algebra.

source
QuantumCliffordHeckeExt.LiftedCodeType
struct LiftedCode <: QuantumClifford.ECC.ClassicalCode

Classical codes lifted over a group algebra, used for lifted product code construction ((Panteleev and Kalachev, 2021), (Panteleev and Kalachev, Jun 2022))

The parity-check matrix is constructed by applying repr to each element of A, which is mathematically a linear map from a group algebra element to a binary matrix. The size of the parity check matrix will enlarged with each element of A being inflated into a matrix. The procedure is called a lift (Panteleev and Kalachev, Jun 2022).

Constructors

A lifted code can be constructed via the following approaches:

  1. A matrix of group algebra elements.

  2. A matrix of group elements, where a group element will be considered as a group algebra element by assigning a unit coefficient.

  3. A matrix of integers, where each integer represent the shift of a cyclic permutation. The order of the cyclic permutation should be specified.

The default GA is the group algebra of A[1, 1], the default representation repr is the permutation representation.

The representation function repr

We use the default representation function Hecke.representation_matrix to convert a GF(2)-group algebra element to a binary matrix. The default representation, provided by Hecke, is the permutation representation.

We also accept a custom representation function (the repr field of the constructor). Whatever the representation, the matrix elements need to be convertible to Integers (e.g. permit lift(ZZ, ...)). Such a customization would be useful to reduce the number of bits required by the code construction.

For example, if we use a D4 group for lifting, our default representation will be 8×8 permutation matrices, where 8 is the group's order. However, we can find a 4×4 matrix representation for the group, e.g. by using the typical 2×2 representation and converting it into binary representation by replacing "1" with the Pauli I, and "-1" with the Pauli X matrix.

See also: LPCode.

  • A::Union{LinearAlgebra.Adjoint{<:Hecke.GroupAlgebraElem, <:Matrix{<:Hecke.GroupAlgebraElem}}, Matrix{<:Hecke.GroupAlgebraElem}}: the base matrix of the code, whose elements are in a group algebra.

  • GA::Hecke.GroupAlgebra: the group algebra for which elements in A are from.

  • repr::Function: a function that converts a group algebra element to a binary matrix; default to be the permutation representation for GF(2)-algebra.

source
QuantumCliffordHeckeExt.LiftedCodeMethod

LiftedCode constructor using the default GF(2) representation (coefficients converted to a permutation matrix by representation_matrix provided by Hecke).

source
QuantumClifford.ECC.generalized_bicycle_codesMethod

Generalized bicycle codes, which are a special case of 2GBA codes (and therefore of lifted product codes). Here the group is chosen as the cyclic group of order l, and the base matrices a and b are the sum of the group algebra elements corresponding to the shifts a_shifts and b_shifts.

See also: two_block_group_algebra_codes, bicycle_codes.

A [[254, 28, 14 ≤ d ≤ 20]] code from (A1) in Appendix B of (Panteleev and Kalachev, 2021).

julia> c = generalized_bicycle_codes([0, 15, 20, 28, 66], [0, 58, 59, 100, 121], 127);

julia> code_n(c), code_k(c)
(254, 28)
source