nmatrix 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.autotest +23 -0
  2. data/.gemtest +0 -0
  3. data/Gemfile +7 -0
  4. data/History.txt +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/Manifest.txt +51 -0
  7. data/README.rdoc +63 -0
  8. data/Rakefile +154 -0
  9. data/ext/nmatrix/cblas.c +150 -0
  10. data/ext/nmatrix/dense.c +307 -0
  11. data/ext/nmatrix/dense/blas_header.template.c +52 -0
  12. data/ext/nmatrix/dense/elementwise.template.c +107 -0
  13. data/ext/nmatrix/dense/gemm.template.c +159 -0
  14. data/ext/nmatrix/dense/gemv.template.c +130 -0
  15. data/ext/nmatrix/dense/rationalmath.template.c +68 -0
  16. data/ext/nmatrix/depend +18 -0
  17. data/ext/nmatrix/extconf.rb +143 -0
  18. data/ext/nmatrix/generator.rb +594 -0
  19. data/ext/nmatrix/generator/syntax_tree.rb +481 -0
  20. data/ext/nmatrix/list.c +774 -0
  21. data/ext/nmatrix/nmatrix.c +1977 -0
  22. data/ext/nmatrix/nmatrix.h +912 -0
  23. data/ext/nmatrix/rational.c +98 -0
  24. data/ext/nmatrix/yale.c +726 -0
  25. data/ext/nmatrix/yale/complexmath.template.c +71 -0
  26. data/ext/nmatrix/yale/elementwise.template.c +46 -0
  27. data/ext/nmatrix/yale/elementwise_op.template.c +73 -0
  28. data/ext/nmatrix/yale/numbmm.template.c +94 -0
  29. data/ext/nmatrix/yale/smmp1.template.c +21 -0
  30. data/ext/nmatrix/yale/smmp1_header.template.c +38 -0
  31. data/ext/nmatrix/yale/smmp2.template.c +43 -0
  32. data/ext/nmatrix/yale/smmp2_header.template.c +46 -0
  33. data/ext/nmatrix/yale/sort_columns.template.c +56 -0
  34. data/ext/nmatrix/yale/symbmm.template.c +54 -0
  35. data/ext/nmatrix/yale/transp.template.c +68 -0
  36. data/lib/array.rb +67 -0
  37. data/lib/nmatrix.rb +263 -0
  38. data/lib/string.rb +65 -0
  39. data/spec/nmatrix_spec.rb +395 -0
  40. data/spec/nmatrix_yale_spec.rb +239 -0
  41. data/spec/nvector_spec.rb +43 -0
  42. data/spec/syntax_tree_spec.rb +46 -0
  43. metadata +150 -0
