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,730 @@
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
+ // == storage.cpp
25
+ //
26
+ // Code that is used by or involves more then one storage type.
27
+
28
+ /*
29
+ * Standard Includes
30
+ */
31
+
32
+ /*
33
+ * Project Includes
34
+ */
35
+
36
+ #include "data/data.h"
37
+
38
+ #include "storage.h"
39
+
40
+ #include "common.h"
41
+
42
+ /*
43
+ * Macros
44
+ */
45
+
46
+ /*
47
+ * Global Variables
48
+ */
49
+
50
+ extern "C" {
51
+
52
+ const char* const STYPE_NAMES[nm::NUM_STYPES] = {
53
+ "dense",
54
+ "list",
55
+ "yale"
56
+ };
57
+
58
+ } // end extern "C" block
59
+
60
+ /*
61
+ * Forward Declarations
62
+ */
63
+
64
+ namespace nm {
65
+
66
+
67
+ /*
68
+ * Functions
69
+ */
70
+
71
+ /////////////////////////
72
+ // Templated Functions //
73
+ /////////////////////////
74
+
75
+ namespace dense_storage {
76
+
77
+ template <typename LDType, typename RDType>
78
+ static void cast_copy_list_contents(LDType* lhs, const LIST* rhs, RDType* default_val,
79
+ size_t& pos, const size_t* shape, size_t dim, size_t max_elements, size_t recursions);
80
+
81
+ template <typename LDType, typename RDType>
82
+ static void cast_copy_list_default(LDType* lhs, RDType* default_val, size_t& pos,
83
+ const size_t* shape, size_t dim, size_t max_elements, size_t recursions);
84
+
85
+ /*
86
+ * Convert (by creating a copy) from list storage to dense storage.
87
+ */
88
+ template <typename LDType, typename RDType>
89
+ DENSE_STORAGE* create_from_list_storage(const LIST_STORAGE* rhs, dtype_t l_dtype) {
90
+ nm_list_storage_register(rhs);
91
+ // allocate and copy shape
92
+ size_t* shape = NM_ALLOC_N(size_t, rhs->dim);
93
+ memcpy(shape, rhs->shape, rhs->dim * sizeof(size_t));
94
+
95
+ DENSE_STORAGE* lhs = nm_dense_storage_create(l_dtype, shape, rhs->dim, NULL, 0);
96
+
97
+ // Position in lhs->elements.
98
+ size_t pos = 0;
99
+ size_t max_elements = nm_storage_count_max_elements(rhs);
100
+
101
+ //static void dense_storage_cast_copy_list_contents_template(LDType* lhs, const LIST* rhs, RDType* default_val, size_t& pos, const size_t* shape, size_t dim, size_t max_elements, size_t recursions)
102
+ // recursively copy the contents
103
+ if (rhs->src == rhs)
104
+ cast_copy_list_contents<LDType,RDType>(reinterpret_cast<LDType*>(lhs->elements),
105
+ rhs->rows,
106
+ reinterpret_cast<RDType*>(rhs->default_val),
107
+ pos, shape, lhs->dim, max_elements, rhs->dim-1);
108
+ else {
109
+ LIST_STORAGE *tmp = nm_list_storage_copy(rhs);
110
+ cast_copy_list_contents<LDType,RDType>(reinterpret_cast<LDType*>(lhs->elements),
111
+ tmp->rows,
112
+ reinterpret_cast<RDType*>(tmp->default_val),
113
+ pos, shape, lhs->dim, max_elements, tmp->dim-1);
114
+ nm_list_storage_delete(tmp);
115
+
116
+ }
117
+ nm_list_storage_unregister(rhs);
118
+
119
+ return lhs;
120
+ }
121
+
122
+
123
+
124
+
125
+ /*
126
+ * Create/allocate dense storage, copying into it the contents of a Yale matrix.
127
+ */
128
+ template <typename LDType, typename RDType>
129
+ DENSE_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype) {
130
+
131
+ nm_yale_storage_register(rhs);
132
+ // Position in rhs->elements.
133
+ IType* rhs_ija = reinterpret_cast<YALE_STORAGE*>(rhs->src)->ija;
134
+ RDType* rhs_a = reinterpret_cast<RDType*>(reinterpret_cast<YALE_STORAGE*>(rhs->src)->a);
135
+
136
+ // Allocate and set shape.
137
+ size_t* shape = NM_ALLOC_N(size_t, rhs->dim);
138
+ shape[0] = rhs->shape[0];
139
+ shape[1] = rhs->shape[1];
140
+
141
+ DENSE_STORAGE* lhs = nm_dense_storage_create(l_dtype, shape, rhs->dim, NULL, 0);
142
+ LDType* lhs_elements = reinterpret_cast<LDType*>(lhs->elements);
143
+
144
+ // Position in dense to write to.
145
+ size_t pos = 0;
146
+
147
+ LDType LCAST_ZERO = rhs_a[rhs->src->shape[0]];
148
+
149
+ // Walk through rows. For each entry we set in dense, increment pos.
150
+ for (size_t i = 0; i < shape[0]; ++i) {
151
+ IType ri = i + rhs->offset[0];
152
+
153
+ if (rhs_ija[ri] == rhs_ija[ri+1]) { // Check boundaries of row: is row empty? (Yes.)
154
+
155
+ // Write zeros in each column.
156
+ for (size_t j = 0; j < shape[1]; ++j) { // Move to next dense position.
157
+
158
+ // Fill in zeros and copy the diagonal entry for this empty row.
159
+ if (ri == j + rhs->offset[1]) lhs_elements[pos] = static_cast<LDType>(rhs_a[ri]);
160
+ else lhs_elements[pos] = LCAST_ZERO;
161
+
162
+ ++pos;
163
+ }
164
+
165
+ } else { // Row contains entries: write those in each column, interspersed with zeros.
166
+
167
+ // Get the first ija position of the row (as sliced)
168
+ IType ija = nm::yale_storage::binary_search_left_boundary(rhs, rhs_ija[ri], rhs_ija[ri+1]-1, rhs->offset[1]);
169
+
170
+ // What column is it?
171
+ IType next_stored_rj = rhs_ija[ija];
172
+
173
+ for (size_t j = 0; j < shape[1]; ++j) {
174
+ IType rj = j + rhs->offset[1];
175
+
176
+ if (rj == ri) { // at a diagonal in RHS
177
+ lhs_elements[pos] = static_cast<LDType>(rhs_a[ri]);
178
+
179
+ } else if (rj == next_stored_rj) { // column ID was found in RHS
180
+ lhs_elements[pos] = static_cast<LDType>(rhs_a[ija]); // Copy from rhs.
181
+
182
+ // Get next.
183
+ ++ija;
184
+
185
+ // Increment to next column ID (or go off the end).
186
+ if (ija < rhs_ija[ri+1]) next_stored_rj = rhs_ija[ija];
187
+ else next_stored_rj = rhs->src->shape[1];
188
+
189
+ } else { // rj < next_stored_rj
190
+
191
+ // Insert zero.
192
+ lhs_elements[pos] = LCAST_ZERO;
193
+ }
194
+
195
+ // Move to next dense position.
196
+ ++pos;
197
+ }
198
+ }
199
+ }
200
+ nm_yale_storage_unregister(rhs);
201
+
202
+ return lhs;
203
+ }
204
+
205
+
206
+ /*
207
+ * Copy list contents into dense recursively.
208
+ */
209
+ template <typename LDType, typename RDType>
210
+ static void cast_copy_list_contents(LDType* lhs, const LIST* rhs, RDType* default_val, size_t& pos, const size_t* shape, size_t dim, size_t max_elements, size_t recursions) {
211
+
212
+ NODE *curr = rhs->first;
213
+ int last_key = -1;
214
+
215
+ nm_list_storage_register_list(rhs, recursions);
216
+
217
+ for (size_t i = 0; i < shape[dim - 1 - recursions]; ++i, ++pos) {
218
+
219
+ if (!curr || (curr->key > (size_t)(last_key+1))) {
220
+
221
+ if (recursions == 0) lhs[pos] = static_cast<LDType>(*default_val);
222
+ else cast_copy_list_default<LDType,RDType>(lhs, default_val, pos, shape, dim, max_elements, recursions-1);
223
+
224
+ ++last_key;
225
+
226
+ } else {
227
+
228
+ if (recursions == 0) lhs[pos] = static_cast<LDType>(*reinterpret_cast<RDType*>(curr->val));
229
+ else cast_copy_list_contents<LDType,RDType>(lhs, (const LIST*)(curr->val),
230
+ default_val, pos, shape, dim, max_elements, recursions-1);
231
+
232
+ last_key = curr->key;
233
+ curr = curr->next;
234
+ }
235
+ }
236
+
237
+ nm_list_storage_unregister_list(rhs, recursions);
238
+
239
+ --pos;
240
+ }
241
+
242
+ /*
243
+ * Copy a set of default values into dense.
244
+ */
245
+ template <typename LDType,typename RDType>
246
+ static void cast_copy_list_default(LDType* lhs, RDType* default_val, size_t& pos, const size_t* shape, size_t dim, size_t max_elements, size_t recursions) {
247
+ for (size_t i = 0; i < shape[dim - 1 - recursions]; ++i, ++pos) {
248
+
249
+ if (recursions == 0) lhs[pos] = static_cast<LDType>(*default_val);
250
+ else cast_copy_list_default<LDType,RDType>(lhs, default_val, pos, shape, dim, max_elements, recursions-1);
251
+
252
+ }
253
+
254
+ --pos;
255
+ }
256
+
257
+
258
+ } // end of namespace dense_storage
259
+
260
+ namespace list_storage {
261
+
262
+
263
+ template <typename LDType, typename RDType>
264
+ static bool cast_copy_contents_dense(LIST* lhs, const RDType* rhs, RDType* zero, size_t& pos, size_t* coords, const size_t* shape, size_t dim, size_t recursions);
265
+
266
+ /*
267
+ * Creation of list storage from dense storage.
268
+ */
269
+ template <typename LDType, typename RDType>
270
+ LIST_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype, void* init) {
271
+ nm_dense_storage_register(rhs);
272
+
273
+ LDType* l_default_val = NM_ALLOC_N(LDType, 1);
274
+ RDType* r_default_val = NM_ALLOCA_N(RDType, 1); // clean up when finished with this function
275
+
276
+ // allocate and copy shape and coords
277
+ size_t *shape = NM_ALLOC_N(size_t, rhs->dim),
278
+ *coords = NM_ALLOC_N(size_t, rhs->dim);
279
+
280
+ memcpy(shape, rhs->shape, rhs->dim * sizeof(size_t));
281
+ memset(coords, 0, rhs->dim * sizeof(size_t));
282
+
283
+ // set list default_val to 0
284
+ if (init) *l_default_val = *reinterpret_cast<LDType*>(init);
285
+ else {
286
+ if (l_dtype == RUBYOBJ) *l_default_val = INT2FIX(0);
287
+ else *l_default_val = 0;
288
+ }
289
+
290
+ // need test default value for comparing to elements in dense matrix
291
+ if (rhs->dtype == l_dtype || rhs->dtype != RUBYOBJ) *r_default_val = static_cast<RDType>(*l_default_val);
292
+ else *r_default_val = nm::rubyobj_from_cval(l_default_val, l_dtype);
293
+
294
+
295
+ LIST_STORAGE* lhs = nm_list_storage_create(l_dtype, shape, rhs->dim, l_default_val);
296
+
297
+ nm_list_storage_register(lhs);
298
+
299
+ size_t pos = 0;
300
+
301
+ if (rhs->src == rhs)
302
+ list_storage::cast_copy_contents_dense<LDType,RDType>(lhs->rows,
303
+ reinterpret_cast<const RDType*>(rhs->elements),
304
+ r_default_val,
305
+ pos, coords, rhs->shape, rhs->dim, rhs->dim - 1);
306
+ else {
307
+ DENSE_STORAGE* tmp = nm_dense_storage_copy(rhs);
308
+ list_storage::cast_copy_contents_dense<LDType,RDType>(lhs->rows,
309
+ reinterpret_cast<const RDType*>(tmp->elements),
310
+ r_default_val,
311
+ pos, coords, rhs->shape, rhs->dim, rhs->dim - 1);
312
+
313
+ nm_dense_storage_delete(tmp);
314
+ }
315
+
316
+ nm_list_storage_unregister(lhs);
317
+ nm_dense_storage_unregister(rhs);
318
+
319
+ return lhs;
320
+ }
321
+
322
+
323
+
324
+ /*
325
+ * Creation of list storage from yale storage.
326
+ */
327
+ template <typename LDType, typename RDType>
328
+ LIST_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype) {
329
+ // allocate and copy shape
330
+ nm_yale_storage_register(rhs);
331
+
332
+ size_t *shape = NM_ALLOC_N(size_t, rhs->dim);
333
+ shape[0] = rhs->shape[0]; shape[1] = rhs->shape[1];
334
+
335
+ RDType* rhs_a = reinterpret_cast<RDType*>(reinterpret_cast<YALE_STORAGE*>(rhs->src)->a);
336
+ RDType R_ZERO = rhs_a[ rhs->src->shape[0] ];
337
+
338
+ // copy default value from the zero location in the Yale matrix
339
+ LDType* default_val = NM_ALLOC_N(LDType, 1);
340
+ *default_val = static_cast<LDType>(R_ZERO);
341
+
342
+ LIST_STORAGE* lhs = nm_list_storage_create(l_dtype, shape, rhs->dim, default_val);
343
+
344
+ if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "Can only convert matrices of dim 2 from yale.");
345
+
346
+ IType* rhs_ija = reinterpret_cast<YALE_STORAGE*>(rhs->src)->ija;
347
+
348
+ NODE *last_row_added = NULL;
349
+ // Walk through rows and columns as if RHS were a dense matrix
350
+ for (IType i = 0; i < shape[0]; ++i) {
351
+ IType ri = i + rhs->offset[0];
352
+
353
+ NODE *last_added = NULL;
354
+
355
+ // Get boundaries of beginning and end of row
356
+ IType ija = rhs_ija[ri],
357
+ ija_next = rhs_ija[ri+1];
358
+
359
+ // Are we going to need to add a diagonal for this row?
360
+ bool add_diag = false;
361
+ if (rhs_a[ri] != R_ZERO) add_diag = true; // non-zero and located within the bounds of the slice
362
+
363
+ if (ija < ija_next || add_diag) {
364
+ ija = nm::yale_storage::binary_search_left_boundary(rhs, ija, ija_next-1, rhs->offset[1]);
365
+
366
+ LIST* curr_row = list::create();
367
+
368
+ LDType* insert_val;
369
+
370
+ while (ija < ija_next) {
371
+ // Find first column in slice
372
+ IType rj = rhs_ija[ija];
373
+ IType j = rj - rhs->offset[1];
374
+
375
+ // Is there a nonzero diagonal item between the previously added item and the current one?
376
+ if (rj > ri && add_diag) {
377
+ // Allocate and copy insertion value
378
+ insert_val = NM_ALLOC_N(LDType, 1);
379
+ *insert_val = static_cast<LDType>(rhs_a[ri]);
380
+
381
+ // Insert the item in the list at the appropriate location.
382
+ // What is the appropriate key? Well, it's definitely right(i)==right(j), but the
383
+ // rj index has already been advanced past ri. So we should treat ri as the column and
384
+ // subtract offset[1].
385
+ if (last_added) last_added = list::insert_after(last_added, ri - rhs->offset[1], insert_val);
386
+ else last_added = list::insert(curr_row, false, ri - rhs->offset[1], insert_val);
387
+
388
+ // don't add again!
389
+ add_diag = false;
390
+ }
391
+
392
+ // now allocate and add the current item
393
+ insert_val = NM_ALLOC_N(LDType, 1);
394
+ *insert_val = static_cast<LDType>(rhs_a[ija]);
395
+
396
+ if (last_added) last_added = list::insert_after(last_added, j, insert_val);
397
+ else last_added = list::insert(curr_row, false, j, insert_val);
398
+
399
+ ++ija; // move to next entry in Yale matrix
400
+ }
401
+
402
+ if (add_diag) {
403
+
404
+ // still haven't added the diagonal.
405
+ insert_val = NM_ALLOC_N(LDType, 1);
406
+ *insert_val = static_cast<LDType>(rhs_a[ri]);
407
+
408
+ // insert the item in the list at the appropriate location
409
+ if (last_added) last_added = list::insert_after(last_added, ri - rhs->offset[1], insert_val);
410
+ else last_added = list::insert(curr_row, false, ri - rhs->offset[1], insert_val);
411
+
412
+ // no need to set add_diag to false because it'll be reset automatically in next iteration.
413
+ }
414
+
415
+ // Now add the list at the appropriate location
416
+ if (last_row_added) last_row_added = list::insert_after(last_row_added, i, curr_row);
417
+ else last_row_added = list::insert(lhs->rows, false, i, curr_row);
418
+ }
419
+
420
+ // end of walk through rows
421
+ }
422
+
423
+ nm_yale_storage_unregister(rhs);
424
+
425
+ return lhs;
426
+ }
427
+
428
+
429
+ /* Copy dense into lists recursively
430
+ *
431
+ * FIXME: This works, but could probably be cleaner (do we really need to pass coords around?)
432
+ */
433
+ template <typename LDType, typename RDType>
434
+ static bool cast_copy_contents_dense(LIST* lhs, const RDType* rhs, RDType* zero, size_t& pos, size_t* coords, const size_t* shape, size_t dim, size_t recursions) {
435
+
436
+ nm_list_storage_register_list(lhs, recursions);
437
+
438
+ NODE *prev = NULL;
439
+ LIST *sub_list;
440
+ bool added = false, added_list = false;
441
+ //void* insert_value;
442
+
443
+ for (coords[dim-1-recursions] = 0; coords[dim-1-recursions] < shape[dim-1-recursions]; ++coords[dim-1-recursions], ++pos) {
444
+
445
+ if (recursions == 0) {
446
+ // create nodes
447
+
448
+ if (rhs[pos] != *zero) {
449
+ // is not zero
450
+
451
+ // Create a copy of our value that we will insert in the list
452
+ LDType* insert_value = NM_ALLOC_N(LDType, 1);
453
+ *insert_value = static_cast<LDType>(rhs[pos]);
454
+
455
+ if (!lhs->first) prev = list::insert(lhs, false, coords[dim-1-recursions], insert_value);
456
+ else prev = list::insert_after(prev, coords[dim-1-recursions], insert_value);
457
+
458
+ added = true;
459
+ }
460
+ // no need to do anything if the element is zero
461
+
462
+ } else { // create lists
463
+ // create a list as if there's something in the row in question, and then delete it if nothing turns out to be there
464
+ sub_list = list::create();
465
+
466
+ added_list = list_storage::cast_copy_contents_dense<LDType,RDType>(sub_list, rhs, zero, pos, coords, shape, dim, recursions-1);
467
+
468
+ if (!added_list) list::del(sub_list, recursions-1);
469
+ else if (!lhs->first) prev = list::insert(lhs, false, coords[dim-1-recursions], sub_list);
470
+ else prev = list::insert_after(prev, coords[dim-1-recursions], sub_list);
471
+
472
+ // added = (added || added_list);
473
+ }
474
+ }
475
+
476
+ nm_list_storage_unregister_list(lhs, recursions);
477
+
478
+ coords[dim-1-recursions] = 0;
479
+ --pos;
480
+
481
+ return added;
482
+ }
483
+
484
+ } // end of namespace list_storage
485
+
486
+
487
+ namespace yale_storage { // FIXME: Move to yale.cpp
488
+ /*
489
+ * Creation of yale storage from dense storage.
490
+ */
491
+ template <typename LDType, typename RDType>
492
+ YALE_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype, void* init) {
493
+
494
+ if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "can only convert matrices of dim 2 to yale");
495
+
496
+ nm_dense_storage_register(rhs);
497
+
498
+ IType pos = 0;
499
+ IType ndnz = 0;
500
+
501
+ // We need a zero value. This should nearly always be zero, but sometimes you might want false or nil.
502
+ LDType L_INIT(0);
503
+ if (init) {
504
+ if (l_dtype == RUBYOBJ) L_INIT = *reinterpret_cast<VALUE*>(init);
505
+ else L_INIT = *reinterpret_cast<LDType*>(init);
506
+ }
507
+ RDType R_INIT = static_cast<RDType>(L_INIT);
508
+
509
+ RDType* rhs_elements = reinterpret_cast<RDType*>(rhs->elements);
510
+
511
+ // First, count the non-diagonal nonzeros
512
+ for (size_t i = rhs->shape[0]; i-- > 0;) {
513
+ for (size_t j = rhs->shape[1]; j-- > 0;) {
514
+ pos = rhs->stride[0]*(i + rhs->offset[0]) + rhs->stride[1]*(j + rhs->offset[1]);
515
+ if (i != j && rhs_elements[pos] != R_INIT) ++ndnz;
516
+
517
+ // move forward 1 position in dense matrix elements array
518
+ }
519
+ }
520
+
521
+ // Copy shape for yale construction
522
+ size_t* shape = NM_ALLOC_N(size_t, 2);
523
+ shape[0] = rhs->shape[0];
524
+ shape[1] = rhs->shape[1];
525
+
526
+ size_t request_capacity = shape[0] + ndnz + 1;
527
+
528
+ // Create with minimum possible capacity -- just enough to hold all of the entries
529
+ YALE_STORAGE* lhs = nm_yale_storage_create(l_dtype, shape, 2, request_capacity);
530
+
531
+ if (lhs->capacity < request_capacity)
532
+ rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", (unsigned long)request_capacity, (unsigned long)(lhs->capacity));
533
+
534
+ LDType* lhs_a = reinterpret_cast<LDType*>(lhs->a);
535
+ IType* lhs_ija = lhs->ija;
536
+
537
+ // Set the zero position in the yale matrix
538
+ lhs_a[shape[0]] = L_INIT;
539
+
540
+ // Start just after the zero position.
541
+ IType ija = shape[0]+1;
542
+ pos = 0;
543
+
544
+ // Copy contents
545
+ for (IType i = 0; i < rhs->shape[0]; ++i) {
546
+ // indicate the beginning of a row in the IJA array
547
+ lhs_ija[i] = ija;
548
+
549
+ for (IType j = 0; j < rhs->shape[1]; ++j) {
550
+ pos = rhs->stride[0] * (i + rhs->offset[0]) + rhs->stride[1] * (j + rhs->offset[1]); // calc position with offsets
551
+
552
+ if (i == j) { // copy to diagonal
553
+ lhs_a[i] = static_cast<LDType>(rhs_elements[pos]);
554
+ } else if (rhs_elements[pos] != R_INIT) { // copy nonzero to LU
555
+ lhs_ija[ija] = j; // write column index
556
+ lhs_a[ija] = static_cast<LDType>(rhs_elements[pos]);
557
+
558
+ ++ija;
559
+ }
560
+ }
561
+ }
562
+
563
+ lhs_ija[shape[0]] = ija; // indicate the end of the last row
564
+ lhs->ndnz = ndnz;
565
+
566
+ nm_dense_storage_unregister(rhs);
567
+
568
+ return lhs;
569
+ }
570
+
571
+ /*
572
+ * Creation of yale storage from list storage.
573
+ */
574
+ template <typename LDType, typename RDType>
575
+ YALE_STORAGE* create_from_list_storage(const LIST_STORAGE* rhs, nm::dtype_t l_dtype) {
576
+ if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "can only convert matrices of dim 2 to yale");
577
+
578
+ if (rhs->dtype == RUBYOBJ) {
579
+ VALUE init_val = *reinterpret_cast<VALUE*>(rhs->default_val);
580
+ if (rb_funcall(init_val, rb_intern("!="), 1, Qnil) == Qtrue && rb_funcall(init_val, rb_intern("!="), 1, Qfalse) == Qtrue && rb_funcall(init_val, rb_intern("!="), 1, INT2FIX(0)) == Qtrue)
581
+ rb_raise(nm_eStorageTypeError, "list matrix of Ruby objects must have default value equal to 0, nil, or false to convert to yale");
582
+ } else if (strncmp(reinterpret_cast<const char*>(rhs->default_val), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", DTYPE_SIZES[rhs->dtype]))
583
+ rb_raise(nm_eStorageTypeError, "list matrix of non-Ruby objects must have default value of 0 to convert to yale");
584
+
585
+ nm_list_storage_register(rhs);
586
+
587
+ size_t ndnz = nm_list_storage_count_nd_elements(rhs);
588
+ // Copy shape for yale construction
589
+ size_t* shape = NM_ALLOC_N(size_t, 2);
590
+ shape[0] = rhs->shape[0];
591
+ shape[1] = rhs->shape[1];
592
+
593
+ size_t request_capacity = shape[0] + ndnz + 1;
594
+ YALE_STORAGE* lhs = nm_yale_storage_create(l_dtype, shape, 2, request_capacity);
595
+
596
+ if (lhs->capacity < request_capacity)
597
+ rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", (unsigned long)request_capacity, (unsigned long)(lhs->capacity));
598
+
599
+ // Initialize the A and IJA arrays
600
+ init<LDType>(lhs, rhs->default_val);
601
+
602
+ IType* lhs_ija = lhs->ija;
603
+ LDType* lhs_a = reinterpret_cast<LDType*>(lhs->a);
604
+
605
+ IType ija = lhs->shape[0]+1;
606
+
607
+ // Copy contents
608
+ for (NODE* i_curr = rhs->rows->first; i_curr; i_curr = i_curr->next) {
609
+
610
+ // Shrink reference
611
+ int i = i_curr->key - rhs->offset[0];
612
+ if (i < 0 || i >= (int)rhs->shape[0]) continue;
613
+
614
+ for (NODE* j_curr = ((LIST*)(i_curr->val))->first; j_curr; j_curr = j_curr->next) {
615
+
616
+ // Shrink reference
617
+ int j = j_curr->key - rhs->offset[1];
618
+ if (j < 0 || j >= (int)rhs->shape[1]) continue;
619
+
620
+ LDType cast_jcurr_val = *reinterpret_cast<RDType*>(j_curr->val);
621
+ if (i_curr->key - rhs->offset[0] == j_curr->key - rhs->offset[1])
622
+ lhs_a[i_curr->key - rhs->offset[0]] = cast_jcurr_val; // set diagonal
623
+ else {
624
+ lhs_ija[ija] = j_curr->key - rhs->offset[1]; // set column value
625
+
626
+ lhs_a[ija] = cast_jcurr_val; // set cell value
627
+
628
+ ++ija;
629
+ // indicate the beginning of a row in the IJA array
630
+ for (size_t i = i_curr->key - rhs->offset[0] + 1; i < rhs->shape[0] + rhs->offset[0]; ++i) {
631
+ lhs_ija[i] = ija;
632
+ }
633
+
634
+ }
635
+ }
636
+
637
+ }
638
+
639
+ lhs_ija[rhs->shape[0]] = ija; // indicate the end of the last row
640
+ lhs->ndnz = ndnz;
641
+
642
+ nm_list_storage_unregister(rhs);
643
+
644
+ return lhs;
645
+ }
646
+
647
+ } // end of namespace yale_storage
648
+ } // end of namespace nm
649
+
650
+ extern "C" {
651
+
652
+ /*
653
+ * The following functions represent stype casts -- conversions from one
654
+ * stype to another. Each of these is the C accessor for a templated C++
655
+ * function.
656
+ */
657
+
658
+
659
+ STORAGE* nm_yale_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype, void* init) {
660
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_dense_storage, YALE_STORAGE*, const DENSE_STORAGE* rhs, nm::dtype_t l_dtype, void*);
661
+
662
+ if (!ttable[l_dtype][right->dtype]) {
663
+ rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
664
+ return NULL;
665
+ }
666
+
667
+ return (STORAGE*)ttable[l_dtype][right->dtype]((const DENSE_STORAGE*)right, l_dtype, init);
668
+ }
669
+
670
+ STORAGE* nm_yale_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
671
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_list_storage, YALE_STORAGE*, const LIST_STORAGE* rhs, nm::dtype_t l_dtype);
672
+
673
+ if (!ttable[l_dtype][right->dtype]) {
674
+ rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
675
+ return NULL;
676
+ }
677
+
678
+ return (STORAGE*)ttable[l_dtype][right->dtype]((const LIST_STORAGE*)right, l_dtype);
679
+ }
680
+
681
+ STORAGE* nm_dense_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
682
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::create_from_list_storage, DENSE_STORAGE*, const LIST_STORAGE* rhs, nm::dtype_t l_dtype);
683
+
684
+ if (!ttable[l_dtype][right->dtype]) {
685
+ rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
686
+ return NULL;
687
+ }
688
+
689
+ return (STORAGE*)ttable[l_dtype][right->dtype]((const LIST_STORAGE*)right, l_dtype);
690
+ }
691
+
692
+ STORAGE* nm_dense_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
693
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::create_from_yale_storage, DENSE_STORAGE*, const YALE_STORAGE* rhs, nm::dtype_t l_dtype);
694
+
695
+ const YALE_STORAGE* casted_right = reinterpret_cast<const YALE_STORAGE*>(right);
696
+
697
+ if (!ttable[l_dtype][right->dtype]) {
698
+ rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
699
+ return NULL;
700
+ }
701
+
702
+ return reinterpret_cast<STORAGE*>(ttable[l_dtype][right->dtype](casted_right, l_dtype));
703
+ }
704
+
705
+ STORAGE* nm_list_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype, void* init) {
706
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::create_from_dense_storage, LIST_STORAGE*, const DENSE_STORAGE*, nm::dtype_t, void*);
707
+
708
+ if (!ttable[l_dtype][right->dtype]) {
709
+ rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
710
+ return NULL;
711
+ }
712
+
713
+ return (STORAGE*)ttable[l_dtype][right->dtype]((DENSE_STORAGE*)right, l_dtype, init);
714
+ }
715
+
716
+ STORAGE* nm_list_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
717
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::create_from_yale_storage, LIST_STORAGE*, const YALE_STORAGE* rhs, nm::dtype_t l_dtype);
718
+
719
+ const YALE_STORAGE* casted_right = reinterpret_cast<const YALE_STORAGE*>(right);
720
+
721
+ if (!ttable[l_dtype][right->dtype]) {
722
+ rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
723
+ return NULL;
724
+ }
725
+
726
+ return (STORAGE*)ttable[l_dtype][right->dtype](casted_right, l_dtype);
727
+ }
728
+
729
+ } // end of extern "C"
730
+