Skip to content

Commit ae48574

Browse files
authored
Expose SAMIN options (#1136)
* Update samin.jl * Fix time and add tests * Update Project.toml
1 parent 7503755 commit ae48574

File tree

2 files changed

+38
-23
lines changed
  • src/multivariate/solvers/constrained
  • test/multivariate/solvers/constrained

2 files changed

+38
-23
lines changed

src/multivariate/solvers/constrained/samin.jl

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
```julia
2323
SAMIN(; nt::Int = 5 # reduce temperature every nt*ns*dim(x_init) evaluations
2424
ns::Int = 5 # adjust bounds every ns*dim(x_init) evaluations
25+
t0::T = 2.0 # Initial temperature
2526
rt::T = 0.9 # geometric temperature reduction factor: when temp changes, new temp is t=rt*t
27+
r_expand::T = 10.0 # geometric temperature promotion factor for situation with low coverage: when temp changes, new temp is t=r_expand*t
28+
bounds_ratio::T = 0.6 # cut-off for bounds increment (1-bounds_ratio for decrease)
2629
neps::Int = 5 # number of previous best values the final result is compared to
27-
f_tol::T = 1e-12 # the required tolerance level for function value comparisons
28-
x_tol::T = 1e-6 # the required tolerance level for x
2930
coverage_ok::Bool = false, # if false, increase temperature until initial parameter space is covered
3031
verbosity::Int = 1) # scalar: 0, 1, 2 or 3 (default = 1).
3132
```
@@ -41,12 +42,13 @@ algorithm
4142
@with_kw struct SAMIN{T}<:AbstractConstrainedOptimizer
4243
nt::Int = 5 # reduce temperature every nt*ns*dim(x_init) evaluations
4344
ns::Int = 5 # adjust bounds every ns*dim(x_init) evaluations
45+
t0::T = 2.0 # Initial temperature
4446
rt::T = 0.9 # geometric temperature reduction factor: when temp changes, new temp is t=rt*t
47+
r_expand::T = 10.0 # geometric temperature promotion factor for situation with low coverage: when temp changes, new temp is t=r_expand*t
48+
bounds_ratio::T = 0.6 # cut-off for bounds increment (1-bounds_ratio for decrease)
4549
neps::Int = 5 # number of previous best values the final result is compared to
46-
f_tol::T = 1e-12 # the required tolerance level for function value comparisons
47-
x_tol::T = 1e-6 # the required tolerance level for x
4850
coverage_ok::Bool = false # if false, increase temperature until initial parameter space is covered
49-
verbosity::Int = 1 # scalar: 0, 1, 2 or 3 (default = 1: see final results).
51+
verbosity::Int = 0 # scalar: 0, 1, 2 or 3 (default = 1: see final results).
5052
end
5153
# * verbosity: scalar: 0, 1, 2 or 3 (default = 1).
5254
# * 0 = no screen output
@@ -58,22 +60,24 @@ Base.summary(::SAMIN) = "SAMIN"
5860

5961
function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray{Tx}, method::SAMIN, options::Options = Options()) where Tx
6062

61-
t0 = time() # Initial time stamp used to control early stopping by options.time_limit
63+
time0 = time() # Initial time stamp used to control early stopping by options.time_limit
6264

6365
hline = "="^80
6466
d = NonDifferentiable(obj_fn, x)
6567

6668
tr = OptimizationTrace{typeof(value(d)), typeof(method)}()
6769
tracing = options.store_trace || options.show_trace || options.extended_trace || options.callback !== nothing
6870

69-
@unpack nt, ns, rt, neps, f_tol, x_tol, coverage_ok, verbosity = method
71+
@unpack nt, ns, t0, rt, r_expand, bounds_ratio, neps, coverage_ok, verbosity = method
7072
verbose = verbosity > 0
7173

