Skip to content

Commit 6c70b86

Browse files
Merge pull request #174 from jonasmac16/GCMAES
New interface to GCMAES.jl
2 parents 10023fa + e9f9d5f commit 6c70b86

File tree

6 files changed

+124
-1
lines changed

6 files changed

+124
-1
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+
```

src/GalacticOptim.jl

Lines changed: 1 addition & 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" include("solve/nlopt.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

test/Project.toml

Lines changed: 2 additions & 0 deletions
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"
@@ -43,6 +44,7 @@ Evolutionary = ">= 0.10.0"
4344
FiniteDiff = ">= 2.8.1"
4445
Flux = ">= 0.12.6"
4546
ForwardDiff = ">= 0.10.19"
47+
GCMAES = ">= 0.1.25"
4648
Ipopt = ">= 0.7.0"
4749
IterTools = ">= 1.3.0"
4850
MathOptInterface = ">= 0.9.22"

test/rosenbrock.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ end
173173
# sol = solve(prob, QuadDirect(); splits = ([-0.5, 0.0, 0.5],[-0.5, 0.0, 0.5]))
174174
# @test 10*sol.minimum < l1
175175

176-
@testset "Evolutionary, BlackBoxOptim, Metaheuristics, Nonconvex, SpeedMapping" begin
176+
@testset "Evolutionary, BlackBoxOptim, Metaheuristics, Nonconvex, GCMAES, SpeedMapping" begin
177177
optprob = OptimizationFunction(rosenbrock, GalacticOptim.AutoZygote())
178178
using Evolutionary
179179
prob = GalacticOptim.OptimizationProblem(optprob, x0, _p)
@@ -426,6 +426,18 @@ end
426426

427427
sol = solve(prob, BayesOptAlg(NLoptAlg(:LN_NELDERMEAD)), sub_options=(;maxeval=100))
428428
@test 10*sol.minimum < l1
429+
430+
using GCMAES
431+
f_ad = OptimizationFunction(rosenbrock, GalacticOptim.AutoForwardDiff())
432+
f_noad = OptimizationFunction(rosenbrock)
433+
434+
prob = GalacticOptim.OptimizationProblem(f_ad, 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+
prob = GalacticOptim.OptimizationProblem(f_noad, x0, _p, lb=[-1.0, -1.0], ub=[1.0, 1.0])
439+
sol = solve(prob, GCMAESOpt(), maxiters=1000)
440+
@test 10*sol.minimum < l1
429441

430442
using SpeedMapping
431443
f = OptimizationFunction(rosenbrock, GalacticOptim.AutoForwardDiff())

0 commit comments

Comments
 (0)