nmatrix 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +3 -0
  2. data/CONTRIBUTING.md +66 -0
  3. data/Gemfile +1 -1
  4. data/History.txt +68 -10
  5. data/LICENSE.txt +2 -2
  6. data/Manifest.txt +2 -0
  7. data/README.rdoc +90 -69
  8. data/Rakefile +18 -9
  9. data/ext/nmatrix/data/complex.h +7 -7
  10. data/ext/nmatrix/data/data.cpp +2 -7
  11. data/ext/nmatrix/data/data.h +7 -4
  12. data/ext/nmatrix/data/rational.h +2 -2
  13. data/ext/nmatrix/data/ruby_object.h +3 -10
  14. data/ext/nmatrix/extconf.rb +79 -54
  15. data/ext/nmatrix/new_extconf.rb +11 -12
  16. data/ext/nmatrix/nmatrix.cpp +94 -125
  17. data/ext/nmatrix/nmatrix.h +38 -17
  18. data/ext/nmatrix/ruby_constants.cpp +2 -15
  19. data/ext/nmatrix/ruby_constants.h +2 -14
  20. data/ext/nmatrix/storage/common.cpp +2 -2
  21. data/ext/nmatrix/storage/common.h +2 -2
  22. data/ext/nmatrix/storage/dense.cpp +206 -31
  23. data/ext/nmatrix/storage/dense.h +5 -2
  24. data/ext/nmatrix/storage/list.cpp +52 -4
  25. data/ext/nmatrix/storage/list.h +3 -2
  26. data/ext/nmatrix/storage/storage.cpp +6 -6
  27. data/ext/nmatrix/storage/storage.h +2 -2
  28. data/ext/nmatrix/storage/yale.cpp +202 -49
  29. data/ext/nmatrix/storage/yale.h +5 -4
  30. data/ext/nmatrix/ttable_helper.rb +108 -108
  31. data/ext/nmatrix/types.h +2 -15
  32. data/ext/nmatrix/util/io.cpp +2 -2
  33. data/ext/nmatrix/util/io.h +2 -2
  34. data/ext/nmatrix/util/lapack.h +2 -2
  35. data/ext/nmatrix/util/math.cpp +14 -14
  36. data/ext/nmatrix/util/math.h +2 -2
  37. data/ext/nmatrix/util/sl_list.cpp +2 -2
  38. data/ext/nmatrix/util/sl_list.h +2 -2
  39. data/ext/nmatrix/util/util.h +2 -2
  40. data/lib/nmatrix.rb +13 -35
  41. data/lib/nmatrix/blas.rb +182 -56
  42. data/lib/nmatrix/io/market.rb +38 -14
  43. data/lib/nmatrix/io/mat5_reader.rb +393 -278
  44. data/lib/nmatrix/io/mat_reader.rb +121 -107
  45. data/lib/nmatrix/lapack.rb +59 -14
  46. data/lib/nmatrix/monkeys.rb +32 -30
  47. data/lib/nmatrix/nmatrix.rb +204 -100
  48. data/lib/nmatrix/nvector.rb +166 -57
  49. data/lib/nmatrix/shortcuts.rb +364 -231
  50. data/lib/nmatrix/version.rb +8 -4
  51. data/nmatrix.gemspec +5 -3
  52. data/scripts/mac-brew-gcc.sh +1 -1
  53. data/spec/blas_spec.rb +80 -2
  54. data/spec/math_spec.rb +78 -32
  55. data/spec/nmatrix_list_spec.rb +55 -55
  56. data/spec/nmatrix_spec.rb +60 -117
  57. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  58. data/spec/nmatrix_yale_spec.rb +214 -198
  59. data/spec/nvector_spec.rb +58 -2
  60. data/spec/shortcuts_spec.rb +156 -32
  61. data/spec/slice_spec.rb +229 -178
  62. data/spec/spec_helper.rb +2 -2
  63. metadata +71 -21
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -78,6 +78,8 @@ void nm_dense_storage_mark(void*);
78
78
  // Accessors //
79
79
  ///////////////
80
80
 
