@@ -235,6 +235,7 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::TrustRegion,
235
235
expand_threshold = convert (eltype (u), alg. expand_threshold)
236
236
shrink_factor = convert (eltype (u), alg. shrink_factor)
237
237
expand_factor = convert (eltype (u), alg. expand_factor)
238
+
238
239
# Set default trust region radius if not specified
239
240
if iszero (max_trust_radius)
240
241
max_trust_radius = convert (eltype (u), max (norm (fu1), maximum (u) - minimum (u)))
@@ -552,8 +553,37 @@ function trust_region_step!(cache::TrustRegionCache)
552
553
end
553
554
end
554
555
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
557
587
558
588
# Test if the full step is within the trust region.
559
589
if norm (u_tmp) ≤ trust_r
@@ -573,12 +603,12 @@ function dogleg!(cache::TrustRegionCache)
573
603
u_c = - (d_cauchy/ l_grad) * cache. g
574
604
575
605
# 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
579
609
aux = max (θ^ 2 + l_calf* (trust_r^ 2 - d_cauchy^ 2 ), 0 ) # technically guaranteed to be non-negative but hedging against floating point issues
580
610
τ = ( - θ + sqrt ( aux ) ) / l_calf # stepsize along dogleg
581
- cache. step_size = u_c + τ * Δ
611
+ cache. step_size = u_c + τ * u_tmp
582
612
end
583
613
584
614
function take_step! (cache:: TrustRegionCache{true} )
0 commit comments