Skip to content

Commit 953b9b2

Browse files
Merge branch 'master' into multistartoptimization
2 parents fc637f6 + 6c70b86 commit 953b9b2

File tree

8 files changed

+237
-2
lines changed

8 files changed

+237
-2
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ makedocs(
3131
"CMAEvolutionStrategy.jl" => "optimization_packages/cmaevolutionstrategy.md",
3232
"Evolutionary.jl" => "optimization_packages/evolutionary.md",
3333
"Flux.jl" => "optimization_packages/flux.md",
34+
"GCMAES.jl" => "optimization_packages/gcmaes.md",
3435
"MathOptInterface.jl" => "optimization_packages/mathoptinterface.md",
3536
"MultistartOptimization.jl" => "optimization_packages/multistartoptimization.md",
3637
"Metaheuristics.jl" => "optimization_packages/metaheuristics.md",
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# GCMAES.jl
2+
[`GCMAES`](https://github.com/AStupidBear/GCMAES.jl) is a Julia package implementing the **Gradient-based Covariance Matrix Adaptation Evolutionary Strategy** which can utilize the gradient information to speed up the optimization process.
3+
4+
The GCMAES algorithm is called by `GCMAESOpt()` and the initial search variance is set as a keyword argument `σ0` (default: `σ0 = 0.2`)
5+
6+
## Global Optimizer
7+
### Without Constraint Equations
8+
9+
The method in [`GCMAES`](https://github.com/AStupidBear/GCMAES.jl) is performing global optimization on problems without
10+
constraint equations. However, lower and upper constraints set by `lb` and `ub` in the `OptimizationProblem` are required.
11+
12+
The Rosenbrock function can optimized using the `GCMAESOpt()` without utilizing the gradient information as follows:
13+
14+
```julia
15+
rosenbrock(x, p) = (p[1] - x[1])^2 + p[2] * (x[2] - x[1]^2)^2
16+
x0 = zeros(2)
17+
p = [1.0, 100.0]
18+
f = OptimizationFunction(rosenbrock)
19+
prob = GalacticOptim.OptimizationProblem(f, x0, p, lb = [-1.0,-1.0], ub = [1.0,1.0])
20+
sol = solve(prob, GCMAESOpt())
21+
```
22+
23+
We can also utilise the gradient information of the optimization problem to aid the optimization as follows:
24+
25+
```julia
26+
rosenbrock(x, p) = (p[1] - x[1])^2 + p[2] * (x[2] - x[1]^2)^2
27+
x0 = zeros(2)
28+
p = [1.0, 100.0]
29+
f = OptimizationFunction(rosenbrock, GalacticOptim.ForwardDiff)
30+
prob = GalacticOptim.OptimizationProblem(f, x0, p, lb = [-1.0,-1.0], ub = [1.0,1.0])
31+
sol = solve(prob, GCMAESOpt())
32+
```
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SpeedMapping.jl
2+
[`SpeedMapping`](https://github.com/NicolasL-S/SpeedMapping.jl) accelerates the convergence of a mapping to a fixed point by the Alternating cyclic extrapolation algorithm which can also perform multivariate optimization based on the gradient function.
3+
4+
The SpeedMapping algorithm is called by `SpeedMappingOpt()`
5+
6+
## Global Optimizer
7+
### Without Constraint Equations
8+
9+
The method in [`SpeedMapping`](https://github.com/NicolasL-S/SpeedMapping.jl) is performing optimization on problems without
10+
constraint equations. Lower and upper constraints set by `lb` and `ub` in the `OptimizationProblem` are optional.
11+
12+
If no AD backend is defined via `OptimizationFunction` the gradient is calculated via `SpeedMapping`'s ForwardDiff AD backend.
13+
14+
The Rosenbrock function can be optimized using the `SpeedMappingOpt()` with and without bound as follows:
15+
16+
```julia
17+
rosenbrock(x, p) = (p[1] - x[1])^2 + p[2] * (x[2] - x[1]^2)^2
18+
x0 = zeros(2)
19+
p = [1.0, 100.0]
20+
f = OptimizationFunction(rosenbrock, GalacticOptim.AutoForwardDiff())
21+
prob = OptimizationProblem(f, x0, _p)
22+
sol = solve(prob,SpeedMappingOpt())
23+
24+
prob = OptimizationProblem(f, x0, _p;lb=[0.0,0.0], ub=[1.0,1.0])
25+
sol = solve(prob,SpeedMappingOpt())
26+
```

src/GalacticOptim.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ function __init__()
2424
@require CMAEvolutionStrategy="8d3b24bd-414e-49e0-94fb-163cc3a3e411" include("solve/cmaevolutionstrategy.jl")
2525
@require Evolutionary="86b6b26d-c046-49b6-aa0b-5f0f74682bd6" include("solve/evolutionary.jl")
2626
@require Flux="587475ba-b771-5e3f-ad9e-33799f191a9c" include("solve/flux.jl")
27+
@require GCMAES="4aa9d100-eb0f-11e8-15f1-25748831eb3b" include("solve/gcmaes.jl")
2728
@require MathOptInterface="b8f27783-ece8-5eb3-8dc8-9495eed66fee" include("solve/moi.jl")
2829
@require MultistartOptimization="3933049c-43be-478e-a8bb-6e0f7fd53575" include("solve/multistartoptimization.jl")
2930
@require NLopt="76087f3c-5699-56af-9a33-bf431cd00edd" begin
@@ -45,6 +46,7 @@ function __init__()
4546
end
4647
end
4748
@require Metaheuristics="bcdb8e00-2c21-11e9-3065-2b553b22f898" include("solve/metaheuristics.jl")
49+
@require SpeedMapping="f1835b91-879b-4a3f-a438-e4baacf14412" include("solve/speedmapping.jl")
4850

4951
# AD backends
5052
@require FiniteDiff="6a86dc24-6348-571c-b903-95158fe2bd41" include("function/finitediff.jl")

src/solve/gcmaes.jl

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export GCMAESOpt
2+
3+
struct GCMAESOpt end
4+
5+
function __map_optimizer_args(prob::OptimizationProblem, opt::GCMAESOpt;
6+
cb=nothing,
7+
maxiters::Union{Number, Nothing}=nothing,
8+
maxtime::Union{Number, Nothing}=nothing,
9+
abstol::Union{Number, Nothing}=nothing,
10+
reltol::Union{Number, Nothing}=nothing,
11+
kwargs...)
12+
13+
# add optimiser options from kwargs
14+
mapped_args = (; kwargs...)
15+
16+
if !(isnothing(maxiters))
17+
mapped_args = (; mapped_args..., maxiter = maxiters)
18+
end
19+
20+
if !(isnothing(maxtime))
21+
@warn "common maxtime is currently not used by $(opt)"
22+
end
23+
24+
if !isnothing(abstol)
25+
@warn "common abstol is currently not used by $(opt)"
26+
end
27+
28+
if !isnothing(reltol)
29+
@warn "common reltol is currently not used by $(opt)"
30+
end
31+
32+
return mapped_args
33+
end
34+
35+
36+
function __solve(prob::OptimizationProblem, opt::GCMAESOpt;
37+
maxiters::Union{Number, Nothing} = nothing,
38+
maxtime::Union{Number, Nothing} = nothing,
39+
abstol::Union{Number, Nothing}=nothing,
40+
reltol::Union{Number, Nothing}=nothing,
41+
progress = false,
42+
σ0=0.2,
43+
kwargs...)
44+
local x
45+
local G = similar(prob.u0)
46+
47+
maxiters = _check_and_convert_maxiters(maxiters)
48+
maxtime = _check_and_convert_maxtime(maxtime)
49+
50+
f = instantiate_function(prob.f,prob.u0,prob.f.adtype,prob.p)
51+
52+
_loss = function(θ)
53+
x = f.f(θ, prob.p)
54+
return x[1]
55+
end
56+
57+
if !isnothing(f.grad)
58+
g = function (θ)
59+
f.grad(G, θ)
60+
return G
61+
end
62+
end
63+
64+
opt_args = _map_optimizer_args(prob,opt, maxiters=maxiters, maxtime=maxtime, abstol=abstol, reltol=reltol; kwargs...)
65+
66+
t0 = time()
67+
if prob.sense === MaxSense
68+
opt_xmin, opt_fmin, opt_ret = GCMAES.maximize(isnothing(f.grad) ? _loss : (_loss,g), prob.u0, σ0, prob.lb, prob.ub; opt_args...)
69+
else
70+
opt_xmin, opt_fmin, opt_ret = GCMAES.minimize(isnothing(f.grad) ? _loss : (_loss,g), prob.u0, σ0, prob.lb, prob.ub; opt_args...)
71+
end
72+
t1 = time()
73+
74+
SciMLBase.build_solution(prob, opt, opt_xmin, opt_fmin; retcode=Symbol(Bool(opt_ret)))
75+
end

src/solve/speedmapping.jl

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export SpeedMappingOpt
2+
3+
struct SpeedMappingOpt end
4+
5+
function __map_optimizer_args(prob::OptimizationProblem, opt::SpeedMappingOpt;
6+
cb=nothing,
7+
maxiters::Union{Number, Nothing}=nothing,
8+
maxtime::Union{Number, Nothing}=nothing,
9+
abstol::Union{Number, Nothing}=nothing,
10+
reltol::Union{Number, Nothing}=nothing,
11+
kwargs...)
12+
13+
# add optimiser options from kwargs
14+
mapped_args = (; kwargs...)
15+
16+
if !(isnothing(maxiters))
17+
@info "maxiters defines maximum gradient calls for $(opt)"
18+
mapped_args = (; mapped_args..., maps_limit = maxiters)
19+
end
20+
21+
if !(isnothing(maxtime))
22+
mapped_args = (; mapped_args..., time_limit = maxtime)
23+
end
24+
25+
if !isnothing(abstol)
26+
@warn "common abstol is currently not used by $(opt)"
27+
end
28+
29+
if !isnothing(reltol)
30+
@warn "common reltol is currently not used by $(opt)"
31+
end
32+
33+
return mapped_args
34+
end
35+
36+
37+
function __solve(prob::OptimizationProblem, opt::SpeedMappingOpt;
38+
maxiters::Union{Number, Nothing} = nothing,
39+
maxtime::Union{Number, Nothing} = nothing,
40+
abstol::Union{Number, Nothing}=nothing,
41+
reltol::Union{Number, Nothing}=nothing,
42+
progress = false,
43+
kwargs...)
44+
local x
45+
46+
maxiters = _check_and_convert_maxiters(maxiters)
47+
maxtime = _check_and_convert_maxtime(maxtime)
48+
49+
f = instantiate_function(prob.f,prob.u0,prob.f.adtype,prob.p)
50+
51+
_loss = function(θ)
52+
x = f.f(θ, prob.p)
53+
return first(x)
54+
end
55+
56+
if isnothing(f.grad)
57+
@info "SpeedMapping's ForwardDiff AD backend is used to calculate the gradient information."
58+
end
59+
60+
opt_args = _map_optimizer_args(prob,opt, maxiters=maxiters, maxtime=maxtime, abstol=abstol, reltol=reltol; kwargs...)
61+
62+
t0 = time()
63+
opt_res = SpeedMapping.speedmapping(prob.u0; f = _loss, g! =f.grad, lower=prob.lb, upper=prob.ub, opt_args...)
64+
t1 = time()
65+
opt_ret = Symbol(opt_res.converged)
66+
67+
SciMLBase.build_solution(prob, opt, opt_res.minimizer, _loss(opt_res.minimizer); original=opt_res, retcode=opt_ret)
68+
end

test/Project.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Evolutionary = "86b6b26d-c046-49b6-aa0b-5f0f74682bd6"
77
FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41"
88
Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c"
99
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
10+
GCMAES = "4aa9d100-eb0f-11e8-15f1-25748831eb3b"
1011
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
1112
IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
1213
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
@@ -30,6 +31,7 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
3031
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
3132
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
3233
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
34+
SpeedMapping = "f1835b91-879b-4a3f-a438-e4baacf14412"
3335
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3436
Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"
3537
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
@@ -42,6 +44,7 @@ Evolutionary = ">= 0.10.0"
4244
FiniteDiff = ">= 2.8.1"
4345
Flux = ">= 0.12.6"
4446
ForwardDiff = ">= 0.10.19"
47+
GCMAES = ">= 0.1.25"
4548
Ipopt = ">= 0.7.0"
4649
IterTools = ">= 1.3.0"
4750
MathOptInterface = ">= 0.9.22"
@@ -63,6 +66,7 @@ Optim = ">= 1.4.1"
6366
OrdinaryDiffEq = ">= 5"
6467
ReverseDiff = ">= 1.9.0"
6568
SafeTestsets = ">= 0.0.1"
69+
SpeedMapping = ">= 0.3.0"
6670
Tracker = ">= 0.2"
6771
Zygote = ">= 0.5"
68-
julia = "1.5"
72+
julia = "1.5"

test/rosenbrock.jl

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ end
169169
# sol = solve(prob, QuadDirect(); splits = ([-0.5, 0.0, 0.5],[-0.5, 0.0, 0.5]))
170170
# @test 10*sol.minimum < l1
171171

172-
@testset "Evolutionary, BlackBoxOptim, Metaheuristics, Nonconvex, MultistartOptimization" begin
172+
@testset "Evolutionary, BlackBoxOptim, Metaheuristics, Nonconvex, GCMAES, SpeedMapping, MultistartOptimization" begin
173173
optprob = OptimizationFunction(rosenbrock, GalacticOptim.AutoZygote())
174174
using Evolutionary
175175
prob = GalacticOptim.OptimizationProblem(optprob, x0, _p)
@@ -423,6 +423,33 @@ end
423423
sol = solve(prob, BayesOptAlg(NLoptAlg(:LN_NELDERMEAD)), sub_options=(;maxeval=100))
424424
@test 10*sol.minimum < l1
425425

426+
using GCMAES
427+
f_ad = OptimizationFunction(rosenbrock, GalacticOptim.AutoForwardDiff())
428+
f_noad = OptimizationFunction(rosenbrock)
429+
430+
prob = GalacticOptim.OptimizationProblem(f_ad, x0, _p, lb=[-1.0, -1.0], ub=[1.0, 1.0])
431+
sol = solve(prob, GCMAESOpt(), maxiters=1000)
432+
@test 10*sol.minimum < l1
433+
434+
prob = GalacticOptim.OptimizationProblem(f_noad, x0, _p, lb=[-1.0, -1.0], ub=[1.0, 1.0])
435+
sol = solve(prob, GCMAESOpt(), maxiters=1000)
436+
@test 10*sol.minimum < l1
437+
438+
using SpeedMapping
439+
f = OptimizationFunction(rosenbrock, GalacticOptim.AutoForwardDiff())
440+
prob = OptimizationProblem(f, x0, _p)
441+
sol = solve(prob,SpeedMappingOpt())
442+
443+
prob = OptimizationProblem(f, x0, _p;lb=[0.0,0.0], ub=[1.0,1.0])
444+
sol = solve(prob,SpeedMappingOpt())
445+
446+
f = OptimizationFunction(rosenbrock)
447+
prob = OptimizationProblem(f, x0, _p)
448+
sol = solve(prob,SpeedMappingOpt())
449+
450+
prob = OptimizationProblem(f, x0, _p;lb=[0.0,0.0], ub=[1.0,1.0])
451+
sol = solve(prob,SpeedMappingOpt())
452+
426453
using MultistartOptimization
427454
f = OptimizationFunction(rosenbrock,GalacticOptim.AutoForwardDiff())
428455
prob = GalacticOptim.OptimizationProblem(f, x0, _p, lb = [-1.0,-1.0], ub = [1.5,1.5])

0 commit comments

Comments
 (0)