Skip to content

Commit e22e052

Browse files
committed
materialize the multi-step scheme
1 parent fb88484 commit e22e052

32 files changed

+291
-155
lines changed

Project.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ version = "3.6.0"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
8+
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
89
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
910
ConcreteStructs = "2569d6c7-a4a2-43d3-a901-331e8e4be471"
1011
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
@@ -55,12 +56,13 @@ NonlinearSolveZygoteExt = "Zygote"
5556

5657
[compat]
5758
ADTypes = "0.2.6"
59+
Accessors = "0.1"
5860
Aqua = "0.8"
5961
ArrayInterface = "7.7"
6062
BandedMatrices = "1.4"
6163
BenchmarkTools = "1.4"
62-
ConcreteStructs = "0.2.3"
6364
CUDA = "5.1"
65+
ConcreteStructs = "0.2.3"
6466
DiffEqBase = "6.146.0"
6567
Enzyme = "0.11.11"
6668
FastBroadcast = "0.2.8"

docs/make.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Documenter, DocumenterCitations
22
using NonlinearSolve,
3-
SimpleNonlinearSolve, Sundials, SteadyStateDiffEq, SciMLBase, DiffEqBase
3+
SimpleNonlinearSolve, Sundials, SteadyStateDiffEq, SciMLBase, DiffEqBase
44

55
cp(joinpath(@__DIR__, "Manifest.toml"), joinpath(@__DIR__, "src/assets/Manifest.toml"),
66
force = true)

docs/pages.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,5 @@ pages = [
4343
"devdocs/operators.md",
4444
"devdocs/algorithm_helpers.md"],
4545
"Release Notes" => "release_notes.md",
46-
"References" => "references.md",
46+
"References" => "references.md"
4747
]

docs/src/basics/faq.md

+10-6
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,19 @@ myfun(x, lv) = x * sin(x) - lv
1515
1616
function f(out, levels, u0)
1717
for i in 1:N
18-
out[i] = solve(IntervalNonlinearProblem{false}(IntervalNonlinearFunction{false}(myfun),
19-
u0, levels[i]), Falsi()).u
18+
out[i] = solve(
19+
IntervalNonlinearProblem{false}(IntervalNonlinearFunction{false}(myfun),
20+
u0, levels[i]),
21+
Falsi()).u
2022
end
2123
end
2224
2325
function f2(out, levels, u0)
2426
for i in 1:N
25-
out[i] = solve(NonlinearProblem{false}(NonlinearFunction{false}(myfun),
26-
u0, levels[i]), SimpleNewtonRaphson()).u
27+
out[i] = solve(
28+
NonlinearProblem{false}(NonlinearFunction{false}(myfun),
29+
u0, levels[i]),
30+
SimpleNewtonRaphson()).u
2731
end
2832
end
2933
@@ -68,7 +72,7 @@ differentiate the function based on the input types. However, this function has
6872
`xx = [1.0, 2.0, 3.0, 4.0]` followed by a `xx[1] = var[1] - v_true[1]` where `var` might
6973
be a Dual number. This causes the error. To fix it:
7074

71-
1. Specify the `autodiff` to be `AutoFiniteDiff`
75+
1. Specify the `autodiff` to be `AutoFiniteDiff`
7276

7377
```@example dual_error_faq
7478
sol = solve(prob_oop, LevenbergMarquardt(; autodiff = AutoFiniteDiff()); maxiters = 10000,
@@ -77,7 +81,7 @@ sol = solve(prob_oop, LevenbergMarquardt(; autodiff = AutoFiniteDiff()); maxiter
7781

7882
This worked but, Finite Differencing is not the recommended approach in any scenario.
7983

80-
2. Rewrite the function to use
84+
2. Rewrite the function to use
8185
[PreallocationTools.jl](https://github.com/SciML/PreallocationTools.jl) or write it as
8286

8387
```@example dual_error_faq

docs/src/basics/sparsity_detection.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@ NonlinearSolve will automatically perform matrix coloring and use sparse differe
2222
Now you can help the solver further by providing the color vector. This can be done by
2323

2424
```julia
25-
prob = NonlinearProblem(NonlinearFunction(nlfunc; sparsity = jac_prototype,
25+
prob = NonlinearProblem(
26+
NonlinearFunction(nlfunc; sparsity = jac_prototype,
2627
colorvec = colorvec), x0)
2728
# OR
28-
prob = NonlinearProblem(NonlinearFunction(nlfunc; jac_prototype = jac_prototype,
29+
prob = NonlinearProblem(
30+
NonlinearFunction(nlfunc; jac_prototype = jac_prototype,
2931
colorvec = colorvec), x0)
3032
```
3133

