Skip to content

Commit

Permalink
Merge branch 'master' into fa/BBas2BGA
Browse files Browse the repository at this point in the history
  • Loading branch information
Krastanov authored Nov 5, 2024
2 parents a245163 + 40924b8 commit c63864e
Show file tree
Hide file tree
Showing 27 changed files with 814 additions and 166 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ on:
branches: [master, main]
tags: ["*"]
pull_request:

concurrency:
# group by workflow and ref; the last slightly strange component ensures that for pull
# requests, we limit to 1 concurrent job, but for the master branch we don't
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.run_number }}
# Cancel intermediate builds, but only if it is a pull request build.
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}

env:
PYTHON: ~
jobs:
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@

# News

## v0.9.14 - 2024-11-03

- **(fix)** `affectedqubits()` on `sMX`, `sMY`, and `sMR*`
- **(fix)** restrictive type-assert in `MixedDestabilizer` failing on views of tableaux
- Implementing additional named two-qubit gates: `sSQRTXX, sInvSQRTXX, sSQRTYY, sInvSQRTYY`

## v0.9.13 - 2024-10-30

- New error-correction group theory tools:
- `canonicalize_noncomm` function to find a generating set with minimal anticommutivity
- `SubsystemCodeTableau` data structure to represent the output of `canonicalize_noncomm`
- `commutify` function to find a commutative version of a non-commutative set of Paulis with minimal changes
- `matroid_parent` to, for set of Paulis that doesn't represent a state, find a version
that does.
- Implementing additional named two-qubit gates: `sSWAPCX, sInvSWAPCX, sCZSWAP, sCXSWAP, sISWAP, sInvISWAP, sSQRTZZ, sInvSQRTZZ`

## v0.9.12 - 2024-10-18

- Minor compat fixes for julia 1.11 in the handling of `hgp`
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "QuantumClifford"
uuid = "0525e862-1e90-11e9-3e4d-1b39d7109de1"
authors = ["Stefan Krastanov <[email protected]> and QuantumSavory community members"]
version = "0.9.12"
version = "0.9.14"

[deps]
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
Expand Down Expand Up @@ -50,7 +50,7 @@ DocStringExtensions = "0.9"
Graphs = "1.9"
Hecke = "0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34"
HostCPUFeatures = "0.1.6"
ILog2 = "0.2.3"
ILog2 = "0.2.3, 1, 2"
InteractiveUtils = "1.9"
LDPCDecoders = "0.3.1"
LinearAlgebra = "1.9"
Expand Down
6 changes: 3 additions & 3 deletions docs/src/noisycircuits_mc.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Import with `using QuantumClifford.Experimental.NoisyCircuits`.

This module enables the simulation of noisy Clifford circuits through a Monte Carlo method where the same circuit is evaluated multiple times with random errors interspersed through it as prescribed by a given error model.

Below is an example of a purification circuit. We first prepare the circuit we desire to use, including a noise model. `Quantikz.jl` was is used to visualize the circuit.
Below is an example of a purification circuit. We first prepare the circuit we desire to use, including a noise model. `Quantikz.jl` is used to visualize the circuit.

```@example 1
using QuantumClifford # hide
Expand Down Expand Up @@ -55,8 +55,8 @@ If you want to create a custom gate type (e.g. calling it `Operation`), you need
The `Symbol` is the status of the operation. Predefined statuses are kept in the `registered_statuses` list, but you can add more.
Be sure to expand this list if you want the trajectory simulators using your custom statuses to output all trajectories.

There is also [`applynoise!`](@ref) which is convenient wait to create a noise model that can then be plugged into the [`NoisyGate`](@ref) struct,
There is also [`applynoise!`](@ref) which is a convenient way to create a noise model that can then be plugged into the [`NoisyGate`](@ref) struct,
letting you reuse the predefined perfect gates and measurements.
However, you can also just make up your own noise operator simply by implementing [`applywstatus!`](@ref) for it.

You can also consult the [list of implemented operators](@ref noisycircuits_ops).
You can also consult the [list of implemented operators](@ref noisycircuits_ops).
35 changes: 35 additions & 0 deletions docs/src/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,31 @@ @inproceedings{brown2013short
doi = {10.1109/ISIT.2013.6620245}
}

@article{RevModPhys.87.307,
title = {Quantum error correction for quantum memories},
author = {Terhal, Barbara M.},
journal = {Rev. Mod. Phys.},
volume = {87},
issue = {2},
pages = {307--346},
numpages = {40},
year = {2015},
month = {Apr},
publisher = {American Physical Society},
doi = {10.1103/RevModPhys.87.307},
url = {https://link.aps.org/doi/10.1103/RevModPhys.87.307}
}

@misc{goodenough2024bipartiteentanglementnoisystabilizer,
title={Bipartite entanglement of noisy stabilizer states through the lens of stabilizer codes},
author={Kenneth Goodenough and Aqil Sajjad and Eneet Kaur and Saikat Guha and Don Towsley},
year={2024},
eprint={2406.02427},
archivePrefix={arXiv},
primaryClass={quant-ph},
url={https://arxiv.org/abs/2406.02427},
}

@article{panteleev2021degenerate,
title = {Degenerate {{Quantum LDPC Codes With Good Finite Length Performance}}},
author = {Panteleev, Pavel and Kalachev, Gleb},
Expand Down Expand Up @@ -497,4 +522,14 @@ @article{bravyi2024high
pages={778--782},
year={2024},
publisher={Nature Publishing Group UK London}

@article{lin2024quantum,
title={Quantum two-block group algebra codes},
author={Lin, Hsiang-Ku and Pryadko, Leonid P},
journal={Physical Review A},
volume={109},
number={2},
pages={022407},
year={2024},
publisher={APS}
}
11 changes: 3 additions & 8 deletions ext/QuantumCliffordGPUExt/apply_noise.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
using QuantumClifford: _div, _mod
using QuantumClifford: get_bitmask_idxs

#according to https://github.com/JuliaGPU/CUDA.jl/blob/ac1bc29a118e7be56d9edb084a4dea4224c1d707/test/core/device/random.jl#L33
#CUDA.jl supports calling rand() inside kernel
function applynoise!(frame::PauliFrameGPU{T},noise::UnbiasedUncorrelatedNoise,i::Int) where {T <: Unsigned}
p = noise.p
lowbit = T(1)
ibig = _div(T,i-1)+1
ismall = _mod(T,i-1)
ismallm = lowbit<<(ismall)

stab = frame.frame
xzs = tab(stab).xzs
xzs = tab(frame.frame).xzs
lowbit, ibig, ismall, ismallm = get_bitmask_idxs(xzs,i)
rows = size(stab, 1)

@run_cuda applynoise_kernel(xzs, p, ibig, ismallm, rows) rows
Expand Down
12 changes: 4 additions & 8 deletions ext/QuantumCliffordGPUExt/pauli_frames.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using QuantumClifford: get_bitmask_idxs

##############################
# sMZ
##############################
Expand All @@ -21,10 +23,7 @@ function apply!(frame::PauliFrameGPU{T}, op::QuantumClifford.sMZ) where {T <: Un
op.bit == 0 && return frame
i = op.qubit
xzs = frame.frame.tab.xzs
lowbit = T(1)
ibig = QuantumClifford._div(T,i-1)+1
ismall = QuantumClifford._mod(T,i-1)
ismallm = lowbit<<(ismall)
lowbit, ibig, ismall, ismallm = get_bitmask_idxs(xzs,i)
(@run_cuda apply_sMZ_kernel!(xzs, frame.measurements, op, ibig, ismallm, length(frame)) length(frame))
return frame
end
Expand Down Expand Up @@ -55,10 +54,7 @@ end
function apply!(frame::PauliFrameGPU{T}, op::QuantumClifford.sMRZ) where {T <: Unsigned} # TODO sMRX, sMRY
i = op.qubit
xzs = frame.frame.tab.xzs
lowbit = T(1)
ibig = QuantumClifford._div(T,i-1)+1
ismall = QuantumClifford._mod(T,i-1)
ismallm = lowbit<<(ismall)
lowbit, ibig, ismall, ismallm = get_bitmask_idxs(xzs,i)
(@run_cuda apply_sMRZ_kernel!(xzs, frame.measurements, op, ibig, ismallm, length(frame)) length(frame))
return frame
end
6 changes: 4 additions & 2 deletions ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ using DocStringExtensions
import QuantumClifford, LinearAlgebra
import Hecke: Group, GroupElem, AdditiveGroup, AdditiveGroupElem,
GroupAlgebra, GroupAlgebraElem, FqFieldElem, representation_matrix, dim, base_ring,
multiplication_table, coefficients, abelian_group, group_algebra,
multiplication_table, coefficients, abelian_group, group_algebra, rand,
FinGenAbGroup, FinGenAbGroupElem, one
import Nemo
import Nemo: characteristic, matrix_repr, GF, ZZ, lift

import QuantumClifford.ECC: AbstractECC, CSS, ClassicalCode,
hgp, code_k, code_n, code_s, iscss, parity_checks, parity_checks_x, parity_checks_z, parity_checks_xz,
two_block_group_algebra_codes, generalized_bicycle_codes, bicycle_codes, bivariate_bicycle_codes
two_block_group_algebra_codes, generalized_bicycle_codes, bicycle_codes, bivariate_bicycle_codes,
check_repr_commutation_relation

include("util.jl")
include("types.jl")
include("lifted.jl")
include("lifted_product.jl")
Expand Down
28 changes: 24 additions & 4 deletions ext/QuantumCliffordHeckeExt/lifted_product.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,32 @@ code_s(c::LPCode) = size(c.repr(zero(c.GA)), 1) * (size(c.A, 1) * size(c.B, 1) +
Two-block group algebra (2GBA) codes, which are a special case of lifted product codes
from two group algebra elements `a` and `b`, used as `1x1` base matrices.
Here is an example of a [[56, 28, 2]] 2BGA code from Table 2 of [lin2024quantum](@cite)
with direct product of `C₄ x C₂`.
```jldoctest
julia> import Hecke: group_algebra, GF, abelian_group, gens;
julia> GA = group_algebra(GF(2), abelian_group([14,2]));
julia> x = gens(GA)[1];
julia> s = gens(GA)[2];
julia> A = 1 + x^7
julia> B = 1 + x^7 + s + x^8 + s*x^7 + x
julia> c = two_block_group_algebra_codes(A,B);
julia> code_n(c), code_k(c)
(56, 28)
```
See also: [`LPCode`](@ref), [`generalized_bicycle_codes`](@ref), [`bicycle_codes`](@ref), [`bivariate_bicycle_codes`](@ref)
""" # TODO doctest example
"""
function two_block_group_algebra_codes(a::GroupAlgebraElem, b::GroupAlgebraElem)
A = reshape([a], (1, 1))
B = reshape([b], (1, 1))
LPCode(A, B)
LPCode([a;;], [b;;])
end

"""
Expand Down
15 changes: 15 additions & 0 deletions ext/QuantumCliffordHeckeExt/util.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Checks the commutation relation between the left and right representation matrices
for two randomly-sampled elements `a` and `b` in the group algebra `ℱ[G]` with a general group `G`.
It verifies the commutation relation that states, `L(a)·R(b) = R(b)·L(a)`. This
property shows that matrices from the left and right representation sets commute
with each other, which is an important property related to the CSS orthogonality
condition.
"""
function check_repr_commutation_relation(GA::GroupAlgebra)
a, b = rand(GA), rand(GA)
# Check commutation relation: L(a)R(b) = R(b)L(a)
L_a = representation_matrix(a)
R_b = representation_matrix(b, :right)
return L_a * R_b == R_b * L_a
end
32 changes: 29 additions & 3 deletions src/QuantumClifford.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export
sHadamardXY, sHadamardYZ, sSQRTX, sInvSQRTX, sSQRTY, sInvSQRTY, sCXYZ, sCZYX,
sCNOT, sCPHASE, sSWAP,
sXCX, sXCY, sXCZ, sYCX, sYCY, sYCZ, sZCX, sZCY, sZCZ,
sZCrY, sInvZCrY,
sZCrY, sInvZCrY, sSWAPCX, sInvSWAPCX, sCZSWAP, sCXSWAP, sISWAP, sInvISWAP,
sSQRTZZ, sInvSQRTZZ, sSQRTXX, sInvSQRTXX, sSQRTYY, sInvSQRTYY,
# Misc Ops
SparseGate,
sMX, sMY, sMZ, PauliMeasurement, Reset, sMRX, sMRY, sMRZ,
Expand All @@ -77,6 +78,7 @@ export
graphstate, graphstate!, graph_gatesequence, graph_gate,
# Group theory tools
groupify, minimal_generating_set, pauligroup, normalizer, centralizer, contractor, delete_columns,
canonicalize_noncomm, commutify, matroid_parent, SubsystemCodeTableau,
# Clipped Gauge
canonicalize_clip!, bigram, entanglement_entropy,
# mctrajectories
Expand Down Expand Up @@ -569,8 +571,8 @@ function MixedDestabilizer(stab::Stabilizer{T}; undoperm=true, reportperm=false)
t[n+r+s+1:end] = sZ # The other logical set in the tableau
end
if undoperm
t = t[:,invperm(permx[permz])]::T
return MixedDestabilizer(t, r+s)::MixedDestabilizer{T}
t = t[:,invperm(permx[permz])]
return MixedDestabilizer(t, r+s)
end
if reportperm
return (MixedDestabilizer(t, r+s)::MixedDestabilizer{T}, r, permx, permz)
Expand Down Expand Up @@ -910,6 +912,30 @@ function unsafe_bitfindnext_(chunks::AbstractVector{T}, start::Int) where T<:Uns
return nothing
end

"""
$(TYPEDSIGNATURES)
Computes bitmask indices for an unsigned integer at index `i`
within the binary structure of a `Tableau` or `PauliOperator`.
For `Tableau`, the method operates on the `.xzs` field, while
for `PauliOperator`, it uses the `.xz` field. It calculates
the following values based on the index `i`:
- `lowbit`, the lowest bit.
- `ibig`, the index of the word containing the bit.
- `ismall`, the position of the bit within the word.
- `ismallm`, a bitmask isolating the specified bit.
"""
@inline function get_bitmask_idxs(xzs::AbstractArray{<:Unsigned}, i::Int)
T = eltype(xzs)
lowbit = T(1)
ibig = _div(T, i-1) + 1
ismall = _mod(T, i-1)
ismallm = lowbit << ismall
return lowbit, ibig, ismall, ismallm
end

"""Permute the qubits (i.e., columns) of the tableau in place."""
function Base.permute!(s::Tableau, perm::AbstractVector)
for r in 1:size(s,1)
Expand Down
3 changes: 1 addition & 2 deletions src/affectedqubits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,5 @@ affectedqubits(c::CliffordOperator) = 1:nqubits(c)
affectedqubits(c::ClassicalXOR) = ()

affectedbits(o) = ()
affectedbits(m::sMRZ) = (m.bit,)
affectedbits(m::sMZ) = (m.bit,)
affectedbits(m::Union{sMRZ,sMZ,sMRX,sMX,sMRY,sMY}) = m.bit==0 ? () : (m.bit,)
affectedbits(c::ClassicalXOR) = (c.bits..., c.store)
15 changes: 11 additions & 4 deletions src/ecc/ECC.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
module ECC

using LinearAlgebra
using LinearAlgebra: I
using QuantumClifford
using QuantumClifford: AbstractOperation, AbstractStabilizer, Stabilizer
using LinearAlgebra: LinearAlgebra, I, rank, tr
using QuantumClifford: QuantumClifford, AbstractOperation, AbstractStabilizer,
AbstractTwoQubitOperator, Stabilizer, PauliOperator,
random_brickwork_clifford_circuit, random_all_to_all_clifford_circuit,
canonicalize!, canonicalize_gott!,
logicalxview, logicalzview, stabilizerview, destabilizerview, tab, phases,
sCNOT, sSWAP, sHadamard, sPhase, sInvPhase,
sZCX, sZCY, sZCZ, sXCX, sXCY, sXCZ, sYCX, sYCY, sYCZ, sZ, sX, sY, sMRZ, sMRX,
single_x, single_y, single_z, random_pauli!, PauliError,
apply!, comm, comm!, stab_to_gf2, embed, @S_str, affectedqubits, affectedbits,
pftrajectories, pfmeasurements, mctrajectories
import QuantumClifford: Stabilizer, MixedDestabilizer, nqubits
using DocStringExtensions
using Combinatorics: combinations
Expand Down
3 changes: 3 additions & 0 deletions src/ecc/codes/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ function hgp(h₁,h₂)
hz = hcat(kron(LinearAlgebra.I(n₁), h₂), kron(h₁', LinearAlgebra.I(r₂)))
hx, hz
end

"""Implemented in a package extension with Hecke."""
function check_repr_commutation_relation end
Loading

0 comments on commit c63864e

Please sign in to comment.