Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing some new Trust region radius update schemes #159

Merged
merged 15 commits into from
Mar 21, 2023

Conversation

yash2798
Copy link
Member

@yash2798 yash2798 commented Mar 6, 2023

No description provided.

@yash2798
Copy link
Member Author

yash2798 commented Mar 6, 2023

@ChrisRackauckas is this the correct way to implement this? here, we take the input from the user regarding what update scheme they would like to use as a String solve(probN, TrustRegion(radius_update_scheme="<>"), abstol = 1e-9). and then use this input subsequently?

@ChrisRackauckas
Copy link
Member

we take the input from the user regarding what update scheme they would like to use as a String solve(probN, TrustRegion(radius_update_scheme="<>"), abstol = 1e-9). and then use this input subsequently?

No, never take in a string. Take in a type instance, like the algorithm choice.

@yash2798
Copy link
Member Author

yash2798 commented Mar 6, 2023

we take the input from the user regarding what update scheme they would like to use as a String solve(probN, TrustRegion(radius_update_scheme="<>"), abstol = 1e-9). and then use this input subsequently?

No, never take in a string. Take in a type instance, like the algorithm choice.

okay, got it, so I define all the radius update schemes as composite types? and then use them? just like the TrustRegion type is defined?

@yash2798 yash2798 marked this pull request as draft March 6, 2023 02:01
@yash2798
Copy link
Member Author

yash2798 commented Mar 7, 2023

Hi @ChrisRackauckas , I made some changes regarding how we choose the relevant radius update scheme. Is this approach alright?

@yash2798 yash2798 marked this pull request as ready for review March 7, 2023 11:17
@codecov
Copy link

codecov bot commented Mar 7, 2023

Codecov Report

Merging #159 (b1f34dd) into master (f32e596) will decrease coverage by 7.06%.
The diff coverage is 36.50%.

@@            Coverage Diff             @@
##           master     #159      +/-   ##
==========================================
- Coverage   91.28%   84.22%   -7.06%     
==========================================
  Files           7        7              
  Lines         505      558      +53     
==========================================
+ Hits          461      470       +9     
- Misses         44       88      +44     
Impacted Files Coverage Δ
src/NonlinearSolve.jl 60.00% <ø> (ø)
src/utils.jl 62.31% <0.00%> (-3.84%) ⬇️
src/trustRegion.jl 76.53% <38.98%> (-21.93%) ⬇️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

Comment on lines 98 to 102
struct RadiusUpdate{B}
simple::B
hei::B
yuan::B
bastin::B
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
struct RadiusUpdate{B}
simple::B
hei::B
yuan::B
bastin::B
struct RadiusUpdate
simple::Bool
hei::Bool
yuan::Bool
bastin::Bool

Comment on lines 110 to 116
return RadiusUpdate{Bool}(true, false, false, false)
elseif hei
return RadiusUpdate{Bool}(false, true, false, false)
elseif yuan
return RadiusUpdate{Bool}(false, false, true, false)
elseif bastin
return RadiusUpdate{Bool}(false, false, false, true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return RadiusUpdate{Bool}(true, false, false, false)
elseif hei
return RadiusUpdate{Bool}(false, true, false, false)
elseif yuan
return RadiusUpdate{Bool}(false, false, true, false)
elseif bastin
return RadiusUpdate{Bool}(false, false, false, true)
return RadiusUpdate{Bool}(true, false, false, false)
elseif hei
return RadiusUpdate{Bool}(false, true, false, false)
elseif yuan
return RadiusUpdate(false, false, true, false)
elseif bastin
return RadiusUpdate(false, false, false, true)

Comment on lines 105 to 113
function RadiusUpdate(;simple::Bool = Val{true}(), # 3 different radius update schemes
hei::Bool = Val{false}(),
yuan::Bool = Val{false}(),
bastin::Bool = Val{false}())
if simple
return RadiusUpdate{Bool}(true, false, false, false)
elseif hei
return RadiusUpdate{Bool}(false, true, false, false)
elseif yuan
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't make sense. If it's going to be non-dispatching logic, use an EnumX.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, I am sorry I misinterpreted the use of Val, but now it's clear. I have changed the overall approach.

@yash2798
Copy link
Member Author

yash2798 commented Mar 8, 2023

@ChrisRackauckas I think this approach would be better! It would be great if you can take a look.

I have a question though:
In line 103, the radius_update_scheme input is a Symbol. Another option is to use Val{:simple}() which will change the function call for trust_region_step! in lines 299 and 322. So, should the user input be kept as a Symbol (:simple, :hei, etc.) or should I change it to Val{:simple}(). I mean, there is not a lot of difference between the two but what method would be better from a user's pov?

@yash2798
Copy link
Member Author

yash2798 commented Mar 8, 2023

and thanks for all the feedback that you have been giving, I am learning a lot :)

@ChrisRackauckas
Copy link
Member

In line 103, the radius_update_scheme input is a Symbol. Another option is to use Val{:simple}() which will change the function call for trust_region_step! in lines 299 and 322. So, should the user input be kept as a Symbol (:simple, :hei, etc.) or should I change it to Val{:simple}(). I mean, there is not a lot of difference between the two but what method would be better from a user's pov?

