Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4ad8251
Add warm start to CRPG backtracking
hajg-ijk Jul 10, 2025
f5cd266
Bump changelog
hajg-ijk Jul 10, 2025
93f78a7
Fix some math rendering in docs
hajg-ijk Jul 14, 2025
ee5adeb
Bump changelog
hajg-ijk Jul 14, 2025
e50d3a7
Add some references
hajg-ijk Jul 27, 2025
d4709af
Update changelog
hajg-ijk Jul 27, 2025
bba61fa
Merge branch 'master' into hajg-ijk/backtracking-warm-start
hajg-ijk Jul 30, 2025
19651ff
Update Changelog.md
hajg-ijk Jul 31, 2025
b0caf84
Update docs/src/references.bib
hajg-ijk Jul 31, 2025
926c5f2
Rephrase one doc line
hajg-ijk Aug 11, 2025
290cda0
Merge branch 'master' into hajg-ijk/backtracking-warm-start
hajg-ijk Aug 11, 2025
a72a2b6
Merge branch 'master' into hajg-ijk/backtracking-warm-start
hajg-ijk Oct 2, 2025
41f7ef9
Fallback for distance^2 in backtracking
hajg-ijk Oct 2, 2025
3e4217b
Correct fallback
hajg-ijk Oct 3, 2025
91defff
Bump changelog and version
hajg-ijk Oct 3, 2025
e4b303f
Attempt to cover missing line
hajg-ijk Oct 3, 2025
9e6cf8e
Cover last line
hajg-ijk Oct 3, 2025
6a0ce4f
Simplify fallback
hajg-ijk Oct 3, 2025
90fd2fc
Runic: Update test/solvers/test_proximal_gradient_method.jl
hajg-ijk Oct 3, 2025
df5e426
Runic: Update test/solvers/test_proximal_gradient_method.jl
hajg-ijk Oct 3, 2025
1112d96
Update Changelog.md
hajg-ijk Oct 4, 2025
af78254
Merge branch 'master' into hajg-ijk/backtracking-warm-start
Nov 16, 2025
45487d0
Cover one line in proximal_gradient_plan
Nov 16, 2025
d4c1da9
Format and changelog
Nov 16, 2025
d0962fb
Merge branch 'master' into hajg-ijk/backtracking-warm-start
May 18, 2026
c86e289
Update backtracking for positive curvature
May 19, 2026
9257fb5
Add test, bump project and changelog, format
May 19, 2026
8ec7dc6
Cover the last two lines
May 19, 2026
2868f2e
Fix project.toml formatting
hajg-ijk May 19, 2026
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
7 changes: 6 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ The file was started with Version `0.4`.
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.5.38] May 19, 2026

### Changed

* the `:convex` backtracking strategy for `proximal_gradient_method` now entails a slightly different condition whenever the upper bound on the sectional curvature of the manifold, input via the `k_max` kwarg, is positive. This comes with a "tolerance" type parameter, `δ`, which must be positive.

## [0.5.37] May 5, 2026

