Skip to content

Commit

Permalink
Introduce random functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
kellertuer committed Jan 19, 2024
1 parent 0d7fb13 commit dc6b37b
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 74 deletions.
11 changes: 11 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ 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.x]

### Fixed

* a bug that cause `project` for tangent vectors to return wrong results on `MultinomialDoublyStochastic`

### Added

* the new manifold of `MultinomialSymmetricPositiveDefinite` matrices
* `rand!` for `MultinomialDoublyStochastic` and `MultinomialSymmetric`

## [0.9.11] – 2023-12-27

### Fixed
Expand Down
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ makedocs(;
"Multinomial doubly stochastic matrices" => "manifolds/multinomialdoublystochastic.md",
"Multinomial matrices" => "manifolds/multinomial.md",
"Multinomial symmetric matrices" => "manifolds/multinomialsymmetric.md",
"Multinomial symmetric positive definite matrices" => "manifolds/multinomialsymmetricpositivedefinite.md",
"Oblique manifold" => "manifolds/oblique.md",
"Probability simplex" => "manifolds/probabilitysimplex.md",
"Positive numbers" => "manifolds/positivenumbers.md",
Expand Down
5 changes: 5 additions & 0 deletions docs/src/manifolds/multinomialdoublystochastic.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ Order = [:type, :function]
```

## Literature

```@bibliography
Pages = ["multinomialdoublystochastic.md"]
Canonical=false
```
5 changes: 5 additions & 0 deletions docs/src/manifolds/multinomialsymmetric.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ Order = [:type, :function]
```

## Literature

```@bibliography
Pages = ["multinomialsymmetric.md"]
Canonical=false
```
14 changes: 14 additions & 0 deletions docs/src/manifolds/multinomialsymmetricpositivedefinite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Multinomial symmetric positive definite matrices

```@autodocs
Modules = [Manifolds]
Pages = ["manifolds/MultinomialSymmetricPoitiveDefinite.jl"]
Order = [:type, :function]
```

## Literature

```@bibliography
Pages = ["multinomialsymmetricpositivedefinite.md"]
Canonical=false
```
1 change: 1 addition & 0 deletions docs/src/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ @article{DouikHassibi:2019
TITLE = {Manifold Optimization Over the Set of Doubly Stochastic Matrices: A Second-Order Geometry},
JOURNAL = {IEEE Transactions on Signal Processing}
}

#
# E
# ----------------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/Manifolds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ include("manifolds/GeneralizedStiefel.jl")
include("manifolds/Hyperbolic.jl")
include("manifolds/MultinomialDoublyStochastic.jl")
include("manifolds/MultinomialSymmetric.jl")
include("manifolds/MultinomialSymmetricPoitiveDefinite.jl")
include("manifolds/PositiveNumbers.jl")
include("manifolds/ProjectiveSpace.jl")
include("manifolds/SkewHermitian.jl")
Expand Down
5 changes: 4 additions & 1 deletion src/manifolds/Multinomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ The multinomial manifold consists of `m` column vectors, where each column is of
`n` and unit norm, i.e.
````math
\mathcal{MN}(n,m) \coloneqq \bigl\{ p ∈ ℝ^{n×m}\ \big|\ p_{i,j} > 0 \text{ for all } i=1,…,n, j=1,…,m \text{ and } p^{\mathrm{T}}\mathbb{1}_m = \mathbb{1}_n\bigr\},
\mathcal{MN}(n,m) \coloneqq \bigl\{
p ∈ ℝ^{n×m}\ \big|\ p_{i,j} > 0 \text{ for all } i=1,…,n, j=1,…,m
\text{ and } p^{\mathrm{T}}\mathbb{1}_m = \mathbb{1}_n\bigr\},
````
where $\mathbb{1}_k$ is the vector of length $k$ containing ones.
This yields exactly the same metric as
Expand Down
102 changes: 62 additions & 40 deletions src/manifolds/MultinomialDoublyStochastic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
A common type for manifolds that are doubly stochastic, for example by direct constraint
[`MultinomialDoubleStochastic`](@ref) or by symmetry [`MultinomialSymmetric`](@ref),
or additionally by positife definiteness [`MultinomialSymmetricPoitiveDefinite`](@ref)
as long as they are also modeled as [`IsIsometricEmbeddedManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/decorator.html#ManifoldsBase.IsIsometricEmbeddedManifold).
"""
abstract type AbstractMultinomialDoublyStochastic <: AbstractDecoratorManifold{ℝ} end
Expand All @@ -14,8 +15,9 @@ end
@doc raw"""
MultinomialDoublyStochastic{T} <: AbstractMultinomialDoublyStochastic
The set of doubly stochastic multinomial matrices consists of all $n×n$ matrices with
The set of doubly stochastic multinomial matrices consists of all ``n×n`` matrices with
stochastic columns and rows, i.e.
````math
\begin{aligned}
\mathcal{DP}(n) \coloneqq \bigl\{p ∈ ℝ^{n×n}\ \big|\ &p_{i,j} > 0 \text{ for all } i=1,…,n, j=1,…,m,\\
Expand All @@ -24,7 +26,7 @@ stochastic columns and rows, i.e.
\end{aligned}
````
where $\mathbf{1}_n$ is the vector of length $n$ containing ones.
where ``\mathbf{1}_n`` is the vector of length ``n`` containing ones.
The tangent space can be written as
Expand All @@ -35,15 +37,15 @@ X\mathbf{1}_n = X^{\mathrm{T}}\mathbf{1}_n = \mathbf{0}_n
\bigr\},
````
where $\mathbf{0}_n$ is the vector of length $n$ containing zeros.
where ``\mathbf{0}_n`` is the vector of length ``n`` containing zeros.
More details can be found in Section III [DouikHassibi:2019](@cite).
# Constructor
MultinomialDoubleStochastic(n::Int; parameter::Symbol=:type)
Generate the manifold of matrices $\mathbb R^{n×n}$ that are doubly stochastic and symmetric.
Generate the manifold of matrices ``\mathbb R^{n×n}`` that are doubly stochastic and symmetric.
"""
struct MultinomialDoubleStochastic{T} <: AbstractMultinomialDoublyStochastic
size::T
Expand All @@ -60,21 +62,12 @@ end
Checks whether `p` is a valid point on the [`MultinomialDoubleStochastic`](@ref)`(n)` `M`,
i.e. is a matrix with positive entries whose rows and columns sum to one.
"""
function check_point(
M::MultinomialDoubleStochastic,
p::T;
atol::Real=sqrt(prod(representation_size(M))) * eps(real(float(number_eltype(T)))),
kwargs...,
) where {T}
function check_point(M::MultinomialDoubleStochastic, p::T; kwargs...) where {T}

Check warning on line 65 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L65

Added line #L65 was not covered by tests
n = get_parameter(M.size)[1]
r = sum(p, dims=2)
if !isapprox(norm(r - ones(n, 1)), 0.0; atol=atol, kwargs...)
return DomainError(
r,
"The point $(p) does not lie on $M, since its rows do not sum up to one.",
)
end
return nothing
s = check_point(MultinomialMatrices(n, n), p; kwargs...)
isnothing(s) && return s
s2 = check_point(MultinomialMatrices(n, n), p'; kwargs...)
return s2

Check warning on line 70 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L67-L70

Added lines #L67 - L70 were not covered by tests
end
@doc raw"""
check_vector(M::MultinomialDoubleStochastic p, X; kwargs...)
Expand All @@ -83,21 +76,11 @@ Checks whether `X` is a valid tangent vector to `p` on the [`MultinomialDoubleSt
This means, that `p` is valid, that `X` is of correct dimension and sums to zero along any
column or row.
"""
function check_vector(
M::MultinomialDoubleStochastic,
p,
X::T;
atol::Real=sqrt(prod(representation_size(M))) * eps(real(float(number_eltype(T)))),
kwargs...,
) where {T}
r = sum(X, dims=2) # check for stochastic rows
if !isapprox(norm(r), 0.0; atol=atol, kwargs...)
return DomainError(
r,
"The matrix $(X) is not a tangent vector to $(p) on $(M), since its rows do not sum up to zero.",
)
end
return nothing
function check_vector(M::MultinomialDoubleStochastic, p, X::T; kwargs...) where {T}
s = check_vector(MultinomialMatrices(n, n), p, X; kwargs...)
isnothing(s) && return s
s2 = check_vector(MultinomialMatrices(n, n), p, X'; kwargs...)
return s

Check warning on line 83 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L79-L83

Added lines #L79 - L83 were not covered by tests
end

function get_embedding(::MultinomialDoubleStochastic{TypeParameter{Tuple{n}}}) where {n}
Expand Down Expand Up @@ -134,26 +117,30 @@ end
Project `Y` onto the tangent space at `p` on the [`MultinomialDoubleStochastic`](@ref) `M`, return the result in `X`.
The formula reads
````math
\operatorname{proj}_p(Y) = Y - (α\mathbf{1}_n^{\mathrm{T}} + \mathbf{1}_nβ^{\mathrm{T}}) ⊙ p,
````
where $⊙$ denotes the Hadamard or elementwise product and $\mathbb{1}_n$ is the vector of length $n$ containing ones.
The two vectors $α,β ∈ ℝ^{n×n}$ are computed as a solution (typically using the left pseudo inverse) of
where ``⊙`` denotes the Hadamard or elementwise product and ``\mathbb{1}_n`` is the vector of length ``n`` containing ones.
The two vectors ``α,β ∈ ℝ^{n×n}`` are computed as a solution (typically using the left pseudo inverse) of
````math
\begin{pmatrix} I_n & p\\p^{\mathrm{T}} & I_n \end{pmatrix}
\begin{pmatrix} α\\ β\end{pmatrix}
=
\begin{pmatrix} Y\mathbf{1}\\Y^{\mathrm{T}}\mathbf{1}\end{pmatrix},
````
where $I_n$ is the $n×n$ unit matrix and $\mathbf{1}_n$ is the vector of length $n$ containing ones.
where ``I_n`` is the ``n×n`` unit matrix and ``\mathbf{1}_n`` is the vector of length ``n`` containing ones.
"""
project(::MultinomialDoubleStochastic, ::Any, ::Any)

function project!(M::MultinomialDoubleStochastic, X, p, Y)
n = get_parameter(M.size)[1]
ζ = [I p; p I] \ [sum(Y, dims=2); sum(Y, dims=1)'] # Formula (25) from 1802.02628
return X .= Y .- (repeat(ζ[1:n], 1, 3) .+ repeat(ζ[(n + 1):end]', 3, 1)) .* p
ζ = [I p; p' I] \ [sum(Y, dims=2); sum(Y, dims=1)'] # Formula (25) from 1802.02628
return X .= Y .- (repeat(ζ[1:n], 1, n) .+ repeat(ζ[(n + 1):end]', n, 1)) .* p

Check warning on line 143 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L142-L143

Added lines #L142 - L143 were not covered by tests
end

@doc raw"""
Expand Down Expand Up @@ -206,11 +193,46 @@ function representation_size(M::MultinomialDoubleStochastic)
return (n, n)
end

@doc raw"""
rand(::MultinomialDoubleStochastic; vector_at=nothing, σ::Real=1.0, kwargs...)
Generate random points on the [`MultinomialDoubleStochastic`](@ref) manifold
or tangent vectors at the point `vector_at` if that is not `nothing`.
Let ``n×n`` denote the matrix dimension of the [`MultinomialDoubleStochastic`](@ref).
When `vector_at` is nothing, this is done by generating a random matrix`rand(n,n)`
with positive entries and projecting it onto the manifold. The `kwargs...` are
passed to this projection.
When `vector_at` is not `nothing`, a random matrix in the ambient space is generated
and projected onto the tangent space
"""
rand(::MultinomialDoubleStochastic; σ::Real=1.0)

function Random.rand!(

Check warning on line 213 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L213

Added line #L213 was not covered by tests
rng::AbstractRNG,
M::MultinomialDoubleStochastic,
pX;
vector_at=nothing,
σ::Real=one(real(eltype(pX))),
kwargs...,
)
rand!(rng, pX)
pX .*= σ
if vector_at === nothing
project!(M, pX, pX; kwargs...)

Check warning on line 224 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L221-L224

Added lines #L221 - L224 were not covered by tests
else
project!(M, pX, vector_at, pX)

Check warning on line 226 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L226

Added line #L226 was not covered by tests
end
return pX

Check warning on line 228 in src/manifolds/MultinomialDoublyStochastic.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/MultinomialDoublyStochastic.jl#L228

Added line #L228 was not covered by tests
end

@doc raw"""
retract(M::MultinomialDoubleStochastic, p, X, ::ProjectionRetraction)
compute a projection based retraction by projecting $p\odot\exp(X⨸p)$ back onto the manifold,
where $⊙,⨸$ are elementwise multiplication and division, respectively. Similarly, $\exp$
compute a projection based retraction by projecting ``p\odot\exp(X⨸p)`` back onto the manifold,
where ``⊙,⨸`` are elementwise multiplication and division, respectively. Similarly, ``\exp``
refers to the elementwise exponentiation.
"""
retract(::MultinomialDoubleStochastic, ::Any, ::Any, ::ProjectionRetraction)
Expand Down
Loading

0 comments on commit dc6b37b

Please sign in to comment.