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

Introduce proxes. #37

Merged
merged 15 commits into from
Dec 8, 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
12 changes: 12 additions & 0 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Check Changelog
on:
pull_request:

jobs:
Check-Changelog:
name: Check Changelog Action
runs-on: ubuntu-latest
steps:
- uses: tarides/changelog-check-action@v2
with:
changelog: Changelog.md
14 changes: 14 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Changelog

All notable changes to this Julia package 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.3.9] - December 8, 2023

### Added

* proximal map of the distance function, `prox_distance`, and its mutating variant, `prox_distance!`
* this changelog
* A GitHub Action to check that the Changelog is updated on every PR.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ManifoldDiff"
uuid = "af67fdf4-a580-4b9f-bbec-742ef357defd"
authors = ["Seth Axen <[email protected]>", "Mateusz Baran <[email protected]>", "Ronny Bergmann <[email protected]>"]
version = "0.3.8"
version = "0.3.9"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
26 changes: 22 additions & 4 deletions docs/make.jl
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
#!/usr/bin/env julia
#
#

if "--help" ∈ ARGS
println(
"""
docs/make.jl

Render the `ManifoldDiff.jl` documentation with optional arguments

Arguments
* `--help` - print this help and exit without rendering the documentation
* `--prettyurls` – toggle the prettyurls part to true (which is otherwise only true on CI)
""",
)
exit(0)
end
# (a) if docs is not the current active environment, switch to it
# (from https://github.com/JuliaIO/HDF5.jl/pull/1020/) 
if Base.active_project() != joinpath(@__DIR__, "Project.toml")
Expand All @@ -8,15 +26,15 @@ if Base.active_project() != joinpath(@__DIR__, "Project.toml")
Pkg.instantiate()
end

using ManifoldDiff, ManifoldsBase, ManifoldDiff
using ManifoldsBase, ManifoldDiff
using Documenter, DocumenterCitations
using FiniteDiff, ForwardDiff, ReverseDiff, FiniteDifferences, Zygote

