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,208 @@
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
+ // == yale.h
25
+ //
26
+ // "new yale" storage format for 2D matrices (like yale, but with
27
+ // the diagonal pulled out for O(1) access).
28
+ //
29
+ // Specifications:
30
+ // * dtype and index dtype must necessarily differ
31
+ // * index dtype is defined by whatever unsigned type can store
32
+ // max(rows,cols)
33
+ // * that means vector ija stores only index dtype, but a stores
34
+ // dtype
35
+ // * vectors must be able to grow as necessary
36
+ // * maximum size is rows*cols+1
37
+
38
+ #ifndef YALE_H
39
+ #define YALE_H
40
+
41
+ /*
42
+ * Standard Includes
43
+ */
44
+
45
+ #include <limits> // for std::numeric_limits<T>::max()
46
+
47
+ /*
48
+ * Project Includes
49
+ */
50
+
51
+ #include "types.h"
52
+
53
+ #include "data/data.h"
54
+
55
+ #include "common.h"
56
+
57
+ #include "nmatrix.h"
58
+
59
+ extern "C" {
60
+
61
+ /*
62
+ * Macros
63
+ */
64
+
65
+ #define NM_YALE_MINIMUM(sptr) (((YALE_STORAGE*)(sptr))->shape[0]*2 + 1) // arbitrarily defined
66
+
67
+ #ifndef NM_CHECK_ALLOC
68
+ #define NM_CHECK_ALLOC(x) if (!x) rb_raise(rb_eNoMemError, "insufficient memory");
69
+ #endif
70
+
71
+ /*
72
+ * Types
73
+ */
74
+
75
+
76
+ /*
77
+ * Data
78
+ */
79
+
80
+
81
+ /*
82
+ * Functions
83
+ */
84
+
85
+ ///////////////
86
+ // Lifecycle //
87
+ ///////////////
88
+
89
+ YALE_STORAGE* nm_yale_storage_create(dtype_t dtype, size_t* shape, size_t dim, size_t init_capacity);
90
+ YALE_STORAGE* nm_yale_storage_create_from_old_yale(dtype_t dtype, size_t* shape, void* ia, void* ja, void* a, dtype_t from_dtype);
91
+ YALE_STORAGE* nm_yale_storage_create_merged(const YALE_STORAGE* merge_template, const YALE_STORAGE* other);
92
+ void nm_yale_storage_delete(STORAGE* s);
93
+ void nm_yale_storage_init(YALE_STORAGE* s);
94
+ void nm_yale_storage_mark(void*);
95
+
96
+ ///////////////
97
+ // Accessors //
98
+ ///////////////
99
+
100
+ void* nm_yale_storage_get(STORAGE* s, SLICE* slice);
101
+ void* nm_yale_storage_ref(STORAGE* s, SLICE* slice);
102
+ char nm_yale_storage_set(STORAGE* storage, SLICE* slice, void* v);
103
+
104
+ inline size_t nm_yale_storage_get_size(const YALE_STORAGE* storage);
105
+
106
+ ///////////
107
+ // Tests //
108
+ ///////////
109
+
110
+ bool nm_yale_storage_eqeq(const STORAGE* left, const STORAGE* right);
111
+
112
+ //////////
113
+ // Math //
114
+ //////////
115
+
116
+ STORAGE* nm_yale_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right);
117
+ STORAGE* nm_yale_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector);
118
+
119
+ /////////////
120
+ // Utility //
121
+ /////////////
122
+
123
+ /*
124
+ * Calculates the itype a YALE_STORAGE object would need without actually needing
125
+ * to see the YALE_STORAGE object. Does this just by looking at the shape.
126
+ *
127
+ * Useful for creating Yale Storage by other means than NMatrix.new(:yale, ...),
128
+ * e.g., from a MATLAB v5 .mat file.
129
+ */
130
+ inline itype_t nm_yale_storage_itype_by_shape(const size_t* shape) {
131
+ uint64_t yale_max_size = shape[0] * (shape[1]+1);
132
+
133
+ if (yale_max_size < static_cast<uint64_t>(std::numeric_limits<uint8_t>::max()) - 2) {
134
+ return UINT8;
135
+
136
+ } else if (yale_max_size < static_cast<uint64_t>(std::numeric_limits<uint16_t>::max()) - 2) {
137
+ return UINT16;
138
+
139
+ } else if (yale_max_size < std::numeric_limits<uint32_t>::max() - 2) {
140
+ return UINT32;
141
+
142
+ } else {
143
+ return UINT64;
144
+ }
145
+ }
146
+
147
+ /*
148
+ * Determine the index dtype (which will be used for the ija vector). This is
149
+ * determined by matrix shape, not IJA/A vector capacity. Note that it's MAX-2
150
+ * because UINTX_MAX and UINTX_MAX-1 are both reserved for sparse matrix
151
+ * multiplication.
152
+ */
153
+ inline itype_t nm_yale_storage_itype(const YALE_STORAGE* s) {
154
+ return nm_yale_storage_itype_by_shape(s->shape);
155
+ }
156
+
157
+
158
+ /////////////////////////
159
+ // Copying and Casting //
160
+ /////////////////////////
161
+
162
+ STORAGE* nm_yale_storage_cast_copy(const STORAGE* rhs, dtype_t new_dtype);
163
+ STORAGE* nm_yale_storage_copy_transposed(const STORAGE* rhs_base);
164
+
165
+
166
+
167
+ void nm_init_yale_functions(void);
168
+
169
+
170
+ } // end of extern "C" block
171
+
172
+ namespace nm { namespace yale_storage {
173
+
174
+ /*
175
+ * Constants
176
+ */
177
+ const float GROWTH_CONSTANT = 1.5;
178
+
179
+
180
+ /*
181
+ * Templated Functions
182
+ */
183
+
184
+ template <typename IType>
185
+ int binary_search(YALE_STORAGE* s, IType left, IType right, IType key);
186
+
187
+ /*
188
+ * Clear out the D portion of the A vector (clearing the diagonal and setting
189
+ * the zero value).
190
+ *
191
+ * Note: This sets a literal 0 value. If your dtype is RUBYOBJ (a Ruby object),
192
+ * it'll actually be INT2FIX(0) instead of a string of NULLs.
193
+ */
194
+ template <typename DType>
195
+ inline void clear_diagonal_and_zero(YALE_STORAGE* s) {
196
+ DType* a = reinterpret_cast<DType*>(s->a);
197
+
198
+ // Clear out the diagonal + one extra entry
199
+ for (size_t i = 0; i < s->shape[0]+1; ++i) // insert Ruby zeros
200
+ a[i] = 0;
201
+ }
202
+
203
+ template <typename DType, typename IType>
204
+ void init(YALE_STORAGE* s);
205
+
206
+ }} // end of namespace nm::yale_storage
207
+
208
+ #endif // YALE_H
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # A helper file for generating and maintaining template tables.
4
+
5
+ def nullify(disabled)
6
+ DTYPES.map { |t| if disabled.include?(t) then :NULL else t end }
7
+ end
8
+
9
+ DTYPES = [
10
+ :uint8_t,
11
+ :int8_t,
12
+ :int16_t,
13
+ :int32_t,
14
+ :int64_t,
15
+ :float32_t,
16
+ :float64_t,
17
+ :'nm::Complex64',
18
+ :'nm::Complex128',
19
+ :'nm::Rational32',
20
+ :'nm::Rational64',
21
+ :'nm::Rational128',
22
+ :'nm::RubyObject'
23
+ ]
24
+
25
+ ITYPES = [
26
+ :uint8_t,
27
+ :uint16_t,
28
+ :uint32_t,
29
+ :uint64_t
30
+ ]
31
+
32
+ EWOPS = [
33
+ :'nm::EW_ADD',
34
+ :'nm::EW_SUB',
35
+ :'nm::EW_MUL',
36
+ :'nm::EW_DIV',
37
+ :'nm::EW_MOD',
38
+ :'nm::EW_EQEQ',
39
+ :'nm::EW_NEQ',
40
+ :'nm::EW_LT',
41
+ :'nm::EW_GT',
42
+ :'nm::EW_LEQ',
43
+ :'nm::EW_GEQ'
44
+ ]
45
+
46
+ LR_ALLOWED = {
47
+ :uint8_t => nullify([:RubyObject]),
48
+ :int8_t => nullify([:RubyObject]),
49
+ :int16_t => nullify([:RubyObject]),
50
+ :int32_t => nullify([:RubyObject]),
51
+ :int64_t => nullify([:RubyObject]),
52
+ :float32_t => nullify([:RubyObject]),
53
+ :float64_t => nullify([:RubyObject]),
54
+ :Complex64 => nullify([:RubyObject]),
55
+ :Complex128 => nullify([:RubyObject]),
56
+ :Rational32 => nullify([:float32_t, :float64_t, :'nm::Complex64', :'nm::Complex128', :'nm::RubyObject']),
57
+ :Rational64 => nullify([:float32_t, :float64_t, :'nm::Complex64', :'nm::Complex128', :'nm::RubyObject']),
58
+ :Rational128 => nullify([:float32_t, :float64_t, :'nm::Complex64', :'nm::Complex128', :'nm::RubyObject']),
59
+ :RubyObject => nullify(DTYPES - [:RubyObject])
60
+ }
61
+
62
+ lines =
63
+ case ARGV[0]
64
+ when 'OPLR'
65
+ '{' +
66
+ EWOPS.map do |op|
67
+
68
+ '{' +
69
+ DTYPES.map do |l_dtype|
70
+
71
+ '{' +
72
+ LR_ALLOWED[l_dtype].map do |r_dtype|
73
+ if r_dtype == :NULL
74
+ 'NULL'
75
+ else
76
+ "fun<#{op}, #{l_dtype}, #{r_dtype}>"
77
+ end
78
+ end.join(', ') +
79
+ '}'
80
+
81
+ end.join(",\n") +
82
+ '}'
83
+
84
+ end.join(",\n") +
85
+ '}'
86
+
87
+ when 'OPID'
88
+ '{' +
89
+ EWOPS.map do |op|
90
+ '{' +
91
+ ITYPES.map do |itype|
92
+ '{' +
93
+ DTYPES.map do |dtype|
94
+
95
+ if dtype == :NULL
96
+ 'NULL'
97
+ else
98
+ "fun<#{op}, #{itype}, #{dtype}>"
99
+ end
100
+
101
+ end.join(",") +
102
+ '}'
103
+ end.join(",\\\n") +
104
+ '}'
105
+ end.join(",\\\n") +
106
+ '}'
107
+
108
+ when 'LR'
109
+ '{' +
110
+ DTYPES.map do |l_dtype|
111
+
112
+ '{' +
113
+ LR_ALLOWED[l_dtype].map do |r_dtype|
114
+ if r_dtype == :NULL
115
+ 'NULL'
116
+ else
117
+ "fun<#{l_dtype}, #{r_dtype}>"
118
+ end
119
+ end.join(', ') +
120
+ '}'
121
+
122
+ end.join(",\n") +
123
+ '}'
124
+ end
125
+
126
+ puts lines
@@ -21,18 +21,45 @@
21
21
  //
