Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bloch-Messiah decomposition #37

Merged
merged 1 commit into from
Jan 25, 2025
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# News

## v1.2.7 - 2025-01-25

- Use `blochmessiah` decomposition from SymplecticFactorizations.jl.

## v1.2.6 - 2025-01-14

- Add `changebasis` for changing symplectic bases of Gaussian types.
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Gabs"
uuid = "0eb812ee-a11f-4f5e-b8d4-bb8a44f06f50"
authors = ["Andrew Kille"]
version = "1.2.6"
version = "1.2.7"

[deps]
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
Expand All @@ -23,7 +23,7 @@ LinearAlgebra = "1.9"
Makie = "0.21, 0.22"
QuantumInterface = "0.3.4"
StaticArrays = "1.9.7"
SymplecticFactorizations = "0.1.1"
SymplecticFactorizations = "0.1.4"
julia = "1.6.7, 1.10.0"

[extras]
Expand Down
5 changes: 4 additions & 1 deletion docs/src/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,11 +452,14 @@ symplectic: 4×4 Matrix{Float64}:
0.0 0.0 -0.479426 0.877583
```
Various symplectic decompositions are supported in Gabs through the symplectic linear algebra package [SymplecticFactorizations.jl](https://github.com/apkille/SymplecticFactorizations.jl). Particularly important
ones are the Williamson decomposition ([`williamson`](@ref)) and symplectic polar decomposition ([`polar`](@ref)):
ones are the Williamson decomposition ([`williamson`](@ref)), Bloch-Messiah/Euler decomposition ([`blochmessiah`](@ref)), and the symplectic polar decomposition ([`polar`](@ref)):
```@docs; canonical = false
williamson
```
```@docs; canonical = false
blochmessiah
```
```@docs; canonical = false
polar
```
Let's see an example with the Williamson decomposition:
Expand Down
6 changes: 3 additions & 3 deletions src/Gabs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ using LinearAlgebra: I, det, mul!, diagm, diag, qr, eigvals

import QuantumInterface: StateVector, AbstractOperator, apply!, tensor, ⊗, directsum, ⊕

import SymplecticFactorizations: williamson, Williamson, polar, Polar, randsymplectic, symplecticform, issymplectic
using SymplecticFactorizations: williamson, Williamson, polar, Polar, BlockForm, PairForm
import SymplecticFactorizations: williamson, Williamson, polar, Polar, blochmessiah, BlochMessiah, randsymplectic, symplecticform, issymplectic
using SymplecticFactorizations: williamson, Williamson, polar, Polar, blochmessiah, BlochMessiah, BlockForm, PairForm

export
# types
Expand All @@ -29,7 +29,7 @@ export
# symplectic form and checks
symplecticform, issymplectic, isgaussian, sympspectrum,
# factorizations
williamson, Williamson, polar, Polar,
williamson, Williamson, polar, Polar, blochmessiah, BlochMessiah,
# metrics
purity

Expand Down
27 changes: 20 additions & 7 deletions src/factorizations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
williamson(state::GaussianState) -> Williamson

Compute the williamson decomposition of the `covar` field
of a `Gaussian state` object and return a `Williamson` object.
of a `GaussianState` object and return a `Williamson` object.

A symplectic matrix `S` and symplectic spectrum `spectrum` can be obtained
via `F.S` and `F.spectrum`.
Expand All @@ -21,22 +21,35 @@ function williamson(x::GaussianState{<:QuadPairBasis,M,V}) where {M,V}
end

"""
polar(state::GaussianState) -> Polar
polar(state::GaussianUnitary) -> Polar

Compute the Polar decomposition of the `symplectic` field
of a `Gaussian unitary` object and return a `Polar` object.
of a `GaussianUnitary` object and return a `Polar` object.

`O` and `P` can be obtained from the factorization `F` via `F.O` and `F.P`, such that `S = O * P`.
For the symplectic polar decomposition case, `O` is an orthogonal symplectic matrix and `P` is a positive-definite
symmetric symplectic matrix.

Iterating the decomposition produces the components `O` and `P`.
"""
function polar(x::GaussianUnitary{<:QuadBlockBasis,D,S}) where {D,S}
polar(x::GaussianUnitary{B,D,S}) where {B<:SymplecticBasis,D,S} = polar(x.symplectic)

"""
blochmessiah(state::GaussianUnitary) -> BlochMessiah

Compute the Bloch-Messiah/Euler decomposition of the `symplectic` field
of a `GaussianUnitary` and return a `BlockMessiah` object.

The orthogonal symplectic matrices `O` and `Q` as well as the singular values `values` can be obtained
via `F.O`, `F.Q`, and `F.values`, respectively.

Iterating the decomposition produces the components `O`, `values`, and `Q`, in that order.
"""
function blochmessiah(x::GaussianUnitary{<:QuadBlockBasis,D,S}) where {D,S}
basis = x.basis
return polar(x.symplectic)
return blochmessiah(BlockForm(basis.nmodes), x.symplectic)
end
function polar(x::GaussianUnitary{<:QuadPairBasis,D,S}) where {D,S}
function blochmessiah(x::GaussianUnitary{<:QuadPairBasis,D,S}) where {D,S}
basis = x.basis
return polar(x.symplectic)
return blochmessiah(PairForm(basis.nmodes), x.symplectic)
end
29 changes: 29 additions & 0 deletions test/test_factorizations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,33 @@
@test isapprox(P_block, transpose(P_block), atol = 1e-5) && all(i > 0 for i in eigvals(P_block))
@test isapprox(P_pair, transpose(P_pair), atol = 1e-5) && all(i > 0 for i in eigvals(P_pair))
end

@testset "Bloch-Messiah/Euler" begin
nmodes = rand(1:5)
qpairbasis = QuadPairBasis(nmodes)
qblockbasis = QuadBlockBasis(nmodes)

uni_pair = randunitary(qpairbasis)
S_pair = uni_pair.symplectic
uni_block = randunitary(qblockbasis)
S_block = uni_block.symplectic

F_pair = blochmessiah(uni_pair)
O_pair, vals_pair, Q_pair = F_pair
F_block = blochmessiah(uni_block)
O_block, vals_block, Q_block = F_block

@test F_block.O == O_block && F_block.values == vals_block && F_block.Q == Q_block
@test F_pair.O == O_pair && F_pair.values == vals_pair && F_pair.Q == Q_pair
@test issymplectic(qpairbasis, O_pair, atol = 1e-5) && issymplectic(qblockbasis, O_block, atol = 1e-5)
@test issymplectic(qpairbasis, Q_pair, atol = 1e-5) && issymplectic(qblockbasis, Q_block, atol = 1e-5)
@test isapprox(inv(O_pair), transpose(O_pair), atol = 1e-5) && isapprox(inv(O_block), transpose(O_block), atol = 1e-5)
@test isapprox(inv(Q_pair), transpose(Q_pair), atol = 1e-5) && isapprox(inv(Q_block), transpose(Q_block), atol = 1e-5)

@test all(x -> x > 0.0, vals_block) && all(x -> x > 0.0, vals_pair)
D_block = Diagonal(vcat(vals_block, vals_block .^ (-1)))
D_pair = Diagonal(collect(Iterators.flatten(zip(vals_pair, vals_pair .^ (-1)))))
@test isapprox(O_block * D_block * Q_block, S_block, atol = 1e-5)
@test isapprox(O_pair * D_pair * Q_pair, S_pair, atol = 1e-5)
end
end
Loading