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.
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +3 -5
- data/Guardfile +6 -0
- data/History.txt +33 -0
- data/Manifest.txt +41 -38
- data/README.rdoc +88 -11
- data/Rakefile +35 -53
- data/ext/nmatrix/data/complex.h +372 -0
- data/ext/nmatrix/data/data.cpp +275 -0
- data/ext/nmatrix/data/data.h +707 -0
- data/ext/nmatrix/data/rational.h +421 -0
- data/ext/nmatrix/data/ruby_object.h +446 -0
- data/ext/nmatrix/extconf.rb +101 -51
- data/ext/nmatrix/new_extconf.rb +56 -0
- data/ext/nmatrix/nmatrix.cpp +1609 -0
- data/ext/nmatrix/nmatrix.h +265 -849
- data/ext/nmatrix/ruby_constants.cpp +134 -0
- data/ext/nmatrix/ruby_constants.h +103 -0
- data/ext/nmatrix/storage/common.cpp +70 -0
- data/ext/nmatrix/storage/common.h +170 -0
- data/ext/nmatrix/storage/dense.cpp +665 -0
- data/ext/nmatrix/storage/dense.h +116 -0
- data/ext/nmatrix/storage/list.cpp +1088 -0
- data/ext/nmatrix/storage/list.h +129 -0
- data/ext/nmatrix/storage/storage.cpp +658 -0
- data/ext/nmatrix/storage/storage.h +99 -0
- data/ext/nmatrix/storage/yale.cpp +1601 -0
- data/ext/nmatrix/storage/yale.h +208 -0
- data/ext/nmatrix/ttable_helper.rb +126 -0
- data/ext/nmatrix/{yale/smmp1_header.template.c → types.h} +36 -9
- data/ext/nmatrix/util/io.cpp +295 -0
- data/ext/nmatrix/util/io.h +117 -0
- data/ext/nmatrix/util/lapack.h +1175 -0
- data/ext/nmatrix/util/math.cpp +557 -0
- data/ext/nmatrix/util/math.h +1363 -0
- data/ext/nmatrix/util/sl_list.cpp +475 -0
- data/ext/nmatrix/util/sl_list.h +255 -0
- data/ext/nmatrix/util/util.h +78 -0
- data/lib/nmatrix/blas.rb +70 -0
- data/lib/nmatrix/io/mat5_reader.rb +567 -0
- data/lib/nmatrix/io/mat_reader.rb +162 -0
- data/lib/{string.rb → nmatrix/monkeys.rb} +49 -2
- data/lib/nmatrix/nmatrix.rb +199 -0
- data/lib/nmatrix/nvector.rb +103 -0
- data/lib/nmatrix/version.rb +27 -0
- data/lib/nmatrix.rb +22 -230
- data/nmatrix.gemspec +59 -0
- data/scripts/mac-brew-gcc.sh +47 -0
- data/spec/4x4_sparse.mat +0 -0
- data/spec/4x5_dense.mat +0 -0
- data/spec/blas_spec.rb +47 -0
- data/spec/elementwise_spec.rb +164 -0
- data/spec/io_spec.rb +60 -0
- data/spec/lapack_spec.rb +52 -0
- data/spec/math_spec.rb +96 -0
- data/spec/nmatrix_spec.rb +93 -89
- data/spec/nmatrix_yale_spec.rb +52 -36
- data/spec/nvector_spec.rb +1 -1
- data/spec/slice_spec.rb +257 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/utm5940.mtx +83844 -0
- metadata +113 -71
- data/.autotest +0 -23
- data/.gemtest +0 -0
- data/ext/nmatrix/cblas.c +0 -150
- data/ext/nmatrix/dense/blas_header.template.c +0 -52
- data/ext/nmatrix/dense/elementwise.template.c +0 -107
- data/ext/nmatrix/dense/gemm.template.c +0 -159
- data/ext/nmatrix/dense/gemv.template.c +0 -130
- data/ext/nmatrix/dense/rationalmath.template.c +0 -68
- data/ext/nmatrix/dense.c +0 -307
- data/ext/nmatrix/depend +0 -18
- data/ext/nmatrix/generator/syntax_tree.rb +0 -481
- data/ext/nmatrix/generator.rb +0 -594
- data/ext/nmatrix/list.c +0 -774
- data/ext/nmatrix/nmatrix.c +0 -1977
- data/ext/nmatrix/rational.c +0 -98
- data/ext/nmatrix/yale/complexmath.template.c +0 -71
- data/ext/nmatrix/yale/elementwise.template.c +0 -46
- data/ext/nmatrix/yale/elementwise_op.template.c +0 -73
- data/ext/nmatrix/yale/numbmm.template.c +0 -94
- data/ext/nmatrix/yale/smmp1.template.c +0 -21
- data/ext/nmatrix/yale/smmp2.template.c +0 -43
- data/ext/nmatrix/yale/smmp2_header.template.c +0 -46
- data/ext/nmatrix/yale/sort_columns.template.c +0 -56
- data/ext/nmatrix/yale/symbmm.template.c +0 -54
- data/ext/nmatrix/yale/transp.template.c +0 -68
- data/ext/nmatrix/yale.c +0 -726
- data/lib/array.rb +0 -67
- 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
|
-
// ==
|
|
24
|
+
// == types.h
|
|
25
25
|
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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
|
+
}
|