Skip to content

Commit

Permalink
add bell states
Browse files Browse the repository at this point in the history
  • Loading branch information
araujoms committed Jan 9, 2025
1 parent 5fc0fb3 commit ad4560f
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ GenericLinearAlgebra = "0.3.14"
Hypatia = "0.8.1"
JuMP = "1.23"
LinearAlgebra = "1"
Nemo = "0.39 - 0.47, 0.48"
Nemo = "0.47 - 0.48"
Quadmath = "0.5.10"
QuantumNPA = "0.1.0"
Random = "1"
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://araujoms.github.io/Ket.jl/dev/)

Toolbox for quantum information, nonlocality, and entanglement.
Ket is a toolbox for quantum information, nonlocality, and entanglement written in the Julia programming language. All its functions are designed to work with generic types, allowing one to use `Int64` or `Float64` for efficiency, or arbitrary precision types when needed. Wherever possible they can be also used for optimization with [JuMP](https://jump.dev/JuMP.jl/stable/). And everything is optimized to the last microsecond.

Highlights are the functions `mub` and `sic_povm`, that produce respectively MUBs and SIC-POVMs with arbitrary precision, `local_bound` that uses a parallelized algorithm to compute the local bound of a Bell inequality, and `partial_trace` and `partial_transpose`, that compute the partial trace and partial transpose in a way that can be used for optimization with [JuMP](https://jump.dev/JuMP.jl/stable/). Also worth mentioning are the functions to produce uniformly-distributed random states, unitaries, and POVMs: `random_state`, `random_unitary`, `random_povm`. And the eponymous `ket`, of course.
Highlights:

* Work with multipartite Bell inequalities, computing their local bounds and Tsirelson bounds with `local_bound` and `tsirelson_bound`, and transforming between Collins-Gisin, probability, and correlator representations with `tensor_collinsgisin`, `tensor_probability`, and `tensor_correlation`.
* Work with bipartite entanglement by computing the relative entropy of entanglement, random robustness, or Schmidt number via `entanglement_entropy`, `random_robustness`, and `schmidt_number`. Under the hood these functions use the DPS hierarchy, which is also available in isolation via `_dps_constraints!`.
* Generate MUBs and SIC-POVMs through `mub` and `sic_povm`.
* Generate uniformly-distributed random states, unitaries, and POVMs with `random_state`, `random_unitary`, and `random_povm`.
* Generate well-known families of quantum states, such as the Bell states, the GHZ state, the W state, and the super-singlet via `state_bell`, `state_ghz`, `state_w`, and `state_supersinglet`.
* Work with multilinear algebra via utility functions such as `partial_trace`, `partial_transpose`, and `permute_systems`.
* Generate kets with `ket`.

For the full list of functions see the [documentation](https://araujoms.github.io/Ket.jl/dev/api/).
2 changes: 0 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
MA - multipartite Bell stuff (SD)
MA - generalized Bell states
SD - noise maps: general last argument or separate function?
SD - NL/steering/entanglement robustness SDPs?
SD - KetSparse
Expand Down
10 changes: 5 additions & 5 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,15 @@ random_probability
## States

```@docs
state_bell_ket
state_bell
state_phiplus_ket
state_phiplus
isotropic
state_psiminus_ket
state_psiminus
state_super_singlet_ket
state_super_singlet
state_supersinglet_ket
state_supersinglet
state_ghz_ket
state_ghz
state_w_ket
Expand All @@ -128,9 +130,7 @@ choi
## Internal functions

```@docs
Ket._dps_constraints!
Ket._partition
Ket._fiducial_WH
Ket._idx
Ket._tidx
Ket._idxperm
```
4 changes: 2 additions & 2 deletions src/measurements.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ end
mub_prime(p::Integer) = mub_prime(ComplexF64, p)

function mub_prime_power(::Type{T}, p::Integer, r::Integer) where {T<:Number}
d = Int(p^r)
d = p^r
γ = _root_unity(T, p)
inv_sqrt_d = inv(_sqrt(T, d))
B = [zeros(T, d, d) for _ 1:d+1]
Expand Down Expand Up @@ -78,7 +78,7 @@ Reference: Durt, Englert, Bengtsson, Życzkowski, [arXiv:1004.3348](https://arxi
function mub(::Type{T}, d::Integer) where {T<:Number}
# the dimension d can be any integer greater than two
@assert d 2
f = collect(Nemo.factor(Int(d))) # Nemo.factor requires d to be an Int64 (or UInt64)
f = collect(Nemo.factor(d))
p = f[1][1]
r = f[1][2]
if length(f) > 1 # different prime factors
Expand Down
78 changes: 60 additions & 18 deletions src/states.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,52 @@ function white_noise!(rho::AbstractMatrix, v::Real)
end
export white_noise!

"""
state_bell_ket([T=ComplexF64,] a::Integer, b::Integer, d::Integer = 2)
Produces the ket of the generalized Bell state ψ_`ab` of local dimension `d`.
"""
function state_bell_ket(::Type{T}, a::Integer, b::Integer, d::Integer = 2; coeff = inv(_sqrt(T, d))) where {T<:Number}
ψ = zeros(T, d^2)
ω = _root_unity(T, d)
val = T(0)
for i 0:d-1
exponent = mod(i * b, d)
if exponent == 0
val = 1
elseif 4exponent == d
val = im
elseif 2exponent == d
val = -1
elseif 4exponent == 3d
val = -im
else
val = ω^exponent
end
ψ[d*i+mod(a + i, d)+1] = val * coeff
end
return ψ
end
state_bell_ket(a, b, d::Integer = 2) = state_bell_ket(ComplexF64, a, b, d)
export state_bell_ket

"""
state_bell([T=ComplexF64,] a::Integer, b::Integer, d::Integer = 2, v::Real = 1)
Produces the generalized Bell state ψ_`ab` of local dimension `d` with visibility `v`.
"""
function state_bell(::Type{T}, a::Integer, b::Integer, d::Integer = 2, v::Real = 1) where {T<:Number}
ρ = ketbra(state_bell_ket(T, a, b, d; coeff = one(T)))
parent(ρ) ./= d
return white_noise!(ρ, v)
end
state_bell(a, b, d::Integer = 2) = state_bell(ComplexF64, a, b, d)
export state_bell

"""
state_phiplus_ket([T=ComplexF64,] d::Integer = 2)
Produces the vector of the maximally entangled state Φ⁺ of local dimension `d`.
Produces the ket of the maximally entangled state Φ⁺ of local dimension `d`.
"""
function state_phiplus_ket(::Type{T}, d::Integer = 2; kwargs...) where {T<:Number}
return state_ghz_ket(T, d, 2; kwargs...)
Expand All @@ -53,7 +95,7 @@ export state_phiplus
"""
state_psiminus_ket([T=ComplexF64,] d::Integer = 2)
Produces the vector of the maximally entangled state ψ⁻ of local dimension `d`.
Produces the ket of the maximally entangled state ψ⁻ of local dimension `d`.
"""
function state_psiminus_ket(::Type{T}, d::Integer = 2; coeff = inv(_sqrt(T, d))) where {T<:Number}
psi = zeros(T, d^2)
Expand All @@ -79,7 +121,7 @@ export state_psiminus
"""
state_ghz_ket([T=ComplexF64,] d::Integer = 2, N::Integer = 3; coeff = 1/√d)
Produces the vector of the GHZ state local dimension `d`.
Produces the ket of the GHZ state with `N` parties and local dimension `d`.
"""
function state_ghz_ket(::Type{T}, d::Integer = 2, N::Integer = 3; coeff = inv(_sqrt(T, d))) where {T<:Number}
psi = zeros(T, d^N)
Expand All @@ -93,7 +135,7 @@ export state_ghz_ket
"""
state_ghz([T=ComplexF64,] d::Integer = 2, N::Integer = 3; v::Real = 1, coeff = 1/√d)
Produces the GHZ state of local dimension `d` with visibility `v`.
Produces the GHZ state with `N` parties, local dimension `d`, and visibility `v`.
"""
function state_ghz(::Type{T}, d::Integer = 2, N::Integer = 3; v::Real = 1, kwargs...) where {T<:Number}
return white_noise!(ketbra(state_ghz_ket(T, d, N; kwargs...)), v)
Expand All @@ -102,20 +144,20 @@ state_ghz(d::Integer = 2, N::Integer = 3; kwargs...) = state_ghz(ComplexF64, d,
export state_ghz

"""
state_w_ket([T=ComplexF64,] N::Integer = 3; coeff = 1/√d)
state_w_ket([T=ComplexF64,] N::Integer = 3; coeff = 1/√N)
Produces the vector of the `N`-partite W state.
Produces the ket of the `N`-partite W state.
"""
function state_w_ket(::Type{T}, N::Integer = 3; coeff = inv(_sqrt(T, N))) where {T<:Number}
psi = zeros(T, 2^N)
psi[2 .^ (0:N-1) .+ 1] .= coeff
psi[2 .^ (0:N-1).+1] .= coeff
return psi
end
state_w_ket(N::Integer = 3; kwargs...) = state_w_ket(ComplexF64, N; kwargs...)
export state_w_ket

"""
state_w([T=ComplexF64,] N::Integer = 3; v::Real = 1, coeff = 1/√d)
state_w([T=ComplexF64,] N::Integer = 3; v::Real = 1, coeff = 1/√N)
Produces the `N`-partite W state with visibility `v`.
"""
Expand All @@ -136,13 +178,13 @@ end
export isotropic

"""
state_super_singlet_ket([T=ComplexF64,] N::Integer = 3; coeff = 1/√N!)
state_supersinglet_ket([T=ComplexF64,] N::Integer = 3; coeff = 1/√N!)
Produces the vector of the `N`-partite `N`-level singlet state.
Produces the ket of the `N`-partite `N`-level singlet state.
Reference: Adán Cabello, [arXiv:quant-ph/0203119](https://arxiv.org/abs/quant-ph/0203119)
"""
function state_super_singlet_ket(::Type{T}, N::Integer = 3; coeff = inv(_sqrt(T, factorial(N)))) where {T<:Number}
function state_supersinglet_ket(::Type{T}, N::Integer = 3; coeff = inv(_sqrt(T, factorial(N)))) where {T<:Number}
psi = zeros(T, N^N)
for per Combinatorics.permutations(1:N)
tmp = kron(ket.((T,), per, (N,))...)
Expand All @@ -158,21 +200,21 @@ function state_super_singlet_ket(::Type{T}, N::Integer = 3; coeff = inv(_sqrt(T,
psi .*= coeff
return psi
end
state_super_singlet_ket(N::Integer = 3; kwargs...) = state_super_singlet_ket(ComplexF64, N; kwargs...)
export state_super_singlet_ket
state_supersinglet_ket(N::Integer = 3; kwargs...) = state_supersinglet_ket(ComplexF64, N; kwargs...)
export state_supersinglet_ket

"""
state_super_singlet([T=ComplexF64,] N::Integer = 3; v::Real = 1, coeff = 1/√d)
state_supersinglet([T=ComplexF64,] N::Integer = 3; v::Real = 1, coeff = 1/√d)
Produces the `N`-partite `N`-level singlet state with visibility `v`.
This state is invariant under simultaneous rotations on all parties: `(U⊗…⊗U)ρ(U⊗…⊗U)'=ρ`.
Reference: Adán Cabello, [arXiv:quant-ph/0203119](https://arxiv.org/abs/quant-ph/0203119)
"""
function state_super_singlet(::Type{T}, N::Integer = 3; v::Real = 1) where {T<:Number}
rho = ketbra(state_super_singlet_ket(T, N; coeff = one(T)))
function state_supersinglet(::Type{T}, N::Integer = 3; v::Real = 1) where {T<:Number}
rho = ketbra(state_supersinglet_ket(T, N; coeff = one(T)))
parent(rho) ./= factorial(N)
return white_noise!(rho, v)
end
state_super_singlet(N::Integer = 3; kwargs...) = state_super_singlet(ComplexF64, N; kwargs...)
export state_super_singlet
state_supersinglet(N::Integer = 3; kwargs...) = state_supersinglet(ComplexF64, N; kwargs...)
export state_supersinglet
5 changes: 3 additions & 2 deletions test/states.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
@test ketbra(ψ) state_ghz(T)
coeff = [T(3) / 5, T(4) / 5]
@test state_ghz_ket(T; coeff) == (T(3) * ket(1, 8) + T(4) * ket(8, 8)) / 5
@test state_super_singlet(T, 2) state_psiminus(T)
@test state_supersinglet(T, 2) state_psiminus(T)
U = foldl(kron, fill(Matrix(random_unitary(T, 3)), 3))
rho = state_super_singlet(T, 3)
rho = state_supersinglet(T, 3)
@test U * rho * U' rho
@test kron(I(5),shift(5,3)*clock(5,2))*state_phiplus_ket(5) state_bell_ket(3,2,5)
end
end

0 comments on commit ad4560f

Please sign in to comment.