Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 20 additions & 16 deletions src/multivariate/solvers/constrained/samin.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
```julia
SAMIN(; nt::Int = 5 # reduce temperature every nt*ns*dim(x_init) evaluations
ns::Int = 5 # adjust bounds every ns*dim(x_init) evaluations
t0::T = 2.0 # Initial temperature
rt::T = 0.9 # geometric temperature reduction factor: when temp changes, new temp is t=rt*t
r_expand::T = 10.0 # geometric temperature promotion factor for situation with low coverage: when temp changes, new temp is t=r_expand*t
bounds_ratio::T = 0.6 # cut-off for bounds increment (1-bounds_ratio for decrease)
neps::Int = 5 # number of previous best values the final result is compared to
f_tol::T = 1e-12 # the required tolerance level for function value comparisons
x_tol::T = 1e-6 # the required tolerance level for x
coverage_ok::Bool = false, # if false, increase temperature until initial parameter space is covered
verbosity::Int = 1) # scalar: 0, 1, 2 or 3 (default = 1).
```
Expand All @@ -41,12 +42,13 @@ algorithm
@with_kw struct SAMIN{T}<:AbstractConstrainedOptimizer
nt::Int = 5 # reduce temperature every nt*ns*dim(x_init) evaluations
ns::Int = 5 # adjust bounds every ns*dim(x_init) evaluations
t0::T = 2.0 # Initial temperature
rt::T = 0.9 # geometric temperature reduction factor: when temp changes, new temp is t=rt*t
r_expand::T = 10.0 # geometric temperature promotion factor for situation with low coverage: when temp changes, new temp is t=r_expand*t
bounds_ratio::T = 0.6 # cut-off for bounds increment (1-bounds_ratio for decrease)
neps::Int = 5 # number of previous best values the final result is compared to
f_tol::T = 1e-12 # the required tolerance level for function value comparisons
x_tol::T = 1e-6 # the required tolerance level for x
coverage_ok::Bool = false # if false, increase temperature until initial parameter space is covered
verbosity::Int = 1 # scalar: 0, 1, 2 or 3 (default = 1: see final results).
verbosity::Int = 0 # scalar: 0, 1, 2 or 3 (default = 1: see final results).
end
# * verbosity: scalar: 0, 1, 2 or 3 (default = 1).
# * 0 = no screen output
Expand All @@ -58,22 +60,24 @@ Base.summary(::SAMIN) = "SAMIN"

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

t0 = time() # Initial time stamp used to control early stopping by options.time_limit
time0 = time() # Initial time stamp used to control early stopping by options.time_limit

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

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

@unpack nt, ns, rt, neps, f_tol, x_tol, coverage_ok, verbosity = method
@unpack nt, ns, t0, rt, r_expand, bounds_ratio, neps, coverage_ok, verbosity = method
verbose = verbosity > 0

x_tol, f_tol = options.f_abstol, options.x_abstol

x0 = copy(x)
n = size(x,1) # dimension of parameter
# Set initial values
nacc = 0 # total accepted trials
t = 2.0 # temperature - will initially rise or fall to cover parameter space. Then it will fall
t = t0 # temperature - will initially rise or fall to cover parameter space. Then it will fall
converge = 0 # convergence indicator 0 (failure), 1 (normal success), or 2 (convergence but near bounds)
x_converged = false
f_converged = false
Expand All @@ -96,7 +100,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
options.show_trace && print_header(method)
iteration = 0
_time = time()
trace!(tr, d, (x=xopt, iteration=iteration), iteration, method, options, _time-t0)
trace!(tr, d, (x=xopt, iteration=iteration), iteration, method, options, _time-time0)
stopped_by_callback = false
# main loop, first increase temperature until parameter space covered, then reduce until convergence
while converge==0
Expand Down Expand Up @@ -160,12 +164,12 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray

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

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

if verbose
println(hline)
Expand Down Expand Up @@ -206,7 +210,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
h_calls(d),
true,
options.time_limit,
_time-t0,NamedTuple())
_time-time0,NamedTuple())
end
end
end
Expand All @@ -215,8 +219,8 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
for i = 1:n
if (lb[i] != ub[i])
ratio = nacp[i] / ns
if(ratio > 0.6) bounds[i] = bounds[i] * (1.0 + 2.0 * (ratio - 0.6) / 0.4) end
if(ratio < .4) bounds[i] = bounds[i] / (1.0 + 2.0 * ((0.4 - ratio) / 0.4)) end
if(ratio > bounds_ratio) bounds[i] = bounds[i] * (1.0 + 2.0 * (ratio - 0.6) / 0.4) end
if(ratio < 1-bounds_ratio) bounds[i] = bounds[i] / (1.0 + 2.0 * ((0.4 - ratio) / 0.4)) end
# keep within initial bounds
if(bounds[i] > (ub[i] - lb[i]))
bounds[i] = ub[i] - lb[i]
Expand Down Expand Up @@ -309,7 +313,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
f_old = copy(fopt)
x = copy(xopt)
else # coverage not ok - increase temperature quickly to expand search area
t *= 10.0
t *= r_expand
for i = neps:-1:2
fstar[i] = fstar[i-1]
end
Expand Down Expand Up @@ -343,7 +347,7 @@ function optimize(obj_fn, lb::AbstractArray, ub::AbstractArray, x::AbstractArray
h_calls(d),
true,
options.time_limit,
_time-t0,
_time-time0,
NamedTuple())

end
Expand Down
25 changes: 18 additions & 7 deletions test/multivariate/solvers/constrained/samin.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
@testset "SAMIN" begin
prob = MVP.UnconstrainedProblems.examples["Himmelblau"]

xtrue = prob.solutions
f = OptimTestProblems.MultivariateProblems.objective(prob)
x0 = prob.initial_x
res = optimize(f, x0.-100., x0.+100.0, x0, Optim.SAMIN(), Optim.Options(iterations=1000000))
@test Optim.minimum(res) < 1e-6
@testset "SAMIN $i" for i in keys(MVP.UnconstrainedProblems.examples)
prob = MVP.UnconstrainedProblems.examples[i]
if i !== "Himmelblau"
continue
end
xtrue = prob.solutions
f = OptimTestProblems.MultivariateProblems.objective(prob)
x0 = prob.initial_x
res = optimize(
f,
x0 ./ 1.1 .- 2.0,
x0 .* 1.1 .+ 2.0,
x0,
Optim.SAMIN(t0 = 2.0, r_expand = 9.0, verbosity = 0),
Optim.Options(iterations = 100000),
)
@test Optim.minimum(res) < 1e-5
end
end
Loading