nmatrix 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/.gitignore +27 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +3 -5
  4. data/Guardfile +6 -0
  5. data/History.txt +33 -0
  6. data/Manifest.txt +41 -38
  7. data/README.rdoc +88 -11
  8. data/Rakefile +35 -53
  9. data/ext/nmatrix/data/complex.h +372 -0
  10. data/ext/nmatrix/data/data.cpp +275 -0
  11. data/ext/nmatrix/data/data.h +707 -0
  12. data/ext/nmatrix/data/rational.h +421 -0
  13. data/ext/nmatrix/data/ruby_object.h +446 -0
  14. data/ext/nmatrix/extconf.rb +101 -51
  15. data/ext/nmatrix/new_extconf.rb +56 -0
  16. data/ext/nmatrix/nmatrix.cpp +1609 -0
  17. data/ext/nmatrix/nmatrix.h +265 -849
  18. data/ext/nmatrix/ruby_constants.cpp +134 -0
  19. data/ext/nmatrix/ruby_constants.h +103 -0
  20. data/ext/nmatrix/storage/common.cpp +70 -0
  21. data/ext/nmatrix/storage/common.h +170 -0
  22. data/ext/nmatrix/storage/dense.cpp +665 -0
  23. data/ext/nmatrix/storage/dense.h +116 -0
  24. data/ext/nmatrix/storage/list.cpp +1088 -0
  25. data/ext/nmatrix/storage/list.h +129 -0
  26. data/ext/nmatrix/storage/storage.cpp +658 -0
  27. data/ext/nmatrix/storage/storage.h +99 -0
  28. data/ext/nmatrix/storage/yale.cpp +1601 -0
  29. data/ext/nmatrix/storage/yale.h +208 -0
  30. data/ext/nmatrix/ttable_helper.rb +126 -0
  31. data/ext/nmatrix/{yale/smmp1_header.template.c → types.h} +36 -9
  32. data/ext/nmatrix/util/io.cpp +295 -0
  33. data/ext/nmatrix/util/io.h +117 -0
  34. data/ext/nmatrix/util/lapack.h +1175 -0
  35. data/ext/nmatrix/util/math.cpp +557 -0
  36. data/ext/nmatrix/util/math.h +1363 -0
  37. data/ext/nmatrix/util/sl_list.cpp +475 -0
  38. data/ext/nmatrix/util/sl_list.h +255 -0
  39. data/ext/nmatrix/util/util.h +78 -0
  40. data/lib/nmatrix/blas.rb +70 -0
  41. data/lib/nmatrix/io/mat5_reader.rb +567 -0
  42. data/lib/nmatrix/io/mat_reader.rb +162 -0
  43. data/lib/{string.rb → nmatrix/monkeys.rb} +49 -2
  44. data/lib/nmatrix/nmatrix.rb +199 -0
  45. data/lib/nmatrix/nvector.rb +103 -0
  46. data/lib/nmatrix/version.rb +27 -0
  47. data/lib/nmatrix.rb +22 -230
  48. data/nmatrix.gemspec +59 -0
  49. data/scripts/mac-brew-gcc.sh +47 -0
  50. data/spec/4x4_sparse.mat +0 -0
  51. data/spec/4x5_dense.mat +0 -0
  52. data/spec/blas_spec.rb +47 -0
  53. data/spec/elementwise_spec.rb +164 -0
  54. data/spec/io_spec.rb +60 -0
  55. data/spec/lapack_spec.rb +52 -0
  56. data/spec/math_spec.rb +96 -0
  57. data/spec/nmatrix_spec.rb +93 -89
  58. data/spec/nmatrix_yale_spec.rb +52 -36
  59. data/spec/nvector_spec.rb +1 -1
  60. data/spec/slice_spec.rb +257 -0
  61. data/spec/spec_helper.rb +51 -0
  62. data/spec/utm5940.mtx +83844 -0
  63. metadata +113 -71
  64. data/.autotest +0 -23
  65. data/.gemtest +0 -0
  66. data/ext/nmatrix/cblas.c +0 -150
  67. data/ext/nmatrix/dense/blas_header.template.c +0 -52
  68. data/ext/nmatrix/dense/elementwise.template.c +0 -107
  69. data/ext/nmatrix/dense/gemm.template.c +0 -159
  70. data/ext/nmatrix/dense/gemv.template.c +0 -130
  71. data/ext/nmatrix/dense/rationalmath.template.c +0 -68
  72. data/ext/nmatrix/dense.c +0 -307
  73. data/ext/nmatrix/depend +0 -18
  74. data/ext/nmatrix/generator/syntax_tree.rb +0 -481
  75. data/ext/nmatrix/generator.rb +0 -594
  76. data/ext/nmatrix/list.c +0 -774
  77. data/ext/nmatrix/nmatrix.c +0 -1977
  78. data/ext/nmatrix/rational.c +0 -98
  79. data/ext/nmatrix/yale/complexmath.template.c +0 -71
  80. data/ext/nmatrix/yale/elementwise.template.c +0 -46
  81. data/ext/nmatrix/yale/elementwise_op.template.c +0 -73
  82. data/ext/nmatrix/yale/numbmm.template.c +0 -94
  83. data/ext/nmatrix/yale/smmp1.template.c +0 -21
  84. data/ext/nmatrix/yale/smmp2.template.c +0 -43
  85. data/ext/nmatrix/yale/smmp2_header.template.c +0 -46
  86. data/ext/nmatrix/yale/sort_columns.template.c +0 -56
  87. data/ext/nmatrix/yale/symbmm.template.c +0 -54
  88. data/ext/nmatrix/yale/transp.template.c +0 -68
  89. data/ext/nmatrix/yale.c +0 -726
  90. data/lib/array.rb +0 -67
  91. data/spec/syntax_tree_spec.rb +0 -46