bib = CitationBibliography(joinpath(@__DIR__, "src", "references.bib"); style = :alpha)
makedocs(;
format = Documenter.HTML(
prettyurls = get(ENV, "CI", nothing) == "true",
assets = ["assets/favicon.ico"],
format = Documenter.HTML(;
prettyurls = (get(ENV, "CI", nothing) == "true") || ("--prettyurls" ∈ ARGS),
assets = ["assets/favicon.ico", "assets/citations.css"],
),
modules = [
ManifoldDiff,
Expand Down
19 changes: 19 additions & 0 deletions docs/src/assets/citations.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* Taken from https://juliadocs.org/DocumenterCitations.jl/v1.2/styling/ */

.citation dl {
display: grid;
grid-template-columns: max-content auto; }
.citation dt {
grid-column-start: 1; }
.citation dd {
grid-column-start: 2;
margin-bottom: 0.75em; }
.citation ul {
padding: 0 0 2.25em 0;
margin: 0;
list-style: none;}
.citation ul li {
text-indent: -2.25em;
margin: 0.33em 0.5em 0.5em 2.25em;}
.citation ol li {
padding-left:0.75em;}
19 changes: 19 additions & 0 deletions docs/src/library.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,22 @@ Modules = [ManifoldDiff]
Pages = ["riemannian_diff.jl"]
Order = [:type, :function, :constant]
```

## Proximal Maps

Given a convex, lower semi-continuous function ``f\colon \mathcal M \to \mathbb R``, its proximal map is defined
for some ``λ>0`` as [Bacak:2014](@cite)

```math
\operatorname{prox}_{λf}(p) := \operatorname*{arg\,min}_{q\in\mathcal M} \frac{1}{2λ}d^2_{\mathcal M}(p,q) + f(q).
```

Another name for the proximal map is _resolvent_.
Intuitively this means to minimize the function ``f`` while at the same timme “staying close”
to the argument ``p``.

```@autodocs
Modules = [ManifoldDiff]
Pages = ["proximal_maps.jl"]
Order = [:type, :function, :constant]
```
27 changes: 25 additions & 2 deletions docs/src/references.bib
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
@book{AbsilMahonySepulchre:2008,
AUTHOR = {Absil, P.-A. and Mahony, R. and Sepulchre, R.},
DOI = {10.1515/9781400830244},
NOTE = {available online at [press.princeton.edu/chapters/absil/](http://press.princeton.edu/chapters/absil/)},
NOTE = {available online at \href{http://press.princeton.edu/chapters/absil/}{press.princeton.edu/chapters/absil/}},
PUBLISHER = {Princeton University Press},
TITLE = {Optimization Algorithms on Matrix Manifolds},
YEAR = {2008},
}

@article{Bacak:2014,
AUTHOR = {Bačák, M.},
DOI = {10.1137/140953393},
JOURNAL = {SIAM Journal on Optimization},
NUMBER = {3},
PAGES = {1542--1566},
TITLE = {Computing medians and means in Hadamard spaces},
VOLUME = {24},
YEAR = {2014}
}

@book{Boumal:2023,
TITLE = {An Introduction to Optimization on Smooth Manifolds},
AUTHOR = {Boumal, Nicolas},
Expand All @@ -14,7 +26,7 @@ @book{Boumal:2023
EDITION = {First},
PUBLISHER = {Cambridge University Press},
DOI = {10.1017/9781009166164},
URLDATE = {2023-07-13},
NOTE = {Homepage to the book: \href{https://www.nicolasboumal.net/book/index.html}{nicolasboumal.net/book/index.html}.},
ABSTRACT = {Optimization on Riemannian manifolds-the result of smooth geometry and optimization merging into one elegant modern framework-spans many areas of science and engineering, including machine learning, computer vision, signal processing, dynamical systems and scientific computing. This text introduces the differential geometry and Riemannian geometry concepts that will help students and researchers in applied mathematics, computer science and engineering gain a firm mathematical grounding to use these tools confidently in their research. Its charts-last approach will prove more intuitive from an optimizer's viewpoint, and all definitions and theorems are motivated to build time-tested optimization algorithms. Starting from first principles, the text goes on to cover current research on topics including worst-case complexity and geodesic convexity. Readers will appreciate the tricks of the trade for conducting research and for numerical implementations sprinkled throughout the book.},
ISBN = {978-1-00-916616-4}
}
Expand All @@ -28,4 +40,15 @@ @article{Zimmermann:2020
PAGES = {A2593-A2619},
YEAR = {2020},
DOI = {10.1137/19M1282878},
}

@article{WeinmannDemaretStorath:2014,
AUTHOR = {Weinmann, Andreas and Demaret, Laurent and Storath, Martin},
DOI = {10.1137/130951075},
JOURNAL = {SIAM Journal on Imaging Sciences},
NUMBER = {4},
PAGES = {2226--2257},
TITLE = {Total variation regularization for manifold-valued data},
VOLUME = {7},
YEAR = {2014}
}
1 change: 1 addition & 0 deletions src/ManifoldDiff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ include("derivatives.jl")
include("differentials.jl")
include("gradients.jl")
include("Jacobi_fields.jl")
include("proximal_maps.jl")
include("subgradients.jl")

include("riemannian_diff.jl")
Expand Down
50 changes: 50 additions & 0 deletions src/proximal_maps.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@doc raw"""
y = prox_distance(M::AbstractManifold, λ::Real, p_data, p [, r=2])
prox_distance!(M::AbstractManifold, q, λ::Real, p_data, p [, r=2])

Compute the proximal map ``\operatorname{prox}_{λf}`` with
parameter λ of ``f(p) = \frac{1}{r}d_{\mathcal M}^r(p_{\mathrm{data}},p)``.
For the in-place variant the computation is done in place of `q`.

# Input
* `M` a manifold `M`
* `λ` the prox parameter, a positive real number.
* `p_data` a point on `M`.
* `p` the argument of the proximal map
* `r` (`2`) exponent of the distance.

# Output
* `q` – the result of the proximal map of ``f``

For more details see [WeinmannDemaretStorath:2014](@cite)
kellertuer marked this conversation as resolved.
Show resolved Hide resolved
"""
function prox_distance(M::AbstractManifold, λ::Real, p_data, p, r::Int = 2)
d = distance(M, p_data, p)
if r == 2
t = λ / (1 + λ)
elseif r == 1
t = (λ < d) ? λ / d : 1.0
else
throw(
ErrorException(
"Proximal Map of distance(M, p_data, p) not implemented for an exponent $(r) (requires 1 or 2)",
),
)
end
return shortest_geodesic(M, p, p_data, t)
end
function prox_distance!(M::AbstractManifold, q, λ::Real, p_data, p, r::Int = 2)
d = distance(M, p_data, p)
if r == 2
t = λ / (1 + λ)
elseif r == 1
t = (λ < d) ? λ / d : 1.0
else
throw(
ErrorException(
"Proximal Map of distance(M, p_data, p) not implemented for an exponent $(r) (requires 1 or 2)",
),
)
end
return shortest_geodesic!(M, q, p, p_data, t)
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ using RecursiveArrayTools
include("manifold_specializations.jl")
include("test_gradients.jl")
include("test_derivatives.jl")
include("test_proximal_maps.jl")
include("test_subgradients.jl")
end
26 changes: 26 additions & 0 deletions test/test_proximal_maps.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Manifolds, ManifoldDiff, Test

@testset "proximal maps" begin
#
# Distance
p = [1.0, 0.0, 0.0]
q = [0.0, 1.0, 0.0]
M = Sphere(2)
# Error for r != 1 or 2
@test_throws ErrorException ManifoldDiff.prox_distance(M, 1.0, p, q, 3)
@test_throws ErrorException ManifoldDiff.prox_distance!(M, p, 1.0, p, q, 3)
# r = 1
@test distance(
M,
ManifoldDiff.prox_distance(M, distance(M, p, q) / 2, p, q, 1),
shortest_geodesic(M, p, q, 0.5),
) < eps()
t = similar(p)
ManifoldDiff.prox_distance!(M, t, distance(M, p, q) / 2, p, q, 1)
@test t == ManifoldDiff.prox_distance(M, distance(M, p, q) / 2, p, q, 1)
# r = 2
ManifoldDiff.prox_distance!(M, t, 1.0, p, q, 2)
@test t == ManifoldDiff.prox_distance(M, 1.0, p, q, 2)
@test t == ManifoldDiff.prox_distance(M, 1.0, p, q) # 2 is also the default
@test distance(M, t, shortest_geodesic(M, p, q, 0.5)) ≈ 0 atol = 1e-15
end
Loading