pnmatrix 1.2.4

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 (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
+