@@ -0,0 +1,307 @@
1
+ /////////////////////////////////////////////////////////////////////
2
+ // = NMatrix
3
+ //
4
+ // A linear algebra library for scientific computation in Ruby.
5
+ // NMatrix is part of SciRuby.
6
+ //
7
+ // NMatrix was originally inspired by and derived from NArray, by
8
+ // Masahiro Tanaka: http://narray.rubyforge.org
9
+ //
10
+ // == Copyright Information
11
+ //
12
+ // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2012, Ruby Science Foundation
14
+ //
15
+ // Please see LICENSE.txt for additional copyright notices.
16
+ //
17
+ // == Contributing
18
+ //
19
+ // By contributing source code to SciRuby, you agree to be bound by
20
+ // our Contributor Agreement:
21
+ //
22
+ // * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
+ //
24
+ // == dense.c
25
+ //
26
+ // Dense n-dimensional matrix storage.
27
+
28
+ #ifndef DENSE_C
29
+ #define DENSE_C
30
+
31
+ #include <ruby.h>
32
+
33
+ #include "nmatrix.h"
34
+
35
+
36
+ /* Calculate the number of elements in the dense storage structure, based on shape and rank */
37
+ size_t count_dense_storage_elements(const DENSE_STORAGE* s) {
38
+ size_t i;
39
+ size_t count = 1;
40
+ for (i = 0; i < s->rank; ++i) count *= s->shape[i];
41
+ return count;
42
+ }
43
+
44
+
45
+ // Do these two dense matrices of the same dtype have exactly the same contents?
46
+ bool dense_storage_eqeq(const DENSE_STORAGE* left, const DENSE_STORAGE* right) {
47
+ return !memcmp(left->elements, right->elements, count_dense_storage_elements(left) / nm_sizeof[left->dtype]);
48
+ }
49
+
50
+
51
+ size_t dense_storage_pos(DENSE_STORAGE* s, size_t* coords) {
52
+ size_t k, l;
53
+ size_t inner, outer = 0;
54
+ for (k = 0; k < s->rank; ++k) {
55
+ inner = coords[k];
56
+ for (l = k+1; l < s->rank; ++l) {
57
+ inner *= s->shape[l];
58
+ }
59
+ outer += inner;
60
+ }
61
+ return outer;
62
+ }
63
+
64
+
65
+
66
+ void* dense_storage_get(DENSE_STORAGE* s, size_t* coords) {
67
+ return (char*)(s->elements) + dense_storage_pos(s, coords) * nm_sizeof[s->dtype];
68
+ }
69
+
70
+
71
+ /* Does not free passed-in value! Different from list_storage_insert. */
72
+ void dense_storage_set(DENSE_STORAGE* s, size_t* coords, void* val) {
73
+ memcpy((char*)(s->elements) + dense_storage_pos(s, coords) * nm_sizeof[s->dtype], val, nm_sizeof[s->dtype]);
74
+ }
75
+
76
+
77
+ DENSE_STORAGE* copy_dense_storage(DENSE_STORAGE* rhs) {
78
+ DENSE_STORAGE* lhs;
79
+ size_t count = count_dense_storage_elements(rhs), p;
80
+ size_t* shape = ALLOC_N(size_t, rhs->rank);
81
+ if (!shape) return NULL;
82
+
83
+ // copy shape array
84
+ for (p = 0; p < rhs->rank; ++p)
85
+ shape[p] = rhs->shape[p];
86
+
87
+ lhs = create_dense_storage(rhs->dtype, shape, rhs->rank, NULL, 0);
88
+
89
+ if (lhs && count) // ensure that allocation worked before copying
90
+ memcpy(lhs->elements, rhs->elements, nm_sizeof[rhs->dtype] * count);
91
+
92
+ return lhs;
93
+ }
94
+
95
+
96
+ DENSE_STORAGE* cast_copy_dense_storage(DENSE_STORAGE* rhs, int8_t new_dtype) {
97
+ DENSE_STORAGE* lhs;
98
+ size_t count = count_dense_storage_elements(rhs), p;
99
+ size_t* shape = ALLOC_N(size_t, rhs->rank);
100
+ if (!shape) return NULL;
101
+
102
+ // copy shape array
103
+ for (p = 0; p < rhs->rank; ++p) shape[p] = rhs->shape[p];
104
+
105
+ lhs = create_dense_storage(new_dtype, shape, rhs->rank, NULL, 0);
106
+
107
+ if (lhs && count) // ensure that allocation worked before copying
108
+ if (lhs->dtype == rhs->dtype)
109
+ memcpy(lhs->elements, rhs->elements, nm_sizeof[rhs->dtype] * count);
110
+ else
111
+ SetFuncs[lhs->dtype][rhs->dtype](count, lhs->elements, nm_sizeof[lhs->dtype], rhs->elements, nm_sizeof[rhs->dtype]);
112
+
113
+
114
+ return lhs;
115
+ }
116
+
117
+
118
+
119
+ // Copy a set of default values into dense
120
+ static inline void cast_copy_dense_list_default(void* lhs, void* default_val, int8_t l_dtype, int8_t r_dtype, size_t* pos, const size_t* shape, size_t rank, size_t max_elements, size_t recursions) {
121
+ size_t i;
122
+
123
+ for (i = 0; i < shape[rank-1-recursions]; ++i, ++(*pos)) {
124
+ //fprintf(stderr, "default: pos = %u, dim = %u\t", *pos, shape[rank-1-recursions]);
125
+
126
+ if (recursions == 0) { cast_copy_value_single((char*)lhs + (*pos)*nm_sizeof[l_dtype], default_val, l_dtype, r_dtype); fprintf(stderr, "zero\n"); }
127
+ else { cast_copy_dense_list_default(lhs, default_val, l_dtype, r_dtype, pos, shape, rank, max_elements, recursions-1); fprintf(stderr, "column of zeros\n"); }
128
+ }
129
+ --(*pos);
130
+ }
131
+
132
+
133
+ // Copy list contents into dense recursively
134
+ static void cast_copy_dense_list_contents(void* lhs, const LIST* rhs, void* default_val, int8_t l_dtype, int8_t r_dtype, size_t* pos, const size_t* shape, size_t rank, size_t max_elements, size_t recursions) {
135
+ NODE *curr = rhs->first;
136
+ int last_key = -1;
137
+ size_t i = 0;
138
+
139
+ for (i = 0; i < shape[rank-1-recursions]; ++i, ++(*pos)) {
140
+
141
+ if (!curr || (curr->key > (size_t)(last_key+1))) {
142
+ //fprintf(stderr, "pos = %u, dim = %u, curr->key XX, last_key+1 = %d\t", *pos, shape[rank-1-recursions], last_key+1);
143
+ if (recursions == 0) cast_copy_value_single((char*)lhs + (*pos)*nm_sizeof[l_dtype], default_val, l_dtype, r_dtype); //fprintf(stderr, "zero\n"); }
144
+ else cast_copy_dense_list_default(lhs, default_val, l_dtype, r_dtype, pos, shape, rank, max_elements, recursions-1); //fprintf(stderr, "column of zeros\n"); }
145
+
146
+ ++last_key;
147
+ } else {
148
+ //fprintf(stderr, "pos = %u, dim = %u, curr->key = %u, last_key+1 = %d\t", *pos, shape[rank-1-recursions], curr->key, last_key+1);
149
+ if (recursions == 0) cast_copy_value_single((char*)lhs + (*pos)*nm_sizeof[l_dtype], curr->val, l_dtype, r_dtype); //fprintf(stderr, "value\n"); }
150
+ else cast_copy_dense_list_contents(lhs, curr->val, default_val, l_dtype, r_dtype, pos, shape, rank, max_elements, recursions-1); //fprintf(stderr, "column of values\n"); }
151
+
152
+ last_key = curr->key;
153
+ curr = curr->next;
154
+ }
155
+ }
156
+ --(*pos);
157
+ }
158
+
159
+
160
+ // Convert (by creating a copy) from list storage to dense storage.
161
+ DENSE_STORAGE* scast_copy_dense_list(const LIST_STORAGE* rhs, int8_t l_dtype) {
162
+ DENSE_STORAGE* lhs;
163
+ size_t pos = 0; // position in lhs->elements
164
+
165
+ // allocate and copy shape
166
+ size_t* shape = ALLOC_N(size_t, rhs->rank);
167
+ memcpy(shape, rhs->shape, rhs->rank * sizeof(size_t));
168
+
169
+ lhs = create_dense_storage(l_dtype, shape, rhs->rank, NULL, 0);
170
+
171
+ // recursively copy the contents
172
+ cast_copy_dense_list_contents(lhs->elements, rhs->rows, rhs->default_val, l_dtype, rhs->dtype, &pos, shape, lhs->rank, count_storage_max_elements((STORAGE*)rhs), rhs->rank-1);
173
+
174
+ return lhs;
175
+ }
176
+
177
+
178
+ DENSE_STORAGE* scast_copy_dense_yale(const YALE_STORAGE* rhs, int8_t l_dtype) {
179
+ DENSE_STORAGE* lhs;
180
+ y_size_t i, j, // position in lhs->elements
181
+ ija, ija_next, jj; // position in rhs->elements
182
+ y_size_t pos = 0; // position in dense to write to
183
+ void* R_ZERO = (char*)(rhs->a) + rhs->shape[0] * nm_sizeof[rhs->dtype]; // determine zero representation
184
+
185
+ // allocate and set shape
186
+ size_t* shape = ALLOC_N(size_t, rhs->rank);
187
+ memcpy(shape, rhs->shape, rhs->rank * sizeof(size_t));
188
+
189
+ lhs = create_dense_storage(l_dtype, shape, rhs->rank, NULL, 0);
190
+
191
+ // Walk through rows. For each entry we set in dense, increment pos.
192
+ for (i = 0; i < rhs->shape[0]; ++i) {
193
+
194
+ // get boundaries of this row, store in ija and ija_next
195
+ YaleGetIJA(ija, rhs, i);
196
+ YaleGetIJA(ija_next, rhs, i+1);
197
+
198
+ if (ija == ija_next) { // row is empty?
199
+
200
+ for (j = 0; j < rhs->shape[1]; ++j) { // write zeros in each column
201
+
202
+ // Fill in zeros (except for diagonal)
203
+ if (i == j) cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], (char*)(rhs->a) + i*nm_sizeof[rhs->dtype], l_dtype, rhs->dtype);
204
+ else cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], R_ZERO, l_dtype, rhs->dtype);
205
+
206
+ ++pos; // move to next dense position
207
+ }
208
+
209
+ } else {
210
+ // row contains entries: write those in each column, interspersed with zeros
211
+ YaleGetIJA(jj, rhs, ija);
212
+
213
+ for (j = 0; j < rhs->shape[1]; ++j) {
214
+ if (i == j) {
215
+
216
+ cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], (char*)(rhs->a) + i*nm_sizeof[rhs->dtype], l_dtype, rhs->dtype);
217
+
218
+ } else if (j == jj) {
219
+
220
+ // copy from rhs
221
+ cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], (char*)(rhs->a) + ija*nm_sizeof[rhs->dtype], l_dtype, rhs->dtype);
222
+
223
+ // get next
224
+ ++ija;
225
+
226
+ // increment to next column ID (or go off the end)
227
+ if (ija < ija_next) YaleGetIJA(jj, rhs, ija);
228
+ else jj = rhs->shape[1];
229
+
230
+ } else { // j < jj
231
+
232
+ // insert zero
233
+ cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], R_ZERO, l_dtype, rhs->dtype);
234
+ }
235
+ ++pos; // move to next dense position
236
+ }
237
+ }
238
+ }
239
+
240
+ return lhs;
241
+ }
242
+
243
+
244
+ // Note that elements and elements_length are for initial value(s) passed in. If they are the correct length, they will
245
+ // be used directly. If not, they will be concatenated over and over again into a new elements array. If elements is NULL,
246
+ // the new elements array will not be initialized.
247
+ DENSE_STORAGE* create_dense_storage(int8_t dtype, size_t* shape, size_t rank, void* elements, size_t elements_length) {
248
+ DENSE_STORAGE* s;
249
+ size_t count, i, copy_length = elements_length;
250
+
251
+ s = ALLOC( DENSE_STORAGE );
252
+ //if (!(s = malloc(sizeof(DENSE_STORAGE)))) return NULL;
253
+
254
+ s->rank = rank;
255
+ s->shape = shape;
256
+ s->dtype = dtype;
257
+
258
+ //fprintf(stderr, "create_dense_storage: %p\n", s);
259
+
260
+ count = count_dense_storage_elements(s);
261
+ //fprintf(stderr, "count_dense_storage_elements: %d\n", count);
262
+
263
+ if (elements_length == count) s->elements = elements;
264
+ else {
265
+ s->elements = ALLOC_N(char, nm_sizeof[dtype]*count);
266
+
267
+ if (elements_length > 0) {
268
+ // repeat elements over and over again until the end of the matrix
269
+ for (i = 0; i < count; i += elements_length) {
270
+ if (i + elements_length > count) copy_length = count - i;
271
+ memcpy((char*)(s->elements)+i*nm_sizeof[dtype], (char*)(elements)+(i % elements_length)*nm_sizeof[dtype], copy_length*nm_sizeof[dtype]);
272
+ }
273
+
274
+ // get rid of the init_val
275
+ free(elements);
276
+ }
277
+ }
278
+
279
+ return s;
280
+ }
281
+
282
+
283
+ void delete_dense_storage(DENSE_STORAGE* s) {
284
+ if (s) { // sometimes Ruby passes in NULL storage for some reason (probably on copy construction failure)
285
+ free(s->shape);
286
+ free(s->elements);
287
+ free(s);
288
+ }
289
+ }
290
+
291
+
292
+ void mark_dense_storage(void* m) {
293
+ size_t i;
294
+ DENSE_STORAGE* storage;
295
+
296
+ if (m) {
297
+ storage = (DENSE_STORAGE*)(((NMATRIX*)m)->storage);
298
+ //fprintf(stderr, "mark_dense_storage\n");
299
+ if (storage && storage->dtype == NM_ROBJ)
300
+ for (i = 0; i < count_dense_storage_elements(storage); ++i)
301
+ rb_gc_mark(*((VALUE*)((char*)(storage->elements) + i*nm_sizeof[NM_ROBJ])));
302
+ }
303
+ }
304
+
305
+
306
+
307
+ #endif
@@ -0,0 +1,52 @@
1
+ /////////////////////////////////////////////////////////////////////
2
+ // = NMatrix
3
+ //
4
+ // A linear algebra library for scientific computation in Ruby.
5
+ // NMatrix is part of SciRuby.
6
+ //
7
+ // NMatrix was originally inspired by and derived from NArray, by
8
+ // Masahiro Tanaka: http://narray.rubyforge.org
9
+ //
10
+ // == Copyright Information
11
+ //
12
+ // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2012, Ruby Science Foundation
14
+ //
15
+ // Please see LICENSE.txt for additional copyright notices.
16
+ //
17
+ // == Contributing
18
+ //
19
+ // By contributing source code to SciRuby, you agree to be bound by
20
+ // our Contributor Agreement:
21
+ //
22
+ // * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
+ //
24
+ // == blas.c
25
+ //
26
+ // blas.c is automatically generated by generator.rb. Do not modify
27
+ // it directly!
28
+ //
29
+ // This file contains C ports of BLAS functions that work on integer
30
+ // types and eventually rationals. You can find the original template
31
+ // in ext/nmatrix/blas/igemm.template.c.
32
+ //
33
+ // The port was accomplished using f2c (on dgemm.f) and a magnifying
34
+ // glass.
35
+ //
36
+ // Note that this is in no way comparable to ATLAS. Why?
37
+ // * We didn't test any options other than CblasNoTrans (for A and B)
38
+ // * It doesn't use any of that cool cross-over crap (e.g.,
39
+ // Strassen's algorithm)
40
+ // * It really hasn't been tested exhaustively in any way, shape, or
41
+ // form.
42
+ //
43
+ // This file also contains rational math helper functions so that the
44
+ // aforementioned port will work with rationals too. These are in
45
+ // ext/nmatrix/blas/rationalmath.template.c. They are derived from
46
+ // rational.c in Ruby 1.9.3.
47
+
48
+ #include "nmatrix.h"
49
+
50
+
51
+
52
+
@@ -0,0 +1,107 @@
1
+
2
+ int nm_d_%%TYPE_ABBREV%%_elementwise(const %%TYPE%%* A, const %%TYPE%%* B, %%TYPE%%* C, size_t n, enum NMatrix_Ops op)
3
+ {
4
+ size_t i;
5
+ //fprintf(stderr, "elementwise: n=%d, op=%c\n", n, op);
6
+
7
+ switch (op) {
8
+ case '+':
9
+ for (i = 0; i < n; ++i) {
10
+ %%TYPE C[i] = A[i] + B[i]%%
11
+ }
12
+ break;
13
+ case '-':
14
+ for (i = 0; i < n; ++i) {
15
+ %%TYPE C[i] = A[i] - B[i]%%
16
+ }
17
+ break;
18
+ case '*':
19
+ for (i = 0; i < n; ++i) {
20
+ %%TYPE C[i] = A[i] * B[i]%%
21
+ }
22
+ break;
23
+ case '/':
24
+ for (i = 0; i < n; ++i) {
25
+ %%TYPE C[i] = A[i] / B[i]%%
26
+ }
27
+ break;
28
+ case '%':
29
+ for (i = 0; i < n; ++i) {
30
+ %%TYPE C[i] = A[i] % B[i]%%
31
+ }
32
+ break;
33
+ case '!':
34
+ for (i = 0; i < n; ++i) {
35
+ %%TYPE C[i] = !A[i]%%
36
+ }
37
+ break;
38
+ case NM_OP_NEG:
39
+ for (i = 0; i < n; ++i) {
40
+ %%TYPE C[i] = -A[i]%%
41
+ }
42
+ break;
43
+ case NM_OP_EQEQ:
44
+ for (i = 0; i < n; ++i) {
45
+ %%TYPE C[i] = A[i] == B[i]%%
46
+ }
47
+ break;
48
+ case NM_OP_NEQ:
49
+ for (i = 0; i < n; ++i) {
50
+ %%TYPE C[i] = A[i] != B[i]%%
51
+ }
52
+ break;
53
+ case '>':
54
+ for (i = 0; i < n; ++i) {
55
+ %%TYPE C[i] = A[i] > B[i]%%
56
+ }
57
+ break;
58
+ case '<':
59
+ for (i = 0; i < n; ++i) {
60
+ %%TYPE C[i] = A[i] < B[i]%%
61
+ }
62
+ break;
63
+ case NM_OP_GTE:
64
+ for (i = 0; i < n; ++i) {
65
+ %%TYPE C[i] = A[i] >= B[i]%%
66
+ }
67
+ break;
68
+ case NM_OP_LTE:
69
+ for (i = 0; i < n; ++i) {
70
+ %%TYPE C[i] = A[i] <= B[i]%%
71
+ }
72
+ break;
73
+ case '~':
74
+ for (i = 0; i < n; ++i) {
75
+ %%TYPE C[i] = ~A[i]%%
76
+ }
77
+ break;
78
+ case '&':
79
+ for (i = 0; i < n; ++i) {
80
+ %%TYPE C[i] = A[i] & B[i]%%
81
+ }
82
+ break;
83
+ case '|':
84
+ for (i = 0; i < n; ++i) {
85
+ %%TYPE C[i] = A[i] | B[i]%%
86
+ }
87
+ break;
88
+ case '^':
89
+ for (i = 0; i < n; ++i) {
90
+ %%TYPE C[i] = A[i] ^ B[i]%%
91
+ }
92
+ break;
93
+ case NM_OP_LSH:
94
+ for (i = 0; i < n; ++i) {
95
+ %%TYPE C[i] = A[i] << B[i]%%
96
+ }
97
+ break;
98
+ case NM_OP_RSH:
99
+ for (i = 0; i < n; ++i) {
100
+ %%TYPE C[i] = A[i] >> B[i]%%
101
+ }
102
+ break;
103
+ default:
104
+ rb_raise(rb_eNotImpError, "Unrecognized element-wise operator");
105
+ }
106
+ return 0;
107
+ }