-
Notifications
You must be signed in to change notification settings - Fork 222
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
Add iterator interface #745
base: master
Are you sure you want to change the base?
Conversation
@with_kw struct IteratorState{IT <: OptimIterator, TR <: OptimizationTrace} | ||
# Put `OptimIterator` in iterator state so that `OptimizationResults` can | ||
# be constructed from `IteratorState`. | ||
iter::IT |
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.
We can drop iter
field from IteratorState
if we change the API to:
let istate
iter = optimizing(args...; kwargs...)
for istate′ in iter
istate = istate′
end
OptimizationResults(iter, istate) # need to pass `iter` here
end
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.
Accessor functions like iteration_limit_reached(istate)
and (f|g|h)_calls(istate)
need .iter
, too.
Interesting, thanks. That took surprisingly few changes, but it was mostly written as an iterator already, just wasn't an actual iterator :laugh . Will have to have a more thorough look! |
Codecov Report
@@ Coverage Diff @@
## master #745 +/- ##
==========================================
- Coverage 81.46% 81.41% -0.05%
==========================================
Files 43 43
Lines 2422 2438 +16
==========================================
+ Hits 1973 1985 +12
- Misses 449 453 +4
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #745 +/- ##
==========================================
- Coverage 81.53% 81.41% -0.12%
==========================================
Files 43 43
Lines 2431 2470 +39
==========================================
+ Hits 1982 2011 +29
- Misses 449 459 +10
Continue to review full report at Codecov.
|
|
||
function OptimizationResults(istate::IteratorState) | ||
@unpack_IteratorState istate | ||
@unpack d, initial_x, method, options, state = iter | ||
|
||
after_while!(d, state, method, options) |
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.
Executing a mutating-function after_while!
inside non-bang function OptimizationResults
is not super great. But it looks like after_while!
is a no-op mostly except for NelderMead so maybe it's OK? From a quick look, after_while!
for NelderMead
seems to be idempotent (so that, e.g., calling OptimizationResults(istate)
inside a loop multiple times is OK). If that's the case, OptimizationResults(istate)
practically has no side-effect?
But using a function like result!
sounds good to me as well.
if !isa(r.method, NelderMead) | ||
throw(ArgumentError("There is no centroid involved in optimization using $(r.method). Please use x_trace(...) to grab the points from the trace.")) | ||
function centroid_trace(r::Union{MultivariateOptimizationResults, IteratorState}) | ||
tr = trace(r) |
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 suppose tr = trace(r)
should be added here? I think it'll throw UndefVarError
otherwise. There are two more places I did this change.
I'm including these changes (adding tr = trace(r)
) although they are not directly related to PR.
@pkofod After posted the PR, I realized that the first version didn't provide the way to access iteration state (e.g., getting "best minimizer so far") so I added accessor functions for iterator state by reusing the function names/code already defined for the result type. So the diff may not be as small as you remember now. Anyway, I think I've implemented the APIs I need. I'm looking forward to hear your thoughts on this. |
Aside: Using this API a few times, I realized that function Base.foreach(f, iter::OptimIterator)
local istate
for istate′ in iter
istate = istate′
f(istate)
end
return istate
end We can then use it as result = foreach(optimizing(args...; kwargs...)) do istate
@info "Minimizing..." minimizer(istate) minimum(istate)
end |> Optim.OptimizationResults although this does not let us use (Or we can implement transducer-compatible |
Friendly ping :) Is there anything I can do to make it easier to merge? |
Sorry, I've had too much on my plate. I'll take a look soon. |
Thanks! |
🛎️ Can we have this? I am still interested in plotting the evolution of the optimization : https://discourse.julialang.org/t/plotting-the-evolution-of-the-optimization-using-optim-jl/41978 |
This PR adds an iterator interface for optimizer. I tentatively call it
Optim.optimizing
. It provides an iterator-based API such thatis equivalent to
optimize(args...; kwargs...)
for multivariate optimizations.close #599