pnmatrix 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/ext/nmatrix/binary_format.txt +53 -0
  3. data/ext/nmatrix/data/complex.h +388 -0
  4. data/ext/nmatrix/data/data.cpp +274 -0
  5. data/ext/nmatrix/data/data.h +651 -0
  6. data/ext/nmatrix/data/meta.h +64 -0
  7. data/ext/nmatrix/data/ruby_object.h +386 -0
  8. data/ext/nmatrix/extconf.rb +70 -0
  9. data/ext/nmatrix/math/asum.h +99 -0
  10. data/ext/nmatrix/math/cblas_enums.h +36 -0
  11. data/ext/nmatrix/math/cblas_templates_core.h +507 -0
  12. data/ext/nmatrix/math/gemm.h +241 -0
  13. data/ext/nmatrix/math/gemv.h +178 -0
  14. data/ext/nmatrix/math/getrf.h +255 -0
  15. data/ext/nmatrix/math/getrs.h +121 -0
  16. data/ext/nmatrix/math/imax.h +82 -0
  17. data/ext/nmatrix/math/laswp.h +165 -0
  18. data/ext/nmatrix/math/long_dtype.h +62 -0
  19. data/ext/nmatrix/math/magnitude.h +54 -0
  20. data/ext/nmatrix/math/math.h +751 -0
  21. data/ext/nmatrix/math/nrm2.h +165 -0
  22. data/ext/nmatrix/math/rot.h +117 -0
  23. data/ext/nmatrix/math/rotg.h +106 -0
  24. data/ext/nmatrix/math/scal.h +71 -0
  25. data/ext/nmatrix/math/trsm.h +336 -0
  26. data/ext/nmatrix/math/util.h +162 -0
  27. data/ext/nmatrix/math.cpp +1368 -0
  28. data/ext/nmatrix/nm_memory.h +60 -0
  29. data/ext/nmatrix/nmatrix.cpp +285 -0
  30. data/ext/nmatrix/nmatrix.h +476 -0
  31. data/ext/nmatrix/ruby_constants.cpp +151 -0
  32. data/ext/nmatrix/ruby_constants.h +106 -0
  33. data/ext/nmatrix/ruby_nmatrix.c +3130 -0
  34. data/ext/nmatrix/storage/common.cpp +77 -0
  35. data/ext/nmatrix/storage/common.h +183 -0
  36. data/ext/nmatrix/storage/dense/dense.cpp +1096 -0
  37. data/ext/nmatrix/storage/dense/dense.h +129 -0
  38. data/ext/nmatrix/storage/list/list.cpp +1628 -0
  39. data/ext/nmatrix/storage/list/list.h +138 -0
  40. data/ext/nmatrix/storage/storage.cpp +730 -0
  41. data/ext/nmatrix/storage/storage.h +99 -0
  42. data/ext/nmatrix/storage/yale/class.h +1139 -0
  43. data/ext/nmatrix/storage/yale/iterators/base.h +143 -0
  44. data/ext/nmatrix/storage/yale/iterators/iterator.h +131 -0
  45. data/ext/nmatrix/storage/yale/iterators/row.h +450 -0
  46. data/ext/nmatrix/storage/yale/iterators/row_stored.h +140 -0
  47. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +169 -0
  48. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +124 -0
  49. data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
  50. data/ext/nmatrix/storage/yale/yale.cpp +2074 -0
  51. data/ext/nmatrix/storage/yale/yale.h +203 -0
  52. data/ext/nmatrix/types.h +55 -0
  53. data/ext/nmatrix/util/io.cpp +279 -0
  54. data/ext/nmatrix/util/io.h +115 -0
  55. data/ext/nmatrix/util/sl_list.cpp +627 -0
  56. data/ext/nmatrix/util/sl_list.h +144 -0
  57. data/ext/nmatrix/util/util.h +78 -0
  58. data/lib/nmatrix/blas.rb +378 -0
  59. data/lib/nmatrix/cruby/math.rb +744 -0
  60. data/lib/nmatrix/enumerate.rb +253 -0
  61. data/lib/nmatrix/homogeneous.rb +241 -0
  62. data/lib/nmatrix/io/fortran_format.rb +138 -0
  63. data/lib/nmatrix/io/harwell_boeing.rb +221 -0
  64. data/lib/nmatrix/io/market.rb +263 -0
  65. data/lib/nmatrix/io/point_cloud.rb +189 -0
  66. data/lib/nmatrix/jruby/decomposition.rb +24 -0
  67. data/lib/nmatrix/jruby/enumerable.rb +13 -0
  68. data/lib/nmatrix/jruby/error.rb +4 -0
  69. data/lib/nmatrix/jruby/math.rb +501 -0
  70. data/lib/nmatrix/jruby/nmatrix_java.rb +840 -0
  71. data/lib/nmatrix/jruby/operators.rb +283 -0
  72. data/lib/nmatrix/jruby/slice.rb +264 -0
  73. data/lib/nmatrix/lapack_core.rb +181 -0
  74. data/lib/nmatrix/lapack_plugin.rb +44 -0
  75. data/lib/nmatrix/math.rb +953 -0
  76. data/lib/nmatrix/mkmf.rb +100 -0
  77. data/lib/nmatrix/monkeys.rb +137 -0
  78. data/lib/nmatrix/nmatrix.rb +1172 -0
  79. data/lib/nmatrix/rspec.rb +75 -0
  80. data/lib/nmatrix/shortcuts.rb +1163 -0
  81. data/lib/nmatrix/version.rb +39 -0
  82. data/lib/nmatrix/yale_functions.rb +118 -0
  83. data/lib/nmatrix.rb +28 -0
  84. data/spec/00_nmatrix_spec.rb +892 -0
  85. data/spec/01_enum_spec.rb +196 -0
  86. data/spec/02_slice_spec.rb +407 -0
  87. data/spec/03_nmatrix_monkeys_spec.rb +80 -0
  88. data/spec/2x2_dense_double.mat +0 -0
  89. data/spec/4x4_sparse.mat +0 -0
  90. data/spec/4x5_dense.mat +0 -0
  91. data/spec/blas_spec.rb +215 -0
  92. data/spec/elementwise_spec.rb +311 -0
  93. data/spec/homogeneous_spec.rb +100 -0
  94. data/spec/io/fortran_format_spec.rb +88 -0
  95. data/spec/io/harwell_boeing_spec.rb +98 -0
  96. data/spec/io/test.rua +9 -0
  97. data/spec/io_spec.rb +159 -0
  98. data/spec/lapack_core_spec.rb +482 -0
  99. data/spec/leakcheck.rb +16 -0
  100. data/spec/math_spec.rb +1363 -0
  101. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  102. data/spec/nmatrix_yale_spec.rb +286 -0
  103. data/spec/rspec_monkeys.rb +56 -0
  104. data/spec/rspec_spec.rb +35 -0
  105. data/spec/shortcuts_spec.rb +474 -0
  106. data/spec/slice_set_spec.rb +162 -0
  107. data/spec/spec_helper.rb +172 -0
  108. data/spec/stat_spec.rb +214 -0
  109. data/spec/test.pcd +20 -0
  110. data/spec/utm5940.mtx +83844 -0
  111. metadata +295 -0
