Skip to content

Commit 89855a4

Browse files
committed
Add wrapper for SpeedMapping
1 parent d723578 commit 89855a4

13 files changed

+215
-6
lines changed

Project.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "NonlinearSolve"
22
uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
33
authors = ["SciML"]
4-
version = "3.1.2"
4+
version = "3.2.0"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -32,18 +32,22 @@ UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
3232
[weakdeps]
3333
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
3434
FastLevenbergMarquardt = "7a0df574-e128-4d35-8cbd-3d84502bf7ce"
35+
FixedPointAcceleration = "817d07cb-a79a-5c30-9a31-890123675176"
3536
LeastSquaresOptim = "0fc2ff8b-aaa3-5acd-a817-1944a5e08891"
3637
MINPACK = "4854310b-de5a-5eb6-a2a5-c1dee2bd17f9"
3738
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
39+
SpeedMapping = "f1835b91-879b-4a3f-a438-e4baacf14412"
3840
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
3941
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
4042

4143
[extensions]
4244
NonlinearSolveBandedMatricesExt = "BandedMatrices"
4345
NonlinearSolveFastLevenbergMarquardtExt = "FastLevenbergMarquardt"
46+
NonlinearSolveFixedPointAccelerationExt = "FixedPointAcceleration"
4447
NonlinearSolveLeastSquaresOptimExt = "LeastSquaresOptim"
4548
NonlinearSolveMINPACKExt = "MINPACK"
4649
NonlinearSolveNLsolveExt = "NLsolve"
50+
NonlinearSolveSpeedMappingExt = "SpeedMapping"
4751
NonlinearSolveSymbolicsExt = "Symbolics"
4852
NonlinearSolveZygoteExt = "Zygote"
4953

@@ -60,6 +64,7 @@ Enzyme = "0.11.11"
6064
FastBroadcast = "0.2.8"
6165
FastLevenbergMarquardt = "0.1"
6266
FiniteDiff = "2.21"
67+
FixedPointAcceleration = "0.3"
6368
ForwardDiff = "0.10.36"
6469
LazyArrays = "1.8.2"
6570
LeastSquaresOptim = "0.8.5"
@@ -84,6 +89,7 @@ SciMLOperators = "0.3.7"
8489
SimpleNonlinearSolve = "1.0.2"
8590
SparseArrays = "<0.0.1, 1"
8691
SparseDiffTools = "2.14"
92+
SpeedMapping = "0.3"
8793
StableRNGs = "1"
8894
StaticArrays = "1.7"
8995
Symbolics = "5.13"
@@ -99,6 +105,7 @@ BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
99105
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
100106
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
101107
FastLevenbergMarquardt = "7a0df574-e128-4d35-8cbd-3d84502bf7ce"
108+
FixedPointAcceleration = "817d07cb-a79a-5c30-9a31-890123675176"
102109
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
103110
LeastSquaresOptim = "0fc2ff8b-aaa3-5acd-a817-1944a5e08891"
104111
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -112,11 +119,12 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
112119
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
113120
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
114121
SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
122+
SpeedMapping = "f1835b91-879b-4a3f-a438-e4baacf14412"
115123
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
116124
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
117125
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
118126
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
119127
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
120128

121129
[targets]
122-
test = ["Aqua", "Enzyme", "BenchmarkTools", "SafeTestsets", "Pkg", "Test", "ForwardDiff", "StaticArrays", "Symbolics", "LinearSolve", "Random", "LinearAlgebra", "Zygote", "SparseDiffTools", "NonlinearProblemLibrary", "LeastSquaresOptim", "FastLevenbergMarquardt", "NaNMath", "BandedMatrices", "DiffEqBase", "StableRNGs", "MINPACK", "NLsolve", "OrdinaryDiffEq"]
130+
test = ["Aqua", "Enzyme", "BenchmarkTools", "SafeTestsets", "Pkg", "Test", "ForwardDiff", "StaticArrays", "Symbolics", "LinearSolve", "Random", "LinearAlgebra", "Zygote", "SparseDiffTools", "NonlinearProblemLibrary", "LeastSquaresOptim", "FastLevenbergMarquardt", "NaNMath", "BandedMatrices", "DiffEqBase", "StableRNGs", "MINPACK", "NLsolve", "OrdinaryDiffEq", "SpeedMapping", "FixedPointAcceleration"]

