nmatrix 0.1.0.rc5 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/Gemfile +0 -2
- data/History.txt +39 -4
- data/LICENSE.txt +3 -1
- data/Manifest.txt +2 -0
- data/README.rdoc +6 -14
- data/Rakefile +4 -1
- data/ext/nmatrix/data/data.cpp +1 -1
- data/ext/nmatrix/data/data.h +2 -1
- data/ext/nmatrix/data/rational.h +230 -226
- data/ext/nmatrix/extconf.rb +7 -4
- data/ext/nmatrix/math.cpp +259 -172
- data/ext/nmatrix/math/getri.h +2 -2
- data/ext/nmatrix/math/math.h +1 -1
- data/ext/nmatrix/ruby_constants.cpp +0 -1
- data/ext/nmatrix/ruby_nmatrix.c +55 -32
- data/ext/nmatrix/storage/dense/dense.cpp +1 -0
- data/ext/nmatrix/storage/yale/yale.cpp +12 -14
- data/ext/nmatrix/ttable_helper.rb +0 -1
- data/lib/nmatrix.rb +5 -0
- data/lib/nmatrix/homogeneous.rb +98 -0
- data/lib/nmatrix/io/fortran_format.rb +135 -0
- data/lib/nmatrix/io/harwell_boeing.rb +220 -0
- data/lib/nmatrix/io/market.rb +18 -8
- data/lib/nmatrix/io/mat5_reader.rb +16 -111
- data/lib/nmatrix/io/mat_reader.rb +3 -5
- data/lib/nmatrix/io/point_cloud.rb +27 -28
- data/lib/nmatrix/lapack.rb +3 -1
- data/lib/nmatrix/math.rb +112 -43
- data/lib/nmatrix/monkeys.rb +67 -11
- data/lib/nmatrix/nmatrix.rb +56 -33
- data/lib/nmatrix/rspec.rb +2 -2
- data/lib/nmatrix/shortcuts.rb +42 -25
- data/lib/nmatrix/version.rb +4 -4
- data/nmatrix.gemspec +4 -3
- data/spec/03_nmatrix_monkeys_spec.rb +72 -0
- data/spec/blas_spec.rb +4 -0
- data/spec/homogeneous_spec.rb +12 -4
- data/spec/io/fortran_format_spec.rb +88 -0
- data/spec/io/harwell_boeing_spec.rb +98 -0
- data/spec/io/test.rua +9 -0
- data/spec/math_spec.rb +51 -9
- metadata +38 -9
@@ -0,0 +1,135 @@
|
|
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 - 2014, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2014, John Woods and the 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/matlab/fortran_format.rb
|
25
|
+
#
|
26
|
+
# A parser for making sense of FORTRAN formats.
|
27
|
+
# => Only handles R (real), F (float) and E (exponential) format codes.
|
28
|
+
#++
|
29
|
+
|
30
|
+
class NMatrix
|
31
|
+
module IO
|
32
|
+
module FortranFormat
|
33
|
+
|
34
|
+
# Class for reading strings in FORTRAN format for specifying attributes
|
35
|
+
# of numerical data in a file. Supports F (float), E (exponential) and
|
36
|
+
# R (real).
|
37
|
+
#
|
38
|
+
# == Usage
|
39
|
+
#
|
40
|
+
# p = NMatrix::IO::FortranFormat::Reader.new("(16I5)")
|
41
|
+
# v = p.parse
|
42
|
+
# puts v #=> { :format_code => "INT_ID",
|
43
|
+
# #=> :repeat => 16,
|
44
|
+
# #=> :field_width => 5 }
|
45
|
+
class Reader
|
46
|
+
|
47
|
+
# Accepts a string in FORTRAN format and initializes the
|
48
|
+
# NMatrix::IO::FortranFormat::Reader object for further parsing of the
|
49
|
+
# data.
|
50
|
+
#
|
51
|
+
# == Arguments
|
52
|
+
#
|
53
|
+
# * +string+ - FORTRAN format string to be parsed.
|
54
|
+
def initialize string
|
55
|
+
@string = string
|
56
|
+
end
|
57
|
+
|
58
|
+
# Parses the FORTRAN format string passed in initialize and returns
|
59
|
+
# a hash of the results.
|
60
|
+
#
|
61
|
+
# == Result Hash Format
|
62
|
+
#
|
63
|
+
# Take note that some of the below parameters may be absent in the hash
|
64
|
+
# depending on the type of string being parsed.
|
65
|
+
#
|
66
|
+
# * +:format_code+ - A string containing the format code of the read data.
|
67
|
+
# Can be "INT_ID", "FP_ID" or "EXP_ID"
|
68
|
+
# * +:repeat+ - Number of times this format will repeat in a line.
|
69
|
+
# * +:field_width+ - Width of the numerical part of the number.
|
70
|
+
# * +:post_decimal_width+ - Width of the numerals after the decimal point.
|
71
|
+
# * +:exponent_width+ - Width of exponent part of the number.
|
72
|
+
def parse
|
73
|
+
raise(IOError, "Left or right parentheses missing") if parentheses_missing? # change tests to handle 'raise' not return
|
74
|
+
|
75
|
+
@result = {}
|
76
|
+
@string = @string[1..-2]
|
77
|
+
|
78
|
+
if valid_fortran_format?
|
79
|
+
load_result
|
80
|
+
else
|
81
|
+
raise(IOError, "Invalid FORTRAN format specified. Only Integer, Float or Exponential acceptable.")
|
82
|
+
end
|
83
|
+
|
84
|
+
@result
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
def parentheses_missing?
|
89
|
+
true if @string[0] != '(' or @string[-1] != ')'
|
90
|
+
end
|
91
|
+
|
92
|
+
# Changing any of the following regular expressions can lead to disaster
|
93
|
+
def valid_fortran_format?
|
94
|
+
@mdata = @string.match(/\A(\d*)(I)(\d+)\z/) # check for integer format
|
95
|
+
@mdata = @string.match(/\A(\d*)(F)(\d+)\.(\d+)\z/) if @mdata.nil? # check for floating point if not integer
|
96
|
+
@mdata = @string.match(/\A(\d*)(E)(\d+)\.(\d+)(E)?(\d*)\z/) if @mdata.nil? # check for exponential format if not floating point
|
97
|
+
|
98
|
+
@mdata
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_result
|
102
|
+
if @mdata.to_a.include? "I"
|
103
|
+
create_integer_hash
|
104
|
+
elsif @mdata.to_a.include? "F"
|
105
|
+
create_float_hash
|
106
|
+
else
|
107
|
+
create_exp_hash
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_integer_hash
|
112
|
+
@result[:format_code] = "INT_ID"
|
113
|
+
@result[:repeat] = @mdata[1].to_i if !@mdata[1].empty?
|
114
|
+
@result[:field_width] = @mdata[3].to_i
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_float_hash
|
118
|
+
@result[:format_code] = "FP_ID"
|
119
|
+
@result[:repeat] = @mdata[1].to_i if !@mdata[1].empty?
|
120
|
+
@result[:field_width] = @mdata[3].to_i
|
121
|
+
@result[:post_decimal_width] = @mdata[4].to_i
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_exp_hash
|
125
|
+
@result[:format_code] = "EXP_ID"
|
126
|
+
@result[:repeat] = @mdata[1].to_i if !@mdata[1].empty?
|
127
|
+
@result[:field_width] = @mdata[3].to_i
|
128
|
+
@result[:post_decimal_width] = @mdata[4].to_i
|
129
|
+
@result[:exponent_width] = @mdata[6].to_i if !@mdata[6].empty?
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,220 @@
|
|
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 - 2014, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2014, John Woods and the 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/matlab/harwell_boeing.rb
|
25
|
+
#
|
26
|
+
# Harwell Boeing file reader (and eventually writer too).
|
27
|
+
# => Supports only assembled, non-symmetric, real matrices
|
28
|
+
# => Data types supported are exponential, floating point and integer
|
29
|
+
# => Returned NMatrix is of type :float64
|
30
|
+
#++
|
31
|
+
|
32
|
+
require_relative './fortran_format.rb'
|
33
|
+
|
34
|
+
class NMatrix
|
35
|
+
module IO
|
36
|
+
module HarwellBoeing
|
37
|
+
|
38
|
+
class << self
|
39
|
+
# Loads the contents of a valid Harwell Boeing format file and
|
40
|
+
# returns an NMatrix object with the values of the file and optionally
|
41
|
+
# only the header info.
|
42
|
+
#
|
43
|
+
# Supports only assembled, non-symmetric, real matrices. File name must
|
44
|
+
# have matrix type as extension.
|
45
|
+
#
|
46
|
+
# Example - test_file.rua
|
47
|
+
#
|
48
|
+
# == Arguments
|
49
|
+
#
|
50
|
+
# * +file_path+ - Path of the Harwell Boeing file to load.
|
51
|
+
# * +opts+ - Options for specifying whether you want the values and
|
52
|
+
# header or only the header.
|
53
|
+
#
|
54
|
+
# == Options
|
55
|
+
#
|
56
|
+
# * +:header+ - If specified as *true*, will return only the header of the HB file.
|
57
|
+
# Will return the NMatrix object and header as an array if
|
58
|
+
# left blank.
|
59
|
+
#
|
60
|
+
# == Usage
|
61
|
+
#
|
62
|
+
# mat, head = NMatrix::IO::HarwellBoeing.load("test_file.rua")
|
63
|
+
#
|
64
|
+
# head = NMatrix::IO::HarwellBoeing.load("test_file.rua", {header: true})
|
65
|
+
#
|
66
|
+
# == Alternate Usage
|
67
|
+
#
|
68
|
+
# You can specify the file using NMatrix::IO::Reader.new("path/to/file") and
|
69
|
+
# then call *header* or *values* on the resulting object.
|
70
|
+
def load file_path, opts={}
|
71
|
+
hb_obj = NMatrix::IO::HarwellBoeing::Reader.new(file_path)
|
72
|
+
|
73
|
+
return hb_obj.header if opts[:header]
|
74
|
+
|
75
|
+
[hb_obj.values, hb_obj.header]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Reader
|
80
|
+
def initialize file_name
|
81
|
+
raise(IOError, "Unsupported file format. Specify file as \
|
82
|
+
file_name.rua.") if !file_name.match(/.*\.[rR][uU][aA]/)
|
83
|
+
|
84
|
+
@file_name = file_name
|
85
|
+
@header = {}
|
86
|
+
@body = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def header
|
90
|
+
return @header if !@header.empty?
|
91
|
+
@file = File.open @file_name, "r"
|
92
|
+
|
93
|
+
line = @file.gets
|
94
|
+
|
95
|
+
@header[:title] = line[0...72].strip
|
96
|
+
@header[:key] = line[72...80].strip
|
97
|
+
|
98
|
+
line = @file.gets
|
99
|
+
|
100
|
+
@header[:totcrd] = line[0...14] .strip.to_i
|
101
|
+
@header[:ptrcrd] = line[14...28].strip.to_i
|
102
|
+
@header[:indcrd] = line[28...42].strip.to_i
|
103
|
+
@header[:valcrd] = line[42...56].strip.to_i
|
104
|
+
@header[:rhscrd] = line[56...70].strip.to_i
|
105
|
+
|
106
|
+
raise(IOError, "Right hand sides not supported.") if @header[:rhscrd] > 0
|
107
|
+
|
108
|
+
line = @file.gets
|
109
|
+
|
110
|
+
@header[:mxtype] = line[0...3]
|
111
|
+
|
112
|
+
raise(IOError, "Currently supports only real, assembled, unsymmetric \
|
113
|
+
matrices.") if !@header[:mxtype].match(/RUA/)
|
114
|
+
|
115
|
+
@header[:nrow] = line[13...28].strip.to_i
|
116
|
+
@header[:ncol] = line[28...42].strip.to_i
|
117
|
+
@header[:nnzero] = line[42...56].strip.to_i
|
118
|
+
@header[:neltvl] = line[56...70].strip.to_i
|
119
|
+
|
120
|
+
line = @file.gets
|
121
|
+
|
122
|
+
fortran_reader = NMatrix::IO::FortranFormat::Reader
|
123
|
+
|
124
|
+
@header[:ptrfmt] = fortran_reader.new(line[0...16].strip) .parse
|
125
|
+
@header[:indfmt] = fortran_reader.new(line[16...32].strip).parse
|
126
|
+
@header[:valfmt] = fortran_reader.new(line[32...52].strip).parse
|
127
|
+
@header[:rhsfmt] = fortran_reader.new(line[52...72].strip).parse
|
128
|
+
|
129
|
+
@header
|
130
|
+
end
|
131
|
+
|
132
|
+
def values
|
133
|
+
@header = header if @header.empty?
|
134
|
+
@file.lineno = 5 if @file.lineno != 5
|
135
|
+
@matrix = NMatrix.new([ @header[:nrow], @header[:ncol] ],
|
136
|
+
0, dtype: :float64)
|
137
|
+
|
138
|
+
read_column_pointers
|
139
|
+
read_row_indices
|
140
|
+
read_values
|
141
|
+
|
142
|
+
@file.close
|
143
|
+
|
144
|
+
assemble_matrix
|
145
|
+
|
146
|
+
@matrix
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def read_column_pointers
|
152
|
+
@col_ptrs = []
|
153
|
+
pointer_lines = @header[:ptrcrd]
|
154
|
+
pointers_per_line = @header[:ptrfmt][:repeat]
|
155
|
+
pointer_width = @header[:ptrfmt][:field_width]
|
156
|
+
|
157
|
+
@col_ptrs = read_numbers :to_i, pointer_lines, pointers_per_line,
|
158
|
+
pointer_width
|
159
|
+
|
160
|
+
@col_ptrs.map! {|c| c -= 1}
|
161
|
+
end
|
162
|
+
|
163
|
+
def read_row_indices
|
164
|
+
@row_indices = []
|
165
|
+
row_lines = @header[:indcrd]
|
166
|
+
indices_per_line = @header[:indfmt][:repeat]
|
167
|
+
row_width = @header[:indfmt][:field_width]
|
168
|
+
|
169
|
+
@row_indices = read_numbers :to_i, row_lines, indices_per_line,
|
170
|
+
row_width
|
171
|
+
|
172
|
+
@row_indices.map! {|r| r -= 1}
|
173
|
+
end
|
174
|
+
|
175
|
+
def read_values
|
176
|
+
@vals = []
|
177
|
+
value_lines = @header[:valcrd]
|
178
|
+
values_per_line = @header[:valfmt][:repeat]
|
179
|
+
value_width = @header[:valfmt][:field_width]
|
180
|
+
|
181
|
+
@vals = read_numbers :to_f, value_lines, values_per_line,
|
182
|
+
value_width
|
183
|
+
end
|
184
|
+
|
185
|
+
def read_numbers to_dtype, num_of_lines, numbers_per_line, number_width
|
186
|
+
data = []
|
187
|
+
|
188
|
+
num_of_lines.times do
|
189
|
+
line = @file.gets
|
190
|
+
index = 0
|
191
|
+
|
192
|
+
numbers_per_line.times do
|
193
|
+
delimiter = index + number_width
|
194
|
+
|
195
|
+
data << line[index...delimiter].strip.send(to_dtype)
|
196
|
+
|
197
|
+
break if line.length <= delimiter
|
198
|
+
index += number_width
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
data
|
203
|
+
end
|
204
|
+
|
205
|
+
def assemble_matrix
|
206
|
+
col = 0
|
207
|
+
@col_ptrs[0..-2].each_index do |index|
|
208
|
+
@col_ptrs[index].upto(@col_ptrs[index+1] - 1) do |row_ptr|
|
209
|
+
row = @row_indices[row_ptr]
|
210
|
+
@matrix[row, col] = @vals[row_ptr]
|
211
|
+
end
|
212
|
+
|
213
|
+
col += 1
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
data/lib/nmatrix/io/market.rb
CHANGED
@@ -26,30 +26,42 @@
|
|
26
26
|
#
|
27
27
|
#++
|
28
28
|
|
29
|
+
# Matrix Market is a repository of test data for use in studies of algorithms
|
30
|
+
# for numerical linear algebra. There are 3 file formats used:
|
31
|
+
#
|
32
|
+
# - Matrix Market Exchange Format.
|
33
|
+
# - Harwell-Boeing Exchange Format.
|
34
|
+
# - Coordinate Text File Format. (to be phased out)
|
35
|
+
#
|
36
|
+
# This module can load and save the first format. We might support
|
37
|
+
# Harwell-Boeing in the future.
|
38
|
+
#
|
39
|
+
# The MatrixMarket format is documented in:
|
40
|
+
# * http://math.nist.gov/MatrixMarket/formats.html
|
29
41
|
module NMatrix::IO::Market
|
30
42
|
CONVERTER_AND_DTYPE = {
|
31
43
|
:real => [:to_f, :float64],
|
32
44
|
:complex => [:to_c, :complex128],
|
33
45
|
:integer => [:to_i, :int64],
|
34
46
|
:pattern => [:to_i, :byte]
|
35
|
-
}
|
47
|
+
} #:nodoc:
|
36
48
|
|
37
49
|
ENTRY_TYPE = {
|
38
50
|
:byte => :integer, :int8 => :integer, :int16 => :integer, :int32 => :integer, :int64 => :integer,
|
39
51
|
:float32 => :real, :float64 => :real, :complex64 => :complex, :complex128 => :complex
|
40
|
-
}
|
52
|
+
} #:nodoc:
|
41
53
|
|
42
54
|
class << self
|
43
|
-
|
55
|
+
|
44
56
|
# call-seq:
|
45
|
-
# load(filename) ->
|
57
|
+
# load(filename) -> NMatrix
|
58
|
+
#
|
59
|
+
# Load a MatrixMarket file. Requires a +filename+ as an argument.
|
46
60
|
#
|
47
61
|
# * *Arguments* :
|
48
62
|
# - +filename+ -> String with the filename to be saved.
|
49
63
|
# * *Raises* :
|
50
64
|
# - +IOError+ -> expected type code line beginning with '%%MatrixMarket matrix'
|
51
|
-
#
|
52
|
-
# Load a MatrixMarket file. Requires a filename as an argument.
|
53
65
|
def load(filename)
|
54
66
|
|
55
67
|
f = File.new(filename, "r")
|
@@ -71,7 +83,6 @@ module NMatrix::IO::Market
|
|
71
83
|
end
|
72
84
|
end
|
73
85
|
|
74
|
-
#
|
75
86
|
# call-seq:
|
76
87
|
# save(matrix, filename, options = {}) -> true
|
77
88
|
#
|
@@ -85,7 +96,6 @@ module NMatrix::IO::Market
|
|
85
96
|
# * *Raises* :
|
86
97
|
# - +DataTypeError+ -> MatrixMarket does not support rational or Ruby objects.
|
87
98
|
# - +ArgumentError+ -> Expected two-dimensional NMatrix.
|
88
|
-
#
|
89
99
|
def save(matrix, filename, options = {})
|
90
100
|
options = {:pattern => false,
|
91
101
|
:symmetry => :general}.merge(options)
|
@@ -30,27 +30,16 @@
|
|
30
30
|
require_relative './mat_reader.rb'
|
31
31
|
|
32
32
|
module NMatrix::IO::Matlab
|
33
|
-
|
33
|
+
|
34
34
|
# Reader (and eventual writer) for a version 5 .mat file.
|
35
|
-
|
36
|
-
class Mat5Reader < MatReader
|
35
|
+
class Mat5Reader < MatReader #:nodoc:
|
37
36
|
attr_reader :file_header, :first_tag_field, :first_data_field
|
38
37
|
|
39
|
-
class Compressed
|
38
|
+
class Compressed #:nodoc:
|
40
39
|
include Packable
|
41
|
-
# include TaggedDataEnumerable
|
42
40
|
|
43
41
|
attr_reader :byte_order
|
44
42
|
|
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
|
-
#
|
54
43
|
def initialize(stream = nil, byte_order = nil, content_or_bytes = nil)
|
55
44
|
@stream = stream
|
56
45
|
@byte_order = byte_order
|
@@ -60,69 +49,33 @@ module NMatrix::IO::Matlab
|
|
60
49
|
|
61
50
|
elsif content_or_bytes.is_a?(Fixnum)
|
62
51
|
@padded_bytes = content_or_bytes
|
63
|
-
#else
|
64
|
-
# raise ArgumentError, "Need a content string or a number of bytes; content_or_bytes is #{content_or_bytes.class.to_s}."
|
65
52
|
end
|
66
53
|
end
|
67
54
|
|
68
|
-
#
|
69
|
-
# call-seq:
|
70
|
-
# compressed ->
|
71
|
-
#
|
72
55
|
def compressed
|
73
56
|
require "zlib"
|
74
57
|
# [2..-5] removes headers
|
75
58
|
@compressed ||= Zlib::Deflate.deflate(content)
|
76
59
|
end
|
77
60
|
|
78
|
-
#
|
79
|
-
# call-seq:
|
80
|
-
# content ->
|
81
|
-
#
|
82
61
|
def content
|
83
62
|
@content ||= extract
|
84
63
|
end
|
85
64
|
|
86
|
-
#
|
87
|
-
# call-seq:
|
88
|
-
# padded_bytes ->
|
89
|
-
#
|
90
65
|
def padded_bytes
|
91
66
|
@padded_bytes ||= content.size % 4 == 0 ? content.size : (content.size / 4 + 1) * 4
|
92
67
|
end
|
93
68
|
|
94
|
-
#
|
95
|
-
# call-seq:
|
96
|
-
# write_packed(packedio, options = {}) ->
|
97
|
-
#
|
98
|
-
# * *Arguments* :
|
99
|
-
# - ++ ->
|
100
|
-
# * *Returns* :
|
101
|
-
# -
|
102
|
-
#
|
103
69
|
def write_packed(packedio, options = {})
|
104
70
|
packedio << [compressed, {:bytes => padded_bytes}.merge(options)]
|
105
71
|
end
|
106
72
|
|
107
|
-
#
|
108
|
-
# call-seq:
|
109
|
-
# read_packed(packedio, options = {}) ->
|
110
|
-
#
|
111
|
-
# * *Arguments* :
|
112
|
-
# - ++ ->
|
113
|
-
# * *Returns* :
|
114
|
-
# -
|
115
|
-
#
|
116
73
|
def read_packed(packedio, options)
|
117
74
|
@compressed = (packedio >> [String, options]).first
|
118
75
|
content
|
119
76
|
end
|
120
77
|
|
121
78
|
protected
|
122
|
-
#
|
123
|
-
# call-seq:
|
124
|
-
# extract ->
|
125
|
-
#
|
126
79
|
def extract
|
127
80
|
require 'zlib'
|
128
81
|
|
@@ -140,26 +93,17 @@ module NMatrix::IO::Matlab
|
|
140
93
|
:matlab_class, :dimensions, :matlab_name, :real_part,
|
141
94
|
:imaginary_part, :row_index, :column_index)
|
142
95
|
|
143
|
-
class MatrixData < MatrixDataStruct
|
96
|
+
class MatrixData < MatrixDataStruct #:nodoc:
|
144
97
|
include Packable
|
145
98
|
|
146
|
-
#
|
147
|
-
# call-seq:
|
148
|
-
# write_packed(packedio, options) ->
|
149
|
-
#
|
150
|
-
# * *Arguments* :
|
151
|
-
# - ++ ->
|
152
|
-
# * *Returns* :
|
153
|
-
# -
|
154
|
-
#
|
155
99
|
def write_packed(packedio, options)
|
156
100
|
raise NotImplementedError
|
157
101
|
packedio << [info, {:bytes => padded_bytes}.merge(options)]
|
158
102
|
end
|
159
103
|
|
160
|
-
#
|
161
104
|
# call-seq:
|
162
|
-
# to_ruby -> NMatrix
|
105
|
+
# to_ruby -> NMatrix
|
106
|
+
# to_ruby -> Array
|
163
107
|
#
|
164
108
|
# Figure out the appropriate Ruby type to convert to, and do it. There
|
165
109
|
# are basically two possible types: +NMatrix+ and +Array+. This method
|
@@ -172,7 +116,6 @@ module NMatrix::IO::Matlab
|
|
172
116
|
# appropriate stype (:yale or :dense, respectively).
|
173
117
|
#
|
174
118
|
# See also to_nm, which is responsible for NMatrix instantiation.
|
175
|
-
#
|
176
119
|
def to_ruby
|
177
120
|
case matlab_class
|
178
121
|
when :mxSPARSE then return to_nm
|
@@ -181,7 +124,6 @@ module NMatrix::IO::Matlab
|
|
181
124
|
end
|
182
125
|
end
|
183
126
|
|
184
|
-
#
|
185
127
|
# call-seq:
|
186
128
|
# guess_dtype_from_mdtype -> Symbol
|
187
129
|
#
|
@@ -189,7 +131,6 @@ module NMatrix::IO::Matlab
|
|
189
131
|
#
|
190
132
|
# TODO: Needs to be verified that unsigned MATLAB types are being
|
191
133
|
# converted to the correct NMatrix signed dtypes.
|
192
|
-
#
|
193
134
|
def guess_dtype_from_mdtype
|
194
135
|
dtype = MatReader::MDTYPE_TO_DTYPE[self.real_part.tag.data_type]
|
195
136
|
|
@@ -228,10 +169,6 @@ module NMatrix::IO::Matlab
|
|
228
169
|
|
229
170
|
end
|
230
171
|
|
231
|
-
#
|
232
|
-
# call-seq:
|
233
|
-
# repacked_data(to_dtype = nil) ->
|
234
|
-
#
|
235
172
|
# Unpacks and repacks data into the appropriate format for NMatrix.
|
236
173
|
#
|
237
174
|
# If data is already in the appropriate format, does not unpack or
|
@@ -291,15 +228,10 @@ module NMatrix::IO::Matlab
|
|
291
228
|
to_dtype]
|
292
229
|
end
|
293
230
|
|
294
|
-
#
|
295
|
-
# call-seq:
|
296
|
-
# repacked_indices ->
|
297
|
-
#
|
298
231
|
# Unpacks and repacks index data into the appropriate format for NMatrix.
|
299
232
|
#
|
300
233
|
# If data is already in the appropriate format, does not unpack or
|
301
234
|
# repack, just returns directly.
|
302
|
-
#
|
303
235
|
def repacked_indices
|
304
236
|
repacked_row_indices = ::NMatrix::IO::Matlab.repack( self.row_index.data, :miINT32, :itype )
|
305
237
|
repacked_col_indices = ::NMatrix::IO::Matlab.repack( self.column_index.data, :miINT32, :itype )
|
@@ -352,29 +284,17 @@ module NMatrix::IO::Matlab
|
|
352
284
|
end
|
353
285
|
end
|
354
286
|
|
355
|
-
#
|
356
|
-
# call-seq:
|
357
|
-
# read_packed(packedio, options) ->
|
358
|
-
#
|
359
|
-
# * *Arguments* :
|
360
|
-
# - ++ ->
|
361
|
-
# * *Returns* :
|
362
|
-
# -
|
363
|
-
#
|
364
287
|
def read_packed(packedio, options)
|
365
288
|
flags_class, self.nonzero_max = packedio.read([Element, options]).data
|
366
289
|
|
367
290
|
self.matlab_class = MatReader::MCLASSES[flags_class % 16]
|
368
|
-
#STDERR.puts "Matrix class: #{self.matlab_class}"
|
369
291
|
|
370
292
|
self.logical = (flags_class >> 8) % 2 == 1 ? true : false
|
371
293
|
self.global = (flags_class >> 9) % 2 == 1 ? true : false
|
372
294
|
self.complex = (flags_class >> 10) % 2 == 1 ? true : false
|
373
|
-
#STDERR.puts "nzmax: #{self.nonzero_max}"
|
374
295
|
|
375
296
|
dimensions_tag_data = packedio.read([Element, options])
|
376
297
|
self.dimensions = dimensions_tag_data.data
|
377
|
-
#STDERR.puts "dimensions: #{self.dimensions}"
|
378
298
|
|
379
299
|
begin
|
380
300
|
name_tag_data = packedio.read([Element, options])
|
@@ -390,7 +310,6 @@ module NMatrix::IO::Matlab
|
|
390
310
|
raise(e)
|
391
311
|
end
|
392
312
|
|
393
|
-
#STDERR.puts [flags_class.to_s(2), self.complex, self.global, self.logical, nil, self.mclass, self.nonzero_max].join("\t")
|
394
313
|
if self.matlab_class == :mxCELL
|
395
314
|
# Read what may be a series of matrices
|
396
315
|
self.cells = []
|
@@ -404,8 +323,6 @@ module NMatrix::IO::Matlab
|
|
404
323
|
if self.matlab_class == :mxSPARSE
|
405
324
|
self.column_index = packedio.read(read_opts)
|
406
325
|
self.row_index = packedio.read(read_opts)
|
407
|
-
|
408
|
-
# STDERR.puts "row and col indices: #{self.row_index.inspect}, #{self.column_index.inspect}"
|
409
326
|
end
|
410
327
|
|
411
328
|
self.real_part = packedio.read(read_opts)
|
@@ -413,15 +330,6 @@ module NMatrix::IO::Matlab
|
|
413
330
|
end
|
414
331
|
end
|
415
332
|
|
416
|
-
#
|
417
|
-
# call-seq:
|
418
|
-
# ignore_padding(packedio, bytes) ->
|
419
|
-
#
|
420
|
-
# * *Arguments* :
|
421
|
-
# - ++ ->
|
422
|
-
# * *Returns* :
|
423
|
-
# -
|
424
|
-
#
|
425
333
|
def ignore_padding(packedio, bytes)
|
426
334
|
packedio.read([Integer, {:unsigned => true, :bytes => bytes}]) if bytes > 0
|
427
335
|
end
|
@@ -433,7 +341,6 @@ module NMatrix::IO::Matlab
|
|
433
341
|
:miCOMPRESSED => [Compressed, {}],
|
434
342
|
:miMATRIX => [MatrixData, {}]
|
435
343
|
})
|
436
|
-
# include TaggedDataEnumerable
|
437
344
|
|
438
345
|
FIRST_TAG_FIELD_POS = 128
|
439
346
|
|
@@ -441,6 +348,8 @@ module NMatrix::IO::Matlab
|
|
441
348
|
# Instance Methods for Mat5Reader #
|
442
349
|
###################################
|
443
350
|
|
351
|
+
# call-seq:
|
352
|
+
# NMatrix::IO::Mat5Reader.new(stream, options = {}) -> NMatrix
|
444
353
|
def initialize(stream, options = {})
|
445
354
|
super(stream, options)
|
446
355
|
@file_header = seek_and_read_file_header
|
@@ -492,11 +401,9 @@ module NMatrix::IO::Matlab
|
|
492
401
|
self
|
493
402
|
end
|
494
403
|
|
495
|
-
|
496
|
-
# Internal Classes #
|
497
|
-
####################
|
404
|
+
# Internal Classes.
|
498
405
|
|
499
|
-
class Header < Struct.new(:desc, :data_offset, :version, :endian)
|
406
|
+
class Header < Struct.new(:desc, :data_offset, :version, :endian) #:nodoc:
|
500
407
|
|
501
408
|
include Packable
|
502
409
|
|
@@ -506,7 +413,7 @@ module NMatrix::IO::Matlab
|
|
506
413
|
VERSION_LENGTH = 2
|
507
414
|
BYTE_ORDER_POS = 126
|
508
415
|
|
509
|
-
|
416
|
+
# TODO: TEST WRITE.
|
510
417
|
def write_packed(packedio, options)
|
511
418
|
packedio << [desc, {:bytes => DESC_LENGTH }] <<
|
512
419
|
[data_offset, {:bytes => DATA_OFFSET_LENGTH }] <<
|
@@ -529,13 +436,13 @@ module NMatrix::IO::Matlab
|
|
529
436
|
end
|
530
437
|
end
|
531
438
|
|
532
|
-
class Tag < Struct.new(:data_type, :raw_data_type, :bytes, :small)
|
439
|
+
class Tag < Struct.new(:data_type, :raw_data_type, :bytes, :small) #:nodoc:
|
533
440
|
include Packable
|
534
441
|
|
535
442
|
DATA_TYPE_OPTS = BYTES_OPTS = {:bytes => 4, :signed => false}
|
536
443
|
LENGTH = DATA_TYPE_OPTS[:bytes] + BYTES_OPTS[:bytes]
|
537
444
|
|
538
|
-
|
445
|
+
# TODO: TEST WRITE.
|
539
446
|
def write_packed packedio, options
|
540
447
|
packedio << [data_type, DATA_TYPE_OPTS] << [bytes, BYTES_OPTS]
|
541
448
|
end
|
@@ -575,7 +482,7 @@ module NMatrix::IO::Matlab
|
|
575
482
|
end
|
576
483
|
|
577
484
|
|
578
|
-
class ElementDataIOError < IOError
|
485
|
+
class ElementDataIOError < IOError #:nodoc:
|
579
486
|
attr_reader :tag
|
580
487
|
|
581
488
|
def initialize(tag = nil, msg = nil)
|
@@ -589,7 +496,7 @@ module NMatrix::IO::Matlab
|
|
589
496
|
end
|
590
497
|
|
591
498
|
|
592
|
-
class Element < Struct.new(:tag, :data)
|
499
|
+
class Element < Struct.new(:tag, :data) #:nodoc:
|
593
500
|
include Packable
|
594
501
|
|
595
502
|
def write_packed packedio, options
|
@@ -600,11 +507,9 @@ module NMatrix::IO::Matlab
|
|
600
507
|
raise(ArgumentError, 'Missing mandatory option :endian.') unless options.has_key?(:endian)
|
601
508
|
|
602
509
|
tag = packedio.read([Tag, {:endian => options[:endian]}])
|
603
|
-
#STDERR.puts tag.inspect
|
604
510
|
data_type = MDTYPE_UNPACK_ARGS[tag.data_type]
|
605
511
|
|
606
512
|
self.tag = tag
|
607
|
-
#STDERR.puts self.tag.inspect
|
608
513
|
|
609
514
|
raise ElementDataIOError.new(tag, "Unrecognized Matlab type #{tag.raw_data_type}") if data_type.nil?
|
610
515
|
|
@@ -651,7 +556,7 @@ module NMatrix::IO::Matlab
|
|
651
556
|
|
652
557
|
# Doesn't unpack the contents of the element, e.g., if we want to handle
|
653
558
|
# manually, or pass the raw string of bytes into NMatrix.
|
654
|
-
class RawElement < Element
|
559
|
+
class RawElement < Element #:nodoc:
|
655
560
|
def read_packed(packedio, options)
|
656
561
|
raise(ArgumentError, 'Missing mandatory option :endian.') unless options.has_key?(:endian)
|
657
562
|
|