Skip to content

Commit 3111adc

Browse files
committed
refactoring
1 parent f1c78ab commit 3111adc

File tree

3 files changed

+244
-141
lines changed

3 files changed

+244
-141
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ julia = "1"
2828
[extras]
2929
NonconvexNLopt = "b43a31b8-ff9b-442d-8e31-c163daa8ab75"
3030
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
31+
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
3132

3233
[targets]
33-
test = ["NonconvexNLopt", "Test"]
34+
test = ["NonconvexNLopt", "Test", "Zygote"]

src/bayesian.jl

Lines changed: 109 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,51 @@ mutable struct ZeroOrderGPSurrogate <: Function
44
f::Function
55
gps::Vector{<:GP}
66
X::Vector{Vector{Float64}}
7-
y::Union{Vector{Vector{Float64}}, Vector{Float64}}
7+
y::Union{Vector{Vector{Float64}},Vector{Float64}}
88
noise::Float64
99
std_multiple::Float64
1010
mode::Symbol
1111
N::Int
1212
every::Int
1313
skip::Int
14-
last::Union{Symbol, Int}
14+
last::Union{Symbol,Int}
1515
fit_prior::Bool
1616
fit_noise::Bool
1717
counter::Int
1818
end
1919
function ZeroOrderGPSurrogate(
20-
f, x; kernel = SqExponentialKernel(), X = [x], y = [f(x)], noise = 1e-8,
21-
std_multiple = 3.0, mode = :interval, every = 5, skip = 10, last = :all,
22-
fit_prior = true, fit_noise = false,
20+
f,
21+
x;
22+
kernel = SqExponentialKernel(),
23+
X = [x],
24+
y = [f(x)],
25+
noise = 1e-8,
26+
std_multiple = 3.0,
27+
mode = :interval,
28+
every = 5,
29+
skip = 10,
30+
last = :all,
31+
fit_prior = true,
32+
fit_noise = false,
2333
)
2434
@assert noise > 0
25-
gps = [GP(AbstractGPs.ConstMean(0.0), kernel) for _ in 1:length(y[1])]
35+
gps = [GP(AbstractGPs.ConstMean(0.0), kernel) for _ = 1:length(y[1])]
2636
N = length(y[1])
2737
return ZeroOrderGPSurrogate(
28-
f, gps, X, y, noise, std_multiple, mode, N, every, skip, last,
29-
fit_prior, fit_noise, 0,
38+
f,
39+
gps,
40+
X,
41+
y,
42+
noise,
43+
std_multiple,
44+
mode,
45+
N,
46+
every,
47+
skip,
48+
last,
49+
fit_prior,
50+
fit_noise,
51+
0,
3052
)
3153
end
3254

@@ -66,25 +88,27 @@ function fit_mle!(s, gps, X, y, noise, last, fit_noise)
6688
_X = X
6789
_y = y
6890
else
69-
_X = X[max(end-last+1, 1):end]
70-
_y = y[max(end-last+1, 1):end]
91+
_X = X[max(end - last + 1, 1):end]
92+
_y = y[max(end - last + 1, 1):end]
7193
end
7294
obj(θ) = begin
7395
if _y isa Vector{<:Vector}
7496
offset = 0
75-
return -sum(map(1:length(_y[1])) do i
76-
l1 = length(xs_uns_1[i][1])
77-
un1 = xs_uns_1[i][2]
78-
l2 = length(xs_lbs_ubs_uns_2[i][1])
79-
un2 = xs_lbs_ubs_uns_2[i][4]
80-
_gp = GP(un1(θ[offset+1:offset+l1]), un2(θ[offset+l1+1:offset+l1+l2]))
81-
offset += l1 + l2
82-
if fit_noise
83-
return logpdf(_gp(_X, θ[end]), getindex.(_y, i))
84-
else
85-
return logpdf(_gp(_X, noise), getindex.(_y, i))
86-
end
87-
end)
97+
return -sum(
98+
map(1:length(_y[1])) do i
99+
l1 = length(xs_uns_1[i][1])
100+
un1 = xs_uns_1[i][2]
101+
l2 = length(xs_lbs_ubs_uns_2[i][1])
102+
un2 = xs_lbs_ubs_uns_2[i][4]
103+
_gp = GP(un1(θ[offset+1:offset+l1]), un2(θ[offset+l1+1:offset+l1+l2]))
104+
offset += l1 + l2
105+
if fit_noise
106+
return logpdf(_gp(_X, θ[end]), getindex.(_y, i))
107+
else
108+
return logpdf(_gp(_X, noise), getindex.(_y, i))
109+
end
110+
end,
111+
)
88112
else
89113
l1 = length(xs_uns_1[1][1])
90114
un1 = xs_uns_1[1][2]
@@ -112,13 +136,15 @@ function fit_mle!(s, gps, X, y, noise, last, fit_noise)
112136
out = GP(un1(x[offset+1:offset+l1]), un2(x[offset+l1+1:offset+l1+l2]))
113137
offset += l1 + l2
114138
return out
115-
end, fit_noise ? x[end] : noise
139+
end,
140+
fit_noise ? x[end] : noise
116141
s.gps = gps
117142
s.noise = noise
118143
return s
119144
end
120145
function ChainRulesCore.rrule(::typeof(fit_mle!), s, gp, X, y, noise, last, fit_noise)
121-
return fit_mle!(s, gp, X, y, noise, last, fit_noise), _ -> begin
146+
return fit_mle!(s, gp, X, y, noise, last, fit_noise),
147+
_ -> begin
122148
return ntuple(_ -> NoTangent(), Val(8))
123149
end
124150
end
@@ -132,20 +158,21 @@ function (s::ZeroOrderGPSurrogate)(x)
132158
if s.fit_prior && s.counter > s.skip * s.every && (s.counter % s.every) == 0
133159
fit_mle!(s, s.gps, s.X, s.y, s.noise, s.last, s.fit_noise)
134160
end
135-
return Interval.(y, y)
161+
return Interval.(y, y)
136162
else
137163
if eltype(s.y) <: Real
138164
return _call_gp(s.gps[1], x, s.X, s.y, s.noise, s.std_multiple)
139165
else
140-
return map(i -> _call_gp(s.gps[i], x, s.X, getindex.(s.y, i), s.noise, s.std_multiple), 1:length(s.gps))
166+
return map(
167+
i -> _call_gp(s.gps[i], x, s.X, getindex.(s.y, i), s.noise, s.std_multiple),
168+
1:s.N,
169+
)
141170
end
142171
end
143172
end
144173

