nmatrix 0.2.1 → 0.2.3
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.
- checksums.yaml +4 -4
- data/ext/nmatrix/data/data.cpp +9 -9
- data/ext/nmatrix/data/data.h +7 -8
- data/ext/nmatrix/data/ruby_object.h +1 -4
- data/ext/nmatrix/extconf.rb +9 -127
- data/ext/nmatrix/math.cpp +25 -25
- data/ext/nmatrix/math/asum.h +10 -31
- data/ext/nmatrix/math/cblas_templates_core.h +10 -10
- data/ext/nmatrix/math/getrf.h +2 -2
- data/ext/nmatrix/math/imax.h +12 -9
- data/ext/nmatrix/math/laswp.h +3 -3
- data/ext/nmatrix/math/long_dtype.h +16 -3
- data/ext/nmatrix/math/magnitude.h +54 -0
- data/ext/nmatrix/math/nrm2.h +19 -14
- data/ext/nmatrix/math/trsm.h +40 -36
- data/ext/nmatrix/math/util.h +14 -0
- data/ext/nmatrix/nmatrix.h +39 -1
- data/ext/nmatrix/ruby_nmatrix.c +45 -83
- data/ext/nmatrix/storage/common.h +9 -3
- data/ext/nmatrix/storage/dense/dense.cpp +4 -4
- data/ext/nmatrix/storage/list/list.cpp +2 -2
- data/ext/nmatrix/storage/yale/class.h +1 -1
- data/lib/nmatrix/blas.rb +103 -34
- data/lib/nmatrix/io/fortran_format.rb +8 -5
- data/lib/nmatrix/io/harwell_boeing.rb +11 -10
- data/lib/nmatrix/io/market.rb +9 -6
- data/lib/nmatrix/io/mat5_reader.rb +54 -29
- data/lib/nmatrix/io/mat_reader.rb +26 -14
- data/lib/nmatrix/io/point_cloud.rb +19 -11
- data/lib/nmatrix/math.rb +224 -5
- data/lib/nmatrix/mkmf.rb +103 -0
- data/lib/nmatrix/nmatrix.rb +20 -6
- data/lib/nmatrix/shortcuts.rb +415 -0
- data/lib/nmatrix/version.rb +1 -1
- data/spec/00_nmatrix_spec.rb +50 -1
- data/spec/02_slice_spec.rb +21 -21
- data/spec/blas_spec.rb +25 -3
- data/spec/math_spec.rb +233 -5
- data/spec/shortcuts_spec.rb +145 -5
- data/spec/spec_helper.rb +24 -1
- metadata +20 -4
@@ -551,7 +551,7 @@ void set(VALUE left, SLICE* slice, VALUE right) {
|
|
551
551
|
v = reinterpret_cast<D*>(t->elements);
|
552
552
|
v_size = nm_storage_count_max_elements(t);
|
553
553
|
|
554
|
-
} else if (
|
554
|
+
} else if (RB_TYPE_P(right, T_ARRAY)) {
|
555
555
|
nm_register_nmatrix(nm_and_free.first);
|
556
556
|
v_size = RARRAY_LEN(right);
|
557
557
|
v = NM_ALLOC_N(D, v_size);
|
@@ -1016,7 +1016,7 @@ VALUE nm_list_map_merged_stored(VALUE left, VALUE right, VALUE init) {
|
|
1016
1016
|
void* scalar_init = NULL;
|
1017
1017
|
|
1018
1018
|
// right might be a scalar, in which case this is a scalar operation.
|
1019
|
-
if (
|
1019
|
+
if (!IsNMatrixType(right)) {
|
1020
1020
|
nm::dtype_t r_dtype = Upcast[NM_DTYPE(left)][nm_dtype_min(right)];
|
1021
1021
|
scalar_init = rubyobj_to_cval(right, r_dtype); // make a copy of right
|
1022
1022
|
|
@@ -376,7 +376,7 @@ public:
|
|
376
376
|
v = reinterpret_cast<D*>(s->elements);
|
377
377
|
v_size = nm_storage_count_max_elements(s);
|
378
378
|
|
379
|
-
} else if (
|
379
|
+
} else if (RB_TYPE_P(right, T_ARRAY)) {
|
380
380
|
v_size = RARRAY_LEN(right);
|
381
381
|
v = NM_ALLOC_N(D, v_size);
|
382
382
|
if (dtype() == nm::RUBYOBJ) {
|
data/lib/nmatrix/blas.rb
CHANGED
@@ -9,8 +9,8 @@
|
|
9
9
|
#
|
10
10
|
# == Copyright Information
|
11
11
|
#
|
12
|
-
# SciRuby is Copyright (c) 2010 -
|
13
|
-
# NMatrix is Copyright (c) 2012 -
|
12
|
+
# SciRuby is Copyright (c) 2010 - 2016, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2016, John Woods and the Ruby Science Foundation
|
14
14
|
#
|
15
15
|
# Please see LICENSE.txt for additional copyright notices.
|
16
16
|
#
|
@@ -68,10 +68,19 @@ module NMatrix::BLAS
|
|
68
68
|
# - +ArgumentError+ -> +c+ must be +nil+ or a dense matrix.
|
69
69
|
# - +ArgumentError+ -> The dtype of the matrices must be equal.
|
70
70
|
#
|
71
|
-
def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0,
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0,
|
72
|
+
transpose_a = false, transpose_b = false, m = nil,
|
73
|
+
n = nil, k = nil, lda = nil, ldb = nil, ldc = nil)
|
74
|
+
|
75
|
+
raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') \
|
76
|
+
unless a.is_a?(NMatrix) and b.is_a? \
|
77
|
+
(NMatrix) and a.stype == :dense and b.stype == :dense
|
78
|
+
|
79
|
+
raise(ArgumentError, 'Expected nil or dense NMatrix as third argument.') \
|
80
|
+
unless c.nil? or (c.is_a?(NMatrix) \
|
81
|
+
and c.stype == :dense)
|
82
|
+
raise(ArgumentError, 'NMatrix dtype mismatch.') \
|
83
|
+
unless a.dtype == b.dtype and (c ? a.dtype == c.dtype : true)
|
75
84
|
|
76
85
|
# First, set m, n, and k, which depend on whether we're taking the
|
77
86
|
# transpose of a and b.
|
@@ -108,7 +117,8 @@ module NMatrix::BLAS
|
|
108
117
|
end
|
109
118
|
|
110
119
|
# For argument descriptions, see: http://www.netlib.org/blas/dgemm.f
|
111
|
-
::NMatrix::BLAS.cblas_gemm(:row, transpose_a, transpose_b,
|
120
|
+
::NMatrix::BLAS.cblas_gemm(:row, transpose_a, transpose_b,
|
121
|
+
m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
|
112
122
|
|
113
123
|
return c
|
114
124
|
end
|
@@ -140,17 +150,27 @@ module NMatrix::BLAS
|
|
140
150
|
# * *Raises* :
|
141
151
|
# - ++ ->
|
142
152
|
#
|
143
|
-
def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0,
|
144
|
-
|
145
|
-
|
146
|
-
raise(ArgumentError, '
|
153
|
+
def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0,
|
154
|
+
transpose_a = false, m = nil, n = nil, lda = nil,
|
155
|
+
incx = nil, incy = nil)
|
156
|
+
raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') \
|
157
|
+
unless a.is_a?(NMatrix) and x.is_a?(NMatrix) and \
|
158
|
+
a.stype == :dense and x.stype == :dense
|
159
|
+
|
160
|
+
raise(ArgumentError, 'Expected nil or dense NMatrix as third argument.') \
|
161
|
+
unless y.nil? or (y.is_a?(NMatrix) and y.stype == :dense)
|
162
|
+
|
163
|
+
raise(ArgumentError, 'NMatrix dtype mismatch.') \
|
164
|
+
unless a.dtype == x.dtype and (y ? a.dtype == y.dtype : true)
|
147
165
|
|
148
166
|
m ||= transpose_a == :transpose ? a.shape[1] : a.shape[0]
|
149
167
|
n ||= transpose_a == :transpose ? a.shape[0] : a.shape[1]
|
150
|
-
raise(ArgumentError, "dimensions don't match")
|
168
|
+
raise(ArgumentError, "dimensions don't match") \
|
169
|
+
unless x.shape[0] == n && x.shape[1] == 1
|
151
170
|
|
152
171
|
if y
|
153
|
-
raise(ArgumentError, "dimensions don't match")
|
172
|
+
raise(ArgumentError, "dimensions don't match") \
|
173
|
+
unless y.shape[0] == m && y.shape[1] == 1
|
154
174
|
else
|
155
175
|
y = NMatrix.new([m,1], dtype: a.dtype)
|
156
176
|
end
|
@@ -159,7 +179,8 @@ module NMatrix::BLAS
|
|
159
179
|
incx ||= 1
|
160
180
|
incy ||= 1
|
161
181
|
|
162
|
-
::NMatrix::BLAS.cblas_gemv(transpose_a, m, n,
|
182
|
+
::NMatrix::BLAS.cblas_gemv(transpose_a, m, n,
|
183
|
+
alpha, a, lda, x, incx, beta, y, incy)
|
163
184
|
|
164
185
|
return y
|
165
186
|
end
|
@@ -178,18 +199,27 @@ module NMatrix::BLAS
|
|
178
199
|
# - +incx+ -> stride of NMatrix +x+
|
179
200
|
# - +incy+ -> stride of NMatrix +y+
|
180
201
|
# - +n+ -> number of elements to consider in x and y
|
181
|
-
# - +in_place+ -> true
|
202
|
+
# - +in_place+ -> true if it's okay to modify the supplied
|
203
|
+
# +x+ and +y+ parameters directly;
|
204
|
+
# false if not. Default is false.
|
182
205
|
# * *Returns* :
|
183
206
|
# - Array with the results, in the format [xx, yy]
|
184
207
|
# * *Raises* :
|
185
208
|
# - +ArgumentError+ -> Expected dense NMatrices as first two arguments.
|
186
209
|
# - +ArgumentError+ -> NMatrix dtype mismatch.
|
187
|
-
# - +ArgumentError+ -> Need to supply n for non-standard incx,
|
210
|
+
# - +ArgumentError+ -> Need to supply n for non-standard incx,
|
211
|
+
# incy values.
|
188
212
|
#
|
189
213
|
def rot(x, y, c, s, incx = 1, incy = 1, n = nil, in_place=false)
|
190
|
-
raise(ArgumentError, 'Expected dense NMatrices as first two arguments.')
|
191
|
-
|
192
|
-
|
214
|
+
raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') \
|
215
|
+
unless x.is_a?(NMatrix) and y.is_a?(NMatrix) \
|
216
|
+
and x.stype == :dense and y.stype == :dense
|
217
|
+
|
218
|
+
raise(ArgumentError, 'NMatrix dtype mismatch.') \
|
219
|
+
unless x.dtype == y.dtype
|
220
|
+
|
221
|
+
raise(ArgumentError, 'Need to supply n for non-standard incx, incy values') \
|
222
|
+
if n.nil? && incx != 1 && incx != -1 && incy != 1 && incy != -1
|
193
223
|
|
194
224
|
n ||= [x.size/incx.abs, y.size/incy.abs].min
|
195
225
|
|
@@ -223,9 +253,11 @@ module NMatrix::BLAS
|
|
223
253
|
# call-seq:
|
224
254
|
# rotg(ab) -> [Numeric, Numeric]
|
225
255
|
#
|
226
|
-
# Apply givens plane rotation to the coordinates (a,b),
|
256
|
+
# Apply givens plane rotation to the coordinates (a,b),
|
257
|
+
# returning the cosine and sine of the angle theta.
|
227
258
|
#
|
228
|
-
# Since the givens rotation includes a square root,
|
259
|
+
# Since the givens rotation includes a square root,
|
260
|
+
# integers are disallowed.
|
229
261
|
#
|
230
262
|
# * *Arguments* :
|
231
263
|
# - +ab+ -> NMatrix with two elements
|
@@ -235,7 +267,8 @@ module NMatrix::BLAS
|
|
235
267
|
# - +ArgumentError+ -> Expected dense NMatrix of size 2
|
236
268
|
#
|
237
269
|
def rotg(ab)
|
238
|
-
raise(ArgumentError, "Expected dense NMatrix of shape [2,1] or [1,2]")
|
270
|
+
raise(ArgumentError, "Expected dense NMatrix of shape [2,1] or [1,2]") \
|
271
|
+
unless ab.is_a?(NMatrix) && ab.stype == :dense && ab.size == 2
|
239
272
|
|
240
273
|
::NMatrix::BLAS.cblas_rotg(ab)
|
241
274
|
end
|
@@ -245,10 +278,12 @@ module NMatrix::BLAS
|
|
245
278
|
# call-seq:
|
246
279
|
# asum(x, incx, n) -> Numeric
|
247
280
|
#
|
248
|
-
# Calculate the sum of absolute values of the entries of a
|
281
|
+
# Calculate the sum of absolute values of the entries of a
|
282
|
+
# vector +x+ of size +n+
|
249
283
|
#
|
250
284
|
# * *Arguments* :
|
251
|
-
# - +x+ -> an NMatrix (will also allow an NMatrix,
|
285
|
+
# - +x+ -> an NMatrix (will also allow an NMatrix,
|
286
|
+
# but will treat it as if it's a vector )
|
252
287
|
# - +incx+ -> the skip size (defaults to 1)
|
253
288
|
# - +n+ -> the size of +x+ (defaults to +x.size / incx+)
|
254
289
|
# * *Returns* :
|
@@ -259,9 +294,12 @@ module NMatrix::BLAS
|
|
259
294
|
#
|
260
295
|
def asum(x, incx = 1, n = nil)
|
261
296
|
n ||= x.size / incx
|
262
|
-
raise(ArgumentError, "Expected dense NMatrix for arg 0")
|
263
|
-
|
264
|
-
|
297
|
+
raise(ArgumentError, "Expected dense NMatrix for arg 0") \
|
298
|
+
unless x.is_a?(NMatrix)
|
299
|
+
|
300
|
+
raise(RangeError, "n out of range") \
|
301
|
+
if n*incx > x.size || n*incx <= 0 || n <= 0
|
302
|
+
::NMatrix::BLAS.cblas_asum(n, x, incx)
|
265
303
|
end
|
266
304
|
|
267
305
|
#
|
@@ -271,7 +309,8 @@ module NMatrix::BLAS
|
|
271
309
|
# Calculate the 2-norm of a vector +x+ of size +n+
|
272
310
|
#
|
273
311
|
# * *Arguments* :
|
274
|
-
# - +x+ -> an NMatrix (will also allow an
|
312
|
+
# - +x+ -> an NMatrix (will also allow an
|
313
|
+
# NMatrix, but will treat it as if it's a vector )
|
275
314
|
# - +incx+ -> the skip size (defaults to 1)
|
276
315
|
# - +n+ -> the size of +x+ (defaults to +x.size / incx+)
|
277
316
|
# * *Returns* :
|
@@ -282,24 +321,54 @@ module NMatrix::BLAS
|
|
282
321
|
#
|
283
322
|
def nrm2(x, incx = 1, n = nil)
|
284
323
|
n ||= x.size / incx
|
285
|
-
raise(ArgumentError, "Expected dense NMatrix for arg 0")
|
286
|
-
|
287
|
-
|
324
|
+
raise(ArgumentError, "Expected dense NMatrix for arg 0") \
|
325
|
+
unless x.is_a?(NMatrix)
|
326
|
+
|
327
|
+
raise(RangeError, "n out of range") \
|
328
|
+
if n*incx > x.size || n*incx <= 0 || n <= 0
|
329
|
+
::NMatrix::BLAS.cblas_nrm2(n, x, incx)
|
330
|
+
end
|
331
|
+
|
332
|
+
#
|
333
|
+
# call-seq:
|
334
|
+
# scal(alpha, vector, incx, n)
|
335
|
+
#
|
336
|
+
# Scale a matrix by a given scaling factor
|
337
|
+
#
|
338
|
+
# * *Arguments* :
|
339
|
+
# - +alpha+ -> a scaling factor
|
340
|
+
# - +vector+ -> an NMatrix
|
341
|
+
# - +incx+ -> the skip size (defaults to 1)
|
342
|
+
# - +n+ -> the size of +x+ (defaults to +x.size / incx+)
|
343
|
+
# * *Returns* :
|
344
|
+
# - The scaling result
|
345
|
+
# * *Raises* :
|
346
|
+
# - +ArgumentError+ -> Expected dense NMatrix for arg 0
|
347
|
+
# - +RangeError+ -> n out of range
|
348
|
+
#
|
349
|
+
def scal(alpha, vector, incx=1, n=nil)
|
350
|
+
n ||= vector.size / incx
|
351
|
+
raise(ArgumentError, "Expected dense NMatrix for arg 0") unless vector.is_a?(NMatrix)
|
352
|
+
raise(RangeError, "n out of range") if n*incx > vector.size || n*incx <= 0 || n <= 0
|
353
|
+
::NMatrix::BLAS.cblas_scal(n, alpha, vector, incx)
|
288
354
|
end
|
289
355
|
|
290
356
|
# The following are functions that used to be implemented in C, but
|
291
357
|
# now require nmatrix-atlas or nmatrix-lapcke to run properly, so we can just
|
292
358
|
# implemented their stubs in Ruby.
|
293
359
|
def cblas_trmm(order, side, uplo, trans_a, diag, m, n, alpha, a, lda, b, ldb)
|
294
|
-
raise(NotImplementedError,"cblas_trmm requires either the
|
360
|
+
raise(NotImplementedError,"cblas_trmm requires either the
|
361
|
+
nmatrix-lapacke or nmatrix-atlas gem")
|
295
362
|
end
|
296
363
|
|
297
364
|
def cblas_syrk(order, uplo, trans, n, k, alpha, a, lda, beta, c, ldc)
|
298
|
-
raise(NotImplementedError,"cblas_syrk requires either the
|
365
|
+
raise(NotImplementedError,"cblas_syrk requires either the
|
366
|
+
nmatrix-lapacke or nmatrix-atlas gem")
|
299
367
|
end
|
300
368
|
|
301
369
|
def cblas_herk(order, uplo, trans, n, k, alpha, a, lda, beta, c, ldc)
|
302
|
-
raise(NotImplementedError,"cblas_herk requires either the
|
370
|
+
raise(NotImplementedError,"cblas_herk requires either the
|
371
|
+
nmatrix-lapacke or nmatrix-atlas gem")
|
303
372
|
end
|
304
373
|
end
|
305
374
|
end
|
@@ -9,8 +9,8 @@
|
|
9
9
|
#
|
10
10
|
# == Copyright Information
|
11
11
|
#
|
12
|
-
# SciRuby is Copyright (c) 2010 -
|
13
|
-
# NMatrix is Copyright (c) 2012 -
|
12
|
+
# SciRuby is Copyright (c) 2010 - 2016, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2016, John Woods and the Ruby Science Foundation
|
14
14
|
#
|
15
15
|
# Please see LICENSE.txt for additional copyright notices.
|
16
16
|
#
|
@@ -70,7 +70,8 @@ class NMatrix
|
|
70
70
|
# * +:post_decimal_width+ - Width of the numerals after the decimal point.
|
71
71
|
# * +:exponent_width+ - Width of exponent part of the number.
|
72
72
|
def parse
|
73
|
-
raise(IOError, "Left or right parentheses missing")
|
73
|
+
raise(IOError, "Left or right parentheses missing") \
|
74
|
+
if parentheses_missing? # change tests to handle 'raise' not return
|
74
75
|
|
75
76
|
@result = {}
|
76
77
|
@string = @string[1..-2]
|
@@ -92,8 +93,10 @@ class NMatrix
|
|
92
93
|
# Changing any of the following regular expressions can lead to disaster
|
93
94
|
def valid_fortran_format?
|
94
95
|
@mdata = @string.match(/\A(\d*)(I)(\d+)\z/) # check for integer format
|
95
|
-
@mdata = @string.match(/\A(\d*)(F)(\d+)\.(\d+)\z/)
|
96
|
-
|
96
|
+
@mdata = @string.match(/\A(\d*)(F)(\d+)\.(\d+)\z/) \
|
97
|
+
if @mdata.nil? # check for floating point if not integer
|
98
|
+
@mdata = @string.match(/\A(\d*)(E)(\d+)\.(\d+)(E)?(\d*)\z/) \
|
99
|
+
if @mdata.nil? # check for exponential format if not floating point
|
97
100
|
|
98
101
|
@mdata
|
99
102
|
end
|
@@ -9,8 +9,8 @@
|
|
9
9
|
#
|
10
10
|
# == Copyright Information
|
11
11
|
#
|
12
|
-
# SciRuby is Copyright (c) 2010 -
|
13
|
-
# NMatrix is Copyright (c) 2012 -
|
12
|
+
# SciRuby is Copyright (c) 2010 - 2016, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2016, John Woods and the Ruby Science Foundation
|
14
14
|
#
|
15
15
|
# Please see LICENSE.txt for additional copyright notices.
|
16
16
|
#
|
@@ -48,14 +48,14 @@ class NMatrix
|
|
48
48
|
# == Arguments
|
49
49
|
#
|
50
50
|
# * +file_path+ - Path of the Harwell Boeing file to load.
|
51
|
-
# * +opts+ - Options for specifying whether you want
|
52
|
-
# header or only the header.
|
51
|
+
# * +opts+ - Options for specifying whether you want
|
52
|
+
# the values and header or only the header.
|
53
53
|
#
|
54
54
|
# == Options
|
55
55
|
#
|
56
|
-
# * +:header+ - If specified as *true*, will return only the header of
|
57
|
-
# Will return the NMatrix object and
|
58
|
-
# left blank.
|
56
|
+
# * +:header+ - If specified as *true*, will return only the header of
|
57
|
+
# the HB file.Will return the NMatrix object and
|
58
|
+
# header as an array if left blank.
|
59
59
|
#
|
60
60
|
# == Usage
|
61
61
|
#
|
@@ -65,8 +65,8 @@ class NMatrix
|
|
65
65
|
#
|
66
66
|
# == Alternate Usage
|
67
67
|
#
|
68
|
-
# You can specify the file using NMatrix::IO::Reader.new("path/to/file")
|
69
|
-
# then call *header* or *values* on the resulting object.
|
68
|
+
# You can specify the file using NMatrix::IO::Reader.new("path/to/file")
|
69
|
+
# and then call *header* or *values* on the resulting object.
|
70
70
|
def load file_path, opts={}
|
71
71
|
hb_obj = NMatrix::IO::HarwellBoeing::Reader.new(file_path)
|
72
72
|
|
@@ -103,7 +103,8 @@ class NMatrix
|
|
103
103
|
@header[:valcrd] = line[42...56].strip.to_i
|
104
104
|
@header[:rhscrd] = line[56...70].strip.to_i
|
105
105
|
|
106
|
-
raise(IOError, "Right hand sides not supported.")
|
106
|
+
raise(IOError, "Right hand sides not supported.") \
|
107
|
+
if @header[:rhscrd] > 0
|
107
108
|
|
108
109
|
line = @file.gets
|
109
110
|
|
data/lib/nmatrix/io/market.rb
CHANGED
@@ -8,8 +8,8 @@
|
|
8
8
|
#
|
9
9
|
# == Copyright Information
|
10
10
|
#
|
11
|
-
# SciRuby is Copyright (c) 2010 -
|
12
|
-
# NMatrix is Copyright (c) 2012 -
|
11
|
+
# SciRuby is Copyright (c) 2010 - 2016, Ruby Science Foundation
|
12
|
+
# NMatrix is Copyright (c) 2012 - 2016, John Woods and the Ruby Science Foundation
|
13
13
|
#
|
14
14
|
# Please see LICENSE.txt for additional copyright notices.
|
15
15
|
#
|
@@ -47,8 +47,9 @@ module NMatrix::IO::Market
|
|
47
47
|
} #:nodoc:
|
48
48
|
|
49
49
|
ENTRY_TYPE = {
|
50
|
-
:byte => :integer, :int8 => :integer, :int16 => :integer,
|
51
|
-
:
|
50
|
+
:byte => :integer, :int8 => :integer, :int16 => :integer,
|
51
|
+
:int32 => :integer, :int64 => :integer,:float32 => :real,
|
52
|
+
:float64 => :real, :complex64 => :complex, :complex128 => :complex
|
52
53
|
} #:nodoc:
|
53
54
|
|
54
55
|
class << self
|
@@ -68,7 +69,8 @@ module NMatrix::IO::Market
|
|
68
69
|
|
69
70
|
header = f.gets
|
70
71
|
header.chomp!
|
71
|
-
raise(IOError, "expected type code line beginning with '%%MatrixMarket matrix'")
|
72
|
+
raise(IOError, "expected type code line beginning with '%%MatrixMarket matrix'") \
|
73
|
+
if header !~ /^\%\%MatrixMarket\ matrix/
|
72
74
|
|
73
75
|
header = header.split
|
74
76
|
|
@@ -106,7 +108,8 @@ module NMatrix::IO::Market
|
|
106
108
|
end
|
107
109
|
entry_type = options[:pattern] ? :pattern : ENTRY_TYPE[matrix.dtype]
|
108
110
|
|
109
|
-
raise(ArgumentError, "expected two-dimensional NMatrix")
|
111
|
+
raise(ArgumentError, "expected two-dimensional NMatrix") \
|
112
|
+
if matrix.dim != 2
|
110
113
|
|
111
114
|
f = File.new(filename, 'w')
|
112
115
|
|
@@ -9,8 +9,8 @@
|
|
9
9
|
#
|
10
10
|
# == Copyright Information
|
11
11
|
#
|
12
|
-
# SciRuby is Copyright (c) 2010 -
|
13
|
-
# NMatrix is Copyright (c) 2012 -
|
12
|
+
# SciRuby is Copyright (c) 2010 - 2016, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2016, John Woods and the Ruby Science Foundation
|
14
14
|
#
|
15
15
|
# Please see LICENSE.txt for additional copyright notices.
|
16
16
|
#
|
@@ -63,7 +63,8 @@ module NMatrix::IO::Matlab
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def padded_bytes
|
66
|
-
@padded_bytes ||= content.size % 4 == 0 ?
|
66
|
+
@padded_bytes ||= content.size % 4 == 0 ? \
|
67
|
+
content.size : (content.size / 4 + 1) * 4
|
67
68
|
end
|
68
69
|
|
69
70
|
def write_packed(packedio, options = {})
|
@@ -89,9 +90,10 @@ module NMatrix::IO::Matlab
|
|
89
90
|
end
|
90
91
|
|
91
92
|
MatrixDataStruct = Struct.new(
|
92
|
-
:cells, :logical, :global, :complex,
|
93
|
-
:matlab_class, :dimensions,
|
94
|
-
:
|
93
|
+
:cells, :logical, :global, :complex,
|
94
|
+
:nonzero_max,:matlab_class, :dimensions,
|
95
|
+
:matlab_name, :real_part,:imaginary_part,
|
96
|
+
:row_index, :column_index)
|
95
97
|
|
96
98
|
class MatrixData < MatrixDataStruct #:nodoc:
|
97
99
|
include Packable
|
@@ -196,16 +198,19 @@ module NMatrix::IO::Matlab
|
|
196
198
|
imag_mdtype = self.imaginary_part.tag.data_type
|
197
199
|
|
198
200
|
# Make sure we convert both mdtypes do the same dtype
|
199
|
-
to_dtype ||= NMatrix.upcast(MatReader::MDTYPE_TO_DTYPE[real_mdtype],
|
201
|
+
to_dtype ||= NMatrix.upcast(MatReader::MDTYPE_TO_DTYPE[real_mdtype], \
|
202
|
+
MatReader::MDTYPE_TO_DTYPE[imag_mdtype])
|
200
203
|
|
201
|
-
# Let's make sure we don't try to send NMatrix complex integers.
|
204
|
+
# Let's make sure we don't try to send NMatrix complex integers.
|
205
|
+
# We need complex floating points.
|
202
206
|
unless [:float32, :float64].include?(to_dtype)
|
203
207
|
to_dtype = NMatrix.upcast(to_dtype, :float32)
|
204
208
|
end
|
205
209
|
|
206
210
|
STDERR.puts "imag: Requesting dtype #{to_dtype.inspect}"
|
207
211
|
# Repack the imaginary part
|
208
|
-
components[1] = ::NMatrix::IO::Matlab.repack( self.imaginary_part.data,
|
212
|
+
components[1] = ::NMatrix::IO::Matlab.repack( self.imaginary_part.data, \
|
213
|
+
imag_mdtype, :dtype => to_dtype )
|
209
214
|
|
210
215
|
else
|
211
216
|
|
@@ -221,10 +226,12 @@ module NMatrix::IO::Matlab
|
|
221
226
|
|
222
227
|
# Repack the real part
|
223
228
|
STDERR.puts "real: Requesting dtype #{to_dtype.inspect}"
|
224
|
-
components[0] = ::NMatrix::IO::Matlab.repack(
|
229
|
+
components[0] = ::NMatrix::IO::Matlab.repack( \
|
230
|
+
self.real_part.data, real_mdtype, :dtype => to_dtype )
|
225
231
|
|
226
232
|
# Merge the two parts if complex, or just return the real part.
|
227
|
-
[self.complex ? ::NMatrix::IO::Matlab.complex_merge(
|
233
|
+
[self.complex ? ::NMatrix::IO::Matlab.complex_merge( \
|
234
|
+
components[0], components[1], to_dtype ) : components[0],
|
228
235
|
to_dtype]
|
229
236
|
end
|
230
237
|
|
@@ -233,8 +240,10 @@ module NMatrix::IO::Matlab
|
|
233
240
|
# If data is already in the appropriate format, does not unpack or
|
234
241
|
# repack, just returns directly.
|
235
242
|
def repacked_indices
|
236
|
-
repacked_row_indices = ::NMatrix::IO::Matlab.repack(
|
237
|
-
|
243
|
+
repacked_row_indices = ::NMatrix::IO::Matlab.repack( \
|
244
|
+
self.row_index.data, :miINT32, :itype )
|
245
|
+
repacked_col_indices = ::NMatrix::IO::Matlab.repack( \
|
246
|
+
self.column_index.data, :miINT32, :itype )
|
238
247
|
|
239
248
|
[repacked_row_indices, repacked_col_indices]
|
240
249
|
end
|
@@ -276,7 +285,8 @@ module NMatrix::IO::Matlab
|
|
276
285
|
# MATLAB always uses :miINT32 for indices according to the spec
|
277
286
|
ia_ja = repacked_indices
|
278
287
|
data_str, repacked_dtype = repacked_data(dtype)
|
279
|
-
NMatrix.new(:yale, self.dimensions.reverse, repacked_dtype,
|
288
|
+
NMatrix.new(:yale, self.dimensions.reverse, repacked_dtype, \
|
289
|
+
ia_ja[0], ia_ja[1], data_str, repacked_dtype)
|
280
290
|
|
281
291
|
else
|
282
292
|
# Call regular dense constructor.
|
@@ -298,7 +308,9 @@ module NMatrix::IO::Matlab
|
|
298
308
|
|
299
309
|
begin
|
300
310
|
name_tag_data = packedio.read([Element, options])
|
301
|
-
self.matlab_name = name_tag_data.data.is_a?(Array) ?
|
311
|
+
self.matlab_name = name_tag_data.data.is_a?(Array) ? \
|
312
|
+
name_tag_data.data.collect { |i| i.chr }.join('') : \
|
313
|
+
name_tag_data.data.chr
|
302
314
|
|
303
315
|
rescue ElementDataIOError => e
|
304
316
|
STDERR.puts "ERROR: Failure while trying to read Matlab variable name: #{name_tag_data.inspect}"
|
@@ -315,10 +327,12 @@ module NMatrix::IO::Matlab
|
|
315
327
|
self.cells = []
|
316
328
|
STDERR.puts("Warning: Cell array does not yet support reading multiple dimensions") if dimensions.size > 2 || (dimensions[0] > 1 && dimensions[1] > 1)
|
317
329
|
number_of_cells = dimensions.inject(1) { |prod,i| prod * i }
|
318
|
-
number_of_cells.times { self.cells <<
|
330
|
+
number_of_cells.times { self.cells << \
|
331
|
+
packedio.read([Element, options]) }
|
319
332
|
|
320
333
|
else
|
321
|
-
read_opts = [RawElement, {:bytes => options[:bytes],
|
334
|
+
read_opts = [RawElement, {:bytes => options[:bytes], \
|
335
|
+
:endian => :native}]
|
322
336
|
|
323
337
|
if self.matlab_class == :mxSPARSE
|
324
338
|
self.column_index = packedio.read(read_opts)
|
@@ -331,7 +345,8 @@ module NMatrix::IO::Matlab
|
|
331
345
|
end
|
332
346
|
|
333
347
|
def ignore_padding(packedio, bytes)
|
334
|
-
packedio.read([Integer, {:unsigned => true,
|
348
|
+
packedio.read([Integer, {:unsigned => true, \
|
349
|
+
:bytes => bytes}]) if bytes > 0
|
335
350
|
end
|
336
351
|
end
|
337
352
|
|
@@ -386,7 +401,8 @@ module NMatrix::IO::Matlab
|
|
386
401
|
def each(&block)
|
387
402
|
stream.each(Element, {:endian => byte_order}) do |element|
|
388
403
|
if element.data.is_a?(Compressed)
|
389
|
-
StringIO.new(element.data.content, 'rb').each(Element,
|
404
|
+
StringIO.new(element.data.content, 'rb').each(Element, \
|
405
|
+
{:endian => byte_order}) do |compressed_element|
|
390
406
|
yield compressed_element.data
|
391
407
|
end
|
392
408
|
|
@@ -456,7 +472,8 @@ module NMatrix::IO::Matlab
|
|
456
472
|
end
|
457
473
|
|
458
474
|
def read_packed packedio, options
|
459
|
-
self.raw_data_type = packedio.read([Integer,
|
475
|
+
self.raw_data_type = packedio.read([Integer, \
|
476
|
+
DATA_TYPE_OPTS.merge(options)])
|
460
477
|
|
461
478
|
# Borrowed from a SciPy patch
|
462
479
|
upper = self.raw_data_type >> 16
|
@@ -504,20 +521,23 @@ module NMatrix::IO::Matlab
|
|
504
521
|
end
|
505
522
|
|
506
523
|
def read_packed(packedio, options)
|
507
|
-
raise(ArgumentError, 'Missing mandatory option :endian.')
|
524
|
+
raise(ArgumentError, 'Missing mandatory option :endian.') \
|
525
|
+
unless options.has_key?(:endian)
|
508
526
|
|
509
527
|
tag = packedio.read([Tag, {:endian => options[:endian]}])
|
510
528
|
data_type = MDTYPE_UNPACK_ARGS[tag.data_type]
|
511
529
|
|
512
530
|
self.tag = tag
|
513
531
|
|
514
|
-
raise ElementDataIOError.new(tag, "Unrecognized Matlab type #{tag.raw_data_type}")
|
532
|
+
raise ElementDataIOError.new(tag, "Unrecognized Matlab type #{tag.raw_data_type}") \
|
533
|
+
if data_type.nil?
|
515
534
|
|
516
535
|
if tag.bytes == 0
|
517
536
|
self.data = []
|
518
537
|
|
519
538
|
else
|
520
|
-
number_of_reads = data_type[1].has_key?(:bytes) ?
|
539
|
+
number_of_reads = data_type[1].has_key?(:bytes) ? \
|
540
|
+
tag.bytes / data_type[1][:bytes] : 1
|
521
541
|
data_type[1].merge!({:endian => options[:endian]})
|
522
542
|
|
523
543
|
if number_of_reads == 1
|
@@ -531,7 +551,8 @@ module NMatrix::IO::Matlab
|
|
531
551
|
end
|
532
552
|
|
533
553
|
begin
|
534
|
-
ignore_padding(packedio, (tag.bytes + tag.size) % 8)
|
554
|
+
ignore_padding(packedio, (tag.bytes + tag.size) % 8) \
|
555
|
+
unless [:miMATRIX, :miCOMPRESSED].include?(tag.data_type)
|
535
556
|
|
536
557
|
rescue EOFError
|
537
558
|
STDERR.puts self.tag.inspect
|
@@ -545,7 +566,8 @@ module NMatrix::IO::Matlab
|
|
545
566
|
#STDERR.puts "Ignored #{8 - bytes} on #{self.tag.data_type}"
|
546
567
|
ignored = packedio.read(8 - bytes)
|
547
568
|
ignored_unpacked = ignored.unpack("C*")
|
548
|
-
raise(IOError, "Nonzero padding detected: #{ignored_unpacked}")
|
569
|
+
raise(IOError, "Nonzero padding detected: #{ignored_unpacked}") \
|
570
|
+
if ignored_unpacked.any? { |i| i != 0 }
|
549
571
|
end
|
550
572
|
end
|
551
573
|
|
@@ -558,13 +580,16 @@ module NMatrix::IO::Matlab
|
|
558
580
|
# manually, or pass the raw string of bytes into NMatrix.
|
559
581
|
class RawElement < Element #:nodoc:
|
560
582
|
def read_packed(packedio, options)
|
561
|
-
raise(ArgumentError, 'Missing mandatory option :endian.')
|
583
|
+
raise(ArgumentError, 'Missing mandatory option :endian.') \
|
584
|
+
unless options.has_key?(:endian)
|
562
585
|
|
563
|
-
self.tag = packedio.read([Tag, {:endian => options[:endian]
|
564
|
-
self.data = packedio.read([String, {:endian => options[:endian],
|
586
|
+
self.tag = packedio.read([Tag, {:endian => options[:endian]}])
|
587
|
+
self.data = packedio.read([String, {:endian => options[:endian], \
|
588
|
+
:bytes => tag.bytes }])
|
565
589
|
|
566
590
|
begin
|
567
|
-
ignore_padding(packedio, (tag.bytes + tag.size) % 8)
|
591
|
+
ignore_padding(packedio, (tag.bytes + tag.size) % 8) \
|
592
|
+
unless [:miMATRIX, :miCOMPRESSED].include?(tag.data_type)
|
568
593
|
|
569
594
|
rescue EOFError
|
570
595
|
STDERR.puts self.tag.inspect
|