22
22
  // * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
23
  //
24
- // == smmp1.c
24
+ // == types.h
25
25
  //
26
- // smmp1.c is automatically generated by generator.rb. Do not modify
27
- // it directly!
28
- //
29
- // This file ensures that all SMMP functions have the same signature,
30
- // so we can call them using arrays of function pointers.
26
+ // Definition of simple types used throughout NMatrix.
27
+
28
+ #ifndef NMATRIX_TYPES_H
29
+ #define NMATRIX_TYPES_H
30
+
31
+ /*
32
+ * Standard Includes
33
+ */
34
+
35
+ #include <stdint.h>
36
+
37
+ /*
38
+ * Project Includes
39
+ */
40
+
41
+ /*
42
+ * Macros
43
+ */
44
+
45
+ #define EPSILON 1E-10
46
+ #define FP_IS_ZERO(n) (-EPSILON < n && n < EPSILON)
47
+ #define FP_EQUAL(a, b) FP_IS_ZERO((a - b))
48
+
49
+ /*
50
+ * Types
51
+ */
31
52
 
32
- #include "nmatrix.h"
53
+ typedef float float32_t;
54
+ typedef double float64_t;
33
55
 
34
- #include <stdlib.h>
35
- #include <stdio.h>
36
56
 
57
+ /*
58
+ * Data
59
+ */
37
60
 