145174
function _call_gp(gp, x, X, y, noise, std_multiple)
146-
_m, _v = mean_and_var(posterior(
147-
gp(X, noise), y,
148-
), [x])
175+
_m, _v = mean_and_var(posterior(gp(X, noise), y), [x])
149176
m, v = _m[1], _v[1]
150177
r = std_multiple * sqrt(v)
151178
return Interval(m - r, m + r)
@@ -163,7 +190,7 @@ get_lo(x::AbstractVector) = map(get_lo, x)
163190
_lower_f(s) = get_lo s
164191
_equality_f(s) = x -> begin
165192
t = s(x)
166-
return [getproperty.(t, :lo); .- getproperty(t, :hi)]
193+
return [getproperty.(t, :lo); .-getproperty(t, :hi)]
167194
end
168195

169196
function surrogate_model(vecmodel::VecModel; kwargs...)
@@ -172,11 +199,7 @@ function surrogate_model(vecmodel::VecModel; kwargs...)
172199
if :expensive in vecmodel.objective.flags
173200
s = surrogate(vecmodel.objective.f, copy(x0); kwargs...)
174201
push!(surrogates, s)
175-
obj = Objective(
176-
_lower_f(s),
177-
vecmodel.objective.multiple,
178-
vecmodel.objective.flags,
179-
)
202+
obj = Objective(_lower_f(s), vecmodel.objective.multiple, vecmodel.objective.flags)
180203
else
181204
obj = vecmodel.objective
182205
end
@@ -188,32 +211,41 @@ function surrogate_model(vecmodel::VecModel; kwargs...)
188211
!(:expensive in c.flags)
189212
end
190213
eq_constraints = VectorOfFunctions(cheap_eq_constraints)
191-
ineq_constraints1 = Tuple(mapreduce(vcat, expensive_eq_constraints; init = Union{}[]) do c
192-
@assert c isa EqConstraint
193-
s = surrogate(c, copy(x0); kwargs...)
194-
push!(surrogates, s)
195-
return IneqConstraint(
196-
_equality_f(s), [zero.(c.rhs); zero.(c.rhs)], c.dim * 2, c.flags,
197-
)
198-
end)
214+
ineq_constraints1 = Tuple(
215+
mapreduce(vcat, expensive_eq_constraints; init = Union{}[]) do c
216+
@assert c isa EqConstraint
217+
s = surrogate(c, copy(x0); kwargs...)
218+
push!(surrogates, s)
219+
return IneqConstraint(
220+
_equality_f(s),
221+
[zero.(c.rhs); zero.(c.rhs)],
222+
c.dim * 2,
223+
c.flags,
224+
)
225+
end,
226+
)
199227
ineq_constraints2 = map(vecmodel.ineq_constraints.fs) do c
200228
@assert c isa IneqConstraint
201229
if :expensive in c.flags
202230
s = surrogate(c, copy(x0); kwargs...)
203231
push!(surrogates, s)
204-
return IneqConstraint(
205-
_lower_f(s), zero.(c.rhs), c.dim, c.flags,
206-
)
232+
return IneqConstraint(_lower_f(s), zero.(c.rhs), c.dim, c.flags)
207233
else
208234
return c
209235
end
210236
end
211-
ineq_constraints = VectorOfFunctions(
212-
(ineq_constraints1..., ineq_constraints2...),
213-
)
237+
ineq_constraints = VectorOfFunctions((ineq_constraints1..., ineq_constraints2...),)
214238
return VecModel(
215-
obj, eq_constraints, ineq_constraints, vecmodel.sd_constraints, vecmodel.box_min, vecmodel.box_max, vecmodel.init, vecmodel.integer,
216-
), Tuple(surrogates)
239+
obj,
240+
eq_constraints,
241+
ineq_constraints,
242+
vecmodel.sd_constraints,
243+
vecmodel.box_min,
244+
vecmodel.box_max,
245+
vecmodel.init,
246+
vecmodel.integer,
247+
),
248+
Tuple(surrogates)
217249
end
218250

