From ad4560fcebc39ceb16c4b7ec22fba684528a6853 Mon Sep 17 00:00:00 2001 From: araujoms Date: Thu, 9 Jan 2025 14:13:48 +0100 Subject: [PATCH] add bell states --- Project.toml | 2 +- README.md | 12 +++++-- TODO | 2 -- docs/src/api.md | 10 +++--- src/measurements.jl | 4 +-- src/states.jl | 78 ++++++++++++++++++++++++++++++++++----------- test/states.jl | 5 +-- 7 files changed, 81 insertions(+), 32 deletions(-) diff --git a/Project.toml b/Project.toml index 69edbaf..7f11d41 100755 --- a/Project.toml +++ b/Project.toml @@ -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" diff --git a/README.md b/README.md index 71c1b8e..4ee0702 100644 --- a/README.md +++ b/README.md @@ -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/). diff --git a/TODO b/TODO index 9564316..e953450 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/docs/src/api.md b/docs/src/api.md index 1e167e2..7b2f3ca 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -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 @@ -128,9 +130,7 @@ choi ## Internal functions ```@docs +Ket._dps_constraints! Ket._partition Ket._fiducial_WH -Ket._idx -Ket._tidx -Ket._idxperm ``` diff --git a/src/measurements.jl b/src/measurements.jl index f876e32..b21fad0 100644 --- a/src/measurements.jl +++ b/src/measurements.jl @@ -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] @@ -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 diff --git a/src/states.jl b/src/states.jl index 6db5265..69c45f9 100644 --- a/src/states.jl +++ b/src/states.jl @@ -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...) @@ -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) @@ -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) @@ -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) @@ -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`. """ @@ -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,))...) @@ -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 diff --git a/test/states.jl b/test/states.jl index cf26e05..fc4892d 100644 --- a/test/states.jl +++ b/test/states.jl @@ -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