diff --git a/CHANGELOG.md b/CHANGELOG.md index 7226dbdc2..e47df2f05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -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 diff --git a/docs/src/resources/api.md b/docs/src/resources/api.md index f965ff24f..bb3e0b361 100644 --- a/docs/src/resources/api.md +++ b/docs/src/resources/api.md @@ -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) diff --git a/docs/src/resources/bibliography.bib b/docs/src/resources/bibliography.bib index e8386a703..2f55bbf57 100644 --- a/docs/src/resources/bibliography.bib +++ b/docs/src/resources/bibliography.bib @@ -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}, +} diff --git a/docs/src/users_guide/states_and_operators.md b/docs/src/users_guide/states_and_operators.md index 913f640af..f52c1e978 100644 --- a/docs/src/users_guide/states_and_operators.md +++ b/docs/src/users_guide/states_and_operators.md @@ -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) diff --git a/src/metrics.jl b/src/metrics.jl index 39ff1e3ad..d9462682f 100644 --- a/src/metrics.jl +++ b/src/metrics.jl @@ -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) @@ -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(ρ, σ)) diff --git a/test/core-test/entropy_and_metric.jl b/test/core-test/entropy_and_metric.jl index 746a491e7..b90a059f7 100644 --- a/test/core-test/entropy_and_metric.jl +++ b/test/core-test/entropy_and_metric.jl @@ -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)) @@ -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