219251
function update_surrogates!(model, surrogates, x)
@@ -229,7 +261,7 @@ function update_surrogates!(model, surrogates, x)
229261
return o, i, e
230262
end
231263

232-
struct BayesOptOptions{S, N <: NamedTuple}
264+
struct BayesOptOptions{S,N<:NamedTuple}
233265
sub_options::S
234266
maxiter::Int
235267
initialize::Bool
@@ -277,15 +309,21 @@ function BayesOptOptions(;
277309
)
278310
end
279311

280-
mutable struct BayesOptWorkspace{M <: VecModel, S1, X <: AbstractVector, O <: BayesOptOptions, S2 <: Union{Tuple, AbstractVector}} <: Workspace
312+
mutable struct BayesOptWorkspace{
313+
M<:VecModel,
314+
S1,
315+
X<:AbstractVector,
316+
O<:BayesOptOptions,
317+
S2<:Union{Tuple,AbstractVector},
318+
} <: Workspace
281319
model::M
282320
sub_workspace::S1
283321
x0::X
284322
options::O
285323
surrogates::S2
286324
end
287325

288-
struct BayesOptResult{M1, M2, S1 <: AbstractResult, S2} <: AbstractResult
326+
struct BayesOptResult{M1,M2,S1<:AbstractResult,S2} <: AbstractResult
289327
minimizer::M1
290328
minimum::M2
291329
niters::Int
@@ -308,8 +346,12 @@ Returns an iterator over `N` elements of a Sobol sequence between `lowerbounds`
308346
and `upperbounds`. The first `N` elements of the Sobol sequence are skipped for
309347
better uniformity (see https://github.com/stevengj/Sobol.jl)
310348
"""
311-
function ScaledSobolIterator(lowerbounds, upperbounds, N;
312-
seq = SobolSeq(length(lowerbounds)))
349+
function ScaledSobolIterator(
350+
lowerbounds,
351+
upperbounds,
352+
N;
353+
seq = SobolSeq(length(lowerbounds)),
354+
)
313355
N > 0 && skip(seq, N)
314356
ScaledSobolIterator(lowerbounds, upperbounds, N, seq)
315357
end
@@ -389,33 +431,27 @@ function optimize!(workspace::BayesOptWorkspace)
389431
s.mode = :interval
390432
end
391433
end
392-
return BayesOptResult(
393-
minimizer, minval, iter, r, surrogates,
394-
)
434+
return BayesOptResult(minimizer, minval, iter, r, surrogates)
395435
end
396436

397437
struct BayesOptAlg{A} <: AbstractOptimizer
398438
sub_alg::A
399439
end
400440

401441
function Workspace(
402-
model::VecModel, optimizer::BayesOptAlg, x0::AbstractVector;
403-
options::BayesOptOptions, surrogates = nothing, kwargs...,
442+
model::VecModel,
443+
optimizer::BayesOptAlg,
444+
x0::AbstractVector;
445+
options::BayesOptOptions,
446+
surrogates = nothing,
447+
kwargs...,
404448
)
405449
if surrogates !== nothing
406450
smodel = model
407451
else
408452
smodel, surrogates = surrogate_model(model; options.nt...)
409453
end
410-
sub_workspace = Workspace(
411-
smodel, optimizer.sub_alg, x0;
412-
options = options.sub_options, kwargs...,
413-
)
414-
return BayesOptWorkspace(
415-
model,
416-
sub_workspace,
417-
x0,
418-
options,
419-
surrogates,
420-
)
454+
sub_workspace =
455+
Workspace(smodel, optimizer.sub_alg, x0; options = options.sub_options, kwargs...)
456+
return BayesOptWorkspace(model, sub_workspace, x0, options, surrogates)
421457
end

0 commit comments

Comments
 (0)