201
201
H
202
202
g
203
203
shrink_counter:: Int
204
- step_size
204
+ du
205
205
u_tmp
206
- u_c
206
+ u_cauchy
207
207
fu_new
208
208
make_new_J:: Bool
209
209
r:: floatType
@@ -227,13 +227,13 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::TrustRegion,
227
227
loss = get_loss (fu1)
228
228
uf, linsolve, J, fu2, jac_cache, du = jacobian_caches (alg, f, u, p, Val (iip);
229
229
linsolve_kwargs)
230
- u_c = zero (u)
230
+ u_tmp = zero (u)
231
+ u_cauchy = zero (u)
231
232
232
233
loss_new = loss
233
234
H = zero (J)
234
235
g = _mutable_zero (fu1)
235
236
shrink_counter = 0
236
- step_size = zero (u)
237
237
fu_new = zero (fu1)
238
238
make_new_J = true
239
239
r = loss
@@ -242,7 +242,7 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::TrustRegion,
242
242
radius_update_scheme = alg. radius_update_scheme
243
243
244
244
# set default type for all trust region parameters
245
- trustType = Float64 # typeof(alg.initial_trust_radius)
245
+ trustType = eltype (u) # typeof(alg.initial_trust_radius)
246
246
max_trust_radius = convert (trustType, alg. max_trust_radius)
247
247
if iszero (max_trust_radius)
248
248
max_trust_radius = convert (trustType, max (norm (fu1), maximum (u) - minimum (u)))
@@ -314,7 +314,7 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::TrustRegion,
314
314
jac_cache, false , maxiters, internalnorm, ReturnCode. Default, abstol, prob,
315
315
radius_update_scheme, initial_trust_radius, max_trust_radius, step_threshold,
316
316
shrink_threshold, expand_threshold, shrink_factor, expand_factor, loss, loss_new,
317
- H, g, shrink_counter, step_size, du, u_c , fu_new, make_new_J, r, p1, p2, p3, p4, ϵ,
317
+ H, g, shrink_counter, du, u_tmp, u_cauchy , fu_new, make_new_J, r, p1, p2, p3, p4, ϵ,
318
318
NLStats (1 , 0 , 0 , 0 , 0 ))
319
319
end
320
320
@@ -337,7 +337,7 @@ function perform_step!(cache::TrustRegionCache{true})
337
337
dogleg! (cache)
338
338
339
339
# Compute the potentially new u
340
- cache. u_tmp . = u . + cache. step_size
340
+ @. cache. u_tmp = u + cache. du
341
341
f (cache. fu_new, cache. u_tmp, p)
342
342
trust_region_step! (cache)
343
343
cache. stats. nf += 1
@@ -358,11 +358,15 @@ function perform_step!(cache::TrustRegionCache{false})
358
358
359
359
@unpack g, H = cache
360
360
# Compute the Newton step.
361
- cache. u_tmp = - H \ g
361
+ cache. u_tmp = - 1 .* ( H \ g)
362
362
dogleg! (cache)
363
363
364
364
# Compute the potentially new u
365
- cache. u_tmp = u .+ cache. step_size
365
+ if u isa Number
366
+ cache. u_tmp = u + cache. du
367
+ else
368
+ @. cache. u_tmp = u + cache. du
369
+ end
366
370
cache. fu_new = f (cache. u_tmp, p)
367
371
trust_region_step! (cache)
368
372
cache. stats. nf += 1
@@ -382,18 +386,18 @@ function retrospective_step!(cache::TrustRegionCache)
382
386
mul! (cache. g, J' , fu)
383
387
end
384
388
cache. stats. njacs += 1
385
- @unpack H, g, step_size = cache
389
+ @unpack H, g, du = cache
386
390
387
391
return - (get_loss (fu_prev) - get_loss (fu)) /
388
- (dot (step_size , g) + dot (step_size , H, step_size ) / 2 )
392
+ (dot (du , g) + dot (du , H, du ) / 2 )
389
393
end
390
394
391
395
function trust_region_step! (cache:: TrustRegionCache )
392
- @unpack fu_new, step_size , g, H, loss, max_trust_r, radius_update_scheme = cache
396
+ @unpack fu_new, du , g, H, loss, max_trust_r, radius_update_scheme = cache
393
397
cache. loss_new = get_loss (fu_new)
394
398
395
399
# Compute the ratio of the actual reduction to the predicted reduction.
396
- cache. r = - (loss - cache. loss_new) / (dot (step_size , g) + dot (step_size , H, step_size ) / 2 )
400
+ cache. r = - (loss - cache. loss_new) / (dot (du , g) + dot (du , H, du ) / 2 )
397
401
@unpack r = cache
398
402
399
403
if radius_update_scheme === RadiusUpdateSchemes. Simple
@@ -437,9 +441,9 @@ function trust_region_step!(cache::TrustRegionCache)
437
441
if r < cache. shrink_threshold # default 1 // 10
438
442
cache. trust_r *= cache. shrink_factor # default 1 // 2
439
443
elseif r >= cache. expand_threshold # default 9 // 10
440
- cache. trust_r = cache. expand_factor * norm (cache. step_size ) # default 2
444
+ cache. trust_r = cache. expand_factor * norm (cache. du ) # default 2
441
445
elseif r >= cache. p1 # default 1 // 2
442
- cache. trust_r = max (cache. trust_r, cache. expand_factor * norm (cache. step_size ))
446
+ cache. trust_r = max (cache. trust_r, cache. expand_factor * norm (cache. du ))
443
447
end
444
448
445
449
# convergence test
@@ -458,8 +462,8 @@ function trust_region_step!(cache::TrustRegionCache)
458
462
end
459
463
460
464
if r < 1 // 4
461
- cache. trust_r = (1 // 4 ) * norm (cache. step_size )
462
- elseif (r > (3 // 4 )) && abs (norm (cache. step_size ) - cache. trust_r)/ cache. trust_r < 1e-6
465
+ cache. trust_r = (1 // 4 ) * norm (cache. du )
466
+ elseif (r > (3 // 4 )) && abs (norm (cache. du ) - cache. trust_r)/ cache. trust_r < 1e-6
463
467
cache. trust_r = min (2 * cache. trust_r, cache. max_trust_r)
464
468
end
465
469
@@ -473,14 +477,14 @@ function trust_region_step!(cache::TrustRegionCache)
473
477
end
474
478
# Hei's radius update scheme
475
479
@unpack shrink_threshold, p1, p2, p3, p4 = cache
476
- if rfunc (r, shrink_threshold, p1, p3, p4, p2) * cache. internalnorm (step_size ) <
480
+ if rfunc (r, shrink_threshold, p1, p3, p4, p2) * cache. internalnorm (du ) <
477
481
cache. trust_r
478
482
cache. shrink_counter += 1
479
483
else
480
484
cache. shrink_counter = 0
481
485
end
482
486
cache. trust_r = rfunc (r, shrink_threshold, p1, p3, p4, p2) *
483
- cache. internalnorm (step_size )
487
+ cache. internalnorm (du )
484
488
485
489
if iszero (cache. fu) || cache. internalnorm (cache. fu) < cache. abstol ||
486
490
cache. internalnorm (g) < cache. ϵ
@@ -492,7 +496,7 @@ function trust_region_step!(cache::TrustRegionCache)
492
496
cache. p1 = cache. p2 * cache. p1
493
497
cache. shrink_counter += 1
494
498
elseif r >= cache. expand_threshold &&
495
- cache. internalnorm (step_size ) > cache. trust_r / 2
499
+ cache. internalnorm (du ) > cache. trust_r / 2
496
500
cache. p1 = cache. p3 * cache. p1
497
501
cache. shrink_counter = 0
498
502
end
@@ -541,7 +545,7 @@ function trust_region_step!(cache::TrustRegionCache)
541
545
cache. loss = cache. loss_new
542
546
cache. make_new_J = true
543
547
if retrospective_step! (cache) >= cache. expand_threshold
544
- cache. trust_r = max (cache. p1 * cache. internalnorm (step_size ), cache. trust_r)
548
+ cache. trust_r = max (cache. p1 * cache. internalnorm (du ), cache. trust_r)
545
549
end
546
550
547
551
else
@@ -556,61 +560,62 @@ function trust_region_step!(cache::TrustRegionCache)
556
560
end
557
561
558
562
function dogleg! (cache:: TrustRegionCache{true} )
559
- @unpack u_tmp, u_c , trust_r = cache
563
+ @unpack u_tmp, u_cauchy , trust_r = cache
560
564
561
- # Test if the full step is within the trust region.
565
+ # Take the full Gauss-Newton step if lies within the trust region.
562
566
if norm (u_tmp) ≤ trust_r
563
- cache. step_size .= u_tmp
567
+ cache. du .= u_tmp
564
568
return
565
569
end
566
570
567
- # Calcualte Cauchy point, optimum along the steepest descent direction.
568
- l_grad = norm (cache. g)
571
+ # Take intersection of steepest descent direction and trust region if Cauchy point lies outside of trust region
572
+ l_grad = norm (cache. g) # length of the gradient
569
573
d_cauchy = l_grad^ 3 / dot (cache. g, cache. H, cache. g) # distance of the cauchy point from the current iterate
570
- if d_cauchy > trust_r # cauchy point lies outside of trust region
571
- @. cache. step_size = - (trust_r/ l_grad) * cache. g # step to the end of the trust region
574
+ if d_cauchy > trust_r
575
+ @. cache. du = - (trust_r/ l_grad) * cache. g # step to the end of the trust region
572
576
return
573
577
end
574
578
575
- # cauchy point lies inside the trust region
576
- @. u_c = - (d_cauchy/ l_grad) * cache. g
577
-
578
- # Find the intersection point on the boundary.
579
- @. u_tmp -= u_c # calf of the dogleg, use u_tmp to avoid allocation
580
- θ = dot (u_tmp, u_c) # ~ cos(∠(calf,thigh))
581
- l_calf = dot (u_tmp,u_tmp ) # length of the calf of the dogleg
582
- aux = max (θ ^ 2 + l_calf * (trust_r ^ 2 - d_cauchy ^ 2 ), 0 ) # technically guaranteed to be non-negative but hedging against floating point issues
583
- τ = ( - θ + sqrt ( aux ) ) / l_calf # stepsize along dogleg
584
- @. cache. step_size = u_c + τ * u_tmp
579
+ # Take the intersection of dogled with trust region if Cauchy point lies inside the trust region
580
+ @. u_cauchy = - (d_cauchy/ l_grad) * cache. g # compute Cauchy point
581
+ @. u_tmp -= u_cauchy # calf of the dogleg -- use u_tmp to avoid allocation
582
+ a = dot (u_tmp, u_tmp)
583
+ b = 2 * dot (u_cauchy, u_tmp)
584
+ c = d_cauchy ^ 2 - trust_r ^ 2
585
+ aux = max (b ^ 2 - 4 * a * c, 0.0 ) # technically guaranteed to be non-negative but hedging against floating point issues
586
+ τ = ( - b + sqrt (aux)) / ( 2 * a) # stepsize along dogleg to trust region boundary
587
+
588
+ @. cache. du = u_cauchy + τ * u_tmp
585
589
end
586
590
591
+
587
592
function dogleg! (cache:: TrustRegionCache{false} )
588
- @unpack u_tmp, u_c , trust_r = cache
593
+ @unpack u_tmp, u_cauchy , trust_r = cache
589
594
590
595
# Test if the full step is within the trust region.
591
596
if norm (u_tmp) ≤ trust_r
592
- cache. step_size = deepcopy (u_tmp)
597
+ cache. du = deepcopy (u_tmp)
593
598
return
594
599
end
595
600
596
601
# Calcualte Cauchy point, optimum along the steepest descent direction.
597
602
l_grad = norm (cache. g)
598
603
d_cauchy = l_grad^ 3 / dot (cache. g, cache. H, cache. g) # distance of the cauchy point from the current iterate
599
604
if d_cauchy > trust_r # cauchy point lies outside of trust region
600
- cache. step_size = - (trust_r/ l_grad) * cache. g # step to the end of the trust region
605
+ cache. du = - (trust_r/ l_grad) * cache. g # step to the end of the trust region
601
606
return
602
607
end
603
608
604
609
# cauchy point lies inside the trust region
605
- u_c = - (d_cauchy/ l_grad) * cache. g
610
+ u_cauchy = - (d_cauchy/ l_grad) * cache. g
606
611
607
612
# Find the intersection point on the boundary.
608
- u_tmp -= u_c # calf of the dogleg, use u_tmp to avoid allocation
609
- θ = dot (u_tmp, u_c ) # ~ cos(∠(calf,thigh))
613
+ u_tmp -= u_cauchy # calf of the dogleg, use u_tmp to avoid allocation
614
+ θ = dot (u_tmp, u_cauchy ) # ~ cos(∠(calf,thigh))
610
615
l_calf = dot (u_tmp,u_tmp) # length of the calf of the dogleg
611
616
aux = max (θ^ 2 + l_calf* (trust_r^ 2 - d_cauchy^ 2 ), 0 ) # technically guaranteed to be non-negative but hedging against floating point issues
612
617
τ = ( - θ + sqrt ( aux ) ) / l_calf # stepsize along dogleg
613
- cache. step_size = u_c + τ * u_tmp
618
+ cache. du = u_cauchy + τ * u_tmp
614
619
end
615
620
616
621
function take_step! (cache:: TrustRegionCache{true} )
0 commit comments