docs/pages.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pages = ["index.md",
2020
"solvers/BracketingSolvers.md",
2121
"solvers/SteadyStateSolvers.md",
2222
"solvers/NonlinearLeastSquaresSolvers.md",
23+
"solvers/FixedPointSolvers.md",
2324
"solvers/LineSearch.md"],
2425
"Detailed Solver APIs" => Any["api/nonlinearsolve.md",
2526
"api/simplenonlinearsolve.md",
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# FixedPointAcceleration.jl
2+
3+
This is a extension for importing solvers from FixedPointAcceleration.jl into the SciML
4+
interface. Note that these solvers do not come by default, and thus one needs to install
5+
the package before using these solvers:
6+
7+
```julia
8+
using Pkg
9+
Pkg.add("FixedPointAcceleration")
10+
using FixedPointAcceleration, NonlinearSolve
11+
```
12+
13+
## Solver API
14+
15+
```@docs
16+
FixedPointAccelerationJL
17+
```

docs/src/api/speedmapping.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# SppedMapping.jl
2+
3+
This is a extension for importing solvers from SppedMapping.jl into the SciML
4+
interface. Note that these solvers do not come by default, and thus one needs to install
5+
the package before using these solvers:
6+
7+
```julia
8+
using Pkg
9+
Pkg.add("SppedMapping")
10+
using SppedMapping, NonlinearSolve
11+
```
12+
13+
## Solver API
14+
15+
```@docs
16+
SppedMappingJL
17+
```

docs/src/solvers/FixedPointSolvers.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Fixed Point Solvers
2+
3+
Currently we don't have an API to directly specify Fixed Point Solvers. However, a Fixed
4+
Point Problem can be triviall converted to a Root Finding Problem. Say we want to solve:
5+
6+
```math
7+
f(u) = u
8+
```
9+
10+
This can be written as:
11+
12+
```math
13+
g(u) = f(u) - u = 0
14+
```
15+
16+
Where ``g(u) = 0`` is a root finding problem. Note that we can use any root finding
17+
algorithm to solve this problem. However, this is often not the most efficient way to
18+
solve a fixed point problem. We provide a few algorithms available via extensions that
19+
are more efficient for fixed point problems.
20+
21+
Note that even if you use one of the Fixed Point Solvers mentioned here, you must still
22+
use the `NonlinearProblem` API to specify the problem, i.e., ``g(u) = 0``.
23+
24+
## Recommended Methods
25+
26+
Using [native NonlinearSolve.jl methods](@ref nonlinearsystemsolvers) is the recommended
27+
approach. For systems where constructing Jacobian Matrices are expensive, we recommend
28+
using a Krylov Method with one of those solvers.
29+
30+
## Full List of Methods
31+
32+
We are only listing the methods that natively solve fixed point problems.
33+
34+
### SpeedMapping.jl
35+
36+
- `SpeedMappingJL()`: accelerates the convergence of a mapping to a fixed point by the
37+
Alternating cyclic extrapolation algorithm (ACX).
38+
39+
### FixedPointAcceleration.jl
40+
41+
- `FixedPointAccelerationJL()`: accelerates the convergence of a mapping to a fixed point
42+
by the Anderson acceleration algorithm and a few other methods.

docs/src/solvers/NonlinearSystemSolvers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# [Nonlinear System Solvers](@id nonlinearsystemsolvers)
22

3-
`solve(prob::NonlinearProblem,alg;kwargs)`
3+
`solve(prob::NonlinearProblem, alg; kwargs)`
44

55
Solves for ``f(u)=0`` in the problem defined by `prob` using the algorithm
66
`alg`. If no algorithm is given, a default algorithm will be chosen.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module NonlinearSolveFixedPointAccelerationExt
2+
3+
end

ext/NonlinearSolveSpeedMappingExt.jl

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
module NonlinearSolveSpeedMappingExt
2+
3+
using NonlinearSolve, SpeedMapping, DiffEqBase, SciMLBase
4+
import UnPack: @unpack
5+
6+
function SciMLBase.__solve(prob::NonlinearProblem, alg::SpeedMappingJL, args...;
7+
abstol = nothing, maxiters = 1000, alias_u0::Bool = false,
8+
store_trace::Val{store_info} = Val(false), termination_condition = nothing,
9+
kwargs...) where {store_info}
10+
@assert (termination_condition ===
11+
nothing)||(termination_condition isa AbsNormTerminationMode) "SpeedMappingJL does not support termination conditions!"
12+
13+
if typeof(prob.u0) <: Number
14+
u0 = [prob.u0]
15+
else
16+
u0 = NonlinearSolve.__maybe_unaliased(prob.u0, alias_u0)
17+
end
18+
19+
T = eltype(u0)
20+
iip = isinplace(prob)
21+
p = prob.p
22+
23+
if prob.u0 isa Number
24+
resid = [NonlinearSolve.evaluate_f(prob, first(u0))]
25+
else
26+
resid = NonlinearSolve.evaluate_f(prob, u0)
27+
end
28+
29+
if !iip && prob.u0 isa Number
30+
m! = (du, u) -> (du .= prob.f(first(u), p) .+ first(u))
31+
elseif !iip
32+
m! = (du, u) -> (du .= prob.f(u, p) .+ u)
33+
else
34+
m! = (du, u) -> (prob.f(du, u, p); du .+= u)
35+
end
36+
37+
tol = abstol === nothing ? real(oneunit(T)) * (eps(real(one(T))))^(4 // 5) : abstol
38+
39+
sol = speedmapping(u0; m!, tol, Lp = Inf, maps_limit = maxiters, alg.orders,
40+
alg.check_obj, store_info, alg.σ_min, alg.stabilize)
41+
res = prob.u0 isa Number ? first(sol.minimizer) : sol.minimizer
42+
resid = NonlinearSolve.evaluate_f(prob, sol.minimizer)
43+
44+
return SciMLBase.build_solution(prob, alg, res, resid;
45+
retcode = sol.converged ? ReturnCode.Success : ReturnCode.Failure,
46+
stats = SciMLBase.NLStats(sol.maps, 0, 0, 0, sol.maps), original = sol)
47+
end
48+
49+
end

src/NonlinearSolve.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ export RadiusUpdateSchemes
236236

237237
export NewtonRaphson, TrustRegion, LevenbergMarquardt, DFSane, GaussNewton, PseudoTransient,
238238
Broyden, Klement, LimitedMemoryBroyden
239-
export LeastSquaresOptimJL, FastLevenbergMarquardtJL, CMINPACK, NLsolveJL
239+
export LeastSquaresOptimJL,
240+
FastLevenbergMarquardtJL, CMINPACK, NLsolveJL, FixedPointAccelerationJL, SpeedMappingJL
240241
export NonlinearSolvePolyAlgorithm,
241242
RobustMultiNewton, FastShortcutNonlinearPolyalg, FastShortcutNLLSPolyalg
242243

src/extension_algs.jl

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ for solving `NonlinearLeastSquaresProblem`.
1919
2020
This algorithm is only available if `LeastSquaresOptim.jl` is installed.
2121
"""
22-
struct LeastSquaresOptimJL{alg, linsolve} <: AbstractNonlinearSolveAlgorithm
22+
struct LeastSquaresOptimJL{alg, linsolve} <: AbstractNonlinearAlgorithm
2323
autodiff::Symbol
2424
end
2525

@@ -58,7 +58,7 @@ for solving `NonlinearLeastSquaresProblem`.
5858
5959
This algorithm is only available if `FastLevenbergMarquardt.jl` is installed.
6060
"""
61-
@concrete struct FastLevenbergMarquardtJL{linsolve} <: AbstractNonlinearSolveAlgorithm
61+
@concrete struct FastLevenbergMarquardtJL{linsolve} <: AbstractNonlinearAlgorithm
6262
autodiff
6363
factor
6464
factoraccept
@@ -206,3 +206,45 @@ function NLsolveJL(; method = :trust_region, autodiff = :central, store_trace =
206206
return NLsolveJL(method, autodiff, store_trace, extended_trace, linesearch, linsolve,
207207
factor, autoscale, m, beta, show_trace)
208208
end
209+
210+
"""
211+
SpeedMappingJL(; σ_min = 0.0, stabilize::Bool = false, check_obj::Bool = false,
212+
orders::Vector{Int} = [3, 3, 2], time_limit::Real = 1000)
213+
214+
Wrapper over [SpeedMapping.jl](https://nicolasl-s.github.io/SpeedMapping.jl) for solving
215+
Fixed Point Problems. We allow using this algorithm to solve root finding problems as well.
216+
217+
## Arguments:
218+
219+
- `σ_min`: Setting to `1` may avoid stalling (see paper).
220+
- `stabilize`: performs a stabilization mapping before extrapolating. Setting to `true`
221+
may improve the performance for applications like accelerating the EM or MM algorithms
222+
(see paper).
223+
- `check_obj`: In case of NaN or Inf values, the algorithm restarts at the best past
224+
iterate.
225+
- `orders`: determines ACX's alternating order. Must be between `1` and `3` (where `1`
226+
means no extrapolation). The two recommended orders are `[3, 2]` and `[3, 3, 2]`, the
227+
latter being potentially better for highly non-linear applications (see paper).
228+
- `time_limit`: time limit for the algorithm.
229+
230+
## References:
231+
232+
- N. Lepage-Saucier, Alternating cyclic extrapolation methods for optimization algorithms,
233+
arXiv:2104.04974 (2021). https://arxiv.org/abs/2104.04974.
234+
"""
235+
@concrete struct SpeedMappingJL <: AbstractNonlinearAlgorithm
236+
σ_min
237+
stabilize::Bool
238+
check_obj::Bool
239+
orders::Vector{Int}
240+
time_limit
241+
end
242+
243+
function SpeedMappingJL(; σ_min = 0.0, stabilize::Bool = false, check_obj::Bool = false,
244+
orders::Vector{Int} = [3, 3, 2], time_limit::Real = 1000)
245+
if Base.get_extension(@__MODULE__, :NonlinearSolveSpeedMappingExt) === nothing
246+
error("SpeedMappingJL requires SpeedMapping.jl to be loaded")
247+
end
248+
249+
return SpeedMappingJL(σ_min, stabilize, check_obj, orders, time_limit)
250+
end

0 commit comments

Comments
 (0)