Val{:sample}() is a valid construction, so that doesn't give good errors for typos.

See the ReturnCodes implementation and EnumX.jl

https://github.com/SciML/SciMLBase.jl/blob/master/src/retcodes.jl

@yash2798
Copy link
Member Author

yash2798 commented Mar 9, 2023

Okay, so by this you mean that if the user makes a typo :sample instead of the required :simple, then the program will show an exception something like this no method matching trust_region_step!(cache::TrustRegionCache, ::Val{:sample}) and this error is not very clear for the user? Is this what you mean?

If yes, couldn't we simply check for the validity of the input beforehand and raise an exception in case of any mismatch?

@yash2798
Copy link
Member Author

yash2798 commented Mar 9, 2023

@ChrisRackauckas Is this approach with EnumX alright? I have used my previous approach of creating a RadiusUpdate type variable and then used enumx just for multiple dispatching.

Bastin
end

struct RadiusUpdate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't they mutually exclusive? We should just use enum.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the structs can be deleted.

@ChrisRackauckas
Copy link
Member

Everything should use the enums and the structs should be deleted.

AbstractNewtonAlgorithm{CS, AD, FDT, ST, CJ}
linsolve::L
precs::P
radius_update_scheme::RUS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
radius_update_scheme::RUS
radius_update_scheme::RadiusUpdateSchemes.T

It doesn't need to be parametric.,

@@ -138,6 +147,7 @@ mutable struct TrustRegionCache{iip, fType, algType, uType, resType, pType,
retcode::SciMLBase.ReturnCode.T
abstol::tolType
prob::probType
radius_update_scheme::radType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

return nothing
end

function trust_region_step!(cache::TrustRegionCache)
function trust_region_step!(cache::TrustRegionCache, ::Val{0}) # conventional radius update scheme
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make a single dispatch and branch

Copy link
Member Author

@yash2798 yash2798 Mar 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function trust_region_step!(cache::TrustRegionCache, ::Val{0}) # conventional radius update scheme
function trust_region_step!(cache::TrustRegionCache)
@unpack radius_update_scheme = cache
if radius_update_scheme == RadiusUpdateSchemes.Simple
#method 1
elseif radius_update_scheme == RadiusUpdateSchemes.Hei
#method 2
...
end
end

do you mean like this in a single method?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool! also if I need some helper functions, like in Hei's scheme, there is a monotonic function used which depends on the actual:predicted change ratio. So these kind of helper functions can go in utils.jl, right?

@@ -10,6 +10,7 @@ using ForwardDiff: Dual
using LinearAlgebra
using StaticArraysCore
using RecursiveArrayTools
import EnumX
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing from the Project.toml

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i added the pkg in the env but didn't commit it yet. will do it in the next commit

src/trustRegion.jl Outdated Show resolved Hide resolved
src/trustRegion.jl Outdated Show resolved Hide resolved
cache.force_stop = true
end

elseif radius_update_scheme === RadiusUpdateSchemes.Hei
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error for not implemented

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, like a TypeError when the radius_update_scheme type doesn't match RadiusUpdateSchemes.T ?

Comment on lines 285 to 307
# Parameters for the Schemes
p1 = 0
p2 = 0
p3 = 0
p4 = 0
ϵ = 1e-8
if radius_update_scheme === RadiusUpdateSchemes.Hei
step_threshold = 0
shrink_threshold = 0.25
expand_threshold = 0.25
p1 = 5.0 # M
p2 = 0.1 # β
p3 = 0.15 # γ1
p4 = 0.15 # γ2
elseif radius_update_scheme === RadiusUpdateSchemes.Yuan
step_threshold = 0.0001
shrink_threshold = 0.25
expand_threshold = 0.25
p1 = 2.0 # μ
p2 = 1/6 # c5
p3 = 6 # c6
p4 = 0
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these values should match the type of u0.


# yuan's scheme
@unpack fu = cache
cache.trust_r = p1 * cache.internalnorm(jacobian(cache, f) * fu) # we need the gradient at the new (k+1)th point WILL THIS BECOME ALLOCATING?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't needto calculate the whole Jacobian here, we can fix that in a future PR though.

@ChrisRackauckas
Copy link
Member

Last step here is to make sure the tests don't fail, and fix the constants definitions so that they match the state types.

@yash2798
Copy link
Member Author

Last step here is to make sure the tests don't fail, and fix the constants definitions so that they match the state types.

Oh yes thanks, I understood it. I was just testing the two new methods myself and will make a commit real soon.

@yash2798
Copy link
Member Author

Hi @ChrisRackauckas I can't quite get how can we get the gradient in line 421 without the whole jacobian? Did you mean something through jvp?

@ChrisRackauckas ChrisRackauckas merged commit 0d07b27 into SciML:master Mar 21, 2023
@yash2798 yash2798 deleted the ys/tr_radius_schemes branch March 23, 2023 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants