ruby-svd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,2 @@
1
+ Public Domain
2
+
data/README ADDED
@@ -0,0 +1,6 @@
1
+ Singular Value Decomposition for Ruby with no dependency on GSL or LAPACK. Uses a C extension
2
+ to the Numerical Recipies C implementation of an SVD matrix decomposer. Also includes an
3
+ extension to the native Ruby Matrix class with a simple LSA method (decomposes the matrix,
4
+ transposes matrix V, diagonalises the S array into a matrix, then removes all but the two
5
+ leading terms in S to compress the original matrix to two dimensions).
6
+
data/ext/extconf.rb ADDED
@@ -0,0 +1,3 @@
1
+ # file: extconf.rb
2
+ require 'mkmf'
3
+ create_makefile('svd')
data/ext/nrutil.h ADDED
@@ -0,0 +1,376 @@
1
+ /* nrutil.h */
2
+ #include <stdio.h>
3
+ #include <stddef.h>
4
+ #include <stdlib.h>
5
+ #define NR_END 1
6
+ #define FREE_ARG char*
7
+
8
+
9
+ #ifndef _NR_UTILS_H_
10
+ #define _NR_UTILS_H_
11
+
12
+ static float sqrarg;
13
+ #define SQR(a) ((sqrarg = (a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
14
+
15
+ static double dsqrarg;
16
+ #define DSQR(a) ((dsqrarg = (a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg)
17
+
18
+ static double dmaxarg1, dmaxarg2;
19
+ #define DMAX(a, b) (dmaxarg1 = (a), dmaxarg2 = (b), (dmaxarg1) > (dmaxarg2) ? (dmaxarg1) : (dmaxarg2))
20
+
21
+ static double dminarg1, dminarg2;
22
+ #define DMIN(a, b) (dminarg1 = (a), dminarg2 = (b), (dminarg1) < (dminarg2) ? (dminarg1) : (dminarg2))
23
+
24
+ static float maxarg1, maxarg2;
25
+ #define FMAX(a, b) (maxarg1 = (a), maxarg2 = (b), (maxarg1) > (maxarg2) ? (maxarg1) : (maxarg2))
26
+
27
+ static float minarg1, minarg2;
28
+ #define FMIN(a, b) (minarg1 = (a), minarg2 = (b), (minarg1) < (minarg2) ? (minarg1) : (minarg2))
29
+
30
+ static long lmaxarg1, lmaxarg2;
31
+ #define LMAX(a, b) (lmaxarg1 = (a), lmaxarg2 = (b), (lmaxarg1) > (lmaxarg2) ? (lmaxarg1) : (lmaxarg2))
32
+
33
+ static long lminarg1, lminarg2;
34
+ #define LMIN(a, b) (lminarg1 = (a), lminarg2 = (b), (lminarg1) < (lminarg2) ? (lminarg1) : (lminarg2))
35
+
36
+ static int imaxarg1, imaxarg2;
37
+ #define IMAX(a, b) (imaxarg1 = (a), imaxarg2 = (b), (imaxarg1) > (imaxarg2) ? (imaxarg1) : (imaxarg2))
38
+
39
+ static int iminarg1, iminarg2;
40
+ #define IMIN(a, b) (iminarg1 = (a), iminarg2 = (b), (iminarg1) < (iminarg2) ? (iminarg1) : (iminarg2))
41
+
42
+ #define SIGN(a, b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
43
+
44
+
45
+ /* prototype declaration */
46
+
47
+ #if defined(__STDC__) || defined(ANSI) || defined(NRANSI) /* ANSI */
48
+
49
+ void nrerror(char error_test[]);
50
+ float *vector(long nl, long nh);
51
+ int *ivector(long nl, long nh);
52
+ unsigned char *cvector(long nl, long nh);
53
+ unsigned long *lvector(long nl, long nh);
54
+ double *dvector(long nl, long nh);
55
+ float **matrix(long nrl, long nrh, long ncl, long nch);
56
+ double **dmatrix(long nrl, long nrh, long ncl, long nch);
57
+ int **imatrix(long nrl, long nrh, long ncl, long nch);
58
+ float **submatrix(float **a, long oldrl, long oldrh,
59
+ long oldcl, long oldch, long newrl, long newcl);
60
+ float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch);
61
+ float ***f3tensor(long nrl, long nrh, long ncl, long nch,
62
+ long ndl, long ndh);
63
+ void free_vector(float *v, long nl, long nh);
64
+ void free_ivector(int *v, long nl, long nh);
65
+ void free_cvector(unsigned char *v, long nl, long nh);
66
+ void free_lvector(unsigned long *v, long nl, long nh);
67
+ void free_dvector(double *v, long nl, long nh);
68
+ void free_matrix(float **m, long nrl, long nrh, long ncl, long nch);
69
+ void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch);
70
+ void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch);
71
+ void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch);
72
+ void free_convert_matrix(float **b, long nrl, long nrh,
73
+ long ncl, long nch);
74
+ void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch,
75
+ long ndl, long ndh);
76
+
77
+ #else /* ANSI */
78
+ /* traditional -K&R */
79
+
80
+ void nrerror();
81
+ float *vector();
82
+
83
+ #endif /* ANSI */
84
+
85
+ #endif /* _NR_UTILS_H_ */
86
+
87
+
88
+ /* function definition */
89
+
90
+
91
+ void nrerror(char error_text[])
92
+ /* Numerical Recipes standard error handler */
93
+ {
94
+ fprintf(stderr, "Numerical Recipes run-time error...\n");
95
+ fprintf(stderr, "%s\n",error_text);
96
+ fprintf(stderr, "...now exiting to system...\n");
97
+ exit(1);
98
+ }
99
+
100
+ float *vector(long nl, long nh)
101
+ /* allocate a float vector with subscript range v[nl..nr] */
102
+ {
103
+ float *v;
104
+
105
+ v = (float *)malloc((size_t)((nh - nl + 1 + NR_END) * sizeof(float)));
106
+ if (!v) nrerror("allocation failure in vector()");
107
+ return v - nl + NR_END;
108
+ }
109
+
110
+ int *ivector(long nl, long nh)
111
+ /* allocate an int vector with subscript range v[nl..nr] */
112
+ {
113
+ int *v;
114
+
115
+ v = (int *)malloc((size_t)((nh - nl + 1 + NR_END)*sizeof(int)));
116
+ if (!v) nrerror("allocation failure in ivector()");
117
+ return v - nl + NR_END;
118
+ }
119
+
120
+ unsigned char *cvector(long nl, long nh)
121
+ /* allocate an unsigned char vector with subscript range v[nl..nr] */
122
+ {
123
+ unsigned char *v;
124
+
125
+ v = (unsigned char *)malloc((size_t)((nh - nl + 1 + NR_END)
126
+ * sizeof(unsigned char)));
127
+ if (!v) nrerror("allocation failure in cvector()");
128
+ return v - nl + NR_END;
129
+ }
130
+
131
+ unsigned long *lvector(long nl, long nh)
132
+ /* allocate an unsigned long vector with subscript range v[nl..nr] */
133
+ {
134
+ unsigned long *v;
135
+
136
+ v = (unsigned long *)malloc((size_t)((nh - nl + 1 + NR_END) * sizeof(long)));
137
+ if (!v) nrerror("allocation failure in lvector()");
138
+ return v - nl + NR_END;
139
+ }
140
+
141
+ double *dvector(long nl, long nh)
142
+ /* allocate a double vector with subscript range v[nl..nr] */
143
+ {
144
+ double *v;
145
+
146
+ v = (double *)malloc((size_t)((nh - nl + 1 + NR_END) * sizeof(double)));
147
+ if (!v) nrerror("allocation failure in dvector()");
148
+ return v - nl + NR_END;
149
+ }
150
+
151
+ float **matrix(long nrl, long nrh, long ncl, long nch)
152
+ /* allocate a float matrix with subscript range m[nrl..nrh][ncl, nch] */
153
+ {
154
+ long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1;
155
+ float **m;
156
+
157
+ /* allocate pointers to rows */
158
+ m = (float **)malloc((size_t)((nrow + NR_END) * sizeof(float *)));
159
+ if (!m) nrerror("allocation failure 1 in matrix()");
160
+ m += NR_END;
161
+ m -= nrl;
162
+
163
+ /* allocate rows and set pointers to them */
164
+ m[nrl] = (float *)malloc((size_t)((nrow * ncol + NR_END) * sizeof(float)));
165
+ if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
166
+ m[nrl] += NR_END;
167
+ m[nrl] -= ncl;
168
+
169
+ for (i = nrl + 1; i <= nrh; i++) m[i] = m[i-1] + ncol;
170
+
171
+ /* return pointer to array of pointers to rows */
172
+ return m;
173
+ }
174
+
175
+ double **dmatrix(long nrl, long nrh, long ncl, long nch)
176
+ /* allocate a double matrix with subscript range m[nrl..nrh][ncl, nch] */
177
+ {
178
+ long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1;
179
+ double **m;
180
+
181
+ /* allocate pointers to rows */
182
+ m = (double **)malloc((size_t)((nrow + NR_END) * sizeof(double *)));
183
+ if (!m) nrerror("allocation failure 1 in matrix()");
184
+ m += NR_END;
185
+ m -= nrl;
186
+
187
+ /* allocate rows and set pointers to them */
188
+ m[nrl] = (double *)malloc((size_t)((nrow * ncol + NR_END) * sizeof(double)));
189
+ if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
190
+ m[nrl] += NR_END;
191
+ m[nrl] -= ncl;
192
+
193
+ for (i = nrl + 1; i <= nrh; i++) m[i] = m[i-1] + ncol;
194
+
195
+ /* return pointer to array of pointers to rows */
196
+ return m;
197
+ }
198
+
199
+ int **imatrix(long nrl, long nrh, long ncl, long nch)
200
+ /* allocate an int matrix with subscript range m[nrl..nrh][ncl, nch] */
201
+ {
202
+ long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1;
203
+ int **m;
204
+
205
+ /* allocate pointers to rows */
206
+ m = (int **)malloc((size_t)((nrow + NR_END) * sizeof(int *)));
207
+ if (!m) nrerror("allocation failure 1 in matrix()");
208
+ m += NR_END;
209
+ m -= nrl;
210
+
211
+ /* allocate rows and set pointers to them */
212
+ m[nrl] = (int *)malloc((size_t)((nrow * ncol + NR_END) * sizeof(int)));
213
+ if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
214
+ m[nrl] += NR_END;
215
+ m[nrl] -= ncl;
216
+
217
+ for (i = nrl + 1; i <= nrh; i++) m[i] = m[i-1] + ncol;
218
+
219
+ /* return pointer to array of pointers to rows */
220
+ return m;
221
+ }
222
+
223
+ float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch,
224
+ long newrl, long newcl)
225
+ /* point a submatrix [newrl..][newcl..]
226
+ to a[oldrl..oldrh][oldcl..oldch] */
227
+
228
+ {
229
+ long i, j, nrow = oldrh - oldrl + 1, ncol = oldcl - newcl;
230
+ float **m;
231
+
232
+ /* allocate array of pointers to rows */
233
+ m = (float **)malloc((size_t)((nrow + NR_END) * sizeof(float *)));
234
+ if (!m) nrerror("allocation failure in submatrix()");
235
+ m += NR_END;
236
+ m -= newrl;
237
+
238
+ /* set pointers to rows */
239
+ for (i = oldrl, j = newrl; i <= oldrh; i++, j++) m[j] = a[i] + ncol;
240
+
241
+ /* return pointer to array of pointers to rows */
242
+ return m;
243
+ }
244
+
245
+ float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch)
246
+ /* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix
247
+ declared in the standard C manner as a[nrow][ncol],
248
+ where nrow = nrh - nrl + 1 and ncol = nch - ncl + 1. The routine should
249
+ be called with the address &a[0][0] as the first argument. */
250
+ {
251
+ long i, j, nrow = nrh -nrl + 1, ncol = nch - ncl + 1;
252
+ float **m;
253
+
254
+ /* allocate pointers to rows */
255
+ m = (float **)malloc((size_t)((nrow + NR_END) * sizeof(float *)));
256
+ if (!m) nrerror("allocation failure in convert_matrix()");
257
+ m += NR_END;
258
+ m -= nrl;
259
+
260
+ /* set pointers to rows */
261
+ m[nrl] = a - ncl;
262
+ for (i = 1, j = nrl + 1; i < nrow; i++, j++) m[j] = m[j - 1] + ncol;
263
+
264
+ /* return pointer to array of pointers to rows */
265
+ return m;
266
+ }
267
+
268
+ float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh)
269
+ /* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */
270
+ {
271
+ long i, j, nrow = nrh - nrl + 1, ncol = nch - ncl + 1, ndep = ndh - ndl + 1;
272
+ float ***t;
273
+
274
+ /* allocate pointers to pointers to rows */
275
+ t = (float ***)malloc((size_t)((nrow + NR_END) * sizeof(float **)));
276
+ if (!t) nrerror("allocation failure 1 in f3tensor()");
277
+ t += NR_END;
278
+ t -= nrl;
279
+
280
+ /* allocate pointers to rows and set pointers to them */
281
+ t[nrl] = (float **)malloc((size_t)((nrow * ncol + NR_END)
282
+ * sizeof(float *)));
283
+ if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()");
284
+ t[nrl] += NR_END;
285
+ t[nrl] -= ncl;
286
+
287
+ /* allocate rows and set pointers to them */
288
+ t[nrl][ncl] = (float *)malloc((size_t)((nrow * ncol * ndep + NR_END)
289
+ * sizeof(float)));
290
+ if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()");
291
+ t[nrl][ncl] += NR_END;
292
+ t[nrl][ncl] -= ndl;
293
+
294
+ for (j = ncl + 1; j <= nch; j++) t[nrl][j] = t[nrl][j - 1] + ndep;
295
+ for (i = nrl + 1; i <= nrh; i++) {
296
+ t[i] = t[i - 1] + ncol;
297
+ t[i][ncl] = t[i - 1][ncl] + ncol * ndep;
298
+ for ( j = ncl + 1; j <= nch; j++) t[i][j] = t[i][j - 1] + ndep;
299
+ }
300
+
301
+ /* return pointer to array of pointers to rows */
302
+ return t;
303
+ }
304
+
305
+ void free_vector(float *v, long nl, long nh)
306
+ /* free a float vector allocated with vector() */
307
+ {
308
+ free((FREE_ARG)(v + nl - NR_END));
309
+ }
310
+
311
+ void free_ivector(int *v, long nl, long nh)
312
+ /* free an int vector allocated with ivector() */
313
+ {
314
+ free((FREE_ARG)(v + nl - NR_END));
315
+ }
316
+
317
+ void free_cvector(unsigned char *v, long nl, long nh)
318
+ /* free an unsigned char vector allocated with cvector() */
319
+ {
320
+ free((FREE_ARG)(v + nl - NR_END));
321
+ }
322
+
323
+ void free_lvector(unsigned long *v, long nl, long nh)
324
+ /* free an unsigned long vector allocated with lvector() */
325
+ {
326
+ free((FREE_ARG)(v + nl - NR_END));
327
+ }
328
+
329
+ void free_dvector(double *v, long nl, long nh)
330
+ /* free a double vector allocated with dvector() */
331
+ {
332
+ free((FREE_ARG)(v + nl - NR_END));
333
+ }
334
+
335
+ void free_matrix(float **m, long nrl, long nrh, long ncl, long nch)
336
+ /* free a float matrix allocated by matrix() */
337
+ {
338
+ free((FREE_ARG)(m[nrl] + ncl - NR_END));
339
+ free((FREE_ARG)(m + nrl - NR_END));
340
+ }
341
+
342
+ void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch)
343
+ /* free a double matrix allocated by dmatrix() */
344
+ {
345
+ free((FREE_ARG)(m[nrl] + ncl - NR_END));
346
+ free((FREE_ARG)(m + nrl - NR_END));
347
+ }
348
+
349
+ void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch)
350
+ /* free an int matrix allocated by imatrix() */
351
+ {
352
+ free((FREE_ARG)(m[nrl] + ncl - NR_END));
353
+ free((FREE_ARG)(m + nrl - NR_END));
354
+ }
355
+
356
+ void free_submatirx(float **b, long nrl, long nrh, long ncl, long nch)
357
+ /* free a submatirx allocated by submatirx() */
358
+ {
359
+ free((FREE_ARG)(b + nrl - NR_END));
360
+ }
361
+
362
+ void free_convert_matirx(float **b, long nrl, long nrh, long ncl, long nch)
363
+ /* free a matirx allocated by convert_matirx() */
364
+ {
365
+ free((FREE_ARG)(b + nrl - NR_END));
366
+ }
367
+
368
+ void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch,
369
+ long ndl, long ndh)
370
+ /* free a float f3tensor allocated by f3tensor() */
371
+ {
372
+ free((FREE_ARG)(t[nrl][ncl] + ndl - NR_END));
373
+ free((FREE_ARG)(t[nrl] + ncl - NR_END));
374
+ free((FREE_ARG)(t + nrl - NR_END));
375
+ }
376
+
data/ext/svd.c ADDED
@@ -0,0 +1,66 @@
1
+ #include <stdio.h>
2
+ #include <ruby/ruby.h>
3
+ #include "svd.h"
4
+
5
+ VALUE decompose(VALUE module, VALUE matrix_ruby, VALUE m_ruby, VALUE n_ruby) {
6
+ int m = NUM2INT(m_ruby);
7
+ int n = NUM2INT(n_ruby);
8
+ float **u = matrix(1, m, 1, n);
9
+ float **v = matrix(1, m, 1, n);
10
+ float *w = vector(1, n);
11
+ VALUE *matrix_values = RARRAY_PTR(matrix_ruby);
12
+ int offset = 0;
13
+ int i, j;
14
+
15
+ /* output arrays */
16
+ VALUE u_output = rb_ary_new();
17
+ VALUE v_output = rb_ary_new();
18
+ VALUE w_output = rb_ary_new();
19
+ VALUE output = rb_ary_new();
20
+
21
+ // precondition
22
+ if((m*n) != RARRAY_LEN(matrix_ruby)) {
23
+ rb_raise(rb_eRangeError, "Size of the array is not equal to m * n");
24
+ return;
25
+ }
26
+
27
+ // convert to u matrix
28
+ for(i = 1; i <= m; i++) {
29
+ for(j = 1; j <= n; j++) {
30
+ offset = ((i-1)*n) + (j-1);
31
+ u[i][j] = (float) NUM2DBL(matrix_values[offset]);
32
+ }
33
+ }
34
+
35
+ /* perform SVD */
36
+ svdcmp(u, m, n, w, v);
37
+
38
+ /* create w output array */
39
+ for(i = 1; i <= n; i++)
40
+ rb_ary_push(w_output, rb_float_new(w[i]));
41
+
42
+ /* create u arrays */
43
+ for(i = 1; i <= m; i++) {
44
+ for(j = 1; j <= n; j++) {
45
+ rb_ary_push(u_output, rb_float_new(u[i][j]));
46
+ }
47
+ }
48
+
49
+ /* create v arrays */
50
+ for(i = 1; i <= n; i++) {
51
+ for(j = 1; j <= n; j++) {
52
+ rb_ary_push(v_output, rb_float_new(v[i][j]));
53
+ }
54
+ }
55
+
56
+ rb_ary_push(output, u_output);
57
+ rb_ary_push(output, w_output);
58
+ rb_ary_push(output, v_output);
59
+ return output;
60
+ }
61
+
62
+ void Init_svd()
63
+ {
64
+ VALUE module = rb_define_module("SVD");
65
+ rb_define_module_function(module, "decompose", decompose, 3);
66
+ }
data/ext/svd.h ADDED
@@ -0,0 +1,194 @@
1
+ /* svd.h */
2
+ /* Singular Value Decomposition for solving linear algebraic equations */
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <math.h>
6
+ #include "nrutil.h"
7
+
8
+ float pythag(float a, float b)
9
+ {
10
+ float absa,absb;
11
+ absa=fabs(a);
12
+ absb=fabs(b);
13
+ if (absa > absb) return absa*sqrt(1.0+SQR(absb/absa));
14
+ else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+SQR(absa/absb)));
15
+ }
16
+
17
+ void svdcmp(float **a, int m, int n, float w[], float **v)
18
+ {
19
+ float pythag(float a, float b);
20
+ int flag,i,its,j,jj,k,l,nm;
21
+ float anorm,c,f,g,h,s,scale,x,y,z,*rv1;
22
+
23
+ rv1=vector(1,n);
24
+ g=scale=anorm=0.0;
25
+ for (i=1;i<=n;i++) {
26
+ l=i+1;
27
+ rv1[i]=scale*g;
28
+ g=s=scale=0.0;
29
+ if (i <= m) {
30
+ for (k=i;k<=m;k++) scale += fabs(a[k][i]);
31
+ if (scale) {
32
+ for (k=i;k<=m;k++) {
33
+ a[k][i] /= scale;
34
+ s += a[k][i]*a[k][i];
35
+ }
36
+ f=a[i][i];
37
+ g = -SIGN(sqrt(s),f);
38
+ h=f*g-s;
39
+ a[i][i]=f-g;
40
+ for (j=l;j<=n;j++) {
41
+ for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
42
+ f=s/h;
43
+ for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
44
+ }
45
+ for (k=i;k<=m;k++) a[k][i] *= scale;
46
+ }
47
+ }
48
+ w[i]=scale *g;
49
+ g=s=scale=0.0;
50
+ if (i <= m && i != n) {
51
+ for (k=l;k<=n;k++) scale += fabs(a[i][k]);
52
+ if (scale) {
53
+ for (k=l;k<=n;k++) {
54
+ a[i][k] /= scale;
55
+ s += a[i][k]*a[i][k];
56
+ }
57
+ f=a[i][l];
58
+ g = -SIGN(sqrt(s),f);
59
+ h=f*g-s;
60
+ a[i][l]=f-g;
61
+ for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
62
+ for (j=l;j<=m;j++) {
63
+ for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
64
+ for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
65
+ }
66
+ for (k=l;k<=n;k++) a[i][k] *= scale;
67
+ }
68
+ }
69
+ anorm=FMAX(anorm,(fabs(w[i])+fabs(rv1[i])));
70
+ }
71
+ for (i=n;i>=1;i--) {
72
+ if (i < n) {
73
+ if (g) {
74
+ for (j=l;j<=n;j++)
75
+ v[j][i]=(a[i][j]/a[i][l])/g;
76
+ for (j=l;j<=n;j++) {
77
+ for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
78
+ for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
79
+ }
80
+ }
81
+ for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
82
+ }
83
+ v[i][i]=1.0;
84
+ g=rv1[i];
85
+ l=i;
86
+ }
87
+ for (i=IMIN(m,n);i>=1;i--) {
88
+ l=i+1;
89
+ g=w[i];
90
+ for (j=l;j<=n;j++) a[i][j]=0.0;
91
+ if (g) {
92
+ g=1.0/g;
93
+ for (j=l;j<=n;j++) {
94
+ for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
95
+ f=(s/a[i][i])*g;
96
+ for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
97
+ }
98
+ for (j=i;j<=m;j++) a[j][i] *= g;
99
+ } else for (j=i;j<=m;j++) a[j][i]=0.0;
100
+ ++a[i][i];
101
+ }
102
+ for (k=n;k>=1;k--) {
103
+ for (its=1;its<=30;its++) {
104
+ flag=1;
105
+ for (l=k;l>=1;l--) {
106
+ nm=l-1;
107
+ if ((float)(fabs(rv1[l])+anorm) == anorm) {
108
+ flag=0;
109
+ break;
110
+ }
111
+ if ((float)(fabs(w[nm])+anorm) == anorm) break;
112
+ }
113
+ if (flag) {
114
+ c=0.0;
115
+ s=1.0;
116
+ for (i=l;i<=k;i++) {
117
+ f=s*rv1[i];
118
+ rv1[i]=c*rv1[i];
119
+ if ((float)(fabs(f)+anorm) == anorm) break;
120
+ g=w[i];
121
+ h=pythag(f,g);
122
+ w[i]=h;
123
+ h=1.0/h;
124
+ c=g*h;
125
+ s = -f*h;
126
+ for (j=1;j<=m;j++) {
127
+ y=a[j][nm];
128
+ z=a[j][i];
129
+ a[j][nm]=y*c+z*s;
130
+ a[j][i]=z*c-y*s;
131
+ }
132
+ }
133
+ }
134
+ z=w[k];
135
+ if (l == k) {
136
+ if (z < 0.0) {
137
+ w[k] = -z;
138
+ for (j=1;j<=n;j++) v[j][k] = -v[j][k];
139
+ }
140
+ break;
141
+ }
142
+ if (its == 30) nrerror("no convergence in 30 svdcmp iterations");
143
+ x=w[l];
144
+ nm=k-1;
145
+ y=w[nm];
146
+ g=rv1[nm];
147
+ h=rv1[k];
148
+ f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
149
+ g=pythag(f,1.0);
150
+ f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
151
+ c=s=1.0;
152
+ for (j=l;j<=nm;j++) {
153
+ i=j+1;
154
+ g=rv1[i];
155
+ y=w[i];
156
+ h=s*g;
157
+ g=c*g;
158
+ z=pythag(f,h);
159
+ rv1[j]=z;
160
+ c=f/z;
161
+ s=h/z;
162
+ f=x*c+g*s;
163
+ g = g*c-x*s;
164
+ h=y*s;
165
+ y *= c;
166
+ for (jj=1;jj<=n;jj++) {
167
+ x=v[jj][j];
168
+ z=v[jj][i];
169
+ v[jj][j]=x*c+z*s;
170
+ v[jj][i]=z*c-x*s;
171
+ }
172
+ z=pythag(f,h);
173
+ w[j]=z;
174
+ if (z) {
175
+ z=1.0/z;
176
+ c=f*z;
177
+ s=h*z;
178
+ }
179
+ f=c*g+s*y;
180
+ x=c*y-s*g;
181
+ for (jj=1;jj<=m;jj++) {
182
+ y=a[jj][j];
183
+ z=a[jj][i];
184
+ a[jj][j]=y*c+z*s;
185
+ a[jj][i]=z*c-y*s;
186
+ }
187
+ }
188
+ rv1[l]=0.0;
189
+ rv1[k]=f;
190
+ w[k]=x;
191
+ }
192
+ }
193
+ free_vector(rv1,1,n);
194
+ }
data/lib/ruby-svd.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'svd'
2
+ require 'svd_matrix'
3
+
data/lib/svd_matrix.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'mathn'
2
+ require 'svd'
3
+
4
+ class SVDMatrix < Matrix
5
+ public_class_method :new
6
+ def initialize(m, n)
7
+ @rows = Array.new(m)
8
+ m.times {|i| @rows[i] = Array.new(n)}
9
+ end
10
+
11
+ def []=(i, j, val)
12
+ @rows[i][j] = val
13
+ end
14
+
15
+ def []=(i, row)
16
+ @rows[i] = row
17
+ end
18
+
19
+ def inspect
20
+ @rows.collect {|row| "#{row.inspect}\n"}
21
+ end
22
+
23
+ def lsa
24
+ input_array = []
25
+ @rows.each {|row| input_array += row}
26
+ u_array, w_array, v_array = SVD.decompose(input_array, row_size, column_size)
27
+
28
+ u = SVDMatrix.new(row_size, column_size)
29
+ row_size.times {|i| u[i] = u_array.slice!(0,column_size)}
30
+
31
+ v = SVDMatrix.new(column_size, column_size)
32
+ column_size.times {|i| v[i] = v_array.slice!(0,column_size)}
33
+ v = v.transpose
34
+
35
+ w_array = w_array[0...2] + Array.new(w_array.size - 2).collect {|i| 0}
36
+ w = Matrix.diagonal(*w_array)
37
+
38
+ r = (u * w * v)
39
+ end
40
+ end
41
+
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-svd
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Will
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-18 00:00:00 +11:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Singular Value Decomposition with no dependency on GSL or LAPACK
22
+ email: me@willcannings.com
23
+ executables: []
24
+
25
+ extensions:
26
+ - ext/extconf.rb
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README
30
+ files:
31
+ - ext/extconf.rb
32
+ - ext/nrutil.h
33
+ - ext/svd.c
34
+ - ext/svd.h
35
+ - lib/ruby-svd.rb
36
+ - lib/svd_matrix.rb
37
+ - LICENSE
38
+ - README
39
+ has_rdoc: true
40
+ homepage: http://github.com/willcannings/ruby-svd
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ - ext
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.6
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: SVD for Ruby
70
+ test_files: []
71
+