@@ -0,0 +1,658 @@
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
+ // == 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
+ void (* const STYPE_MARK[nm::NUM_STYPES])(void*) = {
59
+ nm_dense_storage_mark,
60
+ nm_list_storage_mark,
61
+ nm_yale_storage_mark
62
+ };
63
+
64
+ } // end extern "C" block
65
+
66
+ /*
67
+ * Forward Declarations
68
+ */
69
+
70
+ namespace nm {
71
+
72
+
73
+ /*
74
+ * Functions
75
+ */
76
+
77
+ /////////////////////////
78
+ // Templated Functions //
79
+ /////////////////////////
80
+
81
+ namespace dense_storage {
82
+
83
+ template <typename LDType, typename RDType>
84
+ static void cast_copy_list_contents(LDType* lhs, const LIST* rhs, RDType* default_val,
85
+ size_t& pos, const size_t* shape, size_t dim, size_t max_elements, size_t recursions);
86
+
87
+ template <typename LDType, typename RDType>
88
+ static void cast_copy_list_default(LDType* lhs, RDType* default_val, size_t& pos,
89
+ const size_t* shape, size_t dim, size_t max_elements, size_t recursions);
90
+
91
+ /*
92
+ * Convert (by creating a copy) from list storage to dense storage.
93
+ */
94
+ template <typename LDType, typename RDType>
95
+ DENSE_STORAGE* create_from_list_storage(const LIST_STORAGE* rhs, dtype_t l_dtype) {
96
+
97
+ // allocate and copy shape
98
+ size_t* shape = ALLOC_N(size_t, rhs->dim);
99
+ memcpy(shape, rhs->shape, rhs->dim * sizeof(size_t));
100
+
101
+ DENSE_STORAGE* lhs = nm_dense_storage_create(l_dtype, shape, rhs->dim, NULL, 0);
102
+
103
+ // Position in lhs->elements.
104
+ size_t pos = 0;
105
+ size_t max_elements = nm_storage_count_max_elements(rhs);
106
+
107
+ //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)
108
+ // recursively copy the contents
109
+ if (rhs->src == rhs)
110
+ cast_copy_list_contents<LDType,RDType>(reinterpret_cast<LDType*>(lhs->elements),
111
+ rhs->rows,
112
+ reinterpret_cast<RDType*>(rhs->default_val),
113
+ pos, shape, lhs->dim, max_elements, rhs->dim-1);
114
+ else {
115
+ LIST_STORAGE *tmp = nm_list_storage_copy(rhs);
116
+ cast_copy_list_contents<LDType,RDType>(reinterpret_cast<LDType*>(lhs->elements),
117
+ tmp->rows,
118
+ reinterpret_cast<RDType*>(tmp->default_val),
119
+ pos, shape, lhs->dim, max_elements, tmp->dim-1);
120
+ nm_list_storage_delete(tmp);
121
+
122
+ }
123
+
124
+ return lhs;
125
+ }
126
+
127
+
128
+
129
+
130
+ /*
131
+ * Create/allocate dense storage, copying into it the contents of a Yale matrix.
132
+ */
133
+ template <typename LDType, typename RDType, typename RIType>
134
+ DENSE_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype) {
135
+
136
+ // Position in rhs->elements.
137
+ RIType* rhs_ija = reinterpret_cast<RIType*>(rhs->ija);
138
+ RDType* rhs_a = reinterpret_cast<RDType*>(rhs->a);
139
+
140
+ // Allocate and set shape.
141
+ size_t* shape = ALLOC_N(size_t, rhs->dim);
142
+ memcpy(shape, rhs->shape, rhs->dim * sizeof(size_t));
143
+
144
+ DENSE_STORAGE* lhs = nm_dense_storage_create(l_dtype, shape, rhs->dim, NULL, 0);
145
+ LDType* lhs_elements = reinterpret_cast<LDType*>(lhs->elements);
146
+
147
+ // Position in dense to write to.
148
+ size_t pos = 0;
149
+
150
+ LDType LCAST_ZERO = rhs_a[rhs->shape[0]];
151
+
152
+ // Walk through rows. For each entry we set in dense, increment pos.
153
+ for (RIType i = 0; i < rhs->shape[0]; ++i) {
154
+
155
+ // Position in yale array
156
+ RIType ija = rhs_ija[i];
157
+
158
+ if (ija == rhs_ija[i+1]) { // Check boundaries of row: is row empty?
159
+
160
+ // Write zeros in each column.
161
+ for (RIType j = 0; j < rhs->shape[1]; ++j) { // Move to next dense position.
162
+
163
+ // Fill in zeros (except for diagonal)
164
+ if (i == j) lhs_elements[pos] = rhs_a[i];
165
+ else lhs_elements[pos] = LCAST_ZERO;
166
+
167
+ ++pos;
168
+ }
169
+
170
+ } else {
171
+ // Row contains entries: write those in each column, interspersed with zeros.
172
+ RIType jj = rhs_ija[ija];
173
+
174
+ for (size_t j = 0; j < rhs->shape[1]; ++j) {
175
+ if (i == j) {
176
+ lhs_elements[pos] = rhs_a[i];
177
+
178
+ } else if (j == jj) {
179
+ lhs_elements[pos] = rhs_a[ija]; // Copy from rhs.
180
+
181
+ // Get next.
182
+ ++ija;
183
+
184
+ // Increment to next column ID (or go off the end).
185
+ if (ija < rhs_ija[i+1]) jj = rhs_ija[ija];
186
+ else jj = rhs->shape[1];
187
+
188
+ } else { // j < jj
189
+
190
+ // Insert zero.
191
+ lhs_elements[pos] = LCAST_ZERO;
192
+ }
193
+
194
+ // Move to next dense position.
195
+ ++pos;
196
+ }
197
+ }
198
+ }
199
+
200
+ return lhs;
201
+ }
202
+
203
+
204
+ /*
205
+ * Copy list contents into dense recursively.
206
+ */
207
+ template <typename LDType, typename RDType>
208
+ 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) {
209
+
210
+ NODE *curr = rhs->first;
211
+ int last_key = -1;
212
+
213
+ for (size_t i = 0; i < shape[dim - 1 - recursions]; ++i, ++pos) {
214
+
215
+ if (!curr || (curr->key > (size_t)(last_key+1))) {
216
+
217
+ if (recursions == 0) lhs[pos] = *default_val;
218
+ else cast_copy_list_default<LDType,RDType>(lhs, default_val, pos, shape, dim, max_elements, recursions-1);
219
+
220
+ ++last_key;
221
+
222
+ } else {
223
+
224
+ if (recursions == 0) lhs[pos] = *reinterpret_cast<RDType*>(curr->val);
225
+ else cast_copy_list_contents<LDType,RDType>(lhs, (const LIST*)(curr->val),
226
+ default_val, pos, shape, dim, max_elements, recursions-1);
227
+
228
+ last_key = curr->key;
229
+ curr = curr->next;
230
+ }
231
+ }
232
+
233
+ --pos;
234
+ }
235
+
236
+ /*
237
+ * Copy a set of default values into dense.
238
+ */
239
+ template <typename LDType,typename RDType>
240
+ 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) {
241
+ for (size_t i = 0; i < shape[dim - 1 - recursions]; ++i, ++pos) {
242
+
243
+ if (recursions == 0) lhs[pos] = *default_val;
244
+ else cast_copy_list_default<LDType,RDType>(lhs, default_val, pos, shape, dim, max_elements, recursions-1);
245
+
246
+ }
247
+
248
+ --pos;
249
+ }
250
+
251
+
252
+ } // end of namespace dense_storage
253
+
254
+ namespace list_storage {
255
+
256
+
257
+ template <typename LDType, typename RDType>
258
+ 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);
259
+
260
+ /*
261
+ * Creation of list storage from dense storage.
262
+ */
263
+ template <typename LDType, typename RDType>
264
+ LIST_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype) {
265
+
266
+ LDType* l_default_val = ALLOC_N(LDType, 1);
267
+ RDType* r_default_val = ALLOCA_N(RDType, 1); // clean up when finished with this function
268
+
269
+ // allocate and copy shape and coords
270
+ size_t *shape = ALLOC_N(size_t, rhs->dim),
271
+ *coords = ALLOC_N(size_t, rhs->dim);
272
+
273
+ memcpy(shape, rhs->shape, rhs->dim * sizeof(size_t));
274
+ memset(coords, 0, rhs->dim * sizeof(size_t));
275
+
276
+ // set list default_val to 0
277
+ if (l_dtype == RUBYOBJ) *l_default_val = INT2FIX(0);
278
+ else *l_default_val = 0;
279
+
280
+ // need test default value for comparing to elements in dense matrix
281
+ if (rhs->dtype == l_dtype) *r_default_val = *l_default_val;
282
+ else if (rhs->dtype == RUBYOBJ) *r_default_val = INT2FIX(0);
283
+ else *r_default_val = 0;
284
+
285
+ LIST_STORAGE* lhs = nm_list_storage_create(l_dtype, shape, rhs->dim, l_default_val);
286
+
287
+ size_t pos = 0;
288
+
289
+ if (rhs->src == rhs)
290
+ list_storage::cast_copy_contents_dense<LDType,RDType>(lhs->rows,
291
+ reinterpret_cast<const RDType*>(rhs->elements),
292
+ r_default_val,
293
+ pos, coords, rhs->shape, rhs->dim, rhs->dim - 1);
294
+ else {
295
+ DENSE_STORAGE* tmp = nm_dense_storage_copy(rhs);
296
+ list_storage::cast_copy_contents_dense<LDType,RDType>(lhs->rows,
297
+ reinterpret_cast<const RDType*>(tmp->elements),
298
+ r_default_val,
299
+ pos, coords, rhs->shape, rhs->dim, rhs->dim - 1);
300
+
301
+ nm_dense_storage_delete(tmp);
302
+ }
303
+
304
+ return lhs;
305
+ }
306
+
307
+
308
+
309
+ /*
310
+ * Creation of list storage from yale storage.
311
+ */
312
+ template <typename LDType, typename RDType, typename RIType>
313
+ LIST_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype) {
314
+ // allocate and copy shape
315
+ size_t *shape = ALLOC_N(size_t, rhs->dim);
316
+ shape[0] = rhs->shape[0]; shape[1] = rhs->shape[1];
317
+
318
+ RDType* rhs_a = reinterpret_cast<RDType*>(rhs->a);
319
+ RDType R_ZERO = rhs_a[ rhs->shape[0] ];
320
+
321
+ // copy default value from the zero location in the Yale matrix
322
+ LDType* default_val = ALLOC_N(LDType, 1);
323
+ *default_val = R_ZERO;
324
+
325
+ LIST_STORAGE* lhs = nm_list_storage_create(l_dtype, shape, rhs->dim, default_val);
326
+
327
+ if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "Can only convert matrices of dim 2 from yale.");
328
+
329
+ RIType* rhs_ija = reinterpret_cast<RIType*>(rhs->ija);
330
+
331
+ NODE *last_added = NULL, *last_row_added = NULL;
332
+
333
+ // Walk through rows and columns as if RHS were a dense matrix
334
+ for (RIType i = 0; i < rhs->shape[0]; ++i) {
335
+
336
+ // Get boundaries of beginning and end of row
337
+ RIType ija = rhs_ija[i],
338
+ ija_next = rhs_ija[i+1];
339
+
340
+ // Are we going to need to add a diagonal for this row?
341
+ bool add_diag = false;
342
+ if (rhs_a[i] != R_ZERO) add_diag = true;
343
+
344
+ if (ija < ija_next || add_diag) {
345
+
346
+ LIST* curr_row = list::create();
347
+
348
+ LDType* insert_val;
349
+
350
+ while (ija < ija_next) {
351
+ RIType jj = rhs_ija[ija]; // what column number is this?
352
+
353
+ // Is there a nonzero diagonal item between the previously added item and the current one?
354
+ if (jj > i && add_diag) {
355
+ // Allocate and copy insertion value
356
+ insert_val = ALLOC_N(LDType, 1);
357
+ *insert_val = rhs_a[i];
358
+
359
+ // insert the item in the list at the appropriate location
360
+ if (last_added) last_added = list::insert_after(last_added, i, insert_val);
361
+ else last_added = list::insert(curr_row, false, i, insert_val);
362
+
363
+ // don't add again!
364
+ add_diag = false;
365
+ }
366
+
367
+ // now allocate and add the current item
368
+ insert_val = ALLOC_N(LDType, 1);
369
+ *insert_val = rhs_a[ija];
370
+
371
+ if (last_added) last_added = list::insert_after(last_added, jj, insert_val);
372
+ else last_added = list::insert(curr_row, false, jj, insert_val);
373
+
374
+ ++ija; // move to next entry in Yale matrix
375
+ }
376
+
377
+ if (add_diag) {
378
+ // still haven't added the diagonal.
379
+ insert_val = ALLOC_N(LDType, 1);
380
+ *insert_val = rhs_a[i];
381
+
382
+ // insert the item in the list at the appropriate location
383
+ if (last_added) last_added = list::insert_after(last_added, i, insert_val);
384
+ else last_added = list::insert(curr_row, false, i, insert_val);
385
+ }
386
+
387
+ // Now add the list at the appropriate location
388
+ if (last_row_added) last_row_added = list::insert_after(last_row_added, i, curr_row);
389
+ else last_row_added = list::insert(lhs->rows, false, i, curr_row);
390
+ }
391
+
392
+ // end of walk through rows
393
+ }
394
+
395
+ return lhs;
396
+ }
397
+
398
+
399
+ /* Copy dense into lists recursively
400
+ *
401
+ * FIXME: This works, but could probably be cleaner (do we really need to pass coords around?)
402
+ */
403
+ template <typename LDType, typename RDType>
404
+ 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) {
405
+ NODE *prev = NULL;
406
+ LIST *sub_list;
407
+ bool added = false, added_list = false;
408
+ //void* insert_value;
409
+
410
+ for (coords[dim-1-recursions] = 0; coords[dim-1-recursions] < shape[dim-1-recursions]; ++coords[dim-1-recursions], ++pos) {
411
+
412
+ if (recursions == 0) {
413
+ // create nodes
414
+
415
+ if (rhs[pos] != *zero) {
416
+ // is not zero
417
+
418
+ // Create a copy of our value that we will insert in the list
419
+ LDType* insert_value = ALLOC_N(LDType, 1);
420
+ *insert_value = (LDType)(rhs[pos]);
421
+
422
+ if (!lhs->first) prev = list::insert(lhs, false, coords[dim-1-recursions], insert_value);
423
+ else prev = list::insert_after(prev, coords[dim-1-recursions], insert_value);
424
+
425
+ added = true;
426
+ }
427
+ // no need to do anything if the element is zero
428
+
429
+ } else { // create lists
430
+ // create a list as if there's something in the row in question, and then delete it if nothing turns out to be there
431
+ sub_list = list::create();
432
+
433
+ added_list = list_storage::cast_copy_contents_dense<LDType,RDType>(sub_list, rhs, zero, pos, coords, shape, dim, recursions-1);
434
+
435
+ if (!added_list) list::del(sub_list, recursions-1);
436
+ else if (!lhs->first) prev = list::insert(lhs, false, coords[dim-1-recursions], sub_list);
437
+ else prev = list::insert_after(prev, coords[dim-1-recursions], sub_list);
438
+
439
+ // added = (added || added_list);
440
+ }
441
+ }
442
+
443
+ coords[dim-1-recursions] = 0;
444
+ --pos;
445
+
446
+ return added;
447
+ }
448
+
449
+ } // end of namespace list_storage
450
+
451
+
452
+ namespace yale_storage { // FIXME: Move to yale.cpp
453
+ /*
454
+ * Creation of yale storage from dense storage.
455
+ */
456
+ template <typename LDType, typename RDType, typename LIType>
457
+ YALE_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype) {
458
+ if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "can only convert matrices of dim 2 to yale");
459
+
460
+ LIType pos = 0;
461
+ LIType ndnz = 0;
462
+
463
+ RDType R_ZERO; // need zero for easier comparisons
464
+ if (rhs->dtype == RUBYOBJ) R_ZERO = INT2FIX(0);
465
+ else R_ZERO = 0;
466
+
467
+
468
+ RDType* rhs_elements = reinterpret_cast<RDType*>(rhs->elements);
469
+
470
+ // First, count the non-diagonal nonzeros
471
+ for (size_t i = rhs->shape[0]; i-- > 0;) {
472
+ for (size_t j = rhs->shape[1]; j-- > 0;) {
473
+ pos = rhs->stride[0]*(i + rhs->offset[0]) + rhs->stride[1]*(j + rhs->offset[1]);
474
+ if (i != j && rhs_elements[pos] != R_ZERO) ++ndnz;
475
+
476
+ // move forward 1 position in dense matrix elements array
477
+ }
478
+ }
479
+
480
+ // Copy shape for yale construction
481
+ size_t* shape = ALLOC_N(size_t, 2);
482
+ shape[0] = rhs->shape[0];
483
+ shape[1] = rhs->shape[1];
484
+
485
+ size_t request_capacity = shape[0] + ndnz + 1;
486
+
487
+ // Create with minimum possible capacity -- just enough to hold all of the entries
488
+ YALE_STORAGE* lhs = nm_yale_storage_create(l_dtype, shape, 2, request_capacity);
489
+
490
+ if (lhs->capacity < request_capacity)
491
+ rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", (unsigned long)request_capacity, (unsigned long)(lhs->capacity));
492
+
493
+ LDType* lhs_a = reinterpret_cast<LDType*>(lhs->a);
494
+ LIType* lhs_ija = reinterpret_cast<LIType*>(lhs->ija);
495
+
496
+ // Set the zero position in the yale matrix
497
+ lhs_a[shape[0]] = R_ZERO;
498
+
499
+ // Start just after the zero position.
500
+ LIType ija = shape[0]+1;
501
+ LIType i;
502
+ pos = 0;
503
+
504
+ // Copy contents
505
+ for (i = 0; i < rhs->shape[0]; ++i) {
506
+ // indicate the beginning of a row in the IJA array
507
+ lhs_ija[i]= ija;
508
+
509
+ for (LIType j = 0; j < rhs->shape[1]; ++j) {
510
+ pos = rhs->stride[0]*(i + rhs->offset[0]) + rhs->stride[1]*(j + rhs->offset[1]); // calc position with offsets
511
+
512
+ if (i == j) { // copy to diagonal
513
+ lhs_a[i] = rhs_elements[pos];
514
+ } else if (rhs_elements[pos] != R_ZERO) { // copy nonzero to LU
515
+ lhs_ija[ija] = j; // write column index
516
+
517
+ lhs_a[ija] = rhs_elements[pos];
518
+
519
+ ++ija;
520
+ }
521
+ }
522
+ }
523
+
524
+ lhs_ija[shape[0]] = ija; // indicate the end of the last row
525
+ lhs->ndnz = ndnz;
526
+
527
+ return lhs;
528
+ }
529
+
530
+ /*
531
+ * Creation of yale storage from list storage.
532
+ */
533
+ template <typename LDType, typename RDType, typename LIType>
534
+ YALE_STORAGE* create_from_list_storage(const LIST_STORAGE* rhs, dtype_t l_dtype) {
535
+ if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "can only convert matrices of dim 2 to yale");
536
+
537
+ if ((rhs->dtype == RUBYOBJ and (*reinterpret_cast<RubyObject*>(rhs->default_val)) == RubyObject(INT2FIX(0)))
538
+ || 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]))
539
+ rb_raise(nm_eStorageTypeError, "list matrix must have default value of 0 to convert to yale");
540
+
541
+
542
+ size_t ndnz = nm_list_storage_count_nd_elements(rhs);
543
+ // Copy shape for yale construction
544
+ size_t* shape = ALLOC_N(size_t, 2);
545
+ shape[0] = rhs->shape[0];
546
+ shape[1] = rhs->shape[1];
547
+
548
+ size_t request_capacity = shape[0] + ndnz + 1;
549
+ YALE_STORAGE* lhs = nm_yale_storage_create(l_dtype, shape, 2, request_capacity);
550
+
551
+ if (lhs->capacity < request_capacity)
552
+ rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", (unsigned long)request_capacity, (unsigned long)(lhs->capacity));
553
+
554
+ // Initialize the A and IJA arrays
555
+ init<LDType,LIType>(lhs);
556
+
557
+ LIType* lhs_ija = reinterpret_cast<LIType*>(lhs->ija);
558
+ LDType* lhs_a = reinterpret_cast<LDType*>(lhs->a);
559
+
560
+ LIType ija = lhs->shape[0]+1;
561
+
562
+ // Copy contents
563
+ for (NODE* i_curr = rhs->rows->first; i_curr; i_curr = i_curr->next) {
564
+
565
+ // Shrink refernce
566
+ int i = i_curr->key - rhs->offset[0];
567
+ if (i < 0 || i >= (int)rhs->shape[0]) continue;
568
+
569
+ for (NODE* j_curr = ((LIST*)(i_curr->val))->first; j_curr; j_curr = j_curr->next) {
570
+
571
+ // Shrink refernce
572
+ int j = j_curr->key - rhs->offset[1];
573
+ if (j < 0 || j >= (int)rhs->shape[1]) continue;
574
+
575
+ LDType cast_jcurr_val = *reinterpret_cast<RDType*>(j_curr->val);
576
+ if (i_curr->key - rhs->offset[0] == j_curr->key - rhs->offset[1])
577
+ lhs_a[i_curr->key - rhs->offset[0]] = cast_jcurr_val; // set diagonal
578
+ else {
579
+ lhs_ija[ija] = j_curr->key - rhs->offset[1]; // set column value
580
+
581
+ lhs_a[ija] = cast_jcurr_val; // set cell value
582
+
583
+ ++ija;
584
+ // indicate the beginning of a row in the IJA array
585
+ for (size_t i = i_curr->key - rhs->offset[0] + 1; i < rhs->shape[0] + rhs->offset[0]; ++i) {
586
+ lhs_ija[i] = ija;
587
+ }
588
+
589
+ }
590
+ }
591
+
592
+ }
593
+
594
+ lhs_ija[rhs->shape[0]] = ija; // indicate the end of the last row
595
+ lhs->ndnz = ndnz;
596
+
597
+ return lhs;
598
+ }
599
+
600
+ } // end of namespace yale_storage
601
+ } // end of namespace nm
602
+
603
+ extern "C" {
604
+
605
+
606
+ /*
607
+ * The following functions represent stype casts -- conversions from one
608
+ * stype to another. Each of these is the C accessor for a templated C++
609
+ * function.
610
+ */
611
+
612
+
613
+
614
+ STORAGE* nm_yale_storage_from_dense(const STORAGE* right, dtype_t l_dtype) {
615
+ NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_dense_storage, YALE_STORAGE*, const DENSE_STORAGE* rhs, dtype_t l_dtype);
616
+
617
+ itype_t itype = nm_yale_storage_itype((const YALE_STORAGE*)right);
618
+
619
+ return (STORAGE*)ttable[l_dtype][right->dtype][itype]((const DENSE_STORAGE*)right, l_dtype);
620
+ }
621
+
622
+ STORAGE* nm_yale_storage_from_list(const STORAGE* right, dtype_t l_dtype) {
623
+ NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_list_storage, YALE_STORAGE*, const LIST_STORAGE* rhs, dtype_t l_dtype);
624
+
625
+ itype_t itype = nm_yale_storage_itype((const YALE_STORAGE*)right);
626
+
627
+ return (STORAGE*)ttable[l_dtype][right->dtype][itype]((const LIST_STORAGE*)right, l_dtype);
628
+ }
629
+
630
+ STORAGE* nm_dense_storage_from_list(const STORAGE* right, dtype_t l_dtype) {
631
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::create_from_list_storage, DENSE_STORAGE*, const LIST_STORAGE* rhs, dtype_t l_dtype);
632
+
633
+ return (STORAGE*)ttable[l_dtype][right->dtype]((const LIST_STORAGE*)right, l_dtype);
634
+ }
635
+
636
+ STORAGE* nm_dense_storage_from_yale(const STORAGE* right, dtype_t l_dtype) {
637
+ NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::create_from_yale_storage, DENSE_STORAGE*, const YALE_STORAGE* rhs, dtype_t l_dtype);
638
+
639
+ const YALE_STORAGE* casted_right = reinterpret_cast<const YALE_STORAGE*>(right);
640
+ return reinterpret_cast<STORAGE*>(ttable[l_dtype][right->dtype][casted_right->itype](casted_right, l_dtype));
641
+ }
642
+
643
+ STORAGE* nm_list_storage_from_dense(const STORAGE* right, dtype_t l_dtype) {
644
+ NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::create_from_dense_storage, LIST_STORAGE*, const DENSE_STORAGE*, dtype_t);
645
+
646
+ return (STORAGE*)ttable[l_dtype][right->dtype]((DENSE_STORAGE*)right, l_dtype);
647
+ }
648
+
649
+ STORAGE* nm_list_storage_from_yale(const STORAGE* right, dtype_t l_dtype) {
650
+ NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::create_from_yale_storage, LIST_STORAGE*, const YALE_STORAGE* rhs, dtype_t l_dtype);
651
+
652
+ const YALE_STORAGE* casted_right = reinterpret_cast<const YALE_STORAGE*>(right);
653
+
654
+ return (STORAGE*)ttable[l_dtype][right->dtype][casted_right->itype](casted_right, l_dtype);
655
+ }
656
+
657
+ } // end of extern "C"
658
+