Skip to content

Commit 645c1f1

Browse files
authored
Fix some outstanding Fminbox issues (#856)
* Fix #818 by using AbstractConstrainedOptimizer and AbstractOptimizer. * Communicate why it stopped so we can stop on callback in Fminbox * Allow callback to stop Fminbox. * Pass in options to convergence checker in Fminbox.
1 parent c6798a2 commit 645c1f1

File tree

9 files changed

+59
-32
lines changed

9 files changed

+59
-32
lines changed

src/multivariate/optimize/optimize.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,13 @@ function optimize(d::D, initial_x::Tx, method::M,
9494
# in variables besides the option settings
9595
Tf = typeof(value(d))
9696
f_incr_pick = f_increased && !options.allow_f_increases
97-
98-
return MultivariateOptimizationResults{typeof(method),T,Tx,typeof(x_abschange(state)),Tf,typeof(tr), Bool}(method,
97+
stopped_by =(f_limit_reached=f_limit_reached,
98+
g_limit_reached=g_limit_reached,
99+
h_limit_reached=h_limit_reached,
100+
time_limit=stopped_by_time_limit,
101+
callback=stopped_by_callback,
102+
f_increased=f_incr_pick)
103+
return MultivariateOptimizationResults{typeof(method),T,Tx,typeof(x_abschange(state)),Tf,typeof(tr), Bool, typeof(stopped_by)}(method,
99104
initial_x,
100105
pick_best_x(f_incr_pick, state),
101106
pick_best_f(f_incr_pick, state, d),
@@ -122,5 +127,6 @@ function optimize(d::D, initial_x::Tx, method::M,
122127
ls_success,
123128
options.time_limit,
124129
_time-t0,
130+
stopped_by,
125131
)
126132
end

src/multivariate/solvers/constrained/fminbox.jl

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -225,25 +225,25 @@ optimize(f, g, l::AbstractArray, u::Number, initial_x::AbstractArray{T}, opt::Op
225225
optimize(f, g, l::Number, u::AbstractArray, initial_x::AbstractArray{T}, opt::Options; kwargs...) where T = optimize(f, g, Fill(T(l), size(initial_x)...), u, initial_x, opt; kwargs...)
226226

227227
function optimize(f,
228-
l::AbstractArray{T},
229-
u::AbstractArray{T},
230-
initial_x::AbstractArray{T},
228+
l::AbstractArray,
229+
u::AbstractArray,
230+
initial_x::AbstractArray,
231231
F::Fminbox = Fminbox(),
232-
options = Options(); inplace = true, autodiff = :finite) where T<:AbstractFloat
232+
options::Options = Options(); inplace = true, autodiff = :finite)
233233

234-
od = OnceDifferentiable(f, initial_x, zero(T); autodiff = autodiff)
234+
od = OnceDifferentiable(f, initial_x, zero(eltype(initial_x)); autodiff = autodiff)
235235
optimize(od, l, u, initial_x, F, options)
236236
end
237237

238238
function optimize(
239239
df::OnceDifferentiable,
240-
l::AbstractArray{T},
241-
u::AbstractArray{T},
242-
initial_x::AbstractArray{T},
240+
l::AbstractArray,
241+
u::AbstractArray,
242+
initial_x::AbstractArray,
243243
F::Fminbox = Fminbox(),
244-
options = Options()) where T<:AbstractFloat
245-
244+
options::Options = Options())
246245

246+
T = eltype(initial_x)
247247
t0 = time()
248248

249249
outer_iterations = options.outer_iterations
@@ -310,7 +310,7 @@ function optimize(
310310
converged = false
311311
local results
312312
first = true
313-
313+
f_increased, stopped_by_time_limit, stopped_by_callback = false, false, false
314314
stopped = false
315315
_time = time()
316316
while !converged && !stopped && iteration < outer_iterations
@@ -340,6 +340,7 @@ function optimize(
340340
reset!(_optimizer, state, dfbox, x)
341341
#end
342342
resultsnew = optimize(dfbox, x, _optimizer, options, state)
343+
stopped_by_callback = resultsnew.stopped_by.callback
343344
if first
344345
results = resultsnew
345346
first = false
@@ -371,8 +372,8 @@ function optimize(
371372
g = x.-min.(max.(x.-gradient(dfbox.obj), l), u)
372373
results.x_converged, results.f_converged,
373374
results.g_converged, f_increased = assess_convergence(x, xold, minimum(results), fval0, g,
374-
options.outer_x_abstol, options.outer_f_reltol, options.outer_g_abstol)
375-
converged = results.x_converged || results.f_converged || results.g_converged
375+
options.outer_x_abstol, options.outer_x_reltol, options.outer_f_abstol, options.outer_f_reltol, options.outer_g_abstol)
376+
converged = results.x_converged || results.f_converged || results.g_converged || stopped_by_callback
376377
if f_increased && !allow_outer_f_increases
377378
@warn("f(x) increased: stopping optimization")
378379
break
@@ -381,6 +382,13 @@ function optimize(
381382
stopped_by_time_limit = _time-t0 > options.time_limit ? true : false
382383
stopped = stopped_by_time_limit
383384
end
385+
386+
stopped_by =(#f_limit_reached=f_limit_reached,
387+
#g_limit_reached=g_limit_reached,
388+
#h_limit_reached=h_limit_reached,
389+
time_limit=stopped_by_time_limit,
390+
callback=stopped_by_callback,
391+
f_increased=f_increased && !options.allow_f_increases)
384392

385393
return MultivariateOptimizationResults(F, initial_x, minimizer(results), df.f(minimizer(results)),
386394
iteration, results.iteration_converged,
@@ -390,5 +398,5 @@ function optimize(
390398
results.f_increased, results.trace, results.f_calls,
391399
results.g_calls, results.h_calls, nothing,
392400
options.time_limit,
393-
_time-t0,)
401+
_time-t0, stopped_by)
394402
end

src/multivariate/solvers/constrained/ipnewton/interior.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ function optimize(d::AbstractObjective, constraints::AbstractConstraints, initia
288288
nothing,
289289
options.time_limit,
290290
_time-t0,
291-
)
291+
NamedTuple())
292292
end
293293

294294
# Fallbacks (for methods that don't need these)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
abstract type ConstrainedOptimizer{T} <: AbstractOptimizer end
1+
abstract type ConstrainedOptimizer{T} <: AbstractConstrainedOptimizer end
22
abstract type IPOptimizer{T} <: ConstrainedOptimizer{T} end # interior point methods

src/multivariate/solvers/constrained/samin.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ algorithm
3838
- Goffe, et. al. (1994) "Global Optimization of Statistical Functions with Simulated Annealing", Journal of Econometrics, V. 60, N. 1/2.
3939
- Goffe, William L. (1996) "SIMANN: A Global Optimization Algorithm using Simulated Annealing " Studies in Nonlinear Dynamics & Econometrics, Oct96, Vol. 1 Issue 3.
4040
"""
41-
@with_kw struct SAMIN{T}<:ZerothOrderOptimizer
41+
@with_kw struct SAMIN{T}<:AbstractConstrainedOptimizer
4242
nt::Int = 5 # reduce temperature every nt*ns*dim(x_init) evaluations
4343
ns::Int = 5 # adjust bounds every ns*dim(x_init) evaluations
4444
rt::T = 0.9 # geometric temperature reduction factor: when temp changes, new temp is t=rt*t
@@ -205,7 +205,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
205205
h_calls(d),
206206
true,
207207
options.time_limit,
208-
_time-t0,)
208+
_time-t0,NamedTuple())
209209
end
210210
end
211211
end
@@ -344,7 +344,8 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
344344
h_calls(d),
345345
true,
346346
options.time_limit,
347-
_time-t0,)
347+
_time-t0,
348+
NamedTuple())
348349

349350
end
350351

src/multivariate/solvers/zeroth_order/nelder_mead.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ function initial_convergence(d, state::NelderMeadState, method::NelderMead, init
307307
nmobjective(state.f_simplex, state.m, length(initial_x)) < options.g_abstol
308308
end
309309

310-
function trace!(tr, d, state, iteration, method::NelderMead, options, curr_time=time())
310+
function trace!(tr, d, state, iteration, method::NelderMead, options::Options, curr_time=time())
311311
dt = Dict()
312312
dt["time"] = curr_time
313313
if options.extended_trace

src/multivariate/solvers/zeroth_order/zeroth_utils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function trace!(tr, d, state, iteration, method::ZerothOrderOptimizer, options, curr_time=time())
1+
function trace!(tr, d, state, iteration, method::Union{ZerothOrderOptimizer, SAMIN}, options::Options, curr_time=time())
22
dt = Dict()
33
dt["time"] = curr_time
44
if options.extended_trace

src/types.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
abstract type AbstractOptimizer end
2-
abstract type AbstractConstrainedOptimizer end
2+
abstract type AbstractConstrainedOptimizer <: AbstractOptimizer end
33
abstract type ZerothOrderOptimizer <: AbstractOptimizer end
44
abstract type FirstOrderOptimizer <: AbstractOptimizer end
55
abstract type SecondOrderOptimizer <: AbstractOptimizer end
@@ -163,7 +163,7 @@ const OptimizationTrace{Tf, T} = Vector{OptimizationState{Tf, T}}
163163

164164
abstract type OptimizationResults end
165165

166-
mutable struct MultivariateOptimizationResults{O, T, Tx, Tc, Tf, M, Tls} <: OptimizationResults
166+
mutable struct MultivariateOptimizationResults{O, T, Tx, Tc, Tf, M, Tls, Tsb} <: OptimizationResults
167167
method::O
168168
initial_x::Tx
169169
minimizer::Tx
@@ -191,6 +191,7 @@ mutable struct MultivariateOptimizationResults{O, T, Tx, Tc, Tf, M, Tls} <: Opti
191191
ls_success::Tls
192192
time_limit::Float64
193193
time_run::Float64
194+
stopped_by::Tsb
194195
end
195196

196197

src/utilities/assess_convergence.jl

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,43 @@ gradient_convergence_assessment(state::ZerothOrderState, d, options) = false
1818
# AcceleratedGradientDescentState, BFGSState, ConjugateGradientState,
1919
# GradientDescentState, LBFGSState, MomentumGradientDescentState and NewtonState
2020
function assess_convergence(state::AbstractOptimizerState, d, options::Options)
21+
assess_convergence(state.x,
22+
state.x_previous,
23+
value(d),
24+
state.f_x_previous,
25+
gradient(d),
26+
options.x_abstol,
27+
options.x_reltol,
28+
options.f_abstol,
29+
options.f_reltol,
30+
options.g_abstol)
31+
end
32+
function assess_convergence(x, x_previous, f_x, f_x_previous, gx, x_abstol, x_reltol, f_abstol, f_reltol, g_abstol)
2133
x_converged, f_converged, f_increased, g_converged = false, false, false, false
2234

2335
# TODO: Create function for x_convergence_assessment
24-
if x_abschange(state.x, state.x_previous) options.x_abstol
36+
if x_abschange(x, x_previous) x_abstol
2537
x_converged = true
2638
end
27-
if x_abschange(state.x, state.x_previous) options.x_reltol * norm(state.x, Inf)
39+
if x_abschange(x, x_previous) x_reltol * norm(x, Inf)
2840
x_converged = true
2941
end
3042

3143
# Relative Tolerance
3244
# TODO: Create function for f_convergence_assessment
33-
f_x = value(d)
34-
if f_abschange(f_x, state.f_x_previous) options.f_abstol
45+
if f_abschange(f_x, f_x_previous) f_abstol
3546
f_converged = true
3647
end
3748

38-
if f_abschange(f_x, state.f_x_previous) options.f_reltol*abs(f_x)
49+
if f_abschange(f_x, f_x_previous) f_reltol*abs(f_x)
3950
f_converged = true
4051
end
4152

42-
if f_x > state.f_x_previous
53+
if f_x > f_x_previous
4354
f_increased = true
4455
end
4556

46-
g_converged = gradient_convergence_assessment(state,d,options)
57+
g_converged = g_residual(gx) g_abstol
4758

4859
return x_converged, f_converged, g_converged, f_increased
4960
end

0 commit comments

Comments
 (0)