### Changed
Expand Down Expand Up @@ -99,7 +105,6 @@ so it can be easier reused by others as well (#550)
This also allows finally to run single test files without installing all packages manually, but instead just switching to and instantiating the test environment. (#550)
* for compatibility, state also `[source]` entries consistently in the sub `Project.toml` files. (#550)


## [0.5.28] November 17, 2025

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Manopt"
uuid = "0fc0a36d-df90-57f3-8f93-d78a9fc72bb5"
version = "0.5.37"
version = "0.5.38"
authors = [{family-names = "Bergmann", given-names = "Ronny", alias = "kellertuer", city = "Trondheim", affiliation = "Norwegian University of Science and Technology", country = "NO", email = "manopt@ronnybergmann.net", orcid = "https://orcid.org/0000-0001-8342-7218", website = "https://ronnybergmann.net"}]

[workspace]
Expand Down
20 changes: 18 additions & 2 deletions src/plans/proximal_gradient_plan.jl
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ A functor for backtracking line search in proximal gradient methods.
* `sufficient_decrease=0.5`: sufficient decrease parameter
* `contraction_factor=0.5`: step size reduction factor
* `strategy=:nonconvex`: backtracking strategy, either `:convex` or `:nonconvex`
* `k_max=0.0`: an upper bound to the sectional curvatures of the manifold, only for the `:convex` strategy
* `δ=1e-2`: parameter for backtracking in case `k_max > 0`, only for the `:convex` strategy
"""
mutable struct ProximalGradientMethodBacktrackingStepsize{P, T} <: Stepsize
initial_stepsize::T
Expand All @@ -413,6 +415,8 @@ mutable struct ProximalGradientMethodBacktrackingStepsize{P, T} <: Stepsize
last_stepsize::T
stop_when_stepsize_less::T
warm_start_factor::T
k_max::T
δ::T

function ProximalGradientMethodBacktrackingStepsize(
M::AbstractManifold;
Expand All @@ -422,6 +426,8 @@ mutable struct ProximalGradientMethodBacktrackingStepsize{P, T} <: Stepsize
strategy::Symbol = :nonconvex,
stop_when_stepsize_less::T = 1.0e-8,
warm_start_factor::T = 1.0,
k_max::T = 0.0,
δ::T = 1.0e-2,
) where {T}
0 < sufficient_decrease < 1 ||
throw(DomainError(sufficient_decrease, "sufficient_decrease must be in (0, 1)"))
Expand All @@ -439,6 +445,9 @@ mutable struct ProximalGradientMethodBacktrackingStepsize{P, T} <: Stepsize
warm_start_factor > 0 ||
throw(DomainError(warm_start_factor, "warm_start_factor must be positive"))

(k_max > 0 && δ ≤ 0) &&
throw(DomainError(δ, "the tolerance parameter δ must be positive if k_max > 0"))

p = rand(M)
return new{typeof(p), T}(
initial_stepsize,
Expand All @@ -449,6 +458,8 @@ mutable struct ProximalGradientMethodBacktrackingStepsize{P, T} <: Stepsize
initial_stepsize,
stop_when_stepsize_less,
warm_start_factor,
k_max,
δ
)
end
end
Expand All @@ -465,6 +476,8 @@ function Base.show(io::IO, pgb::ProximalGradientMethodBacktrackingStepsize)
sufficient_decrease=$(pgb.sufficient_decrease),
strategy=$(pgb.strategy),
warm_start_factor=$(pgb.warm_start_factor),
k_max=$(pgb.k_max),
δ=$(pgb.δ)
)
"""
return print(io, s)
Expand Down Expand Up @@ -522,8 +535,11 @@ function (s::ProximalGradientMethodBacktrackingStepsize)(
g_p = get_cost_smooth(M, objective, p)
g_q = get_cost_smooth(M, objective, candidate_point)


ζ_δ = s.k_max ≤ zero(eltype(s.k_max)) ? one(eltype(s.k_max)) : π / (2 + s.δ) * cot(π / (2 + s.δ))

# Convex descent condition
if g_q <= g_p + inner(M, p, X, log_p_q) + (1 / 2λ) * squared_distance
if g_q <= g_p + inner(M, p, X, log_p_q) + (ζ_δ / 2λ) * squared_distance
s.last_stepsize = λ
return λ
end
Expand Down Expand Up @@ -552,7 +568,7 @@ where ``G_{λ}(p) = (1/λ) * $(_tex(:log))_p(T_{λ}(p))`` is the gradient mappin
For the convex case, the condition is:

```math
g(T_{λ}(p)) ≤ g(p) + ⟨$(_tex(:grad)) g(p), $(_tex(:log))_p T_{λ}(p)⟩ + $(_tex(:frac, "1", "2λ")) $(_math(:distance))^2(p, T_{λ}(p))
g(T_{λ}(p)) ≤ g(p) + ⟨$(_tex(:grad)) g(p), $(_tex(:log))_p T_{λ}(p)⟩ + $(_tex(:frac, "ζ_δ", "2λ")) $(_math(:distance))^2(p, T_{λ}(p))
```

Returns a stepsize `λ` that satisfies the specified condition.
Expand Down
1 change: 1 addition & 0 deletions src/solvers/convex_bundle_method.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ function show(io::IO, cbms::ConvexBundleMethodState)
* bundle cap size: $(cbms.bundle_cap)
* current bundle size: $(length(cbms.bundle))
* curvature upper bound: $(cbms.k_max)
* curvature lower bound: $(cbms.k_min)
* descent test parameter: $(cbms.m)
* diameter: $(cbms.diameter)
* inverse retraction: $(cbms.inverse_retraction_method)
Expand Down
21 changes: 20 additions & 1 deletion test/solvers/test_proximal_gradient_method.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ using Manopt, Manifolds, Test, ManifoldDiff
# Trigger manually
sc1.at_iteration = 2
@test length(get_reason(sc1)) > 0

pgms.last_stepsize = 1.0
g(M, q) = distance(M, q, p)^2
grad_g(M, q) = -2 * log(M, q, p)
h(M, q) = distance(M, q, p)
prox_h(M, λ, q) = ManifoldDiff.prox_distance(M, λ, p, q, 1)
f(M, q) = g(M, q) + h(M, q)
ob = ManifoldProximalGradientObjective(f, g, grad_g, prox_h)
mp = DefaultManoptProblem(M, ob)

@test sc1.last_change < sc1.threshold
@test sc1.at_iteration == 2
@test sc1(mp, pgms, 2) == true
pgms.last_stepsize = 0.0
end
@testset "Proximal Gradient Backtracking" begin
pgb = Manopt.ProximalGradientMethodBacktrackingStepsize(M)
Expand Down Expand Up @@ -84,6 +98,9 @@ using Manopt, Manifolds, Test, ManifoldDiff
@test_throws DomainError Manopt.ProximalGradientMethodBacktrackingStepsize(
M; warm_start_factor = -1.0
)
@test_throws DomainError Manopt.ProximalGradientMethodBacktrackingStepsize(
M; initial_stepsize = 1.0, strategy = :convex, stop_when_stepsize_less = 2.0, k_max = 1.0, δ = -1.0
)

@testset "Backtracking Warnings" begin
dw1 = DebugWarnIfStepsizeCollapsed(:Once)
Expand Down Expand Up @@ -233,7 +250,9 @@ using Manopt, Manifolds, Test, ManifoldDiff
inverse_retraction_method = ProjectionInverseRetraction(),
stepsize = ProximalGradientMethodBacktracking(;
initial_stepsize = 1.0,
strategy = :convex
strategy = :convex,
k_max = 1.0,
δ = 1.0e-2,
),
return_state = true
)
Expand Down
Loading