nmatrix 0.2.1 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|