61
+ /*
62
+ * Functions
63
+ */
38
64
 
65
+ #endif
@@ -0,0 +1,295 @@
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
+ // == io.cpp
25
+ //
26
+ // Input/output support functions.
27
+
28
+ #include "io.h"
29
+
30
+ #include <ruby.h>
31
+
32
+ namespace nm { namespace io {
33
+
34
+ const char* const MATLAB_DTYPE_NAMES[NUM_MATLAB_DTYPES] = {
35
+ "miUNDEFINED0",
36
+ "miINT8",
37
+ "miUINT8",
38
+ "miINT16",
39
+ "miUINT16",
40
+ "miINT32",
41
+ "miUINT32",
42
+ "miSINGLE",
43
+ "miRESERVED8",
44
+ "miDOUBLE",
45
+ "miRESERVED10",
46
+ "miRESERVED11",
47
+ "miINT64",
48
+ "miUINT64",
49
+ "miMATRIX"
50
+ };
51
+
52
+ const size_t MATLAB_DTYPE_SIZES[NUM_MATLAB_DTYPES] = {
53
+ 1, // undefined
54
+ 1, // int8
55
+ 1, // uint8
56
+ 2, // int16
57
+ 2, // uint16
58
+ 4, // int32
59
+ 4, // uint32
60
+ sizeof(float),
61
+ 1, // reserved
62
+ sizeof(double),
63
+ 1, // reserved
64
+ 1, // reserved
65
+ 8, // int64
66
+ 8, // uint64
67
+ 1 // matlab array?
68
+ };
69
+
70
+
71
+ /*
72
+ * Templated function for converting from MATLAB dtypes to NMatrix dtypes.
73
+ */
74
+ template <typename DType, typename MDType>
75
+ char* matlab_cstring_to_dtype_string(size_t& result_len, const char* str, size_t bytes) {
76
+
77
+ result_len = bytes / sizeof(DType);
78
+ char* result = ALLOC_N(char, bytes / sizeof(DType));
79
+
80
+ if (bytes % sizeof(MDType) != 0) {
81
+ rb_raise(rb_eArgError, "the given string does not divide evenly for the given MATLAB dtype");
82
+ }
83
+
84
+ for (size_t i = 0, j = 0; i < bytes; i += sizeof(MDType), j += sizeof(DType)) {
85
+ *reinterpret_cast<DType*>(result+j) = (DType)(*reinterpret_cast<const MDType*>(str + i));
86
+ }
87
+
88
+ return result;
89
+ }
90
+
91
+ }} // end of namespace nm::io
92
+
93
+ extern "C" {
94
+
95
+ ///////////////////////
96
+ // Utility Functions //
97
+ ///////////////////////
98
+
99
+ /*
100
+ * Converts a string to a data type.
101
+ */
102
+ dtype_t nm_dtype_from_rbstring(VALUE str) {
103
+
104
+ for (size_t index = 0; index < NM_NUM_DTYPES; ++index) {
105
+ if (!std::strncmp(RSTRING_PTR(str), DTYPE_NAMES[index], RSTRING_LEN(str))) {
106
+ return static_cast<dtype_t>(index);
107
+ }
108
+ }
109
+
110
+ rb_raise(rb_eArgError, "Invalid data type string specified.");
111
+ }
112
+
113
+
114
+ /*
115
+ * Converts a symbol to a data type.
116
+ */
117
+ dtype_t nm_dtype_from_rbsymbol(VALUE sym) {
118
+
119
+ for (size_t index = 0; index < NM_NUM_DTYPES; ++index) {
120
+ if (SYM2ID(sym) == rb_intern(DTYPE_NAMES[index])) {
121
+ return static_cast<dtype_t>(index);
122
+ }
123
+ }
124
+
125
+ rb_raise(rb_eArgError, "Invalid data type symbol specified.");
126
+ }
127
+
128
+
129
+ /*
130
+ * Converts a symbol to an index type.
131
+ */
132
+ itype_t nm_itype_from_rbsymbol(VALUE sym) {
133
+
134
+ for (size_t index = 0; index < NM_NUM_ITYPES; ++index) {
135
+ if (SYM2ID(sym) == rb_intern(ITYPE_NAMES[index])) {
136
+ return static_cast<itype_t>(index);
137
+ }
138
+ }
139
+
140
+ rb_raise(rb_eArgError, "Invalid index type specified.");
141
+ }
142
+
143
+ /*
144
+ * Converts a string to a storage type. Only looks at the first three
145
+ * characters.
146
+ */
147
+ stype_t nm_stype_from_rbstring(VALUE str) {
148
+
149
+ for (size_t index = 0; index < NM_NUM_STYPES; ++index) {
150
+ if (!std::strncmp(RSTRING_PTR(str), STYPE_NAMES[index], 3)) {
151
+ return static_cast<stype_t>(index);
152
+ }
153
+ }
154
+
155
+ rb_raise(rb_eArgError, "Invalid storage type string specified");
156
+ return DENSE_STORE;
157
+ }
158
+
159
+ /*
160
+ * Converts a symbol to a storage type.
161
+ */
162
+ stype_t nm_stype_from_rbsymbol(VALUE sym) {
163
+
164
+ for (size_t index = 0; index < NM_NUM_STYPES; ++index) {
165
+ if (SYM2ID(sym) == rb_intern(STYPE_NAMES[index])) {
166
+ return static_cast<stype_t>(index);
167
+ }
168
+ }
169
+
170
+ rb_raise(rb_eArgError, "Invalid storage type symbol specified");
171
+ return DENSE_STORE;
172
+ }
173
+
174
+
175
+ /*
176
+ * Converts a MATLAB data-type symbol to an enum.
177
+ */
178
+ static nm::io::matlab_dtype_t matlab_dtype_from_rbsymbol(VALUE sym) {
179
+ for (size_t index = 0; index < nm::io::NUM_MATLAB_DTYPES; ++index) {
180
+ if (SYM2ID(sym) == rb_intern(nm::io::MATLAB_DTYPE_NAMES[index])) {
181
+ return static_cast<nm::io::matlab_dtype_t>(index);
182
+ }
183
+ }
184
+
185
+ rb_raise(rb_eArgError, "Invalid matlab type specified.");
186
+ }
187
+
188
+
189
+ /*
190
+ * Take a string of bytes which represent MATLAB data type values and repack them into a string
191
+ * of bytes representing values of an NMatrix dtype (or itype).
192
+ *
193
+ * Returns what appears to be a Ruby String.
194
+ *
195
+ * Arguments:
196
+ * * str :: the data
197
+ * * from :: symbol representing MATLAB data type (e.g., :miINT8)
198
+ * * options :: hash, give either :itype => some_itype or :dtype => some_dtype, tells function
199
+ * what to give as output.
200
+ */
201
+ static VALUE nm_rbstring_matlab_repack(VALUE self, VALUE str, VALUE from, VALUE options) {
202
+ nm::io::matlab_dtype_t from_type = matlab_dtype_from_rbsymbol(from);
203
+ uint8_t to_type;
204
+
205
+ if (TYPE(options) != T_HASH) {
206
+ rb_raise(rb_eArgError, "third argument to repack must be an options hash");
207
+ }
208
+
209
+ if (RB_HASH_HAS_SYMBOL_KEY(options, "dtype")) { // Hash#has_key?(:dtype)
210
+
211
+ dtype_t to_dtype = nm_dtype_from_rbsymbol(rb_hash_aref(options, ID2SYM(rb_intern("dtype"))));
212
+ to_type = static_cast<int8_t>(to_dtype);
213
+
214
+ } else if (RB_HASH_HAS_SYMBOL_KEY(options, "itype")) {
215
+
216
+ itype_t to_itype = nm_itype_from_rbsymbol(rb_hash_aref(options, ID2SYM(rb_intern("itype"))));
217
+
218
+ // we're going to cheat and use the DTYPE template table. To do this, we just act like uint8_t
219
+ // is a dtype (both are 0, itype and dtype), or we add 1 to the other itypes and treat them as
220
+ // signed.
221
+ to_type = static_cast<uint8_t>(to_itype);
222
+ if (to_itype != UINT8) to_type += 1;
223
+
224
+
225
+ } else {
226
+ rb_raise(rb_eArgError, "third argument must have either :itype or :dtype as a key");
227
+ }
228
+
229
+ // For next few lines, see explanation above NM_MATLAB_DTYPE_TEMPLATE_TABLE definition in io.h.
230
+ if (to_type >= static_cast<uint8_t>(COMPLEX64)) {
231
+ rb_raise(rb_eArgError, "can only repack into a simple dtype, no complex/rational/VALUE");
232
+ }
233
+
234
+ // Do the actual repacking -- really simple!
235
+ NM_MATLAB_DTYPE_TEMPLATE_TABLE(ttable, nm::io::matlab_cstring_to_dtype_string, char*, size_t& result_len, const char* str, size_t bytes);
236
+
237
+ size_t repacked_data_length;
238
+ char* repacked_data = ttable[to_type][from_type](repacked_data_length, RSTRING_PTR(str), RSTRING_LEN(str));
239
+
240
+ // Encode as 8-bit ASCII with a length -- don't want to hiccup on \0
241
+ VALUE result = rb_str_new(repacked_data, repacked_data_length);
242
+ free(repacked_data); // Don't forget to free what we allocated!
243
+
244
+ return result;
245
+ }
246
+
247
+
248
+ /*
249
+ * Take two byte-strings (real and imaginary) and treat them as if they contain
250
+ * a sequence of data of type dtype. Merge them together and return a new string.
251
+ */
252
+ static VALUE nm_rbstring_merge(VALUE self, VALUE rb_real, VALUE rb_imaginary, VALUE rb_dtype) {
253
+
254
+ // Sanity check.
255
+ if (RSTRING_LEN(rb_real) != RSTRING_LEN(rb_imaginary)) {
256
+ rb_raise(rb_eArgError, "real and imaginary components do not have same length");
257
+ }
258
+
259
+ dtype_t dtype = nm_dtype_from_rbsymbol(rb_dtype);
260
+ size_t len = DTYPE_SIZES[dtype];
261
+
262
+ char *real = RSTRING_PTR(rb_real),
263
+ *imag = RSTRING_PTR(rb_imaginary);
264
+
265
+ char* merge = ALLOCA_N(char, RSTRING_LEN(rb_real)*2);
266
+
267
+ size_t merge_pos = 0;
268
+
269
+ // Merge the two sequences
270
+ for (size_t i = 0; i < RSTRING_LEN(rb_real); i += len) {
271
+
272
+ // Copy real number
273
+ memcpy(merge + merge_pos, real + i, len);
274
+ merge_pos += len;
275
+
276
+ // Copy imaginary number
277
+ memcpy(merge + merge_pos, imag + i, len);
278
+ merge_pos += len;
279
+ }
280
+
281
+ return rb_str_new(merge, merge_pos);
282
+ }
283
+
284
+
285
+ void nm_init_io() {
286
+ cNMatrix_IO = rb_define_module_under(cNMatrix, "IO");
287
+ cNMatrix_IO_Matlab = rb_define_module_under(cNMatrix_IO, "Matlab");
288
+
289
+ rb_define_singleton_method(cNMatrix_IO_Matlab, "repack", (METHOD)nm_rbstring_matlab_repack, 3);
290
+ rb_define_singleton_method(cNMatrix_IO_Matlab, "complex_merge", (METHOD)nm_rbstring_merge, 3);
291
+ }
292
+
293
+
294
+
295
+ }