diff --git a/src/StatesZoo/StatesZoo.jl b/src/StatesZoo/StatesZoo.jl index 2c87d15a..7d32a35f 100644 --- a/src/StatesZoo/StatesZoo.jl +++ b/src/StatesZoo/StatesZoo.jl @@ -5,7 +5,10 @@ using QuantumSymbolics, QuantumOpticsBase using QuantumSymbolics: withmetadata, @withmetadata, Metadata import QuantumSymbolics: express_nolookup -export SingleRailMidSwapBell, DualRailMidSwapBell, ZALMSpinPair +using LinearAlgebra +import LinearAlgebra: tr + +export SingleRailMidSwapBellW, SingleRailMidSwapBell, DualRailMidSwapBellW, DualRailMidSwapBell, ZALMSpinPairW, ZALMSpinPair, tr abstract type AbstractTwoQubitState <: QuantumSymbolics.AbstractTwoQubitOp end #For representing density matrices Base.show(io::IO, x::AbstractTwoQubitState) = print(io, "$(symbollabel(x))") diff --git a/src/StatesZoo/single_dual_rail_midswap/single_dual_rail_midswap.jl b/src/StatesZoo/single_dual_rail_midswap/single_dual_rail_midswap.jl index ccaa1b88..10e5e1ac 100644 --- a/src/StatesZoo/single_dual_rail_midswap/single_dual_rail_midswap.jl +++ b/src/StatesZoo/single_dual_rail_midswap/single_dual_rail_midswap.jl @@ -34,7 +34,44 @@ Fields: $FIELDS -Generates the spin-spin density matrix for linear photonic entanglement swap +Generates the unnormalized spin-spin density matrix for linear photonic entanglement swap +with emissive memories emitting single rail photonic qubits from the paper [prajit2023entangling](@cite). +Since the matrix is 'weighted' by the probability for success, it is suffixed with a W to distinguish it +from the normalized object `SingleRailMidSwapBell`. +It takes the following parameters: +- eA, eB: Link efficiencies for memories A and B upto the swap (include link loss, detector efficiency, etc.) +- gA, gB: Memory initialization parameter for memories A and B +- Pd: Detector dark count probability per photonic mode (assumed to be the same for both detectors) +- Vis: Interferometer visibility for the midpoint swap' can be complex to account for phase instability + +```jldoctest +julia> r = Register(2) + +julia> initialize!(r[1:2], SingleRailMidSwapBellW(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99)) + +julia> observable(r[1:2], Z⊗Z) +``` +""" +@withmetadata struct SingleRailMidSwapBellW <: AbstractTwoQubitState + eA::Float64 + eB::Float64 + gA::Float64 + gB::Float64 + Pd::Float64 + Vis::Float64 +end + +symbollabel(x::SingleRailMidSwapBellW) = "ρˢʳᵐˢᵂ" + + +""" +$TYPEDEF + +Fields: + +$FIELDS + +Generates the normalized spin-spin density matrix for linear photonic entanglement swap with emissive memories emitting single rail photonic qubits from the paper [prajit2023entangling](@cite) It takes the following parameters: - eA, eB: Link efficiencies for memories A and B upto the swap (include link loss, detector efficiency, etc.) @@ -69,7 +106,44 @@ Fields: $FIELDS -Generates the spin-spin density matrix for linear photonic entanglement swap with emissive +Generates the unnormalized spin-spin density matrix for linear photonic entanglement swap with emissive + memories emitting dual rail photonic qubits from the paper [prajit2023entangling](@cite). + Since the matrix is 'weighted' by the probability for success, it is suffixed with a W to distinguish it +from the normalized object `DualRailMidSwapBell`. + It takes the following parameters: + - eA, eB: Link efficiencies for memories A and B upto the swap (include link loss, detector efficiency, etc.) +- gA, gB: Memory initialization parameter for memories A and B +- Pd: Detector dark count probability per photonic mode (assumed to be the same for both detectors) +- Vis: Interferometer visibility for the midpoint swap + +```jldoctest +julia> r = Register(2) + +julia> initialize!(r[1:2], DualRailMidSwapBellW(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99)) + +julia> observable(r[1:2], Z⊗Z) +``` +""" +@withmetadata struct DualRailMidSwapBellW <: AbstractTwoQubitState + eA::Float64 + eB::Float64 + gA::Float64 + gB::Float64 + Pd::Float64 + Vis::Float64 +end + +symbollabel(x::DualRailMidSwapBellW) = "ρᵈʳᵐˢᵂ" + + +""" +$TYPEDEF + +Fields: + +$FIELDS + +Generates the normalized spin-spin density matrix for linear photonic entanglement swap with emissive memories emitting dual rail photonic qubits from the paper [prajit2023entangling](@cite). It takes the following parameters: - eA, eB: Link efficiencies for memories A and B upto the swap (include link loss, detector efficiency, etc.) @@ -99,12 +173,27 @@ symbollabel(x::DualRailMidSwapBell) = "ρᵈʳᵐˢ" ## express +function express_nolookup(x::SingleRailMidSwapBellW, ::QuantumOpticsRepr) + data = midswap_single_rail(x.eA, x.eB, x.gA, x.gB, x.Pd, x.Vis) + return SparseOperator(_bspin⊗_bspin, Complex.(data)) +end + function express_nolookup(x::SingleRailMidSwapBell, ::QuantumOpticsRepr) data = midswap_single_rail(x.eA, x.eB, x.gA, x.gB, x.Pd, x.Vis) + return SparseOperator(_bspin⊗_bspin, Complex.(data/tr(data))) +end + +function express_nolookup(x::DualRailMidSwapBellW, ::QuantumOpticsRepr) + data = midswap_dual_rail(x.eA, x.eB, x.gA, x.gB, x.Pd, x.Vis) return SparseOperator(_bspin⊗_bspin, Complex.(data)) end function express_nolookup(x::DualRailMidSwapBell, ::QuantumOpticsRepr) data = midswap_dual_rail(x.eA, x.eB, x.gA, x.gB, x.Pd, x.Vis) - return SparseOperator(_bspin⊗_bspin, Complex.(data)) -end \ No newline at end of file + return SparseOperator(_bspin⊗_bspin, Complex.(data/tr(data))) +end + +# Symbolic trace + +tr(::SingleRailMidSwapBell) = 1 +tr(::DualRailMidSwapBell) = 1 \ No newline at end of file diff --git a/src/StatesZoo/zalm_pair/zalm_pair.jl b/src/StatesZoo/zalm_pair/zalm_pair.jl index 49660d6b..261b2553 100644 --- a/src/StatesZoo/zalm_pair/zalm_pair.jl +++ b/src/StatesZoo/zalm_pair/zalm_pair.jl @@ -568,7 +568,59 @@ Fields: $FIELDS -Generate symbolic object for the spin-spin density matrix for a +Generate symbolic object for the unnormalized spin-spin density matrix for a +cascaded source swapped with emissive spin memories. Since the matrix is 'weighted' by the probability for +success, it is suffixed with a W to distinguish it from the normalized object `ZALMSpinPair`. The cascaded +source from papers [prajit2022heralded](@cite) and [kevin2023zero](@cite) +is stored in spin memories as discussed in [prajit2023entangling](@cite). +It takes the following parameters: +- Ns: mean photon number per mode of the cascaded source model +- gA: qubit initialization parameter on Alice's side +- gB: qubit initialization parameter on Bob's side +- eAm: memory out-coupling efficiency for Alice's side (Allowed range: [0,1]) +- eBm: memory out-coupling efficiency for Bob's side (Allowed range: [0,1]) +- eAs: source out-coupling efficiency for Alice's side (Allowed range: [0,1]) +- eBs: source out-coupling efficiency for Bob's side (Allowed range: [0,1]) +- eD: detector efficiency (Allowed range: [0,1]) +- Pd: dark click probability per photonic mode on source's swap +- Pdo1: dark click probability per photonic mode on Alice side swap +- Pdo2: dark click probability per photonic mode on Bob side swap +- VisF: product of visibilities of all three interferometers (Allowed range: [0,1]) + +```jldoctest +julia> r = Register(2) + +julia> initialize!(r[1:2], ZALMSpinPairW(1e-3, 0.5, 0.5, 1, 1, 1, 1, 0.9, 1e-8, 1e-8, 1e-8, 0.99)) + +juilia> observable(r[1:2], Z⊗Z) +``` +""" +@withmetadata struct ZALMSpinPairW <: AbstractTwoQubitState + Ns::Float64 + gA::Float64 + gB::Float64 + eAm::Float64 + eBm::Float64 + eAs::Float64 + eBs::Float64 + eD::Float64 + Pd::Float64 + Pdo1::Float64 + Pdo2::Float64 + VisF::Float64 +end + +symbollabel(x::ZALMSpinPairW) = "ρᶻᵃˡᵐᵂ" + + +""" +$TYPEDEF + +Fields: + +$FIELDS + +Generate symbolic object for the normalized spin-spin density matrix for a cascaded source swapped with emissive spin memories. The cascaded source from papers [prajit2022heralded](@cite) and [kevin2023zero](@cite) is stored in spin memories as discussed in [prajit2023entangling](@cite). @@ -611,7 +663,17 @@ end symbollabel(x::ZALMSpinPair) = "ρᶻᵃˡᵐ" -function express_nolookup(x::ZALMSpinPair, ::QuantumOpticsRepr) +## express + +function express_nolookup(x::ZALMSpinPairW, ::QuantumOpticsRepr) data = cascaded_source_spin(x.Ns, x.gA, x.gB, x.eAm, x.eBm, x.eAs, x.eBs, x.eD, x.Pd, x.Pdo1, x.Pdo2, x.VisF) return SparseOperator(_bspin⊗_bspin, Complex.(data)) -end \ No newline at end of file +end + +function express_nolookup(x::ZALMSpinPair, ::QuantumOpticsRepr) + data = cascaded_source_spin(x.Ns, x.gA, x.gB, x.eAm, x.eBm, x.eAs, x.eBs, x.eD, x.Pd, x.Pdo1, x.Pdo2, x.VisF) + return SparseOperator(_bspin⊗_bspin, Complex.(data/tr(data))) +end + +## Symbolic trace +tr(::ZALMSpinPair) = 1 \ No newline at end of file diff --git a/test/test_stateszoo_api.jl b/test/test_stateszoo_api.jl index 9f0efa08..cd4ed1f7 100644 --- a/test/test_stateszoo_api.jl +++ b/test/test_stateszoo_api.jl @@ -1,15 +1,41 @@ using QuantumSavory -using QuantumSavory.StatesZoo: ZALMSpinPair, SingleRailMidSwapBell, DualRailMidSwapBell +using QuantumSavory.StatesZoo: ZALMSpinPairW, ZALMSpinPair, SingleRailMidSwapBellW, SingleRailMidSwapBell, DualRailMidSwapBellW, DualRailMidSwapBell +using QuantumOpticsBase using Test +zalmW = ZALMSpinPairW(1e-3, 0.5, 0.5, 1, 1, 1, 1, 0.9, 1e-8, 1e-8, 1e-8, 0.99) +zalm = ZALMSpinPair(1e-3, 0.5, 0.5, 1, 1, 1, 1, 0.9, 1e-8, 1e-8, 1e-8, 0.99) +srmsW = SingleRailMidSwapBellW(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99) +srms = SingleRailMidSwapBell(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99) +drmsW = DualRailMidSwapBellW(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99) +drms = DualRailMidSwapBell(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99) + +r_zalmW = Register(2) +initialize!(r_zalmW[1:2], zalmW) +@test ! iszero(observable(r_zalmW[1:2], Z⊗Z)) + r_zalm = Register(2) -initialize!(r_zalm[1:2], ZALMSpinPair(1e-3, 0.5, 0.5, 1, 1, 1, 1, 0.9, 1e-8, 1e-8, 1e-8, 0.99)) +initialize!(r_zalm[1:2], zalm) @test ! iszero(observable(r_zalm[1:2], Z⊗Z)) +r_srmsW = Register(2) +initialize!(r_srmsW[1:2], srmsW) +@test ! iszero(observable(r_srmsW[1:2], Z⊗Z)) + r_srms = Register(2) -initialize!(r_srms[1:2], SingleRailMidSwapBell(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99)) +initialize!(r_srms[1:2], srms) @test ! iszero(observable(r_srms[1:2], Z⊗Z)) +r_drmsW = Register(2) +initialize!(r_drmsW[1:2], drmsW) +@test ! iszero(observable(r_drmsW[1:2], Z⊗Z)) + r_drms = Register(2) -initialize!(r_drms[1:2], DualRailMidSwapBell(0.9, 0.9, 0.5, 0.5, 1e-8, 0.99)) -@test ! iszero(observable(r_drms[1:2], Z⊗Z)) \ No newline at end of file +initialize!(r_drms[1:2], drms) +@test ! iszero(observable(r_drms[1:2], Z⊗Z)) + +@test tr(zalm) == tr(express(zalm)) + +@test tr(srms) == tr(express(srms)) + +@test tr(drms) == tr(express(drms)) \ No newline at end of file