File: linear_utils.ml

package info (click to toggle)
pplacer 1.1~alpha19-8
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 17,324 kB
  • sloc: ml: 20,927; ansic: 9,002; python: 1,641; makefile: 171; sh: 77; xml: 50
file content (224 lines) | stat: -rw-r--r-- 5,284 bytes parent folder | download | duplicates (2)
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
(* Some nicer ways to make and use Gsl.Vectors and Gsl.Matrices.
 *
 * look at
 http://www.gnu.org/software/gsl/manual/html_node/GSL-BLAS-Interface.html
 and
 http://oandrieu.nerim.net/ocaml/gsl/doc/Gsl.Blas.html
 *
 * Reminder: the Gsl.Matrix is made with c_layout.
 *)

let tolerance = 1e-12

open Bigarray
open Ppatteries


(* *** Vector operations *** *)

let vec_init n f =
  let v = Gsl.Vector.create n in
  for i=0 to n-1 do Array1.unsafe_set v i (f i) done;
  v

let vec_fold_left f start v =
  let x = ref start
  and n = Gsl.Vector.length v in
  for i=0 to n-1 do
    x := f !x (Array1.unsafe_get v i)
  done;
  !x

let vec_map f v =
  vec_init (Gsl.Vector.length v) (fun i -> f (Array1.unsafe_get v i))

let vec_iter f a =
  let n = Gsl.Vector.length a in
  for i=0 to n-1 do
    f (Array1.unsafe_get a i)
  done

let vec_iteri f a =
  let n = Gsl.Vector.length a in
  for i=0 to n-1 do
    f i (Array1.unsafe_get a i)
  done

let vec_iter2 f a b =
  let n = Gsl.Vector.length a in
  assert(n = Gsl.Vector.length b);
  for i=0 to n-1 do
    f (Array1.unsafe_get a i) (Array1.unsafe_get b i)
  done

let vec_map2_into f ~dst a b =
  let n = Gsl.Vector.length dst in
  assert(n = Gsl.Vector.length a);
  assert(n = Gsl.Vector.length b);
  for i=0 to n-1 do
    Array1.unsafe_set dst i
      (f (Array1.unsafe_get a i) (Array1.unsafe_get b i))
  done

(* If all of the entries of v satisfy pred. *)
let vec_predicate pred v =
  vec_fold_left (fun so_far x -> so_far && pred x) true v

(* Maximum element after applying f. *)
let vec_fmax_index f v =
  assert(0 <> Gsl.Vector.length v);
  let max_val = ref (f v.{0})
  and max_ind = ref 0
  in
  vec_iteri
    (fun i x ->
      let fx = f x in
      if fx > !max_val then begin
        max_val := fx;
        max_ind := i;
      end)
    v;
  !max_ind

(* norms and normalizing *)
let lp_norm p v =
  assert(p > 0.);
  let x = ref 0. in
  for i=0 to (Gsl.Vector.length v)-1 do
    x := !x +. (v.{i} ** p)
  done;
  !x ** (1. /. p)

let l1_norm v = lp_norm 1. v
let l2_norm v = lp_norm 2. v

(* normalize in place *)
let gen_normalize norm_fun v =
  Gsl.Vector.scale v (1. /. (norm_fun v))
let l1_normalize v = gen_normalize l1_norm v
let l2_normalize v = gen_normalize l2_norm v

let alloc_gen_normalize norm_fun v =
  let normed = Gsl.Vector.copy v in
  Gsl.Vector.scale normed (1. /. (norm_fun normed));
  normed
let alloc_l1_normalize v = alloc_gen_normalize l1_norm v
let alloc_l2_normalize v = alloc_gen_normalize l2_norm v


(* *** Matrix operations *** *)

let mat_init n_rows n_cols f =
  let m = Gsl.Matrix.create n_rows n_cols in
  for i=0 to n_rows-1 do
    let row = Array2.slice_left m i in
    for j=0 to n_cols-1 do
      Array1.unsafe_set row j (f i j)
    done;
  done;
  m

let mat_map f m =
  let (rows, cols) = Gsl.Matrix.dims m in
  mat_init rows cols (fun i j -> f m.{i,j})

let diag v =
  let n = Gsl.Vector.length v in
  let m = Gsl.Matrix.create ~init:0. n n in
  for i=0 to n-1 do
    m.{i,i} <- v.{i}
  done;
  m

(* information about vectors and matrices *)
let assert_symmetric m =
  let n, cols = Gsl.Matrix.dims m in
  assert(n = cols);
  for i=0 to n-1 do
    for j=i to n-1 do
      if (abs_float(m.{i,j} -. m.{j,i}) > tolerance) then
        failwith (
          Printf.sprintf
            "matrix not symmetric: %f vs %f" m.{i,j} m.{j,i})
    done
  done

let alloc_transpose m =
  let mt = Gsl.Matrix.copy m in
  Gsl.Matrix.transpose_in_place mt;
  mt

let mat_dim_asserting_square m =
  let n = Array2.dim1 m in
  assert(n = Array2.dim2 m);
  n

let qform m v =
  let n = Gsl.Vector.length v in
  assert(n = Array2.dim1 m && n = Array2.dim2 m);
  let x = ref 0. in
  for i=0 to n-1 do
    let vi = Array1.unsafe_get v i
    and mi = Array2.slice_left m i
    in
    for j=0 to n-1 do
      x := (!x) +. vi *. (Array1.unsafe_get v j) *. (Array1.unsafe_get mi j)
    done;
  done;
  !x

let trace m =
  let n = Array2.dim1 m in
  assert(n = (Array2.dim2 m));
  let x = ref 0. in
  for i=0 to n-1 do
      x := (!x) +. (Array2.unsafe_get m i i)
  done;
  !x

let mat_vec_mul dest a v =
  Gsl.Blas.gemv
    Gsl.Blas.NoTrans ~alpha:1.
    ~a:a ~x:v ~beta:0. ~y:dest

let alloc_mat_vec_mul a v =
  let (rows, midA) = Gsl.Matrix.dims a
  and midV = Gsl.Vector.length v in
  assert(midA = midV);
  let w = Gsl.Vector.create rows in
  mat_vec_mul w a v;
  w

let mat_mat_mul dest a b =
  Gsl.Blas.gemm
    ~ta:Gsl.Blas.NoTrans ~tb:Gsl.Blas.NoTrans
    ~alpha:1. ~a:a ~b:b ~beta:0. ~c:dest

let alloc_mat_mat_mul a b =
  let (rows, midA) = Gsl.Matrix.dims a
  and (midB, cols) = Gsl.Matrix.dims b in
  assert(midA = midB);
  let m = Gsl.Matrix.create rows cols in
  mat_mat_mul m a b;
  m

(* gives a matrix such that the columns are the eigenvectors. *)
let symm_eigs m =
  assert_symmetric m;
  Gsl.Eigen.symmv (`M(m))

(* pretty printers *)
let ppr_gsl_vector ff y =
  Legacy.Format.fprintf ff "@[{";
  Ppr.ppr_list_inners Legacy.Format.pp_print_float ff (
    Array.to_list (Gsl.Vector.to_array y));
  Legacy.Format.fprintf ff "}@]"

let ppr_gsl_matrix ff m =
  let nrows, _ = Gsl.Matrix.dims m in
  Legacy.Format.fprintf ff "@[{";
  for i=0 to nrows-1 do
    ppr_gsl_vector ff (Gsl.Matrix.row m i);
    if i < nrows-1 then Legacy.Format.fprintf ff ";@ "
  done;
  Legacy.Format.fprintf ff "}@]"