nmatrix 0.0.5 → 0.0.6

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +102 -10
  3. data/README.rdoc +24 -32
  4. data/Rakefile +1 -1
  5. data/ext/nmatrix/data/complex.h +9 -0
  6. data/ext/nmatrix/data/data.cpp +78 -4
  7. data/ext/nmatrix/data/data.h +86 -54
  8. data/ext/nmatrix/data/rational.h +2 -0
  9. data/ext/nmatrix/data/ruby_object.h +38 -8
  10. data/ext/nmatrix/extconf.rb +13 -7
  11. data/ext/nmatrix/nmatrix.cpp +262 -139
  12. data/ext/nmatrix/nmatrix.h +11 -4
  13. data/ext/nmatrix/storage/common.cpp +20 -13
  14. data/ext/nmatrix/storage/common.h +18 -12
  15. data/ext/nmatrix/storage/dense.cpp +122 -192
  16. data/ext/nmatrix/storage/dense.h +4 -2
  17. data/ext/nmatrix/storage/list.cpp +467 -636
  18. data/ext/nmatrix/storage/list.h +6 -3
  19. data/ext/nmatrix/storage/storage.cpp +83 -46
  20. data/ext/nmatrix/storage/storage.h +7 -7
  21. data/ext/nmatrix/storage/yale.cpp +621 -361
  22. data/ext/nmatrix/storage/yale.h +21 -9
  23. data/ext/nmatrix/ttable_helper.rb +27 -31
  24. data/ext/nmatrix/types.h +1 -1
  25. data/ext/nmatrix/util/math.cpp +9 -10
  26. data/ext/nmatrix/util/sl_list.cpp +1 -7
  27. data/ext/nmatrix/util/sl_list.h +0 -118
  28. data/lib/nmatrix/blas.rb +59 -18
  29. data/lib/nmatrix/monkeys.rb +0 -52
  30. data/lib/nmatrix/nmatrix.rb +136 -9
  31. data/lib/nmatrix/nvector.rb +33 -0
  32. data/lib/nmatrix/shortcuts.rb +95 -16
  33. data/lib/nmatrix/version.rb +1 -1
  34. data/lib/nmatrix/yale_functions.rb +25 -19
  35. data/spec/blas_spec.rb +1 -19
  36. data/spec/elementwise_spec.rb +132 -17
  37. data/spec/lapack_spec.rb +0 -3
  38. data/spec/nmatrix_list_spec.rb +18 -0
  39. data/spec/nmatrix_spec.rb +44 -18
  40. data/spec/nmatrix_yale_spec.rb +1 -3
  41. data/spec/shortcuts_spec.rb +26 -36
  42. data/spec/slice_spec.rb +2 -4
  43. metadata +2 -2
@@ -91,6 +91,8 @@ class Rational {
91
91
  rb_raise(rb_eNotImpError, "cannot convert from complex to rational");
92
92
  }
93
93
 
94
+ Rational(const RubyObject& other);
95
+
94
96
  /*
95
97
  * Rational inverse function -- creates a copy, but inverted.
96
98
  */
