pnmatrix 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|