3234
If the `colorvec` is not provided, then it is computed on demand.
3335

3436
!!! note
35-
37+
3638
One thing to be careful about in this case is that `colorvec` is dependent on the
3739
autodiff backend used. Forward Mode and Finite Differencing will assume that the
3840
colorvec is the column colorvec, while Reverse Mode will assume that the colorvec is the
@@ -47,7 +49,8 @@ algorithm you want to use, then you can create your problem as follows:
4749
prob = NonlinearProblem(NonlinearFunction(nlfunc; sparsity = SymbolicsSparsityDetection()),
4850
x0) # Remember to have Symbolics.jl loaded
4951
# OR
50-
prob = NonlinearProblem(NonlinearFunction(nlfunc; sparsity = ApproximateJacobianSparsity()),
52+
prob = NonlinearProblem(
53+
NonlinearFunction(nlfunc; sparsity = ApproximateJacobianSparsity()),
5154
x0)
5255
```
5356

@@ -73,7 +76,7 @@ loaded, we default to using `SymbolicsSparsityDetection()`, else we default to u
7376
options if those are provided.
7477

7578
!!! warning
76-
79+
7780
If you provide a non-sparse AD, and provide a `sparsity` or `jac_prototype` then
7881
we will use dense AD. This is because, if you provide a specific AD type, we assume
7982
that you know what you are doing and want to override the default choice of `nothing`.

docs/src/tutorials/large_systems.md

+17-13
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
This tutorial is for getting into the extra features of using NonlinearSolve.jl. Solving
44
ill-conditioned nonlinear systems requires specializing the linear solver on properties of
5-
the Jacobian in order to cut down on the ``\mathcal{O}(n^3)`` linear solve and the
6-
``\mathcal{O}(n^2)`` back-solves. This tutorial is designed to explain the advanced usage of
5+
the Jacobian in order to cut down on the `\mathcal{O}(n^3)` linear solve and the
6+
`\mathcal{O}(n^2)` back-solves. This tutorial is designed to explain the advanced usage of
77
NonlinearSolve.jl by solving the steady state stiff Brusselator partial differential
88
equation (BRUSS) using NonlinearSolve.jl.
99

1010
## Definition of the Brusselator Equation
1111

1212
!!! note
13-
13+
1414
Feel free to skip this section: it simply defines the example problem.
1515

1616
The Brusselator PDE is defined as follows:
@@ -118,11 +118,11 @@ However, if you know the sparsity of your problem, then you can pass a different
118118
type. For example, a `SparseMatrixCSC` will give a sparse matrix. Other sparse matrix types
119119
include:
120120

121-
- Bidiagonal
122-
- Tridiagonal
123-
- SymTridiagonal
124-
- BandedMatrix ([BandedMatrices.jl](https://github.com/JuliaLinearAlgebra/BandedMatrices.jl))
125-
- BlockBandedMatrix ([BlockBandedMatrices.jl](https://github.com/JuliaLinearAlgebra/BlockBandedMatrices.jl))
121+
- Bidiagonal
122+
- Tridiagonal
123+
- SymTridiagonal
124+
- BandedMatrix ([BandedMatrices.jl](https://github.com/JuliaLinearAlgebra/BandedMatrices.jl))
125+
- BlockBandedMatrix ([BlockBandedMatrices.jl](https://github.com/JuliaLinearAlgebra/BlockBandedMatrices.jl))
126126

127127
## Approximate Sparsity Detection & Sparse Jacobians
128128

@@ -213,7 +213,7 @@ choices, see the
213213
`linsolve` choices are any valid [LinearSolve.jl](https://linearsolve.sciml.ai/dev/) solver.
214214

215215
!!! note
216-
216+
217217
Switching to a Krylov linear solver will automatically change the nonlinear problem
218218
solver into Jacobian-free mode, dramatically reducing the memory required. This can be
219219
overridden by adding `concrete_jac=true` to the algorithm.
@@ -308,10 +308,14 @@ for the exact sparsity detection case, we left out the time it takes to perform
308308
sparsity detection. Let's compare the two by setting the sparsity detection algorithms.
309309

310310
```@example ill_conditioned_nlprob
311-
prob_brusselator_2d_exact = NonlinearProblem(NonlinearFunction(brusselator_2d_loop;
312-
sparsity = SymbolicsSparsityDetection()), u0, p; abstol = 1e-10, reltol = 1e-10)
313-
prob_brusselator_2d_approx = NonlinearProblem(NonlinearFunction(brusselator_2d_loop;
314-
sparsity = ApproximateJacobianSparsity()), u0, p; abstol = 1e-10, reltol = 1e-10)
311+
prob_brusselator_2d_exact = NonlinearProblem(
312+
NonlinearFunction(brusselator_2d_loop;
313+
sparsity = SymbolicsSparsityDetection()),
314+
u0, p; abstol = 1e-10, reltol = 1e-10)
315+
prob_brusselator_2d_approx = NonlinearProblem(
316+
NonlinearFunction(brusselator_2d_loop;
317+
sparsity = ApproximateJacobianSparsity()),
318+
u0, p; abstol = 1e-10, reltol = 1e-10)
315319
316320
@btime solve(prob_brusselator_2d_exact, NewtonRaphson());
317321
@btime solve(prob_brusselator_2d_approx, NewtonRaphson());

docs/src/tutorials/modelingtoolkit.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ u0 = [x => 1.0,
2222
z => 0.0]
2323
2424
ps = [σ => 10.0
25-
ρ => 26.0
26-
β => 8 / 3]
25+
ρ => 26.0
26+
β => 8 / 3]
2727
2828
prob = NonlinearProblem(ns, u0, ps)
2929
sol = solve(prob, NewtonRaphson())
@@ -65,7 +65,7 @@ eqs = [
6565
0 ~ u2 - cos(u1),
6666
0 ~ u3 - hypot(u1, u2),
6767
0 ~ u4 - hypot(u2, u3),
68-
0 ~ u5 - hypot(u4, u1),
68+
0 ~ u5 - hypot(u4, u1)
6969
]
7070
@named sys = NonlinearSystem(eqs, [u1, u2, u3, u4, u5], [])
7171
```

ext/NonlinearSolveMINPACKExt.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ using MINPACK, NonlinearSolve, SciMLBase
44
import FastClosures: @closure
55

66
function SciMLBase.__solve(prob::Union{NonlinearLeastSquaresProblem,
7-
NonlinearProblem}, alg::CMINPACK, args...; abstol = nothing, maxiters = 1000,
7+
NonlinearProblem},
8+
alg::CMINPACK, args...; abstol = nothing, maxiters = 1000,
89
alias_u0::Bool = false, show_trace::Val{ShT} = Val(false),
910
store_trace::Val{StT} = Val(false), termination_condition = nothing,
1011
kwargs...) where {ShT, StT}

src/NonlinearSolve.jl

+30-21
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,23 @@ import Reexport: @reexport
88
import PrecompileTools: @recompile_invalidations, @compile_workload, @setup_workload
99

1010
@recompile_invalidations begin
11-
using ADTypes, ConcreteStructs, DiffEqBase, FastBroadcast, FastClosures, LazyArrays,
12-
LineSearches, LinearAlgebra, LinearSolve, MaybeInplace, Preferences, Printf,
13-
SciMLBase, SimpleNonlinearSolve, SparseArrays, SparseDiffTools
11+
using Accessors, ADTypes, ConcreteStructs, DiffEqBase, FastBroadcast, FastClosures,
12+
LazyArrays, LineSearches, LinearAlgebra, LinearSolve, MaybeInplace, Preferences,
13+
Printf, SciMLBase, SimpleNonlinearSolve, SparseArrays, SparseDiffTools
1414

1515
import ArrayInterface: undefmatrix, can_setindex, restructure, fast_scalar_indexing
1616
import DiffEqBase: AbstractNonlinearTerminationMode,
17-
AbstractSafeNonlinearTerminationMode, AbstractSafeBestNonlinearTerminationMode,
18-
NonlinearSafeTerminationReturnCode, get_termination_mode
17+
AbstractSafeNonlinearTerminationMode,
18+
AbstractSafeBestNonlinearTerminationMode,
19+
NonlinearSafeTerminationReturnCode, get_termination_mode
1920
import FiniteDiff
2021
import ForwardDiff
2122
import ForwardDiff: Dual
2223
import LinearSolve: ComposePreconditioner, InvPreconditioner, needs_concrete_A
2324
import RecursiveArrayTools: recursivecopy!, recursivefill!
2425

2526
import SciMLBase: AbstractNonlinearAlgorithm, JacobianWrapper, AbstractNonlinearProblem,
26-
AbstractSciMLOperator, NLStats, _unwrap_val, has_jac, isinplace
27+
AbstractSciMLOperator, NLStats, _unwrap_val, has_jac, isinplace
2728
import SparseDiffTools: AbstractSparsityDetection, AutoSparseEnzyme
2829
import StaticArraysCore: StaticArray, SVector, SArray, MArray, Size, SMatrix, MMatrix
2930
end
@@ -98,20 +99,28 @@ include("default.jl")
9899
probs_nlls = NonlinearLeastSquaresProblem[]
99100
nlfuncs = ((NonlinearFunction{false}((u, p) -> (u .^ 2 .- p)[1:1]), [0.1, 0.0]),
100101
(NonlinearFunction{false}((u, p) -> vcat(u .* u .- p, u .* u .- p)), [0.1, 0.1]),
101-
(NonlinearFunction{true}((du, u, p) -> du[1] = u[1] * u[1] - p,
102-
resid_prototype = zeros(1)), [0.1, 0.0]),
103-
(NonlinearFunction{true}((du, u, p) -> du .= vcat(u .* u .- p, u .* u .- p),
104-
resid_prototype = zeros(4)), [0.1, 0.1]))
102+
(
103+
NonlinearFunction{true}((du, u, p) -> du[1] = u[1] * u[1] - p,
104+
resid_prototype = zeros(1)),
105+
[0.1, 0.0]),
106+
(
107+
NonlinearFunction{true}((du, u, p) -> du .= vcat(u .* u .- p, u .* u .- p),
108+
resid_prototype = zeros(4)),
109+
[0.1, 0.1]))
105110
for (fn, u0) in nlfuncs
106111
push!(probs_nlls, NonlinearLeastSquaresProblem(fn, u0, 2.0))
107112
end
108113
nlfuncs = ((NonlinearFunction{false}((u, p) -> (u .^ 2 .- p)[1:1]), Float32[0.1, 0.0]),
109114
(NonlinearFunction{false}((u, p) -> vcat(u .* u .- p, u .* u .- p)),
110115
Float32[0.1, 0.1]),
111-
(NonlinearFunction{true}((du, u, p) -> du[1] = u[1] * u[1] - p,
112-
resid_prototype = zeros(Float32, 1)), Float32[0.1, 0.0]),
113-
(NonlinearFunction{true}((du, u, p) -> du .= vcat(u .* u .- p, u .* u .- p),
114-
resid_prototype = zeros(Float32, 4)), Float32[0.1, 0.1]))
116+
(
117+
NonlinearFunction{true}((du, u, p) -> du[1] = u[1] * u[1] - p,
118+
resid_prototype = zeros(Float32, 1)),
119+
Float32[0.1, 0.0]),
120+
(
121+
NonlinearFunction{true}((du, u, p) -> du .= vcat(u .* u .- p, u .* u .- p),
122+
resid_prototype = zeros(Float32, 4)),
123+
Float32[0.1, 0.1]))
115124
for (fn, u0) in nlfuncs
116125
push!(probs_nlls, NonlinearLeastSquaresProblem(fn, u0, 2.0f0))
117126
end
@@ -133,21 +142,21 @@ end
133142

134143
# Core Algorithms
135144
export NewtonRaphson, PseudoTransient, Klement, Broyden, LimitedMemoryBroyden, DFSane,
136-
MultiStepNonlinearSolver
145+
MultiStepNonlinearSolver
137146
export GaussNewton, LevenbergMarquardt, TrustRegion
138147
export NonlinearSolvePolyAlgorithm,
139-
RobustMultiNewton, FastShortcutNonlinearPolyalg, FastShortcutNLLSPolyalg
148+
RobustMultiNewton, FastShortcutNonlinearPolyalg, FastShortcutNLLSPolyalg
140149

141150
# Extension Algorithms
142151
export LeastSquaresOptimJL, FastLevenbergMarquardtJL, CMINPACK, NLsolveJL,
143-
FixedPointAccelerationJL, SpeedMappingJL, SIAMFANLEquationsJL
152+
FixedPointAccelerationJL, SpeedMappingJL, SIAMFANLEquationsJL
144153

145154
# Advanced Algorithms -- Without Bells and Whistles
146155
export GeneralizedFirstOrderAlgorithm, ApproximateJacobianSolveAlgorithm, GeneralizedDFSane
147156

148157
# Descent Algorithms
149158
export NewtonDescent, SteepestDescent, Dogleg, DampedNewtonDescent,
150-
GeodesicAcceleration, GenericMultiStepDescent
159+
GeodesicAcceleration, GenericMultiStepDescent
151160
## Multistep Algorithms
152161
export MultiStepSchemes
153162

@@ -159,9 +168,9 @@ export RadiusUpdateSchemes
159168

160169
# Export the termination conditions from DiffEqBase
161170
export SteadyStateDiffEqTerminationMode, SimpleNonlinearSolveTerminationMode,
162-
NormTerminationMode, RelTerminationMode, RelNormTerminationMode, AbsTerminationMode,
163-
AbsNormTerminationMode, RelSafeTerminationMode, AbsSafeTerminationMode,
164-
RelSafeBestTerminationMode, AbsSafeBestTerminationMode
171+
NormTerminationMode, RelTerminationMode, RelNormTerminationMode, AbsTerminationMode,
172+
AbsNormTerminationMode, RelSafeTerminationMode, AbsSafeTerminationMode,
173+
RelSafeBestTerminationMode, AbsSafeBestTerminationMode
165174

166175
# Tracing Functionality
167176
export TraceAll, TraceMinimal, TraceWithJacobianConditionNumber

src/abstract_types.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ squares solver.
1616
### `__internal_init` specification
1717
1818
```julia
19-
__internal_init(prob::NonlinearProblem{uType, iip}, alg::AbstractDescentAlgorithm, J, fu, u;
19+
__internal_init(
20+
prob::NonlinearProblem{uType, iip}, alg::AbstractDescentAlgorithm, J, fu, u;
2021
pre_inverted::Val{INV} = Val(false), linsolve_kwargs = (;), abstol = nothing,
2122
reltol = nothing, alias_J::Bool = true, shared::Val{N} = Val(1),
2223
kwargs...) where {INV, N, uType, iip} --> AbstractDescentCache
@@ -225,7 +226,8 @@ Abstract Type for Damping Functions in DampedNewton.
225226
### `__internal_init` specification
226227
227228
```julia
228-
__internal_init(prob::AbstractNonlinearProblem, f::AbstractDampingFunction, initial_damping,
229+
__internal_init(
230+
prob::AbstractNonlinearProblem, f::AbstractDampingFunction, initial_damping,
229231
J, fu, u, args...; internal_norm = DEFAULT_NORM,
230232
kwargs...) --> AbstractDampingFunctionCache
231233
```

src/algorithms/broyden.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ search.
2828
useful for specific problems, but whether it will work may depend strongly on the
2929
problem
3030
"""
31-
function Broyden(; max_resets = 100, linesearch = NoLineSearch(), reset_tolerance = nothing,
31+
function Broyden(;
32+
max_resets = 100, linesearch = NoLineSearch(), reset_tolerance = nothing,
3233
init_jacobian::Val{IJ} = Val(:identity), autodiff = nothing, alpha = nothing,
3334
update_rule::Val{UR} = Val(:good_broyden)) where {IJ, UR}
3435
if IJ === :identity

src/algorithms/dfsane.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ For other keyword arguments, see [`RobustNonMonotoneLineSearch`](@ref).
1919
function DFSane(; σ_min = 1 // 10^10, σ_max = 1e10, σ_1 = 1, M::Int = 10, γ = 1 // 10^4,
2020
τ_min = 1 // 10, τ_max = 1 // 2, n_exp::Int = 2, max_inner_iterations::Int = 100,
2121
η_strategy::ETA = (fn_1, n, x_n, f_n) -> fn_1 / n^2) where {ETA}
22-
linesearch = RobustNonMonotoneLineSearch(; gamma = γ, sigma_1 = σ_1, M, tau_min = τ_min,
22+
linesearch = RobustNonMonotoneLineSearch(;
23+
gamma = γ, sigma_1 = σ_1, M, tau_min = τ_min,
2324
tau_max = τ_max, n_exp, η_strategy, maxiters = max_inner_iterations)
2425
return GeneralizedDFSane{:DFSane}(linesearch, σ_min, σ_max, nothing)
2526
end

0 commit comments

Comments
 (0)