81
+ VALUE nm_dense_each(VALUE nmatrix);
82
+ VALUE nm_dense_each_with_indices(VALUE nmatrix);
81
83
  void* nm_dense_storage_get(STORAGE* s, SLICE* slice);
82
84
  void* nm_dense_storage_ref(STORAGE* s, SLICE* slice);
83
85
  void nm_dense_storage_set(STORAGE* s, SLICE* slice, void* val);
@@ -102,6 +104,7 @@ STORAGE* nm_dense_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, si
102
104
  /////////////
103
105
 
104
106
  size_t nm_dense_storage_pos(const DENSE_STORAGE* s, const size_t* coords);
107
+ void nm_dense_storage_coords(const DENSE_STORAGE* s, const size_t slice_pos, size_t* coords_out);
105
108
 
106
109
  /////////////////////////
107
110
  // Copying and Casting //
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -182,9 +182,57 @@ NODE* list_storage_get_single_node(LIST_STORAGE* s, SLICE* slice)
182
182
  return n;
183
183
  }
184
184
 
185
+ /*
186
+ * Each stored iterator, brings along the indices
187
+ */
188
+ VALUE nm_list_each_stored_with_indices(VALUE nmatrix) {
185
189
 
186
- static LIST* slice_copy(const LIST_STORAGE *src, LIST *src_rows, size_t *coords, size_t *lengths, size_t n)
187
- {
190
+ // If we don't have a block, return an enumerator.
191
+ RETURN_SIZED_ENUMERATOR(nmatrix, 0, 0, 0);
192
+
193
+ LIST_STORAGE* s = NM_STORAGE_LIST(nmatrix);
194
+ // Create indices and initialize to zero
195
+ size_t* coords = ALLOCA_N(size_t, s->dim);
196
+ memset(coords, 0, sizeof(size_t) * s->dim);
197
+
198
+ // Set up the LIST and NODE
199
+ LIST* l = s->rows;
200
+ NODE* curr = l->first;
201
+
202
+ // Levels...
203
+ while (curr) { // LOOPS through the rows
204
+ NODE* subnode = reinterpret_cast<LIST*>(curr->val)->first;
205
+ size_t row = curr->key;
206
+ // Iterate along each row, yielding the val, row, col for each non-default entry
207
+ while (subnode) {
208
+ VALUE ary = rb_ary_new();
209
+ size_t col = subnode->key;
210
+
211
+ // Conditional type handling
212
+ if (NM_DTYPE(nmatrix) == nm::RUBYOBJ) {
213
+ rb_ary_push(ary, *reinterpret_cast<VALUE*>(subnode->val));
214
+ } else {
215
+ rb_ary_push(ary, rubyobj_from_cval((char*)(subnode->val ) , NM_DTYPE(nmatrix)).rval);
216
+ }
217
+
218
+ // Push the coordinate values into the ary
219
+ rb_ary_push(ary, INT2FIX(row));
220
+ rb_ary_push(ary, INT2FIX(col));
221
+
222
+ // Yield the ary
223
+ rb_yield(ary);
224
+
225
+ // Update the col position
226
+ subnode = subnode->next;
227
+ }
228
+ // Update the row node
229
+ curr = curr->next;
230
+ }
231
+ return nmatrix;
232
+ }
233
+
234
+
235
+ static LIST* slice_copy(const LIST_STORAGE *src, LIST *src_rows, size_t *coords, size_t *lengths, size_t n) {
188
236
  NODE *src_node;
189
237
  LIST *dst_rows = NULL;
190
238
  void *val = NULL;
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -82,6 +82,7 @@ extern "C" {
82
82
  // Accessors //
83
83
  ///////////////
84
84
 
85
+ VALUE nm_list_each_stored_with_indices(VALUE nmatrix);
85
86
  void* nm_list_storage_ref(STORAGE* s, SLICE* slice);
86
87
  void* nm_list_storage_get(STORAGE* s, SLICE* slice);
87
88
  void* nm_list_storage_insert(STORAGE* s, SLICE* slice, void* val);
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -485,7 +485,7 @@ namespace yale_storage { // FIXME: Move to yale.cpp
485
485
  size_t request_capacity = shape[0] + ndnz + 1;
486
486
 
487
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);
488
+ YALE_STORAGE* lhs = nm_yale_storage_create(l_dtype, shape, 2, request_capacity, UINT8);
489
489
 
490
490
  if (lhs->capacity < request_capacity)
491
491
  rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", (unsigned long)request_capacity, (unsigned long)(lhs->capacity));
@@ -546,7 +546,7 @@ namespace yale_storage { // FIXME: Move to yale.cpp
546
546
  shape[1] = rhs->shape[1];
547
547
 
548
548
  size_t request_capacity = shape[0] + ndnz + 1;
549
- YALE_STORAGE* lhs = nm_yale_storage_create(l_dtype, shape, 2, request_capacity);
549
+ YALE_STORAGE* lhs = nm_yale_storage_create(l_dtype, shape, 2, request_capacity, UINT8);
550
550
 
551
551
  if (lhs->capacity < request_capacity)
552
552
  rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", (unsigned long)request_capacity, (unsigned long)(lhs->capacity));
@@ -614,7 +614,7 @@ extern "C" {
614
614
  STORAGE* nm_yale_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype) {
615
615
  NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_dense_storage, YALE_STORAGE*, const DENSE_STORAGE* rhs, nm::dtype_t l_dtype);
616
616
 
617
- nm::itype_t itype = nm_yale_storage_itype((const YALE_STORAGE*)right);
617
+ nm::itype_t itype = nm_yale_storage_default_itype((const YALE_STORAGE*)right);
618
618
 
619
619
  return (STORAGE*)ttable[l_dtype][right->dtype][itype]((const DENSE_STORAGE*)right, l_dtype);
620
620
  }
@@ -622,7 +622,7 @@ extern "C" {
622
622
  STORAGE* nm_yale_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype) {
623
623
  NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_list_storage, YALE_STORAGE*, const LIST_STORAGE* rhs, nm::dtype_t l_dtype);
624
624
 
625
- nm::itype_t itype = nm_yale_storage_itype((const YALE_STORAGE*)right);
625
+ nm::itype_t itype = nm_yale_storage_default_itype((const YALE_STORAGE*)right);
626
626
 
627
627
  return (STORAGE*)ttable[l_dtype][right->dtype][itype]((const LIST_STORAGE*)right, l_dtype);
628
628
  }
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -42,6 +42,7 @@
42
42
  #include <ruby.h>
43
43
  #include <algorithm> // std::min
44
44
  #include <cstdio> // std::fprintf
45
+ #include <iostream>
45
46
 
46
47
  /*
47
48
  * Project Includes
@@ -61,23 +62,19 @@
61
62
  /*
62
63
  * Macros
63
64
  */
65
+
64
66
  #ifndef NM_MAX
65
67
  #define NM_MAX(a,b) (((a)>(b))?(a):(b))
66
68
  #define NM_MIN(a,b) (((a)<(b))?(a):(b))
67
69
  #endif
68
70
 
69
-
70
- /*
71
- * Global Variables
72
- */
73
-
74
71
  /*
75
72
  * Forward Declarations
76
73
  */
77
74
 
78
75
  extern "C" {
79
76
  static YALE_STORAGE* nm_copy_alloc_struct(const YALE_STORAGE* rhs, const nm::dtype_t new_dtype, const size_t new_capacity, const size_t new_size);
80
- static YALE_STORAGE* alloc(nm::dtype_t dtype, size_t* shape, size_t dim);
77
+ static YALE_STORAGE* alloc(nm::dtype_t dtype, size_t* shape, size_t dim, nm::itype_t min_itype);
81
78
 
82
79
  /* Ruby-accessible functions */
83
80
  static VALUE nm_size(VALUE self);
@@ -90,8 +87,6 @@ extern "C" {
90
87
 
91
88
  } // end extern "C" block
92
89
 
93
-
94
-
95
90
  namespace nm { namespace yale_storage {
96
91
 
97
92
  template <typename DType, typename IType>
@@ -149,7 +144,7 @@ YALE_STORAGE* create_from_old_yale(dtype_t dtype, size_t* shape, void* r_ia, voi
149
144
  }
150
145
 
151
146
  // Having walked through the matrix, we now go about allocating the space for it.
152
- YALE_STORAGE* s = alloc(dtype, shape, 2);
147
+ YALE_STORAGE* s = alloc(dtype, shape, 2, UINT8);
153
148
 
154
149
  s->capacity = shape[0] + ndnz + 1;
155
150
  s->ndnz = ndnz;
@@ -299,9 +294,7 @@ size_t max_size(YALE_STORAGE* s) {
299
294
  ///////////////
300
295
 
301
296
  /*
302
- * Returns a slice of YALE_STORAGE object by coppy
303
- *
304
- * Slicing-related.
297
+ * Returns a slice of YALE_STORAGE object by copy
305
298
  */
306
299
  template <typename DType,typename IType>
307
300
  void* get(YALE_STORAGE* storage, SLICE* slice) {
@@ -312,10 +305,10 @@ void* get(YALE_STORAGE* storage, SLICE* slice) {
312
305
  shape[0] = slice->lengths[0];
313
306
  shape[1] = slice->lengths[1];
314
307
 
315
- IType *src_ija = reinterpret_cast<IType*>(storage->ija);
316
- DType *src_a = reinterpret_cast<DType*>(storage->a);
308
+ IType* src_ija = reinterpret_cast<IType*>(storage->ija);
309
+ DType* src_a = reinterpret_cast<DType*>(storage->a);
317
310
 
318
- // Calc ndnz
311
+ // Calc ndnz for the destination
319
312
  size_t ndnz = 0;
320
313
  size_t i,j; // indexes of destination matrix
321
314
  size_t k,l; // indexes of source matrix
@@ -326,54 +319,71 @@ void* get(YALE_STORAGE* storage, SLICE* slice) {
326
319
 
327
320
  if (j == i) continue;
328
321
 
329
- if (k == l && src_a[k] != 0) ndnz++; // for diagonal element of source
330
- else { // for non-diagonal element
331
- for (size_t c = src_ija[k]; c < src_ija[k+1]; c++)
332
- if (src_ija[c] == l) { ndnz++; break; }
322
+ if (k == l) { // for diagonal element of source
323
+ if (src_a[k] != 0) ++ndnz;
324
+ } else { // for non-diagonal element
325
+ for (size_t c = src_ija[k]; c < src_ija[k+1]; c++) {
326
+ if (src_ija[c] == l) {
327
+ ++ndnz;
328
+ break;
329
+ }
330
+ }
333
331
  }
334
332
 
335
333
  }
336
334
  }
337
335
 
338
336
  size_t request_capacity = shape[0] + ndnz + 1;
339
- YALE_STORAGE* ns = nm_yale_storage_create(storage->dtype, shape, 2, request_capacity);
337
+ //fprintf(stderr, "yale get copy: shape0=%d, shape1=%d, ndnz=%d, request_capacity=%d\n", shape[0], shape[1], ndnz, request_capacity);
338
+ YALE_STORAGE* ns = nm_yale_storage_create(storage->dtype, shape, 2, request_capacity, storage->itype);
340
339
 
341
340
  if (ns->capacity < request_capacity)
342
- rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", request_capacity, ns->capacity);
341
+ rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", request_capacity, ns->capacity);
343
342
 
344
343
  // Initialize the A and IJA arrays
345
344
  init<DType,IType>(ns);
346
- IType *dst_ija = reinterpret_cast<IType*>(ns->ija);
347
- DType *dst_a = reinterpret_cast<DType*>(ns->a);
345
+ IType* dst_ija = reinterpret_cast<IType*>(ns->ija);
346
+ DType* dst_a = reinterpret_cast<DType*>(ns->a);
348
347
 
349
348
  size_t ija = shape[0] + 1;
350
- DType val;
349
+ DType val = src_a[storage->shape[0]]; // use 0 as the default for copy
351
350
  for (i = 0; i < shape[0]; ++i) {
352
351
  k = i + offset[0];
353
352
  for (j = 0; j < shape[1]; ++j) {
353
+ bool found = false;
354
354
  l = j + offset[1];
355
355
 
356
356
  // Get value from source matrix
357
- if (k == l) val = src_a[k];
358
- else {
359
- // copy non-diagonal element
360
- for (size_t c = src_ija[k]; c < src_ija[k+1]; ++c) {
361
- if (src_ija[c] == l) val = src_a[c];
357
+ if (k == l) { // source diagonal
358
+ if (src_a[k] != 0) { // don't bother copying non-zero values from the diagonal
359
+ val = src_a[k];
360
+ found = true;
361
+ }
362
+ } else {
363
+ // copy one non-diagonal element
364
+ for (size_t c = src_ija[k]; !found && c < src_ija[k+1]; ++c) {
365
+ if (src_ija[c] == l) {
366
+ val = src_a[c];
367
+ found = true;
368
+ }
362
369
  }
363
370
  }
364
371
 
365
- // Set value to destination matrix
366
- if (i == j) dst_a[i] = val;
367
- else {
368
- // copy non-diagonal element
369
- dst_ija[ija] = j;
370
- dst_a[ija] = val;
372
+ if (found) {
373
+ // Set value in destination matrix
374
+ if (i == j) {
375
+ dst_a[i] = val;
376
+ } else {
377
+ // copy non-diagonal element
378
+ dst_ija[ija] = j;
379
+ dst_a[ija] = val;
371
380
 
372
- ++ija;
373
- for (size_t c = i + 1; c <= shape[0]; ++c) {
374
- dst_ija[c] = ija;
381
+ ++ija;
382
+ for (size_t c = i + 1; c <= shape[0]; ++c) {
383
+ dst_ija[c] = ija;
384
+ }
375
385
  }
376
- }
386
+ }
377
387
  }
378
388
  }
379
389
 
@@ -643,7 +653,7 @@ YALE_STORAGE* ew_op(const YALE_STORAGE* left, const YALE_STORAGE* right, dtype_t
643
653
 
644
654
  init_capacity = std::min(left->ndnz + right->ndnz + new_shape[0], new_shape[0] * new_shape[1]);
645
655
 
646
- dest = nm_yale_storage_create(dtype, new_shape, 2, init_capacity);
656
+ dest = nm_yale_storage_create(dtype, new_shape, 2, init_capacity, left->itype);
647
657
  da = reinterpret_cast<DType*>(dest->a);
648
658
 
649
659
  // Calculate diagonal values.
@@ -838,7 +848,7 @@ YALE_STORAGE* ew_op(const YALE_STORAGE* left, const YALE_STORAGE* right, dtype_t
838
848
  // Set the number of non-diagonal non-zero entries in the destination matrix.
839
849
  dest->ndnz = da_index;
840
850
 
841
- printf("Number of non-diagonal non-zero entires: %ld\n\n", (unsigned long)(dest->ndnz));
851
+ printf("Number of non-diagonal non-zero entries: %ld\n\n", (unsigned long)(dest->ndnz));
842
852
 
843
853
  // Set the capacity of the destination matrix.
844
854
  dest->capacity = dest->shape[0] + dest->ndnz + 1;
@@ -940,6 +950,8 @@ static char vector_insert_resize(YALE_STORAGE* s, size_t current_size, size_t po
940
950
  s->ija = reinterpret_cast<void*>(new_ija);
941
951
  s->a = reinterpret_cast<void*>(new_a);
942
952
 
953
+ fprintf(stderr, "resize\n");
954
+
943
955
  return 'i';
944
956
  }
945
957
 
@@ -1122,7 +1134,8 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
1122
1134
  // int8_t dtype = left->dtype;
1123
1135
 
1124
1136
  // Create result storage.
1125
- YALE_STORAGE* result = nm_yale_storage_create(left->dtype, resulting_shape, 2, left->capacity + right->capacity);
1137
+ nm::itype_t result_itype = static_cast<uint8_t>(left->itype) < static_cast<uint8_t>(right->itype) ? right->itype : left->itype;
1138
+ YALE_STORAGE* result = nm_yale_storage_create(left->dtype, resulting_shape, 2, left->capacity + right->capacity, result_itype);
1126
1139
  init<DType,IType>(result);
1127
1140
 
1128
1141
  IType* ijl = reinterpret_cast<IType*>(left->ija);
@@ -1144,7 +1157,106 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
1144
1157
  return reinterpret_cast<STORAGE*>(result);
1145
1158
  }
1146
1159
 
1147
- }} // end of namespace nm::yale_storage.
1160
+
1161
+ } // end of namespace nm::yale_storage
1162
+
1163
+
1164
+ // Helper function used only for the RETURN_SIZED_ENUMERATOR macro. Returns the length of
1165
+ // the matrix's storage.
1166
+ static VALUE nm_yale_enumerator_length(VALUE nmatrix) {
1167
+ long len = nm_yale_storage_get_size(NM_STORAGE_YALE(nmatrix));
1168
+ return LONG2NUM(len);
1169
+ }
1170
+
1171
+
1172
+ template <typename DType, typename IType>
1173
+ struct yale_each_stored_with_indices_helper {
1174
+ static VALUE iterate(VALUE nm) {
1175
+
1176
+ YALE_STORAGE* s = NM_STORAGE_YALE(nm);
1177
+ DType* a = reinterpret_cast<DType*>(s->a);
1178
+ IType* ija = reinterpret_cast<IType*>(s->ija);
1179
+
1180
+ // If we don't have a block, return an enumerator.
1181
+ RETURN_SIZED_ENUMERATOR(nm, 0, 0, nm_yale_enumerator_length);
1182
+
1183
+ // Iterate along diagonal
1184
+ for (size_t k = 0; k < s->shape[0]; ++k) {
1185
+ VALUE ii = LONG2NUM(k),
1186
+ jj = LONG2NUM(k);
1187
+
1188
+ VALUE v = rubyobj_from_cval(&(a[k]), NM_DTYPE(nm)).rval;
1189
+ rb_yield_values(3, v, ii, jj );
1190
+ }
1191
+
1192
+ // Iterate through non-diagonal elements, row by row
1193
+ for (long i = 0; i < s->shape[0]; ++i) {
1194
+ long p = static_cast<long>( ija[i] ),
1195
+ next_p = static_cast<long>( ija[i+1] );
1196
+
1197
+ for (; p < next_p; ++p) {
1198
+ long j = static_cast<long>(ija[p]);
1199
+ VALUE ii = LONG2NUM(i),
1200
+ jj = LONG2NUM(j);
1201
+
1202
+ VALUE v = rubyobj_from_cval(&(a[p]), NM_DTYPE(nm)).rval;
1203
+ rb_yield_values(3, v, ii, jj );
1204
+ }
1205
+ }
1206
+
1207
+ return nm;
1208
+ }
1209
+ };
1210
+
1211
+
1212
+ template <typename IType>
1213
+ struct yale_each_stored_with_indices_helper<RubyObject, IType> {
1214
+ static VALUE iterate(VALUE nm) {
1215
+
1216
+ YALE_STORAGE* s = NM_STORAGE_YALE(nm);
1217
+ RubyObject* a = reinterpret_cast<RubyObject*>(s->a);
1218
+ IType* ija = reinterpret_cast<IType*>(s->ija);
1219
+
1220
+ // If we don't have a block, return an enumerator.
1221
+ RETURN_SIZED_ENUMERATOR(nm, 0, 0, nm_yale_enumerator_length);
1222
+
1223
+ // Iterate along diagonal
1224
+ for (size_t k = 0; k < s->shape[0]; ++k) {
1225
+ VALUE ii = LONG2NUM(k),
1226
+ jj = LONG2NUM(k);
1227
+ rb_yield_values(3, a[k].rval, ii, jj ); // yield element, i, j
1228
+ }
1229
+
1230
+ // Iterate through non-diagonal elements, row by row
1231
+ for (long i = 0; i < s->shape[0]; ++i) {
1232
+ long p = static_cast<long>( ija[i] ),
1233
+ next_p = static_cast<long>( ija[i+1] );
1234
+
1235
+ for (; p < next_p; ++p) {
1236
+ long j = static_cast<long>(ija[p]);
1237
+ VALUE ii = LONG2NUM(i),
1238
+ jj = LONG2NUM(j);
1239
+
1240
+ rb_yield_values(3, a[p].rval, ii, jj );
1241
+ }
1242
+ }
1243
+
1244
+ return nm;
1245
+ }
1246
+ };
1247
+
1248
+
1249
+ /*
1250
+ * This function and the two helper structs enable us to use partial template specialization.
1251
+ * See also: http://stackoverflow.com/questions/6623375/c-template-specialization-on-functions
1252
+ */
1253
+ template <typename DType, typename IType>
1254
+ static VALUE yale_each_stored_with_indices(VALUE nm) {
1255
+ return yale_each_stored_with_indices_helper<DType, IType>::iterate(nm);
1256
+ }
1257
+
1258
+
1259
+ } // end of namespace nm.
1148
1260
 
1149
1261
  ///////////////////
1150
1262
  // Ruby Bindings //
@@ -1155,6 +1267,10 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
1155
1267
  extern "C" {
1156
1268
 
1157
1269
  void nm_init_yale_functions() {
1270
+ /*
1271
+ * This module stores methods that are useful for debugging Yale matrices,
1272
+ * i.e. the ones with +:yale+ stype.
1273
+ */
1158
1274
  cNMatrix_YaleFunctions = rb_define_module_under(cNMatrix, "YaleFunctions");
1159
1275
 
1160
1276
  rb_define_method(cNMatrix_YaleFunctions, "yale_ija", (METHOD)nm_ija, 0);
@@ -1172,6 +1288,18 @@ void nm_init_yale_functions() {
1172
1288
  // C ACCESSORS //
1173
1289
  /////////////////
1174
1290
 
1291
+
1292
+
1293
+ VALUE nm_yale_each_stored_with_indices(VALUE nmatrix) {
1294
+ nm::dtype_t d = NM_DTYPE(nmatrix);
1295
+ nm::itype_t i = NM_ITYPE(nmatrix);
1296
+
1297
+ NAMED_LI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_each_stored_with_indices, VALUE, VALUE)
1298
+
1299
+ return ttable[d][i](nmatrix);
1300
+ }
1301
+
1302
+
1175
1303
  /*
1176
1304
  * C accessor for inserting some value in a matrix (or replacing an existing cell).
1177
1305
  */
@@ -1262,7 +1390,7 @@ STORAGE* nm_yale_storage_copy_transposed(const STORAGE* rhs_base) {
1262
1390
 
1263
1391
  size_t size = nm_yale_storage_get_size(rhs);
1264
1392
 
1265
- YALE_STORAGE* lhs = nm_yale_storage_create(rhs->dtype, shape, 2, size);
1393
+ YALE_STORAGE* lhs = nm_yale_storage_create(rhs->dtype, shape, 2, size, nm::UINT8);
1266
1394
  nm_yale_storage_init(lhs);
1267
1395
 
1268
1396
  NAMED_LI_DTYPE_TEMPLATE_TABLE(transp, nm::math::transpose_yale, void, const size_t n, const size_t m, const void* ia_, const void* ja_, const void* a_, const bool diaga, void* ib_, void* jb_, void* b_, const bool move);
@@ -1362,7 +1490,7 @@ STORAGE* nm_yale_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE
1362
1490
  * create the storage.
1363
1491
  */
1364
1492
 
1365
- YALE_STORAGE* nm_yale_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, size_t init_capacity) {
1493
+ YALE_STORAGE* nm_yale_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, size_t init_capacity, nm::itype_t min_itype) {
1366
1494
  YALE_STORAGE* s;
1367
1495
  size_t max_capacity;
1368
1496
 
@@ -1371,7 +1499,7 @@ YALE_STORAGE* nm_yale_storage_create(nm::dtype_t dtype, size_t* shape, size_t di
1371
1499
  rb_raise(rb_eNotImpError, "Can only support 2D matrices");
1372
1500
  }
1373
1501
 
1374
- s = alloc(dtype, shape, dim);
1502
+ s = alloc(dtype, shape, dim, min_itype);
1375
1503
  max_capacity = nm::yale_storage::max_size(s);
1376
1504
 
1377
1505
  // Set matrix capacity (and ensure its validity)
@@ -1434,7 +1562,7 @@ void nm_yale_storage_mark(void* storage_base) {
1434
1562
  /*
1435
1563
  * Allocates and initializes the basic struct (but not the IJA or A vectors).
1436
1564
  */
1437
- static YALE_STORAGE* alloc(nm::dtype_t dtype, size_t* shape, size_t dim) {
1565
+ static YALE_STORAGE* alloc(nm::dtype_t dtype, size_t* shape, size_t dim, nm::itype_t min_itype) {
1438
1566
  YALE_STORAGE* s;
1439
1567
 
1440
1568
  s = ALLOC( YALE_STORAGE );
@@ -1445,6 +1573,10 @@ static YALE_STORAGE* alloc(nm::dtype_t dtype, size_t* shape, size_t dim) {
1445
1573
  s->dim = dim;
1446
1574
  s->itype = nm_yale_storage_itype_by_shape(shape);
1447
1575
 
1576
+ // See if a higher itype has been requested.
1577
+ if (static_cast<int8_t>(s->itype) < static_cast<int8_t>(min_itype))
1578
+ s->itype = min_itype;
1579
+
1448
1580
  return s;
1449
1581
  }
1450
1582
 
@@ -1466,6 +1598,9 @@ YALE_STORAGE* nm_yale_storage_create_from_old_yale(nm::dtype_t dtype, size_t* sh
1466
1598
  //////////////////////////////////////////////
1467
1599
 
1468
1600
  /*
1601
+ * call-seq:
1602
+ * yale_size -> Integer
1603
+ *
1469
1604
  * Get the size of a Yale matrix (the number of elements actually stored).
1470
1605
  *
1471
1606
  * For capacity (the maximum number of elements that can be stored without a resize), use capacity instead.
@@ -1478,6 +1613,9 @@ static VALUE nm_size(VALUE self) {
1478
1613
 
1479
1614
 
1480
1615
  /*
1616
+ * call-seq:
1617
+ * yale_a -> Array
1618
+ *
1481
1619
  * Get the A array of a Yale matrix (which stores the diagonal and the LU portions of the matrix).
1482
1620
  */
1483
1621
  static VALUE nm_a(VALUE self) {
@@ -1499,6 +1637,9 @@ static VALUE nm_a(VALUE self) {
1499
1637
 
1500
1638
 
1501
1639
  /*
1640
+ * call-seq:
1641
+ * yale_d -> Array
1642
+ *
1502
1643
  * Get the diagonal ("D") portion of the A array of a Yale matrix.
1503
1644
  */
1504
1645
  static VALUE nm_d(VALUE self) {
@@ -1513,6 +1654,9 @@ static VALUE nm_d(VALUE self) {
1513
1654
  }
1514
1655
 
1515
1656
  /*
1657
+ * call-seq:
1658
+ * yale_lu -> Array
1659
+ *
1516
1660
  * Get the non-diagonal ("LU") portion of the A array of a Yale matrix.
1517
1661
  */
1518
1662
  static VALUE nm_lu(VALUE self) {
@@ -1535,6 +1679,9 @@ static VALUE nm_lu(VALUE self) {
1535
1679
  }
1536
1680
 
1537
1681
  /*
1682
+ * call-seq:
1683
+ * yale_ia -> Array
1684
+ *
1538
1685
  * Get the IA portion of the IJA array of a Yale matrix. This gives the start and end positions of rows in the
1539
1686
  * JA and LU portions of the IJA and A arrays, respectively.
1540
1687
  */
@@ -1551,6 +1698,9 @@ static VALUE nm_ia(VALUE self) {
1551
1698
  }
1552
1699
 
1553
1700
  /*
1701
+ * call-seq:
1702
+ * yale_ja -> Array
1703
+ *
1554
1704
  * Get the JA portion of the IJA array of a Yale matrix. This gives the column indices for entries in corresponding
1555
1705
  * positions in the LU portion of the A array.
1556
1706
  */
@@ -1574,6 +1724,9 @@ static VALUE nm_ja(VALUE self) {
1574
1724
  }
1575
1725
 
1576
1726
  /*
1727
+ * call-seq:
1728
+ * yale_ija -> Array
1729
+ *
1577
1730
  * Get the IJA array of a Yale matrix.
1578
1731
  */
1579
1732
  static VALUE nm_ija(VALUE self) {