Skip to content

Commit

Permalink
Add Limited Memory Broyden
Browse files Browse the repository at this point in the history
  • Loading branch information
avik-pal committed Oct 23, 2023
1 parent ee5e5b8 commit 4dc40bc
Show file tree
Hide file tree
Showing 7 changed files with 398 additions and 14 deletions.
3 changes: 2 additions & 1 deletion src/NonlinearSolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ include("dfsane.jl")
include("pseudotransient.jl")
include("broyden.jl")
include("klement.jl")
include("lbroyden.jl")
include("jacobian.jl")
include("ad.jl")
include("default.jl")
Expand Down Expand Up @@ -106,7 +107,7 @@ end
export RadiusUpdateSchemes

export NewtonRaphson, TrustRegion, LevenbergMarquardt, DFSane, GaussNewton, PseudoTransient,
GeneralBroyden, GeneralKlement
GeneralBroyden, GeneralKlement, LimitedMemoryBroyden
export LeastSquaresOptimJL, FastLevenbergMarquardtJL
export RobustMultiNewton, FastShortcutNonlinearPolyalg

Expand Down
37 changes: 28 additions & 9 deletions src/broyden.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# Sadly `Broyden` is taken up by SimpleNonlinearSolve.jl
"""
GeneralBroyden(max_resets, linesearch)
GeneralBroyden(; max_resets = 3, linesearch = LineSearch())
GeneralBroyden(; max_resets = 3, linesearch = LineSearch(), reset_tolerance = nothing)
An implementation of `Broyden` with reseting and line search.
## Arguments
- `max_resets`: the maximum number of resets to perform. Defaults to `3`.
- `reset_tolerance`: the tolerance for the reset check. Defaults to
`sqrt(eps(eltype(u)))`.
- `linesearch`: the line search algorithm to use. Defaults to [`LineSearch()`](@ref),
which means that no line search is performed. Algorithms from `LineSearches.jl` can be
used here directly, and they will be converted to the correct `LineSearch`. It is
Expand All @@ -16,12 +17,14 @@ An implementation of `Broyden` with reseting and line search.
"""
@concrete struct GeneralBroyden <: AbstractNewtonAlgorithm{false, Nothing}
max_resets::Int
reset_tolerance
linesearch
end

function GeneralBroyden(; max_resets = 3, linesearch = LineSearch())
function GeneralBroyden(; max_resets = 3, linesearch = LineSearch(),

Check warning on line 24 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L24

Added line #L24 was not covered by tests
reset_tolerance = nothing)
linesearch = linesearch isa LineSearch ? linesearch : LineSearch(; method = linesearch)
return GeneralBroyden(max_resets, linesearch)
return GeneralBroyden(max_resets, reset_tolerance, linesearch)

Check warning on line 27 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L26-L27

Added lines #L26 - L27 were not covered by tests
end

@concrete mutable struct GeneralBroydenCache{iip} <: AbstractNonlinearSolveCache{iip}
Expand All @@ -43,6 +46,8 @@ end
internalnorm
retcode::ReturnCode.T
abstol
reset_tolerance
reset_check
prob
stats::NLStats
lscache
Expand All @@ -57,9 +62,13 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::GeneralBroyde
u = alias_u0 ? u0 : deepcopy(u0)
fu = evaluate_f(prob, u)
J⁻¹ = __init_identity_jacobian(u, fu)
reset_tolerance = alg.reset_tolerance === nothing ? sqrt(eps(eltype(u))) :

Check warning on line 65 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L61-L65

