nmatrix 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/CONTRIBUTING.md +66 -0
- data/Gemfile +1 -1
- data/History.txt +68 -10
- data/LICENSE.txt +2 -2
- data/Manifest.txt +2 -0
- data/README.rdoc +90 -69
- data/Rakefile +18 -9
- data/ext/nmatrix/data/complex.h +7 -7
- data/ext/nmatrix/data/data.cpp +2 -7
- data/ext/nmatrix/data/data.h +7 -4
- data/ext/nmatrix/data/rational.h +2 -2
- data/ext/nmatrix/data/ruby_object.h +3 -10
- data/ext/nmatrix/extconf.rb +79 -54
- data/ext/nmatrix/new_extconf.rb +11 -12
- data/ext/nmatrix/nmatrix.cpp +94 -125
- data/ext/nmatrix/nmatrix.h +38 -17
- data/ext/nmatrix/ruby_constants.cpp +2 -15
- data/ext/nmatrix/ruby_constants.h +2 -14
- data/ext/nmatrix/storage/common.cpp +2 -2
- data/ext/nmatrix/storage/common.h +2 -2
- data/ext/nmatrix/storage/dense.cpp +206 -31
- data/ext/nmatrix/storage/dense.h +5 -2
- data/ext/nmatrix/storage/list.cpp +52 -4
- data/ext/nmatrix/storage/list.h +3 -2
- data/ext/nmatrix/storage/storage.cpp +6 -6
- data/ext/nmatrix/storage/storage.h +2 -2
- data/ext/nmatrix/storage/yale.cpp +202 -49
- data/ext/nmatrix/storage/yale.h +5 -4
- data/ext/nmatrix/ttable_helper.rb +108 -108
- data/ext/nmatrix/types.h +2 -15
- data/ext/nmatrix/util/io.cpp +2 -2
- data/ext/nmatrix/util/io.h +2 -2
- data/ext/nmatrix/util/lapack.h +2 -2
- data/ext/nmatrix/util/math.cpp +14 -14
- data/ext/nmatrix/util/math.h +2 -2
- data/ext/nmatrix/util/sl_list.cpp +2 -2
- data/ext/nmatrix/util/sl_list.h +2 -2
- data/ext/nmatrix/util/util.h +2 -2
- data/lib/nmatrix.rb +13 -35
- data/lib/nmatrix/blas.rb +182 -56
- data/lib/nmatrix/io/market.rb +38 -14
- data/lib/nmatrix/io/mat5_reader.rb +393 -278
- data/lib/nmatrix/io/mat_reader.rb +121 -107
- data/lib/nmatrix/lapack.rb +59 -14
- data/lib/nmatrix/monkeys.rb +32 -30
- data/lib/nmatrix/nmatrix.rb +204 -100
- data/lib/nmatrix/nvector.rb +166 -57
- data/lib/nmatrix/shortcuts.rb +364 -231
- data/lib/nmatrix/version.rb +8 -4
- data/nmatrix.gemspec +5 -3
- data/scripts/mac-brew-gcc.sh +1 -1
- data/spec/blas_spec.rb +80 -2
- data/spec/math_spec.rb +78 -32
- data/spec/nmatrix_list_spec.rb +55 -55
- data/spec/nmatrix_spec.rb +60 -117
- data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
- data/spec/nmatrix_yale_spec.rb +214 -198
- data/spec/nvector_spec.rb +58 -2
- data/spec/shortcuts_spec.rb +156 -32
- data/spec/slice_spec.rb +229 -178
- data/spec/spec_helper.rb +2 -2
- metadata +71 -21
data/lib/nmatrix/blas.rb
CHANGED
@@ -1,70 +1,196 @@
|
|
1
|
-
|
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 - 2013, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2013, 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
|
+
# == blas.rb
|
25
|
+
#
|
26
|
+
# This file contains the safer accessors for the BLAS functions
|
27
|
+
# supported by NMatrix.
|
28
|
+
#++
|
2
29
|
|
30
|
+
module NMatrix::BLAS
|
3
31
|
class << self
|
4
|
-
|
32
|
+
#
|
33
|
+
# call-seq:
|
34
|
+
# gemm(a, b) -> NMatrix
|
35
|
+
# gemm(a, b, c) -> NMatrix
|
36
|
+
# gemm(a, b, c, alpha, beta) -> NMatrix
|
37
|
+
#
|
38
|
+
# Updates the value of C via the matrix multiplication
|
39
|
+
# C = (alpha * A * B) + (beta * C)
|
40
|
+
# where +alpha+ and +beta+ are scalar values.
|
41
|
+
#
|
42
|
+
# * *Arguments* :
|
43
|
+
# - +a+ -> Matrix A.
|
44
|
+
# - +b+ -> Matrix B.
|
45
|
+
# - +c+ -> Matrix C.
|
46
|
+
# - +alpha+ -> A scalar value that multiplies A * B.
|
47
|
+
# - +beta+ -> A scalar value that multiplies C.
|
48
|
+
# - +transpose_a+ ->
|
49
|
+
# - +transpose_b+ ->
|
50
|
+
# - +m+ ->
|
51
|
+
# - +n+ ->
|
52
|
+
# - +k+ ->
|
53
|
+
# - +lda+ ->
|
54
|
+
# - +ldb+ ->
|
55
|
+
# - +ldc+ ->
|
56
|
+
# * *Returns* :
|
57
|
+
# - A NMatrix equal to (alpha * A * B) + (beta * C).
|
58
|
+
# * *Raises* :
|
59
|
+
# - +ArgumentError+ -> +a+ and +b+ must be dense matrices.
|
60
|
+
# - +ArgumentError+ -> +c+ must be +nil+ or a dense matrix.
|
61
|
+
# - +ArgumentError+ -> The dtype of the matrices must be equal.
|
62
|
+
#
|
5
63
|
def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0, transpose_a = false, transpose_b = false, m = nil, n = nil, k = nil, lda = nil, ldb = nil, ldc = nil)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
64
|
+
raise ArgumentError, 'Expected dense NMatrices as first two arguments.' unless a.is_a?(NMatrix) and b.is_a?(NMatrix) and a.stype == :dense and b.stype == :dense
|
65
|
+
raise ArgumentError, 'Expected nil or dense NMatrix as third argument.' unless c.nil? or (c.is_a?(NMatrix) and c.stype == :dense)
|
66
|
+
raise ArgumentError, 'NMatrix dtype mismatch.' unless a.dtype == b.dtype and (c ? a.dtype == c.dtype : true)
|
67
|
+
|
68
|
+
# First, set m, n, and k, which depend on whether we're taking the
|
69
|
+
# transpose of a and b.
|
70
|
+
if c
|
71
|
+
m ||= c.shape[0]
|
72
|
+
n ||= c.shape[1]
|
73
|
+
k ||= transpose_a ? a.shape[0] : a.shape[1]
|
74
|
+
|
75
|
+
else
|
76
|
+
if transpose_a
|
77
|
+
# Either :transpose or :complex_conjugate.
|
78
|
+
m ||= a.shape[1]
|
79
|
+
k ||= a.shape[0]
|
80
|
+
|
81
|
+
else
|
82
|
+
# No transpose.
|
83
|
+
m ||= a.shape[0]
|
84
|
+
k ||= a.shape[1]
|
85
|
+
end
|
86
|
+
|
87
|
+
n ||= transpose_b ? b.shape[0] : b.shape[1]
|
88
|
+
c = NMatrix.new([m, n], a.dtype)
|
89
|
+
end
|
90
|
+
|
91
|
+
# I think these are independent of whether or not a transpose occurs.
|
92
|
+
lda ||= a.shape[1]
|
93
|
+
ldb ||= b.shape[1]
|
94
|
+
ldc ||= c.shape[1]
|
95
|
+
|
96
|
+
# NM_COMPLEX64 and NM_COMPLEX128 both require complex alpha and beta.
|
97
|
+
if a.dtype == :complex64 or a.dtype == :complex128
|
98
|
+
alpha = Complex(1.0, 0.0) if alpha == 1.0
|
99
|
+
beta = Complex(0.0, 0.0) if beta == 0.0
|
100
|
+
end
|
101
|
+
|
102
|
+
# For argument descriptions, see: http://www.netlib.org/blas/dgemm.f
|
103
|
+
::NMatrix::BLAS.cblas_gemm(:row, transpose_a, transpose_b, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
|
104
|
+
|
105
|
+
return c
|
48
106
|
end
|
49
107
|
|
108
|
+
#
|
109
|
+
# call-seq:
|
110
|
+
# gemv(a, x) -> NVector
|
111
|
+
# gemv(a, x, y) -> NVector
|
112
|
+
# gemv(a, x, y, alpha, beta) -> NVector
|
113
|
+
#
|
114
|
+
# Implements matrix-vector product via
|
115
|
+
# y = (alpha * A * x) + (beta * y)
|
116
|
+
# where +alpha+ and +beta+ are scalar values.
|
117
|
+
#
|
118
|
+
# * *Arguments* :
|
119
|
+
# - +a+ -> Matrix A.
|
120
|
+
# - +x+ -> Vector x.
|
121
|
+
# - +y+ -> Vector y.
|
122
|
+
# - +alpha+ -> A scalar value that multiplies A * x.
|
123
|
+
# - +beta+ -> A scalar value that multiplies y.
|
124
|
+
# - +transpose_a+ ->
|
125
|
+
# - +m+ ->
|
126
|
+
# - +n+ ->
|
127
|
+
# - +lda+ ->
|
128
|
+
# - +incx+ ->
|
129
|
+
# - +incy+ ->
|
130
|
+
# * *Returns* :
|
131
|
+
# -
|
132
|
+
# * *Raises* :
|
133
|
+
# - ++ ->
|
134
|
+
#
|
50
135
|
def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0, transpose_a = false, m = nil, n = nil, lda = nil, incx = nil, incy = nil)
|
51
|
-
|
52
|
-
|
136
|
+
raise ArgumentError, 'Expected dense NMatrices as first two arguments.' unless a.is_a?(NMatrix) and x.is_a?(NMatrix) and a.stype == :dense and x.stype == :dense
|
137
|
+
raise ArgumentError, 'Expected nil or dense NMatrix as third argument.' unless y.nil? or (y.is_a?(NMatrix) and y.stype == :dense)
|
138
|
+
raise ArgumentError, 'NMatrix dtype mismatch.' unless a.dtype == x.dtype and (y ? a.dtype == y.dtype : true)
|
53
139
|
|
54
|
-
|
55
|
-
|
56
|
-
incy ||= 1
|
140
|
+
m ||= transpose_a ? a.shape[1] : a.shape[0]
|
141
|
+
n ||= transpose_a ? a.shape[0] : a.shape[1]
|
57
142
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
beta = Complex(0.0, 0.0) if beta == 0.0
|
62
|
-
end
|
143
|
+
lda ||= a.shape[1]
|
144
|
+
incx ||= 1
|
145
|
+
incy ||= 1
|
63
146
|
|
64
|
-
|
147
|
+
# NM_COMPLEX64 and NM_COMPLEX128 both require complex alpha and beta.
|
148
|
+
if a.dtype == :complex64 or a.dtype == :complex128
|
149
|
+
alpha = Complex(1.0, 0.0) if alpha == 1.0
|
150
|
+
beta = Complex(0.0, 0.0) if beta == 0.0
|
151
|
+
end
|
65
152
|
|
66
|
-
|
153
|
+
y ||= NMatrix.new([m, n], a.dtype)
|
154
|
+
|
155
|
+
::NMatrix::BLAS.cblas_gemv(transpose_a, m, n, alpha, a, lda, x, incx, beta, y, incy)
|
156
|
+
|
157
|
+
return y
|
67
158
|
end
|
68
159
|
|
160
|
+
#
|
161
|
+
# call-seq:
|
162
|
+
# rot(x, y, c, s)
|
163
|
+
#
|
164
|
+
# Apply plane rotation.
|
165
|
+
#
|
166
|
+
# * *Arguments* :
|
167
|
+
# - +x+ ->
|
168
|
+
# - +y+ ->
|
169
|
+
# - +s+ ->
|
170
|
+
# - +c+ ->
|
171
|
+
# - +incx+ ->
|
172
|
+
# - +incy+ ->
|
173
|
+
# - +n+ ->
|
174
|
+
# * *Returns* :
|
175
|
+
# - Array with the results, in the format [xx, yy]
|
176
|
+
# * *Raises* :
|
177
|
+
# - +ArgumentError+ -> Expected dense NMatrices as first two arguments.
|
178
|
+
# - +ArgumentError+ -> Nmatrix dtype mismatch.
|
179
|
+
# - +ArgumentError+ -> Need to supply n for non-standard incx, incy values.
|
180
|
+
#
|
181
|
+
def rot(x, y, c, s, incx = 1, incy = 1, n = nil)
|
182
|
+
raise ArgumentError, 'Expected dense NMatrices as first two arguments.' unless x.is_a?(NMatrix) and y.is_a?(NMatrix) and x.stype == :dense and y.stype == :dense
|
183
|
+
raise ArgumentError, 'NMatrix dtype mismatch.' unless x.dtype == y.dtype
|
184
|
+
raise ArgumentError, 'Need to supply n for non-standard incx, incy values' if n.nil? && incx != 1 && incx != -1 && incy != 1 && incy != -1
|
185
|
+
|
186
|
+
n ||= x.size > y.size ? y.size : x.size
|
187
|
+
|
188
|
+
xx = x.clone
|
189
|
+
yy = y.clone
|
190
|
+
|
191
|
+
::NMatrix::BLAS.cblas_rot(n, xx, incx, yy, incy, c, s)
|
192
|
+
|
193
|
+
return [xx,yy]
|
194
|
+
end
|
69
195
|
end
|
70
196
|
end
|
data/lib/nmatrix/io/market.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#--
|
1
2
|
# = NMatrix
|
2
3
|
#
|
3
4
|
# A linear algebra library for scientific computation in Ruby.
|
@@ -24,22 +25,33 @@
|
|
24
25
|
#
|
25
26
|
# MatrixMarket reader and writer.
|
26
27
|
#
|
28
|
+
#++
|
29
|
+
|
27
30
|
module NMatrix::IO::Market
|
28
31
|
CONVERTER_AND_DTYPE = {
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
:real => [:to_f, :float64],
|
33
|
+
:complex => [:to_c, :complex128],
|
34
|
+
:integer => [:to_i, :int64],
|
35
|
+
:pattern => [:to_i, :byte]
|
33
36
|
}
|
34
37
|
|
35
38
|
ENTRY_TYPE = {
|
36
|
-
|
37
|
-
|
39
|
+
:byte => :integer, :int8 => :integer, :int16 => :integer, :int32 => :integer, :int64 => :integer,
|
40
|
+
:float32 => :real, :float64 => :real, :complex64 => :complex, :complex128 => :complex
|
38
41
|
}
|
39
42
|
|
40
43
|
class << self
|
44
|
+
#
|
45
|
+
# call-seq:
|
46
|
+
# load(filename) ->
|
47
|
+
#
|
48
|
+
# * *Arguments* :
|
49
|
+
# - +filename+ -> String with the filename to be saved.
|
50
|
+
# * *Raises* :
|
51
|
+
# - +IOError+ -> expected type code line beginning with '%%MatrixMarket matrix'
|
52
|
+
#
|
41
53
|
# Load a MatrixMarket file. Requires a filename as an argument.
|
42
|
-
def load
|
54
|
+
def load(filename)
|
43
55
|
|
44
56
|
f = File.new(filename, "r")
|
45
57
|
|
@@ -60,12 +72,24 @@ module NMatrix::IO::Market
|
|
60
72
|
end
|
61
73
|
end
|
62
74
|
|
63
|
-
|
64
|
-
#
|
65
|
-
#
|
66
|
-
|
75
|
+
#
|
76
|
+
# call-seq:
|
77
|
+
# save(matrix, filename, options = {}) -> true
|
78
|
+
#
|
79
|
+
# Can optionally set :symmetry to :general, :symmetric, :hermitian; and can
|
80
|
+
# set :pattern => true if you're writing a sparse matrix and don't want
|
81
|
+
# values stored.
|
82
|
+
#
|
83
|
+
# * *Arguments* :
|
84
|
+
# - +matrix+ -> NMatrix with the data to be saved.
|
85
|
+
# - +filename+ -> String with the filename to be saved.
|
86
|
+
# * *Raises* :
|
87
|
+
# - +DataTypeError+ -> MatrixMarket does not support rational or Ruby objects.
|
88
|
+
# - +ArgumentError+ -> Expected two-dimensional NMatrix.
|
89
|
+
#
|
90
|
+
def save(matrix, filename, options = {})
|
67
91
|
options = {:pattern => false,
|
68
|
-
|
92
|
+
:symmetry => :general}.merge(options)
|
69
93
|
|
70
94
|
mode = matrix.stype == :dense ? :array : :coordinate
|
71
95
|
if [:rational32,:rational64,:rational128,:object].include?(matrix.dtype)
|
@@ -91,7 +115,7 @@ module NMatrix::IO::Market
|
|
91
115
|
end
|
92
116
|
|
93
117
|
|
94
|
-
|
118
|
+
protected
|
95
119
|
|
96
120
|
def save_coordinate matrix, file, symmetry, pattern
|
97
121
|
# Convert to a hash in order to store
|
@@ -224,4 +248,4 @@ module NMatrix::IO::Market
|
|
224
248
|
mat
|
225
249
|
end
|
226
250
|
end
|
227
|
-
end
|
251
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
#--
|
1
2
|
# = NMatrix
|
2
3
|
#
|
3
4
|
# A linear algebra library for scientific computation in Ruby.
|
@@ -24,14 +25,16 @@
|
|
24
25
|
#
|
25
26
|
# Matlab version 5 .mat file reader (and eventually writer too).
|
26
27
|
#
|
28
|
+
#++
|
27
29
|
|
28
|
-
|
29
|
-
require_relative 'mat_reader.rb'
|
30
|
+
require_relative './mat_reader.rb'
|
30
31
|
|
31
32
|
module NMatrix::IO::Matlab
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
#
|
34
|
+
# Reader (and eventual writer) for a version 5 .mat file.
|
35
|
+
#
|
36
|
+
class Mat5Reader < MatReader
|
37
|
+
attr_reader :file_header, :first_tag_field, :first_data_field
|
35
38
|
|
36
39
|
class Compressed
|
37
40
|
include Packable
|
@@ -39,6 +42,15 @@ module NMatrix::IO::Matlab
|
|
39
42
|
|
40
43
|
attr_reader :byte_order
|
41
44
|
|
45
|
+
#
|
46
|
+
# call-seq:
|
47
|
+
# new(stream = nil, byte_order = nil, content_or_bytes = nil) -> Mat5Reader::Compressed
|
48
|
+
#
|
49
|
+
# * *Arguments* :
|
50
|
+
# - ++ ->
|
51
|
+
# * *Raises* :
|
52
|
+
# - ++ ->
|
53
|
+
#
|
42
54
|
def initialize(stream = nil, byte_order = nil, content_or_bytes = nil)
|
43
55
|
@stream = stream
|
44
56
|
@byte_order = byte_order
|
@@ -48,35 +60,69 @@ module NMatrix::IO::Matlab
|
|
48
60
|
|
49
61
|
elsif content_or_bytes.is_a?(Fixnum)
|
50
62
|
@padded_bytes = content_or_bytes
|
51
|
-
|
52
|
-
|
63
|
+
#else
|
64
|
+
# raise ArgumentError, "Need a content string or a number of bytes; content_or_bytes is #{content_or_bytes.class.to_s}."
|
53
65
|
end
|
54
66
|
end
|
55
67
|
|
68
|
+
#
|
69
|
+
# call-seq:
|
70
|
+
# compressed ->
|
71
|
+
#
|
56
72
|
def compressed
|
57
73
|
require "zlib"
|
58
74
|
# [2..-5] removes headers
|
59
75
|
@compressed ||= Zlib::Deflate.deflate(content)
|
60
76
|
end
|
61
77
|
|
78
|
+
#
|
79
|
+
# call-seq:
|
80
|
+
# content ->
|
81
|
+
#
|
62
82
|
def content
|
63
83
|
@content ||= extract
|
64
84
|
end
|
65
85
|
|
86
|
+
#
|
87
|
+
# call-seq:
|
88
|
+
# padded_bytes ->
|
89
|
+
#
|
66
90
|
def padded_bytes
|
67
91
|
@padded_bytes ||= content.size % 4 == 0 ? content.size : (content.size / 4 + 1) * 4
|
68
92
|
end
|
69
93
|
|
70
|
-
|
94
|
+
#
|
95
|
+
# call-seq:
|
96
|
+
# write_packed(packedio, options = {}) ->
|
97
|
+
#
|
98
|
+
# * *Arguments* :
|
99
|
+
# - ++ ->
|
100
|
+
# * *Returns* :
|
101
|
+
# -
|
102
|
+
#
|
103
|
+
def write_packed(packedio, options = {})
|
71
104
|
packedio << [compressed, {:bytes => padded_bytes}.merge(options)]
|
72
105
|
end
|
73
106
|
|
107
|
+
#
|
108
|
+
# call-seq:
|
109
|
+
# read_packed(packedio, options = {}) ->
|
110
|
+
#
|
111
|
+
# * *Arguments* :
|
112
|
+
# - ++ ->
|
113
|
+
# * *Returns* :
|
114
|
+
# -
|
115
|
+
#
|
74
116
|
def read_packed(packedio, options)
|
75
117
|
@compressed = (packedio >> [String, options]).first
|
76
118
|
content
|
77
119
|
end
|
78
120
|
|
79
121
|
protected
|
122
|
+
#
|
123
|
+
# call-seq:
|
124
|
+
# extract ->
|
125
|
+
#
|
80
126
|
def extract
|
81
127
|
require 'zlib'
|
82
128
|
|
@@ -90,26 +136,43 @@ module NMatrix::IO::Matlab
|
|
90
136
|
end
|
91
137
|
|
92
138
|
MatrixDataStruct = Struct.new(
|
93
|
-
|
94
|
-
|
95
|
-
|
139
|
+
:cells, :logical, :global, :complex, :nonzero_max,
|
140
|
+
:matlab_class, :dimensions, :matlab_name, :real_part,
|
141
|
+
:imaginary_part, :row_index, :column_index)
|
96
142
|
|
97
143
|
class MatrixData < MatrixDataStruct
|
98
144
|
include Packable
|
99
145
|
|
146
|
+
#
|
147
|
+
# call-seq:
|
148
|
+
# write_packed(packedio, options) ->
|
149
|
+
#
|
150
|
+
# * *Arguments* :
|
151
|
+
# - ++ ->
|
152
|
+
# * *Returns* :
|
153
|
+
# -
|
154
|
+
#
|
100
155
|
def write_packed(packedio, options)
|
101
156
|
raise NotImplementedError
|
102
157
|
packedio << [info, {:bytes => padded_bytes}.merge(options)]
|
103
158
|
end
|
104
159
|
|
105
|
-
#
|
106
|
-
#
|
160
|
+
#
|
161
|
+
# call-seq:
|
162
|
+
# to_ruby -> NMatrix or Array
|
163
|
+
#
|
164
|
+
# Figure out the appropriate Ruby type to convert to, and do it. There
|
165
|
+
# are basically two possible types: +NMatrix+ and +Array+. This method
|
166
|
+
# is recursive, so an +Array+ is going to contain other +Array+s and/or
|
167
|
+
# +NMatrix+ objects.
|
107
168
|
#
|
108
169
|
# mxCELL types (cells) will be converted to the Array type.
|
109
170
|
#
|
110
|
-
# mxSPARSE and other types will be converted to NMatrix, with the
|
171
|
+
# mxSPARSE and other types will be converted to NMatrix, with the
|
172
|
+
# appropriate stype (:yale or :dense, respectively).
|
111
173
|
#
|
112
174
|
# See also to_nm, which is responsible for NMatrix instantiation.
|
175
|
+
#
|
113
176
|
def to_ruby
|
114
177
|
case matlab_class
|
115
178
|
when :mxSPARSE then return to_nm
|
@@ -118,9 +181,15 @@ module NMatrix::IO::Matlab
|
|
118
181
|
end
|
119
182
|
end
|
120
183
|
|
184
|
+
#
|
185
|
+
# call-seq:
|
186
|
+
# guess_dtype_from_mdtype -> Symbol
|
187
|
+
#
|
121
188
|
# Try to determine what dtype and such to use.
|
122
189
|
#
|
123
|
-
# TODO: Needs to be verified that unsigned MATLAB types are being
|
190
|
+
# TODO: Needs to be verified that unsigned MATLAB types are being
|
191
|
+
# converted to the correct NMatrix signed dtypes.
|
192
|
+
#
|
124
193
|
def guess_dtype_from_mdtype
|
125
194
|
dtype = MatReader::MDTYPE_TO_DTYPE[self.real_part.tag.data_type]
|
126
195
|
|
@@ -129,10 +198,16 @@ module NMatrix::IO::Matlab
|
|
129
198
|
dtype == :float32 ? :complex64 : :complex128
|
130
199
|
end
|
131
200
|
|
201
|
+
#
|
202
|
+
# call-seq:
|
203
|
+
# unpacked_data(real_mdtype = nil, imag_mdtype = nil) ->
|
204
|
+
#
|
132
205
|
# Unpacks data without repacking it.
|
133
206
|
#
|
134
|
-
# Used only for dense matrix creation. Yale matrix creation uses
|
135
|
-
|
207
|
+
# Used only for dense matrix creation. Yale matrix creation uses
|
208
|
+
# repacked_data.
|
209
|
+
#
|
210
|
+
def unpacked_data(real_mdtype = nil, imag_mdtype = nil)
|
136
211
|
# Get Matlab data type and unpack args
|
137
212
|
real_mdtype ||= self.real_part.tag.data_type
|
138
213
|
real_unpack_args = MatReader::MDTYPE_UNPACK_ARGS[real_mdtype]
|
@@ -153,22 +228,30 @@ module NMatrix::IO::Matlab
|
|
153
228
|
|
154
229
|
end
|
155
230
|
|
231
|
+
#
|
232
|
+
# call-seq:
|
233
|
+
# repacked_data(to_dtype = nil) ->
|
234
|
+
#
|
156
235
|
# Unpacks and repacks data into the appropriate format for NMatrix.
|
157
236
|
#
|
158
|
-
# If data is already in the appropriate format, does not unpack or
|
237
|
+
# If data is already in the appropriate format, does not unpack or
|
238
|
+
# repack, just returns directly.
|
159
239
|
#
|
160
|
-
# Complex is always unpacked and repacked, as the real and imaginary
|
161
|
-
# stores them separately for
|
240
|
+
# Complex is always unpacked and repacked, as the real and imaginary
|
241
|
+
# components must be merged together (MATLAB stores them separately for
|
242
|
+
# some crazy reason).
|
162
243
|
#
|
163
244
|
# Used only for Yale storage creation. For dense, see unpacked_data.
|
164
245
|
#
|
165
|
-
# This function calls repack and complex_merge, which are both defined in
|
246
|
+
# This function calls repack and complex_merge, which are both defined in
|
247
|
+
# io.cpp.
|
166
248
|
def repacked_data(to_dtype = nil)
|
167
249
|
|
168
250
|
real_mdtype = self.real_part.tag.data_type
|
169
251
|
|
170
|
-
# Figure out what dtype to use based on the MATLAB data-types
|
171
|
-
#
|
252
|
+
# Figure out what dtype to use based on the MATLAB data-types
|
253
|
+
# (mdtypes). They could be different for real and imaginary, so call
|
254
|
+
# upcast to figure out what to use.
|
172
255
|
|
173
256
|
components = [] # real and imaginary parts or just the real part
|
174
257
|
|
@@ -208,10 +291,15 @@ module NMatrix::IO::Matlab
|
|
208
291
|
to_dtype]
|
209
292
|
end
|
210
293
|
|
211
|
-
|
294
|
+
#
|
295
|
+
# call-seq:
|
296
|
+
# repacked_indices(to_itype) ->
|
297
|
+
#
|
212
298
|
# Unpacks and repacks index data into the appropriate format for NMatrix.
|
213
299
|
#
|
214
|
-
# If data is already in the appropriate format, does not unpack or
|
300
|
+
# If data is already in the appropriate format, does not unpack or
|
301
|
+
# repack, just returns directly.
|
302
|
+
#
|
215
303
|
def repacked_indices(to_itype)
|
216
304
|
return [row_index.data, column_index.data] if to_itype == :uint32 # No need to re-pack -- already correct
|
217
305
|
|
@@ -222,18 +310,27 @@ module NMatrix::IO::Matlab
|
|
222
310
|
[repacked_row_indices, repacked_col_indices]
|
223
311
|
end
|
224
312
|
|
225
|
-
|
313
|
+
#
|
314
|
+
# call-seq:
|
315
|
+
# to_nm(dtype = nil) -> NMatrix
|
316
|
+
#
|
226
317
|
# Create an NMatrix from a MATLAB .mat (v5) matrix.
|
227
318
|
#
|
228
|
-
# This function matches the storage type exactly. That is, a regular
|
229
|
-
#
|
319
|
+
# This function matches the storage type exactly. That is, a regular
|
320
|
+
# matrix in MATLAB will be a dense NMatrix, and a sparse (old Yale) one
|
321
|
+
# in MATLAB will be a :yale (new Yale) matrix in NMatrix.
|
322
|
+
#
|
323
|
+
# Note that NMatrix has no old Yale type, so this uses a semi-hidden
|
324
|
+
# version of the NMatrix constructor to pass in --- as directly as
|
325
|
+
# possible -- the stored bytes in a MATLAB sparse matrix. This
|
326
|
+
# constructor should also be used for other IO formats that want to
|
327
|
+
# create sparse matrices from IA and JA vectors (e.g., SciPy).
|
230
328
|
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
329
|
+
# This is probably not the fastest code. An ideal solution would be a C
|
330
|
+
# plugin of some sort for reading the MATLAB .mat file. However, .mat v5
|
331
|
+
# is a really complicated format, and lends itself to an object-oriented
|
332
|
+
# solution.
|
234
333
|
#
|
235
|
-
# This is probably not the fastest code. An ideal solution would be a C plugin of some sort for reading the MATLAB
|
236
|
-
# .mat file. However, .mat v5 is a really complicated format, and lends itself to an object-oriented solution.
|
237
334
|
def to_nm(dtype = nil)
|
238
335
|
# Hardest part is figuring out from_dtype, from_index_dtype, and dtype.
|
239
336
|
dtype ||= guess_dtype_from_mdtype
|
@@ -261,6 +358,15 @@ module NMatrix::IO::Matlab
|
|
261
358
|
end
|
262
359
|
end
|
263
360
|
|
361
|
+
#
|
362
|
+
# call-seq:
|
363
|
+
# read_packed(packedio, options) ->
|
364
|
+
#
|
365
|
+
# * *Arguments* :
|
366
|
+
# - ++ ->
|
367
|
+
# * *Returns* :
|
368
|
+
# -
|
369
|
+
#
|
264
370
|
def read_packed(packedio, options)
|
265
371
|
flags_class, self.nonzero_max = packedio.read([Element, options]).data
|
266
372
|
|
@@ -313,255 +419,264 @@ module NMatrix::IO::Matlab
|
|
313
419
|
end
|
314
420
|
end
|
315
421
|
|
316
|
-
|
422
|
+
#
|
423
|
+
# call-seq:
|
424
|
+
# ignore_padding(packedio, bytes) ->
|
425
|
+
#
|
426
|
+
# * *Arguments* :
|
427
|
+
# - ++ ->
|
428
|
+
# * *Returns* :
|
429
|
+
# -
|
430
|
+
#
|
431
|
+
def ignore_padding(packedio, bytes)
|
317
432
|
packedio.read([Integer, {:unsigned => true, :bytes => bytes}]) if bytes > 0
|
318
433
|
end
|
319
434
|
end
|
320
435
|
|
321
436
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
437
|
+
MDTYPE_UNPACK_ARGS =
|
438
|
+
MatReader::MDTYPE_UNPACK_ARGS.merge({
|
439
|
+
:miCOMPRESSED => [Compressed, {}],
|
440
|
+
:miMATRIX => [MatrixData, {}]
|
441
|
+
})
|
442
|
+
# include TaggedDataEnumerable
|
443
|
+
|
444
|
+
FIRST_TAG_FIELD_POS = 128
|
445
|
+
|
446
|
+
####################
|
447
|
+
# Instance Methods #
|
448
|
+
####################
|
449
|
+
|
450
|
+
def initialize(stream, options = {})
|
451
|
+
super(stream, options)
|
452
|
+
@file_header = seek_and_read_file_header
|
453
|
+
end
|
454
|
+
|
455
|
+
def to_a
|
456
|
+
returning(Array.new) do |ary|
|
457
|
+
self.each { |el| ary << el }
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
def to_ruby
|
462
|
+
ary = self.to_a
|
463
|
+
|
464
|
+
if ary.size == 1
|
465
|
+
ary.first.to_ruby
|
466
|
+
else
|
467
|
+
ary.collect { |item| item.to_ruby }
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def guess_byte_order
|
472
|
+
stream.seek(Header::BYTE_ORDER_POS)
|
473
|
+
mi = stream.read(Header::BYTE_ORDER_LENGTH)
|
474
|
+
stream.seek(0)
|
475
|
+
mi == 'IM' ? :little : :big
|
476
|
+
end
|
477
|
+
|
478
|
+
def seek_and_read_file_header
|
479
|
+
stream.seek(0)
|
480
|
+
stream.read(FIRST_TAG_FIELD_POS).unpack(Header, {:endian => byte_order})
|
481
|
+
end
|
482
|
+
|
483
|
+
def each(&block)
|
484
|
+
stream.each(Element, {:endian => byte_order}) do |element|
|
485
|
+
if element.data.is_a?(Compressed)
|
486
|
+
StringIO.new(element.data.content, 'rb').each(Element, {:endian => byte_order}) do |compressed_element|
|
487
|
+
yield compressed_element.data
|
488
|
+
end
|
489
|
+
|
490
|
+
else
|
491
|
+
yield element.data
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
# Go back to the beginning in case we want to do it again.
|
496
|
+
stream.seek(FIRST_TAG_FIELD_POS)
|
497
|
+
|
498
|
+
self
|
499
|
+
end
|
500
|
+
|
501
|
+
####################
|
502
|
+
# Internal Classes #
|
503
|
+
####################
|
504
|
+
|
505
|
+
class Header < Struct.new(:desc, :data_offset, :version, :endian)
|
506
|
+
|
507
|
+
include Packable
|
508
|
+
|
509
|
+
BYTE_ORDER_LENGTH = 2
|
510
|
+
DESC_LENGTH = 116
|
511
|
+
DATA_OFFSET_LENGTH = 8
|
512
|
+
VERSION_LENGTH = 2
|
513
|
+
BYTE_ORDER_POS = 126
|
514
|
+
|
515
|
+
## TODO: TEST WRITE.
|
516
|
+
def write_packed(packedio, options)
|
517
|
+
packedio << [desc, {:bytes => DESC_LENGTH }] <<
|
518
|
+
[data_offset, {:bytes => DATA_OFFSET_LENGTH }] <<
|
519
|
+
[version, {:bytes => VERSION_LENGTH }] <<
|
520
|
+
[byte_order, {:bytes => BYTE_ORDER_LENGTH }]
|
521
|
+
end
|
522
|
+
|
523
|
+
def read_packed(packedio, options)
|
524
|
+
self.desc, self.data_offset, self.version, self.endian = packedio >>
|
410
525
|
[String, {:bytes => DESC_LENGTH }] >>
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
526
|
+
[String, {:bytes => DATA_OFFSET_LENGTH }] >>
|
527
|
+
[Integer, {:bytes => VERSION_LENGTH, :endian => options[:endian] }] >>
|
528
|
+
[String, {:bytes => 2 }]
|
529
|
+
|
530
|
+
self.desc.strip!
|
531
|
+
self.data_offset.strip!
|
532
|
+
self.data_offset = nil if self.data_offset.empty?
|
533
|
+
|
534
|
+
self.endian == 'IM' ? :little : :big
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
class Tag < Struct.new(:data_type, :raw_data_type, :bytes, :small)
|
539
|
+
include Packable
|
540
|
+
|
541
|
+
DATA_TYPE_OPTS = BYTES_OPTS = {:bytes => 4, :signed => false}
|
542
|
+
LENGTH = DATA_TYPE_OPTS[:bytes] + BYTES_OPTS[:bytes]
|
543
|
+
|
544
|
+
## TODO: TEST WRITE.
|
545
|
+
def write_packed packedio, options
|
546
|
+
packedio << [data_type, DATA_TYPE_OPTS] << [bytes, BYTES_OPTS]
|
547
|
+
end
|
548
|
+
|
549
|
+
def small?
|
550
|
+
self.bytes > 0 and self.bytes <= 4
|
551
|
+
end
|
552
|
+
|
553
|
+
def size
|
554
|
+
small? ? 4 : 8
|
555
|
+
end
|
556
|
+
|
557
|
+
def read_packed packedio, options
|
558
|
+
self.raw_data_type = packedio.read([Integer, DATA_TYPE_OPTS.merge(options)])
|
559
|
+
|
560
|
+
# Borrowed from a SciPy patch
|
561
|
+
upper = self.raw_data_type >> 16
|
562
|
+
lower = self.raw_data_type & 0xFFFF
|
563
|
+
|
564
|
+
if upper > 0
|
565
|
+
# Small data element format
|
566
|
+
raise IOError, 'Small data element format indicated, but length is more than 4 bytes!' if upper > 4
|
567
|
+
|
568
|
+
self.bytes = upper
|
569
|
+
self.raw_data_type = lower
|
570
|
+
|
571
|
+
else
|
572
|
+
self.bytes = packedio.read([Integer, BYTES_OPTS.merge(options)])
|
573
|
+
end
|
574
|
+
|
575
|
+
self.data_type = MatReader::MDTYPES[self.raw_data_type]
|
576
|
+
end
|
577
|
+
|
578
|
+
def inspect
|
579
|
+
"#<#{self.class.to_s} data_type=#{data_type}[#{raw_data_type}][#{raw_data_type.to_s(2)}] bytes=#{bytes} size=#{size}#{small? ? ' small' : ''}>"
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
|
584
|
+
class ElementDataIOError < IOError
|
585
|
+
attr_reader :tag
|
586
|
+
|
587
|
+
def initialize(tag = nil, msg = nil)
|
588
|
+
@tag = tag
|
589
|
+
super msg
|
590
|
+
end
|
591
|
+
|
592
|
+
def to_s
|
593
|
+
@tag.inspect + "\n" + super
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
|
598
|
+
class Element < Struct.new(:tag, :data)
|
599
|
+
include Packable
|
600
|
+
|
601
|
+
def write_packed packedio, options
|
602
|
+
packedio << [tag, {}] << [data, {}]
|
603
|
+
end
|
604
|
+
|
605
|
+
def read_packed(packedio, options)
|
606
|
+
raise(ArgumentError, 'Missing mandatory option :endian.') unless options.has_key?(:endian)
|
607
|
+
|
608
|
+
tag = packedio.read([Tag, {:endian => options[:endian]}])
|
609
|
+
#STDERR.puts tag.inspect
|
610
|
+
data_type = MDTYPE_UNPACK_ARGS[tag.data_type]
|
611
|
+
|
612
|
+
self.tag = tag
|
613
|
+
#STDERR.puts self.tag.inspect
|
614
|
+
|
615
|
+
raise ElementDataIOError.new(tag, "Unrecognized Matlab type #{tag.raw_data_type}") if data_type.nil?
|
616
|
+
|
617
|
+
if tag.bytes == 0
|
618
|
+
self.data = []
|
619
|
+
|
620
|
+
else
|
621
|
+
number_of_reads = data_type[1].has_key?(:bytes) ? tag.bytes / data_type[1][:bytes] : 1
|
622
|
+
data_type[1].merge!({:endian => options[:endian]})
|
623
|
+
|
624
|
+
if number_of_reads == 1
|
625
|
+
self.data = packedio.read(data_type)
|
626
|
+
|
627
|
+
else
|
628
|
+
self.data =
|
629
|
+
returning(Array.new) do |ary|
|
630
|
+
number_of_reads.times { ary << packedio.read(data_type) }
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
begin
|
635
|
+
ignore_padding(packedio, (tag.bytes + tag.size) % 8) unless [:miMATRIX, :miCOMPRESSED].include?(tag.data_type)
|
636
|
+
|
637
|
+
rescue EOFError
|
638
|
+
STDERR.puts self.tag.inspect
|
639
|
+
raise(ElementDataIOError.new(tag, "Ignored too much"))
|
640
|
+
end
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
def ignore_padding(packedio, bytes)
|
645
|
+
if bytes > 0
|
646
|
+
#STDERR.puts "Ignored #{8 - bytes} on #{self.tag.data_type}"
|
647
|
+
ignored = packedio.read(8 - bytes)
|
648
|
+
ignored_unpacked = ignored.unpack("C*")
|
649
|
+
raise(IOError, "Nonzero padding detected: #{ignored_unpacked}") if ignored_unpacked.any? { |i| i != 0 }
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
def to_ruby
|
654
|
+
data.to_ruby
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
# Doesn't unpack the contents of the element, e.g., if we want to handle
|
659
|
+
# manually, or pass the raw string of bytes into NMatrix.
|
660
|
+
class RawElement < Element
|
661
|
+
def read_packed(packedio, options)
|
662
|
+
raise(ArgumentError, 'Missing mandatory option :endian.') unless options.has_key?(:endian)
|
663
|
+
|
664
|
+
self.tag = packedio.read([Tag, {:endian => options[:endian] }])
|
665
|
+
self.data = packedio.read([String, {:endian => options[:endian], :bytes => tag.bytes }])
|
666
|
+
|
667
|
+
begin
|
668
|
+
ignore_padding(packedio, (tag.bytes + tag.size) % 8) unless [:miMATRIX, :miCOMPRESSED].include?(tag.data_type)
|
669
|
+
|
670
|
+
rescue EOFError
|
671
|
+
STDERR.puts self.tag.inspect
|
672
|
+
raise ElementDataIOError.new(tag, 'Ignored too much.')
|
673
|
+
end
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
#####################
|
678
|
+
# End of Mat5Reader #
|
679
|
+
#####################
|
680
|
+
|
681
|
+
end
|
567
682
|
end
|