Gradient Enhanced Kriging Surrogate Tutorial
Gradient-enhanced Kriging is an extension of kriging which supports gradient information. GEK is usually more accurate than kriging. However, it is not computationally efficient when the number of inputs, the number of sampling points, or both, are high. This is mainly due to the size of the corresponding correlation matrix, which increases proportionally with both the number of inputs and the number of sampling points.
Let's have a look at the following function to use Gradient Enhanced Surrogate: $f(x) = x^3 - 6x^2 + 4x + 12$
First of all, we will import Surrogates and Plots packages:
using Surrogates
using PlotsSampling
We choose to sample f in 100 points between 2 and 10 using the sample function. The sampling points are chosen using a Sobol sequence, this can be done by passing SobolSample() to the sample function.
n_samples = 100
lower_bound = 2
upper_bound = 10
xs = lower_bound:0.001:upper_bound
x = sample(n_samples, lower_bound, upper_bound, SobolSample())
f(x) = x^3 - 6x^2 + 4x + 12
y1 = f.(x)
der = x -> 3 * x^2 - 12 * x + 4
y2 = der.(x)
y = vcat(y1, y2)
scatter(x, y1, label = "Sampled points", xlims = (lower_bound, upper_bound), legend = :top)
plot!(f, label = "True function", xlims = (lower_bound, upper_bound), legend = :top)Building a surrogate
With our sampled points, we can build the Gradient Enhanced Kriging surrogate using the GEK function.
my_gek = GEK(x, y, lower_bound, upper_bound, p = 0.03, theta = 0.3)
scatter(x, y1, label = "Sampled points", xlims = (lower_bound, upper_bound), legend = :top)
plot!(f, label = "True function", xlims = (lower_bound, upper_bound), legend = :top)
plot!(my_gek, label = "Surrogate function", ribbon = p -> std_error_at_point(my_gek, p),
xlims = (lower_bound, upper_bound), legend = :top)Gradient Enhanced Kriging Surrogate Tutorial (ND)
First of all, let's define the function we are going to build a surrogate for.
using Plots
using SurrogatesNow, let's define the function:
function leon(x)
x1 = x[1]
x2 = x[2]
term1 = (x2 - x1^3)^2
term2 = (1 - x1)^2
y = term1 + term2
endleon (generic function with 1 method)Sampling
Let's define our bounds, this time we are working in two dimensions. In particular, we want our first dimension x to have bounds 0, 1, and 0, 1 for the second dimension. We are taking 100 samples of the space using Sobol Sequences. We then evaluate our function on all the sampling points.
n_samples = 100
lower_bound = [0, 0]
upper_bound = [1, 1]
xys = sample(n_samples, lower_bound, upper_bound, SobolSample())
y1 = leon.(xys)100-element Vector{Float64}:
1.1124164985287734
0.7971708308525649
0.15007553258897133
0.9222684086473691
0.36346270954368265
0.05102696733797529
0.12359681268412714
1.3183157051082617
0.6632428030300161
0.20718450295885305
⋮
0.7813352313541237
0.5076610619732129
0.05600952949467697
0.25017019456678113
1.6610263616386511
0.890628840729395
0.3485896751477675
0.08169559776627366
1.097441250041019x, y = 0:1, 0:1
p1 = surface(x, y, (x1, x2) -> leon((x1, x2)))
xs = [xy[1] for xy in xys]
ys = [xy[2] for xy in xys]
scatter!(xs, ys, y1)
p2 = contour(x, y, (x1, x2) -> leon((x1, x2)))
scatter!(xs, ys)
plot(p1, p2, title = "True function")Building a surrogate
Using the sampled points, we build the surrogate, the steps are analogous to the 1-dimensional case.
grad1 = x -> 2 * (x[2] - x[1]^3) * (-3x[1]^2) - 2 * (1 - x[1])
grad2 = x -> 2 * (x[2] - x[1]^3)
d = 2
n = 100
function create_grads(n, d, grad1, grad2, y1)
c = 0
y2 = zeros(eltype(y1[1]), n * d)
for i in 1:n
y2[i + c] = grad1(xys[i])
y2[i + c + 1] = grad2(xys[i])
c = c + 1
end
return y2
end
y2 = create_grads(n, d, grad1, grad2, y1)
y = vcat(y1, y2)300-element Vector{Float64}:
1.1124164985287734
0.7971708308525649
0.15007553258897133
0.9222684086473691
0.36346270954368265
0.05102696733797529
0.12359681268412714
1.3183157051082617
0.6632428030300161
0.20718450295885305
⋮
1.726403832435608
-1.8841762827123603
0.1324101686477661
-1.6169057588904252
0.7842198610305786
0.44991703246523684
-0.42454326152801514
-1.832499806454507
1.5740376710891724my_GEK = GEK(xys, y, lower_bound, upper_bound)(::GEK{Vector{Tuple{Float64, Float64}}, Vector{Float64}, Vector{Int64}, Vector{Int64}, Vector{Float64}, Vector{Float64}, Float64, Vector{Float64}, Float64, Matrix{Float64}}) (generic function with 2 methods)p1 = surface(x, y, (x, y) -> my_GEK([x y]))
scatter!(xs, ys, y1, marker_z = y1)
p2 = contour(x, y, (x, y) -> my_GEK([x y]))
scatter!(xs, ys, marker_z = y1)
plot(p1, p2, title = "Surrogate")