nmatrix 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
data/ext/nmatrix/list.c DELETED
@@ -1,774 +0,0 @@
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
- // == list.c
25
- //
26
- // List-of-lists n-dimensional matrix storage. Uses singly-linked
27
- // lists.
28
-
29
- #ifndef LIST_C
30
- # define LIST_C
31
-
32
- #include <ruby.h>
33
-
34
- #include "nmatrix.h"
35
-
36
- extern VALUE nm_eStorageTypeError;
37
-
38
-
39
- /* Calculate the max number of elements in the list storage structure, based on shape and rank */
40
- inline size_t count_storage_max_elements(const STORAGE* s) {
41
- return count_dense_storage_elements((DENSE_STORAGE*)s);
42
- }
43
-
44
- static size_t count_list_storage_elements_r(const LIST* l, size_t recursions) {
45
- size_t count = 0;
46
- NODE* curr = l->first;
47
- if (recursions) {
48
- while (curr) {
49
- count += count_list_storage_elements_r(curr->val, recursions-1);
50
- curr = curr->next;
51
- }
52
- } else {
53
- while (curr) {
54
- ++count;
55
- curr = curr->next;
56
- }
57
- }
58
- return count;
59
- }
60
-
61
-
62
- // Count non-zero elements. See also count_list_storage_nd_elements.
63
- size_t count_list_storage_elements(const LIST_STORAGE* s) {
64
- return count_list_storage_elements_r(s->rows, s->rank-1);
65
- }
66
-
67
-
68
- // Count non-diagonal non-zero elements
69
- size_t count_list_storage_nd_elements(const LIST_STORAGE* s) {
70
- NODE *i_curr, *j_curr;
71
- size_t count = 0;
72
- if (s->rank != 2) rb_raise(rb_eNotImpError, "non-diagonal element counting only defined for rank = 2");
73
-
74
- for (i_curr = s->rows->first; i_curr; i_curr = i_curr->next) {
75
- for (j_curr = ((LIST*)(i_curr->val))->first; j_curr; j_curr = j_curr->next) {
76
- if (i_curr->key != j_curr->key) ++count;
77
- }
78
- }
79
- return count;
80
- }
81
-
82
-
83
- /* Finds the node that should go before whatever key we request, whether or not that key is present */
84
- static NODE* list_find_preceding_from(NODE* prev, size_t key) {
85
- NODE* curr = prev->next;
86
-
87
- if (!curr || key <= curr->key) return prev;
88
- return list_find_preceding_from(curr, key);
89
- }
90
-
91
-
92
- /* Finds a node or the one immediately preceding it if it doesn't exist */
93
- static NODE* list_find_nearest_from(NODE* prev, size_t key) {
94
- NODE* f;
95
-
96
- if (prev && prev->key == key) return prev;
97
-
98
- f = list_find_preceding_from(prev, key);
99
-
100
- if (!f->next) return f;
101
- else if (key == f->next->key) return f->next;
102
- else return prev;
103
- }
104
-
105
-
106
- /* Finds the node or, if not present, the node that it should follow.
107
- * NULL indicates no preceding node. */
108
- //static NODE* list_find_nearest(LIST* list, size_t key) {
109
- // return list_find_nearest_from(list->first, key);
110
- //}
111
-
112
-
113
- /* Find some element in the list and return the node ptr for that key. */
114
- static NODE* list_find(LIST* list, size_t key) {
115
- NODE* f;
116
- if (!list->first) return NULL; // empty list -- does not exist
117
-
118
- // see if we can find it.
119
- f = list_find_nearest_from(list->first, key);
120
- if (!f || f->key == key) return f;
121
- return NULL;
122
- }
123
-
124
-
125
-
126
- /* Get the contents of some set of coordinates. Note: Does not make a copy! Don't free! */
127
- void* list_storage_get(LIST_STORAGE* s, size_t* coords) {
128
- //LIST_STORAGE* s = (LIST_STORAGE*)(t);
129
- size_t r;
130
- NODE* n;
131
- LIST* l = s->rows;
132
-
133
- for (r = s->rank; r > 1; --r) {
134
- n = list_find(l, coords[s->rank - r]);
135
- if (n) l = n->val;
136
- else return s->default_val;
137
- }
138
-
139
- n = list_find(l, coords[s->rank - r]);
140
- if (n) return n->val;
141
- else return s->default_val;
142
- }
143
-
144
-
145
- /* Returns the value pointer (not the node) for some key. Note that it doesn't free the memory
146
- * for the value stored in the node -- that pointer gets returned! Only the node is destroyed.
147
- */
148
- static void* list_remove(LIST* list, size_t key) {
149
- NODE *f, *rm;
150
- void* val;
151
-
152
- if (!list->first || list->first->key > key) return NULL; // empty list or def. not present
153
-
154
- if (list->first->key == key) {
155
- val = list->first->val;
156
- rm = list->first;
157
- list->first = rm->next;
158
- free(rm);
159
- return val;
160
- }
161
-
162
- f = list_find_preceding_from(list->first, key);
163
- if (!f || !f->next) return NULL; // not found, end of list
164
-
165
- if (f->next->key == key) {
166
- // remove the node
167
- rm = f->next;
168
- f->next = rm->next;
169
-
170
- // get the value and free the memory for the node
171
- val = rm->val;
172
- free(rm);
173
- return val;
174
- }
175
-
176
- return NULL; // not found, middle of list
177
- }
178
-
179
-
180
- /// TODO: Speed up removal.
181
- void* list_storage_remove(LIST_STORAGE* s, size_t* coords) {
182
- int r;
183
- NODE *n = NULL;
184
- LIST* l = s->rows;
185
- void* rm = NULL;
186
-
187
- // keep track of where we are in the traversals
188
- NODE** stack = ALLOCA_N( NODE*, s->rank - 1 );
189
-
190
- for (r = (int)(s->rank); r > 1; --r) {
191
- n = list_find(l, coords[s->rank - r]); // does this row exist in the matrix?
192
-
193
- if (!n) { // not found
194
- free(stack);
195
- return NULL;
196
- } else { // found
197
- stack[s->rank - r] = n;
198
- l = n->val;
199
- }
200
- }
201
-
202
- rm = list_remove(l, coords[s->rank - r]);
203
-
204
- // if we removed something, we may now need to remove parent lists
205
- if (rm) {
206
- for (r = (int)(s->rank) - 2; r >= 0; --r) { // walk back down the stack
207
- if (((LIST*)(stack[r]->val))->first == NULL)
208
- free(list_remove(stack[r]->val, coords[r]));
209
- else
210
- break; // no need to continue unless we just deleted one.
211
- }
212
- }
213
-
214
- return rm;
215
- }
216
-
217
-
218
- /* Creates an empty linked list */
219
- static LIST* create_list() {
220
- LIST* list;
221
- //if (!(list = malloc(sizeof(LIST)))) return NULL;
222
- list = ALLOC( LIST );
223
-
224
- //fprintf(stderr, " create_list LIST: %p\n", list);
225
-
226
- list->first = NULL;
227
- return list;
228
- }
229
-
230
-
231
- static NODE* list_insert_after(NODE* node, size_t key, void* val) {
232
- NODE* ins;
233
-
234
- //if (!(ins = malloc(sizeof(NODE)))) return NULL;
235
- ins = ALLOC(NODE);
236
-
237
- // insert 'ins' between 'node' and 'node->next'
238
- ins->next = node->next;
239
- node->next = ins;
240
-
241
- // initialize our new node
242
- ins->key = key;
243
- ins->val = val;
244
-
245
- return ins;
246
- }
247
-
248
-
249
-
250
- /* Given a list and a key/value-ptr pair, create a node (and return that node).
251
- * If NULL is returned, it means insertion failed.
252
- * If the key already exists in the list, replace tells it to delete the old value
253
- * and put in your new one. !replace means delete the new value.
254
- */
255
- static NODE* list_insert(LIST* list, bool replace, size_t key, void* val) {
256
- NODE *ins;
257
-
258
- if (list->first == NULL) { // List is empty
259
- //if (!(ins = malloc(sizeof(NODE)))) return NULL;
260
- ins = ALLOC(NODE);
261
- ins->next = NULL;
262
- ins->val = val;
263
- ins->key = key;
264
- list->first = ins;
265
- return ins;
266
-
267
- } else if (key < list->first->key) { // Goes at the beginning of the list
268
- //if (!(ins = malloc(sizeof(NODE)))) return NULL;
269
- ins = ALLOC(NODE);
270
- ins->next = list->first;
271
- ins->val = val;
272
- ins->key = key;
273
- list->first = ins;
274
- return ins;
275
- }
276
-
277
- // Goes somewhere else in the list.
278
- ins = list_find_nearest_from(list->first, key);
279
-
280
- if (ins->key == key) {
281
- // key already exists
282
- if (replace) {
283
- free(ins->val);
284
- ins->val = val;
285
- } else free(val);
286
- return ins;
287
-
288
- } else return list_insert_after(ins, key, val);
289
-
290
- }
291
-
292
-
293
-
294
- // TODO: Allow this function to accept an entire row and not just one value -- for slicing
295
- void* list_storage_insert(LIST_STORAGE* s, size_t* coords, void* val) {
296
- // Pretend ranks = 2
297
- // Then coords is going to be size 2
298
- // So we need to find out if some key already exists
299
- size_t r;
300
- NODE* n;
301
- LIST* l = s->rows;
302
-
303
- // drill down into the structure
304
- for (r = s->rank; r > 1; --r) {
305
- n = list_insert(l, false, coords[s->rank - r], create_list());
306
- l = n->val;
307
- }
308
-
309
- n = list_insert(l, true, coords[s->rank - r], val);
310
- return n->val;
311
- }
312
-
313
- // Creates a list-of-lists(-of-lists-of-lists-etc) storage framework for a matrix.
314
- //
315
- // Note: The pointers you pass in for shape and init_val become property of our new
316
- // storage. You don't need to free them, and you shouldn't re-use them.
317
- LIST_STORAGE* create_list_storage(int8_t dtype, size_t* shape, size_t rank, void* init_val) {
318
- LIST_STORAGE* s;
319
-
320
- s = ALLOC( LIST_STORAGE );
321
-
322
- s->rank = rank;
323
- s->shape = shape;
324
- s->dtype = dtype;
325
-
326
- s->rows = create_list();
327
-
328
- s->default_val = init_val;
329
-
330
- return s;
331
- }
332
-
333
-
334
- static void cast_copy_list_contents(LIST* lhs, LIST* rhs, int8_t lhs_dtype, int8_t rhs_dtype, size_t recursions) {
335
- NODE *lcurr, *rcurr;
336
-
337
- if (rhs->first) {
338
- // copy head node
339
- rcurr = rhs->first;
340
- lcurr = lhs->first = ALLOC( NODE );
341
-
342
- while (rcurr) {
343
- lcurr->key = rcurr->key;
344
-
345
- if (recursions == 0) { // contents is some kind of value
346
- lcurr->val = ALLOC_N(char, nm_sizeof[lhs_dtype]);
347
- //fprintf(stderr, " create_val: %p\n", lcurr->val);
348
-
349
- if (lhs_dtype == rhs_dtype) memcpy(lcurr->val, rcurr->val, nm_sizeof[lhs_dtype]);
350
- else SetFuncs[lhs_dtype][rhs_dtype](1, lcurr->val, 0, rcurr->val, 0);
351
-
352
- } else { // contents is a list
353
- lcurr->val = ALLOC( LIST );
354
- //fprintf(stderr, " create_list: %p\n", lcurr->val);
355
-
356
- cast_copy_list_contents(lcurr->val, rcurr->val, lhs_dtype, rhs_dtype, recursions-1);
357
- }
358
- if (rcurr->next) lcurr->next = ALLOC( NODE );
359
- else lcurr->next = NULL;
360
-
361
- lcurr = lcurr->next;
362
- rcurr = rcurr->next;
363
- }
364
- } else {
365
- lhs->first = NULL;
366
- }
367
- }
368
-
369
-
370
- /* Deletes the linked list and all of its contents. If you want to delete a list inside of a list,
371
- * set recursions to 1. For lists inside of lists inside of the list, set it to 2; and so on.
372
- * Setting it to 0 is for no recursions.
373
- */
374
- static void delete_list(LIST* list, size_t recursions) {
375
- NODE* next;
376
- NODE* curr = list->first;
377
-
378
- while (curr != NULL) {
379
- next = curr->next;
380
-
381
- if (recursions == 0) {
382
- //fprintf(stderr, " free_val: %p\n", curr->val);
383
- free(curr->val);
384
- } else {
385
- //fprintf(stderr, " free_list: %p\n", list);
386
- delete_list(curr->val, recursions-1);
387
- }
388
-
389
- free(curr);
390
- curr = next;
391
- }
392
- //fprintf(stderr, " free_list: %p\n", list);
393
- free(list);
394
- }
395
-
396
-
397
- // Copy dense into lists recursively
398
- //
399
- // TODO: This works, but could probably be cleaner (do we really need to pass coords around?)
400
- static bool cast_copy_list_contents_dense(LIST* lhs, const char* rhs, void* zero, int8_t l_dtype, int8_t r_dtype, size_t* pos, size_t* coords, const size_t* shape, size_t rank, size_t recursions) {
401
- NODE *prev;
402
- LIST *sub_list;
403
- bool added = false, added_list = false;
404
- void* insert_value;
405
-
406
- for (coords[rank-1-recursions] = 0; coords[rank-1-recursions] < shape[rank-1-recursions]; ++coords[rank-1-recursions], ++(*pos)) {
407
- //fprintf(stderr, "(%u)\t<%u, %u>: ", recursions, coords[0], coords[1]);
408
-
409
- if (recursions == 0) { // create nodes
410
- if (memcmp((char*)rhs + (*pos)*nm_sizeof[r_dtype], zero, nm_sizeof[r_dtype])) { // is not zero
411
- //fprintf(stderr, "inserting value\n");
412
-
413
- // Create a copy of our value that we will insert in the list
414
- insert_value = ALLOC_N(char, nm_sizeof[l_dtype]);
415
- cast_copy_value_single(insert_value, rhs + (*pos)*nm_sizeof[r_dtype], l_dtype, r_dtype);
416
-
417
- if (!lhs->first) prev = list_insert(lhs, false, coords[rank-1-recursions], insert_value);
418
- else prev = list_insert_after(prev, coords[rank-1-recursions], insert_value);
419
- added = true;
420
- } //else fprintf(stderr, "zero\n");
421
- // no need to do anything if the element is zero
422
- } else { // create lists
423
- //fprintf(stderr, "inserting list\n");
424
- // create a list as if there's something in the row in question, and then delete it if nothing turns out to be there
425
- sub_list = create_list();
426
-
427
- added_list = cast_copy_list_contents_dense(sub_list, rhs, zero, l_dtype, r_dtype, pos, coords, shape, rank, recursions-1);
428
-
429
- if (!added_list) { delete_list(sub_list, recursions-1); fprintf(stderr, "deleting list\n"); }// nothing added
430
- else if (!lhs->first) prev = list_insert(lhs, false, coords[rank-1-recursions], sub_list);
431
- else prev = list_insert_after(prev, coords[rank-1-recursions], sub_list);
432
-
433
- // added = (added || added_list);
434
-
435
- }
436
- }
437
-
438
- coords[rank-1-recursions] = 0;
439
- --(*pos);
440
-
441
- return added;
442
- }
443
-
444
-
445
-
446
- LIST_STORAGE* copy_list_storage(LIST_STORAGE* rhs) {
447
- LIST_STORAGE* lhs;
448
- size_t* shape;
449
- void* default_val = ALLOC_N(char, nm_sizeof[rhs->dtype]);
450
-
451
- //fprintf(stderr, "copy_list_storage\n");
452
-
453
- // allocate and copy shape
454
- shape = ALLOC_N(size_t, rhs->rank);
455
- memcpy(shape, rhs->shape, rhs->rank * sizeof(size_t));
456
- memcpy(default_val, rhs->default_val, nm_sizeof[rhs->dtype]);
457
-
458
- lhs = create_list_storage(rhs->dtype, shape, rhs->rank, default_val);
459
-
460
- if (lhs) {
461
- lhs->rows = create_list();
462
- cast_copy_list_contents(lhs->rows, rhs->rows, rhs->dtype, rhs->dtype, rhs->rank - 1);
463
- } else free(shape);
464
-
465
- return lhs;
466
- }
467
-
468
-
469
- LIST_STORAGE* cast_copy_list_storage(LIST_STORAGE* rhs, int8_t new_dtype) {
470
- LIST_STORAGE* lhs;
471
- size_t* shape;
472
- void* default_val = ALLOC_N(char, nm_sizeof[rhs->dtype]);
473
-
474
- //fprintf(stderr, "copy_list_storage\n");
475
-
476
- // allocate and copy shape
477
- shape = ALLOC_N(size_t, rhs->rank);
478
- memcpy(shape, rhs->shape, rhs->rank * sizeof(size_t));
479
-
480
- // copy default value
481
- if (new_dtype == rhs->dtype) memcpy(default_val, rhs->default_val, nm_sizeof[rhs->dtype]);
482
- else SetFuncs[new_dtype][rhs->dtype](1, default_val, 0, rhs->default_val, 0);
483
-
484
- lhs = create_list_storage(new_dtype, shape, rhs->rank, default_val);
485
-
486
- lhs->rows = create_list();
487
- cast_copy_list_contents(lhs->rows, rhs->rows, new_dtype, rhs->dtype, rhs->rank - 1);
488
-
489
- return lhs;
490
- }
491
-
492
-
493
-
494
- LIST_STORAGE* scast_copy_list_dense(const DENSE_STORAGE* rhs, int8_t l_dtype) {
495
- LIST_STORAGE* lhs;
496
- size_t pos = 0;
497
- void* l_default_val = ALLOC_N(char, nm_sizeof[l_dtype]);
498
- void* r_default_val = ALLOCA_N(char, nm_sizeof[rhs->dtype]); // clean up when finished with this function
499
-
500
- // allocate and copy shape and coords
501
- size_t *shape = ALLOC_N(size_t, rhs->rank), *coords = ALLOC_N(size_t, rhs->rank);
502
- memcpy(shape, rhs->shape, rhs->rank * sizeof(size_t));
503
- memset(coords, 0, rhs->rank * sizeof(size_t));
504
-
505
- // set list default_val to 0
506
- if (l_dtype == NM_ROBJ) *(VALUE*)l_default_val = INT2FIX(0);
507
- else memset(l_default_val, 0, nm_sizeof[l_dtype]);
508
-
509
- // need test default value for comparing to elements in dense matrix
510
- if (rhs->dtype == l_dtype) r_default_val = l_default_val;
511
- else if (rhs->dtype == NM_ROBJ) *(VALUE*)r_default_val = INT2FIX(0);
512
- else memset(r_default_val, 0, nm_sizeof[rhs->dtype]);
513
-
514
- lhs = create_list_storage(l_dtype, shape, rhs->rank, l_default_val);
515
-
516
- lhs->rows = create_list();
517
- cast_copy_list_contents_dense(lhs->rows, rhs->elements, r_default_val, l_dtype, rhs->dtype, &pos, coords, rhs->shape, rhs->rank, rhs->rank - 1);
518
-
519
- return lhs;
520
- }
521
-
522
-
523
- LIST_STORAGE* scast_copy_list_yale(const YALE_STORAGE* rhs, int8_t l_dtype) {
524
- LIST_STORAGE* lhs;
525
- NODE *last_added, *last_row_added = NULL;
526
- LIST* curr_row;
527
- y_size_t ija, ija_next, i, jj;
528
- bool add_diag;
529
- void* default_val = ALLOC_N(char, nm_sizeof[l_dtype]);
530
- void* R_ZERO = (char*)(rhs->a) + rhs->shape[0]*nm_sizeof[rhs->dtype];
531
- void* insert_val;
532
-
533
- // allocate and copy shape
534
- size_t *shape = ALLOC_N(size_t, rhs->rank);
535
- shape[0] = rhs->shape[0]; shape[1] = rhs->shape[1];
536
-
537
- // copy default value from the zero location in the Yale matrix
538
- SetFuncs[l_dtype][rhs->dtype](1, default_val, 0, R_ZERO, 0);
539
-
540
- lhs = create_list_storage(l_dtype, shape, rhs->rank, default_val);
541
-
542
- if (rhs->rank != 2)
543
- rb_raise(nm_eStorageTypeError, "can only convert matrices of rank 2 from yale");
544
-
545
- // Walk through rows and columns as if RHS were a dense matrix
546
- for (i = 0; i < rhs->shape[0]; ++i) {
547
-
548
- // Get boundaries of beginning and end of row
549
- YaleGetIJA(ija, rhs, i);
550
- YaleGetIJA(ija_next, rhs, i+1);
551
-
552
- // Are we going to need to add a diagonal for this row?
553
- if (!memcmp((char*)(rhs->a) + i*nm_sizeof[rhs->dtype], R_ZERO, nm_sizeof[rhs->dtype])) add_diag = false; // zero
554
- else add_diag = true; // nonzero diagonal
555
-
556
-
557
- if (ija < ija_next || add_diag) {
558
-
559
- curr_row = create_list();
560
- last_added = NULL;
561
-
562
- while (ija < ija_next) {
563
- YaleGetIJA(jj, rhs, ija); // what column number is this?
564
-
565
- // Is there a nonzero diagonal item between the previously added item and the current one?
566
- if (jj > i && add_diag) {
567
- // Allocate and copy insertion value
568
- insert_val = ALLOC_N(char, nm_sizeof[l_dtype]);
569
- SetFuncs[l_dtype][rhs->dtype](1, insert_val, 0, (char*)(rhs->a) + i*nm_sizeof[rhs->dtype], 0);
570
-
571
- // insert the item in the list at the appropriate location
572
- if (last_added) last_added = list_insert_after(last_added, i, insert_val);
573
- else last_added = list_insert(curr_row, false, i, insert_val);
574
-
575
- add_diag = false; // don't add again!
576
- }
577
-
578
- // now allocate and add the current item
579
- insert_val = ALLOC_N(char, nm_sizeof[l_dtype]);
580
- SetFuncs[l_dtype][rhs->dtype](1, insert_val, 0, (char*)(rhs->a) + ija*nm_sizeof[rhs->dtype], 0);
581
-
582
- if (last_added) last_added = list_insert_after(last_added, jj, insert_val);
583
- else last_added = list_insert(curr_row, false, jj, insert_val);
584
-
585
- ++ija; // move to next entry in Yale matrix
586
- }
587
-
588
- if (add_diag) { // still haven't added the diagonal.
589
- insert_val = ALLOC_N(char, nm_sizeof[l_dtype]);
590
- SetFuncs[l_dtype][rhs->dtype](1, insert_val, 0, (char*)(rhs->a) + i*nm_sizeof[rhs->dtype], 0);
591
-
592
- // insert the item in the list at the appropriate location
593
- if (last_added) last_added = list_insert_after(last_added, i, insert_val);
594
- else last_added = list_insert(curr_row, false, i, insert_val);
595
- }
596
-
597
- // Now add the list at the appropriate location
598
- if (last_row_added) last_row_added = list_insert_after(last_row_added, i, curr_row);
599
- else last_row_added = list_insert(lhs->rows, false, i, curr_row);
600
- }
601
-
602
- } // end of walk through rows
603
-
604
- return lhs;
605
- }
606
-
607
-
608
-
609
- // Do all values in a list == some value?
610
- static bool list_eqeq_value(const LIST* l, const void* v, size_t value_size, size_t recursions, size_t* checked) {
611
- NODE *next, *curr = l->first;
612
-
613
- while (curr) {
614
- next = curr->next;
615
-
616
- if (recursions == 0) {
617
- ++(*checked);
618
- if (memcmp(curr->val, v, value_size)) return false;
619
- } else if (!list_eqeq_value(curr->val, v, value_size, recursions-1, checked))
620
- return false;
621
-
622
- curr = next;
623
- }
624
- return true;
625
- }
626
-
627
-
628
- // Are all values in the two lists equal? If one is missing a value, but the other isn't, does the value in the list match
629
- // the default value?
630
- static bool list_eqeq_list(const LIST* left, const LIST* right, const void* left_val, const void* right_val, size_t value_size, size_t recursions, size_t* checked) {
631
- NODE *lnext, *lcurr = left->first, *rnext, *rcurr = right->first;
632
-
633
- //fprintf(stderr, "list_eqeq_list: recursions=%d\n", recursions);
634
-
635
- if (lcurr) lnext = lcurr->next;
636
- if (rcurr) rnext = rcurr->next;
637
-
638
- while (lcurr && rcurr) {
639
-
640
- if (lcurr->key == rcurr->key) { // MATCHING KEYS
641
- if (recursions == 0) {
642
- ++(*checked);
643
- if (memcmp(lcurr->val, rcurr->val, value_size)) return false;
644
- } else if (!list_eqeq_list(lcurr->val, rcurr->val, left_val, right_val, value_size, recursions-1, checked))
645
- return false;
646
-
647
- // increment both iterators
648
- rcurr = rnext;
649
- if (rcurr) rnext = rcurr->next;
650
- lcurr = lnext;
651
- if (lcurr) lnext = lcurr->next;
652
-
653
- } else if (lcurr->key < rcurr->key) { // NON-MATCHING KEYS
654
-
655
- if (recursions == 0) {
656
- // compare left entry to right default value
657
- ++(*checked);
658
- if (memcmp(lcurr->val, right_val, value_size)) return false;
659
- } else if (!list_eqeq_value(lcurr->val, right_val, value_size, recursions-1, checked))
660
- return false;
661
-
662
- // increment left iterator
663
- lcurr = lnext;
664
- if (lcurr) lnext = lcurr->next;
665
-
666
- } else { // if (rcurr->key < lcurr->key)
667
-
668
- if (recursions == 0) {
669
- // compare right entry to left default value
670
- ++(*checked);
671
- if (memcmp(rcurr->val, left_val, value_size)) return false;
672
- } else if (!list_eqeq_value(rcurr->val, left_val, value_size, recursions-1, checked))
673
- return false;
674
-
675
- // increment right iterator
676
- rcurr = rnext;
677
- if (rcurr) rnext = rcurr->next;
678
- }
679
-
680
- }
681
-
682
- // One final check, in case we get to the end of one list but not the other one.
683
- if (lcurr) { // nothing left in right-hand list
684
- if (memcmp(lcurr->val, right_val, value_size)) return false;
685
- } else if (rcurr) { // nothing left in left-hand list
686
- if (memcmp(rcurr->val, left_val, value_size)) return false;
687
- }
688
-
689
- // Nothing different between the two lists -- but make sure after this return that you compare the default values themselves,
690
- // if we haven't visited every value in the two matrices.
691
- return true;
692
- }
693
-
694
-
695
- // Do these two dense matrices of the same dtype have exactly the same contents?
696
- bool list_storage_eqeq(const LIST_STORAGE* left, const LIST_STORAGE* right) {
697
-
698
- // in certain cases, we need to keep track of the number of elements checked.
699
- size_t num_checked = 0,
700
- max_elements = count_storage_max_elements((STORAGE*)left),
701
- sz = nm_sizeof[left->dtype];
702
-
703
- if (!left->rows->first) {
704
- // fprintf(stderr, "!left->rows true\n");
705
- // Easy: both lists empty -- just compare default values
706
- if (!right->rows->first) return !memcmp(left->default_val, right->default_val, sz);
707
-
708
- // Left empty, right not empty. Do all values in right == left->default_val?
709
- if (!list_eqeq_value(right->rows, left->default_val, sz, left->rank-1, &num_checked)) return false;
710
-
711
- // If the matrix isn't full, we also need to compare default values.
712
- if (num_checked < max_elements) return !memcmp(left->default_val, right->default_val, sz);
713
-
714
- } else if (!right->rows->first) {
715
- // fprintf(stderr, "!right->rows true\n");
716
- // Right empty, left not empty. Do all values in left == right->default_val?
717
- if (!list_eqeq_value(left->rows, right->default_val, sz, left->rank-1, &num_checked)) return false;
718
-
719
- // If the matrix isn't full, we also need to compare default values.
720
- if (num_checked < max_elements) return !memcmp(left->default_val, right->default_val, sz);
721
-
722
- } else {
723
- // fprintf(stderr, "both matrices have entries\n");
724
- // Hardest case. Compare lists node by node. Let's make it simpler by requiring that both have the same default value
725
- if (!list_eqeq_list(left->rows, right->rows, left->default_val, right->default_val, sz, left->rank-1, &num_checked)) return false;
726
- if (num_checked < max_elements) return !memcmp(left->default_val, right->default_val, sz);
727
- }
728
-
729
- return true;
730
- }
731
-
732
-
733
- void delete_list_storage(LIST_STORAGE* s) {
734
- if (s) {
735
- //fprintf(stderr, "* Deleting list storage rows at %p\n", s->rows);
736
- delete_list( s->rows, s->rank - 1 );
737
-
738
- //fprintf(stderr, " Deleting list storage shape at %p\n", s->shape);
739
- free(s->shape);
740
- //fprintf(stderr, " Deleting list storage default_val at %p\n", s->default_val);
741
- free(s->default_val);
742
- //fprintf(stderr, " Deleting list storage at %p\n", s);
743
- free(s);
744
- }
745
- }
746
-
747
-
748
- static void mark_list(LIST* list, size_t recursions) {
749
- NODE* next;
750
- NODE* curr = list->first;
751
-
752
- while (curr != NULL) {
753
- next = curr->next;
754
- if (recursions == 0) rb_gc_mark(*((VALUE*)(curr->val)));
755
- else mark_list(curr->val, recursions-1);
756
- curr = next;
757
- }
758
- }
759
-
760
-
761
- void mark_list_storage(void* m) {
762
- LIST_STORAGE* storage;
763
-
764
- if (m) {
765
- storage = (LIST_STORAGE*)(((NMATRIX*)m)->storage);
766
- if (storage && storage->dtype == NM_ROBJ) {
767
- rb_gc_mark(*((VALUE*)(storage->default_val)));
768
- mark_list(storage->rows, storage->rank - 1);
769
- }
770
- }
771
- }
772
-
773
-
774
- #endif