pnmatrix 1.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/nmatrix/binary_format.txt +53 -0
- data/ext/nmatrix/data/complex.h +388 -0
- data/ext/nmatrix/data/data.cpp +274 -0
- data/ext/nmatrix/data/data.h +651 -0
- data/ext/nmatrix/data/meta.h +64 -0
- data/ext/nmatrix/data/ruby_object.h +386 -0
- data/ext/nmatrix/extconf.rb +70 -0
- data/ext/nmatrix/math/asum.h +99 -0
- data/ext/nmatrix/math/cblas_enums.h +36 -0
- data/ext/nmatrix/math/cblas_templates_core.h +507 -0
- data/ext/nmatrix/math/gemm.h +241 -0
- data/ext/nmatrix/math/gemv.h +178 -0
- data/ext/nmatrix/math/getrf.h +255 -0
- data/ext/nmatrix/math/getrs.h +121 -0
- data/ext/nmatrix/math/imax.h +82 -0
- data/ext/nmatrix/math/laswp.h +165 -0
- data/ext/nmatrix/math/long_dtype.h +62 -0
- data/ext/nmatrix/math/magnitude.h +54 -0
- data/ext/nmatrix/math/math.h +751 -0
- data/ext/nmatrix/math/nrm2.h +165 -0
- data/ext/nmatrix/math/rot.h +117 -0
- data/ext/nmatrix/math/rotg.h +106 -0
- data/ext/nmatrix/math/scal.h +71 -0
- data/ext/nmatrix/math/trsm.h +336 -0
- data/ext/nmatrix/math/util.h +162 -0
- data/ext/nmatrix/math.cpp +1368 -0
- data/ext/nmatrix/nm_memory.h +60 -0
- data/ext/nmatrix/nmatrix.cpp +285 -0
- data/ext/nmatrix/nmatrix.h +476 -0
- data/ext/nmatrix/ruby_constants.cpp +151 -0
- data/ext/nmatrix/ruby_constants.h +106 -0
- data/ext/nmatrix/ruby_nmatrix.c +3130 -0
- data/ext/nmatrix/storage/common.cpp +77 -0
- data/ext/nmatrix/storage/common.h +183 -0
- data/ext/nmatrix/storage/dense/dense.cpp +1096 -0
- data/ext/nmatrix/storage/dense/dense.h +129 -0
- data/ext/nmatrix/storage/list/list.cpp +1628 -0
- data/ext/nmatrix/storage/list/list.h +138 -0
- data/ext/nmatrix/storage/storage.cpp +730 -0
- data/ext/nmatrix/storage/storage.h +99 -0
- data/ext/nmatrix/storage/yale/class.h +1139 -0
- data/ext/nmatrix/storage/yale/iterators/base.h +143 -0
- data/ext/nmatrix/storage/yale/iterators/iterator.h +131 -0
- data/ext/nmatrix/storage/yale/iterators/row.h +450 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored.h +140 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +169 -0
- data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +124 -0
- data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
- data/ext/nmatrix/storage/yale/yale.cpp +2074 -0
- data/ext/nmatrix/storage/yale/yale.h +203 -0
- data/ext/nmatrix/types.h +55 -0
- data/ext/nmatrix/util/io.cpp +279 -0
- data/ext/nmatrix/util/io.h +115 -0
- data/ext/nmatrix/util/sl_list.cpp +627 -0
- data/ext/nmatrix/util/sl_list.h +144 -0
- data/ext/nmatrix/util/util.h +78 -0
- data/lib/nmatrix/blas.rb +378 -0
- data/lib/nmatrix/cruby/math.rb +744 -0
- data/lib/nmatrix/enumerate.rb +253 -0
- data/lib/nmatrix/homogeneous.rb +241 -0
- data/lib/nmatrix/io/fortran_format.rb +138 -0
- data/lib/nmatrix/io/harwell_boeing.rb +221 -0
- data/lib/nmatrix/io/market.rb +263 -0
- data/lib/nmatrix/io/point_cloud.rb +189 -0
- data/lib/nmatrix/jruby/decomposition.rb +24 -0
- data/lib/nmatrix/jruby/enumerable.rb +13 -0
- data/lib/nmatrix/jruby/error.rb +4 -0
- data/lib/nmatrix/jruby/math.rb +501 -0
- data/lib/nmatrix/jruby/nmatrix_java.rb +840 -0
- data/lib/nmatrix/jruby/operators.rb +283 -0
- data/lib/nmatrix/jruby/slice.rb +264 -0
- data/lib/nmatrix/lapack_core.rb +181 -0
- data/lib/nmatrix/lapack_plugin.rb +44 -0
- data/lib/nmatrix/math.rb +953 -0
- data/lib/nmatrix/mkmf.rb +100 -0
- data/lib/nmatrix/monkeys.rb +137 -0
- data/lib/nmatrix/nmatrix.rb +1172 -0
- data/lib/nmatrix/rspec.rb +75 -0
- data/lib/nmatrix/shortcuts.rb +1163 -0
- data/lib/nmatrix/version.rb +39 -0
- data/lib/nmatrix/yale_functions.rb +118 -0
- data/lib/nmatrix.rb +28 -0
- data/spec/00_nmatrix_spec.rb +892 -0
- data/spec/01_enum_spec.rb +196 -0
- data/spec/02_slice_spec.rb +407 -0
- data/spec/03_nmatrix_monkeys_spec.rb +80 -0
- data/spec/2x2_dense_double.mat +0 -0
- data/spec/4x4_sparse.mat +0 -0
- data/spec/4x5_dense.mat +0 -0
- data/spec/blas_spec.rb +215 -0
- data/spec/elementwise_spec.rb +311 -0
- data/spec/homogeneous_spec.rb +100 -0
- 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/io_spec.rb +159 -0
- data/spec/lapack_core_spec.rb +482 -0
- data/spec/leakcheck.rb +16 -0
- data/spec/math_spec.rb +1363 -0
- data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
- data/spec/nmatrix_yale_spec.rb +286 -0
- data/spec/rspec_monkeys.rb +56 -0
- data/spec/rspec_spec.rb +35 -0
- data/spec/shortcuts_spec.rb +474 -0
- data/spec/slice_set_spec.rb +162 -0
- data/spec/spec_helper.rb +172 -0
- data/spec/stat_spec.rb +214 -0
- data/spec/test.pcd +20 -0
- data/spec/utm5940.mtx +83844 -0
- metadata +295 -0
@@ -0,0 +1,221 @@
|
|
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 - 2016, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2016, 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
|
52
|
+
# the values and header or only the header.
|
53
|
+
#
|
54
|
+
# == Options
|
55
|
+
#
|
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
|
+
#
|
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")
|
69
|
+
# and 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.") \
|
107
|
+
if @header[:rhscrd] > 0
|
108
|
+
|
109
|
+
line = @file.gets
|
110
|
+
|
111
|
+
@header[:mxtype] = line[0...3]
|
112
|
+
|
113
|
+
raise(IOError, "Currently supports only real, assembled, unsymmetric \
|
114
|
+
matrices.") if !@header[:mxtype].match(/RUA/)
|
115
|
+
|
116
|
+
@header[:nrow] = line[13...28].strip.to_i
|
117
|
+
@header[:ncol] = line[28...42].strip.to_i
|
118
|
+
@header[:nnzero] = line[42...56].strip.to_i
|
119
|
+
@header[:neltvl] = line[56...70].strip.to_i
|
120
|
+
|
121
|
+
line = @file.gets
|
122
|
+
|
123
|
+
fortran_reader = NMatrix::IO::FortranFormat::Reader
|
124
|
+
|
125
|
+
@header[:ptrfmt] = fortran_reader.new(line[0...16].strip) .parse
|
126
|
+
@header[:indfmt] = fortran_reader.new(line[16...32].strip).parse
|
127
|
+
@header[:valfmt] = fortran_reader.new(line[32...52].strip).parse
|
128
|
+
@header[:rhsfmt] = fortran_reader.new(line[52...72].strip).parse
|
129
|
+
|
130
|
+
@header
|
131
|
+
end
|
132
|
+
|
133
|
+
def values
|
134
|
+
@header = header if @header.empty?
|
135
|
+
@file.lineno = 5 if @file.lineno != 5
|
136
|
+
@matrix = NMatrix.new([ @header[:nrow], @header[:ncol] ],
|
137
|
+
0, dtype: :float64)
|
138
|
+
|
139
|
+
read_column_pointers
|
140
|
+
read_row_indices
|
141
|
+
read_values
|
142
|
+
|
143
|
+
@file.close
|
144
|
+
|
145
|
+
assemble_matrix
|
146
|
+
|
147
|
+
@matrix
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def read_column_pointers
|
153
|
+
@col_ptrs = []
|
154
|
+
pointer_lines = @header[:ptrcrd]
|
155
|
+
pointers_per_line = @header[:ptrfmt][:repeat]
|
156
|
+
pointer_width = @header[:ptrfmt][:field_width]
|
157
|
+
|
158
|
+
@col_ptrs = read_numbers :to_i, pointer_lines, pointers_per_line,
|
159
|
+
pointer_width
|
160
|
+
|
161
|
+
@col_ptrs.map! {|c| c -= 1}
|
162
|
+
end
|
163
|
+
|
164
|
+
def read_row_indices
|
165
|
+
@row_indices = []
|
166
|
+
row_lines = @header[:indcrd]
|
167
|
+
indices_per_line = @header[:indfmt][:repeat]
|
168
|
+
row_width = @header[:indfmt][:field_width]
|
169
|
+
|
170
|
+
@row_indices = read_numbers :to_i, row_lines, indices_per_line,
|
171
|
+
row_width
|
172
|
+
|
173
|
+
@row_indices.map! {|r| r -= 1}
|
174
|
+
end
|
175
|
+
|
176
|
+
def read_values
|
177
|
+
@vals = []
|
178
|
+
value_lines = @header[:valcrd]
|
179
|
+
values_per_line = @header[:valfmt][:repeat]
|
180
|
+
value_width = @header[:valfmt][:field_width]
|
181
|
+
|
182
|
+
@vals = read_numbers :to_f, value_lines, values_per_line,
|
183
|
+
value_width
|
184
|
+
end
|
185
|
+
|
186
|
+
def read_numbers to_dtype, num_of_lines, numbers_per_line, number_width
|
187
|
+
data = []
|
188
|
+
|
189
|
+
num_of_lines.times do
|
190
|
+
line = @file.gets
|
191
|
+
index = 0
|
192
|
+
|
193
|
+
numbers_per_line.times do
|
194
|
+
delimiter = index + number_width
|
195
|
+
|
196
|
+
data << line[index...delimiter].strip.send(to_dtype)
|
197
|
+
|
198
|
+
break if line.length <= delimiter
|
199
|
+
index += number_width
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
data
|
204
|
+
end
|
205
|
+
|
206
|
+
def assemble_matrix
|
207
|
+
col = 0
|
208
|
+
@col_ptrs[0..-2].each_index do |index|
|
209
|
+
@col_ptrs[index].upto(@col_ptrs[index+1] - 1) do |row_ptr|
|
210
|
+
row = @row_indices[row_ptr]
|
211
|
+
@matrix[row, col] = @vals[row_ptr]
|
212
|
+
end
|
213
|
+
|
214
|
+
col += 1
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
# = NMatrix
|
2
|
+
#
|
3
|
+
# A linear algebra library for scientific computation in Ruby.
|
4
|
+
# NMatrix is part of SciRuby.
|
5
|
+
#
|
6
|
+
# NMatrix was originally inspired by and derived from NArray, by
|
7
|
+
# Masahiro Tanaka: http://narray.rubyforge.org
|
8
|
+
#
|
9
|
+
# == Copyright Information
|
10
|
+
#
|
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
|
+
#
|
14
|
+
# Please see LICENSE.txt for additional copyright notices.
|
15
|
+
#
|
16
|
+
# == Contributing
|
17
|
+
#
|
18
|
+
# By contributing source code to SciRuby, you agree to be bound by
|
19
|
+
# our Contributor Agreement:
|
20
|
+
#
|
21
|
+
# * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
22
|
+
#
|
23
|
+
# == io/market.rb
|
24
|
+
#
|
25
|
+
# MatrixMarket reader and writer.
|
26
|
+
#
|
27
|
+
#++
|
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
|
41
|
+
module NMatrix::IO::Market
|
42
|
+
CONVERTER_AND_DTYPE = {
|
43
|
+
:real => [:to_f, :float64],
|
44
|
+
:complex => [:to_c, :complex128],
|
45
|
+
:integer => [:to_i, :int64],
|
46
|
+
:pattern => [:to_i, :byte]
|
47
|
+
} #:nodoc:
|
48
|
+
|
49
|
+
ENTRY_TYPE = {
|
50
|
+
:byte => :integer, :int8 => :integer, :int16 => :integer,
|
51
|
+
:int32 => :integer, :int64 => :integer,:float32 => :real,
|
52
|
+
:float64 => :real, :complex64 => :complex, :complex128 => :complex
|
53
|
+
} #:nodoc:
|
54
|
+
|
55
|
+
class << self
|
56
|
+
|
57
|
+
# call-seq:
|
58
|
+
# load(filename) -> NMatrix
|
59
|
+
#
|
60
|
+
# Load a MatrixMarket file. Requires a +filename+ as an argument.
|
61
|
+
#
|
62
|
+
# * *Arguments* :
|
63
|
+
# - +filename+ -> String with the filename to be saved.
|
64
|
+
# * *Raises* :
|
65
|
+
# - +IOError+ -> expected type code line beginning with '%%MatrixMarket matrix'
|
66
|
+
def load(filename)
|
67
|
+
|
68
|
+
f = File.new(filename, "r")
|
69
|
+
|
70
|
+
header = f.gets
|
71
|
+
header.chomp!
|
72
|
+
raise(IOError, "expected type code line beginning with '%%MatrixMarket matrix'") \
|
73
|
+
if header !~ /^\%\%MatrixMarket\ matrix/
|
74
|
+
|
75
|
+
header = header.split
|
76
|
+
|
77
|
+
entry_type = header[3].downcase.to_sym
|
78
|
+
symmetry = header[4].downcase.to_sym
|
79
|
+
converter, default_dtype = CONVERTER_AND_DTYPE[entry_type]
|
80
|
+
|
81
|
+
if header[2] == 'coordinate'
|
82
|
+
load_coordinate f, converter, default_dtype, entry_type, symmetry
|
83
|
+
else
|
84
|
+
load_array f, converter, default_dtype, entry_type, symmetry
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# call-seq:
|
89
|
+
# save(matrix, filename, options = {}) -> true
|
90
|
+
#
|
91
|
+
# Can optionally set :symmetry to :general, :symmetric, :hermitian; and can
|
92
|
+
# set :pattern => true if you're writing a sparse matrix and don't want
|
93
|
+
# values stored.
|
94
|
+
#
|
95
|
+
# * *Arguments* :
|
96
|
+
# - +matrix+ -> NMatrix with the data to be saved.
|
97
|
+
# - +filename+ -> String with the filename to be saved.
|
98
|
+
# * *Raises* :
|
99
|
+
# - +DataTypeError+ -> MatrixMarket does not support Ruby objects.
|
100
|
+
# - +ArgumentError+ -> Expected two-dimensional NMatrix.
|
101
|
+
def save(matrix, filename, options = {})
|
102
|
+
options = {:pattern => false,
|
103
|
+
:symmetry => :general}.merge(options)
|
104
|
+
|
105
|
+
mode = matrix.stype == :dense ? :array : :coordinate
|
106
|
+
if [:object].include?(matrix.dtype)
|
107
|
+
raise(DataTypeError, "MatrixMarket does not support Ruby objects")
|
108
|
+
end
|
109
|
+
entry_type = options[:pattern] ? :pattern : ENTRY_TYPE[matrix.dtype]
|
110
|
+
|
111
|
+
raise(ArgumentError, "expected two-dimensional NMatrix") \
|
112
|
+
if matrix.dim != 2
|
113
|
+
|
114
|
+
f = File.new(filename, 'w')
|
115
|
+
|
116
|
+
f.puts "%%MatrixMarket matrix #{mode} #{entry_type} #{options[:symmetry]}"
|
117
|
+
|
118
|
+
if matrix.stype == :dense
|
119
|
+
save_array matrix, f, options[:symmetry]
|
120
|
+
elsif [:list,:yale].include?(matrix.stype)
|
121
|
+
save_coordinate matrix, f, options[:symmetry], options[:pattern]
|
122
|
+
end
|
123
|
+
|
124
|
+
f.close
|
125
|
+
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
protected
|
131
|
+
|
132
|
+
def save_coordinate matrix, file, symmetry, pattern
|
133
|
+
# Convert to a hash in order to store
|
134
|
+
rows = matrix.to_h
|
135
|
+
|
136
|
+
# Count non-zeros
|
137
|
+
count = 0
|
138
|
+
rows.each_pair do |i, columns|
|
139
|
+
columns.each_pair do |j, val|
|
140
|
+
next if symmetry != :general && j > i
|
141
|
+
count += 1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Print dimensions and non-zeros
|
146
|
+
file.puts "#{matrix.shape[0]}\t#{matrix.shape[1]}\t#{count}"
|
147
|
+
|
148
|
+
# Print coordinates
|
149
|
+
rows.each_pair do |i, columns|
|
150
|
+
columns.each_pair do |j, val|
|
151
|
+
next if symmetry != :general && j > i
|
152
|
+
file.puts(pattern ? "\t#{i+1}\t#{j+1}" : "\t#{i+1}\t#{j+1}\t#{val}")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
file
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
def save_array matrix, file, symmetry
|
161
|
+
file.puts [matrix.shape[0], matrix.shape[1]].join("\t")
|
162
|
+
|
163
|
+
if symmetry == :general
|
164
|
+
(0...matrix.shape[1]).each do |j|
|
165
|
+
(0...matrix.shape[0]).each do |i|
|
166
|
+
file.puts matrix[i,j]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
else # :symmetric, :'skew-symmetric', :hermitian
|
170
|
+
(0...matrix.shape[1]).each do |j|
|
171
|
+
(j...matrix.shape[0]).each do |i|
|
172
|
+
file.puts matrix[i,j]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
file
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
def load_array file, converter, dtype, entry_type, symmetry
|
182
|
+
mat = nil
|
183
|
+
|
184
|
+
line = file.gets
|
185
|
+
line.chomp!
|
186
|
+
line.lstrip!
|
187
|
+
|
188
|
+
fields = line.split
|
189
|
+
|
190
|
+
mat = NMatrix.new :dense, [fields[0].to_i, fields[1].to_i], dtype
|
191
|
+
|
192
|
+
(0...mat.shape[1]).each do |j|
|
193
|
+
(0...mat.shape[0]).each do |i|
|
194
|
+
datum = file.gets.chomp.send(converter)
|
195
|
+
mat[i,j] = datum
|
196
|
+
|
197
|
+
unless i == j || symmetry == :general
|
198
|
+
if symmetry == :symmetric
|
199
|
+
mat[j,i] = datum
|
200
|
+
elsif symmetry == :hermitian
|
201
|
+
mat[j,i] = Complex.new(datum.real, -datum.imag)
|
202
|
+
elsif symmetry == :'skew-symmetric'
|
203
|
+
mat[j,i] = -datum
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
file.close
|
210
|
+
|
211
|
+
mat
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
# Creates a :list NMatrix from a coordinate-list MatrixMarket file.
|
216
|
+
def load_coordinate file, converter, dtype, entry_type, symmetry
|
217
|
+
|
218
|
+
mat = nil
|
219
|
+
|
220
|
+
# Read until we get the dimensions and nonzeros
|
221
|
+
while line = file.gets
|
222
|
+
line.chomp!
|
223
|
+
line.lstrip!
|
224
|
+
line, comment = line.split('%', 2) # ignore comments
|
225
|
+
if line.size > 4
|
226
|
+
shape0, shape1 = line.split
|
227
|
+
mat = NMatrix.new(:list, [shape0.to_i, shape1.to_i], 0, dtype)
|
228
|
+
break
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Now read the coordinates
|
233
|
+
while line = file.gets
|
234
|
+
line.chomp!
|
235
|
+
line.lstrip!
|
236
|
+
line, comment = line.split('%', 2) # ignore comments
|
237
|
+
|
238
|
+
next unless line.size >= 5 # ignore empty lines
|
239
|
+
|
240
|
+
fields = line.split
|
241
|
+
|
242
|
+
i = fields[0].to_i - 1
|
243
|
+
j = fields[1].to_i - 1
|
244
|
+
datum = entry_type == :pattern ? 1 : fields[2].send(converter)
|
245
|
+
|
246
|
+
mat[i, j] = datum # add to the matrix
|
247
|
+
unless i == j || symmetry == :general
|
248
|
+
if symmetry == :symmetric
|
249
|
+
mat[j, i] = datum
|
250
|
+
elsif symmetry == :'skew-symmetric'
|
251
|
+
mat[j, i] = -datum
|
252
|
+
elsif symmetry == :hermitian
|
253
|
+
mat[j, i] = Complex.new(datum.real, -datum.imag)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
file.close
|
259
|
+
|
260
|
+
mat
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
@@ -0,0 +1,189 @@
|
|
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 - 2016, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2016, 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/point_cloud.rb
|
25
|
+
#
|
26
|
+
# Point Cloud Library (PCL) PCD file IO functions.
|
27
|
+
#
|
28
|
+
#++
|
29
|
+
|
30
|
+
# Reader for Point Cloud Data (PCD) file format.
|
31
|
+
#
|
32
|
+
# The documentation of this format can be found in:
|
33
|
+
#
|
34
|
+
# http://pointclouds.org/documentation/tutorials/pcd_file_format.php
|
35
|
+
#
|
36
|
+
# Note that this implementation does not take the width or height parameters
|
37
|
+
# into account.
|
38
|
+
module NMatrix::IO::PointCloud
|
39
|
+
|
40
|
+
# For UINT, just add 1 to the index.
|
41
|
+
INT_DTYPE_BY_SIZE = [:int8, :int8, :int16, :int32, :int64, :int64] #:nodoc:
|
42
|
+
FLOAT_DTYPE_BY_SIZE = {4 => :float32, 8 => :float64} #:nodoc:
|
43
|
+
|
44
|
+
class << self
|
45
|
+
# call-seq:
|
46
|
+
# load(filename) -> NMatrix
|
47
|
+
#
|
48
|
+
# * *Arguments* :
|
49
|
+
# - +filename+ -> String giving the name of the file to be loaded.
|
50
|
+
#
|
51
|
+
# Load a Point Cloud Library PCD file as a matrix.
|
52
|
+
def load(filename)
|
53
|
+
MetaReader.new(filename).matrix
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class MetaReader #:nodoc:
|
58
|
+
ENTRIES = [:version, :fields, :size, :type,
|
59
|
+
:count, :width, :height, :viewpoint, :points, :data]
|
60
|
+
ASSIGNS = [:version=, :fields=, :size=, :type=,
|
61
|
+
:count=, :width=, :height=, :viewpoint=, :points=, :data=]
|
62
|
+
CONVERT = [:to_s, :downcase_to_sym, :to_i, :downcase_to_sym,
|
63
|
+
:to_i, :to_i, :to_i, :to_f, :to_i, :downcase_to_sym]
|
64
|
+
|
65
|
+
DTYPE_CONVERT = {:byte => :to_i, :int8 => :to_i, :int16 => :to_i,
|
66
|
+
:int32 => :to_i, :float32 => :to_f, :float64 => :to_f}
|
67
|
+
|
68
|
+
# For UINT, just add 1 to the index.
|
69
|
+
INT_DTYPE_BY_SIZE = {1 => :int8, 2 => :int16, 4 => :int32,
|
70
|
+
8 => :int64, 16 => :int64}
|
71
|
+
FLOAT_DTYPE_BY_SIZE = {1 => :float32, 2 => :float32, 4 => :float32,
|
72
|
+
8 => :float64,16 => :float64}
|
73
|
+
|
74
|
+
class << self
|
75
|
+
|
76
|
+
# Given a type and a number of bytes, figure out an appropriate dtype
|
77
|
+
def dtype_by_type_and_size t, s
|
78
|
+
if t == :f
|
79
|
+
FLOAT_DTYPE_BY_SIZE[s]
|
80
|
+
elsif t == :u
|
81
|
+
return :byte if s == 1
|
82
|
+
INT_DTYPE_BY_SIZE[s*2]
|
83
|
+
else
|
84
|
+
INT_DTYPE_BY_SIZE[s]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# call-seq:
|
90
|
+
# PointCloudReader::MetaReader.new(filename) -> MetaReader
|
91
|
+
#
|
92
|
+
# * *Arguments* :
|
93
|
+
# - +filename+ -> String giving the name of the file to be loaded.
|
94
|
+
# * *Raises* :
|
95
|
+
# - +NotImplementedError+ -> only ASCII supported currently
|
96
|
+
# - +IOError+ -> premature end of file
|
97
|
+
#
|
98
|
+
# Open a file and read the metadata at the top; then read the PCD into an
|
99
|
+
# NMatrix.
|
100
|
+
#
|
101
|
+
# In addition to the fields in the PCD file, there will be at least one
|
102
|
+
# additional attribute, :matrix, storing the data.
|
103
|
+
def initialize filename
|
104
|
+
f = File.new(filename, "r")
|
105
|
+
|
106
|
+
ENTRIES.each.with_index do |entry,i|
|
107
|
+
read_entry(f, entry, ASSIGNS[i], CONVERT[i])
|
108
|
+
end
|
109
|
+
|
110
|
+
raise(NotImplementedError, "only ASCII supported currently") \
|
111
|
+
unless self.data.first == :ascii
|
112
|
+
|
113
|
+
@matrix = NMatrix.new(self.shape, dtype: self.dtype)
|
114
|
+
|
115
|
+
# Do we want to use to_i or to_f?
|
116
|
+
convert = DTYPE_CONVERT[self.dtype]
|
117
|
+
|
118
|
+
i = 0
|
119
|
+
while line = f.gets
|
120
|
+
@matrix[i,:*] = line.chomp.split.map { |f| f.send(convert) }
|
121
|
+
i += 1
|
122
|
+
end
|
123
|
+
|
124
|
+
raise(IOError, "premature end of file") if i < self.points[0]
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
attr_accessor *ENTRIES
|
129
|
+
attr_reader :matrix
|
130
|
+
|
131
|
+
protected
|
132
|
+
# Read the current entry of the header.
|
133
|
+
def read_entry f, entry, assign=nil, convert=nil
|
134
|
+
assign ||= (entry.to_s + "=").to_sym
|
135
|
+
|
136
|
+
while line = f.gets
|
137
|
+
next if line =~ /^\s*#/ # ignore comment lines
|
138
|
+
line = line.chomp.split(/\s*#/)[0] # ignore the comments after any data
|
139
|
+
|
140
|
+
# Split, remove the entry name, and convert to the correct type.
|
141
|
+
self.send(assign,
|
142
|
+
line.split.tap { |t| t.shift }.map do |f|
|
143
|
+
if convert.nil?
|
144
|
+
f
|
145
|
+
elsif convert == :downcase_to_sym
|
146
|
+
f.downcase.to_sym
|
147
|
+
else
|
148
|
+
f.send(convert)
|
149
|
+
end
|
150
|
+
end)
|
151
|
+
|
152
|
+
# We don't really want to loop.
|
153
|
+
break
|
154
|
+
end
|
155
|
+
|
156
|
+
self.send(entry)
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# Determine the dtype for a matrix based on the types and
|
161
|
+
# sizes given in the PCD.
|
162
|
+
# Call this only after read_entry has been called.
|
163
|
+
def dtype
|
164
|
+
@dtype ||= begin
|
165
|
+
dtypes = self.type.map.with_index do |t,k|
|
166
|
+
MetaReader.dtype_by_type_and_size(t, size[k])
|
167
|
+
end.sort.uniq
|
168
|
+
|
169
|
+
# This could probably save one comparison at most, but we assume that
|
170
|
+
# worst case isn't going to happen very often.
|
171
|
+
while dtypes.size > 1
|
172
|
+
d = NMatrix.upcast(dtypes[0], dtypes[1])
|
173
|
+
dtypes.shift
|
174
|
+
dtypes[0] = d
|
175
|
+
end
|
176
|
+
|
177
|
+
dtypes[0]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Determine the shape of the matrix.
|
182
|
+
def shape
|
183
|
+
@shape ||= [
|
184
|
+
self.points[0],
|
185
|
+
self.fields.size
|
186
|
+
]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class NMatrix
|
2
|
+
|
3
|
+
# discussion in https://github.com/SciRuby/nmatrix/issues/374
|
4
|
+
|
5
|
+
def matrix_solve rhs
|
6
|
+
if rhs.shape[1] > 1
|
7
|
+
nmatrix = NMatrix.new :copy
|
8
|
+
nmatrix.shape = rhs.shape
|
9
|
+
res = []
|
10
|
+
#Solve a matrix and store the vectors in a matrix
|
11
|
+
(0...rhs.shape[1]).each do |i|
|
12
|
+
res << self.solve(rhs.col(i)).s.toArray.to_a
|
13
|
+
end
|
14
|
+
#res is in col major format
|
15
|
+
result = ArrayGenerator.getArrayColMajorDouble res.to_java :double, rhs.shape[0], rhs.shape[1]
|
16
|
+
nmatrix.s = ArrayRealVector.new result
|
17
|
+
|
18
|
+
return nmatrix
|
19
|
+
else
|
20
|
+
return self.solve rhs
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Source: https://github.com/marcandre/backports/blob/master/lib/backports/rails/enumerable.rb
|
2
|
+
module Enumerable
|
3
|
+
# Standard in rails... See official documentation[http://api.rubyonrails.org/classes/Enumerable.html]
|
4
|
+
# Modified from rails 2.3 to not rely on size
|
5
|
+
def sum(identity = 0, &block)
|
6
|
+
if block_given?
|
7
|
+
map(&block).sum(identity)
|
8
|
+
else
|
9
|
+
inject { |sum, element| sum + element } || identity
|
10
|
+
end
|
11
|
+
end unless method_defined? :sum
|
12
|
+
|
13
|
+
end
|