Skip to content

Commit 0e99655

Browse files
committed
cache memory for cauchy step to enable non-allocating code
1 parent 094eb34 commit 0e99655

File tree

1 file changed

+36
-6
lines changed

1 file changed

+36
-6
lines changed

src/trustRegion.jl

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::TrustRegion,
235235
expand_threshold = convert(eltype(u), alg.expand_threshold)
236236
shrink_factor = convert(eltype(u), alg.shrink_factor)
237237
expand_factor = convert(eltype(u), alg.expand_factor)
238+
238239
# Set default trust region radius if not specified
239240
if iszero(max_trust_radius)
240241
max_trust_radius = convert(eltype(u), max(norm(fu1), maximum(u) - minimum(u)))
@@ -552,8 +553,37 @@ function trust_region_step!(cache::TrustRegionCache)
552553
end
553554
end
554555

555-
function dogleg!(cache::TrustRegionCache)
556-
@unpack u_tmp, trust_r = cache
556+
function dogleg!(cache::TrustRegionCache{true})
557+
@unpack u_tmp, u_c, trust_r = cache
558+
559+
# Test if the full step is within the trust region.
560+
if norm(u_tmp) trust_r
561+
cache.step_size .= u_tmp
562+
return
563+
end
564+
565+
# Calcualte Cauchy point, optimum along the steepest descent direction.
566+
l_grad = norm(cache.g)
567+
d_cauchy = l_grad^3 / dot(cache.g, cache.H, cache.g) # distance of the cauchy point from the current iterate
568+
if d_cauchy > trust_r # cauchy point lies outside of trust region
569+
@. cache.step_size = - (trust_r/l_grad) * cache.g # step to the end of the trust region
570+
return
571+
end
572+
573+
# cauchy point lies inside the trust region
574+
@. u_c = - (d_cauchy/l_grad) * cache.g
575+
576+
# Find the intersection point on the boundary.
577+
@. u_tmp -= u_c # calf of the dogleg, use u_tmp to avoid allocation
578+
θ = dot(u_tmp, u_c) # ~ cos(∠(calf,thigh))
579+
l_calf = dot(u_tmp,u_tmp) # length of the calf of the dogleg
580+
aux = max^2 + l_calf*(trust_r^2 - d_cauchy^2), 0) # technically guaranteed to be non-negative but hedging against floating point issues
581+
τ = ( - θ + sqrt( aux ) ) / l_calf # stepsize along dogleg
582+
@. cache.step_size = u_c + τ * u_tmp
583+
end
584+
585+
function dogleg!(cache::TrustRegionCache{false})
586+
@unpack u_tmp, u_c, trust_r = cache
557587

558588
# Test if the full step is within the trust region.
559589
if norm(u_tmp) trust_r
@@ -573,12 +603,12 @@ function dogleg!(cache::TrustRegionCache)
573603
u_c = - (d_cauchy/l_grad) * cache.g
574604

575605
# Find the intersection point on the boundary.
576-
Δ = u_tmp - u_c # calf of the dogleg
577-
θ = dot(Δ, u_c) # ~ cos(∠(calf,thigh))
578-
l_calf = dot(Δ,Δ) # length of the calf of the dogleg
606+
u_tmp -= u_c # calf of the dogleg, use u_tmp to avoid allocation
607+
θ = dot(u_tmp, u_c) # ~ cos(∠(calf,thigh))
608+
l_calf = dot(u_tmp,u_tmp) # length of the calf of the dogleg
579609
aux = max^2 + l_calf*(trust_r^2 - d_cauchy^2), 0) # technically guaranteed to be non-negative but hedging against floating point issues
580610
τ = ( - θ + sqrt( aux ) ) / l_calf # stepsize along dogleg
581-
cache.step_size = u_c + τ * Δ
611+
cache.step_size = u_c + τ * u_tmp
582612
end
583613

584614
function take_step!(cache::TrustRegionCache{true})

0 commit comments

Comments
 (0)