Added lines #L61 - L65 were not covered by tests
alg.reset_tolerance
reset_check = x -> abs(x) reset_tolerance
return GeneralBroydenCache{iip}(f, alg, u, _mutable_zero(u), fu, zero(fu),

Check warning on line 68 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L67-L68

Added lines #L67 - L68 were not covered by tests
zero(fu), p, J⁻¹, zero(_vec(fu)'), _mutable_zero(u), false, 0, alg.max_resets,
maxiters, internalnorm, ReturnCode.Default, abstol, prob, NLStats(1, 0, 0, 0, 0),
maxiters, internalnorm, ReturnCode.Default, abstol, reset_tolerance,
reset_check, prob, NLStats(1, 0, 0, 0, 0),
init_linesearch_cache(alg.linesearch, f, u, p, fu, Val(iip)))
end

Expand All @@ -79,8 +88,13 @@ function perform_step!(cache::GeneralBroydenCache{true})

# Update the inverse jacobian
dfu .= fu2 .- fu

Check warning on line 90 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L90

Added line #L90 was not covered by tests
if cache.resets < cache.max_resets &&
(all(x -> abs(x) 1e-12, du) || all(x -> abs(x) 1e-12, dfu))

if all(cache.reset_check, du) || all(cache.reset_check, dfu)
if cache.resets cache.max_resets
cache.retcode = ReturnCode.Unstable
cache.force_stop = true
return nothing

Check warning on line 96 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L92-L96

Added lines #L92 - L96 were not covered by tests
end
fill!(J⁻¹, 0)
J⁻¹[diagind(J⁻¹)] .= T(1)
cache.resets += 1

Check warning on line 100 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L98-L100

Added lines #L98 - L100 were not covered by tests
Expand Down Expand Up @@ -111,8 +125,12 @@ function perform_step!(cache::GeneralBroydenCache{false})

# Update the inverse jacobian
cache.dfu = cache.fu2 .- cache.fu
if cache.resets < cache.max_resets &&
(all(x -> abs(x) 1e-12, cache.du) || all(x -> abs(x) 1e-12, cache.dfu))
if all(cache.reset_check, cache.du) || all(cache.reset_check, cache.dfu)
if cache.resets cache.max_resets
cache.retcode = ReturnCode.Unstable
cache.force_stop = true
return nothing

Check warning on line 132 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L127-L132

Added lines #L127 - L132 were not covered by tests
end
cache.J⁻¹ = __init_identity_jacobian(cache.u, cache.fu)
cache.resets += 1

Check warning on line 135 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L134-L135

Added lines #L134 - L135 were not covered by tests
else
Expand Down Expand Up @@ -141,6 +159,7 @@ function SciMLBase.reinit!(cache::GeneralBroydenCache{iip}, u0 = cache.u; p = ca
cache.maxiters = maxiters
cache.stats.nf = 1
cache.stats.nsteps = 1
cache.resets = 0
cache.force_stop = false
cache.retcode = ReturnCode.Default
return cache

Check warning on line 165 in src/broyden.jl

View check run for this annotation

Codecov / codecov/patch

src/broyden.jl#L158-L165

Added lines #L158 - L165 were not covered by tests
Expand Down
260 changes: 260 additions & 0 deletions src/lbroyden.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
"""
LimitedMemoryBroyden(; max_resets::Int = 3, linesearch = LineSearch(),
threshold::Int = 10, reset_tolerance = nothing)
An implementation of `LimitedMemoryBroyden` with reseting and line search.
## Arguments
- `max_resets`: the maximum number of resets to perform. Defaults to `3`.
- `reset_tolerance`: the tolerance for the reset check. Defaults to
`sqrt(eps(eltype(u)))`.
- `threshold`: the number of vectors to store in the low rank approximation. Defaults
to `10`.
- `linesearch`: the line search algorithm to use. Defaults to [`LineSearch()`](@ref),
which means that no line search is performed. Algorithms from `LineSearches.jl` can be
used here directly, and they will be converted to the correct `LineSearch`. It is
recommended to use [LiFukushimaLineSearchCache](@ref) -- a derivative free linesearch
specifically designed for Broyden's method.
"""
@concrete struct LimitedMemoryBroyden <: AbstractNewtonAlgorithm{false, Nothing}
max_resets::Int
threshold::Int
linesearch
reset_tolerance
end

function LimitedMemoryBroyden(; max_resets::Int = 3, linesearch = LineSearch(),

Check warning on line 27 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L27

Added line #L27 was not covered by tests
threshold::Int = 10, reset_tolerance = nothing)
linesearch = linesearch isa LineSearch ? linesearch : LineSearch(; method = linesearch)
return LimitedMemoryBroyden(max_resets, threshold, linesearch, reset_tolerance)

Check warning on line 30 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L29-L30

Added lines #L29 - L30 were not covered by tests
end

@concrete mutable struct LimitedMemoryBroydenCache{iip} <: AbstractNonlinearSolveCache{iip}
f
alg
u
du
fu
fu2
dfu
p
U
Vᵀ
Ux
xᵀVᵀ
u_cache
vᵀ_cache
force_stop::Bool
resets::Int
iterations_since_reset::Int
max_resets::Int
maxiters::Int
internalnorm
retcode::ReturnCode.T
abstol
reset_tolerance
reset_check
prob
stats::NLStats
lscache
end

get_fu(cache::LimitedMemoryBroydenCache) = cache.fu

Check warning on line 63 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L63

Added line #L63 was not covered by tests

function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::LimitedMemoryBroyden,

Check warning on line 65 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L65

Added line #L65 was not covered by tests
args...; alias_u0 = false, maxiters = 1000, abstol = 1e-6, internalnorm = DEFAULT_NORM,
kwargs...) where {uType, iip}
@unpack f, u0, p = prob
u = alias_u0 ? u0 : deepcopy(u0)
if u isa Number

Check warning on line 70 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L68-L70

Added lines #L68 - L70 were not covered by tests
# If u is a number then we simply use Broyden
return SciMLBase.__init(prob,

Check warning on line 72 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L72

Added line #L72 was not covered by tests
GeneralBroyden(; alg.max_resets, alg.reset_tolerance,
alg.linesearch), args...; alias_u0, maxiters, abstol, internalnorm, kwargs...)
end
fu = evaluate_f(prob, u)
threshold = min(alg.threshold, maxiters)
U, Vᵀ = __init_low_rank_jacobian(u, fu, threshold)
du = -fu
reset_tolerance = alg.reset_tolerance === nothing ? sqrt(eps(eltype(u))) :

Check warning on line 80 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L76-L80

Added lines #L76 - L80 were not covered by tests
alg.reset_tolerance
reset_check = x -> abs(x) reset_tolerance
return LimitedMemoryBroydenCache{iip}(f, alg, u, du, fu, zero(fu),

Check warning on line 83 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L82-L83

Added lines #L82 - L83 were not covered by tests
zero(fu), p, U, Vᵀ, similar(u, threshold), similar(u, 1, threshold),
zero(u), zero(u), false, 0, 0, alg.max_resets, maxiters, internalnorm,
ReturnCode.Default, abstol, reset_tolerance, reset_check, prob,
NLStats(1, 0, 0, 0, 0),
init_linesearch_cache(alg.linesearch, f, u, p, fu, Val(iip)))
end

function perform_step!(cache::LimitedMemoryBroydenCache{true})
@unpack f, p, du, u = cache
T = eltype(u)

Check warning on line 93 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L91-L93

Added lines #L91 - L93 were not covered by tests

α = perform_linesearch!(cache.lscache, u, du)
axpy!(α, du, u)
f(cache.fu2, u, p)

Check warning on line 97 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L95-L97

Added lines #L95 - L97 were not covered by tests

cache.internalnorm(cache.fu2) < cache.abstol && (cache.force_stop = true)
cache.stats.nf += 1

Check warning on line 100 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L99-L100

Added lines #L99 - L100 were not covered by tests

cache.force_stop && return nothing

Check warning on line 102 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L102

Added line #L102 was not covered by tests

# Update the Inverse Jacobian Approximation
cache.dfu .= cache.fu2 .- cache.fu

Check warning on line 105 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L105

Added line #L105 was not covered by tests

# Only try to reset if we have enough iterations since last reset
if cache.iterations_since_reset > size(cache.U, 1) &&

Check warning on line 108 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L108

Added line #L108 was not covered by tests
(all(cache.reset_check, du) || all(cache.reset_check, cache.dfu))
if cache.resets cache.max_resets
cache.retcode = ReturnCode.Unstable
cache.force_stop = true
return nothing

Check warning on line 113 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L110-L113

Added lines #L110 - L113 were not covered by tests
end
cache.iterations_since_reset = 0
cache.resets += 1
cache.du .= -cache.fu

Check warning on line 117 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L115-L117

Added lines #L115 - L117 were not covered by tests
else
idx = min(cache.iterations_since_reset, size(cache.U, 1))
U_part = selectdim(cache.U, 1, 1:idx)
Vᵀ_part = selectdim(cache.Vᵀ, 2, 1:idx)

Check warning on line 121 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L119-L121

Added lines #L119 - L121 were not covered by tests

__lbroyden_matvec!(_vec(cache.vᵀ_cache), cache.Ux, U_part, Vᵀ_part, _vec(cache.du))
__lbroyden_rmatvec!(_vec(cache.u_cache), cache.xᵀVᵀ, U_part, Vᵀ_part,

Check warning on line 124 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L123-L124

Added lines #L123 - L124 were not covered by tests
_vec(cache.dfu))
cache.u_cache .= (du .- cache.u_cache) ./

Check warning on line 126 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L126

Added line #L126 was not covered by tests
(dot(cache.vᵀ_cache, cache.dfu) .+ T(1e-5))

idx = mod1(cache.iterations_since_reset + 1, size(cache.U, 1))
selectdim(cache.U, 1, idx) .= _vec(cache.u_cache)
selectdim(cache.Vᵀ, 2, idx) .= _vec(cache.vᵀ_cache)

Check warning on line 131 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L129-L131

Added lines #L129 - L131 were not covered by tests

idx = min(cache.iterations_since_reset + 1, size(cache.U, 1))
U_part = selectdim(cache.U, 1, 1:idx)
Vᵀ_part = selectdim(cache.Vᵀ, 2, 1:idx)
__lbroyden_matvec!(_vec(cache.du), cache.Ux, U_part, Vᵀ_part, _vec(cache.fu2))
cache.du .*= -1
cache.iterations_since_reset += 1

Check warning on line 138 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L133-L138

Added lines #L133 - L138 were not covered by tests
end

cache.fu .= cache.fu2

Check warning on line 141 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L141

Added line #L141 was not covered by tests

return nothing

Check warning on line 143 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L143

Added line #L143 was not covered by tests
end

function perform_step!(cache::LimitedMemoryBroydenCache{false})
@unpack f, p = cache
T = eltype(cache.u)

Check warning on line 148 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L146-L148

Added lines #L146 - L148 were not covered by tests

α = perform_linesearch!(cache.lscache, cache.u, cache.du)
cache.u = cache.u .+ α * cache.du
cache.fu2 = f(cache.u, p)

Check warning on line 152 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L150-L152

Added lines #L150 - L152 were not covered by tests

cache.internalnorm(cache.fu2) < cache.abstol && (cache.force_stop = true)
cache.stats.nf += 1

Check warning on line 155 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L154-L155

Added lines #L154 - L155 were not covered by tests

cache.force_stop && return nothing

Check warning on line 157 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L157

Added line #L157 was not covered by tests

# Update the Inverse Jacobian Approximation
cache.dfu .= cache.fu2 .- cache.fu

Check warning on line 160 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L160

Added line #L160 was not covered by tests

# Only try to reset if we have enough iterations since last reset
if cache.iterations_since_reset > size(cache.U, 1) &&

Check warning on line 163 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L163

Added line #L163 was not covered by tests
(all(cache.reset_check, cache.du) || all(cache.reset_check, cache.dfu))
if cache.resets cache.max_resets
cache.retcode = ReturnCode.Unstable
cache.force_stop = true
return nothing

Check warning on line 168 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L165-L168

Added lines #L165 - L168 were not covered by tests
end
cache.iterations_since_reset = 0
cache.resets += 1
cache.du = -cache.fu

Check warning on line 172 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L170-L172

Added lines #L170 - L172 were not covered by tests
else
idx = min(cache.iterations_since_reset, size(cache.U, 1))
U_part = selectdim(cache.U, 1, 1:idx)
Vᵀ_part = selectdim(cache.Vᵀ, 2, 1:idx)

Check warning on line 176 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L174-L176

Added lines #L174 - L176 were not covered by tests

cache.vᵀ_cache = _restructure(cache.vᵀ_cache,

Check warning on line 178 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L178

Added line #L178 was not covered by tests
__lbroyden_matvec(U_part, Vᵀ_part, _vec(cache.du)))
cache.u_cache = _restructure(cache.u_cache,

Check warning on line 180 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L180

Added line #L180 was not covered by tests
__lbroyden_rmatvec(U_part, Vᵀ_part, _vec(cache.dfu)))
cache.u_cache = (cache.du .- cache.u_cache) ./

Check warning on line 182 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L182

Added line #L182 was not covered by tests
(dot(cache.vᵀ_cache, cache.dfu) .+ T(1e-5))

idx = mod1(cache.iterations_since_reset + 1, size(cache.U, 1))
selectdim(cache.U, 1, idx) .= _vec(cache.u_cache)
selectdim(cache.Vᵀ, 2, idx) .= _vec(cache.vᵀ_cache)

Check warning on line 187 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L185-L187

Added lines #L185 - L187 were not covered by tests

idx = min(cache.iterations_since_reset + 1, size(cache.U, 1))
U_part = selectdim(cache.U, 1, 1:idx)
Vᵀ_part = selectdim(cache.Vᵀ, 2, 1:idx)
cache.du = _restructure(cache.du,

Check warning on line 192 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L189-L192

Added lines #L189 - L192 were not covered by tests
-__lbroyden_matvec(U_part, Vᵀ_part, _vec(cache.fu2)))
cache.iterations_since_reset += 1

Check warning on line 194 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L194

Added line #L194 was not covered by tests
end

cache.fu = cache.fu2

Check warning on line 197 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L197

Added line #L197 was not covered by tests

return nothing

Check warning on line 199 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L199

Added line #L199 was not covered by tests
end

function SciMLBase.reinit!(cache::LimitedMemoryBroydenCache{iip}, u0 = cache.u; p = cache.p,

Check warning on line 202 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L202

Added line #L202 was not covered by tests
abstol = cache.abstol, maxiters = cache.maxiters) where {iip}
cache.p = p
if iip
recursivecopy!(cache.u, u0)
cache.f(cache.fu, cache.u, p)

Check warning on line 207 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L204-L207

Added lines #L204 - L207 were not covered by tests
else
# don't have alias_u0 but cache.u is never mutated for OOP problems so it doesn't matter
cache.u = u0
cache.fu = cache.f(cache.u, p)

Check warning on line 211 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L210-L211

Added lines #L210 - L211 were not covered by tests
end
cache.abstol = abstol
cache.maxiters = maxiters
cache.stats.nf = 1
cache.stats.nsteps = 1
cache.resets = 0
cache.iterations_since_reset = 0
cache.force_stop = false
cache.retcode = ReturnCode.Default
return cache

Check warning on line 221 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L213-L221

Added lines #L213 - L221 were not covered by tests
end

@views function __lbroyden_matvec!(y::AbstractVector, Ux::AbstractVector,

Check warning on line 224 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L224

Added line #L224 was not covered by tests
U::AbstractMatrix, Vᵀ::AbstractMatrix, x::AbstractVector)
# Computes Vᵀ × U × x
η = size(U, 1)
if η == 0
y .= x
return nothing

Check warning on line 230 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L227-L230

Added lines #L227 - L230 were not covered by tests
end
mul!(Ux[1:η], U, x)
mul!(y, Vᵀ[:, 1:η], Ux[1:η])
return nothing

Check warning on line 234 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L232-L234

Added lines #L232 - L234 were not covered by tests
end

@views function __lbroyden_matvec(U::AbstractMatrix, Vᵀ::AbstractMatrix, x::AbstractVector)

Check warning on line 237 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L237

Added line #L237 was not covered by tests
# Computes Vᵀ × U × x
size(U, 1) == 0 && return x
return Vᵀ * (U * x)

Check warning on line 240 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L239-L240

Added lines #L239 - L240 were not covered by tests
end

@views function __lbroyden_rmatvec!(y::AbstractVector, xᵀVᵀ::AbstractMatrix,

Check warning on line 243 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L243

Added line #L243 was not covered by tests
U::AbstractMatrix, Vᵀ::AbstractMatrix, x::AbstractVector)
# Computes xᵀ × Vᵀ × U
η = size(U, 1)
if η == 0
y .= x
return nothing

Check warning on line 249 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L246-L249

Added lines #L246 - L249 were not covered by tests
end
mul!(xᵀVᵀ[:, 1:η], x', Vᵀ)
mul!(y', xᵀVᵀ[:, 1:η], U)
return nothing

Check warning on line 253 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L251-L253

Added lines #L251 - L253 were not covered by tests
end

@views function __lbroyden_rmatvec(U::AbstractMatrix, Vᵀ::AbstractMatrix, x::AbstractVector)

Check warning on line 256 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L256

Added line #L256 was not covered by tests
# Computes xᵀ × Vᵀ × U
size(U, 1) == 0 && return x
return (x' * Vᵀ) * U

Check warning on line 259 in src/lbroyden.jl

View check run for this annotation

Codecov / codecov/patch

src/lbroyden.jl#L258-L259

Added lines #L258 - L259 were not covered by tests
end
12 changes: 12 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,18 @@ function __init_identity_jacobian(u::StaticArray, fu)
Matrix{eltype(u)}(I, length(fu), length(u)))
end

function __init_low_rank_jacobian(u::StaticArray, fu, threshold::Int)
Vᵀ = convert(MArray{Tuple{length(u), threshold}},

Check warning on line 226 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L225-L226

Added lines #L225 - L226 were not covered by tests
zeros(eltype(u), length(u), threshold))
U = convert(MArray{Tuple{threshold, length(u)}}, zeros(eltype(u), threshold, length(u)))
return U, Vᵀ

Check warning on line 229 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L228-L229

Added lines #L228 - L229 were not covered by tests
end
function __init_low_rank_jacobian(u, fu, threshold::Int)
Vᵀ = convert(parameterless_type(_mutable(u)), zeros(eltype(u), length(u), threshold))
U = convert(parameterless_type(_mutable(u)), zeros(eltype(u), threshold, length(u)))
return U, Vᵀ

Check warning on line 234 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L231-L234

Added lines #L231 - L234 were not covered by tests
end

# Check Singular Matrix
_issingular(x::Number) = iszero(x)
@generated function _issingular(x::T) where {T}
Expand Down
Loading

0 comments on commit 4dc40bc

Please sign in to comment.