nmatrix 0.0.1 → 0.0.2

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.
Files changed (91) hide show
  1. data/.gitignore +27 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +3 -5
  4. data/Guardfile +6 -0
  5. data/History.txt +33 -0
  6. data/Manifest.txt +41 -38
  7. data/README.rdoc +88 -11
  8. data/Rakefile +35 -53
  9. data/ext/nmatrix/data/complex.h +372 -0
  10. data/ext/nmatrix/data/data.cpp +275 -0
  11. data/ext/nmatrix/data/data.h +707 -0
  12. data/ext/nmatrix/data/rational.h +421 -0
  13. data/ext/nmatrix/data/ruby_object.h +446 -0
  14. data/ext/nmatrix/extconf.rb +101 -51
  15. data/ext/nmatrix/new_extconf.rb +56 -0
  16. data/ext/nmatrix/nmatrix.cpp +1609 -0
  17. data/ext/nmatrix/nmatrix.h +265 -849
  18. data/ext/nmatrix/ruby_constants.cpp +134 -0
  19. data/ext/nmatrix/ruby_constants.h +103 -0
  20. data/ext/nmatrix/storage/common.cpp +70 -0
  21. data/ext/nmatrix/storage/common.h +170 -0
  22. data/ext/nmatrix/storage/dense.cpp +665 -0
  23. data/ext/nmatrix/storage/dense.h +116 -0
  24. data/ext/nmatrix/storage/list.cpp +1088 -0
  25. data/ext/nmatrix/storage/list.h +129 -0
  26. data/ext/nmatrix/storage/storage.cpp +658 -0
  27. data/ext/nmatrix/storage/storage.h +99 -0
  28. data/ext/nmatrix/storage/yale.cpp +1601 -0
  29. data/ext/nmatrix/storage/yale.h +208 -0
  30. data/ext/nmatrix/ttable_helper.rb +126 -0
  31. data/ext/nmatrix/{yale/smmp1_header.template.c → types.h} +36 -9
  32. data/ext/nmatrix/util/io.cpp +295 -0
  33. data/ext/nmatrix/util/io.h +117 -0
  34. data/ext/nmatrix/util/lapack.h +1175 -0
  35. data/ext/nmatrix/util/math.cpp +557 -0
  36. data/ext/nmatrix/util/math.h +1363 -0
  37. data/ext/nmatrix/util/sl_list.cpp +475 -0
  38. data/ext/nmatrix/util/sl_list.h +255 -0
  39. data/ext/nmatrix/util/util.h +78 -0
  40. data/lib/nmatrix/blas.rb +70 -0
  41. data/lib/nmatrix/io/mat5_reader.rb +567 -0
  42. data/lib/nmatrix/io/mat_reader.rb +162 -0
  43. data/lib/{string.rb → nmatrix/monkeys.rb} +49 -2
  44. data/lib/nmatrix/nmatrix.rb +199 -0
  45. data/lib/nmatrix/nvector.rb +103 -0
  46. data/lib/nmatrix/version.rb +27 -0
  47. data/lib/nmatrix.rb +22 -230
  48. data/nmatrix.gemspec +59 -0
  49. data/scripts/mac-brew-gcc.sh +47 -0
  50. data/spec/4x4_sparse.mat +0 -0
  51. data/spec/4x5_dense.mat +0 -0
  52. data/spec/blas_spec.rb +47 -0
  53. data/spec/elementwise_spec.rb +164 -0
  54. data/spec/io_spec.rb +60 -0
  55. data/spec/lapack_spec.rb +52 -0
  56. data/spec/math_spec.rb +96 -0
  57. data/spec/nmatrix_spec.rb +93 -89
  58. data/spec/nmatrix_yale_spec.rb +52 -36
  59. data/spec/nvector_spec.rb +1 -1
  60. data/spec/slice_spec.rb +257 -0
  61. data/spec/spec_helper.rb +51 -0
  62. data/spec/utm5940.mtx +83844 -0
  63. metadata +113 -71
  64. data/.autotest +0 -23
  65. data/.gemtest +0 -0
  66. data/ext/nmatrix/cblas.c +0 -150
  67. data/ext/nmatrix/dense/blas_header.template.c +0 -52
  68. data/ext/nmatrix/dense/elementwise.template.c +0 -107
  69. data/ext/nmatrix/dense/gemm.template.c +0 -159
  70. data/ext/nmatrix/dense/gemv.template.c +0 -130
  71. data/ext/nmatrix/dense/rationalmath.template.c +0 -68
  72. data/ext/nmatrix/dense.c +0 -307
  73. data/ext/nmatrix/depend +0 -18
  74. data/ext/nmatrix/generator/syntax_tree.rb +0 -481
  75. data/ext/nmatrix/generator.rb +0 -594
  76. data/ext/nmatrix/list.c +0 -774
  77. data/ext/nmatrix/nmatrix.c +0 -1977
  78. data/ext/nmatrix/rational.c +0 -98
  79. data/ext/nmatrix/yale/complexmath.template.c +0 -71
  80. data/ext/nmatrix/yale/elementwise.template.c +0 -46
  81. data/ext/nmatrix/yale/elementwise_op.template.c +0 -73
  82. data/ext/nmatrix/yale/numbmm.template.c +0 -94
  83. data/ext/nmatrix/yale/smmp1.template.c +0 -21
  84. data/ext/nmatrix/yale/smmp2.template.c +0 -43
  85. data/ext/nmatrix/yale/smmp2_header.template.c +0 -46
  86. data/ext/nmatrix/yale/sort_columns.template.c +0 -56
  87. data/ext/nmatrix/yale/symbmm.template.c +0 -54
  88. data/ext/nmatrix/yale/transp.template.c +0 -68
  89. data/ext/nmatrix/yale.c +0 -726
  90. data/lib/array.rb +0 -67
  91. data/spec/syntax_tree_spec.rb +0 -46