@@ -0,0 +1,627 @@
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 - 2014, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2012 - 2014, John Woods and the 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
+ // == sl_list.cpp
25
+ //
26
+ // Singly-linked list implementation
27
+
28
+ /*
29
+ * Standard Includes
30
+ */
31
+
32
+ #include <ruby.h>
33
+
34
+ /*
35
+ * Project Includes
36
+ */
37
+
38
+ #include "types.h"
39
+
40
+ #include "data/data.h"
41
+
42
+ #include "sl_list.h"
43
+
44
+ #include "storage/list/list.h"
45
+
46
+ namespace nm { namespace list {
47
+
48
+ /*
49
+ * Macros
50
+ */
51
+
52
+ #ifndef RHASH_SET_IFNONE
53
+ #define RHASH_SET_IFNONE(h, v) (RHASH(h)->ifnone = (v))
54
+ #endif
55
+
56
+ /*
57
+ * Global Variables
58
+ */
59
+
60
+
61
+ /*
62
+ * Forward Declarations
63
+ */
64
+
65
+ /*
66
+ * Functions
67
+ */
68
+
69
+ ////////////////
70
+ // Lifecycle //
71
+ ///////////////
72
+
73
+ /*
74
+ * Creates an empty linked list.
75
+ */
76
+ LIST* create(void) {
77
+ LIST* list = NM_ALLOC( LIST );
78
+ list->first = NULL;
79
+ return list;
80
+ }
81
+
82
+ /*
83
+ * Deletes the linked list and all of its contents. If you want to delete a
84
+ * list inside of a list, set recursions to 1. For lists inside of lists inside
85
+ * of the list, set it to 2; and so on. Setting it to 0 is for no recursions.
86
+ */
87
+ void del(LIST* list, size_t recursions) {
88
+ NODE* next;
89
+ NODE* curr = list->first;
90
+
91
+ while (curr != NULL) {
92
+ next = curr->next;
93
+
94
+ if (recursions == 0) {
95
+ //fprintf(stderr, " free_val: %p\n", curr->val);
96
+ nm_list_storage_completely_unregister_node(curr);
97
+ NM_FREE(curr->val);
98
+
99
+ } else {
100
+ //fprintf(stderr, " free_list: %p\n", list);
101
+ del((LIST*)curr->val, recursions - 1);
102
+ }
103
+
104
+ NM_FREE(curr);
105
+ curr = next;
106
+ }
107
+ //fprintf(stderr, " free_list: %p\n", list);
108
+ NM_FREE(list);
109
+ }
110
+
111
+ /*
112
+ * Documentation goes here.
113
+ */
114
+ void mark(LIST* list, size_t recursions) {
115
+ NODE* next;
116
+ NODE* curr = list->first;
117
+
118
+ while (curr != NULL) {
119
+ next = curr->next;
120
+
121
+ if (recursions == 0) {
122
+ rb_gc_mark(*((VALUE*)(curr->val)));
123
+
124
+ } else {
125
+ mark((LIST*)curr->val, recursions - 1);
126
+ }
127
+
128
+ curr = next;
129
+ }
130
+ }
131
+
132
+ ///////////////
133
+ // Accessors //
134
+ ///////////////
135
+
136
+
137
+ /*
138
+ * Given a list, insert key/val as the first entry in the list. Does not do any
139
+ * checks, just inserts.
140
+ */
141
+ NODE* insert_first_node(LIST* list, size_t key, void* val, size_t val_size) {
142
+ NODE* ins = NM_ALLOC(NODE);
143
+ ins->next = list->first;
144
+
145
+ void* val_copy = NM_ALLOC_N(char, val_size);
146
+ memcpy(val_copy, val, val_size);
147
+
148
+ ins->val = reinterpret_cast<void*>(val_copy);
149
+ ins->key = key;
150
+ list->first = ins;
151
+
152
+ return ins;
153
+ }
154
+
155
+ NODE* insert_first_list(LIST* list, size_t key, LIST* l) {
156
+ NODE* ins = NM_ALLOC(NODE);
157
+ ins->next = list->first;
158
+
159
+ ins->val = reinterpret_cast<void*>(l);
160
+ ins->key = key;
161
+ list->first = ins;
162
+
163
+ return ins;
164
+ }
165
+
166
+
167
+ /*
168
+ * Given a list and a key/value-ptr pair, create a node (and return that node).
169
+ * If NULL is returned, it means insertion failed.
170
+ * If the key already exists in the list, replace tells it to delete the old
171
+ * value and put in your new one. !replace means delete the new value.
172
+ */
173
+ NODE* insert(LIST* list, bool replace, size_t key, void* val) {
174
+ NODE *ins;
175
+
176
+ if (list->first == NULL) {
177
+ // List is empty
178
+
179
+ //if (!(ins = malloc(sizeof(NODE)))) return NULL;
180
+ ins = NM_ALLOC(NODE);
181
+ ins->next = NULL;
182
+ ins->val = val;
183
+ ins->key = key;
184
+ list->first = ins;
185
+
186
+ return ins;
187
+
188
+ } else if (key < list->first->key) {
189
+ // Goes at the beginning of the list
190
+
191
+ //if (!(ins = malloc(sizeof(NODE)))) return NULL;
192
+ ins = NM_ALLOC(NODE);
193
+ ins->next = list->first;
194
+ ins->val = val;
195
+ ins->key = key;
196
+ list->first = ins;
197
+
198
+ return ins;
199
+ }
200
+
201
+ // Goes somewhere else in the list.
202
+ ins = find_nearest_from(list->first, key);
203
+
204
+ if (ins->key == key) {
205
+ // key already exists
206
+ if (replace) {
207
+ nm_list_storage_completely_unregister_node(ins);
208
+ NM_FREE(ins->val);
209
+ ins->val = val;
210
+ } else {
211
+ NM_FREE(val);
212
+ }
213
+
214
+ return ins;
215
+
216
+ } else {
217
+ return insert_after(ins, key, val);
218
+ }
219
+ }
220
+
221
+
222
+
223
+ /*
224
+ * Documentation goes here.
225
+ */
226
+ NODE* insert_after(NODE* node, size_t key, void* val) {
227
+ //if (!(ins = malloc(sizeof(NODE)))) return NULL;
228
+ NODE* ins = NM_ALLOC(NODE);
229
+
230
+ // insert 'ins' between 'node' and 'node->next'
231
+ ins->next = node->next;
232
+ node->next = ins;
233
+
234
+ // initialize our new node
235
+ ins->key = key;
236
+ ins->val = val;
237
+
238
+ return ins;
239
+ }
240
+
241
+
242
+ /*
243
+ * Insert a new node immediately after +node+, or replace the existing one if its key is a match.
244
+ */
245
+ NODE* replace_insert_after(NODE* node, size_t key, void* val, bool copy, size_t copy_size) {
246
+ if (node->next && node->next->key == key) {
247
+
248
+ // Should we copy into the current one or free and insert?
249
+ if (copy) memcpy(node->next->val, val, copy_size);
250
+ else {
251
+ NM_FREE(node->next->val);
252
+ node->next->val = val;
253
+ }
254
+
255
+ return node->next;
256
+
257
+ } else { // no next node, or if there is one, it's greater than the current key
258
+
259
+ if (copy) {
260
+ void* val_copy = NM_ALLOC_N(char, copy_size);
261
+ memcpy(val_copy, val, copy_size);
262
+ return insert_after(node, key, val_copy);
263
+ } else {
264
+ return insert_after(node, key, val);
265
+ }
266
+
267
+ }
268
+ }
269
+
270
+
271
+
272
+ /*
273
+ * Functions analogously to list::insert but this inserts a copy of the value instead of the original.
274
+ */
275
+ NODE* insert_copy(LIST *list, bool replace, size_t key, void *val, size_t size) {
276
+ void *copy_val = NM_ALLOC_N(char, size);
277
+ memcpy(copy_val, val, size);
278
+
279
+ return insert(list, replace, key, copy_val);
280
+ }
281
+
282
+
283
+ /*
284
+ * Returns the value pointer for some key. Doesn't free the memory for that value. Doesn't require a find operation,
285
+ * assumes finding has already been done. If rm is the first item in the list, prev should be NULL.
286
+ */
287
+ void* remove_by_node(LIST* list, NODE* prev, NODE* rm) {
288
+ if (!prev) list->first = rm->next;
289
+ else prev->next = rm->next;
290
+
291
+ void* val = rm->val;
292
+ NM_FREE(rm);
293
+
294
+ return val;
295
+ }
296
+
297
+
298
+ /*
299
+ * Returns the value pointer (not the node) for some key. Note that it doesn't
300
+ * free the memory for the value stored in the node -- that pointer gets
301
+ * returned! Only the node is destroyed.
302
+ */
303
+ void* remove_by_key(LIST* list, size_t key) {
304
+ NODE *f, *rm;
305
+ void* val;
306
+
307
+ if (!list->first || list->first->key > key) { // empty list or def. not present
308
+ return NULL;
309
+ }
310
+
311
+ if (list->first->key == key) {
312
+ val = list->first->val;
313
+ rm = list->first;
314
+
315
+ list->first = rm->next;
316
+ NM_FREE(rm);
317
+
318
+ return val;
319
+ }
320
+
321
+ f = find_preceding_from_node(list->first, key);
322
+ if (!f || !f->next) { // not found, end of list
323
+ return NULL;
324
+ }
325
+
326
+ if (f->next->key == key) {
327
+ // remove the node
328
+ rm = f->next;
329
+ f->next = rm->next;
330
+
331
+ // get the value and free the memory for the node
332
+ val = rm->val;
333
+ NM_FREE(rm);
334
+
335
+ return val;
336
+ }
337
+
338
+ return NULL; // not found, middle of list
339
+ }
340
+
341
+
342
+ bool node_is_within_slice(NODE* n, size_t coord, size_t len) {
343
+ if (!n) return false;
344
+ if (n->key >= coord && n->key < coord + len) return true;
345
+ else return false;
346
+ }
347
+
348
+
349
+ /*
350
+ * Recursive removal of lists that may contain sub-lists. Stores the value ultimately removed in rm.
351
+ */
352
+ bool remove_recursive(LIST* list, const size_t* coords, const size_t* offsets, const size_t* lengths, size_t r, const size_t& dim) {
353
+ // std::cerr << "remove_recursive: " << r << std::endl;
354
+ // find the current coordinates in the list
355
+ NODE* prev = find_preceding_from_list(list, coords[r] + offsets[r]);
356
+ NODE* n;
357
+ if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
358
+ else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
359
+
360
+ if (r < dim-1) { // nodes here are lists
361
+
362
+ while (n) {
363
+ // from that sub-list, call remove_recursive.
364
+ bool remove_parent = remove_recursive(reinterpret_cast<LIST*>(n->val), coords, offsets, lengths, r+1, dim);
365
+
366
+ if (remove_parent) { // now empty -- so remove the sub-list
367
+ // std::cerr << r << ": removing parent list at " << n->key << std::endl;
368
+ NM_FREE(remove_by_node(list, prev, n));
369
+
370
+ if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
371
+ else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
372
+ } else {
373
+ // Move forward to next node (list at n still exists)
374
+ prev = n;
375
+ n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
376
+ }
377
+
378
+ // Iterate to next one.
379
+ if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
380
+ else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
381
+ }
382
+
383
+ } else { // nodes here are not lists, but actual values
384
+
385
+ while (n) {
386
+ // std::cerr << r << ": removing node at " << n->key << std::endl;
387
+ NM_FREE(remove_by_node(list, prev, n));
388
+
389
+ if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
390
+ else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
391
+ }
392
+ }
393
+
394
+ if (!list->first) return true; // if current list is now empty, signal its removal
395
+
396
+ return false;
397
+ }
398
+
399
+ ///////////
400
+ // Tests //
401
+ ///////////
402
+
403
+
404
+ /////////////
405
+ // Utility //
406
+ /////////////
407
+
408
+ /*
409
+ * Find some element in the list and return the node ptr for that key.
410
+ */
411
+ NODE* find(LIST* list, size_t key) {
412
+ NODE* f;
413
+ if (!list->first) {
414
+ // empty list -- does not exist
415
+ return NULL;
416
+ }
417
+
418
+ // see if we can find it.
419
+ f = find_nearest_from(list->first, key);
420
+
421
+ if (!f || f->key == key) {
422
+ return f;
423
+ }
424
+
425
+ return NULL;
426
+ }
427
+
428
+
429
+
430
+ /*
431
+ * Find some element in the list and return the node ptr for that key.
432
+ */
433
+ NODE* find_with_preceding(LIST* list, size_t key, NODE*& prev) {
434
+ if (!prev) prev = list->first;
435
+ if (!prev) return NULL; // empty list, does not exist
436
+
437
+ if (prev->key == key) {
438
+ NODE* n = prev;
439
+ prev = NULL;
440
+ return n;
441
+ }
442
+
443
+ while (prev->next && prev->next->key < key) {
444
+ prev = prev->next;
445
+ }
446
+
447
+ return prev->next;
448
+ }
449
+
450
+
451
+
452
+
453
+ /*
454
+ * Finds the node that should go before whatever key we request, whether or not
455
+ * that key is present.
456
+ */
457
+ NODE* find_preceding_from_node(NODE* prev, size_t key) {
458
+ NODE* curr = prev->next;
459
+
460
+ if (!curr || key <= curr->key) {
461
+ return prev;
462
+
463
+ } else {
464
+ return find_preceding_from_node(curr, key);
465
+ }
466
+ }
467
+
468
+
469
+ /*
470
+ * Returns NULL if the key being sought is first in the list or *should* be first in the list but is absent. Otherwise
471
+ * returns the previous node to where that key is or should be.
472
+ */
473
+ NODE* find_preceding_from_list(LIST* l, size_t key) {
474
+ NODE* n = l->first;
475
+ if (!n || n->key >= key) return NULL;
476
+ else return find_preceding_from_node(n, key);
477
+ }
478
+
479
+ /*
480
+ * Finds the node or, if not present, the node that it should follow. NULL
481
+ * indicates no preceding node.
482
+ */
483
+ NODE* find_nearest(LIST* list, size_t key) {
484
+ return find_nearest_from(list->first, key);
485
+ }
486
+
487
+ /*
488
+ * Finds a node or the one immediately preceding it if it doesn't exist.
489
+ */
490
+ NODE* find_nearest_from(NODE* prev, size_t key) {
491
+ NODE* f;
492
+
493
+ if (prev && prev->key == key) {
494
+ return prev;
495
+ }
496
+
497
+ f = find_preceding_from_node(prev, key);
498
+
499
+ if (!f->next) { // key exceeds final node; return final node.
500
+ return f;
501
+
502
+ } else if (key == f->next->key) { // node already present; return location
503
+ return f->next;
504
+
505
+ } else {
506
+ return f;
507
+ }
508
+ }
509
+
510
+ /////////////////////////
511
+ // Copying and Casting //
512
+ /////////////////////////
513
+
514
+
515
+ /*
516
+ * Copy the contents of a list.
517
+ */
518
+ template <typename LDType, typename RDType>
519
+ void cast_copy_contents(LIST* lhs, const LIST* rhs, size_t recursions) {
520
+ NODE *lcurr, *rcurr;
521
+
522
+ if (rhs->first) {
523
+ // copy head node
524
+ rcurr = rhs->first;
525
+ lcurr = lhs->first = NM_ALLOC( NODE );
526
+
527
+ while (rcurr) {
528
+ lcurr->key = rcurr->key;
529
+
530
+ if (recursions == 0) {
531
+ // contents is some kind of value
532
+
533
+ lcurr->val = NM_ALLOC( LDType );
534
+
535
+ *reinterpret_cast<LDType*>(lcurr->val) = *reinterpret_cast<RDType*>( rcurr->val );
536
+
537
+ } else {
538
+ // contents is a list
539
+
540
+ lcurr->val = NM_ALLOC( LIST );
541
+
542
+ cast_copy_contents<LDType, RDType>(
543
+ reinterpret_cast<LIST*>(lcurr->val),
544
+ reinterpret_cast<LIST*>(rcurr->val),
545
+ recursions-1
546
+ );
547
+ }
548
+
549
+ if (rcurr->next) {
550
+ lcurr->next = NM_ALLOC( NODE );
551
+
552
+ } else {
553
+ lcurr->next = NULL;
554
+ }
555
+
556
+ lcurr = lcurr->next;
557
+ rcurr = rcurr->next;
558
+ }
559
+
560
+ } else {
561
+ lhs->first = NULL;
562
+ }
563
+ }
564
+
565
+ }} // end of namespace nm::list
566
+
567
+ extern "C" {
568
+
569
+ /*
570
+ * C access for copying the contents of a list.
571
+ */
572
+ void nm_list_cast_copy_contents(LIST* lhs, const LIST* rhs, nm::dtype_t lhs_dtype, nm::dtype_t rhs_dtype, size_t recursions) {
573
+ LR_DTYPE_TEMPLATE_TABLE(nm::list::cast_copy_contents, void, LIST*, const LIST*, size_t);
574
+
575
+ ttable[lhs_dtype][rhs_dtype](lhs, rhs, recursions);
576
+ }
577
+
578
+ /*
579
+ * Sets up a hash with an appropriate default values. That means that if recursions == 0, the default value is default_value,
580
+ * but if recursions == 1, the default value is going to be a hash with default value of default_value, and if recursions == 2,
581
+ * the default value is going to be a hash with default value of hash with default value of default_value, and so on.
582
+ * In other words, it's recursive.
583
+ */
584
+ static VALUE empty_list_to_hash(const nm::dtype_t dtype, size_t recursions, VALUE default_value) {
585
+ VALUE h = rb_hash_new();
586
+ if (recursions) {
587
+ RHASH_SET_IFNONE(h, empty_list_to_hash(dtype, recursions-1, default_value));
588
+ } else {
589
+ RHASH_SET_IFNONE(h, default_value);
590
+ }
591
+ return h;
592
+ }
593
+
594
+
595
+ /*
596
+ * Copy a list to a Ruby Hash
597
+ */
598
+ VALUE nm_list_copy_to_hash(const LIST* l, const nm::dtype_t dtype, size_t recursions, VALUE default_value) {
599
+
600
+ // Create a hash with default values appropriately specified for a sparse matrix.
601
+ VALUE h = empty_list_to_hash(dtype, recursions, default_value);
602
+
603
+ if (l->first) {
604
+ NODE* curr = l->first;
605
+
606
+ while (curr) {
607
+
608
+ size_t key = curr->key;
609
+
610
+ if (recursions == 0) { // content is some kind of value
611
+ rb_hash_aset(h, INT2FIX(key), nm::rubyobj_from_cval(curr->val, dtype).rval);
612
+ } else { // content is a list
613
+ rb_hash_aset(h, INT2FIX(key), nm_list_copy_to_hash(reinterpret_cast<const LIST*>(curr->val), dtype, recursions-1, default_value));
614
+ }
615
+
616
+ curr = curr->next;
617
+
618
+ }
619
+
620
+ }
621
+
622
+ return h;
623
+ }
624
+
625
+
626
+ } // end of extern "C" block
627
+