ruby-svd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+