-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpca.ml
More file actions
333 lines (287 loc) · 8.68 KB
/
pca.ml
File metadata and controls
333 lines (287 loc) · 8.68 KB
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
(*
* Copyright (c) 2005, 2006, 2007 Abram Hindle
*
* This file is part of CaptchaBreaker
* CaptchaBreaker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
* Foobar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*)
open Gsl_linalg;;
open Gsl_stats;;
open Gsl_matrix;;
open Gsl_blas;;
open Gsl_vector;;
open Abez;;
let status x = ();;
(* prerr_endline ("[PCA] "^x)
;; *)
let si = string_of_int ;;
let sf = string_of_float ;;
(*
Gsl_linalg
val invert_LU : ?protect:bool ->
?result:Gsl_vectmat.mat ->
[< `A of float array * int * int
| `AA of float array array
| `M of Gsl_matrix.matrix
| `MF of Gsl_matrix_flat.matrix ] ->
Gsl_vectmat.mat
Gsl_stats
val covariance : float array -> float array -> float
*)
let dims matrix =
let (rows,cols) = Gsl_matrix.dims matrix in
(rows,cols)
;;
let matrix_get matrix row col =
Gsl_matrix.get matrix row col
;;
let matrix_set matrix row col v =
Gsl_matrix.set matrix row col v
;;
let print_matrix matrix =
let (rows,cols) = dims matrix in
for i = 0 to (rows - 1) do
for j = 0 to (cols - 1) do
print_float (matrix_get matrix i j);
print_string "\t";
done;
print_endline "";
done;
;;
let print_vector matrix =
let rows = Gsl_vector.length matrix in
for i = 0 to (rows - 1) do
print_float (Gsl_vector.get matrix i);
print_endline "";
done;
;;
let print_array array =
let l = Array.length array in
for i = 0 to (l - 1) do
print_float array.(i);
print_string "\t";
done;
print_endline "";
;;
let get_column_inplace arr matrix col =
let (rows,cols) = dims matrix in
for i = 0 to rows - 1 do
arr.(i) <- matrix_get matrix i col;
done;
arr
;;
let create_matrix rows cols =
Gsl_matrix.create rows cols
;;
let get_column matrix col =
let (rows,cols) = dims matrix in
let arr = Array.create rows 0. in
get_column_inplace arr matrix col
;;
let covariance_matrix_in_place cov_matrix matrix =
let (rows,cols) = dims matrix in
let cov_matrix = create_matrix cols cols in
for i = 0 to cols - 1 do
let icol = get_column matrix i in
for j = 0 to cols - 1 do
matrix_set cov_matrix i j (Gsl_stats.covariance icol (get_column matrix j));
done;
done;
cov_matrix
;;
let covariance_matrix matrix =
let (rows,cols) = dims matrix in
let cov_matrix = create_matrix cols cols in
covariance_matrix_in_place cov_matrix matrix
;;
let eigen_vector_values matrix =
Gsl_eigen.symmv (`M(matrix))
;;
let eigen_sort (v,m) =
Gsl_eigen.symmv_sort (v,m) Gsl_eigen.VAL_DESC;
(v,m)
;;
let mean_of_column matrix col =
let (rows,cols) = dims matrix in
let sum = ref 0. in
for i = 0 to (rows - 1) do
sum := !sum +. (matrix_get matrix i col);
done;
(!sum) /. (float_of_int rows)
;;
let apply_column matrix f col =
let (rows,cols) = dims matrix in
for i = 0 to (rows - 1) do
matrix_set matrix i col (f (matrix_get matrix i col));
done;
()
;;
let matrix_multiply m1 m2 =
let (rows1,cols1) = dims m1 in
let (rows2,cols2) = dims m2 in
let c = create_matrix rows1 cols2 in
let _ = Gsl_blas.gemm ~ta:Gsl_blas.NoTrans ~tb:Gsl_blas.NoTrans ~alpha:1.0 ~a:m1 ~b:m2 ~beta:0.0 ~c:c in
c
;;
let transpose_matrix matrix =
let (rows,cols) = dims matrix in
let m = create_matrix cols rows in
Gsl_matrix.transpose m matrix;
m
;;
let vector_set = Gsl_vector.set ;;
let vector_get = Gsl_vector.get ;;
let avg_matrix inmat =
let outmat = Gsl_matrix.copy inmat in
let (rows,cols) = dims outmat in
let avg_vector = Gsl_vector.create cols in (*dims*)
let (rows,cols) = dims inmat in
status "Calc avg cols";
for i = 0 to (cols - 1) do
let avg = ref 0. in
for j = 0 to (rows - 1) do
avg := !avg +. (matrix_get inmat j i);
done;
avg := !avg /. (float_of_int rows) ;
vector_set avg_vector i !avg;
done;
status "Set matrix";
for j = 0 to (rows - 1) do
for i = 0 to (cols - 1) do
let rowavg = vector_get avg_vector i in
matrix_set outmat j i ((matrix_get inmat j i) -. rowavg);
done;
done;
(outmat,avg_vector)
;;
let pca matrix =
(* subtract the mean *)
let (rows,cols) = dims matrix in
status ("PCA on matrix of rows: "^(si rows)^" cols: "^(si cols));
let (adjmatrix,avg_vector) = avg_matrix matrix in
(* print_endline "Adj Matrix";
print_matrix adjmatrix; *)
(* for i = 0 to (cols - 1) do
let mean = mean_of_column adjmatrix i in
apply_column adjmatrix (fun x -> x -. mean) i;
done; *)
status "Covariance Matrix";
let cv = covariance_matrix adjmatrix in
let (values,vectors) = eigen_vector_values cv in
let (values,vectors) = eigen_sort (values,vectors) in
let rowvectors = transpose_matrix vectors in
let rowmatrix = transpose_matrix adjmatrix in
let multi = matrix_multiply rowvectors rowmatrix in
(* WHAT ARE WE RETURNING? *)
(multi,values,vectors,avg_vector)
;;
(*
let project_to_space eigenvectors avgvector image =
flatten image into vector
img' = subtract avg image
make img'' (M elements) dot img' against each row of eigenmatrix
let norm = root sum_i=1..M img''[i] x img''[i]
divide img'' by norm
Identify(Image): Image is $W\times H$ pixels in size.
1. Load the saved known projected faces from the database.
2. proj = Project to Face Space(Image)
3. Take the dot product of proj against each known projected face. Call this the score.
4. The known projected face that gets the highest score is considered the identity of the test image.
*)
let convert_to_vector l =
let n = List.length l in
let v = Gsl_vector.create n in
let l' = ref l in
for i = 0 to (n-1) do
let (x::xs) = !l' in
l' := xs;
vector_set v i x
done;
v
;;
(* image is grayscale array *)
let project_to_space ev avgvector image =
(* flattened image *)
let (m,n) = dims ev in
status ("DIMS ROWS:"^(si m)^" Cols:"^(si n));
let img' = Gsl_vector.of_array image in
status ("img' length"^(si (Gsl_vector.length img')));
status ("avgvector length"^(si (Gsl_vector.length avgvector)));
Gsl_vector.sub img' avgvector;
let img'' = Gsl_vector.create (Gsl_vector.length img') in (* m or n ?????? *)
status "Projection dot product?";
for i = 0 to (m-1) do
let row = Gsl_matrix.row ev i in
let dot = Gsl_blas.dot img' row in
Gsl_vector.set img'' i dot;
done;
status "Normalize";
let norm = Gsl_blas.nrm2 img'' in
Gsl_blas.scal norm img'';
img''
;;
let vector_create = Gsl_vector.create ;;
let vector_length = Gsl_vector.length ;;
let get_column_vector_inplace matrix col outvector =
let n = vector_length outvector in
for i = 0 to ( n - 1 ) do
vector_set outvector i (matrix_get matrix i col);
done;
outvector
;;
let identify ev av projs image =
status "Project to space!";
let proj = project_to_space ev av image in
let (n,n') = dims projs in
status ("Rows of projs "^(string_of_int n));
status ("Cols of projs "^(string_of_int n'));
let outvector = vector_create n in
let f i (a,b,c) =
status "GET COLUMN";
let row = get_column_vector_inplace projs i outvector in
let dot = Gsl_blas.dot proj row in
let (v,d,j) = (a,b,c) in
if (dot > d) then (row,dot,i) else (v,d,j)
in
let m = ref ((Gsl_vector.create 1),0.,0) in
status "Row dot proj";
for i = 0 to (n'-1) do
m := f i !m
done;
let (a,b,c) = !m in
(a,b,proj,c)
;;
let pca_test () =
let x = [| 2.5 ; 0.5 ; 2.2 ; 1.9 ; 3.1 ; 2.3 ; 2. ; 1. ; 1.5 ; 1.1 |] in
let y = [| 2.4 ; 0.7 ; 2.9 ; 2.2 ; 3.0 ; 2.7 ; 1.6 ; 1.1; 1.6 ; 0.9 |] in
status "Matrix create";
let matrix = create_matrix (Array.length x) 2 in
status "Matrix set";
for i = 0 to ((Array.length x) - 1) do
matrix_set matrix i 0 (x.(i));
matrix_set matrix i 1 (y.(i));
done;
status "PCA";
let (finaldata,eigenvalues,eigenvectors,meanmatrix) = pca matrix in
print_endline "Init Data";
print_matrix matrix;
print_endline "Mean Data";
(* print_matrix meanmatrix; *)
print_vector meanmatrix;
print_endline "Eigenvalues";
print_vector eigenvalues;
print_endline "Eigenvectors";
print_matrix eigenvectors;
print_endline "Final Data";
print_matrix finaldata;
()
;;
(* pca_test();; *)