Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `entropy_conditional`
- `entropy_relative`
- Fix `entanglement` and introduce `concurrence`. ([#414], [#418], [#419])
- Introduce some metric functions. ([#414], [#420])
- `hilbert_dist`
- `hellinger_dist`
- `bures_dist`
- `bures_angle`

## [v0.27.0]
Release date: 2025-02-14
Expand Down Expand Up @@ -159,3 +164,4 @@ Release date: 2024-11-13
[#416]: https://github.com/qutip/QuantumToolbox.jl/issues/416
[#418]: https://github.com/qutip/QuantumToolbox.jl/issues/418
[#419]: https://github.com/qutip/QuantumToolbox.jl/issues/419
[#420]: https://github.com/qutip/QuantumToolbox.jl/issues/420
6 changes: 5 additions & 1 deletion docs/src/resources/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,12 @@ entropy_conditional
entanglement
concurrence
negativity
tracedist
fidelity
tracedist
hilbert_dist
hellinger_dist
bures_dist
bures_angle
```

## [Spin Lattice](@id doc-API:Spin-Lattice)
Expand Down
23 changes: 23 additions & 0 deletions docs/src/resources/bibliography.bib
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,26 @@ @book{Wiseman2009Quantum
year={2009},
month=nov
}

@article{Vedral-Plenio1998,
title = {Entanglement measures and purification procedures},
author = {Vedral, V. and Plenio, M. B.},
journal = {Phys. Rev. A},
volume = {57},
issue = {3},
pages = {1619--1633},
numpages = {0},
year = {1998},
month = {Mar},
publisher = {American Physical Society},
doi = {10.1103/PhysRevA.57.1619},
url = {https://link.aps.org/doi/10.1103/PhysRevA.57.1619}
}

@article{Spehner2017,
title={Geometric measures of quantum correlations with Bures and Hellinger distances},
author={D. Spehner and F. Illuminati and M. Orszag and W. Roga},
year={2017},
journal={arXiv:1611.03449},
url={https://arxiv.org/abs/1611.03449},
}
2 changes: 1 addition & 1 deletion docs/src/users_guide/states_and_operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ coherent_dm(5, 1.25)
thermal_dm(5, 1.25)
```

`QuantumToolbox` also provides a set of distance metrics for determining how close two density matrix distributions are to each other. Included are the [`fidelity`](@ref), and trace distance ([`tracedist`](@ref)).
`QuantumToolbox` also provides a set of distance metrics for determining how close two density matrix distributions are to each other. For example, [`fidelity`](@ref), and trace distance ([`tracedist`](@ref)) are included. For more metric functions, see section [Entropy and Metrics](@ref doc-API:Entropy-and-Metrics) in the API page.

```@example states_and_operators
x = coherent_dm(5, 1.25)
Expand Down
101 changes: 89 additions & 12 deletions src/metrics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,28 @@
Functions for calculating metrics (distance measures) between states and operators.
=#

export tracedist, fidelity
export fidelity
export tracedist, hilbert_dist, hellinger_dist
export bures_dist, bures_angle

@doc raw"""
fidelity(ρ::QuantumObject, σ::QuantumObject)

Calculate the fidelity of two [`QuantumObject`](@ref):
``F(\hat{\rho}, \hat{\sigma}) = \textrm{Tr} \sqrt{\sqrt{\hat{\rho}} \hat{\sigma} \sqrt{\hat{\rho}}}``

Here, the definition is from [Nielsen-Chuang2011](@citet). It is the square root of the fidelity defined in [Jozsa1994](@citet).

Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref).
"""
function fidelity(ρ::QuantumObject{OperatorQuantumObject}, σ::QuantumObject{OperatorQuantumObject})
sqrt_ρ = sqrt(ρ)
eigval = abs.(eigvals(sqrt_ρ * σ * sqrt_ρ))
return sum(sqrt, eigval)
end
fidelity(ρ::QuantumObject{OperatorQuantumObject}, ψ::QuantumObject{KetQuantumObject}) = sqrt(abs(expect(ρ, ψ)))
fidelity(ψ::QuantumObject{KetQuantumObject}, σ::QuantumObject{OperatorQuantumObject}) = fidelity(σ, ψ)
fidelity(ψ::QuantumObject{KetQuantumObject}, ϕ::QuantumObject{KetQuantumObject}) = abs(dot(ψ, ϕ))

@doc raw"""
tracedist(ρ::QuantumObject, σ::QuantumObject)
Expand All @@ -21,20 +42,76 @@ tracedist(
} = norm(ket2dm(ρ) - ket2dm(σ), 1) / 2

@doc raw"""
fidelity(ρ::QuantumObject, σ::QuantumObject)
hilbert_dist(ρ::QuantumObject, σ::QuantumObject)

Calculate the fidelity of two [`QuantumObject`](@ref):
``F(\hat{\rho}, \hat{\sigma}) = \textrm{Tr} \sqrt{\sqrt{\hat{\rho}} \hat{\sigma} \sqrt{\hat{\rho}}}``
Calculates the Hilbert-Schmidt distance between two [`QuantumObject`](@ref):
``D_{HS}(\hat{\rho}, \hat{\sigma}) = \textrm{Tr}\left[\hat{A}^\dagger \hat{A}\right]``, where ``\hat{A} = \hat{\rho} - \hat{\sigma}``.

Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref).

# References
- [Vedral-Plenio1998](@citet)
"""
function hilbert_dist(
ρ::QuantumObject{ObjType1},
σ::QuantumObject{ObjType2},
) where {
ObjType1<:Union{KetQuantumObject,OperatorQuantumObject},
ObjType2<:Union{KetQuantumObject,OperatorQuantumObject},
}
check_dimensions(ρ, σ)

A = ket2dm(ρ) - ket2dm(σ)
return tr(A' * A)
end

@doc raw"""
hellinger_dist(ρ::QuantumObject, σ::QuantumObject)

Here, the definition is from Nielsen & Chuang, "Quantum Computation and Quantum Information". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994).
Calculates the [Hellinger distance](https://en.wikipedia.org/wiki/Hellinger_distance) between two [`QuantumObject`](@ref):
``D_H(\hat{\rho}, \hat{\sigma}) = \sqrt{2 - 2 \textrm{Tr}\left(\sqrt{\hat{\rho}}\sqrt{\hat{\sigma}}\right)}``

Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref).

# References
- [Spehner2017](@citet)
"""
function fidelity(ρ::QuantumObject{OperatorQuantumObject}, σ::QuantumObject{OperatorQuantumObject})
sqrt_ρ = sqrt(ρ)
eigval = abs.(eigvals(sqrt_ρ * σ * sqrt_ρ))
return sum(sqrt, eigval)
function hellinger_dist(
ρ::QuantumObject{ObjType1},
σ::QuantumObject{ObjType2},
) where {
ObjType1<:Union{KetQuantumObject,OperatorQuantumObject},
ObjType2<:Union{KetQuantumObject,OperatorQuantumObject},
}
# Ket (pure state) doesn't need to do square root
sqrt_ρ = isket(ρ) ? ket2dm(ρ) : sqrt(ρ)
sqrt_σ = isket(σ) ? ket2dm(σ) : sqrt(σ)

# `max` is to avoid numerical instabilities
# it happens when ρ = σ, sum(eigvals) might be slightly larger than 1
return sqrt(2.0 * max(0.0, 1.0 - sum(real, eigvals(sqrt_ρ * sqrt_σ))))
end
fidelity(ρ::QuantumObject{OperatorQuantumObject}, ψ::QuantumObject{KetQuantumObject}) = sqrt(abs(expect(ρ, ψ)))
fidelity(ψ::QuantumObject{KetQuantumObject}, σ::QuantumObject{OperatorQuantumObject}) = fidelity(σ, ψ)
fidelity(ψ::QuantumObject{KetQuantumObject}, ϕ::QuantumObject{KetQuantumObject}) = abs(dot(ψ, ϕ))

@doc raw"""
bures_dist(ρ::QuantumObject, σ::QuantumObject)

Calculate the [Bures distance](https://en.wikipedia.org/wiki/Bures_metric) between two [`QuantumObject`](@ref):
``D_B(\hat{\rho}, \hat{\sigma}) = \sqrt{2 \left(1 - F(\hat{\rho}, \hat{\sigma}) \right)}``

Here, the definition of [`fidelity`](@ref) ``F`` is from [Nielsen-Chuang2011](@citet). It is the square root of the fidelity defined in [Jozsa1994](@citet).

Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref).
"""
bures_dist(ρ::QuantumObject, σ::QuantumObject) = sqrt(2 * (1 - fidelity(ρ, σ)))

@doc raw"""
bures_angle(ρ::QuantumObject, σ::QuantumObject)

Calculate the [Bures angle](https://en.wikipedia.org/wiki/Bures_metric) between two [`QuantumObject`](@ref):
``D_A(\hat{\rho}, \hat{\sigma}) = \arccos\left(F(\hat{\rho}, \hat{\sigma})\right)``

Here, the definition of [`fidelity`](@ref) ``F`` is from [Nielsen-Chuang2011](@citet). It is the square root of the fidelity defined in [Jozsa1994](@citet).

Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref).
"""
bures_angle(ρ::QuantumObject, σ::QuantumObject) = acos(fidelity(ρ, σ))
69 changes: 62 additions & 7 deletions test/core-test/entropy_and_metric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ end
end
end

@testset "trace distance" begin
@testset "trace and Hilbert-Schmidt distance" begin
ψz0 = basis(2, 0)
ψz1 = basis(2, 1)
ρz0 = to_sparse(ket2dm(ψz0))
Expand All @@ -98,26 +98,81 @@ end
@test tracedist(ψz1, ρz0) ≈ 1.0
@test tracedist(ρz0, ρz1) ≈ 1.0

ψ = rand_ket(10)
ϕ = rand_ket(10)
@test isapprox(tracedist(ψ, ϕ)^2, hilbert_dist(ψ, ϕ) / 2; atol = 1e-6)

@testset "Type Inference (trace distance)" begin
@inferred tracedist(ψz0, ψx0)
@inferred tracedist(ρz0, ψz1)
@inferred tracedist(ψz1, ρz0)
@inferred tracedist(ρz0, ρz1)
end

@testset "Type Inference (Hilbert-Schmidt distance)" begin
@inferred hilbert_dist(ψz0, ψx0)
@inferred hilbert_dist(ρz0, ψz1)
@inferred hilbert_dist(ψz1, ρz0)
@inferred hilbert_dist(ρz0, ρz1)
end
end

@testset "fidelity" begin
M = sprand(ComplexF64, 5, 5, 0.5)
M0 = Qobj(M * M')
ψ1 = Qobj(rand(ComplexF64, 5))
ψ2 = Qobj(rand(ComplexF64, 5))
M1 = ψ1 * ψ1'
@testset "fidelity, Bures metric, and Hellinger distance" begin
M0 = rand_dm(5)
ψ1 = rand_ket(5)
ψ2 = rand_ket(5)
M1 = ket2dm(ψ1)
b00 = bell_state(Val(0), Val(0))
b01 = bell_state(Val(0), Val(1))
@test isapprox(fidelity(M0, M1), fidelity(ψ1, M0); atol = 1e-6)
@test isapprox(fidelity(ψ1, ψ2), fidelity(ket2dm(ψ1), ket2dm(ψ2)); atol = 1e-6)
@test isapprox(fidelity(b00, b00), 1; atol = 1e-6)
@test isapprox(bures_dist(b00, b00) + 1, 1; atol = 1e-6)
@test isapprox(bures_angle(b00, b00) + 1, 1; atol = 1e-6)
@test isapprox(hellinger_dist(b00, b00) + 1, 1; atol = 1e-6)
@test isapprox(fidelity(b00, b01) + 1, 1; atol = 1e-6)
@test isapprox(bures_dist(b00, b01), √2; atol = 1e-6)
@test isapprox(bures_angle(b00, b01), π / 2; atol = 1e-6)
@test isapprox(hellinger_dist(b00, b01), √2; atol = 1e-6)

# some relations between Bures and Hellinger dintances
# together with some monotonicity under tensor products
# [see arXiv:1611.03449 (2017); section 4.2]
ρA = rand_dm(5)
ρB = rand_dm(6)
ρAB = tensor(ρA, ρB)
σA = rand_dm(5)
σB = rand_dm(6)
σAB = tensor(σA, σB)
d_Bu_A = bures_dist(ρA, σA)
d_Bu_AB = bures_dist(ρAB, σAB)
d_He_A = hellinger_dist(ρA, σA)
d_He_AB = hellinger_dist(ρAB, σAB)
@test isapprox(fidelity(ρAB, σAB), fidelity(ρA, σA) * fidelity(ρB, σB); atol = 1e-6)
@test d_He_AB >= d_Bu_AB
@test d_Bu_AB >= d_Bu_A
@test isapprox(bures_dist(ρAB, tensor(σA, ρB)), d_Bu_A; atol = 1e-6)
@test d_He_AB >= d_He_A
@test isapprox(hellinger_dist(ρAB, tensor(σA, ρB)), d_He_A; atol = 1e-6)

@testset "Type Inference (fidelity)" begin
@inferred fidelity(M0, M1)
@inferred fidelity(ψ1, M0)
@inferred fidelity(ψ1, ψ2)
end

@testset "Type Inference (Hellinger distance)" begin
@inferred hellinger_dist(M0, M1)
@inferred hellinger_dist(ψ1, M0)
@inferred hellinger_dist(ψ1, ψ2)
end

@testset "Type Inference (Bures metric)" begin
@inferred bures_dist(M0, M1)
@inferred bures_dist(ψ1, M0)
@inferred bures_dist(ψ1, ψ2)
@inferred bures_angle(M0, M1)
@inferred bures_angle(ψ1, M0)
@inferred bures_angle(ψ1, ψ2)
end
end
Loading