-
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 <mtfishman@users.noreply.github.com>
| 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. |
|
I completely understand what you mean, that really is a significant amount of dev time that at least for the case of Manopt has a smaller return on investment as you already have most of the features working. As you may have noticed, for me as well this is something that I am working on slightly sporadically, but at the very least I am not too happy with the current setup in a large part of our ecosystems so this is less of a refactor and more of a feature improvement, so there is slightly more motivation for that. |
|
Just to be clear here:
Just compared to my initial idea (“extract” the main types from Manopt and make it a package), the current design would really mean a major major rework of Manopt.jl. I also value our discussions, I think we got to something really nice. Just that I lack a bit of motivation. If you are fine with that, we can also keep it here in the JuliaManifold ecosystem, just that for now I do not see that Manopt will be rewritten to that; maybe unless there pops up some large argument that I find the motivation suddenly; but its a refactor of (I think) about 70% of the code lines. I am also happy to help in discussions – just for now I am not sure what else I could (find the motivation to) contribute. |
|
Ah, I misunderstood then, I thought you had wanted to migrate the package. I'm totally fine with keeping it here, I guess it just wasn't totally clear whether you wanted to not have to spend any time on this, or simply be kept up to date, or feel like chiming in on the design as well. Obviously I prefer to have you on board, I just don't want to force you to spend time you don't have 😉. |
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.