Skip to content

Commit 73005ca

Browse files
committed
Standardize the Extension Algorithms
1 parent fa16796 commit 73005ca

10 files changed

+89
-45
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
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.3.0"
4+
version = "3.3.1"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"

docs/src/basics/solve.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ solve(prob::SciMLBase.NonlinearProblem, args...; kwargs...)
1414
## Iteration Controls
1515

1616
- `maxiters::Int`: The maximum number of iterations to perform. Defaults to `1000`.
17-
- `abstol::Number`: The absolute tolerance.
18-
- `reltol::Number`: The relative tolerance.
17+
- `abstol::Number`: The absolute tolerance. Defaults to `real(oneunit(T)) * (eps(real(one(T))))^(4 // 5)`.
18+
- `reltol::Number`: The relative tolerance. Defaults to `real(oneunit(T)) * (eps(real(one(T))))^(2 // 5)`.
1919
- `termination_condition`: Termination Condition from DiffEqBase. Defaults to
2020
`AbsSafeBestTerminationMode()` for `NonlinearSolve.jl` and `AbsTerminateMode()` for
2121
`SimpleNonlinearSolve.jl`.

ext/NonlinearSolveFastLevenbergMarquardtExt.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import ConcreteStructs: @concrete
55
import FastLevenbergMarquardt as FastLM
66
import FiniteDiff, ForwardDiff
77

8-
function _fast_lm_solver(::FastLevenbergMarquardtJL{linsolve}, x) where {linsolve}
8+
@inline function _fast_lm_solver(::FastLevenbergMarquardtJL{linsolve}, x) where {linsolve}
99
if linsolve === :cholesky
1010
return FastLM.CholeskySolver(ArrayInterface.undefmatrix(x))
1111
elseif linsolve === :qr
@@ -33,14 +33,17 @@ end
3333
(f::InplaceFunction{false})(fx, x, p) = (fx .= f.f(x, p))
3434

3535
function SciMLBase.__init(prob::NonlinearLeastSquaresProblem,
36-
alg::FastLevenbergMarquardtJL, args...; alias_u0 = false, abstol = 1e-8,
37-
reltol = 1e-8, maxiters = 1000, kwargs...)
36+
alg::FastLevenbergMarquardtJL, args...; alias_u0 = false, abstol = nothing,
37+
reltol = nothing, maxiters = 1000, kwargs...)
3838
iip = SciMLBase.isinplace(prob)
3939
u = NonlinearSolve.__maybe_unaliased(prob.u0, alias_u0)
4040
fu = NonlinearSolve.evaluate_f(prob, u)
4141

4242
f! = InplaceFunction{iip}(prob.f)
4343

44+
abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u))
45+
reltol = NonlinearSolve.DEFAULT_TOLERANCE(reltol, eltype(u))
46+
4447
if prob.f.jac === nothing
4548
use_forward_diff = if alg.autodiff === nothing
4649
ForwardDiff.can_dual(eltype(u))
@@ -95,9 +98,9 @@ function SciMLBase.__init(prob::NonlinearLeastSquaresProblem,
9598
LM = FastLM.LMWorkspace(u, fu, J)
9699

97100
return FastLevenbergMarquardtJLCache(f!, J!, prob, alg, LM, solver,
98-
(; xtol = abstol, ftol = reltol, maxit = maxiters, alg.factor, alg.factoraccept,
99-
alg.factorreject, alg.minscale, alg.maxscale, alg.factorupdate, alg.minfactor,
100-
alg.maxfactor, kwargs...))
101+
(; xtol = reltol, ftol = reltol, gtol = abstol, maxit = maxiters, alg.factor,
102+
alg.factoraccept, alg.factorreject, alg.minscale, alg.maxscale,
103+
alg.factorupdate, alg.minfactor, alg.maxfactor))
101104
end
102105

103106
function SciMLBase.solve!(cache::FastLevenbergMarquardtJLCache)

ext/NonlinearSolveFixedPointAccelerationExt.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::FixedPointAccelerationJL
3030
f = (u) -> (prob.f(du, reshape(u, u_size), p); vec(du) .+ u)
3131
end
3232

33-
tol = abstol === nothing ? real(oneunit(T)) * (eps(real(one(T))))^(4 // 5) : abstol
33+
tol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u0))
3434

