From 4bf3bfd0cc15c7e80e6a59f818459949dc78a08c Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sat, 22 Feb 2025 17:31:22 +0500 Subject: [PATCH 1/2] fix #38 - Implement two-mode summing unitary --- src/Gabs.jl | 2 +- src/unitaries.jl | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/Gabs.jl b/src/Gabs.jl index 217d903..fb04148 100644 --- a/src/Gabs.jl +++ b/src/Gabs.jl @@ -21,7 +21,7 @@ export vacuumstate, thermalstate, coherentstate, squeezedstate, eprstate, # predefined Gaussian channels displace, squeeze, twosqueeze, phaseshift, beamsplitter, - attenuator, amplifier, + attenuator, amplifier, twosumgate, # random objects randstate, randunitary, randchannel, randsymplectic, # wigner functions diff --git a/src/unitaries.jl b/src/unitaries.jl index c4a18a1..85f5f60 100644 --- a/src/unitaries.jl +++ b/src/unitaries.jl @@ -537,6 +537,105 @@ function _beamsplitter(basis::QuadBlockBasis{N}, transmit::R) where {N<:Int,R<:V return disp, symplectic end +""" +Constructs the **two-mode sum gate** (SUM gate), a fundamental operation +in continuous-variable quantum computing.The SUM gate applies a transformation +that displaces one oscillator's quadrature by an amount proportional to the +position quadrature of another oscillator. + +## Mathematical description of a two-mode sum gate + +For two oscillators `a` and `b`, the SUM gate is defined as: SUM(λ) = exp(-i 2λ ẋₐ p̂_b) +which transforms position eigenstates as: SUM(λ) |xₐ⟩ |x_b⟩ = |xₐ⟩ |x_b + λ xₐ⟩. + +The SUM gate can be realized using a [`beamsplitter`](@ref) and [`squeeze`](@ref), +following the *Bloch-Messiah decomposition*: + +```math +\begin{align} +\text{SUM}(\\lambda) &= \\text{BS}(\\pi + 2\\theta, -\\pi/2) \\left[ s(r) \\otimes s(-r) \\right] \text{BS}(2\\theta, -\\pi/2), \\ +\\sinh r &= \frac{\\lambda}{2}, \\ +\\cos(2\\theta) &= \\tanh(r), \\ +\\sin(2\\theta) &= -\\text{sech}(r) +\end{align} +``` + +where: +- `sinh(r) = λ / 2` (squeezing parameter), +- `cos(2θ) = tanh(r)`, `sin(2θ) = -sech(r)` (beam splitter angles). + +## Example + +```julia +julia> twosumgate(QuadBlockBasis(2), 1.0) +GaussianUnitary for 2 modes. + symplectic basis: QuadBlockBasis +displacement: 4-element Vector{Float64}: + 0.0 + 0.0 + 0.0 + 0.0 +symplectic: 4×4 Matrix{Float64}: + 0.17082 0.894427 0.0 0.0 + -0.894427 1.17082 0.0 0.0 + 0.0 0.0 1.17082 0.894427 + 0.0 0.0 -0.894427 0.17082 +``` + +""" +function twosumgate(::Type{Td}, ::Type{Ts}, basis::SymplecticBasis{N}, lambda::R; ħ = 2) where {Td,Ts,N<:Int,R<:Real} + disp, symplectic = _twosumgate(basis, lambda) + return GaussianUnitary(basis, Td(disp), Ts(symplectic); ħ = ħ) +end +twosumgate(::Type{T}, basis::SymplecticBasis{N}, lambda::R; ħ = 2) where {T,N<:Int,R} = twosumgate(T, T, basis, lambda; ħ = ħ) +function twosumgate(basis::SymplecticBasis{N}, lambda::R; ħ = 2) where {N<:Int,R<:Real} + disp, symplectic = _twosumgate(basis, lambda) + return GaussianUnitary(basis, disp, symplectic; ħ = ħ) +end +function _twosumgate(basis::QuadPairBasis{N}, lambda::R) where {N,R<:Real} + # Compute the squeezing parameter from sinh(r) = lambda/2 + r = asinh(lambda / 2) + # Determine the beam-splitter mixing angle: cos(2θ) = tanh(r), sin(2θ) = -sech(r) + twoθ = -acos(tanh(r)) + θ = twoθ / 2 + # First beam splitter: BS(2θ, -π/2) + transmit1 = cos(2θ)^2 + BS1 = _beamsplitter(basis, transmit1) + # Single-mode squeezing: S1 ⊗ S2 + S1 = squeeze(QuadPairBasis(basis.nmodes - 1), r, 0.0) + S2 = squeeze(QuadPairBasis(basis.nmodes - 1), -r, 0.0) + S_tensor = S1 ⊗ S2 + # Second beam splitter: BS(π+2θ, -π/2) + transmit2 = cos(π + 2θ)^2 + BS2 = _beamsplitter(basis, transmit2) + # Compose the operations + final_symplectic = BS2[2] * S_tensor.symplectic * BS1[2] + final_disp = BS2[1] + S_tensor.disp + BS1[1] + return final_disp, final_symplectic +end + +function _twosumgate(basis::QuadBlockBasis{N}, lambda::R) where {N,R<:Real} + # Compute the squeezing parameter from sinh(r) = lambda/2 + r = asinh(lambda / 2) + # Determine the beam-splitter mixing angle: cos(2θ) = tanh(r), sin(2θ) = -sech(r) + twoθ = -acos(tanh(r)) + θ = twoθ / 2 + # First beam splitter: BS(2θ, -π/2) + transmit1 = cos(2θ)^2 + BS1 = _beamsplitter(basis, transmit1) + # Single-mode squeezing: S1 ⊗ S2 + S1 = squeeze(QuadPairBasis(basis.nmodes - 1), r, 0.0) + S2 = squeeze(QuadPairBasis(basis.nmodes - 1), -r, 0.0) + S_tensor = S1 ⊗ S2 + # Second beam splitter: BS(π+2θ, -π/2) + transmit2 = cos(π + 2θ)^2 + BS2 = _beamsplitter(basis, transmit2) + # Compose the operations + final_symplectic = BS2[2] * S_tensor.symplectic * BS1[2] + final_disp = BS2[1] + S_tensor.disp + BS1[1] + return final_disp, final_symplectic +end + ## # Operations on Gaussian unitaries ## From f1525fe336999fd528f2b8bbf613384d26445c42 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sun, 23 Feb 2025 21:53:23 +0500 Subject: [PATCH 2/2] improvements --- src/Gabs.jl | 2 +- src/unitaries.jl | 128 +++++++++++++++++------------------------------ 2 files changed, 47 insertions(+), 83 deletions(-) diff --git a/src/Gabs.jl b/src/Gabs.jl index fb04148..acbdb6e 100644 --- a/src/Gabs.jl +++ b/src/Gabs.jl @@ -21,7 +21,7 @@ export vacuumstate, thermalstate, coherentstate, squeezedstate, eprstate, # predefined Gaussian channels displace, squeeze, twosqueeze, phaseshift, beamsplitter, - attenuator, amplifier, twosumgate, + attenuator, amplifier, sum_gate, # random objects randstate, randunitary, randchannel, randsymplectic, # wigner functions diff --git a/src/unitaries.jl b/src/unitaries.jl index 85f5f60..61bca94 100644 --- a/src/unitaries.jl +++ b/src/unitaries.jl @@ -538,102 +538,66 @@ function _beamsplitter(basis::QuadBlockBasis{N}, transmit::R) where {N<:Int,R<:V end """ -Constructs the **two-mode sum gate** (SUM gate), a fundamental operation -in continuous-variable quantum computing.The SUM gate applies a transformation -that displaces one oscillator's quadrature by an amount proportional to the -position quadrature of another oscillator. - -## Mathematical description of a two-mode sum gate - -For two oscillators `a` and `b`, the SUM gate is defined as: SUM(λ) = exp(-i 2λ ẋₐ p̂_b) -which transforms position eigenstates as: SUM(λ) |xₐ⟩ |x_b⟩ = |xₐ⟩ |x_b + λ xₐ⟩. - -The SUM gate can be realized using a [`beamsplitter`](@ref) and [`squeeze`](@ref), -following the *Bloch-Messiah decomposition*: - -```math -\begin{align} -\text{SUM}(\\lambda) &= \\text{BS}(\\pi + 2\\theta, -\\pi/2) \\left[ s(r) \\otimes s(-r) \\right] \text{BS}(2\\theta, -\\pi/2), \\ -\\sinh r &= \frac{\\lambda}{2}, \\ -\\cos(2\\theta) &= \\tanh(r), \\ -\\sin(2\\theta) &= -\\text{sech}(r) -\end{align} -``` - -where: -- `sinh(r) = λ / 2` (squeezing parameter), -- `cos(2θ) = tanh(r)`, `sin(2θ) = -sech(r)` (beam splitter angles). - -## Example +Constructs the two-mode SUM gate as a Gaussian unitary operator. -```julia -julia> twosumgate(QuadBlockBasis(2), 1.0) +```jldoctest +julia> sum_gate(QuadPairBasis(2)) GaussianUnitary for 2 modes. - symplectic basis: QuadBlockBasis + symplectic basis: QuadPairBasis displacement: 4-element Vector{Float64}: 0.0 0.0 0.0 0.0 symplectic: 4×4 Matrix{Float64}: - 0.17082 0.894427 0.0 0.0 - -0.894427 1.17082 0.0 0.0 - 0.0 0.0 1.17082 0.894427 - 0.0 0.0 -0.894427 0.17082 + 1.0 0.0 0.0 0.0 + 0.0 1.0 0.0 -1.0 + 1.0 0.0 1.0 0.0 + 0.0 0.0 0.0 1.0 ``` - """ -function twosumgate(::Type{Td}, ::Type{Ts}, basis::SymplecticBasis{N}, lambda::R; ħ = 2) where {Td,Ts,N<:Int,R<:Real} - disp, symplectic = _twosumgate(basis, lambda) +function sum_gate(::Type{Td}, ::Type{Ts}, basis::SymplecticBasis{N}; ħ = 2) where {Td, Ts, N} + disp, symplectic = _sum_gate(basis) return GaussianUnitary(basis, Td(disp), Ts(symplectic); ħ = ħ) end -twosumgate(::Type{T}, basis::SymplecticBasis{N}, lambda::R; ħ = 2) where {T,N<:Int,R} = twosumgate(T, T, basis, lambda; ħ = ħ) -function twosumgate(basis::SymplecticBasis{N}, lambda::R; ħ = 2) where {N<:Int,R<:Real} - disp, symplectic = _twosumgate(basis, lambda) +function sum_gate(::Type{T}, basis::SymplecticBasis{N}; ħ = 2) where {T, N} + return sum_gate(T, T, basis; ħ = ħ) +end +function sum_gate(basis::SymplecticBasis{N}; ħ = 2) where {N} + disp, symplectic = _sum_gate(basis) return GaussianUnitary(basis, disp, symplectic; ħ = ħ) end -function _twosumgate(basis::QuadPairBasis{N}, lambda::R) where {N,R<:Real} - # Compute the squeezing parameter from sinh(r) = lambda/2 - r = asinh(lambda / 2) - # Determine the beam-splitter mixing angle: cos(2θ) = tanh(r), sin(2θ) = -sech(r) - twoθ = -acos(tanh(r)) - θ = twoθ / 2 - # First beam splitter: BS(2θ, -π/2) - transmit1 = cos(2θ)^2 - BS1 = _beamsplitter(basis, transmit1) - # Single-mode squeezing: S1 ⊗ S2 - S1 = squeeze(QuadPairBasis(basis.nmodes - 1), r, 0.0) - S2 = squeeze(QuadPairBasis(basis.nmodes - 1), -r, 0.0) - S_tensor = S1 ⊗ S2 - # Second beam splitter: BS(π+2θ, -π/2) - transmit2 = cos(π + 2θ)^2 - BS2 = _beamsplitter(basis, transmit2) - # Compose the operations - final_symplectic = BS2[2] * S_tensor.symplectic * BS1[2] - final_disp = BS2[1] + S_tensor.disp + BS1[1] - return final_disp, final_symplectic -end - -function _twosumgate(basis::QuadBlockBasis{N}, lambda::R) where {N,R<:Real} - # Compute the squeezing parameter from sinh(r) = lambda/2 - r = asinh(lambda / 2) - # Determine the beam-splitter mixing angle: cos(2θ) = tanh(r), sin(2θ) = -sech(r) - twoθ = -acos(tanh(r)) - θ = twoθ / 2 - # First beam splitter: BS(2θ, -π/2) - transmit1 = cos(2θ)^2 - BS1 = _beamsplitter(basis, transmit1) - # Single-mode squeezing: S1 ⊗ S2 - S1 = squeeze(QuadPairBasis(basis.nmodes - 1), r, 0.0) - S2 = squeeze(QuadPairBasis(basis.nmodes - 1), -r, 0.0) - S_tensor = S1 ⊗ S2 - # Second beam splitter: BS(π+2θ, -π/2) - transmit2 = cos(π + 2θ)^2 - BS2 = _beamsplitter(basis, transmit2) - # Compose the operations - final_symplectic = BS2[2] * S_tensor.symplectic * BS1[2] - final_disp = BS2[1] + S_tensor.disp + BS1[1] - return final_disp, final_symplectic +function _sum_gate(basis::QuadBlockBasis{N}) where {N<:Int} + nmodes = basis.nmodes + if nmodes != 2 + error("SUM gate is defined for 2-mode systems only.") + end + disp = zeros(Float64, 2 * nmodes) + symplectic = zeros(Float64, 2 * nmodes, 2 * nmodes) + symplectic[1, 1] = 1.0 + symplectic[2, 1] = 1.0 + symplectic[2, 2] = 1.0 + symplectic[3, 3] = 1.0 + symplectic[3, 4] = -1.0 + symplectic[4, 4] = 1.0 + return disp, symplectic +end +function _sum_gate(basis::QuadPairBasis{N}) where {N<:Int} + nmodes = basis.nmodes + if nmodes != 2 + error("SUM gate is defined for 2-mode systems only.") + end + disp = zeros(Float64, 2 * nmodes) + S = [1.0 0.0 0.0 0.0; + 1.0 1.0 0.0 0.0; + 0.0 0.0 1.0 -1.0; + 0.0 0.0 0.0 1.0] + P = [1.0 0.0 0.0 0.0; + 0.0 0.0 1.0 0.0; + 0.0 1.0 0.0 0.0; + 0.0 0.0 0.0 1.0] + symplectic = P * S * P' + return disp, symplectic end ##