From f88334b044beccdc86a7796be87f211422451c76 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Wed, 14 Aug 2024 20:37:13 +0500 Subject: [PATCH] adding codereview suggestions --- docs/src/references.bib | 12 ++-- src/entanglement.jl | 130 ++++++++++++++------------------------ test/test_entanglement.jl | 15 +++-- 3 files changed, 65 insertions(+), 92 deletions(-) diff --git a/docs/src/references.bib b/docs/src/references.bib index 062f2743b..6a50a9194 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -111,13 +111,13 @@ @article{gullans2020dynamical publisher={APS} } -@incollection{hein2006entanglement, +@article{hein2006entanglement, title={Entanglement in graph states and its applications}, - author={Hein, Marc and D{\"u}r, Wolfgang and Eisert, Jens and Raussendorf, Robert and Van den Nest, Maarten and Briegel, H-J}, - booktitle={Quantum computers, algorithms and chaos}, - pages={115--218}, - year={2006}, - publisher={IOS Press} + author={Hein, Marc and D{\"u}r, Wolfgang and Eisert, Jens and Raussendorf, Robert and Nest, M and Briegel, H-J}, + journal={arXiv preprint quant-ph/0602096}, + url={https://arxiv.org/abs/quant-ph/0602096}, + doi={10.48550/arXiv.quant-ph/0602096}, + year={2006} } @article{wilde2009logical, diff --git a/src/entanglement.jl b/src/entanglement.jl index 954295270..6a8321213 100644 --- a/src/entanglement.jl +++ b/src/entanglement.jl @@ -144,7 +144,8 @@ The bigram set `B(๐’ข)` encodes these endpoints as pairs: `B(๐’ข) โ‰ก {(๐“(gโ‚),๐“‡(gโ‚)),โ€ฆ,(๐“(gโ‚™),๐“‡(gโ‚™))}` The clipped gauge `๐’ข` is a specific choice of stabilizer state where exactly two stabilizer endpoints exist at each site, -ensuring `ฯ๐“(x) + ฯ๐“‡(x) = 2` for all sites `x`. +ensuring `ฯโ‚—(x) + ฯแตฃ(x) = 2` for all sites `x` where `ฯ` represents the reduced density matrix for the subsystem under +consideration. In the clipped gauge, entanglement entropy is determined only by the stabilizers' endpoints, regardless of their internal structure. @@ -187,26 +188,12 @@ end """ $TYPEDSIGNATURES -Get bipartite entanglement entropy of a subsystem `๐’ถ`. +Get bipartite entanglement entropy of a subsystem -In a system of `n`-qubits divided into regions `๐’ถ` and `๐’ท`, the Rรฉnyi (or von Neumann) -entropy `S(ฯ๐’ถ)` where `ฯ๐’ถ` is reduced density matrix, quantifies the quantum information -in region `๐’ถ` after tracing out region `๐’ท`. +Defined as entropy of the reduced density matrix. -The entropy is given by: `S(ฯ๐’ถ) = |๐’ถ| - logโ‚‚ |๐’ข๐’ถ|`, where `๐’ข๐’ถ` is a subgroup of stabilizers -acting non-trivially on `๐’ถ`. This entropy measures the number of independent stabilizers -on `๐’ถ`, reflecting the quantum correlations between regions. - -The stabilizer group `๐’ข`, viewed as a binary vector space `V`, can be decomposed such that: -`S๐’ถ = |๐’ท| - dim V๐’ท = dim (ฮ ๐’ถ V) - |๐’ถ|` where `ฮ ๐’ถ` and `ฮ ๐’ท` are truncation maps for regions -`๐’ถ` and `๐’ท`, respectively. - -Initially, each site has one stabilizer and zero entanglement, but as stabilizers enter -region `๐’ถ` over time, entanglement `S๐’ถ` increases by one bit for each new independent -operator in `๐’ถ`. - -It can be calculated with multiple different algorithms, the most performant one depending -on the particular case. +It can be calculated with multiple different algorithms, +the most performant one depending on the particular case. Currently implemented are the `:clip` (clipped gauge), `:graph` (graph state), and `:rref` (Gaussian elimination) algorithms. Benchmark your particular case to choose the best one. @@ -224,6 +211,8 @@ Get bipartite entanglement entropy of a contiguous subsystem by passing through If `clip=false` is set the canonicalization step is skipped, useful if the input state is already in the clipped gauge. ```jldoctest +julia> using Graphs # hide + julia> s = ghz(3) + XXX + ZZ_ @@ -231,6 +220,15 @@ julia> s = ghz(3) julia> entanglement_entropy(s, 1:3, Val(:clip)) 0 + +julia> s = Stabilizer(Graph(ghz(4))) ++ XZZZ ++ ZX__ ++ Z_X_ ++ Z__X + +julia> entanglement_entropy(s, [1,4], Val(:graph)) +1 ``` See also: [`bigram`](@ref), [`canonicalize_clip!`](@ref) @@ -250,19 +248,6 @@ $TYPEDSIGNATURES Get bipartite entanglement entropy by first converting the state to a graph and computing the rank of the adjacency matrix. -```jldoctest -julia> using Graphs # hide - -julia> s = Stabilizer(Graph(ghz(4))) -+ XZZZ -+ ZX__ -+ Z_X_ -+ Z__X - -julia> entanglement_entropy(s, [1,4], Val(:graph)) -1 -``` - Based on "Entanglement in graph states and its applications". """ # TODO you should use [hein2006entanglement](@cite) instead of "Entanglement in graph states and its applications", but Documenter is giving the weirdest error if you do so... function entanglement_entropy(state::AbstractStabilizer, subsystem::AbstractVector, algorithm::Val{:graph}) @@ -281,20 +266,7 @@ Get bipartite entanglement entropy by converting to RREF form (i.e., partial tra The state will be partially canonicalized in an RREF form. -```jldoctest -julia> s = MixedDestabilizer(T"-IX -YX -ZZ -ZI",2) -๐’Ÿโ„ฏ๐“ˆ๐“‰๐’ถ๐’ท -- _X -- YX -๐’ฎ๐“‰๐’ถ๐’ท -- ZZ -- Z_ - -julia> entanglement_entropy(s, [1,2], Val(:rref)) -0 -``` - -See also: [`canonicalize_rref!`](@ref), [`traceout!`](@ref). +See also: [`canonicalize_rref!`](@ref), [`traceout!`](@ref), [`mutual_information`](@ref) """ function entanglement_entropy(state::AbstractStabilizer, subsystem::AbstractVector, algorithm::Val{:rref}; pure::Bool=false) nb_of_qubits = nqubits(state) @@ -310,39 +282,18 @@ function entanglement_entropy(state::AbstractStabilizer, subsystem::AbstractVect return nb_of_qubits - rank_after_deletion - nb_of_deletions end -""" -$TYPEDSIGNATURES -""" entanglement_entropy(state::MixedDestabilizer, subsystem::AbstractVector, a::Val{:rref}) = entanglement_entropy(state, subsystem, a; pure=nqubits(state)==rank(state)) -_to_unitrange(x) = isa(x, UnitRange) ? x : isa(x, AbstractVector) && !isempty(x) && all(diff(x) .== 1) ? UnitRange(first(x), last(x)) : error("Cannot convert to UnitRange: $x") - """ $TYPEDSIGNATURES -The mutual information between subsystems `๐’ถ` and `๐’ท` in a stabilizer state is -given by `Iโฟ(๐’ถ, ๐’ท) = Sโฟ๐’ถ + Sโฟ๐’ท - Sโฟ๐’ถ๐’ท`, where the Rรฉnyi index `n` is dropped because, for -Clifford circuits, all Renyi entropies are equal due to the flat entanglement spectrum. +The mutual information between subsystems `๐’ถ` and `๐’ท` in a stabilizer state is given by `I(๐’ถ, ๐’ท) = S๐’ถ + S๐’ท - S๐’ถ๐’ท`. ```jldoctest +julia> using Graphs # hide + julia> mutual_information(ghz(3), 1:2, 3:4, Val(:clip)) 2 -``` - -See Eq. E6 of [li2019measurement](@cite). -""" -function mutual_information(state::AbstractStabilizer, A::UnitRange, B::UnitRange, algorithm::Val{:clip}; clip::Bool=true) - S๐’ถ = entanglement_entropy(state, A, algorithm; clip=clip) - S๐’ท = entanglement_entropy(state, B, algorithm; clip=clip) - S๐’ถ๐’ท = entanglement_entropy(state, _to_unitrange(union(A, B)), algorithm; clip=clip) - return S๐’ถ + S๐’ท - S๐’ถ๐’ท -end - -""" -$TYPEDSIGNATURES - -```jldoctest -julia> using Graphs # hide julia> s = Stabilizer(Graph(ghz(4))) + XZZZ @@ -354,17 +305,34 @@ julia> mutual_information(s, [1,2], [3, 4], Val(:graph)) 2 ``` +See Eq. E6 of [li2019measurement](@cite). See also: [`entanglement_entropy`](@ref) """ -function mutual_information(state::AbstractStabilizer, A::AbstractVector, B::AbstractVector, algorithm::Union{Val{:rref}, Val{:graph}}; pure::Bool=false) - if algorithm == Val(:graph) - S๐’ถ = entanglement_entropy(state, A, algorithm) - S๐’ท = entanglement_entropy(state, B, algorithm) - S๐’ถ๐’ท = entanglement_entropy(state, union(A, B), algorithm) - return S๐’ถ + S๐’ท - S๐’ถ๐’ท - else - S๐’ถ = entanglement_entropy(state, A, algorithm; pure=pure) - S๐’ท = entanglement_entropy(state, B, algorithm; pure=pure) - S๐’ถ๐’ท = entanglement_entropy(state, union(A, B), algorithm; pure=pure) - return S๐’ถ + S๐’ท - S๐’ถ๐’ท +function mutual_information(state::AbstractStabilizer, A::UnitRange, B::UnitRange, algorithm::Val{:clip}; clip::Bool=true) + if !isempty(intersect(A, B)) + throw(ArgumentError("Ranges A and B must not overlap.")) + end + S๐’ถ = entanglement_entropy(state, A, algorithm; clip=clip) + S๐’ท = entanglement_entropy(state, B, algorithm; clip=clip) + S๐’ถ๐’ท = entanglement_entropy(state, UnitRange(first(union(A, B)), last(union(A, B))), algorithm; clip=clip) + return S๐’ถ + S๐’ท - S๐’ถ๐’ท +end + +function mutual_information(state::AbstractStabilizer, A::AbstractVector, B::AbstractVector, algorithm::Val{:rref}; pure::Bool=false) + if !isempty(intersect(A, B)) + throw(ArgumentError("Ranges A and B must not overlap.")) + end + S๐’ถ = entanglement_entropy(state, A, algorithm; pure=pure) + S๐’ท = entanglement_entropy(state, B, algorithm; pure=pure) + S๐’ถ๐’ท = entanglement_entropy(state, union(A, B), algorithm; pure=pure) + return S๐’ถ + S๐’ท - S๐’ถ๐’ท +end + +function mutual_information(state::AbstractStabilizer, A::AbstractVector, B::AbstractVector, algorithm::Val{:graph}) + if !isempty(intersect(A, B)) + throw(ArgumentError("Ranges A and B must not overlap.")) end + S๐’ถ = entanglement_entropy(state, A, algorithm) + S๐’ท = entanglement_entropy(state, B, algorithm) + S๐’ถ๐’ท = entanglement_entropy(state, union(A, B), algorithm) + return S๐’ถ + S๐’ท - S๐’ถ๐’ท end diff --git a/test/test_entanglement.jl b/test/test_entanglement.jl index 98bdf8617..9ea36c548 100644 --- a/test/test_entanglement.jl +++ b/test/test_entanglement.jl @@ -50,7 +50,7 @@ @test entanglement_entropy(copy(s), subsystem, Val(:graph))==2 @test entanglement_entropy(copy(s), subsystem, Val(:rref))==2 end - + @testset "Mutual Information for Clifford Circuits" begin for n in test_sizes s = random_stabilizer(n) @@ -59,10 +59,15 @@ startB = rand(subsystem_rangeA) endB = rand(startB:n) subsystem_rangeB = startB:endB - @test mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:clip)) == mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:rref)) == mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:graph)) - # The mutual information `Iโฟ(๐’ถ, ๐’ท) = Sโฟ๐’ถ + Sโฟ๐’ท - Sโฟ๐’ถ๐’ท for Clifford circuits is non-negative since n is 1 [li2019measurement](@cite). - @test mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:clip)) & mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:rref)) >= 0 - @test mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:graph)) >= 0 + if !isempty(intersect(subsystem_rangeA, subsystem_rangeB)) + @test_throws ArgumentError mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:clip)) + @test_throws ArgumentError mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:rref)) + @test_throws ArgumentError mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:graph)) + else + @test mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:clip)) == mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:rref)) == mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:graph)) + # The mutual information `I(๐’ถ, ๐’ท) = S๐’ถ + S๐’ท - S๐’ถ๐’ท for Clifford circuits is non-negative [li2019measurement](@cite). + @test mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:clip)) & mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:rref)) & mutual_information(copy(s), subsystem_rangeA, subsystem_rangeB, Val(:graph)) >= 0 + end end end end