Skip to content

Commit 2a6f1a9

Browse files
committed
Update the FAQ and tutorials
1 parent 267dd3f commit 2a6f1a9

File tree

13 files changed

+161
-76
lines changed

13 files changed

+161
-76
lines changed

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
66
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
77
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
88
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
9+
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
910
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
1011
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
1112
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"

docs/src/basics/diagnostics_api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# [Diagnostics API](@id diagnostics_api)
2+
13
# Logging the Solve Process
24

35
All NonlinearSolve.jl native solvers allow storing and displaying the trace of the nonlinear

docs/src/basics/faq.md

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ sol = solve(prob_oop, LevenbergMarquardt(; autodiff = AutoFiniteDiff()); maxiter
7676
```
7777

7878
This worked but, Finite Differencing is not the recommended approach in any scenario.
79-
Instead, rewrite the function to use
79+
80+
2. Rewrite the function to use
8081
[PreallocationTools.jl](https://github.com/SciML/PreallocationTools.jl) or write it as
8182

8283
```@example dual_error_faq
@@ -93,4 +94,58 @@ sol = solve(prob_oop, LevenbergMarquardt(); maxiters = 10000, abstol = 1e-8)
9394

9495
## I thought NonlinearSolve.jl was type-stable and fast. But it isn't, why?
9596

97+
It is hard to say why your code is not fast. Take a look at the
98+
[Diagnostics API](@ref diagnostics_api) to pin-point the problem. One common issue is that
99+
there is type instability.
100+
101+
If you are using the defaults for the autodiff and your problem is not a scalar or using
102+
static arrays, ForwardDiff will create type unstable code. See this simple example:
103+
104+
```@example type_unstable
105+
using NonlinearSolve, InteractiveUtils
106+
107+
f(u, p) = @. u^2 - p
108+
109+
prob = NonlinearProblem{false}(f, 1.0, 2.0)
110+
111+
@code_warntype solve(prob, NewtonRaphson())
112+
nothing # hide
113+
```
114+
115+
Notice that this was type-stable, since it is a scalar problem. Now what happens for static
116+
arrays
117+
118+
```@example type_unstable
119+
using StaticArrays
120+
121+
prob = NonlinearProblem{false}(f, @SVector([1.0, 2.0]), 2.0)
122+
123+
@code_warntype solve(prob, NewtonRaphson())
124+
nothing # hide
125+
```
126+
127+
Again Type-Stable! Now let's try using a regular array:
128+
129+
```@example type_unstable
130+
prob = NonlinearProblem(f, [1.0, 2.0], 2.0)
131+
132+
@code_warntype solve(prob, NewtonRaphson())
133+
nothing # hide
134+
```
135+
136+
Oh no! This is type unstable. This is because ForwardDiff.jl will chunk the jacobian
137+
computation and the type of this chunksize can't be statically inferred. To fix this, we
138+
directly specify the chunksize:
139+
140+
```@example type_unstable
141+
@code_warntype solve(prob, NewtonRaphson(; autodiff = AutoForwardDiff(; chunksize = 2)))
142+
nothing # hide
143+
```
144+
145+
And boom! Type stable again. For selecting the chunksize the method is:
146+
147+
1. For small inputs `≤ 12` use `chunksize = <length of input>`
148+
2. For larger inputs, use `chunksize = 12`
96149

150+
In general, the chunksize should be `≤ length of input`. However, a very large chunksize
151+
can lead to excessive compilation times and slowdown.

docs/src/basics/nonlinear_problem.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ that `f(u) = 0`, the `NonlinearProblem` does not have a preferred solution, whil
3535
`SteadyStateProblem` the preferred solution is the `u(∞)` that would arise from solving the
3636
ODE `u' = f(u,t)`.
3737

38-
!!! warn
38+
!!! warning
3939

4040
Most solvers for `SteadyStateProblem` do not guarantee the preferred solution and
4141
instead will solve for some `u` in the set of solutions. The documentation of the

docs/src/native/globalization.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Pages = ["globalization.md"]
1212
LiFukushimaLineSearch
1313
LineSearchesJL
1414
RobustNonMonotoneLineSearch
15+
NoLineSearch
1516
```
1617

1718
## Radius Update Schemes for Trust Region

docs/src/refs.bib

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
@article{bastin2010retrospective,
2+
title = {A retrospective trust-region method for unconstrained optimization},
3+
author = {Bastin, Fabian and Malmedy, Vincent and Mouffe, M{\'e}lodie and Toint, Philippe L and Tomanos, Dimitri},
4+
journal = {Mathematical programming},
5+
volume = {123},
6+
pages = {395--418},
7+
year = {2010},
8+
publisher = {Springer}
9+
}
10+
111
@article{broyden1965class,
212
title = {A class of methods for solving nonlinear simultaneous equations},
313
author = {Broyden, Charles G},
@@ -19,6 +29,37 @@ @article{coffey2003pseudotransient
1929
publisher = {SIAM}
2030
}
2131

32+
@article{fan2006convergence,
33+
title = {Convergence rate of the trust region method for nonlinear equations under local error bound condition},
34+
author = {Fan, Jinyan},
35+
journal = {Computational Optimization and Applications},
36+
volume = {34},
37+
number = {2},
38+
pages = {215--227},
39+
year = {2006},
40+
publisher = {Springer}
41+
}
42+
43+
@article{fan2016retrospective,
44+
title = {A retrospective trust region algorithm with trust region converging to zero},
45+
author = {Fan, Jinyan and Pan, Jianyu and Song, Hongyan},
46+
journal = {Journal of Computational Mathematics},
47+
volume = {34},
48+
number = {4},
49+
pages = {421--436},
50+
year = {2016},
51+
publisher = {JSTOR}
52+
}
53+
54+
@article{hei2003self,
55+
title = {A self-adaptive trust region algorithm},
56+
author = {Hei, Long},
57+
journal = {Journal of Computational Mathematics},
58+
pages = {229--236},
59+
year = {2003},
60+
publisher = {JSTOR}
61+
}
62+
2263
@article{kelley1998convergence,
2364
title = {Convergence analysis of pseudo-transient continuation},
2465
author = {Kelley, Carl Timothy and Keyes, David E},
@@ -78,6 +119,16 @@ @article{yuan2015recent
78119
publisher = {Springer}
79120
}
80121

122+
@article{yuan2015recent,
123+
title = {Recent advances in trust region algorithms},
124+
author = {Yuan, Ya-xiang},
125+
journal = {Mathematical Programming},
126+
volume = {151},
127+
pages = {249--281},
128+
year = {2015},
129+
publisher = {Springer}
130+
}
131+
81132
@article{ziani2008autoadaptative,
82133
title = {An autoadaptative limited memory Broyden’s method to solve systems of nonlinear equations},
83134
author = {Ziani, Mohammed and Guyomarc’h, Fr{\'e}d{\'e}ric},

docs/src/tutorials/large_systems.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,14 @@ Symbolic Sparsity Detection. See the manual entry on
137137
using BenchmarkTools # for @btime
138138
139139
@btime solve(prob_brusselator_2d, NewtonRaphson());
140-
@btime solve(prob_brusselator_2d, NewtonRaphson(; autodiff = AutoSparseForwardDiff()));
141140
@btime solve(prob_brusselator_2d,
142-
NewtonRaphson(; autodiff = AutoSparseForwardDiff(), linsolve = KLUFactorization()));
141+
NewtonRaphson(; autodiff = AutoSparseForwardDiff(; chunksize = 32)));
143142
@btime solve(prob_brusselator_2d,
144-
NewtonRaphson(; autodiff = AutoSparseForwardDiff(), linsolve = KrylovJL_GMRES()));
143+
NewtonRaphson(; autodiff = AutoSparseForwardDiff(; chunksize = 32),
144+
linsolve = KLUFactorization()));
145+
@btime solve(prob_brusselator_2d,
146+
NewtonRaphson(; autodiff = AutoSparseForwardDiff(; chunksize = 32),
147+
linsolve = KrylovJL_GMRES()));
145148
nothing # hide
146149
```
147150

@@ -175,7 +178,7 @@ ff = NonlinearFunction(brusselator_2d_loop; sparsity = jac_sparsity)
175178
Build the `NonlinearProblem`:
176179

177180
```@example ill_conditioned_nlprob
178-
prob_brusselator_2d_sparse = NonlinearProblem(ff, u0, p)
181+
prob_brusselator_2d_sparse = NonlinearProblem(ff, u0, p; abstol = 1e-10, reltol = 1e-10)
179182
```
180183

181184
Now let's see how the version with sparsity compares to the version without:

docs/src/tutorials/optimizing_parameterized_ode.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Now, we can use any NLLS solver to solve this problem.
5454

5555
```@example parameterized_ode
5656
res = solve(nlls_prob, LevenbergMarquardt(); maxiters = 1000, show_trace = Val(true),
57-
trace_level = TraceAll())
57+
trace_level = TraceWithJacobianConditionNumber(25))
5858
nothing # hide
5959
```
6060

@@ -66,7 +66,7 @@ We can also use Trust Region methods.
6666

6767
```@example parameterized_ode
6868
res = solve(nlls_prob, TrustRegion(); maxiters = 1000, show_trace = Val(true),
69-
trace_level = TraceAll())
69+
trace_level = TraceWithJacobianConditionNumber(25))
7070
nothing # hide
7171
```
7272

src/NonlinearSolve.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import PrecompileTools: @recompile_invalidations, @compile_workload, @setup_work
1010
@recompile_invalidations begin
1111
using ADTypes, ConcreteStructs, DiffEqBase, FastBroadcast, FastClosures, LazyArrays,
1212
LineSearches, LinearAlgebra, LinearSolve, MaybeInplace, Preferences, Printf,
13-
SciMLBase, SimpleNonlinearSolve, SparseArrays, SparseDiffTools, TimerOutputs
13+
SciMLBase, SimpleNonlinearSolve, SparseArrays, SparseDiffTools
1414

1515
import ArrayInterface: undefmatrix, can_setindex, restructure, fast_scalar_indexing
1616
import DiffEqBase: AbstractNonlinearTerminationMode,

src/globalization/trust_region.jl

Lines changed: 26 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ of specifying a trust region radius.
2121
iteration ``i``. Reasonable choices for `b_uphill` are `1.0` or `2.0`, with
2222
`b_uphill = 2.0` allowing higher uphill moves than `b_uphill = 1.0`. When
2323
`b_uphill = 0.0`, no uphill moves will be accepted. Defaults to `1.0`. See Section 4 of
24-
[1].
25-
26-
### References
27-
28-
[1] Transtrum, Mark K., and James P. Sethna. "Improvements to the Levenberg-Marquardt
29-
algorithm for nonlinear least-squares minimization." arXiv preprint arXiv:1201.5885 (2012).
24+
[transtrum2012improvements](@ref).
3025
"""
3126
@concrete struct LevenbergMarquardtTrustRegion <: AbstractTrustRegionMethod
3227
β_uphill
@@ -120,6 +115,7 @@ end
120115

121116
const T = AbstractRadiusUpdateScheme
122117

118+
struct __Simple <: AbstractRadiusUpdateScheme end
123119
"""
124120
RadiusUpdateSchemes.Simple
125121
@@ -128,93 +124,70 @@ follows the conventional approach to update the trust region radius, i.e. if the
128124
step is accepted it increases the radius by a fixed factor (bounded by a maximum radius)
129125
and if the trial step is rejected, it shrinks the radius by a fixed factor.
130126
"""
131-
struct __Simple <: AbstractRadiusUpdateScheme end
132127
const Simple = __Simple()
133128

129+
struct __NLsolve <: AbstractRadiusUpdateScheme end
134130
"""
135131
RadiusUpdateSchemes.NLsolve
136132
137133
The same updating scheme as in NLsolve's (https://github.com/JuliaNLSolvers/NLsolve.jl)
138134
trust region dogleg implementation.
139135
"""
140-
struct __NLsolve <: AbstractRadiusUpdateScheme end
141136
const NLsolve = __NLsolve()
142137

138+
struct __NocedalWright <: AbstractRadiusUpdateScheme end
143139
"""
144140
RadiusUpdateSchemes.NocedalWright
145141
146142
Trust region updating scheme as in Nocedal and Wright [see Alg 11.5, page 291].
147143
"""
148-
struct __NocedalWright <: AbstractRadiusUpdateScheme end
149144
const NocedalWright = __NocedalWright()
150145

146+
struct __Hei <: AbstractRadiusUpdateScheme end
151147
"""
152148
RadiusUpdateSchemes.Hei
153149
154-
This scheme is proposed by Hei, L. [1]. The trust region radius depends on the size
155-
(norm) of the current step size. The hypothesis is to let the radius converge to zero as
156-
the iterations progress, which is more reliable and robust for ill-conditioned as well
150+
This scheme is proposed in [hei2003self](@citet). The trust region radius depends on the
151+
size (norm) of the current step size. The hypothesis is to let the radius converge to zero
152+
as the iterations progress, which is more reliable and robust for ill-conditioned as well
157153
as degenerate problems.
158-
159-
### References
160-
161-
[1] Hei, Long. "A self-adaptive trust region algorithm." Journal of Computational
162-
Mathematics (2003): 229-236.
163154
"""
164-
struct __Hei <: AbstractRadiusUpdateScheme end
165155
const Hei = __Hei()
166156

157+
struct __Yuan <: AbstractRadiusUpdateScheme end
167158
"""
168159
RadiusUpdateSchemes.Yuan
169160
170-
This scheme is proposed by Yuan, Y [1]. Similar to Hei's scheme, the trust region is
171-
updated in a way so that it converges to zero, however here, the radius depends on the
172-
size (norm) of the current gradient of the objective (merit) function. The hypothesis is
173-
that the step size is bounded by the gradient size, so it makes sense to let the radius
174-
depend on the gradient.
175-
176-
### References
177-
178-
[1] Fan, Jinyan, Jianyu Pan, and Hongyan Song. "A retrospective trust region algorithm
179-
with trust region converging to zero." Journal of Computational Mathematics 34.4 (2016):
180-
421-436.
161+
This scheme is proposed by [yuan2015recent](@citet). Similar to Hei's scheme, the
162+
trust region is updated in a way so that it converges to zero, however here, the radius
163+
depends on the size (norm) of the current gradient of the objective (merit) function. The
164+
hypothesis is that the step size is bounded by the gradient size, so it makes sense to let
165+
the radius depend on the gradient.
181166
"""
182-
struct __Yuan <: AbstractRadiusUpdateScheme end
183167
const Yuan = __Yuan()
184168

169+
struct __Bastin <: AbstractRadiusUpdateScheme end
185170
"""
186171
RadiusUpdateSchemes.Bastin
187172
188-
This scheme is proposed by Bastin, et al. [1]. The scheme is called a retrospective
189-
update scheme as it uses the model function at the current iteration to compute the
190-
ratio of the actual reduction and the predicted reduction in the previous trial step,
191-
and use this ratio to update the trust region radius. The hypothesis is to exploit the
173+
This scheme is proposed by [bastin2010retrospective](@citet). The scheme is called a
174+
retrospective update scheme as it uses the model function at the current iteration to
175+
compute the ratio of the actual reduction and the predicted reduction in the previous trial
176+
step, and use this ratio to update the trust region radius. The hypothesis is to exploit the
192177
information made available during the optimization process in order to vary the accuracy
193178
of the objective function computation.
194-
195-
### References
196-
197-
[1] Bastin, Fabian, et al. "A retrospective trust-region method for unconstrained
198-
optimization." Mathematical programming 123 (2010): 395-418.
199179
"""
200-
struct __Bastin <: AbstractRadiusUpdateScheme end
201180
const Bastin = __Bastin()
202181

182+
struct __Fan <: AbstractRadiusUpdateScheme end
203183
"""
204184
RadiusUpdateSchemes.Fan
205185
206-
This scheme is proposed by Fan, J. [1]. It is very much similar to Hei's and Yuan's
207-
schemes as it lets the trust region radius depend on the current size (norm) of the
208-
objective (merit) function itself. These new update schemes are known to improve local
186+
This scheme is proposed by [fan2006convergence](@citet). It is very much similar to Hei's
187+
and Yuan's schemes as it lets the trust region radius depend on the current size (norm) of
188+
the objective (merit) function itself. These new update schemes are known to improve local
209189
convergence.
210-
211-
### References
212-
213-
[1] Fan, Jinyan. "Convergence rate of the trust region method for nonlinear equations
214-
under local error bound condition." Computational Optimization and Applications 34.2
215-
(2006): 215-227.
216190
"""
217-
struct __Fan <: AbstractRadiusUpdateScheme end
218191
const Fan = __Fan()
219192

220193
end
@@ -248,13 +221,11 @@ the value used in the respective paper.
248221
- `step_threshold`: the threshold for taking a step. In every iteration, the threshold is
249222
compared with a value `r`, which is the actual reduction in the objective function
250223
divided by the predicted reduction. If `step_threshold > r` the model is not a good
251-
approximation, and the step is rejected. Defaults to `nothing`. For more details, see
252-
[2].
224+
approximation, and the step is rejected. Defaults to `nothing`.
253225
- `shrink_threshold`: the threshold for shrinking the trust region radius. In every
254226
iteration, the threshold is compared with a value `r` which is the actual reduction in
255227
the objective function divided by the predicted reduction. If `shrink_threshold > r` the
256-
trust region radius is shrunk by `shrink_factor`. Defaults to `nothing`. For more
257-
details, see [2].
228+
trust region radius is shrunk by `shrink_factor`. Defaults to `nothing`.
258229
- `expand_threshold`: the threshold for expanding the trust region radius. If a step is
259230
taken, i.e `step_threshold < r` (with `r` defined in `shrink_threshold`), a check is
260231
also made to see if `expand_threshold < r`. If that is true, the trust region radius is
@@ -263,13 +234,6 @@ the value used in the respective paper.
263234
`shrink_threshold > r` (with `r` defined in `shrink_threshold`). Defaults to `0.25`.
264235
- `expand_factor`: the factor to expand the trust region radius with if
265236
`expand_threshold < r` (with `r` defined in `shrink_threshold`). Defaults to `2.0`.
266-
267-
### References
268-
269-
[1] Yuan, Ya-xiang. "Recent advances in trust region algorithms." Mathematical Programming
270-
151 (2015): 249-281.
271-
[2] Rahpeymaii, Farzad. "An efficient line search trust-region for systems of nonlinear
272-
equations." Mathematical Sciences 14.3 (2020): 257-268.
273237
"""
274238
@kwdef @concrete struct GenericTrustRegionScheme{
275239
M <: RadiusUpdateSchemes.AbstractRadiusUpdateScheme}
@@ -358,7 +322,7 @@ end
358322
u0_norm, fu_norm) where {T}
359323
method isa RUS.__NLsolve && return T(ifelse(u0_norm > 0, u0_norm, 1))
360324
(method isa RUS.__Hei || method isa RUS.__Bastin) && return T(1)
361-
method isa RUS.__Fan && return T((fu_norm^0.99) // 10)
325+
method isa RUS.__Fan && return T((fu_norm^0.99) / 10)
362326
return T(max_tr / 11)
363327
end
364328

0 commit comments

Comments
 (0)