@@ -96,6 +96,7 @@ class RubyObject {
96
96
  inline RubyObject(int64_t other) : rval(INT2FIX(other)) {}
97
97
  // inline RubyObject(uint64_t other) : rval(INT2FIX(other)) {}
98
98
 
99
+
99
100
  /*
100
101
  * Float constructor.
101
102
  *
@@ -103,7 +104,40 @@ class RubyObject {
103
104
  */
104
105
  inline RubyObject(float other) : rval(rb_float_new(other)) {}
105
106
  inline RubyObject(double other) : rval(rb_float_new(other)) {}
106
-
107
+
108
+ /*
109
+ * Operators for converting RubyObjects to other C types.
110
+ */
111
+
112
+ #define RETURN_OBJ2NUM(mac) if (this->rval == Qtrue) return 1; else if (this->rval == Qfalse) return 0; else return mac(this->rval);
113
+
114
+ inline operator int8_t() const { RETURN_OBJ2NUM(NUM2INT) }
115
+ inline operator uint8_t() const { RETURN_OBJ2NUM(NUM2UINT) }
116
+ inline operator int16_t() const { RETURN_OBJ2NUM(NUM2INT) }
117
+ inline operator uint16_t() const { RETURN_OBJ2NUM(NUM2UINT) }
118
+ inline operator int32_t() const { RETURN_OBJ2NUM(NUM2LONG) }
119
+ inline operator VALUE() const { return rval; }
120
+ //inline operator uint32_t() const { return NUM2ULONG(this->rval); }
121
+ inline operator int64_t() const { RETURN_OBJ2NUM(NUM2LONG) }
122
+ inline operator uint64_t() const { RETURN_OBJ2NUM(NUM2ULONG) }
123
+ inline operator double() const { RETURN_OBJ2NUM(NUM2DBL) }
124
+ inline operator float() const { RETURN_OBJ2NUM(NUM2DBL) }
125
+
126
+ //template <typename IntType>
127
+ //inline operator Rational<typename std::enable_if<std::is_integral<IntType>::value, IntType>::type>() const { return this->to<Rational<IntType> >(); }
128
+
129
+ //template <typename IntType>
130
+ //inline operator Rational<typename std::enable_if<std::is_integral<IntType>::value, IntType>::type>&() const { static Rational<IntType> x = this->to<Rational<IntType> >(); return x; }
131
+ //inline operator Rational32() const { return this->to<Rational32>(); }
132
+ //inline operator Rational64() const { return this->to<Rational64>(); }
133
+ //inline operator Rational128() const { return this->to<Rational128>(); }
134
+
135
+ //template <typename FloatType>
136
+ //inline operator Complex<typename std::enable_if<std::is_floating_point<FloatType>::value, FloatType>::type>() const { return this->to<Complex<FloatType> >(); }
137
+
138
+ //template <typename FloatType>
139
+ //inline operator Complex<typename std::enable_if<std::is_floating_point<FloatType>::value, FloatType>::type>&() const { static Complex<FloatType> x = this->to<Complex<FloatType> >(); return x; }
140
+
107
141
  /*
108
142
  * Copy constructors.
109
143
  */
@@ -278,7 +312,7 @@ class RubyObject {
278
312
  * Convert a Ruby object to a complex number.
279
313
  */
280
314
  template <typename ComplexType>
281
- inline typename std::enable_if<made_from_same_template<ComplexType, Complex64>::value, ComplexType>::type to(void) {
315
+ inline typename std::enable_if<made_from_same_template<ComplexType, Complex64>::value, ComplexType>::type to(void) const {
282
316
  if (FIXNUM_P(this->rval) or TYPE(this->rval) == T_FLOAT or TYPE(this->rval) == T_RATIONAL) {
283
317
  return ComplexType(NUM2DBL(this->rval));
284
318
 
@@ -294,7 +328,7 @@ class RubyObject {
294
328
  * Convert a Ruby object to a rational number.
295
329
  */
296
330
  template <typename RationalType>
297
- inline typename std::enable_if<made_from_same_template<RationalType, Rational32>::value, RationalType>::type to(void) {
331
+ inline typename std::enable_if<made_from_same_template<RationalType, Rational32>::value, RationalType>::type to(void) const {
298
332
  if (FIXNUM_P(this->rval) or TYPE(this->rval) == T_FLOAT or TYPE(this->rval) == T_COMPLEX) {
299
333
  return RationalType(NUM2INT(this->rval));
300
334
 
@@ -305,11 +339,7 @@ class RubyObject {
305
339
  rb_raise(rb_eTypeError, "Invalid conversion to Rational type.");
306
340
  }
307
341
  }
308
-
309
- template <typename OtherType>
310
- inline operator OtherType () {
311
- return to<OtherType>();
312
- }
342
+
313
343
  };
314
344
 
315
345
  // Negative operator
@@ -164,10 +164,14 @@ $objs = %w{nmatrix ruby_constants data/data util/io util/math util/sl_list stora
164
164
  CONFIG['CXX'] = 'g++'
165
165
 
166
166
  def find_newer_gplusplus #:nodoc:
167
- [8,7,6,5,4,3].each do |minor|
168
- result = `which g++-4.#{minor}`
167
+ print "checking for apparent GNU g++ binary with C++0x/C++11 support... "
168
+ [9,8,7,6,5,4,3].each do |minor|
169
+ ver = "4.#{minor}"
170
+ gpp = "g++-#{ver}"
171
+ result = `which #{gpp}`
169
172
  next if result.empty?
170
- CONFIG['CXX'] = "g++-4.#{minor}"
173
+ CONFIG['CXX'] = gpp
174
+ puts ver
171
175
  return CONFIG['CXX']
172
176
  end
173
177
  false
@@ -195,13 +199,15 @@ else
195
199
  else
196
200
  $CPP_STANDARD = 'c++11'
197
201
  end
202
+ puts "using C++ standard... #{$CPP_STANDARD}"
203
+ puts "g++ reports version... " + `#{CONFIG['CXX']} --version|head -n 1|cut -f 3 -d " "`
198
204
  end
199
205
 
200
206
  # For release, these next two should both be changed to -O3.
201
- $CFLAGS += " -O3 " #" -O0 -g "
202
- # $CFLAGS += " -static -O0 -g "
203
- $CPPFLAGS += " -O3 -std=#{$CPP_STANDARD} " #" -O0 -g -std=#{$CPP_STANDARD} " #-fmax-errors=10 -save-temps
204
- # $CPPFLAGS += " -static -O0 -g -std=#{$CPP_STANDARD} "
207
+ #$CFLAGS += " -O3 " #" -O0 -g "
208
+ $CFLAGS += " -static -O0 -g "
209
+ #$CPPFLAGS += " -O3 -std=#{$CPP_STANDARD} " #" -O0 -g -std=#{$CPP_STANDARD} " #-fmax-errors=10 -save-temps
210
+ $CPPFLAGS += " -static -O0 -g -std=#{$CPP_STANDARD} "
205
211
 
206
212
  CONFIG['warnflags'].gsub!('-Wshorten-64-to-32', '') # doesn't work except in Mac-patched gcc (4.2)
207
213
  CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
@@ -50,6 +50,8 @@ extern "C" {
50
50
  #include "util/math.h"
51
51
  #include "util/io.h"
52
52
  #include "storage/storage.h"
53
+ #include "storage/list.h"
54
+ #include "storage/yale.h"
53
55
 
54
56
  #include "nmatrix.h"
55
57
 
@@ -329,21 +331,19 @@ extern "C" {
329
331
  static VALUE nm_init(int argc, VALUE* argv, VALUE nm);
330
332
  static VALUE nm_init_copy(VALUE copy, VALUE original);
331
333
  static VALUE nm_init_transposed(VALUE self);
332
- static VALUE nm_init_cast_copy(VALUE self, VALUE new_stype_symbol, VALUE new_dtype_symbol);
334
+ static VALUE nm_cast(VALUE self, VALUE new_stype_symbol, VALUE new_dtype_symbol, VALUE init);
333
335
  static VALUE nm_read(int argc, VALUE* argv, VALUE self);
334
336
  static VALUE nm_write(int argc, VALUE* argv, VALUE self);
335
- static VALUE nm_to_hash(VALUE self);
336
337
  static VALUE nm_init_yale_from_old_yale(VALUE shape, VALUE dtype, VALUE ia, VALUE ja, VALUE a, VALUE from_dtype, VALUE nm);
337
338
  static VALUE nm_alloc(VALUE klass);
338
- static void nm_delete(NMATRIX* mat);
339
- static void nm_delete_ref(NMATRIX* mat);
340
339
  static VALUE nm_dtype(VALUE self);
341
340
  static VALUE nm_itype(VALUE self);
342
341
  static VALUE nm_stype(VALUE self);
342
+ static VALUE nm_default_value(VALUE self);
343
343
  static VALUE nm_dim(VALUE self);
344
344
  static VALUE nm_shape(VALUE self);
345
345
  static VALUE nm_capacity(VALUE self);
346
- static VALUE nm_each(VALUE nmatrix);
346
+ static VALUE nm_each_with_indices(VALUE nmatrix);
347
347
  static VALUE nm_each_stored_with_indices(VALUE nmatrix);
348
348
 
349
349
  static SLICE* get_slice(size_t dim, VALUE* c, VALUE self);
@@ -355,6 +355,9 @@ static VALUE nm_is_ref(VALUE self);
355
355
 
356
356
  static VALUE is_symmetric(VALUE self, bool hermitian);
357
357
 
358
+ static VALUE nm_guess_dtype(VALUE self, VALUE v);
359
+ static VALUE nm_min_dtype(VALUE self, VALUE v);
360
+
358
361
  /*
359
362
  * Macro defines an element-wise accessor function for some operation.
360
363
  *
@@ -374,6 +377,8 @@ DECL_ELEMENTWISE_RUBY_ACCESSOR(add)
374
377
  DECL_ELEMENTWISE_RUBY_ACCESSOR(subtract)
375
378
  DECL_ELEMENTWISE_RUBY_ACCESSOR(multiply)
376
379
  DECL_ELEMENTWISE_RUBY_ACCESSOR(divide)
380
+ DECL_ELEMENTWISE_RUBY_ACCESSOR(power)
381
+ DECL_ELEMENTWISE_RUBY_ACCESSOR(mod)
377
382
  DECL_ELEMENTWISE_RUBY_ACCESSOR(eqeq)
378
383
  DECL_ELEMENTWISE_RUBY_ACCESSOR(neq)
379
384
  DECL_ELEMENTWISE_RUBY_ACCESSOR(lt)
@@ -417,17 +422,17 @@ void Init_nmatrix() {
417
422
  ///////////////////////
418
423
  // Class Definitions //
419
424
  ///////////////////////
420
-
425
+
421
426
  cNMatrix = rb_define_class("NMatrix", rb_cObject);
422
427
  cNVector = rb_define_class("NVector", cNMatrix);
423
-
428
+
424
429
  // Special exceptions
425
-
430
+
426
431
  /*
427
432
  * Exception raised when there's a problem with data.
428
433
  */
429
434
  nm_eDataTypeError = rb_define_class("DataTypeError", rb_eStandardError);
430
-
435
+
431
436
  /*
432
437
  * Exception raised when something goes wrong with the storage of a matrix.
433
438
  */
@@ -436,7 +441,7 @@ void Init_nmatrix() {
436
441
  ///////////////////
437
442
  // Class Methods //
438
443
  ///////////////////
439
-
444
+
440
445
  rb_define_alloc_func(cNMatrix, nm_alloc);
441
446
 
442
447
  ///////////////////////
@@ -445,6 +450,8 @@ void Init_nmatrix() {
445
450
 
446
451
  rb_define_singleton_method(cNMatrix, "upcast", (METHOD)nm_upcast, 2);
447
452
  rb_define_singleton_method(cNMatrix, "itype_by_shape", (METHOD)nm_itype_by_shape, 1);
453
+ rb_define_singleton_method(cNMatrix, "guess_dtype", (METHOD)nm_guess_dtype, 1);
454
+ rb_define_singleton_method(cNMatrix, "min_dtype", (METHOD)nm_min_dtype, 1);
448
455
 
449
456
  //////////////////////
450
457
  // Instance Methods //
@@ -462,7 +469,10 @@ void Init_nmatrix() {
462
469
  rb_define_method(cNMatrix, "dtype", (METHOD)nm_dtype, 0);
463
470
  rb_define_method(cNMatrix, "itype", (METHOD)nm_itype, 0);
464
471
  rb_define_method(cNMatrix, "stype", (METHOD)nm_stype, 0);
465
- rb_define_method(cNMatrix, "cast", (METHOD)nm_init_cast_copy, 2);
472
+ rb_define_method(cNMatrix, "cast_full", (METHOD)nm_cast, 3);
473
+ rb_define_method(cNMatrix, "default_value", (METHOD)nm_default_value, 0);
474
+ rb_define_protected_method(cNMatrix, "__list_default_value__", (METHOD)nm_list_default_value, 0);
475
+ rb_define_protected_method(cNMatrix, "__yale_default_value__", (METHOD)nm_yale_default_value, 0);
466
476
 
467
477
  rb_define_method(cNMatrix, "[]", (METHOD)nm_mref, -1);
468
478
  rb_define_method(cNMatrix, "slice", (METHOD)nm_mget, -1);
@@ -470,16 +480,21 @@ void Init_nmatrix() {
470
480
  rb_define_method(cNMatrix, "is_ref?", (METHOD)nm_is_ref, 0);
471
481
  rb_define_method(cNMatrix, "dimensions", (METHOD)nm_dim, 0);
472
482
 
473
- rb_define_protected_method(cNMatrix, "to_hash_c", (METHOD)nm_to_hash, 0); // handles list and dense, which are n-dimensional
474
- //rb_define_alias(cNMatrix, "to_h", "to_hash");
483
+ rb_define_protected_method(cNMatrix, "__list_to_hash__", (METHOD)nm_to_hash, 0); // handles list and dense, which are n-dimensional
475
484
 
476
485
  rb_define_method(cNMatrix, "shape", (METHOD)nm_shape, 0);
477
486
  rb_define_method(cNMatrix, "det_exact", (METHOD)nm_det_exact, 0);
478
487
  //rb_define_method(cNMatrix, "transpose!", (METHOD)nm_transpose_self, 0);
479
488
  rb_define_method(cNMatrix, "complex_conjugate!", (METHOD)nm_complex_conjugate_bang, 0);
480
489
 
481
- rb_define_method(cNMatrix, "each", (METHOD)nm_each, 0);
490
+ rb_define_protected_method(cNMatrix, "__dense_each__", (METHOD)nm_dense_each, 0);
491
+ rb_define_protected_method(cNMatrix, "__dense_map__", (METHOD)nm_dense_map, 0);
492
+ rb_define_protected_method(cNMatrix, "__dense_map_pair__", (METHOD)nm_dense_map_pair, 1);
493
+ rb_define_method(cNMatrix, "each_with_indices", (METHOD)nm_each_with_indices, 0);
482
494
  rb_define_method(cNMatrix, "each_stored_with_indices", (METHOD)nm_each_stored_with_indices, 0);
495
+ rb_define_protected_method(cNMatrix, "__list_map_merged_stored__", (METHOD)nm_list_map_merged_stored, 2);
496
+ rb_define_protected_method(cNMatrix, "__yale_map_merged_stored__", (METHOD)nm_yale_map_merged_stored, 2);
497
+ rb_define_protected_method(cNMatrix, "__yale_map_stored__", (METHOD)nm_yale_map_stored, 0);
483
498
 
484
499
  rb_define_method(cNMatrix, "==", (METHOD)nm_eqeq, 1);
485
500
 
@@ -487,7 +502,8 @@ void Init_nmatrix() {
487
502
  rb_define_method(cNMatrix, "-", (METHOD)nm_ew_subtract, 1);
488
503
  rb_define_method(cNMatrix, "*", (METHOD)nm_ew_multiply, 1);
489
504
  rb_define_method(cNMatrix, "/", (METHOD)nm_ew_divide, 1);
490
- //rb_define_method(cNMatrix, "%", (METHOD)nm_ew_mod, 1);
505
+ rb_define_method(cNMatrix, "**", (METHOD)nm_ew_power, 1);
506
+ rb_define_method(cNMatrix, "%", (METHOD)nm_ew_mod, 1);
491
507
 
492
508
  rb_define_method(cNMatrix, "=~", (METHOD)nm_ew_eqeq, 1);
493
509
  rb_define_method(cNMatrix, "!~", (METHOD)nm_ew_neq, 1);
@@ -496,6 +512,11 @@ void Init_nmatrix() {
496
512
  rb_define_method(cNMatrix, "<", (METHOD)nm_ew_lt, 1);
497
513
  rb_define_method(cNMatrix, ">", (METHOD)nm_ew_gt, 1);
498
514
 
515
+ /////////////////////////////
516
+ // Helper Instance Methods //
517
+ /////////////////////////////
518
+ rb_define_protected_method(cNMatrix, "__yale_vector_set__", (METHOD)nm_vector_set, -1);
519
+
499
520
  /////////////////////////
500
521
  // Matrix Math Methods //
501
522
  /////////////////////////
@@ -507,18 +528,18 @@ void Init_nmatrix() {
507
528
  rb_define_method(cNMatrix, "hermitian?", (METHOD)nm_hermitian, 0);
508
529
 
509
530
  rb_define_method(cNMatrix, "capacity", (METHOD)nm_capacity, 0);
510
-
531
+
511
532
  /////////////
512
533
  // Aliases //
513
534
  /////////////
514
-
535
+
515
536
  rb_define_alias(cNMatrix, "dim", "dimensions");
516
537
  rb_define_alias(cNMatrix, "equal?", "eql?");
517
-
538
+
518
539
  ///////////////////////
519
540
  // Symbol Generation //
520
541
  ///////////////////////
521
-
542
+
522
543
  nm_init_ruby_constants();
523
544
 
524
545
  //////////////////////////
@@ -611,7 +632,7 @@ static VALUE nm_capacity(VALUE self) {
611
632
  /*
612
633
  * Destructor.
613
634
  */
614
- static void nm_delete(NMATRIX* mat) {
635
+ void nm_delete(NMATRIX* mat) {
615
636
  static void (*ttable[nm::NUM_STYPES])(STORAGE*) = {
616
637
  nm_dense_storage_delete,
617
638
  nm_list_storage_delete,
@@ -625,10 +646,10 @@ static void nm_delete(NMATRIX* mat) {
625
646
  /*
626
647
  * Slicing destructor.
627
648
  */
628
- static void nm_delete_ref(NMATRIX* mat) {
649
+ void nm_delete_ref(NMATRIX* mat) {
629
650
  static void (*ttable[nm::NUM_STYPES])(STORAGE*) = {
630
651
  nm_dense_storage_delete_ref,
631
- nm_list_storage_delete_ref,
652
+ nm_list_storage_delete_ref,
632
653
  nm_yale_storage_delete
633
654
  };
634
655
  ttable[mat->stype](mat->storage);
@@ -679,7 +700,7 @@ static VALUE nm_itype_by_shape(VALUE self, VALUE shape_arg) {
679
700
 
680
701
  /*
681
702
  * call-seq:
682
- * upcast(first_dtype, second_dtype) ->
703
+ * upcast(first_dtype, second_dtype) -> Symbol
683
704
  *
684
705
  * Given a binary operation between types t1 and t2, what type will be returned?
685
706
  *
@@ -694,28 +715,52 @@ static VALUE nm_upcast(VALUE self, VALUE t1, VALUE t2) {
694
715
  }
695
716
 
696
717
 
697
-
698
718
  /*
699
719
  * call-seq:
700
- * each -> Enumerator
720
+ default_value -> ...
701
721
  *
702
- * Iterate over the matrix as you would an Enumerable (e.g., Array).
722
+ * Get the default value for the matrix. For dense, this is undefined and will return Qnil. For list, it is user-defined.
723
+ * For yale, it's going to be some variation on zero, but may be Qfalse or Qnil.
724
+ */
725
+ static VALUE nm_default_value(VALUE self) {
726
+ switch(NM_STYPE(self)) {
727
+ case nm::YALE_STORE:
728
+ return nm_yale_default_value(self);
729
+ case nm::LIST_STORE:
730
+ return nm_list_default_value(self);
731
+ case nm::DENSE_STORE:
732
+ default:
733
+ return Qnil;
734
+ }
735
+ }
736
+
737
+
738
+ /*
739
+ * call-seq:
740
+ * each_with_indices -> Enumerator
703
741
  *
704
- * Currently only works for dense.
742
+ * Iterate over all entries of any matrix in standard storage order (as with #each), and include the indices.
705
743
  */
706
- static VALUE nm_each(VALUE nmatrix) {
707
- volatile VALUE nm = nmatrix; // not sure why we do this, but it gets done in ruby's array.c.
744
+ static VALUE nm_each_with_indices(VALUE nmatrix) {
745
+ volatile VALUE nm = nmatrix;
708
746
 
709
747
  switch(NM_STYPE(nm)) {
748
+ case nm::YALE_STORE:
749
+ return nm_yale_each_with_indices(nm);
710
750
  case nm::DENSE_STORE:
711
- return nm_dense_each(nm);
751
+ return nm_dense_each_with_indices(nm);
752
+ case nm::LIST_STORE:
753
+ return nm_list_each_with_indices(nm, false);
712
754
  default:
713
- rb_raise(rb_eNotImpError, "only dense matrix's each method works right now");
755
+ rb_raise(nm_eDataTypeError, "Not a proper storage type");
714
756
  }
715
757
  }
716
758
 
717
759
  /*
718
- * Iterate over the sparse entries of any matrix. For dense and yale, this iterates over non-zero
760
+ * call-seq:
761
+ * each_stored_with_indices -> Enumerator
762
+ *
763
+ * Iterate over the stored entries of any matrix. For dense and yale, this iterates over non-zero
719
764
  * entries; for list, this iterates over non-default entries. Yields dim+1 values for each entry:
720
765
  * i, j, ..., and the entry itself.
721
766
  */
@@ -728,14 +773,13 @@ static VALUE nm_each_stored_with_indices(VALUE nmatrix) {
728
773
  case nm::DENSE_STORE:
729
774
  return nm_dense_each_with_indices(nm);
730
775
  case nm::LIST_STORE:
731
- return nm_list_each_stored_with_indices(nm);
776
+ return nm_list_each_with_indices(nm, true);
732
777
  default:
733
778
  rb_raise(nm_eDataTypeError, "Not a proper storage type");
734
779
  }
735
780
  }
736
781
 
737
782
 
738
-
739
783
  /*
740
784
  * Equality operator. Returns a single true or false value indicating whether
741
785
  * the matrices are equivalent.
@@ -777,7 +821,8 @@ DEF_ELEMENTWISE_RUBY_ACCESSOR(ADD, add)
777
821
  DEF_ELEMENTWISE_RUBY_ACCESSOR(SUB, subtract)
778
822
  DEF_ELEMENTWISE_RUBY_ACCESSOR(MUL, multiply)
779
823
  DEF_ELEMENTWISE_RUBY_ACCESSOR(DIV, divide)
780
- //DEF_ELEMENTWISE_RUBY_ACCESSOR(MOD, mod)
824
+ DEF_ELEMENTWISE_RUBY_ACCESSOR(POW, power)
825
+ DEF_ELEMENTWISE_RUBY_ACCESSOR(MOD, mod)
781
826
  DEF_ELEMENTWISE_RUBY_ACCESSOR(EQEQ, eqeq)
782
827
  DEF_ELEMENTWISE_RUBY_ACCESSOR(NEQ, neq)
783
828
  DEF_ELEMENTWISE_RUBY_ACCESSOR(LEQ, leq)
@@ -927,7 +972,7 @@ static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
927
972
 
928
973
  if (!SYMBOL_P(argv[0]) && TYPE(argv[0]) != T_STRING) {
929
974
  stype = nm::DENSE_STORE;
930
-
975
+
931
976
  } else {
932
977
  // 0: String or Symbol
933
978
  stype = interpret_stype(argv[0]);
@@ -938,12 +983,12 @@ static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
938
983
  if (argc == 7) {
939
984
  if (stype == nm::YALE_STORE) {
940
985
  return nm_init_yale_from_old_yale(argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], nm);
941
-
986
+
942
987
  } else {
943
988
  rb_raise(rb_eArgError, "Expected 2-4 arguments (or 7 for internal Yale creation)");
944
989
  }
945
990
  }
946
-
991
+
947
992
  // 1: Array or Fixnum
948
993
  size_t dim;
949
994
  size_t* shape = interpret_shape(argv[offset], &dim);
@@ -953,23 +998,23 @@ static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
953
998
 
954
999
  size_t init_cap = 0, init_val_len = 0;
955
1000
  void* init_val = NULL;
956
- if (NM_RUBYVAL_IS_NUMERIC(argv[1+offset]) || TYPE(argv[1+offset]) == T_ARRAY) {
1001
+ if (!SYMBOL_P(argv[1+offset]) || TYPE(argv[1+offset]) == T_ARRAY) {
957
1002
  // Initial value provided (could also be initial capacity, if yale).
958
-
959
- if (stype == nm::YALE_STORE) {
1003
+
1004
+ if (stype == nm::YALE_STORE && NM_RUBYVAL_IS_NUMERIC(argv[1+offset])) {
960
1005
  init_cap = FIX2UINT(argv[1+offset]);
961
-
1006
+
962
1007
  } else {
963
1008
  // 4: initial value / dtype
964
1009
  init_val = interpret_initial_value(argv[1+offset], dtype);
965
-
1010
+
966
1011
  if (TYPE(argv[1+offset]) == T_ARRAY) init_val_len = RARRAY_LEN(argv[1+offset]);
967
1012
  else init_val_len = 1;
968
1013
  }
969
-
1014
+
970
1015
  } else {
971
1016
  // DType is RUBYOBJ.
972
-
1017
+
973
1018
  if (stype == nm::DENSE_STORE) {
974
1019
  /*
975
1020
  * No need to initialize dense with any kind of default value unless it's
@@ -979,9 +1024,9 @@ static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
979
1024
  // Pretend [nil] was passed for RUBYOBJ.
980
1025
  init_val = ALLOC(VALUE);
981
1026
  *(VALUE*)init_val = Qnil;
982
-
1027
+
983
1028
  init_val_len = 1;
984
-
1029
+
985
1030
  } else {
986
1031
  init_val = NULL;
987
1032
  }
@@ -990,51 +1035,40 @@ static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
990
1035
  std::memset(init_val, 0, DTYPE_SIZES[dtype]);
991
1036
  }
992
1037
  }
993
-
1038
+
994
1039
  // TODO: Update to allow an array as the initial value.
995
1040
  NMATRIX* nmatrix;
996
1041
  UnwrapNMatrix(nm, nmatrix);
997
1042
 
998
1043
  nmatrix->stype = stype;
999
-
1044
+
1000
1045
  switch (stype) {
1001
1046
  case nm::DENSE_STORE:
1002
1047
  nmatrix->storage = (STORAGE*)nm_dense_storage_create(dtype, shape, dim, init_val, init_val_len);
1003
1048
  break;
1004
-
1049
+
1005
1050
  case nm::LIST_STORE:
1006
1051
  nmatrix->storage = (STORAGE*)nm_list_storage_create(dtype, shape, dim, init_val);
1007
1052
  break;
1008
-
1053
+
1009
1054
  case nm::YALE_STORE:
1010
1055
  nmatrix->storage = (STORAGE*)nm_yale_storage_create(dtype, shape, dim, init_cap, nm::UINT8);
1011
- nm_yale_storage_init((YALE_STORAGE*)(nmatrix->storage));
1056
+ nm_yale_storage_init((YALE_STORAGE*)(nmatrix->storage), NULL);
1012
1057
  break;
1013
1058
  }
1014
1059
 
1015
1060
  return nm;
1016
1061
  }
1017
1062
 
1063
+
1018
1064
  /*
1019
1065
  * call-seq:
1020
- * to_hash -> Hash
1021
- *
1022
- * Create a Ruby Hash from an NMatrix.
1066
+ * cast(stype) -> NMatrix
1067
+ * cast(stype, dtype, sparse_basis) -> NMatrix
1023
1068
  *
1024
- * This is an internal C function which handles list stype only.
1025
- */
1026
- static VALUE nm_to_hash(VALUE self) {
1027
- if (NM_STYPE(self) != nm::LIST_STORE) {
1028
- rb_raise(rb_eNotImpError, "please cast to :list first");
1029
- }
1030
-
1031
- return nm_list_storage_to_hash(NM_STORAGE_LIST(self), NM_DTYPE(self));
1032
- }
1033
-
1034
- /*
1035
1069
  * Copy constructor for changing dtypes and stypes.
1036
1070
  */
1037
- static VALUE nm_init_cast_copy(VALUE self, VALUE new_stype_symbol, VALUE new_dtype_symbol) {
1071
+ static VALUE nm_cast(VALUE self, VALUE new_stype_symbol, VALUE new_dtype_symbol, VALUE init) {
1038
1072
  nm::dtype_t new_dtype = nm_dtype_from_rbsymbol(new_dtype_symbol);
1039
1073
  nm::stype_t new_stype = nm_stype_from_rbsymbol(new_stype_symbol);
1040
1074
 
@@ -1046,9 +1080,12 @@ static VALUE nm_init_cast_copy(VALUE self, VALUE new_stype_symbol, VALUE new_dty
1046
1080
 
1047
1081
  UnwrapNMatrix( self, rhs );
1048
1082
 
1083
+ void* init_ptr = ALLOCA_N(char, DTYPE_SIZES[new_dtype]);
1084
+ rubyval_to_cval(init, new_dtype, init_ptr);
1085
+
1049
1086
  // Copy the storage
1050
- STYPE_CAST_COPY_TABLE(cast_copy);
1051
- lhs->storage = cast_copy[lhs->stype][rhs->stype](rhs->storage, new_dtype);
1087
+ CAST_TABLE(cast_copy);
1088
+ lhs->storage = cast_copy[lhs->stype][rhs->stype](rhs->storage, new_dtype, init_ptr);
1052
1089
 
1053
1090
  STYPE_MARK_TABLE(mark);
1054
1091
 
@@ -1090,8 +1127,8 @@ static VALUE nm_init_copy(VALUE copy, VALUE original) {
1090
1127
  lhs->stype = rhs->stype;
1091
1128
 
1092
1129
  // Copy the storage
1093
- STYPE_CAST_COPY_TABLE(ttable);
1094
- lhs->storage = ttable[lhs->stype][rhs->stype](rhs->storage, rhs->storage->dtype);
1130
+ CAST_TABLE(ttable);
1131
+ lhs->storage = ttable[lhs->stype][rhs->stype](rhs->storage, rhs->storage->dtype, NULL);
1095
1132
 
1096
1133
  return copy;
1097
1134
  }
@@ -1299,7 +1336,7 @@ static VALUE nm_read(int argc, VALUE* argv, VALUE self) {
1299
1336
 
1300
1337
 
1301
1338
  if (!RB_FILE_EXISTS(file)) { // FIXME: Errno::ENOENT
1302
- rb_raise(rb_get_errno_exc("ENOENT"), RSTRING_PTR(file));
1339
+ rb_raise(rb_get_errno_exc("ENOENT"), "%s", RSTRING_PTR(file));
1303
1340
  }
1304
1341
 
1305
1342
  // Open a file stream
@@ -1373,7 +1410,7 @@ static VALUE nm_read(int argc, VALUE* argv, VALUE self) {
1373
1410
  case nm::DENSE_STORE:
1374
1411
  return Data_Wrap_Struct(klass, nm_dense_storage_mark, nm_delete, nm);
1375
1412
  case nm::YALE_STORE:
1376
- return Data_Wrap_Struct(cNMatrix, nm_yale_storage_mark, nm_delete, nm);
1413
+ return Data_Wrap_Struct(klass, nm_yale_storage_mark, nm_delete, nm);
1377
1414
  default:
1378
1415
  return Qnil;
1379
1416
  }
@@ -1438,7 +1475,7 @@ static VALUE nm_mget(int argc, VALUE* argv, VALUE self) {
1438
1475
  nm_list_storage_get,
1439
1476
  nm_yale_storage_get
1440
1477
  };
1441
-
1478
+
1442
1479
  return nm_xslice(argc, argv, ttable[NM_STYPE(self)], nm_delete, self);
1443
1480
  }
1444
1481
 
@@ -1551,7 +1588,7 @@ static VALUE nm_multiply(VALUE left_v, VALUE right_v) {
1551
1588
 
1552
1589
  return matrix_multiply(left, right);
1553
1590
 
1554
- }
1591
+ }
1555
1592
 
1556
1593
  return Qnil;
1557
1594
  }
@@ -1708,26 +1745,29 @@ static VALUE nm_xslice(int argc, VALUE* argv, void* (*slice_func)(STORAGE*, SLIC
1708
1745
  static VALUE elementwise_op(nm::ewop_t op, VALUE left_val, VALUE right_val) {
1709
1746
  STYPE_MARK_TABLE(mark);
1710
1747
 
1711
- static STORAGE* (*ew_op[nm::NUM_STYPES])(nm::ewop_t, const STORAGE*, const STORAGE*, VALUE scalar) = {
1712
- nm_dense_storage_ew_op,
1713
- nm_list_storage_ew_op,
1714
- nm_yale_storage_ew_op
1715
- };
1716
-
1717
- NMATRIX *result = ALLOC(NMATRIX), *left;
1718
-
1748
+ NMATRIX* left;
1749
+ NMATRIX* result;
1750
+
1719
1751
  CheckNMatrixType(left_val);
1720
1752
  UnwrapNMatrix(left_val, left);
1721
1753
 
1722
1754
  if (TYPE(right_val) != T_DATA || (RDATA(right_val)->dfree != (RUBY_DATA_FUNC)nm_delete && RDATA(right_val)->dfree != (RUBY_DATA_FUNC)nm_delete_ref)) {
1723
1755
  // This is a matrix-scalar element-wise operation.
1724
-
1725
- if (left->stype != nm::YALE_STORE) {
1726
- result->storage = ew_op[left->stype](op, reinterpret_cast<STORAGE*>(left->storage), NULL, right_val);
1727
- result->stype = left->stype;
1728
- } else {
1729
- rb_raise(rb_eNotImpError, "Scalar element-wise operations not implemented for Yale storage yet");
1756
+ std::string sym;
1757
+ switch(left->stype) {
1758
+ case nm::DENSE_STORE:
1759
+ sym = "__dense_scalar_" + nm::EWOP_NAMES[op] + "__";
1760
+ break;
1761
+ case nm::YALE_STORE:
1762
+ sym = "__yale_scalar_" + nm::EWOP_NAMES[op] + "__";
1763
+ break;
1764
+ case nm::LIST_STORE:
1765
+ sym = "__list_scalar_" + nm::EWOP_NAMES[op] + "__";
1766
+ break;
1767
+ default:
1768
+ rb_raise(rb_eNotImpError, "unknown storage type requested scalar element-wise operation");
1730
1769
  }
1770
+ return rb_funcall(left_val, rb_intern(sym.c_str()), 1, right_val);
1731
1771
 
1732
1772
  } else {
1733
1773
 
@@ -1743,20 +1783,31 @@ static VALUE elementwise_op(nm::ewop_t op, VALUE left_val, VALUE right_val) {
1743
1783
 
1744
1784
  NMATRIX* right;
1745
1785
  UnwrapNMatrix(right_val, right);
1746
-
1747
- if (left->stype == right->stype) {
1748
1786
 
1749
- result->storage = ew_op[left->stype](op, reinterpret_cast<STORAGE*>(left->storage), reinterpret_cast<STORAGE*>(right->storage), Qnil);
1750
- result->stype = left->stype;
1787
+ if (left->stype == right->stype) {
1788
+ std::string sym;
1789
+
1790
+ switch(left->stype) {
1791
+ case nm::DENSE_STORE:
1792
+ sym = "__dense_elementwise_" + nm::EWOP_NAMES[op] + "__";
1793
+ break;
1794
+ case nm::YALE_STORE:
1795
+ sym = "__yale_elementwise_" + nm::EWOP_NAMES[op] + "__";
1796
+ break;
1797
+ case nm::LIST_STORE:
1798
+ sym = "__list_elementwise_" + nm::EWOP_NAMES[op] + "__";
1799
+ break;
1800
+ default:
1801
+ rb_raise(rb_eNotImpError, "unknown storage type requested element-wise operation");
1802
+ }
1803
+ return rb_funcall(left_val, rb_intern(sym.c_str()), 1, right_val);
1751
1804
 
1752
1805
  } else {
1753
1806
  rb_raise(rb_eArgError, "Element-wise operations are not currently supported between matrices with differing stypes.");
1754
1807
  }
1755
1808
  }
1756
1809
 
1757
- VALUE result_val = Data_Wrap_Struct(CLASS_OF(left_val), mark[result->stype], nm_delete, result);
1758
-
1759
- return result_val;
1810
+ return Data_Wrap_Struct(CLASS_OF(left_val), mark[result->stype], nm_delete, result);
1760
1811
  }
1761
1812
 
1762
1813
  /*
@@ -1767,7 +1818,7 @@ bool is_ref(const NMATRIX* matrix) {
1767
1818
  if (matrix->stype != nm::DENSE_STORE) {
1768
1819
  return false;
1769
1820
  }
1770
-
1821
+
1771
1822
  return ((DENSE_STORAGE*)(matrix->storage))->src != matrix->storage;
1772
1823
  }
1773
1824
 
@@ -1782,11 +1833,11 @@ static VALUE is_symmetric(VALUE self, bool hermitian) {
1782
1833
  if (NM_STYPE(self) == nm::DENSE_STORE) {
1783
1834
  if (hermitian) {
1784
1835
  nm_dense_storage_is_hermitian((DENSE_STORAGE*)(m->storage), m->storage->shape[0]);
1785
-
1836
+
1786
1837
  } else {
1787
1838
  nm_dense_storage_is_symmetric((DENSE_STORAGE*)(m->storage), m->storage->shape[0]);
1788
1839
  }
1789
-
1840
+
1790
1841
  } else {
1791
1842
  // TODO: Implement, at the very least, yale_is_symmetric. Model it after yale/transp.template.c.
1792
1843
  rb_raise(rb_eNotImpError, "symmetric? and hermitian? only implemented for dense currently");
@@ -1801,6 +1852,84 @@ static VALUE is_symmetric(VALUE self, bool hermitian) {
1801
1852
  // Utility Functions //
1802
1853
  ///////////////////////
1803
1854
 
1855
+ /*
1856
+ * Guess the dtype given a Ruby VALUE and return it as a symbol.
1857
+ *
1858
+ * Not to be confused with nm_dtype_guess, which returns an nm::dtype_t. (This calls that.)
1859
+ */
1860
+ static VALUE nm_guess_dtype(VALUE self, VALUE v) {
1861
+ return ID2SYM(rb_intern(DTYPE_NAMES[nm_dtype_guess(v)]));
1862
+ }
1863
+
1864
+ /*
1865
+ * Get the minimum allowable dtype for a Ruby VALUE and return it as a symbol.
1866
+ */
1867
+ static VALUE nm_min_dtype(VALUE self, VALUE v) {
1868
+ return ID2SYM(rb_intern(DTYPE_NAMES[nm_dtype_min(v)]));
1869
+ }
1870
+
1871
+ /*
1872
+ * Helper for nm_dtype_min(), handling integers.
1873
+ */
1874
+ nm::dtype_t nm_dtype_min_fixnum(int64_t v) {
1875
+ if (v >= 0 && v <= UCHAR_MAX) return nm::BYTE;
1876
+ else {
1877
+ v = std::abs(v);
1878
+ if (v <= CHAR_MAX) return nm::INT8;
1879
+ else if (v <= SHRT_MAX) return nm::INT16;
1880
+ else if (v <= INT_MAX) return nm::INT32;
1881
+ else return nm::INT64;
1882
+ }
1883
+ }
1884
+
1885
+ /*
1886
+ * Helper for nm_dtype_min(), handling rationals.
1887
+ */
1888
+ nm::dtype_t nm_dtype_min_rational(VALUE vv) {
1889
+ nm::Rational128* v = ALLOCA_N(nm::Rational128, 1);
1890
+ rubyval_to_cval(vv, nm::RATIONAL128, v);
1891
+
1892
+ int64_t i = std::max(std::abs(v->n), v->d);
1893
+ if (i <= SHRT_MAX) return nm::INT16;
1894
+ else if (i <= INT_MAX) return nm::INT32;
1895
+ else return nm::INT64;
1896
+ }
1897
+
1898
+ /*
1899
+ * Return the minimum dtype required to store a given value.
1900
+ *
1901
+ * This is kind of arbitrary. For Float, it always returns :float32 for example, since in some cases neither :float64
1902
+ * not :float32 are sufficient.
1903
+ *
1904
+ * This function is used in upcasting for scalar math. We want to ensure that :int8 + 1 does not return an :int64, basically.
1905
+ *
1906
+ * FIXME: Eventually, this function should actually look at the value stored in Fixnums (for example), so that it knows
1907
+ * whether to return :int64 or :int32.
1908
+ */
1909
+ nm::dtype_t nm_dtype_min(VALUE v) {
1910
+
1911
+ switch(TYPE(v)) {
1912
+ case T_FIXNUM:
1913
+ return nm_dtype_min_fixnum(FIX2LONG(v));
1914
+ case T_BIGNUM:
1915
+ return nm::INT64;
1916
+ case T_FLOAT:
1917
+ return nm::FLOAT32;
1918
+ case T_COMPLEX:
1919
+ return nm::COMPLEX64;
1920
+ case T_RATIONAL:
1921
+ return nm_dtype_min_rational(v);
1922
+ case T_STRING:
1923
+ return RSTRING_LEN(v) == 1 ? nm::BYTE : nm::RUBYOBJ;
1924
+ case T_TRUE:
1925
+ case T_FALSE:
1926
+ case T_NIL:
1927
+ default:
1928
+ return nm::RUBYOBJ;
1929
+ }
1930
+ }
1931
+
1932
+
1804
1933
  /*
1805
1934
  * Guess the data type given a value.
1806
1935
  *
@@ -1810,35 +1939,30 @@ nm::dtype_t nm_dtype_guess(VALUE v) {
1810
1939
  switch(TYPE(v)) {
1811
1940
  case T_TRUE:
1812
1941
  case T_FALSE:
1813
- return nm::BYTE;
1814
-
1942
+ case T_NIL:
1943
+ return nm::RUBYOBJ;
1815
1944
  case T_STRING:
1816
- if (RSTRING_LEN(v) == 1) {
1817
- return nm::BYTE;
1818
-
1819
- } else {
1820
- rb_raise(rb_eArgError, "Strings of length > 1 may not be stored in a matrix.");
1821
- }
1945
+ return RSTRING_LEN(v) == 1 ? nm::BYTE : nm::RUBYOBJ;
1822
1946
 
1823
1947
  #if SIZEOF_INT == 8
1824
1948
  case T_FIXNUM:
1825
1949
  return nm::INT64;
1826
-
1950
+
1827
1951
  case T_RATIONAL:
1828
1952
  return nm::RATIONAL128;
1829
-
1953
+
1830
1954
  #else
1831
1955
  # if SIZEOF_INT == 4
1832
1956
  case T_FIXNUM:
1833
1957
  return nm::INT32;
1834
-
1958
+
1835
1959
  case T_RATIONAL:
1836
1960
  return nm::RATIONAL64;
1837
-
1961
+
1838
1962
  #else
1839
1963
  case T_FIXNUM:
1840
1964
  return nm::INT16;
1841
-
1965
+
1842
1966
  case T_RATIONAL:
1843
1967
  return nm::RATIONAL32;
1844
1968
  # endif
@@ -1850,15 +1974,15 @@ nm::dtype_t nm_dtype_guess(VALUE v) {
1850
1974
  #if SIZEOF_FLOAT == 4
1851
1975
  case T_COMPLEX:
1852
1976
  return nm::COMPLEX128;
1853
-
1977
+
1854
1978
  case T_FLOAT:
1855
1979
  return nm::FLOAT64;
1856
-
1980
+
1857
1981
  #else
1858
1982
  # if SIZEOF_FLOAT == 2
1859
1983
  case T_COMPLEX:
1860
1984
  return nm::COMPLEX64;
1861
-
1985
+
1862
1986
  case T_FLOAT:
1863
1987
  return nm::FLOAT32;
1864
1988
  # endif
@@ -1867,13 +1991,12 @@ nm::dtype_t nm_dtype_guess(VALUE v) {
1867
1991
  case T_ARRAY:
1868
1992
  /*
1869
1993
  * May be passed for dense -- for now, just look at the first element.
1870
- *
1994
+ *
1871
1995
  * TODO: Look at entire array for most specific type.
1872
1996
  */
1873
-
1997
+
1874
1998
  return nm_dtype_guess(RARRAY_PTR(v)[0]);
1875
1999
 
1876
- case T_NIL:
1877
2000
  default:
1878
2001
  rb_raise(rb_eArgError, "Unable to guess a data type from provided parameters; data type must be specified manually.");
1879
2002
  }
@@ -1928,9 +2051,9 @@ static SLICE* get_slice(size_t dim, VALUE* c, VALUE self) {
1928
2051
  static double get_time(void) {
1929
2052
  struct timeval t;
1930
2053
  struct timezone tzp;
1931
-
2054
+
1932
2055
  gettimeofday(&t, &tzp);
1933
-
2056
+
1934
2057
  return t.tv_sec + t.tv_usec*1e-6;
1935
2058
  }
1936
2059
  #endif
@@ -1942,16 +2065,16 @@ static double get_time(void) {
1942
2065
  */
1943
2066
  static nm::dtype_t interpret_dtype(int argc, VALUE* argv, nm::stype_t stype) {
1944
2067
  int offset;
1945
-
2068
+
1946
2069
  switch (argc) {
1947
2070
  case 1:
1948
2071
  offset = 0;
1949
2072
  break;
1950
-
2073
+
1951
2074
  case 2:
1952
2075
  offset = 1;
1953
2076
  break;
1954
-
2077
+
1955
2078
  default:
1956
2079
  rb_raise(rb_eArgError, "Need an initial value or a dtype.");
1957
2080
  break;
@@ -1959,13 +2082,13 @@ static nm::dtype_t interpret_dtype(int argc, VALUE* argv, nm::stype_t stype) {
1959
2082
 
1960
2083
  if (SYMBOL_P(argv[offset])) {
1961
2084
  return nm_dtype_from_rbsymbol(argv[offset]);
1962
-
2085
+
1963
2086
  } else if (TYPE(argv[offset]) == T_STRING) {
1964
2087
  return nm_dtype_from_rbstring(StringValue(argv[offset]));
1965
-
2088
+
1966
2089
  } else if (stype == nm::YALE_STORE) {
1967
2090
  rb_raise(rb_eArgError, "Yale storage class requires a dtype.");
1968
-
2091
+
1969
2092
  } else {
1970
2093
  return nm_dtype_guess(argv[0]);
1971
2094
  }
@@ -1977,18 +2100,18 @@ static nm::dtype_t interpret_dtype(int argc, VALUE* argv, nm::stype_t stype) {
1977
2100
  static void* interpret_initial_value(VALUE arg, nm::dtype_t dtype) {
1978
2101
  unsigned int index;
1979
2102
  void* init_val;
1980
-
2103
+
1981
2104
  if (TYPE(arg) == T_ARRAY) {
1982
2105
  // Array
1983
-
2106
+
1984
2107
  init_val = ALLOC_N(int8_t, DTYPE_SIZES[dtype] * RARRAY_LEN(arg));
1985
2108
  for (index = 0; index < RARRAY_LEN(arg); ++index) {
1986
2109
  rubyval_to_cval(RARRAY_PTR(arg)[index], dtype, (char*)init_val + (index * DTYPE_SIZES[dtype]));
1987
2110
  }
1988
-
2111
+
1989
2112
  } else {
1990
2113
  // Single value
1991
-
2114
+
1992
2115
  init_val = rubyobj_to_cval(arg, dtype);
1993
2116
  }
1994
2117
 
@@ -2007,18 +2130,18 @@ static size_t* interpret_shape(VALUE arg, size_t* dim) {
2007
2130
  if (TYPE(arg) == T_ARRAY) {
2008
2131
  *dim = RARRAY_LEN(arg);
2009
2132
  shape = ALLOC_N(size_t, *dim);
2010
-
2133
+
2011
2134
  for (size_t index = 0; index < *dim; ++index) {
2012
2135
  shape[index] = FIX2UINT( RARRAY_PTR(arg)[index] );
2013
2136
  }
2014
-
2137
+
2015
2138
  } else if (FIXNUM_P(arg)) {
2016
2139
  *dim = 2;
2017
2140
  shape = ALLOC_N(size_t, *dim);
2018
-
2141
+
2019
2142
  shape[0] = FIX2UINT(arg);
2020
2143
  shape[1] = FIX2UINT(arg);
2021
-
2144
+
2022
2145
  } else {
2023
2146
  rb_raise(rb_eArgError, "Expected an array of numbers or a single Fixnum for matrix shape");
2024
2147
  }
@@ -2032,10 +2155,10 @@ static size_t* interpret_shape(VALUE arg, size_t* dim) {
2032
2155
  static nm::stype_t interpret_stype(VALUE arg) {
2033
2156
  if (SYMBOL_P(arg)) {
2034
2157
  return nm_stype_from_rbsymbol(arg);
2035
-
2158
+
2036
2159
  } else if (TYPE(arg) == T_STRING) {
2037
2160
  return nm_stype_from_rbstring(StringValue(arg));
2038
-
2161
+
2039
2162
  } else {
2040
2163
  rb_raise(rb_eArgError, "Expected storage type");
2041
2164
  }
@@ -2049,8 +2172,8 @@ STORAGE* matrix_storage_cast_alloc(NMATRIX* matrix, nm::dtype_t new_dtype) {
2049
2172
  if (matrix->storage->dtype == new_dtype && !is_ref(matrix))
2050
2173
  return matrix->storage;
2051
2174
 
2052
- STYPE_CAST_COPY_TABLE(cast_copy_storage);
2053
- return cast_copy_storage[matrix->stype][matrix->stype](matrix->storage, new_dtype);
2175
+ CAST_TABLE(cast_copy_storage);
2176
+ return cast_copy_storage[matrix->stype][matrix->stype](matrix->storage, new_dtype, NULL);
2054
2177
  }
2055
2178
 
2056
2179
  STORAGE_PAIR binary_storage_cast_alloc(NMATRIX* left_matrix, NMATRIX* right_matrix) {
@@ -2156,7 +2279,7 @@ VALUE rb_nmatrix_dense_create(nm::dtype_t dtype, size_t* shape, size_t dim, void
2156
2279
  shape_copy = ALLOC_N(size_t, nm_dim);
2157
2280
  shape_copy[0] = shape[0];
2158
2281
  shape_copy[1] = 1;
2159
-
2282
+
2160
2283
  } else {
2161
2284
  klass = cNMatrix;
2162
2285
  nm_dim = dim;