@@ -0,0 +1,475 @@
1
+ //
2
+ // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
3
+ // NMatrix is Copyright (c) 2012, Ruby Science Foundation
4
+ //
5
+ // Please see LICENSE.txt for additional copyright notices.
6
+ //
7
+ // == Contributing
8
+ //
9
+ // By contributing source code to SciRuby, you agree to be bound by
10
+ // our Contributor Agreement:
11
+ //
12
+ // * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
13
+ //
14
+ // == sl_list.cpp
15
+ //
16
+ // Singly-linked list implementation
17
+
18
+ /*
19
+ * Standard Includes
20
+ */
21
+
22
+ #include <ruby.h>
23
+
24
+ /*
25
+ * Project Includes
26
+ */
27
+
28
+ #include "types.h"
29
+
30
+ #include "data/data.h"
31
+
32
+ #include "sl_list.h"
33
+
34
+ namespace nm { namespace list {
35
+
36
+ /*
37
+ * Macros
38
+ */
39
+
40
+ /*
41
+ * Global Variables
42
+ */
43
+
44
+
45
+ /*
46
+ * Forward Declarations
47
+ */
48
+
49
+ /*
50
+ * Functions
51
+ */
52
+
53
+ ////////////////
54
+ // Lifecycle //
55
+ ///////////////
56
+
57
+ /*
58
+ * Creates an empty linked list.
59
+ */
60
+ LIST* create(void) {
61
+ LIST* list;
62
+
63
+ //if (!(list = malloc(sizeof(LIST)))) return NULL;
64
+ list = ALLOC( LIST );
65
+
66
+ //fprintf(stderr, " create_list LIST: %p\n", list);
67
+
68
+ list->first = NULL;
69
+ return list;
70
+ }
71
+
72
+ /*
73
+ * Deletes the linked list and all of its contents. If you want to delete a
74
+ * list inside of a list, set recursions to 1. For lists inside of lists inside
75
+ * of the list, set it to 2; and so on. Setting it to 0 is for no recursions.
76
+ */
77
+ void del(LIST* list, size_t recursions) {
78
+ NODE* next;
79
+ NODE* curr = list->first;
80
+
81
+ while (curr != NULL) {
82
+ next = curr->next;
83
+
84
+ if (recursions == 0) {
85
+ //fprintf(stderr, " free_val: %p\n", curr->val);
86
+ free(curr->val);
87
+
88
+ } else {
89
+ //fprintf(stderr, " free_list: %p\n", list);
90
+ del((LIST*)curr->val, recursions - 1);
91
+ }
92
+
93
+ free(curr);
94
+ curr = next;
95
+ }
96
+ //fprintf(stderr, " free_list: %p\n", list);
97
+ free(list);
98
+ }
99
+
100
+ /*
101
+ * Documentation goes here.
102
+ */
103
+ void mark(LIST* list, size_t recursions) {
104
+ NODE* next;
105
+ NODE* curr = list->first;
106
+
107
+ while (curr != NULL) {
108
+ next = curr->next;
109
+
110
+ if (recursions == 0) {
111
+ rb_gc_mark(*((VALUE*)(curr->val)));
112
+
113
+ } else {
114
+ mark((LIST*)curr->val, recursions - 1);
115
+ }
116
+
117
+ curr = next;
118
+ }
119
+ }
120
+
121
+ ///////////////
122
+ // Accessors //
123
+ ///////////////
124
+
125
+ /*
126
+ * Given a list and a key/value-ptr pair, create a node (and return that node).
127
+ * If NULL is returned, it means insertion failed.
128
+ * If the key already exists in the list, replace tells it to delete the old
129
+ * value and put in your new one. !replace means delete the new value.
130
+ */
131
+ NODE* insert(LIST* list, bool replace, size_t key, void* val) {
132
+ NODE *ins;
133
+
134
+ if (list->first == NULL) {
135
+ // List is empty
136
+
137
+ //if (!(ins = malloc(sizeof(NODE)))) return NULL;
138
+ ins = ALLOC(NODE);
139
+ ins->next = NULL;
140
+ ins->val = val;
141
+ ins->key = key;
142
+ list->first = ins;
143
+
144
+ return ins;
145
+
146
+ } else if (key < list->first->key) {
147
+ // Goes at the beginning of the list
148
+
149
+ //if (!(ins = malloc(sizeof(NODE)))) return NULL;
150
+ ins = ALLOC(NODE);
151
+ ins->next = list->first;
152
+ ins->val = val;
153
+ ins->key = key;
154
+ list->first = ins;
155
+
156
+ return ins;
157
+ }
158
+
159
+ // Goes somewhere else in the list.
160
+ ins = find_nearest_from(list->first, key);
161
+
162
+ if (ins->key == key) {
163
+ // key already exists
164
+ if (replace) {
165
+ free(ins->val);
166
+ ins->val = val;
167
+
168
+ } else {
169
+ free(val);
170
+ }
171
+
172
+ return ins;
173
+
174
+ } else {
175
+ return insert_after(ins, key, val);
176
+ }
177
+ }
178
+
179
+ /*
180
+ * Documentation goes here.
181
+ */
182
+ NODE* insert_after(NODE* node, size_t key, void* val) {
183
+ NODE* ins;
184
+
185
+ //if (!(ins = malloc(sizeof(NODE)))) return NULL;
186
+ ins = ALLOC(NODE);
187
+
188
+ // insert 'ins' between 'node' and 'node->next'
189
+ ins->next = node->next;
190
+ node->next = ins;
191
+
192
+ // initialize our new node
193
+ ins->key = key;
194
+ ins->val = val;
195
+
196
+ return ins;
197
+ }
198
+
199
+ /*
200
+ * Analog functions list_insert but this insert copy of value.
201
+ */
202
+ NODE* insert_with_copy(LIST *list, size_t key, void *val, size_t size) {
203
+ void *copy_val = ALLOC_N(char, size);
204
+ memcpy(copy_val, val, size);
205
+
206
+
207
+ return insert(list, false, key, copy_val);
208
+ }
209
+ /*
210
+ * Returns the value pointer (not the node) for some key. Note that it doesn't
211
+ * free the memory for the value stored in the node -- that pointer gets
212
+ * returned! Only the node is destroyed.
213
+ */
214
+ void* remove(LIST* list, size_t key) {
215
+ NODE *f, *rm;
216
+ void* val;
217
+
218
+ if (!list->first || list->first->key > key) { // empty list or def. not present
219
+ return NULL;
220
+ }
221
+
222
+ if (list->first->key == key) {
223
+ val = list->first->val;
224
+ rm = list->first;
225
+
226
+ list->first = rm->next;
227
+ free(rm);
228
+
229
+ return val;
230
+ }
231
+
232
+ f = find_preceding_from(list->first, key);
233
+ if (!f || !f->next) { // not found, end of list
234
+ return NULL;
235
+ }
236
+
237
+ if (f->next->key == key) {
238
+ // remove the node
239
+ rm = f->next;
240
+ f->next = rm->next;
241
+
242
+ // get the value and free the memory for the node
243
+ val = rm->val;
244
+ free(rm);
245
+
246
+ return val;
247
+ }
248
+
249
+ return NULL; // not found, middle of list
250
+ }
251
+
252
+
253
+ /*
254
+ * Recursive removal of lists that may contain sub-lists. Stores the value ultimately removed in rm.
255
+ *
256
+ * FIXME: Could be made slightly faster by using a variety of find which also returns the previous node. This way,
257
+ * FIXME: we can remove directly instead of calling remove() and doing the search over again.
258
+ */
259
+ bool remove_recursive(LIST* list, const size_t* coords, const size_t* offset, size_t r, const size_t& dim, void* rm) {
260
+
261
+ if (r < dim-1) { // nodes here are lists
262
+ // find the current coordinates in the list
263
+ NODE* n = find(list, coords[r] + offset[r]);
264
+
265
+ if (n) {
266
+ // from that sub-list, call remove_recursive.
267
+ bool remove_parent = remove_recursive(reinterpret_cast<LIST*>(n->val), coords, offset, r+1, dim, rm);
268
+
269
+ if (remove_parent) { // now empty -- so remove the sub-list
270
+ free(remove(list, coords[r] + offset[r]));
271
+ }
272
+ }
273
+
274
+ } else { // nodes here are not lists, but actual values
275
+ rm = remove(list, coords[r] + offset[r]);
276
+ }
277
+
278
+ if (!list->first) return true; // if current list is now empty, signal its removal
279
+
280
+ return false;
281
+ }
282
+
283
+ ///////////
284
+ // Tests //
285
+ ///////////
286
+
287
+
288
+ /////////////
289
+ // Utility //
290
+ /////////////
291
+
292
+ /*
293
+ * Find some element in the list and return the node ptr for that key.
294
+ */
295
+ NODE* find(LIST* list, size_t key) {
296
+ NODE* f;
297
+ if (!list->first) {
298
+ // empty list -- does not exist
299
+ return NULL;
300
+ }
301
+
302
+ // see if we can find it.
303
+ f = find_nearest_from(list->first, key);
304
+
305
+ if (!f || f->key == key) {
306
+ return f;
307
+ }
308
+
309
+ return NULL;
310
+ }
311
+
312
+ /*
313
+ * Finds the node that should go before whatever key we request, whether or not
314
+ * that key is present.
315
+ */
316
+ NODE* find_preceding_from(NODE* prev, size_t key) {
317
+ NODE* curr = prev->next;
318
+
319
+ if (!curr || key <= curr->key) {
320
+ return prev;
321
+
322
+ } else {
323
+ return find_preceding_from(curr, key);
324
+ }
325
+ }
326
+
327
+ /*
328
+ * Finds the node or, if not present, the node that it should follow. NULL
329
+ * indicates no preceding node.
330
+ */
331
+ NODE* find_nearest(LIST* list, size_t key) {
332
+ return find_nearest_from(list->first, key);
333
+ }
334
+
335
+ /*
336
+ * Finds a node or the one immediately preceding it if it doesn't exist.
337
+ */
338
+ NODE* find_nearest_from(NODE* prev, size_t key) {
339
+ NODE* f;
340
+
341
+ if (prev && prev->key == key) {
342
+ return prev;
343
+ }
344
+
345
+ f = find_preceding_from(prev, key);
346
+
347
+ if (!f->next) {
348
+ return f;
349
+
350
+ } else if (key == f->next->key) {
351
+ return f->next;
352
+
353
+ } else {
354
+ return prev;
355
+ }
356
+ }
357
+
358
+ /////////////////////////
359
+ // Copying and Casting //
360
+ /////////////////////////
361
+
362
+
363
+ /*
364
+ * Copy the contents of a list.
365
+ */
366
+ template <typename LDType, typename RDType>
367
+ void cast_copy_contents(LIST* lhs, const LIST* rhs, size_t recursions) {
368
+ NODE *lcurr, *rcurr;
369
+
370
+ if (rhs->first) {
371
+ // copy head node
372
+ rcurr = rhs->first;
373
+ lcurr = lhs->first = ALLOC( NODE );
374
+
375
+ while (rcurr) {
376
+ lcurr->key = rcurr->key;
377
+
378
+ if (recursions == 0) {
379
+ // contents is some kind of value
380
+
381
+ lcurr->val = ALLOC( LDType );
382
+
383
+ *reinterpret_cast<LDType*>(lcurr->val) = *reinterpret_cast<RDType*>( rcurr->val );
384
+
385
+ } else {
386
+ // contents is a list
387
+
388
+ lcurr->val = ALLOC( LIST );
389
+
390
+ cast_copy_contents<LDType, RDType>(
391
+ reinterpret_cast<LIST*>(lcurr->val),
392
+ reinterpret_cast<LIST*>(rcurr->val),
393
+ recursions-1
394
+ );
395
+ }
396
+
397
+ if (rcurr->next) {
398
+ lcurr->next = ALLOC( NODE );
399
+
400
+ } else {
401
+ lcurr->next = NULL;
402
+ }
403
+
404
+ lcurr = lcurr->next;
405
+ rcurr = rcurr->next;
406
+ }
407
+
408
+ } else {
409
+ lhs->first = NULL;
410
+ }
411
+ }
412
+
413
+ }} // end of namespace nm::list
414
+
415
+ extern "C" {
416
+
417
+ /*
418
+ * C access for copying the contents of a list.
419
+ */
420
+ void nm_list_cast_copy_contents(LIST* lhs, const LIST* rhs, dtype_t lhs_dtype, dtype_t rhs_dtype, size_t recursions) {
421
+ LR_DTYPE_TEMPLATE_TABLE(nm::list::cast_copy_contents, void, LIST*, const LIST*, size_t);
422
+
423
+ ttable[lhs_dtype][rhs_dtype](lhs, rhs, recursions);
424
+ }
425
+
426
+ /*
427
+ * Sets up a hash with an appropriate default values. That means that if recursions == 0, the default value is default_value,
428
+ * but if recursions == 1, the default value is going to be a hash with default value of default_value, and if recursions == 2,
429
+ * the default value is going to be a hash with default value of hash with default value of default_value, and so on.
430
+ * In other words, it's recursive.
431
+ */
432
+ static VALUE empty_list_to_hash(const dtype_t dtype, size_t recursions, VALUE default_value) {
433
+ VALUE h = rb_hash_new();
434
+ if (recursions) {
435
+ RHASH_IFNONE(h) = empty_list_to_hash(dtype, recursions-1, default_value);
436
+ } else {
437
+ RHASH_IFNONE(h) = default_value;
438
+ }
439
+ return h;
440
+ }
441
+
442
+
443
+ /*
444
+ * Copy a list to a Ruby Hash
445
+ */
446
+ VALUE nm_list_copy_to_hash(const LIST* l, const dtype_t dtype, size_t recursions, VALUE default_value) {
447
+
448
+ // Create a hash with default values appropriately specified for a sparse matrix.
449
+ VALUE h = empty_list_to_hash(dtype, recursions, default_value);
450
+
451
+ if (l->first) {
452
+ NODE* curr = l->first;
453
+
454
+ while (curr) {
455
+
456
+ size_t key = curr->key;
457
+
458
+ if (recursions == 0) { // content is some kind of value
459
+ rb_hash_aset(h, INT2FIX(key), rubyobj_from_cval(curr->val, dtype).rval);
460
+ } else { // content is a list
461
+ rb_hash_aset(h, INT2FIX(key), nm_list_copy_to_hash(reinterpret_cast<const LIST*>(curr->val), dtype, recursions-1, default_value));
462
+ }
463
+
464
+ curr = curr->next;
465
+
466
+ }
467
+
468
+ }
469
+
470
+ return h;
471
+ }
472
+
473
+
474
+ } // end of extern "C" block
475
+