Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

Commit 59b0d96

Browse files
committed
Make DFSane non-allocating as well
1 parent ce8353d commit 59b0d96

File tree

3 files changed

+43
-26
lines changed

3 files changed

+43
-26
lines changed

src/nlsolve/dfsane.jl

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
SimpleDFSane(; σ_min::Real = 1e-10, σ_max::Real = 1e10, σ_1::Real = 1.0,
3-
M::Int = 10, γ::Real = 1e-4, τ_min::Real = 0.1, τ_max::Real = 0.5,
3+
M::Union{Int, Val} = Val(10), γ::Real = 1e-4, τ_min::Real = 0.1, τ_max::Real = 0.5,
44
nexp::Int = 2, η_strategy::Function = (f_1, k, x, F) -> f_1 ./ k^2)
55
66
A low-overhead implementation of the df-sane method for solving large-scale nonlinear
@@ -42,21 +42,26 @@ see the paper [1].
4242
information for solving large-scale nonlinear systems of equations, Mathematics of
4343
Computation, 75, 1429-1448.
4444
"""
45-
@kwdef @concrete struct SimpleDFSane <: AbstractSimpleNonlinearSolveAlgorithm
46-
σ_min = 1e-10
47-
σ_max = 1e10
48-
σ_1 = 1.0
49-
M::Int = 10
50-
γ = 1e-4
51-
τ_min = 0.1
52-
τ_max = 0.5
53-
nexp::Int = 2
54-
η_strategy = (f_1, k, x, F) -> f_1 ./ k^2
45+
@concrete struct SimpleDFSane{M} <: AbstractSimpleNonlinearSolveAlgorithm
46+
σ_min
47+
σ_max
48+
σ_1
49+
γ
50+
τ_min
51+
τ_max
52+
nexp::Int
53+
η_strategy
5554
end
5655

57-
function SciMLBase.__solve(prob::NonlinearProblem, alg::SimpleDFSane, args...;
56+
function SimpleDFSane(; σ_min::Real = 1e-10, σ_max::Real = 1e10, σ_1::Real = 1.0,
57+
M::Union{Int, Val} = Val(10), γ::Real = 1e-4, τ_min::Real = 0.1, τ_max::Real = 0.5,
58+
nexp::Int = 2, η_strategy::F = (f_1, k, x, F) -> f_1 ./ k^2) where {F}
59+
return SimpleDFSane{SciMLBase._unwrap_val(M)}(σ_min, σ_max, σ_1, γ, τ_min, τ_max, nexp, η_strategy)
60+
end
61+
62+
function SciMLBase.__solve(prob::NonlinearProblem, alg::SimpleDFSane{M}, args...;
5863
abstol = nothing, reltol = nothing, maxiters = 1000, alias_u0 = false,
59-
termination_condition = nothing, kwargs...)
64+
termination_condition = nothing, kwargs...) where {M}
6065
x = __maybe_unaliased(prob.u0, alias_u0)
6166
fx = _get_fx(prob, x)
6267
T = eltype(x)
@@ -65,7 +70,7 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::SimpleDFSane, args...;
6570
σ_max = T(alg.σ_max)
6671
σ_k = T(alg.σ_1)
6772

68-
(; M, nexp, η_strategy) = alg
73+
(; nexp, η_strategy) = alg
6974
γ = T(alg.γ)
7075
τ_min = T(alg.τ_min)
7176
τ_max = T(alg.τ_max)
@@ -77,7 +82,11 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::SimpleDFSane, args...;
7782
α_1 = one(T)
7883
f_1 = fx_norm
7984

80-
history_f_k = fill(fx_norm, M)
85+
history_f_k = if x isa SArray
86+
ones(SVector{M, T}) * fx_norm
87+
else
88+
fill(fx_norm, M)
89+
end
8190

8291
# Generate the cache
8392
@bb x_cache = similar(x)
@@ -143,7 +152,11 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::SimpleDFSane, args...;
143152
fx_norm = fx_norm_new
144153

145154
# Store function value
146-
history_f_k[mod1(k, M)] = fx_norm_new
155+
if history_f_k isa SVector
156+
history_f_k = Base.setindex(history_f_k, fx_norm_new, mod1(k, M))
157+
else
158+
history_f_k[mod1(k, M)] = fx_norm_new
159+
end
147160
k += 1
148161
end
149162

src/nlsolve/lbroyden.jl

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ function __static_solve(prob::NonlinearProblem{<:SArray}, alg::SimpleLimitedMemo
107107
fx = _get_fx(prob, x)
108108
threshold = __get_threshold(alg)
109109

110-
U, Vᵀ = __init_low_rank_jacobian(x, fx, threshold)
110+
U, Vᵀ = __init_low_rank_jacobian(vec(x), vec(fx), threshold)
111111

112112
abstol = DiffEqBase._get_tolerance(abstol, eltype(x))
113113

@@ -230,8 +230,8 @@ function __mapdot(x::SVector{S1}, Y::SVector{S2, <:SVector{S1}}) where {S1, S2}
230230
end
231231
@generated function __mapTdot(x::SVector{S1}, Y::SVector{S1, <:SVector{S2}}) where {S1, S2}
232232
calls = []
233-
syms = [gensym("m$(i)") for i in 1:length(Y)]
234-
for i in 1:length(Y)
233+
syms = [gensym("m$(i)") for i in 1:S1]
234+
for i in 1:S1
235235
push!(calls, :($(syms[i]) = x[$(i)] .* Y[$i]))
236236
end
237237
push!(calls, :(return .+($(syms...))))
@@ -259,18 +259,21 @@ function __init_low_rank_jacobian(u::StaticArray{S1, T1}, fu::StaticArray{S2, T2
259259
U = MArray{Tuple{prod(fuSize), threshold}, T}(undef)
260260
return U, Vᵀ
261261
end
262-
@generated function __init_low_rank_jacobian(u::SArray{S1, T1}, fu::SArray{S2, T2},
263-
::Val{threshold}) where {S1, S2, T1, T2, threshold}
262+
263+
@generated function __init_low_rank_jacobian(u::SVector{Lu, T1}, fu::SVector{Lfu, T2},
264+
::Val{threshold}) where {Lu, Lfu, T1, T2, threshold}
264265
T = promote_type(T1, T2)
265-
Lfu, Lu = prod(Size(fu)), prod(Size(u))
266-
inner_inits_Vᵀ = [zeros(SVector{Lu, T}) for i in 1:threshold]
267-
inner_inits_U = [zeros(SVector{Lfu, T}) for i in 1:threshold]
266+
# Lfu, Lu = __prod_size(S2), __prod_size(S1)
267+
# Lfu, Lu = __prod(Size(fu)), __prod(Size(u))
268+
inner_inits_Vᵀ = [:(zeros(SVector{$Lu, $T})) for i in 1:threshold]
269+
inner_inits_U = [:(zeros(SVector{$Lfu, $T})) for i in 1:threshold]
268270
return quote
269271
Vᵀ = SVector($(inner_inits_Vᵀ...))
270272
U = SVector($(inner_inits_U...))
271273
return U, Vᵀ
272274
end
273275
end
276+
274277
function __init_low_rank_jacobian(u, fu, ::Val{threshold}) where {threshold}
275278
Vᵀ = similar(u, threshold, length(u))
276279
U = similar(u, length(fu), threshold)

test/basictests.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ end
164164
## SimpleDFSane needs to allocate a history vector
165165
@testset "Allocation Checks: $(_nameof(alg))" for alg in (SimpleNewtonRaphson(),
166166
SimpleHalley(), SimpleBroyden(), SimpleKlement(), SimpleLimitedMemoryBroyden(),
167-
SimpleTrustRegion())
167+
SimpleTrustRegion(), SimpleDFSane())
168168
@check_allocs nlsolve(prob, alg) = SciMLBase.solve(prob, alg; abstol = 1e-9)
169169

170170
nlprob_scalar = NonlinearProblem{false}(quadratic_f, 1.0, 2.0)
@@ -175,7 +175,8 @@ end
175175
@test true
176176
catch e
177177
@error e
178-
@test false
178+
# History Vector Allocates
179+
@test false broken=(alg isa SimpleDFSane)
179180
end
180181

181182
# ForwardDiff allocates for hessian since we don't propagate the chunksize

0 commit comments

Comments
 (0)