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.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/ext/nmatrix/binary_format.txt +53 -0
  3. data/ext/nmatrix/data/complex.h +388 -0
  4. data/ext/nmatrix/data/data.cpp +274 -0
  5. data/ext/nmatrix/data/data.h +651 -0
  6. data/ext/nmatrix/data/meta.h +64 -0
  7. data/ext/nmatrix/data/ruby_object.h +386 -0
  8. data/ext/nmatrix/extconf.rb +70 -0
  9. data/ext/nmatrix/math/asum.h +99 -0
  10. data/ext/nmatrix/math/cblas_enums.h +36 -0
  11. data/ext/nmatrix/math/cblas_templates_core.h +507 -0
  12. data/ext/nmatrix/math/gemm.h +241 -0
  13. data/ext/nmatrix/math/gemv.h +178 -0
  14. data/ext/nmatrix/math/getrf.h +255 -0
  15. data/ext/nmatrix/math/getrs.h +121 -0
  16. data/ext/nmatrix/math/imax.h +82 -0
  17. data/ext/nmatrix/math/laswp.h +165 -0
  18. data/ext/nmatrix/math/long_dtype.h +62 -0
  19. data/ext/nmatrix/math/magnitude.h +54 -0
  20. data/ext/nmatrix/math/math.h +751 -0
  21. data/ext/nmatrix/math/nrm2.h +165 -0
  22. data/ext/nmatrix/math/rot.h +117 -0
  23. data/ext/nmatrix/math/rotg.h +106 -0
  24. data/ext/nmatrix/math/scal.h +71 -0
  25. data/ext/nmatrix/math/trsm.h +336 -0
  26. data/ext/nmatrix/math/util.h +162 -0
  27. data/ext/nmatrix/math.cpp +1368 -0
  28. data/ext/nmatrix/nm_memory.h +60 -0
  29. data/ext/nmatrix/nmatrix.cpp +285 -0
  30. data/ext/nmatrix/nmatrix.h +476 -0
  31. data/ext/nmatrix/ruby_constants.cpp +151 -0
  32. data/ext/nmatrix/ruby_constants.h +106 -0
  33. data/ext/nmatrix/ruby_nmatrix.c +3130 -0
  34. data/ext/nmatrix/storage/common.cpp +77 -0
  35. data/ext/nmatrix/storage/common.h +183 -0
  36. data/ext/nmatrix/storage/dense/dense.cpp +1096 -0
  37. data/ext/nmatrix/storage/dense/dense.h +129 -0
  38. data/ext/nmatrix/storage/list/list.cpp +1628 -0
  39. data/ext/nmatrix/storage/list/list.h +138 -0
  40. data/ext/nmatrix/storage/storage.cpp +730 -0
  41. data/ext/nmatrix/storage/storage.h +99 -0
  42. data/ext/nmatrix/storage/yale/class.h +1139 -0
  43. data/ext/nmatrix/storage/yale/iterators/base.h +143 -0
  44. data/ext/nmatrix/storage/yale/iterators/iterator.h +131 -0
  45. data/ext/nmatrix/storage/yale/iterators/row.h +450 -0
  46. data/ext/nmatrix/storage/yale/iterators/row_stored.h +140 -0
  47. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +169 -0
  48. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +124 -0
  49. data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
  50. data/ext/nmatrix/storage/yale/yale.cpp +2074 -0
  51. data/ext/nmatrix/storage/yale/yale.h +203 -0
  52. data/ext/nmatrix/types.h +55 -0
  53. data/ext/nmatrix/util/io.cpp +279 -0
  54. data/ext/nmatrix/util/io.h +115 -0
  55. data/ext/nmatrix/util/sl_list.cpp +627 -0
  56. data/ext/nmatrix/util/sl_list.h +144 -0
  57. data/ext/nmatrix/util/util.h +78 -0
  58. data/lib/nmatrix/blas.rb +378 -0
  59. data/lib/nmatrix/cruby/math.rb +744 -0
  60. data/lib/nmatrix/enumerate.rb +253 -0
  61. data/lib/nmatrix/homogeneous.rb +241 -0
  62. data/lib/nmatrix/io/fortran_format.rb +138 -0
  63. data/lib/nmatrix/io/harwell_boeing.rb +221 -0
  64. data/lib/nmatrix/io/market.rb +263 -0
  65. data/lib/nmatrix/io/point_cloud.rb +189 -0
  66. data/lib/nmatrix/jruby/decomposition.rb +24 -0
  67. data/lib/nmatrix/jruby/enumerable.rb +13 -0
  68. data/lib/nmatrix/jruby/error.rb +4 -0
  69. data/lib/nmatrix/jruby/math.rb +501 -0
  70. data/lib/nmatrix/jruby/nmatrix_java.rb +840 -0
  71. data/lib/nmatrix/jruby/operators.rb +283 -0
  72. data/lib/nmatrix/jruby/slice.rb +264 -0
  73. data/lib/nmatrix/lapack_core.rb +181 -0
  74. data/lib/nmatrix/lapack_plugin.rb +44 -0
  75. data/lib/nmatrix/math.rb +953 -0
  76. data/lib/nmatrix/mkmf.rb +100 -0
  77. data/lib/nmatrix/monkeys.rb +137 -0
  78. data/lib/nmatrix/nmatrix.rb +1172 -0
  79. data/lib/nmatrix/rspec.rb +75 -0
  80. data/lib/nmatrix/shortcuts.rb +1163 -0
  81. data/lib/nmatrix/version.rb +39 -0
  82. data/lib/nmatrix/yale_functions.rb +118 -0
  83. data/lib/nmatrix.rb +28 -0
  84. data/spec/00_nmatrix_spec.rb +892 -0
  85. data/spec/01_enum_spec.rb +196 -0
  86. data/spec/02_slice_spec.rb +407 -0
  87. data/spec/03_nmatrix_monkeys_spec.rb +80 -0
  88. data/spec/2x2_dense_double.mat +0 -0
  89. data/spec/4x4_sparse.mat +0 -0
  90. data/spec/4x5_dense.mat +0 -0
  91. data/spec/blas_spec.rb +215 -0
  92. data/spec/elementwise_spec.rb +311 -0
  93. data/spec/homogeneous_spec.rb +100 -0
  94. data/spec/io/fortran_format_spec.rb +88 -0
  95. data/spec/io/harwell_boeing_spec.rb +98 -0
  96. data/spec/io/test.rua +9 -0
  97. data/spec/io_spec.rb +159 -0
  98. data/spec/lapack_core_spec.rb +482 -0
  99. data/spec/leakcheck.rb +16 -0
  100. data/spec/math_spec.rb +1363 -0
  101. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  102. data/spec/nmatrix_yale_spec.rb +286 -0
  103. data/spec/rspec_monkeys.rb +56 -0
  104. data/spec/rspec_spec.rb +35 -0
  105. data/spec/shortcuts_spec.rb +474 -0
  106. data/spec/slice_set_spec.rb +162 -0
  107. data/spec/spec_helper.rb +172 -0
  108. data/spec/stat_spec.rb +214 -0
  109. data/spec/test.pcd +20 -0
  110. data/spec/utm5940.mtx +83844 -0
  111. 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