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
open Core
module Unix = Core_unix
open Bigarray
open Lacaml.D
module Int_vec = struct
type t = (int, int_elt, fortran_layout) Array1.t
let create n : t = Array1.create int fortran_layout n
let dim (t : t) = Array1.dim t
let sub (t : t) n = Array1.sub t n
end
let debug = ref false
let cholesky_jitter = ref 1e-6
type fast_float_ref = { mutable x : float }
let pi = 4. *. Float.atan 1.
let log_2pi = log (pi +. pi)
let default_rng = Gsl.Rng.make (Gsl.Rng.default ())
let print_int name n = Format.printf "%s: @[%d@]@.@." name n
let print_float name n = Format.printf "%s: @[%.9f@]@.@." name n
let print_vec name vec = Format.printf "%s: @[%a@]@.@." name pp_vec vec
let print_mat name mat = Format.printf "%s: @[%a@]@.@." name pp_mat mat
let timing name f =
let t1 = Unix.times () in
let res = f () in
let t2 = Unix.times () in
Format.printf "%s %.2f@." name (t2.Unix.tms_utime -. t1.Unix.tms_utime);
res
let choose_cols mat indexes =
let m = Mat.dim1 mat in
let n = Mat.dim2 mat in
let k = Int_vec.dim indexes in
let res = Mat.create m k in
for c = 1 to k do
let real_c = indexes.{c} in
if real_c < 1 || real_c > n then
failwithf "Gpr.Utils.choose_cols: violating 1 <= index (%d) <= dim (%d)"
real_c n ()
else
for r = 1 to m do
res.{r, c} <- mat.{r, real_c}
done
done;
res
let sum_mat mat = Vec.sum (Mat.as_vec mat)
let sum_symm_mat mat =
let diag_ref = ref 0. in
let rest_ref = ref 0. in
let n = Mat.dim1 mat in
for c = 1 to n do
for r = 1 to c - 1 do
rest_ref := !rest_ref +. mat.{r, c}
done;
diag_ref := !diag_ref +. mat.{c, c}
done;
let rest = !rest_ref in
rest +. !diag_ref +. rest
let log_det mat =
let n = Mat.dim1 mat in
if Mat.dim2 mat <> n then failwith "log_det: not a square matrix";
let rec loop acc i =
if i = 0 then acc +. acc else loop (acc +. log mat.{i, i}) (i - 1)
in
loop 0. n
let solve_tri ?trans chol mat =
let ichol_mat = lacpy mat in
trtrs ?trans chol ichol_mat;
ichol_mat
let ichol chol =
let inv = lacpy ~uplo:`U chol in
potri inv;
inv
let check_sparse_row_mat_sane ~real_m ~smat ~rows =
if !debug then (
if real_m < 0 then
failwith "Gpr.Utils.check_sparse_row_mat_sane: real_m < 0";
let m = Mat.dim1 smat in
let n_rows = Int_vec.dim rows in
if n_rows <> m then
failwithf
"Gpr.Utils.check_sparse_row_mat_sane: number of rows in sparse matrix \
(%d) disagrees with size of row array (%d)"
m n_rows ();
let rec loop ~i ~limit =
if i > 0 then
let rows_i = rows.{i} in
if rows_i <= 0 then
failwithf
"Gpr.Utils.check_sparse_row_mat_sane: sparse row %d contains \
illegal negative real row index %d"
i rows_i ()
else if rows_i > limit then
failwithf
"Gpr.Utils.check_sparse_row_mat_sane: sparse row %d associated \
with real row index %d violates consistency (current row limit: \
%d)"
i rows_i limit ()
else loop ~i:(i - 1) ~limit:rows_i
in
loop ~i:n_rows ~limit:real_m)
let check_sparse_col_mat_sane ~real_n ~smat ~cols =
if !debug then (
if real_n < 0 then
failwith "Gpr.Utils.check_sparse_col_mat_sane: real_n < 0";
let n = Mat.dim2 smat in
let n_cols = Int_vec.dim cols in
if n_cols <> n then
failwithf
"Gpr.Utils.check_sparse_col_mat_sane: number of cols in sparse matrix \
(%d) disagrees with size of col array (%d)"
n n_cols ();
let rec loop ~i ~limit =
if i > 0 then
let cols_i = cols.{i} in
if cols_i <= 0 then
failwithf
"Gpr.Utils.check_sparse_col_mat_sane: sparse col %d contains \
illegal negative real col index %d"
i cols_i ()
else if cols_i > limit then
failwithf
"Gpr.Utils.check_sparse_col_mat_sane: sparse col %d associated \
with real col index %d violates consistency (current col limit: \
%d)"
i cols_i limit ()
else loop ~i:(i - 1) ~limit:cols_i
in
loop ~i:n_cols ~limit:real_n)
let check_sparse_vec_sane ~real_n ~svec ~rows =
if !debug then (
let k = Vec.dim svec in
if Int_vec.dim rows <> k then
failwith
"Gpr.Utils.check_sparse_vec_sane: size of sparse vector disagrees with \
indexes";
let rec loop ~last i =
if i > 0 then
let ind = rows.{i} in
if ind >= last || ind <= 0 then
failwith "Gpr.Utils.check_sparse_vec_sane: rows inconsistent"
else loop ~last:ind (i - 1)
in
loop ~last:real_n (Int_vec.dim rows))
let symm2_sparse_trace ~mat ~smat ~rows =
let m = Int_vec.dim rows in
let n = Mat.dim2 smat in
let full_ref = ref 0. in
let half_ref = ref 0. in
let rows_ix_ref = ref 1 in
for sparse_r = 1 to m do
let c = rows.{sparse_r} in
for r = 1 to n do
let mat_el = if r > c then mat.{c, r} else mat.{r, c} in
let rows_ix = !rows_ix_ref in
if
rows_ix > m
||
let rows_el = rows.{rows_ix} in
r < rows_el || c < rows_el
then full_ref := !full_ref +. (mat_el *. smat.{sparse_r, r})
else (
half_ref := !half_ref +. (mat_el *. smat.{rows_ix, c});
incr rows_ix_ref)
done;
rows_ix_ref := 1
done;
let full = !full_ref in
full +. !half_ref +. full