Skip to content

Commit 84aa723

Browse files
committed
add tests for entropy functions
1 parent f49cab6 commit 84aa723

File tree

6 files changed

+119
-62
lines changed

6 files changed

+119
-62
lines changed

src/entropy.jl

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,12 @@ function entropy_relative(
100100
= σ_result.vectors
101101

102102
# create P_ij matrix (all elements should be real)
103-
P = abs2(Uρ' * Uσ) # this equals to ⟨i|j⟩⟨j|i⟩
103+
P = abs2.(Uρ' * Uσ) # this equals to ⟨i|j⟩⟨j|i⟩
104104

105-
# return +∞ if kernel of σ overlaps with support of ρ
106-
dot((p .>= tol), (P .>= tol), (q .< tol)) && return Inf
105+
# return +∞ if kernel of σ overlaps with support of ρ, i.e., supp(p) ⊆ supp(q)
106+
# That is, if σ is not full rank, S(ρ||σ) = +∞
107+
# note that, one special case is that S(ρ||σ) = 0 (if ρ == σ)
108+
((transpose(p .>= tol) * (P .>= tol) * (q .< tol)) == 0) || return Inf
107109

108110
# Avoid -∞ from log(0), these terms will be multiplied by zero later anyway
109111
replace!(q_j -> abs(q_j) < tol ? 1 : q_j, q)
@@ -119,7 +121,7 @@ function entropy_relative(
119121

120122
# the relative entropy is guaranteed to be ≥ 0
121123
# so we calculate the value to 0 to avoid small violations of the lower bound.
122-
return max(0, dot(p_vals, log_p) - dot(p, P, log_q))
124+
return max(0.0, dot(p_vals, log_p) - dot(p, P, log_q))
123125
end
124126

125127
@doc raw"""
@@ -158,9 +160,11 @@ function entropy_mutual(
158160
BType<:Union{Int,AbstractVector{Int},Tuple},
159161
}
160162
# check if selA and selB matches the dimensions of ρAB
161-
sel_A_B = vcat(selA, selB)
162-
(length(sel_A_B) != N) && ArgumentError(
163-
"The indices in `selA = $(selA)` and `selB = $(selB)` does not match the given QuantumObject which has $N sub-systems",
163+
sel_A_B = (selA..., selB...)
164+
(length(sel_A_B) != N) && throw(
165+
ArgumentError(
166+
"The indices in `selA = $(selA)` and `selB = $(selB)` does not match the given QuantumObject which has $N sub-systems",
167+
),
164168
)
165169
allunique(sel_A_B) || throw(ArgumentError("Duplicate selection indices in `selA = $(selA)` and `selB = $(selB)`"))
166170

@@ -196,11 +200,10 @@ Calculates the entanglement by doing the partial trace of `QO`, selecting only t
196200
"""
197201
function entanglement(
198202
QO::QuantumObject{OpType},
199-
sel::Union{AbstractVector{Int},Tuple},
203+
sel::Union{Int,AbstractVector{Int},Tuple},
200204
) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}}
201205
ψ = normalize(QO)
202206
ρ_tr = ptrace(ψ, sel)
203207
entropy = entropy_vn(ρ_tr)
204208
return (entropy > 0) * entropy
205209
end
206-
entanglement(QO::QuantumObject, sel::Int) = entanglement(QO, (sel,))

src/qobj/functions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ to_dense(::Type{T}, A::AbstractSparseArray) where {T<:Number} = Array{T}(A)
125125
to_dense(::Type{T1}, A::AbstractArray{T2}) where {T1<:Number,T2<:Number} = Array{T1}(A)
126126
to_dense(::Type{T}, A::AbstractArray{T}) where {T<:Number} = A
127127

128-
function to_dense(::Type{M}) where {M<:SparseMatrixCSC}
128+
function to_dense(::Type{M}) where {M<:Union{Diagonal,SparseMatrixCSC}}
129129
T = M
130130
par = T.parameters
131131
npar = length(par)

test/core-test/entanglement.jl

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
@testset "entropy" begin
2+
base = 2
3+
λ = rand()
4+
ψ = rand_ket(10)
5+
ρ1 = rand_dm(10)
6+
ρ2 = rand_dm(10)
7+
σ1 = rand_dm(10)
8+
σ2 = rand_dm(10)
9+
10+
dims = (2, 3)
11+
ρAB = rand_dm((dims..., dims...))
12+
selA = (1, 2)
13+
selB = (3, 4)
14+
ρA = ptrace(ρAB, selA)
15+
ρB = ptrace(ρAB, selB)
16+
nA = nB = prod(dims)
17+
IA = qeye(nA, dims = dims)
18+
IB = qeye(nB, dims = dims)
19+
20+
# quantum relative entropy
21+
@test entropy_relative(ρ1, ψ) == Inf
22+
@test entropy_relative(ρ1, rand_dm(10, rank = 9)) == Inf
23+
@test entropy_relative(ψ, ψ) 0
24+
@test entropy_relative* ρ1 + (1 - λ) * ρ2, λ * σ1 + (1 - λ) * σ2) <=
25+
λ * entropy_relative(ρ1, σ1) + (1 - λ) * entropy_relative(ρ2, σ2) # joint convexity
26+
27+
# relations between different entropies
28+
@test entropy_relative(ρA, IA / nA) log(nA) - entropy_vn(ρA)
29+
@test entropy_relative(ρB, IB / nB; base = base) log(base, nB) - entropy_vn(ρB; base = base)
30+
@test entropy_relative(ρAB, tensor(ρA, ρB)) entropy_mutual(ρAB, selA, selB)
31+
@test entropy_relative(ρAB, tensor(ρA, ρB)) entropy_mutual(ρAB, selA, selB)
32+
@test entropy_relative(ρAB, tensor(ρA, IB / nB)) log(nB) - entropy_conditional(ρAB, selA)
33+
@test entropy_linear(ρ1) == 1 - purity(ρ1)
34+
35+
ρ_wrong = Qobj(rand(ComplexF64, 10, 10))
36+
@test_throws ErrorException entropy_relative(ρ1, ρ_wrong)
37+
@test_throws ErrorException entropy_relative(ρ_wrong, ρ1)
38+
@test_throws ArgumentError entropy_mutual(ρAB, 1, 3)
39+
@test_throws ArgumentError entropy_mutual(ρAB, 1, (3, 4))
40+
@test_throws ArgumentError entropy_mutual(ρAB, (1, 2), 3)
41+
@test_throws ArgumentError entropy_mutual(ρAB, (1, 2), (1, 3))
42+
43+
@testset "Type Stability (entropy)" begin
44+
@inferred entropy_vn(ρ1)
45+
@inferred entropy_vn(ρ1, base = base)
46+
@inferred entropy_relative(ρ1, ψ)
47+
@inferred entropy_relative(ρ1, σ1, base = base)
48+
@inferred entropy_linear(ρ1)
49+
@inferred entropy_mutual(ρAB, selA, selB)
50+
@inferred entropy_conditional(ρAB, selA)
51+
end
52+
end
53+
54+
@testset "Entanglement" begin
55+
g = fock(2, 1)
56+
e = fock(2, 0)
57+
state = normalize(kron(g, e) + kron(e, g))
58+
rho = state * state'
59+
@test entanglement(state, 1) / log(2) 1
60+
@test entanglement(rho, 1) / log(2) 1
61+
62+
@testset "Type Stability (entanglement)" begin
63+
@inferred entanglement(state, 1)
64+
@inferred entanglement(rho, 1)
65+
end
66+
end
67+
68+
@testset "trace distance" begin
69+
ψz0 = basis(2, 0)
70+
ψz1 = basis(2, 1)
71+
ρz0 = to_sparse(ket2dm(ψz0))
72+
ρz1 = to_sparse(ket2dm(ψz1))
73+
ψx0 = sqrt(0.5) * (basis(2, 0) + basis(2, 1))
74+
@test tracedist(ψz0, ψx0) sqrt(0.5)
75+
@test tracedist(ρz0, ψz1) 1.0
76+
@test tracedist(ψz1, ρz0) 1.0
77+
@test tracedist(ρz0, ρz1) 1.0
78+
79+
@testset "Type Inference (trace distance)" begin
80+
@inferred tracedist(ψz0, ψx0)
81+
@inferred tracedist(ρz0, ψz1)
82+
@inferred tracedist(ψz1, ρz0)
83+
@inferred tracedist(ρz0, ρz1)
84+
end
85+
end
86+
87+
@testset "fidelity" begin
88+
M = sprand(ComplexF64, 5, 5, 0.5)
89+
M0 = Qobj(M * M')
90+
ψ1 = Qobj(rand(ComplexF64, 5))
91+
ψ2 = Qobj(rand(ComplexF64, 5))
92+
M1 = ψ1 * ψ1'
93+
@test isapprox(fidelity(M0, M1), fidelity(ψ1, M0); atol = 1e-6)
94+
@test isapprox(fidelity(ψ1, ψ2), fidelity(ket2dm(ψ1), ket2dm(ψ2)); atol = 1e-6)
95+
96+
@testset "Type Inference (fidelity)" begin
97+
@inferred fidelity(M0, M1)
98+
@inferred fidelity(ψ1, M0)
99+
@inferred fidelity(ψ1, ψ2)
100+
end
101+
end

test/core-test/quantum_objects.jl

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -566,54 +566,20 @@
566566
end
567567
end
568568

569-
@testset "trace distance" begin
570-
ψz0 = basis(2, 0)
571-
ψz1 = basis(2, 1)
572-
ρz0 = to_sparse(ket2dm(ψz0))
573-
ρz1 = to_sparse(ket2dm(ψz1))
574-
ψx0 = sqrt(0.5) * (basis(2, 0) + basis(2, 1))
575-
@test tracedist(ψz0, ψx0) sqrt(0.5)
576-
@test tracedist(ρz0, ψz1) 1.0
577-
@test tracedist(ψz1, ρz0) 1.0
578-
@test tracedist(ρz0, ρz1) 1.0
579-
580-
@testset "Type Inference (trace distance)" begin
581-
@inferred tracedist(ψz0, ψx0)
582-
@inferred tracedist(ρz0, ψz1)
583-
@inferred tracedist(ψz1, ρz0)
584-
@inferred tracedist(ρz0, ρz1)
585-
end
586-
end
587-
588-
@testset "sqrt and fidelity" begin
589-
M = sprand(ComplexF64, 5, 5, 0.5)
590-
M0 = Qobj(M * M')
591-
ψ1 = Qobj(rand(ComplexF64, 5))
592-
ψ2 = Qobj(rand(ComplexF64, 5))
593-
M1 = ψ1 * ψ1'
594-
@test sqrtm(M0) sqrtm(to_dense(M0))
595-
@test isapprox(fidelity(M0, M1), fidelity(ψ1, M0); atol = 1e-6)
596-
@test isapprox(fidelity(ψ1, ψ2), fidelity(ket2dm(ψ1), ket2dm(ψ2)); atol = 1e-6)
597-
598-
@testset "Type Inference (sqrt and fidelity)" begin
599-
@inferred sqrtm(M0)
600-
@inferred fidelity(M0, M1)
601-
@inferred fidelity(ψ1, M0)
602-
@inferred fidelity(ψ1, ψ2)
603-
end
604-
end
605-
606-
@testset "log, exp, sinm, cosm" begin
569+
@testset "sqrt, log, exp, sinm, cosm" begin
607570
M0 = rand(ComplexF64, 4, 4)
608571
Md = Qobj(M0 * M0')
609572
Ms = to_sparse(Md)
610573
e_p = expm(1im * Md)
611574
e_m = expm(-1im * Md)
575+
@test sqrtm(Md) sqrtm(Ms)
612576
@test logm(expm(Ms)) expm(logm(Md))
613577
@test cosm(Ms) (e_p + e_m) / 2
614578
@test sinm(Ms) (e_p - e_m) / 2im
615579

616580
@testset "Type Inference" begin
581+
@inferred sqrtm(Md)
582+
@inferred sqrtm(Ms)
617583
@inferred expm(Md)
618584
@inferred expm(Ms)
619585
@inferred logm(Md)

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ core_tests = [
1212
"dynamical_fock_dimension_mesolve.jl",
1313
"dynamical-shifted-fock.jl",
1414
"eigenvalues_and_operators.jl",
15-
"entanglement.jl",
15+
"entropy_and_metric.jl",
1616
"generalized_master_equation.jl",
1717
"low_rank_dynamics.jl",
1818
"negativity_and_partial_transpose.jl",

0 commit comments

Comments
 (0)