3535
sol = fixed_point(f, NonlinearSolve._vec(u0); Algorithm = alg.algorithm,
3636
ConvergenceMetricThreshold = tol, MaxIter = maxiters, MaxM = alg.m,

ext/NonlinearSolveLeastSquaresOptimExt.jl

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ using NonlinearSolve, SciMLBase
44
import ConcreteStructs: @concrete
55
import LeastSquaresOptim as LSO
66

7-
function _lso_solver(::LeastSquaresOptimJL{alg, linsolve}) where {alg, linsolve}
7+
@inline function _lso_solver(::LeastSquaresOptimJL{alg, linsolve}) where {alg, linsolve}
88
ls = linsolve === :qr ? LSO.QR() :
99
(linsolve === :cholesky ? LSO.Cholesky() :
1010
(linsolve === :lsmr ? LSO.LSMR() : nothing))
@@ -33,25 +33,28 @@ end
3333
(f::FunctionWrapper{false})(du, u) = (du .= f.f(u, f.p))
3434

3535
function SciMLBase.__init(prob::NonlinearLeastSquaresProblem, alg::LeastSquaresOptimJL,
36-
args...; alias_u0 = false, abstol = 1e-8, reltol = 1e-8, verbose = false,
37-
maxiters = 1000, kwargs...)
36+
args...; alias_u0 = false, abstol = nothing, show_trace::Val{ShT} = Val(false),
37+
trace_level = TraceMinimal(), store_trace::Val{StT} = Val(false), maxiters = 1000,
38+
reltol = nothing, kwargs...) where {ShT, StT}
3839
iip = SciMLBase.isinplace(prob)
39-
u = alias_u0 ? prob.u0 : deepcopy(prob.u0)
40+
u = NonlinearSolve.__maybe_unaliased(prob.u0, alias_u0)
41+
42+
abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u))
43+
reltol = NonlinearSolve.DEFAULT_TOLERANCE(reltol, eltype(u))
4044

4145
f! = FunctionWrapper{iip}(prob.f, prob.p)
4246
g! = prob.f.jac === nothing ? nothing : FunctionWrapper{iip}(prob.f.jac, prob.p)
4347

4448
resid_prototype = prob.f.resid_prototype === nothing ?
45-
(!iip ? prob.f(u, prob.p) : zeros(u)) :
46-
prob.f.resid_prototype
49+
(!iip ? prob.f(u, prob.p) : zeros(u)) : prob.f.resid_prototype
4750

4851
lsoprob = LSO.LeastSquaresProblem(; x = u, f!, y = resid_prototype, g!,
4952
J = prob.f.jac_prototype, alg.autodiff, output_length = length(resid_prototype))
5053
allocated_prob = LSO.LeastSquaresProblemAllocated(lsoprob, _lso_solver(alg))
5154

5255
return LeastSquaresOptimJLCache(prob, alg, allocated_prob,
53-
(; x_tol = abstol, f_tol = reltol, iterations = maxiters, show_trace = verbose,
54-
kwargs...))
56+
(; x_tol = reltol, f_tol = abstol, g_tol = abstol, iterations = maxiters,
57+
show_trace = ShT, store_trace = StT, show_every = trace_level.print_frequency))
5558
end
5659

5760
function SciMLBase.solve!(cache::LeastSquaresOptimJLCache)

ext/NonlinearSolveMINPACKExt.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ using MINPACK
55

66
function SciMLBase.__solve(prob::Union{NonlinearProblem{uType, iip},
77
NonlinearLeastSquaresProblem{uType, iip}}, alg::CMINPACK, args...;
8-
abstol = nothing, maxiters = 100000, alias_u0::Bool = false,
9-
termination_condition = nothing, kwargs...) where {uType, iip}
8+
abstol = nothing, maxiters = 1000, alias_u0::Bool = false,
9+
show_trace::Val{ShT} = Val(false), store_trace::Val{StT} = Val(false),
10+
termination_condition = nothing, kwargs...) where {uType, iip, ShT, StT}
1011
@assert (termination_condition ===
1112
nothing)||(termination_condition isa AbsNormTerminationMode) "CMINPACK does not support termination conditions!"
1213