74+
x_tol, f_tol = options.f_abstol, options.x_abstol
75+
7276
x0 = copy(x)
7377
n = size(x,1) # dimension of parameter
7478
# Set initial values
7579
nacc = 0 # total accepted trials
76-
t = 2.0 # temperature - will initially rise or fall to cover parameter space. Then it will fall
80+
t = t0 # temperature - will initially rise or fall to cover parameter space. Then it will fall
7781
converge = 0 # convergence indicator 0 (failure), 1 (normal success), or 2 (convergence but near bounds)
7882
x_converged = false
7983
f_converged = false
@@ -96,7 +100,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
96100
options.show_trace && print_header(method)
97101
iteration = 0
98102
_time = time()
99-
trace!(tr, d, (x=xopt, iteration=iteration), iteration, method, options, _time-t0)
103+
trace!(tr, d, (x=xopt, iteration=iteration), iteration, method, options, _time-time0)
100104
stopped_by_callback = false
101105
# main loop, first increase temperature until parameter space covered, then reduce until convergence
102106
while converge==0
@@ -160,12 +164,12 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
160164

161165
if tracing
162166
# update trace; callbacks can stop routine early by returning true
163-
stopped_by_callback = trace!(tr, d, (x=xopt,iteration=iteration), iteration, method, options, time()-t0)
167+
stopped_by_callback = trace!(tr, d, (x=xopt,iteration=iteration), iteration, method, options, time()-time0)
164168
end
165169

166170
# If options.iterations exceeded, terminate the algorithm
167171
_time = time()
168-
if f_calls(d) >= options.iterations || _time-t0 > options.time_limit || stopped_by_callback
172+
if f_calls(d) >= options.iterations || _time-time0 > options.time_limit || stopped_by_callback
169173

170174
if verbose
171175
println(hline)
@@ -206,7 +210,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
206210
h_calls(d),
207211
true,
208212
options.time_limit,
209-
_time-t0,NamedTuple())
213+
_time-time0,NamedTuple())
210214
end
211215
end
212216
end
@@ -215,8 +219,8 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
215219
for i = 1:n
216220
if (lb[i] != ub[i])
217221
ratio = nacp[i] / ns
218-
if(ratio > 0.6) bounds[i] = bounds[i] * (1.0 + 2.0 * (ratio - 0.6) / 0.4) end
219-
if(ratio < .4) bounds[i] = bounds[i] / (1.0 + 2.0 * ((0.4 - ratio) / 0.4)) end
222+
if(ratio > bounds_ratio) bounds[i] = bounds[i] * (1.0 + 2.0 * (ratio - 0.6) / 0.4) end
223+
if(ratio < 1-bounds_ratio) bounds[i] = bounds[i] / (1.0 + 2.0 * ((0.4 - ratio) / 0.4)) end
220224
# keep within initial bounds
221225
if(bounds[i] > (ub[i] - lb[i]))
222226
bounds[i] = ub[i] - lb[i]
@@ -309,7 +313,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
309313
f_old = copy(fopt)
310314
x = copy(xopt)
311315
else # coverage not ok - increase temperature quickly to expand search area
312-
t *= 10.0
316+
t *= r_expand
313317
for i = neps:-1:2
314318
fstar[i] = fstar[i-1]
315319
end
@@ -343,7 +347,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
343347
h_calls(d),
344348
true,
345349
options.time_limit,
346-
_time-t0,
350+
_time-time0,
347351
NamedTuple())
348352

349353
end
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
@testset "SAMIN" begin
2-
prob = MVP.UnconstrainedProblems.examples["Himmelblau"]
3-
4-
xtrue = prob.solutions
5-
f = OptimTestProblems.MultivariateProblems.objective(prob)
6-
x0 = prob.initial_x
7-
res = optimize(f, x0.-100., x0.+100.0, x0, Optim.SAMIN(), Optim.Options(iterations=1000000))
8-
@test Optim.minimum(res) < 1e-6
2+
@testset "SAMIN $i" for i in keys(MVP.UnconstrainedProblems.examples)
3+
prob = MVP.UnconstrainedProblems.examples[i]
4+
if i !== "Himmelblau"
5+
continue
6+
end
7+
xtrue = prob.solutions
8+
f = OptimTestProblems.MultivariateProblems.objective(prob)
9+
x0 = prob.initial_x
10+
res = optimize(
11+
f,
12+
x0 ./ 1.1 .- 2.0,
13+
x0 .* 1.1 .+ 2.0,
14+
x0,
15+
Optim.SAMIN(t0 = 2.0, r_expand = 9.0, verbosity = 0),
16+
Optim.Options(iterations = 100000),
17+
)
18+
@test Optim.minimum(res) < 1e-5
19+
end
920
end

0 commit comments

Comments
 (0)