-
Notifications
You must be signed in to change notification settings - Fork 1
Separate State and StoppingCriterionState initialization
#9
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
base: main
Are you sure you want to change the base?
Conversation
|
@mtfishman, does this align slightly better with what you had in mind? |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #9 +/- ##
=======================================
Coverage ? 57.70%
=======================================
Files ? 6
Lines ? 227
Branches ? 0
=======================================
Hits ? 131
Misses ? 96
Partials ? 0 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Oh, this is quiiiiiite some rework. I do not get understand what changed in practice though. It seems like now it's random whether Or phrased differently: one now has to pass a sc-state to the init, but where is that from / initialised before? |
|
Apologies, I could have explained this a whole lot better. The main goal was to separate out state initialization from stopping state initialization, since I think it feels slightly awkward that you have to remember that when you are implementing an algorithm, you have to remember to also call Then I wanted to do the same thing for Walking through the flow of
I can see the confusion with the third parameter being a Finally, I wanted to not disallow workflows where the initialization of the stopping criterion state and of the regular state have to be intertwined and cannot be cleanly separated out. |
Co-authored-by: Matt Fishman <[email protected]>
| function AlgorithmsInterface.initialize_state( | ||
| problem::SqrtProblem, algorithm::HeronAlgorithm, | ||
| stopping_criterion_state::StoppingCriterionState; | ||
| kwargs... | ||
| ) | ||
| x0 = rand() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a small change, but in practice what I've been doing is writing the definition of initialize_state more like this:
function AlgorithmsInterface.initialize_state(
problem::SqrtProblem, algorithm::HeronAlgorithm,
stopping_criterion_state::StoppingCriterionState;
x0 = rand()
)Maybe I was being dense, but it took me some time to realize that was a "valid" way to define it and still have control over the parts of the state initialization that I wanted to control, since that allows running solve as:
solve(SqrtProblem(16.0), HeronAlgorithm(StopAfterIteration(10)); x0 = 1.0)I think seeing the example written that way would have helped me understand how I should define initialize_state.
However, I realized a slightly awkward thing about defining initialize_state in that way and then calling solve as solve(SqrtProblem(16.0), HeronAlgorithm(StopAfterIteration(10)); x0 = 1.0) is that then x0 gets passed to both initialize_state and initialize_state!. Maybe that's not a problem in practice but I found it to be a bit strange (i.e. should initialize_state! use x0 or not?), and also made me confused about the roles of intialize_state vs. initialize_state!. I think the suggestion in this PR of just having initialize_state! reset iteration helps clarify that issue a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment about the kwargs is a really good one, I was looking at this a bit before and it's somewhat difficult to come up with a way to split arbitrary keywords generically, but it could even make sense to just not pass the keyword arguments to initialize_state! anymore if they have already been passed to initialize_state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about that, indeed maybe it makes sense to not pass the keyword arguments to initialize_state!. That could make the distinction between initialize_state and initialize_state! clearer, since then initialize_state handles external inputs (i.e. initial guesses for the iterate) while initialize_state! just handles resetting the "internal" state, such as the iteration number and stopping criterion state. Calling solve! means that you made the state already, so it seems like anything handled through keyword arguments to initialize_state! could instead be handled by just modifying the state directly (i.e. before calling solve!/initialize_state!).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I disagree here, for me functions of same name should do the same and accept the same keywords. Or to be more precise
initialize_state should create a state from new memory but also
initialize_state! applied to the same memory state should set it to the same situation as well.
|
I think for me all this is getting a bit too much. My original goal was to maybe integrate Manopt a bit better into the Julia world so people could use it. That failed with JuMP and it also failed with Optimization. I do not mean this in any negative way, I think it was nice to ponder about these ideas a bit, I just notice that I do not have the capacity to continue here - neither in motivation nor time. Nor does it look like I will be able to afford any future JuliaCons anyways (celebrating 10 years without grants by now). Let me know what you think. Without me you can also easily follow the ideas above of doing something completely different in the mutating versus non mutating variants of functions and such. |
This is a slight refactor of the initialization procedure, where I did the following
initialize_state!on the stopping state.iteratein theinitialize_state!calls, and only generate a random starting point ininitialize_stateas this led to confusion insolve!withoutinitialize_state!#8. The idea is thatinitialize_state!really means making sure everything is set up to correctly start running the algorithm, which does not necessarily include a reset of theiteratebut rather means setup like caches, counters, auxiliary memory etc.