Skip to content

Commit

Permalink
feat: explicit random stabilizer states using Categorical state sampl…
Browse files Browse the repository at this point in the history
…ing and qbinomial coefficients
  • Loading branch information
Fe-r-oz committed Jan 14, 2025
1 parent 3297023 commit 85d713f
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ version = "0.9.16"
[deps]
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
HostCPUFeatures = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0"
Expand Down Expand Up @@ -46,6 +47,7 @@ QuantumCliffordQuantikzExt = "Quantikz"
CUDA = "4.4.0, 5"
Combinatorics = "1.0"
DataStructures = "0.18"
Distributions = "0.25.116"
DocStringExtensions = "0.9"
Graphs = "1.9"
Hecke = "0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35"
Expand Down
11 changes: 11 additions & 0 deletions docs/src/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ @article{li2019measurement
doi={10.1103/PhysRevB.100.134306}
}

@article{struchalin2021experimental,
title={Experimental estimation of quantum state properties from classical shadows},
author={Struchalin, GI and Zagorovskii, Ya A and Kovlakov, EV and Straupe, SS and Kulik, SP},
journal={PRX Quantum},
volume={2},
number={1},
pages={010307},
year={2021},
publisher={APS}
}

% Canonicalization Methods
@article{garcia2012efficient,
Expand Down
138 changes: 138 additions & 0 deletions src/randoms.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Random: randperm, AbstractRNG, GLOBAL_RNG, rand!
using ILog2
import Nemo
using Distributions

##############################
# Random Paulis
Expand Down Expand Up @@ -298,3 +299,140 @@ function random_all_to_all_clifford_circuit(rng::AbstractRNG, nqubits::Int, ngat
end

random_all_to_all_clifford_circuit(nqubits::Int, ngates::Int) = random_all_to_all_clifford_circuit(GLOBAL_RNG, nqubits, ngates)

##############################
# Random stabilizer state
##############################

"""Convert an array of bits to an integer."""
function bits2int(bits)
r = 0
s = 1
for b in bits
if b & 1 != 0
r += s

Check warning on line 313 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L308-L313

Added lines #L308 - L313 were not covered by tests
end
s <<= 1
end
return r

Check warning on line 317 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L315-L317

Added lines #L315 - L317 were not covered by tests
end

"""Count the number of '1' bits in the binary representation of 'v' modulo 2."""
function parity(v)
return count_ones(v) % 2

Check warning on line 322 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L321-L322

Added lines #L321 - L322 were not covered by tests
end

"""Normalize a quantum state vector."""
function normalize_state(state)
norm_factor = norm(state)
for s in state
if s != 0
norm_factor *= s / abs(s)
break

Check warning on line 331 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L326-L331

Added lines #L326 - L331 were not covered by tests
end
end
return state / norm_factor

Check warning on line 334 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L333-L334

Added lines #L333 - L334 were not covered by tests
end

"""Find the rank of a matrix over GF(2)"""
function gf2_rank(rows)
rank = 0
while !isempty(rows)
pivot_row = pop!(rows)
if pivot_row != 0
rank += 1
lsb = pivot_row & -pivot_row
for i in eachindex(rows)
if rows[i] & lsb != 0
rows[i] ⊻= pivot_row

Check warning on line 347 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L338-L347

Added lines #L338 - L347 were not covered by tests
end
end

Check warning on line 349 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L349

Added line #L349 was not covered by tests
end
end
return rank

Check warning on line 352 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L351-L352

Added lines #L351 - L352 were not covered by tests
end

"""Multiply a matrix by a vector over GF(2)."""
function gf2_mul_mat_vec(m, v)
return bits2int([parity(m[i] & v) for i in 1:length(m)])

Check warning on line 357 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L356-L357

Added lines #L356 - L357 were not covered by tests
end

"""Calculate the dot product of two vectors over GF(2)."""
function gf2_mul_vec_vec(v1, v2)
return parity(v1 & v2)

Check warning on line 362 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L361-L362

Added lines #L361 - L362 were not covered by tests
end

"""
Computes the q-binomial coefficient, which generalizes the binomial coefficient to finite fields.
Inputs:
- n::Int: The first argument of the q-binomial coefficient.
- k::Int: The second argument of the q-binomial coefficient.
- q::Int: The base of the field (default is 2 for binary field).
Outputs:
- Int: The q-binomial coefficient C(n, k) over GF(q).
"""
function qbinomial(n, k, q = 2)
c = 1
for j in 0:(k - 1)
c *= q^n - q^j
end
for j in 0:(k - 1)
c ÷= q^k - q^j
end
return max(0, c) # Ensure non-negative values

Check warning on line 384 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L376-L384

Added lines #L376 - L384 were not covered by tests
end

"""Calculate the number of n-qubit states with 2**k nonzero elements."""
function number_of_states(n)
return [2^n * 2^((k+1)*k ÷ 2) * qbinomial(n, k) for k in 0:n]

Check warning on line 389 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L388-L389

Added lines #L388 - L389 were not covered by tests
end

"""
Generate a random n-qubit stabilizer state. It does so by using the procedure
described in the [struchalin2021experimental](@cite).
The procedure involves selecting a random value of k, sampling from the set of
stabilizer states with 2^k nonzero elements, and generating a random stabilizer
operator. The resulting state vector is normalized and returned.
"""
function random_stabilizer_state(n)
dtype = Int32
nmax = floor(Int, log2(typemax(dtype)) + 1)
if !(0 < n <= nmax)
throw(ArgumentError("Number of qubits must be in range(1, $nmax)!"))

Check warning on line 404 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L400-L404

Added lines #L400 - L404 were not covered by tests
end

dimn = 2^n
state = ComplexF32[0.0f0 for _ in 1:dimn]
weights = number_of_states(n)
dist = Distributions.Categorical(weights ./ sum(weights)) # Use a Categorical distribution for weighted sampling
k = rand(dist) - 1 # Offset by -1 to match 0-based indexing in Julia
dimk = 2^k

Check warning on line 412 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L407-L412

Added lines #L407 - L412 were not covered by tests

if k == 0
state[rand(1:dimn)] = 1.0f0
return state

Check warning on line 416 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L414-L416

Added lines #L414 - L416 were not covered by tests
end

rank = 0
R = rand(0:dimk-1, n) # Ensure R is initialized as a matrix
while rank < k
R = [rand(0:dimk-1) for _ in 1:n] # Generate `n` rows with elements in GF(2^k)
rank = gf2_rank(copy(R))
end

Check warning on line 424 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L419-L424

Added lines #L419 - L424 were not covered by tests

t = rand(0:dimn-1) # Random vector in GF(2^n)
Q = [rand(0:dimk-1) for _ in 1:k] # Generate `k` rows for Q
c = rand(0:dimk-1) # Random vector in GF(2^k)

Check warning on line 428 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L426-L428

Added lines #L426 - L428 were not covered by tests

for x in 0:(dimk - 1)
y = gf2_mul_mat_vec(R, x) t # y = R @ x + t
ib = gf2_mul_vec_vec(c, x) # 'imaginary' bit
mb = gf2_mul_vec_vec(x, gf2_mul_mat_vec(Q, x)) # 'minus' bit
state[y + 1] = 1im^ib * (-1)^mb
end

Check warning on line 435 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L430-L435

Added lines #L430 - L435 were not covered by tests

return normalize_state(state)

Check warning on line 437 in src/randoms.jl

View check run for this annotation

Codecov / codecov/patch

src/randoms.jl#L437

Added line #L437 was not covered by tests
end

0 comments on commit 85d713f

Please sign in to comment.