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

Introduction of the orthographic retraction for the fixed rank manifold #662

Merged
merged 19 commits into from
Oct 25, 2023
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
5 changes: 5 additions & 0 deletions .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
"name": "Weiß, Manuel",
"type": "ProjectMember"
},
{
"affiliation": "Georg-August-University Göttingen",
"name": "Klingbiel, Lukas",
"type": "ProjectMember"
},
{
"affiliation": "NTNU Trondheim",
"name": "Kolstø, Johannes Voll",
Expand Down
12 changes: 9 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.9.0] - 2023-mm-dd
## [0.9.1] - 2023-10-25

### Added

- a new retraction and its inverse for the fixed Rank Manifolds, the orthographic retraction.

## [0.9.0] - 2023-10-24

### Added

Expand Down Expand Up @@ -57,7 +63,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `SymplecticStiefel{n,k}`,
- `TranslationGroup`,
- `Tucker`.

For example

```{julia}
Expand All @@ -84,7 +90,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
```

for groups with size stored in field. Alternatively, you can use a single generic method like this:

```{julia}
function Base.show(io::IO, M::CenteredMatrices{T}) where {T}
m, n = get_parameter(M)
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Manifolds"
uuid = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e"
authors = ["Seth Axen <[email protected]>", "Mateusz Baran <[email protected]>", "Ronny Bergmann <[email protected]>", "Antoine Levitt <[email protected]>"]
version = "0.9.0"
version = "0.9.1"

[deps]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Expand Down
23 changes: 22 additions & 1 deletion docs/src/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,28 @@ @incollection{AbsilMahonyTrumpf:2013
PUBLISHER = {Springer Berlin Heidelberg},
PAGES = {361--368},
TITLE = {An Extrinsic Look at the Riemannian Hessian},
BOOKTITLE = {Geometric Science of Information},
BOOKTITLE = {Geometric Science of Information}
}
@article{AbsilMalick:2012,
AUTHOR = {Absil, P.-A. and Malick, Jérôme},
TITLE = {Projection-like Retractions on Matrix Manifolds},
JOURNAL = {SIAM Journal on Optimization},
VOLUME = {22},
NUMBER = {1},
PAGES = {135-158},
YEAR = {2012},
DOI = {10.1137/100802529}
}
@article{AbsilOseledets:2014,
DOI = {10.1007/s10589-014-9714-4},
YEAR = {2014},
PUBLISHER = {Springer Science and Business Media LLC},
VOLUME = {62},
NUMBER = {1},
PAGES = {5--29},
AUTHOR = {P.-A. Absil and I. V. Oseledets},
TITLE = {Low-rank retractions: a survey and new results},
JOURNAL = {Computational Optimization and Applications}
}
@article{AfsariTronVidal:2013,
DOI = {10.1137/12086282x},
Expand Down
17 changes: 16 additions & 1 deletion ext/ManifoldsTestExt/tests_general.jl
Original file line number Diff line number Diff line change
Expand Up @@ -333,21 +333,36 @@
Test.@test isapprox(M, p2, q; atol=point_atol)
# This test is not reasonable for `inverse_retract!(M, X, p, q, m)`,
# since X is of different type/concept than p,q

end
end
end
for p in pts
epsx = find_eps(p)
for inv_retr_method in inverse_retraction_methods
X = inverse_retract(M, p, p, inv_retr_method)
Test.@test isapprox(
M,
p,
zero_vector(M, p),
inverse_retract(M, p, p, inv_retr_method);
X;
atol=epsx * retraction_atol_multiplier,
rtol=retraction_atol_multiplier == 0 ?
sqrt(epsx) * retraction_rtol_multiplier : 0,
)
if (test_inplace && is_mutating)
Y = copy(M, p, X)
inverse_retract!(M, Y, p, p, inv_retr_method)
Test.@test isapprox(

Check warning on line 356 in ext/ManifoldsTestExt/tests_general.jl

View check run for this annotation

Codecov / codecov/patch

ext/ManifoldsTestExt/tests_general.jl#L354-L356

Added lines #L354 - L356 were not covered by tests
M,
p,
zero_vector(M, p),
Y;
atol=epsx * retraction_atol_multiplier,
rtol=retraction_atol_multiplier == 0 ?
sqrt(epsx) * retraction_rtol_multiplier : 0,
)
end
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions src/Manifolds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ import ManifoldsBase:
representation_size,
retract,
retract!,
_retract,
retract!,
retract_cayley!,
retract_exp_ode!,
retract_pade!,
Expand Down Expand Up @@ -729,6 +731,7 @@ export AbstractRetractionMethod,
ProjectionRetraction,
SoftmaxRetraction,
ODEExponentialRetraction,
OrthographicRetraction,
PadeRetraction,
ProductRetraction,
SasakiRetraction
Expand All @@ -739,6 +742,7 @@ export AbstractInverseRetractionMethod,
CayleyInverseRetraction,
LogarithmicInverseRetraction,
QRInverseRetraction,
OrthographicInverseRetraction,
PolarInverseRetraction,
ProjectionInverseRetraction,
ShootingInverseRetraction,
Expand Down
134 changes: 134 additions & 0 deletions src/manifolds/FixedRankMatrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,67 @@
Base.:+(v::UMVTVector) = UMVTVector(v.U, v.M, v.Vt)
Base.:(==)(v::UMVTVector, w::UMVTVector) = (v.U == w.U) && (v.M == w.M) && (v.Vt == w.Vt)

# Move to Base when name is established – i.e. used in more than one manifold
# |/---
"""
OrthographicRetraction <: AbstractRetractionMethod

Retractions that are related to orthographic projections, which was first
used in [AbsilMalick:2012](@cite).
"""
struct OrthographicRetraction <: AbstractRetractionMethod end

"""
OrthographicInverseRetraction <: AbstractInverseRetractionMethod

Retractions that are related to orthographic projections, which was first
used in [AbsilMalick:2012](@cite).
"""
struct OrthographicInverseRetraction <: AbstractInverseRetractionMethod end

# Layer II
function _inverse_retract!(

Check warning on line 140 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L140

Added line #L140 was not covered by tests
M::AbstractManifold,
X,
p,
q,
::OrthographicInverseRetraction;
kwargs...,
)
return inverse_retract_orthographic!(M, X, p, q; kwargs...)

Check warning on line 148 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L148

Added line #L148 was not covered by tests
end

# Layer III
"""
inverse_retract_orthographic!(M::AbstractManifold, X, p, q)

Compute the in-place variant of the [`OrthographicInverseRetraction`](@ref).
"""
inverse_retract_orthographic!(M::AbstractManifold, X, p, q)

## Layer II
function _retract!(

Check warning on line 160 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L160

Added line #L160 was not covered by tests
M::AbstractManifold,
q,
p,
X,
t::Number,
::OrthographicRetraction;
kwargs...,
)
return retract_orthographic!(M, q, p, X, t; kwargs...)

Check warning on line 169 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L169

Added line #L169 was not covered by tests
end

## Layer III
"""
retract_orthographic!(M::AbstractManifold, q, p, X, t::Number)

Compute the in-place variant of the [`OrthographicRetraction`](@ref).
"""
retract_orthographic!(M::AbstractManifold, q, p, X, t::Number)

# \|---

allocate(p::SVDMPoint) = SVDMPoint(allocate(p.U), allocate(p.S), allocate(p.Vt))
function allocate(p::SVDMPoint, ::Type{T}) where {T}
return SVDMPoint(allocate(p.U, T), allocate(p.S, T), allocate(p.Vt, T))
Expand All @@ -127,6 +188,9 @@
return UMVTVector(allocate(X.U, T), allocate(X.M, T), allocate(X.Vt, T))
end

function allocate_result(M::FixedRankMatrices, ::typeof(inverse_retract), p, q)
return zero_vector(M, p)

Check warning on line 192 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L191-L192

Added lines #L191 - L192 were not covered by tests
end
function allocate_result(M::FixedRankMatrices, ::typeof(project), X, p, vals...)
m, n, k = get_parameter(M.size)
# vals are p and X, so we can use their fields to set up those of the UMVTVector
Expand Down Expand Up @@ -378,6 +442,31 @@
return dot(v.U, w.U) + dot(v.M, w.M) + dot(v.Vt, w.Vt)
end

@doc raw"""
inverse_retract(M, p, q, ::OrthographicInverseRetraction)

Compute the orthographic inverse retraction [`FixedRankMatrices`](@ref) `M` by computing

```math
X = P_{T_{p}M}(q - p) = qVV^\mathrm{T} + UU^{\mathrm{T}}q - UU^{\mathrm{T}}qVV^{\mathrm{T}} - p,
```
where ``p`` is a [`SVDMPoint`](@ref)`(U,S,Vt)` and ``P_{T_{p}M}`` is the [`project`](@ref)ion
onto the tangent space at ``p``.

For more details, see [AbsilOseledets:2014](@cite).
"""
inverse_retract(::FixedRankMatrices, ::Any, ::Any, ::OrthographicInverseRetraction)

function inverse_retract_orthographic!(

Check warning on line 460 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L460

Added line #L460 was not covered by tests
M::FixedRankMatrices,
X::UMVTVector,
p::SVDMPoint,
q::SVDMPoint,
)
project!(M, X, p, embed(M, q) - embed(M, p))
return X

Check warning on line 467 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L466-L467

Added lines #L466 - L467 were not covered by tests
end

function _isapprox(::FixedRankMatrices, p::SVDMPoint, q::SVDMPoint; kwargs...)
return isapprox(p.U * Diagonal(p.S) * p.Vt, q.U * Diagonal(q.S) * q.Vt; kwargs...)
end
Expand Down Expand Up @@ -523,6 +612,51 @@
return (m, n)
end

@doc raw"""
retract(M::FixedRankMatrices, p, X, ::OrthographicRetraction)

Compute the OrthographicRetraction on the [`FixedRankMatrices`](@ref) `M` by finding
the nearest point to ``p + X`` in

```math
p + X + N_{p}\mathcal M \cap \mathcal M
```

where ``N_{p}\mathcal M `` is the Normal Space of ``T_{p}\mathcal M ``.

If ``X`` is sufficiently small, then the nearest such point is unique and can be expressed by

```math
q = (U(S + M) + U_{p})(S + M)^{-1}((S + M)V^{\mathrm{T}} + V^{\mathrm{T}}_{p}),
mateuszbaran marked this conversation as resolved.
Show resolved Hide resolved
```

where ``p`` is a [`SVDMPoint`](@ref)`(U,S,Vt)` and ``X`` is an [`UMVTVector`](@ref)`(Up,M,Vtp)`.

For more details, see [AbsilOseledets:2014](@cite).
"""
retract(::FixedRankMatrices, ::Any, ::Any, ::OrthographicRetraction)

function retract_orthographic!(

Check warning on line 639 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L639

Added line #L639 was not covered by tests
M::FixedRankMatrices,
q::SVDMPoint,
p::SVDMPoint,
X::UMVTVector,
t::Number,
)
m, n, k = get_parameter(M.size)
tX = t * X
QU, RU = qr(p.U * (diagm(p.S) + tX.M) + tX.U)
QV, RV = qr(p.Vt' * (diagm(p.S) + tX.M') + tX.Vt')

Check warning on line 649 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L646-L649

Added lines #L646 - L649 were not covered by tests

Uk, Sk, Vtk = svd(RU * inv(diagm(p.S) + tX.M) * RV')

Check warning on line 651 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L651

Added line #L651 was not covered by tests

mul!(q.U, QU[:, 1:k], Uk)
q.S .= Sk[1:k]
mul!(q.Vt, Vtk, QV[:, 1:k]')

Check warning on line 655 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L653-L655

Added lines #L653 - L655 were not covered by tests

return q

Check warning on line 657 in src/manifolds/FixedRankMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/FixedRankMatrices.jl#L657

Added line #L657 was not covered by tests
end

@doc raw"""
retract(M, p, X, ::PolarRetraction)

Expand Down
3 changes: 2 additions & 1 deletion test/manifolds/fixed_rank.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ include("../utils.jl")
test_vee_hat=false,
test_tangent_vector_broadcasting=true,
projection_atol_multiplier=15,
retraction_methods=[PolarRetraction()],
retraction_methods=[PolarRetraction(), OrthographicRetraction()],
inverse_retraction_methods=[OrthographicInverseRetraction()],
vector_transport_methods=[ProjectionTransport()],
vector_transport_retractions=[PolarRetraction()],
vector_transport_inverse_retractions=[PolarInverseRetraction()],
Expand Down
Loading