Source file cov_se_iso.ml
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
open Interfaces
open Core
open Lacaml.D
module Params = struct type t = { log_ell : float; log_sf2 : float } end
type inducing_hyper = { ind : int; dim : int }
module Eval = struct
module Kernel = struct
type params = Params.t
type t = {
params : params;
inv_ell2 : float;
inv_ell2_05 : float;
log_sf2 : float;
sf2 : float;
}
let create ({ Params.log_sf2; log_ell } as params) =
let inv_ell2 = exp (-2. *. log_ell) in
let inv_ell2_05 = -0.5 *. inv_ell2 in
{ params; inv_ell2; inv_ell2_05; log_sf2; sf2 = exp log_sf2 }
let get_params k = k.params
end
open Kernel
module Inducing = struct
type t = mat
let get_n_points = Mat.dim2
let calc_sqr_diff_mat inducing =
let d = Mat.dim1 inducing in
let m = Mat.dim2 inducing in
let res = Mat.create m m in
let ssqr_diff_ref = ref 0. in
for c = 1 to m do
for r = 1 to c - 1 do
for i = 1 to d do
let diff = inducing.{i, c} -. inducing.{i, r} in
ssqr_diff_ref := !ssqr_diff_ref +. diff *. diff
done;
res.{r, c} <- !ssqr_diff_ref;
ssqr_diff_ref := 0.
done;
res.{c, c} <- 0.
done;
res
let calc_upper_with_sqr_diff_mat k sqr_diff_mat =
let m = Mat.dim2 sqr_diff_mat in
let res = Mat.create m m in
let { inv_ell2_05; log_sf2; sf2 } = k in
for c = 1 to m do
for r = 1 to c - 1 do
res.{r, c} <- exp (log_sf2 +. inv_ell2_05 *. sqr_diff_mat.{r, c});
done;
res.{c, c} <- sf2;
done;
res
let calc_upper k inducing =
calc_upper_with_sqr_diff_mat k (calc_sqr_diff_mat inducing)
end
module Input = struct
type t = vec
let eval { Kernel.inv_ell2_05; log_sf2 } input inducing =
let d = Mat.dim1 inducing in
let m = Mat.dim2 inducing in
let res = Vec.create m in
let ssqr_diff_ref = ref 0. in
for c = 1 to m do
for i = 1 to d do
let diff = input.{i} -. inducing.{i, c} in
ssqr_diff_ref := !ssqr_diff_ref +. diff *. diff
done;
res.{c} <- exp (log_sf2 +. inv_ell2_05 *. !ssqr_diff_ref);
ssqr_diff_ref := 0.;
done;
res
let weighted_eval k input inducing ~coeffs =
dot coeffs (eval k input inducing)
let eval_one k _input = k.Kernel.sf2
end
module Inputs = struct
type t = mat
let create = Mat.of_col_vecs
let get_n_points = Mat.dim2
let choose_subset inputs indexes = Utils.choose_cols inputs indexes
let create_inducing _kernel inputs = inputs
let create_default_kernel_params _inputs ~n_inducing:_ =
{ Params.log_ell = 0.; log_sf2 = 0. }
let calc_upper k inputs = Inducing.calc_upper k inputs
let calc_diag k inputs = Vec.make (Mat.dim2 inputs) k.Kernel.sf2
let calc_sqr_diff_mat ~inputs ~inducing =
let d = Mat.dim1 inducing in
let m = Mat.dim2 inducing in
let n = Mat.dim2 inputs in
let res = Mat.create n m in
let ssqr_diff_ref = ref 0. in
for c = 1 to m do
for r = 1 to n do
for i = 1 to d do
let diff = inputs.{i, r} -. inducing.{i, c} in
ssqr_diff_ref := !ssqr_diff_ref +. diff *. diff
done;
res.{r, c} <- !ssqr_diff_ref;
ssqr_diff_ref := 0.
done
done;
res
let calc_cross_with_sqr_diff_mat k sqr_diff_mat =
let { Kernel.inv_ell2_05; log_sf2 } = k in
let n = Mat.dim1 sqr_diff_mat in
let m = Mat.dim2 sqr_diff_mat in
let res = Mat.create n m in
for c = 1 to m do
for r = 1 to n do
res.{r, c} <- exp (log_sf2 +. inv_ell2_05 *. sqr_diff_mat.{r, c})
done
done;
res
let calc_cross k ~inputs ~inducing =
calc_cross_with_sqr_diff_mat k (calc_sqr_diff_mat ~inputs ~inducing)
let weighted_eval k ~inputs ~inducing ~coeffs =
let sqr_diff_mat = calc_sqr_diff_mat ~inputs ~inducing in
let n = Mat.dim1 sqr_diff_mat in
let m = Mat.dim2 sqr_diff_mat in
if Vec.dim coeffs <> m then
failwith "Gpr.Cov_se_iso.Eval.Inputs.weighted_eval: dim(coeffs) <> m";
let { Kernel.inv_ell2_05; log_sf2 } = k in
let rec loop r acc c =
if c = 0 then acc
else
let el =
coeffs.{c} *. exp (log_sf2 +. inv_ell2_05 *. sqr_diff_mat.{r, c})
in
loop r (acc +. el) (c - 1)
in
Vec.init n (fun r -> loop r 0. m)
end
end
module Deriv = struct
module Eval = Eval
type gen_deriv = [ `Log_ell | `Log_sf2 ]
module Hyper = struct
type t = [ gen_deriv | `Inducing_hyper of inducing_hyper ]
let get_all _kernel inducing _inputs =
let d = Mat.dim1 inducing in
let m = Mat.dim2 inducing in
let n_inducing_hypers = d * m in
let n_all_hypers = 2 + n_inducing_hypers in
let hypers = Array.create ~len:n_all_hypers `Log_ell in
hypers.(1) <- `Log_sf2 ;
for ind = 1 to m do
let indd = (ind - 1) * d in
for dim = 1 to d do
let inducing_hyper = { ind; dim } in
hypers.(1 + indd + dim) <- `Inducing_hyper inducing_hyper
done
done;
hypers
let get_value { Eval.Kernel.params } inducing _inputs = function
| `Log_ell -> params.Params.log_ell
| `Log_sf2 -> params.Params.log_sf2
| `Inducing_hyper { ind; dim } -> inducing.{dim, ind}
let set_values { Eval.Kernel.params } inducing inputs hypers values =
let { Params.log_ell; log_sf2 } = params in
let log_ell_ref = ref log_ell in
let log_sf2_ref = ref log_sf2 in
let inducing_lazy = lazy (lacpy inducing) in
for i = 1 to Array.length hypers do
match hypers.(i - 1) with
| `Log_ell -> log_ell_ref := values.{i}
| `Log_sf2 -> log_sf2_ref := values.{i}
| `Inducing_hyper { ind; dim } ->
(Lazy.force inducing_lazy).{dim, ind} <- values.{i}
done;
let new_kernel =
let log_ell = !log_ell_ref in
Eval.Kernel.create { Params.log_ell; log_sf2 = !log_sf2_ref }
in
let lift lazy_value value =
if Lazy.is_val lazy_value then Lazy.force lazy_value
else value
in
let new_inducing = lift inducing_lazy inducing in
new_kernel, new_inducing, inputs
end
type deriv_common = {
kernel : Eval.Kernel.t;
sqr_diff_mat : mat;
eval_mat : mat;
}
module Inducing = struct
type upper = Eval.Inducing.t * deriv_common
let calc_shared_upper kernel eval_inducing =
let module EI = Eval.Inducing in
let sqr_diff_mat = EI.calc_sqr_diff_mat eval_inducing in
let eval_mat = EI.calc_upper_with_sqr_diff_mat kernel sqr_diff_mat in
eval_mat, (eval_inducing, { kernel; sqr_diff_mat; eval_mat })
let calc_deriv_upper (inducing, common) = function
| `Log_sf2 -> `Factor 1.
| `Log_ell ->
let { sqr_diff_mat; eval_mat; kernel } = common in
let m = Mat.dim1 sqr_diff_mat in
let res = Mat.create m m in
let { Eval.Kernel.inv_ell2 } = kernel in
for c = 1 to m do
for r = 1 to c - 1 do
res.{r, c} <- eval_mat.{r, c} *. sqr_diff_mat.{r, c} *. inv_ell2
done;
res.{c, c} <- 0.;
done;
`Dense res
| `Inducing_hyper { ind; dim } ->
let eval_mat = common.eval_mat in
let m = Mat.dim2 eval_mat in
let res = Mat.create 1 m in
let inducing_dim = inducing.{dim, ind} in
let inv_ell2 = common.kernel.Eval.Kernel.inv_ell2 in
for i = 1 to ind - 1 do
let ind_d = inducing.{dim, i} in
res.{1, i} <-
inv_ell2 *. (ind_d -. inducing_dim) *. eval_mat.{i, ind}
done;
res.{1, ind} <- 0.;
for i = ind + 1 to m do
let ind_d = inducing.{dim, i} in
res.{1, i} <-
inv_ell2 *. (ind_d -. inducing_dim) *. eval_mat.{ind, i}
done;
let rows = Sparse_indices.create 1 in
rows.{1} <- ind;
`Sparse_rows (res, rows)
end
module Inputs = struct
type diag = Eval.Kernel.t
type cross = Eval.Inputs.t * Eval.Inducing.t * deriv_common
let calc_shared_diag k diag_eval_inputs =
Eval.Inputs.calc_diag k diag_eval_inputs, k
let calc_shared_cross kernel ~inputs ~inducing =
let module EI = Eval.Inputs in
let sqr_diff_mat = EI.calc_sqr_diff_mat ~inputs ~inducing in
let eval_mat = EI.calc_cross_with_sqr_diff_mat kernel sqr_diff_mat in
let shared = inputs, inducing, { kernel; sqr_diff_mat; eval_mat } in
eval_mat, shared
let calc_deriv_diag _diag = function
| `Log_sf2 -> `Factor 1.
| `Log_ell | `Inducing_hyper _ -> `Const 0.
let calc_deriv_cross (inputs, inducing, common) = function
| `Log_sf2 -> `Factor 1.
| `Log_ell ->
let { sqr_diff_mat; eval_mat; kernel } = common in
let n = Mat.dim1 sqr_diff_mat in
let m = Mat.dim2 sqr_diff_mat in
let res = Mat.create n m in
let { Eval.Kernel.inv_ell2 } = kernel in
for c = 1 to m do
for r = 1 to n do
res.{r, c} <- eval_mat.{r, c} *. sqr_diff_mat.{r, c} *. inv_ell2
done
done;
`Dense res
| `Inducing_hyper { ind; dim } ->
let eval_mat = common.eval_mat in
let n = Mat.dim1 eval_mat in
let res = Mat.create n 1 in
let indx_d = inducing.{dim, ind} in
let inv_ell2 = common.kernel.Eval.Kernel.inv_ell2 in
for r = 1 to n do
let inp_d = inputs.{dim, r} in
res.{r, 1} <- inv_ell2 *. (inp_d -. indx_d) *. eval_mat.{r, ind}
done;
let cols = Sparse_indices.create 1 in
cols.{1} <- ind;
`Sparse_cols (res, cols)
end
end