Skip to content

Commit b7a1ef8

Browse files
committed
Allow specifying an alpha for Broyden
1 parent 8dd6291 commit b7a1ef8

File tree

2 files changed

+41
-23
lines changed

2 files changed

+41
-23
lines changed

src/broyden.jl

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Sadly `Broyden` is taken up by SimpleNonlinearSolve.jl
22
"""
33
GeneralBroyden(; max_resets = 3, linesearch = nothing, reset_tolerance = nothing,
4-
init_jacobian::Val = Val(:identity), autodiff = nothing)
4+
init_jacobian::Val = Val(:identity), autodiff = nothing, alpha = 1.0)
55
66
An implementation of `Broyden` with resetting and line search.
77
@@ -16,6 +16,8 @@ An implementation of `Broyden` with resetting and line search.
1616
used here directly, and they will be converted to the correct `LineSearch`. It is
1717
recommended to use [LiFukushimaLineSearch](@ref) -- a derivative free linesearch
1818
specifically designed for Broyden's method.
19+
- `alpha_initial`: If `init_jacobian` is set to `Val(:identity)`, then the initial
20+
Jacobian inverse is set to be `(αI)⁻¹`. Defaults to `1.0`.
1921
- `init_jacobian`: the method to use for initializing the jacobian. Defaults to using the
2022
identity matrix (`Val(:identitiy)`). Alternatively, can be set to `Val(:true_jacobian)`
2123
to use the true jacobian as initialization.
@@ -33,30 +35,33 @@ An implementation of `Broyden` with resetting and line search.
3335
max_resets::Int
3436
reset_tolerance
3537
linesearch
38+
inv_alpha
3639
end
3740

38-
function __alg_print_modifiers(::GeneralBroyden{IJ, UR}) where {IJ, UR}
41+
function __alg_print_modifiers(alg::GeneralBroyden{IJ, UR}) where {IJ, UR}
3942
modifiers = String[]
4043
IJ !== :identity && push!(modifiers, "init_jacobian = :$(IJ)")
4144
UR !== :good_broyden && push!(modifiers, "update_rule = :$(UR)")
45+
alg.inv_alpha != 1 && push!(modifiers, "alpha = $(1 / alg.inv_alpha)")
4246
return modifiers
4347
end
4448

4549
function set_ad(alg::GeneralBroyden{IJ, UR, CJ}, ad) where {IJ, UR, CJ}
4650
return GeneralBroyden{IJ, UR, CJ}(ad, alg.max_resets, alg.reset_tolerance,
47-
alg.linesearch)
51+
alg.linesearch, alg.inv_alpha)
4852
end
4953

5054
function GeneralBroyden(; max_resets = 3, linesearch = nothing, reset_tolerance = nothing,
51-
init_jacobian::Val = Val(:identity), autodiff = nothing,
55+
init_jacobian::Val = Val(:identity), autodiff = nothing, alpha = 1.0,
5256
update_rule = Val(:good_broyden))
5357
UR = _unwrap_val(update_rule)
5458
@assert UR (:good_broyden, :bad_broyden)
5559
IJ = _unwrap_val(init_jacobian)
5660
@assert IJ (:identity, :true_jacobian)
5761
linesearch = linesearch isa LineSearch ? linesearch : LineSearch(; method = linesearch)
5862
CJ = IJ === :true_jacobian
59-
return GeneralBroyden{IJ, UR, CJ}(autodiff, max_resets, reset_tolerance, linesearch)
63+
return GeneralBroyden{IJ, UR, CJ}(autodiff, max_resets, reset_tolerance, linesearch,
64+
1 / alpha)
6065
end
6166

6267
@concrete mutable struct GeneralBroydenCache{iip, IJ, UR} <:
@@ -109,7 +114,7 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg_::GeneralBroyd
109114
alg = alg_
110115
@bb du = similar(u)
111116
uf, fu_cache, jac_cache = nothing, nothing, nothing
112-
J⁻¹ = __init_identity_jacobian(u, fu)
117+
J⁻¹ = __init_identity_jacobian(u, fu, alg.inv_alpha)
113118
end
114119

115120
reset_tolerance = alg.reset_tolerance === nothing ? sqrt(eps(real(eltype(u)))) :
@@ -162,7 +167,7 @@ function perform_step!(cache::GeneralBroydenCache{iip, IJ, UR}) where {iip, IJ,
162167
if IJ === :true_jacobian
163168
cache.J⁻¹ = inv(jacobian!!(cache.J⁻¹, cache))
164169
else
165-
cache.J⁻¹ = __reinit_identity_jacobian!!(cache.J⁻¹)
170+
cache.J⁻¹ = __reinit_identity_jacobian!!(cache.J⁻¹, cache.alg.inv_alpha)
166171
end
167172
cache.resets += 1
168173
else
@@ -189,7 +194,7 @@ function perform_step!(cache::GeneralBroydenCache{iip, IJ, UR}) where {iip, IJ,
189194
end
190195

191196
function __reinit_internal!(cache::GeneralBroydenCache; kwargs...)
192-
cache.J⁻¹ = __reinit_identity_jacobian!!(cache.J⁻¹)
197+
cache.J⁻¹ = __reinit_identity_jacobian!!(cache.J⁻¹, cache.alg.inv_alpha)
193198
cache.resets = 0
194199
return nothing
195200
end

src/utils.jl

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -315,34 +315,47 @@ function check_and_update!(tc_cache, cache, fu, u, uprev,
315315
end
316316
end
317317

318-
@inline __init_identity_jacobian(u::Number, _) = one(u)
319-
@inline function __init_identity_jacobian(u, fu)
318+
@inline __init_identity_jacobian(u::Number, fu, α = true) = oftype(u, α)
319+
@inline @views function __init_identity_jacobian(u, fu, α = true)
320320
J = similar(fu, promote_type(eltype(fu), eltype(u)), length(fu), length(u))
321321
fill!(J, zero(eltype(J)))
322-
J[diagind(J)] .= one(eltype(J))
322+
if fast_scalar_indexing(J)
323+
@inbounds for i in axes(J, 1)
324+
J[i, i] = α
325+
end
326+
else
327+
J[diagind(J)] .= α
328+
end
323329
return J
324330
end
325-
@inline function __init_identity_jacobian(u::StaticArray, fu::StaticArray)
331+
@inline function __init_identity_jacobian(u::StaticArray, fu::StaticArray, α = true)
326332
T = promote_type(eltype(fu), eltype(u))
327-
return MArray{Tuple{prod(Size(fu)), prod(Size(u))}, T}(I)
333+
return MArray{Tuple{prod(Size(fu)), prod(Size(u))}, T}(I * α)
328334
end
329-
@inline function __init_identity_jacobian(u::SArray, fu::SArray)
335+
@inline function __init_identity_jacobian(u::SArray, fu::SArray, α = true)
330336
T = promote_type(eltype(fu), eltype(u))
331-
return SArray{Tuple{prod(Size(fu)), prod(Size(u))}, T}(I)
337+
return SArray{Tuple{prod(Size(fu)), prod(Size(u))}, T}(I * α)
332338
end
333339

334-
@inline __reinit_identity_jacobian!!(J::Number) = one(J)
335-
@inline __reinit_identity_jacobian!!(J::AbstractVector) = fill!(J, one(eltype(J)))
336-
@inline function __reinit_identity_jacobian!!(J::AbstractMatrix)
340+
@inline __reinit_identity_jacobian!!(J::Number, α = true) = oftype(J, α)
341+
@inline __reinit_identity_jacobian!!(J::AbstractVector, α = true) = fill!(J, α)
342+
@inline @views function __reinit_identity_jacobian!!(J::AbstractMatrix, α = true)
337343
fill!(J, zero(eltype(J)))
338-
J[diagind(J)] .= one(eltype(J))
344+
if fast_scalar_indexing(J)
345+
@inbounds for i in axes(J, 1)
346+
J[i, i] = α
347+
end
348+
else
349+
J[diagind(J)] .= α
350+
end
339351
return J
340352
end
341-
@inline __reinit_identity_jacobian!!(J::SVector) = ones(SArray{
342-
Tuple{Size(J)[1]}, eltype(J)})
343-
@inline function __reinit_identity_jacobian!!(J::SMatrix)
353+
@inline function __reinit_identity_jacobian!!(J::SVector, α = true)
354+
return ones(SArray{Tuple{Size(J)[1]}, eltype(J)}) .* α
355+
end
356+
@inline function __reinit_identity_jacobian!!(J::SMatrix, α = true)
344357
S = Size(J)
345-
return SArray{Tuple{S[1], S[2]}, eltype(J)}(I)
358+
return SArray{Tuple{S[1], S[2]}, eltype(J)}(I) .* α
346359
end
347360

348361
function __init_low_rank_jacobian(u::StaticArray{S1, T1}, fu::StaticArray{S2, T2},

0 commit comments

Comments
 (0)