-
Notifications
You must be signed in to change notification settings - Fork 2
/
covariance_matrix_adaptation.jl
46 lines (40 loc) · 1.68 KB
/
covariance_matrix_adaptation.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#! algorithm 8.9 of Kochenderfer & Wheeler (2019)
using LinearAlgebra
using Distributions
function covariance_matrix_adaptation(f, x, k_max; σ = 1.0,
m = 4 + floor(Int, 3*log(length(x))),
m_elite = div(m, 2))
μ, n = copy(x), length(x)
ws = normalize!(vcat(log((m+1)/2) .- log.(1:m_elite),
zeros(m - m_elite)), 1)
μ_eff = 1 / sum(ws.^2)
cσ = (μ_eff + 2)/(n + μ_eff + 5)
dσ = 1 + 2max(0, sqrt((μ_eff-1)/(n+1))-1) + cσ
cΣ = (4 + μ_eff/n)/(n + 4 + 2μ_eff/n)
c1 = 2/((n+1.3)^2 + μ_eff)
cμ = min(1-c1, 2*(μ_eff-2+1/μ_eff)/((n+2)^2 + μ_eff))
E = n^0.5*(1-1/(4n)+1/(21*n^2))
pσ, pΣ, Σ = zeros(n), zeros(n), Matrix(1.0I, n, n)
for k in 1 : k_max
P = MvNormal(μ, σ^2*Σ)
xs = [rand(P) for i in 1:m]
ys = [f(x) for x in xs]
is = sortperm(ys) # best to worst
# selection and mean update
δs = [(x - μ)/σ for x in xs]
δw = sum(ws[i]*δs[is[i]] for i in 1 : m_elite)
μ += σ*δw
# step-size control
C = Σ^-0.5
pσ = (1-cσ)*pσ + sqrt(cσ*(2-cσ)*μ_eff)*C*δw
σ *= exp(cσ/dσ * (norm(pσ)/E - 1))
# covariance adaptation
hσ = Int(norm(pσ)/sqrt(1-(1-cσ)^(2k)) < (1.4+2/(n+1))*E)
pΣ = (1-cΣ)*pΣ + hσ*sqrt(cΣ*(2-cΣ)*μ_eff)*δw
w0 = [ws[i] >= 0 ? ws[i] : n*ws[i]/norm(C*δs[is[i]])^2 for i in 1:m]
Σ = (1-c1-cμ) * Σ + c1*(pΣ*pΣ' + (1-hσ) * cΣ*(2-cΣ) * Σ) +
cμ*sum(w0[i]*δs[is[i]]*δs[is[i]]' for i in 1 : m)
Σ = triu(Σ)+ triu(Σ, 1)' # enforce symmetry
end
return μ
end