@@ -16,13 +17,12 @@ function SciMLBase.__solve(prob::Union{NonlinearProblem{uType, iip},
1617
u0 = NonlinearSolve.__maybe_unaliased(prob.u0, alias_u0)
1718
end
1819

19-
T = eltype(u0)
2020
sizeu = size(prob.u0)
2121
p = prob.p
2222

2323
# unwrapping alg params
24-
show_trace = alg.show_trace
25-
tracing = alg.tracing
24+
show_trace = alg.show_trace || ShT
25+
tracing = alg.tracing || StT
2626

2727
if !iip && prob.u0 isa Number
2828
f! = (du, u) -> (du .= prob.f(first(u), p); Cint(0))
@@ -44,7 +44,7 @@ function SciMLBase.__solve(prob::Union{NonlinearProblem{uType, iip},
4444
method = ifelse(alg.method === :auto,
4545
ifelse(prob isa NonlinearLeastSquaresProblem, :lm, :hybr), alg.method)
4646

47-
abstol = abstol === nothing ? real(oneunit(T)) * (eps(real(one(T))))^(4 // 5) : abstol
47+
abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u))
4848

4949
if SciMLBase.has_jac(prob.f)
5050
if !iip && prob.u0 isa Number
@@ -62,10 +62,10 @@ function SciMLBase.__solve(prob::Union{NonlinearProblem{uType, iip},
6262
end
6363
end
6464
original = MINPACK.fsolve(f!, g!, vec(u0), m; tol = abstol, show_trace, tracing,
65-
method, iterations = maxiters, kwargs...)
65+
method, iterations = maxiters)
6666
else
6767
original = MINPACK.fsolve(f!, vec(u0), m; tol = abstol, show_trace, tracing,
68-
method, iterations = maxiters, kwargs...)
68+
method, iterations = maxiters)
6969
end
7070

7171
u = reshape(original.x, size(u))

ext/NonlinearSolveNLsolveExt.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::NLsolveJL, args...;
1515
u0 = NonlinearSolve.__maybe_unaliased(prob.u0, alias_u0)
1616
end
1717

18-
T = eltype(u0)
1918
iip = isinplace(prob)
20-
2119
sizeu = size(prob.u0)
2220
p = prob.p
2321

@@ -70,7 +68,7 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::NLsolveJL, args...;
7068
df = OnceDifferentiable(f!, vec(u0), vec(resid); autodiff)
7169
end
7270

73-
abstol = abstol === nothing ? real(oneunit(T)) * (eps(real(one(T))))^(4 // 5) : abstol
71+
abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u))
7472

7573
original = nlsolve(df, vec(u0); ftol = abstol, iterations = maxiters, method,
7674
store_trace, extended_trace, linesearch, linsolve, factor, autoscale, m, beta,

ext/NonlinearSolveSpeedMappingExt.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::SpeedMappingJL, args...;
1515
u0 = NonlinearSolve.__maybe_unaliased(prob.u0, alias_u0)
1616
end
1717

18-
T = eltype(u0)
1918
iip = isinplace(prob)
2019
p = prob.p
2120

@@ -27,7 +26,7 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::SpeedMappingJL, args...;
2726
m! = (du, u) -> (prob.f(du, u, p); du .+= u)
2827
end
2928

30-
tol = abstol === nothing ? real(oneunit(T)) * (eps(real(one(T))))^(4 // 5) : abstol
29+
tol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u0))
3130

3231
sol = speedmapping(u0; m!, tol, Lp = Inf, maps_limit = maxiters, alg.orders,
3332
alg.check_obj, store_info, alg.σ_min, alg.stabilize)

src/extension_algs.jl

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,10 @@ function FastLevenbergMarquardtJL(linsolve::Symbol = :cholesky; factor = 1e-6,
8888
end
8989

9090
"""
91-
CMINPACK(; show_trace::Bool=false, tracing::Bool=false, method::Symbol=:auto)
91+
CMINPACK(; method::Symbol = :auto)
9292
9393
### Keyword Arguments
9494
95-
- `show_trace`: whether to show the trace.
96-
- `tracing`: who the hell knows what this does. If you find out, please open an issue/PR.
9795
- `method`: the choice of method for the solver.
9896
9997
### Method Choices
@@ -134,27 +132,42 @@ struct CMINPACK <: AbstractNonlinearSolveAlgorithm
134132
method::Symbol
135133
end
136134

137-
function CMINPACK(; show_trace::Bool = false, tracing::Bool = false, method::Symbol = :auto)
135+
function CMINPACK(; show_trace = missing, tracing = missing, method::Symbol = :auto)
138136
if Base.get_extension(@__MODULE__, :NonlinearSolveMINPACKExt) === nothing
139137
error("CMINPACK requires MINPACK.jl to be loaded")
140138
end
141139

140+
if show_trace !== missing
141+
Base.depwarn("`show_trace` for CMINPACK has been deprecated and will be removed \
142+
in v4. Use the `show_trace` keyword argument via the logging API \
143+
https://docs.sciml.ai/NonlinearSolve/stable/basics/Logging/ \
144+
instead.")
145+
else
146+
show_trace = false
147+
end
148+
149+
if tracing !== missing
150+
Base.depwarn("`tracing` for CMINPACK has been deprecated and will be removed \
151+
in v4. Use the `store_trace` keyword argument via the logging API \
152+
https://docs.sciml.ai/NonlinearSolve/stable/basics/Logging/ \
153+
instead.")
154+
else
155+
tracing = false
156+
end
157+
142158
return CMINPACK(show_trace, tracing, method)
143159
end
144160

145161
"""
146-
NLsolveJL(; method=:trust_region, autodiff=:central, store_trace=false,
147-
extended_trace=false, linesearch=LineSearches.Static(),
148-
linsolve=(x, A, b) -> copyto!(x, A\\b), factor = one(Float64), autoscale=true,
149-
m=10, beta=one(Float64), show_trace=false)
162+
NLsolveJL(; method = :trust_region, autodiff = :central, linesearch = Static(),
163+
linsolve = (x, A, b) -> copyto!(x, A\\b), factor = one(Float64), autoscale = true,
164+
m = 10, beta = one(Float64))
150165
151166
### Keyword Arguments
152167
153168
- `method`: the choice of method for solving the nonlinear system.
154169
- `autodiff`: the choice of method for generating the Jacobian. Defaults to `:central` or
155170
central differencing via FiniteDiff.jl. The other choices are `:forward`
156-
- `show_trace`: should a trace of the optimization algorithm's state be shown on `STDOUT`?
157-
- `extended_trace`: should additional algorithm internals be added to the state trace?
158171
- `linesearch`: the line search method to be used within the solver method. The choices
159172
are line search types from
160173
[LineSearches.jl](https://github.com/JuliaNLSolvers/LineSearches.jl).
@@ -168,7 +181,6 @@ end
168181
constants are close to 1. If convergence fails, though, you may consider lowering it.
169182
- `beta`: It is also known as DIIS or Pulay mixing, this method is based on the acceleration
170183
of the fixed-point iteration xₙ₊₁ = xₙ + beta*f(xₙ), where by default beta = 1.
171-
- `store_trace``: should a trace of the optimization algorithm's state be stored?
172184
173185
### Submethod Choice
174186
@@ -195,14 +207,41 @@ Choices for methods in `NLsolveJL`:
195207
show_trace::Bool
196208
end
197209

198-
function NLsolveJL(; method = :trust_region, autodiff = :central, store_trace = false,
199-
extended_trace = false, linesearch = LineSearches.Static(),
210+
function NLsolveJL(; method = :trust_region, autodiff = :central, store_trace = missing,
211+
extended_trace = missing, linesearch = LineSearches.Static(),
200212
linsolve = (x, A, b) -> copyto!(x, A \ b), factor = 1.0, autoscale = true, m = 10,
201-
beta = one(Float64), show_trace = false)
213+
beta = one(Float64), show_trace = missing)
202214
if Base.get_extension(@__MODULE__, :NonlinearSolveNLsolveExt) === nothing
203215
error("NLsolveJL requires NLsolve.jl to be loaded")
204216
end
205217

218+
if show_trace !== missing
219+
Base.depwarn("`show_trace` for NLsolveJL has been deprecated and will be removed \
220+
in v4. Use the `show_trace` keyword argument via the logging API \
221+
https://docs.sciml.ai/NonlinearSolve/stable/basics/Logging/ \
222+
instead.")
223+
else
224+
show_trace = false
225+
end
226+
227+
if store_trace !== missing
228+
Base.depwarn("`store_trace` for NLsolveJL has been deprecated and will be removed \
229+
in v4. Use the `store_trace` keyword argument via the logging API \
230+
https://docs.sciml.ai/NonlinearSolve/stable/basics/Logging/ \
231+
instead.")
232+
else
233+
store_trace = false
234+
end
235+
236+
if extended_trace !== missing
237+
Base.depwarn("`extended_trace` for NLsolveJL has been deprecated and will be \
238+
removed in v4. Use the `trace_level = TraceAll()` keyword argument \
239+
via the logging API \
240+
https://docs.sciml.ai/NonlinearSolve/stable/basics/Logging/ instead.")
241+
else
242+
extended_trace = false
243+
end
244+
206245
return NLsolveJL(method, autodiff, store_trace, extended_trace, linesearch, linsolve,
207246
factor, autoscale, m, beta, show_trace)
208247
end

src/utils.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
const DEFAULT_NORM = DiffEqBase.NONLINEARSOLVE_DEFAULT_NORM
22

3+
@inline DEFAULT_TOLERANCE(args...) = DiffEqBase._get_tolerance(args...)
4+
35
@concrete mutable struct FakeLinearSolveJLCache
46
A
57
b

0 commit comments

Comments
 (0)