nmatrix 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/nmatrix/data/complex.h +20 -55
- data/ext/nmatrix/data/data.cpp +11 -44
- data/ext/nmatrix/data/data.h +174 -311
- data/ext/nmatrix/data/meta.h +1 -7
- data/ext/nmatrix/data/ruby_object.h +3 -85
- data/ext/nmatrix/extconf.rb +2 -73
- data/ext/nmatrix/math.cpp +170 -813
- data/ext/nmatrix/math/asum.h +2 -25
- data/ext/nmatrix/math/{inc.h → cblas_enums.h} +11 -22
- data/ext/nmatrix/math/cblas_templates_core.h +507 -0
- data/ext/nmatrix/math/gemm.h +2 -32
- data/ext/nmatrix/math/gemv.h +1 -35
- data/ext/nmatrix/math/getrf.h +21 -6
- data/ext/nmatrix/math/getrs.h +0 -8
- data/ext/nmatrix/math/imax.h +0 -22
- data/ext/nmatrix/math/long_dtype.h +0 -3
- data/ext/nmatrix/math/math.h +11 -337
- data/ext/nmatrix/math/nrm2.h +2 -23
- data/ext/nmatrix/math/rot.h +1 -25
- data/ext/nmatrix/math/rotg.h +4 -13
- data/ext/nmatrix/math/scal.h +0 -22
- data/ext/nmatrix/math/trsm.h +0 -55
- data/ext/nmatrix/math/util.h +148 -0
- data/ext/nmatrix/nmatrix.cpp +0 -14
- data/ext/nmatrix/nmatrix.h +92 -84
- data/ext/nmatrix/ruby_constants.cpp +0 -2
- data/ext/nmatrix/ruby_constants.h +0 -2
- data/ext/nmatrix/ruby_nmatrix.c +86 -45
- data/ext/nmatrix/storage/dense/dense.cpp +1 -7
- data/ext/nmatrix/storage/storage.h +0 -1
- data/ext/nmatrix/ttable_helper.rb +0 -6
- data/ext/nmatrix/util/io.cpp +1 -1
- data/lib/nmatrix.rb +1 -19
- data/lib/nmatrix/blas.rb +33 -11
- data/lib/nmatrix/io/market.rb +3 -3
- data/lib/nmatrix/lapack_core.rb +181 -0
- data/lib/nmatrix/lapack_plugin.rb +44 -0
- data/lib/nmatrix/math.rb +382 -131
- data/lib/nmatrix/monkeys.rb +2 -3
- data/lib/nmatrix/nmatrix.rb +166 -13
- data/lib/nmatrix/shortcuts.rb +72 -7
- data/lib/nmatrix/version.rb +2 -2
- data/spec/00_nmatrix_spec.rb +154 -5
- data/spec/02_slice_spec.rb +2 -6
- data/spec/03_nmatrix_monkeys_spec.rb +7 -1
- data/spec/blas_spec.rb +60 -33
- data/spec/homogeneous_spec.rb +10 -10
- data/spec/lapack_core_spec.rb +482 -0
- data/spec/math_spec.rb +436 -52
- data/spec/shortcuts_spec.rb +28 -4
- data/spec/spec_helper.rb +14 -2
- data/spec/utm5940.mtx +83844 -0
- metadata +49 -76
- data/.gitignore +0 -27
- data/.rspec +0 -2
- data/.travis.yml +0 -15
- data/CONTRIBUTING.md +0 -82
- data/Gemfile +0 -2
- data/History.txt +0 -677
- data/LICENSE.txt +0 -23
- data/Manifest.txt +0 -92
- data/README.rdoc +0 -150
- data/Rakefile +0 -216
- data/ext/nmatrix/data/rational.h +0 -440
- data/ext/nmatrix/math/geev.h +0 -82
- data/ext/nmatrix/math/ger.h +0 -96
- data/ext/nmatrix/math/gesdd.h +0 -80
- data/ext/nmatrix/math/gesvd.h +0 -78
- data/ext/nmatrix/math/getf2.h +0 -86
- data/ext/nmatrix/math/getri.h +0 -108
- data/ext/nmatrix/math/potrs.h +0 -129
- data/ext/nmatrix/math/swap.h +0 -52
- data/lib/nmatrix/lapack.rb +0 -240
- data/nmatrix.gemspec +0 -55
- data/scripts/mac-brew-gcc.sh +0 -50
- data/scripts/mac-mavericks-brew-gcc.sh +0 -22
- data/spec/lapack_spec.rb +0 -459
data/lib/nmatrix/monkeys.rb
CHANGED
@@ -44,13 +44,12 @@ class Array
|
|
44
44
|
# instead of :float64) -- optional.
|
45
45
|
# <tt>stype</tt> :: Optional storage type (defaults to :dense)
|
46
46
|
def to_nm(shape = nil, dtype = nil, stype = :dense)
|
47
|
-
elements = self
|
47
|
+
elements = self.dup
|
48
48
|
|
49
49
|
guess_dtype = ->(type) {
|
50
50
|
case type
|
51
51
|
when Fixnum then :int64
|
52
52
|
when Float then :float64
|
53
|
-
when Rational then :rational128
|
54
53
|
when Complex then :complex128
|
55
54
|
end
|
56
55
|
}
|
@@ -75,7 +74,7 @@ class Array
|
|
75
74
|
}
|
76
75
|
|
77
76
|
unless shape
|
78
|
-
shape = guess_shape.call(
|
77
|
+
shape = guess_shape.call(elements)
|
79
78
|
elements.flatten!(shape.size - 1)
|
80
79
|
if elements.flatten != elements
|
81
80
|
dtype = :object
|
data/lib/nmatrix/nmatrix.rb
CHANGED
@@ -23,18 +23,33 @@
|
|
23
23
|
#
|
24
24
|
# == nmatrix.rb
|
25
25
|
#
|
26
|
-
# This file
|
26
|
+
# This file loads the C extension for NMatrix and all the ruby
|
27
|
+
# files and contains those core functionalities which can be
|
27
28
|
# implemented efficiently (or much more easily) in Ruby (e.g.,
|
28
29
|
# inspect, pretty_print, element-wise operations).
|
29
30
|
#++
|
30
31
|
|
31
|
-
|
32
|
+
# For some reason nmatrix.so ends up in a different place during gem build.
|
33
|
+
if File.exist?("lib/nmatrix/nmatrix.so") #|| File.exist?("lib/nmatrix/nmatrix.bundle")
|
34
|
+
# Development
|
35
|
+
require "nmatrix/nmatrix.so"
|
36
|
+
else
|
37
|
+
# Gem
|
38
|
+
require "nmatrix.so"
|
39
|
+
end
|
40
|
+
|
41
|
+
require_relative './io/mat_reader'
|
42
|
+
require_relative './io/mat5_reader'
|
43
|
+
require_relative './io/market'
|
44
|
+
require_relative './io/point_cloud'
|
45
|
+
|
46
|
+
require_relative './lapack_core.rb'
|
32
47
|
require_relative './yale_functions.rb'
|
33
48
|
require_relative './monkeys'
|
34
49
|
|
35
50
|
# NMatrix is a matrix class that supports both multidimensional arrays
|
36
51
|
# (`:dense` stype) and sparse storage (`:list` or `:yale` stypes) and 13 data
|
37
|
-
# types, including complex
|
52
|
+
# types, including complex numbers, various integer and
|
38
53
|
# floating-point sizes and ruby objects.
|
39
54
|
class NMatrix
|
40
55
|
# Read and write extensions for NMatrix.
|
@@ -90,6 +105,59 @@ class NMatrix
|
|
90
105
|
shape = [shape,shape] unless shape.is_a?(Array)
|
91
106
|
(0...shape.size).inject(1) { |x,i| x * shape[i] }
|
92
107
|
end
|
108
|
+
|
109
|
+
# Make N-D coordinate arrays for vectorized evaluations of
|
110
|
+
# N-D scalar/vector fields over N-D grids, given N
|
111
|
+
# coordinate arrays arrs. N > 1.
|
112
|
+
#
|
113
|
+
# call-seq:
|
114
|
+
# meshgrid(arrs) -> Array of NMatrix
|
115
|
+
# meshgrid(arrs, options) -> Array of NMatrix
|
116
|
+
#
|
117
|
+
# * *Arguments* :
|
118
|
+
# - +vectors+ -> Array of N coordinate arrays (Array or NMatrix), if any have more than one dimension they will be flatten
|
119
|
+
# - +options+ -> Hash with options (:sparse Boolean, false by default; :indexing Symbol, may be :ij or :xy, :xy by default)
|
120
|
+
# * *Returns* :
|
121
|
+
# - Array of N N-D NMatrixes
|
122
|
+
# * *Examples* :
|
123
|
+
# x, y = NMatrix::meshgrid([[1, [2, 3]], [4, 5]])
|
124
|
+
# x.to_a #<= [[1, 2, 3], [1, 2, 3]]
|
125
|
+
# y.to_a #<= [[4, 4, 4], [5, 5, 5]]
|
126
|
+
#
|
127
|
+
# * *Using* *options* :
|
128
|
+
#
|
129
|
+
# x, y = NMatrix::meshgrid([[[1, 2], 3], [4, 5]], sparse: true)
|
130
|
+
# x.to_a #<= [[1, 2, 3]]
|
131
|
+
# y.to_a #<= [[4], [5]]
|
132
|
+
#
|
133
|
+
# x, y = NMatrix::meshgrid([[1, 2, 3], [[4], 5]], indexing: :ij)
|
134
|
+
# x.to_a #<= [[1, 1], [2, 2], [3, 3]]
|
135
|
+
# y.to_a #<= [[4, 5], [4, 5], [4, 5]]
|
136
|
+
def meshgrid(vectors, options = {})
|
137
|
+
raise(ArgumentError, 'Expected at least 2 arrays.') if vectors.size < 2
|
138
|
+
options[:indexing] ||= :xy
|
139
|
+
raise(ArgumentError, 'Indexing must be :xy of :ij') unless [:ij, :xy].include? options[:indexing]
|
140
|
+
mats = vectors.map { |arr| arr.respond_to?(:flatten) ? arr.flatten : arr.to_flat_array }
|
141
|
+
mats[0], mats[1] = mats[1], mats[0] if options[:indexing] == :xy
|
142
|
+
new_dim = mats.size
|
143
|
+
lengths = mats.map(&:size)
|
144
|
+
result = mats.map.with_index do |matrix, axis|
|
145
|
+
if options[:sparse]
|
146
|
+
new_shape = Array.new(new_dim, 1)
|
147
|
+
new_shape[axis] = lengths[axis]
|
148
|
+
new_elements = matrix
|
149
|
+
else
|
150
|
+
before_axis = lengths[0...axis].reduce(:*)
|
151
|
+
after_axis = lengths[(axis+1)..-1].reduce(:*)
|
152
|
+
new_shape = lengths
|
153
|
+
new_elements = after_axis ? matrix.map{ |el| [el] * after_axis }.flatten : matrix
|
154
|
+
new_elements *= before_axis if before_axis
|
155
|
+
end
|
156
|
+
NMatrix.new(new_shape, new_elements)
|
157
|
+
end
|
158
|
+
result[0], result[1] = result[1], result[0] if options[:indexing] == :xy
|
159
|
+
result
|
160
|
+
end
|
93
161
|
end
|
94
162
|
|
95
163
|
# TODO: Make this actually pretty.
|
@@ -153,7 +221,7 @@ class NMatrix
|
|
153
221
|
# one. You can actually call this function with no arguments, in which case it functions like #clone.
|
154
222
|
#
|
155
223
|
# If your dtype is :object and you are converting from :dense to a sparse type, it is recommended that you
|
156
|
-
# provide a :default, as 0 may behave differently from its Float
|
224
|
+
# provide a :default, as 0 may behave differently from its Float or Complex equivalent. If no option
|
157
225
|
# is given, Fixnum 0 will be used.
|
158
226
|
def cast(*params)
|
159
227
|
if (params.size > 0 && params[0].is_a?(Hash))
|
@@ -200,6 +268,35 @@ class NMatrix
|
|
200
268
|
shape[1]
|
201
269
|
end
|
202
270
|
|
271
|
+
# Return the main diagonal or antidiagonal a matrix. Only works with 2D matrices.
|
272
|
+
#
|
273
|
+
# == Arguments
|
274
|
+
#
|
275
|
+
# * +main_diagonal+ - Defaults to true. If passed 'false', then will return the
|
276
|
+
# antidiagonal of the matrix.
|
277
|
+
#
|
278
|
+
# == References
|
279
|
+
#
|
280
|
+
# * http://en.wikipedia.org/wiki/Main_diagonal
|
281
|
+
def diagonal main_diagonal=true
|
282
|
+
diag_size = [cols, rows].min
|
283
|
+
diag = NMatrix.new [diag_size], dtype: dtype
|
284
|
+
|
285
|
+
if main_diagonal
|
286
|
+
0.upto(diag_size-1) do |i|
|
287
|
+
diag[i] = self[i,i]
|
288
|
+
end
|
289
|
+
else
|
290
|
+
row = 0
|
291
|
+
(diag_size-1).downto(0) do |col|
|
292
|
+
diag[row] = self[row,col]
|
293
|
+
row += 1
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
diag
|
298
|
+
end
|
299
|
+
|
203
300
|
#
|
204
301
|
# call-seq:
|
205
302
|
# to_hash -> Hash
|
@@ -249,6 +346,15 @@ class NMatrix
|
|
249
346
|
[:byte, :int8, :int16, :int32, :int64].include?(self.dtype)
|
250
347
|
end
|
251
348
|
|
349
|
+
# call-seq:
|
350
|
+
# float_dtype?() -> Boolean
|
351
|
+
#
|
352
|
+
# Checks if dtype is a floating point type
|
353
|
+
#
|
354
|
+
def float_dtype?
|
355
|
+
[:float32, :float64].include?(dtype)
|
356
|
+
end
|
357
|
+
|
252
358
|
##
|
253
359
|
# call-seq:
|
254
360
|
# complex_dtype?() -> Boolean
|
@@ -261,12 +367,12 @@ class NMatrix
|
|
261
367
|
|
262
368
|
##
|
263
369
|
# call-seq:
|
264
|
-
#
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
268
|
-
def
|
269
|
-
|
370
|
+
#
|
371
|
+
# object_dtype?() -> Boolean
|
372
|
+
#
|
373
|
+
# Checks if dtype is a ruby object
|
374
|
+
def object_dtype?
|
375
|
+
dtype == :object
|
270
376
|
end
|
271
377
|
|
272
378
|
|
@@ -832,13 +938,13 @@ class NMatrix
|
|
832
938
|
end
|
833
939
|
|
834
940
|
|
835
|
-
def respond_to?(method) #:nodoc:
|
941
|
+
def respond_to?(method, include_all = false) #:nodoc:
|
836
942
|
if [:shuffle, :shuffle!, :each_with_index, :sorted_indices, :binned_sorted_indices, :nrm2, :asum].include?(method.intern) # vector-only methods
|
837
943
|
return vector?
|
838
944
|
elsif [:each_layer, :layer].include?(method.intern) # 3-or-more dimensions only
|
839
945
|
return dim > 2
|
840
946
|
else
|
841
|
-
super
|
947
|
+
super
|
842
948
|
end
|
843
949
|
end
|
844
950
|
|
@@ -854,6 +960,22 @@ class NMatrix
|
|
854
960
|
return self.map_stored.inject(sym)
|
855
961
|
end
|
856
962
|
|
963
|
+
# Returns the index of the first occurence of the specified value. Returns
|
964
|
+
# an array containing the position of the value, nil in case the value is not found.
|
965
|
+
#
|
966
|
+
def index(value)
|
967
|
+
index = nil
|
968
|
+
|
969
|
+
self.each_with_indices do |yields|
|
970
|
+
if yields.first == value
|
971
|
+
yields.shift
|
972
|
+
index = yields
|
973
|
+
break
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
index
|
978
|
+
end
|
857
979
|
|
858
980
|
#
|
859
981
|
# call-seq:
|
@@ -870,6 +992,33 @@ class NMatrix
|
|
870
992
|
NMatrix.new(self.shape, opts)
|
871
993
|
end
|
872
994
|
|
995
|
+
#
|
996
|
+
# call-seq:
|
997
|
+
# repeat(count, axis) -> NMatrix
|
998
|
+
#
|
999
|
+
# * *Arguments* :
|
1000
|
+
# - +count+ -> how many times NMatrix should be repeated
|
1001
|
+
# - +axis+ -> index of axis along which NMatrix should be repeated
|
1002
|
+
# * *Returns* :
|
1003
|
+
# - NMatrix created by repeating the existing one along an axis
|
1004
|
+
# * *Examples* :
|
1005
|
+
# m = NMatrix.new([2, 2], [1, 2, 3, 4])
|
1006
|
+
# m.repeat(2, 0).to_a #<= [[1, 2], [3, 4], [1, 2], [3, 4]]
|
1007
|
+
# m.repeat(2, 1).to_a #<= [[1, 2, 1, 2], [3, 4, 3, 4]]
|
1008
|
+
def repeat(count, axis)
|
1009
|
+
raise(ArgumentError, 'Matrix should be repeated at least 2 times.') if count < 2
|
1010
|
+
new_shape = shape
|
1011
|
+
new_shape[axis] *= count
|
1012
|
+
new_matrix = NMatrix.new(new_shape)
|
1013
|
+
slice = new_shape.map { |axis_size| 0...axis_size }
|
1014
|
+
start = 0
|
1015
|
+
count.times do
|
1016
|
+
slice[axis] = start...(start += shape[axis])
|
1017
|
+
new_matrix[*slice] = self
|
1018
|
+
end
|
1019
|
+
new_matrix
|
1020
|
+
end
|
1021
|
+
|
873
1022
|
# This is how you write an individual element-wise operation function:
|
874
1023
|
#def __list_elementwise_add__ rhs
|
875
1024
|
# self.__list_map_merged_stored__(rhs){ |l,r| l+r }.cast(self.stype, NMatrix.upcast(self.dtype, rhs.dtype))
|
@@ -928,7 +1077,8 @@ protected
|
|
928
1077
|
end
|
929
1078
|
|
930
1079
|
|
931
|
-
#
|
1080
|
+
# This function assumes that the shapes of the two matrices have already
|
1081
|
+
# been tested and are the same.
|
932
1082
|
#
|
933
1083
|
# Called from inside NMatrix: nm_eqeq
|
934
1084
|
#
|
@@ -973,3 +1123,6 @@ end
|
|
973
1123
|
require_relative './shortcuts.rb'
|
974
1124
|
require_relative './math.rb'
|
975
1125
|
require_relative './enumerate.rb'
|
1126
|
+
|
1127
|
+
require_relative './version.rb'
|
1128
|
+
require_relative './blas.rb'
|
data/lib/nmatrix/shortcuts.rb
CHANGED
@@ -59,7 +59,6 @@ class NMatrix
|
|
59
59
|
#
|
60
60
|
# The default value for +dtype+ is guessed from the first parameter. For example:
|
61
61
|
# NMatrix[1.0, 2.0].dtype # => :float64
|
62
|
-
# NMatrix[1r, 2r].dtype # => :rational64
|
63
62
|
#
|
64
63
|
# But this is just a *guess*. If the other values can't be converted to
|
65
64
|
# this dtype, a +TypeError+ will be raised.
|
@@ -275,6 +274,76 @@ class NMatrix
|
|
275
274
|
alias :diag :diagonal
|
276
275
|
alias :diagonals :diagonal
|
277
276
|
|
277
|
+
# Generate a block-diagonal NMatrix from the supplied 2D square matrices.
|
278
|
+
#
|
279
|
+
# * *Arguments*
|
280
|
+
# - +*params+ -> An array that collects all arguments passed to the method. The method
|
281
|
+
# can receive any number of arguments. Optionally, the last entry of +params+ is
|
282
|
+
# a hash of options from NMatrix#initialize. All other entries of +params+ are
|
283
|
+
# the blocks of the desired block-diagonal matrix. Each such matrix block can be
|
284
|
+
# supplied as a square 2D NMatrix object, or alternatively as an array of arrays
|
285
|
+
# (with dimensions corresponding to a square matrix), or alternatively as a number.
|
286
|
+
# * *Returns*
|
287
|
+
# - NMatrix of block-diagonal form filled with specified matrices
|
288
|
+
# as the blocks along the diagonal.
|
289
|
+
#
|
290
|
+
# * *Example*
|
291
|
+
#
|
292
|
+
# a = NMatrix.new([2,2], [1,2,3,4])
|
293
|
+
# b = NMatrix.new([1,1], [123], dtype: :float64)
|
294
|
+
# c = Array.new(2) { [[10,10], [10,10]] }
|
295
|
+
# d = Array[[1,2,3], [4,5,6], [7,8,9]]
|
296
|
+
# m = NMatrix.block_diagonal(a, b, *c, d, 10.0, 11, dtype: :int64, stype: :yale)
|
297
|
+
# =>
|
298
|
+
# [
|
299
|
+
# [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
300
|
+
# [3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
301
|
+
# [0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
302
|
+
# [0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0]
|
303
|
+
# [0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0]
|
304
|
+
# [0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0]
|
305
|
+
# [0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0]
|
306
|
+
# [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0]
|
307
|
+
# [0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0]
|
308
|
+
# [0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0]
|
309
|
+
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0]
|
310
|
+
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11]
|
311
|
+
# ]
|
312
|
+
#
|
313
|
+
def block_diagonal(*params)
|
314
|
+
options = params.last.is_a?(Hash) ? params.pop : {}
|
315
|
+
|
316
|
+
params.each_index do |i|
|
317
|
+
params[i] = params[i].to_nm if params[i].is_a?(Array) # Convert Array to NMatrix
|
318
|
+
params[i] = NMatrix.new([1,1], [params[i]]) if params[i].is_a?(Numeric) # Convert number to NMatrix
|
319
|
+
end
|
320
|
+
|
321
|
+
block_sizes = [] #holds the size of each matrix block
|
322
|
+
params.each do |b|
|
323
|
+
unless b.is_a?(NMatrix)
|
324
|
+
raise(ArgumentError, "Only NMatrix or appropriate Array objects or single numbers allowed")
|
325
|
+
end
|
326
|
+
raise(ArgumentError, "Only 2D matrices or 2D arrays allowed") unless b.shape.size == 2
|
327
|
+
raise(ArgumentError, "Only square-shaped blocks allowed") unless b.shape[0] == b.shape[1]
|
328
|
+
block_sizes << b.shape[0]
|
329
|
+
end
|
330
|
+
|
331
|
+
block_diag_mat = NMatrix.zeros(block_sizes.sum, options)
|
332
|
+
(0...params.length).each do |n|
|
333
|
+
# First determine the size and position of the n'th block in the block-diagonal matrix
|
334
|
+
block_size = block_sizes[n]
|
335
|
+
block_pos = block_sizes[0...n].sum
|
336
|
+
# populate the n'th block in the block-diagonal matrix
|
337
|
+
(0...block_size).each do |i|
|
338
|
+
(0...block_size).each do |j|
|
339
|
+
block_diag_mat[block_pos+i,block_pos+j] = params[n][i,j]
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
return block_diag_mat
|
345
|
+
end
|
346
|
+
alias :block_diag :block_diagonal
|
278
347
|
|
279
348
|
#
|
280
349
|
# call-seq:
|
@@ -284,8 +353,7 @@ class NMatrix
|
|
284
353
|
# by +Random::rand+. The parameter is the dimension of the matrix.
|
285
354
|
#
|
286
355
|
# If you use an integer dtype, make sure to specify :scale as a parameter, or you'll
|
287
|
-
# only get a matrix of 0s.
|
288
|
-
# a rational matrix.
|
356
|
+
# only get a matrix of 0s.
|
289
357
|
#
|
290
358
|
# * *Arguments* :
|
291
359
|
# - +shape+ -> Array (or integer for square matrix) specifying the dimensions.
|
@@ -302,8 +370,6 @@ class NMatrix
|
|
302
370
|
def random(shape, opts={})
|
303
371
|
scale = opts.delete(:scale) || 1.0
|
304
372
|
|
305
|
-
raise(NotImplementedError, "does not support rational random number generation") if opts[:dtype].to_s =~ /^rational/
|
306
|
-
|
307
373
|
rng = Random.new
|
308
374
|
|
309
375
|
random_values = []
|
@@ -330,7 +396,6 @@ class NMatrix
|
|
330
396
|
# dindgen(shape) -> NMatrix of :float64
|
331
397
|
# cindgen(shape) -> NMatrix of :complex64
|
332
398
|
# zindgen(shape) -> NMatrix of :complex128
|
333
|
-
# rindgen(shape) -> NMatrix of :rational128
|
334
399
|
# rbindgen(shape) -> NMatrix of :object
|
335
400
|
#
|
336
401
|
# Creates a matrix filled with a sequence of integers starting at zero.
|
@@ -361,7 +426,7 @@ class NMatrix
|
|
361
426
|
|
362
427
|
{:bindgen => :byte, :indgen => :int64, :findgen => :float32, :dindgen => :float64,
|
363
428
|
:cindgen => :complex64, :zindgen => :complex128,
|
364
|
-
:
|
429
|
+
:rbindgen => :object}.each_pair do |meth, dtype|
|
365
430
|
define_method(meth) { |shape| NMatrix.seq(shape, :dtype => dtype) }
|
366
431
|
end
|
367
432
|
end
|
data/lib/nmatrix/version.rb
CHANGED
@@ -28,9 +28,9 @@ class NMatrix
|
|
28
28
|
# IO can still understand NMatrix::VERSION.
|
29
29
|
module VERSION #:nodoc:
|
30
30
|
MAJOR = 0
|
31
|
-
MINOR =
|
31
|
+
MINOR = 2
|
32
32
|
TINY = 0
|
33
|
-
#
|
33
|
+
#PRE = "a"
|
34
34
|
|
35
35
|
STRING = [MAJOR, MINOR, TINY].compact.join(".")
|
36
36
|
#STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
data/spec/00_nmatrix_spec.rb
CHANGED
@@ -478,13 +478,36 @@ describe 'NMatrix' do
|
|
478
478
|
context "#==" do
|
479
479
|
[:dense, :list, :yale].each do |left|
|
480
480
|
[:dense, :list, :yale].each do |right|
|
481
|
-
next if left == right
|
482
481
|
context ("#{left}?#{right}") do
|
483
|
-
it "
|
484
|
-
n = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0
|
485
|
-
m = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0
|
486
|
-
|
482
|
+
it "tests equality of two equal matrices" do
|
483
|
+
n = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: left)
|
484
|
+
m = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: right)
|
485
|
+
|
486
|
+
expect(n==m).to eq(true)
|
487
|
+
end
|
488
|
+
|
489
|
+
it "tests equality of two unequal matrices" do
|
490
|
+
n = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,1], stype: left)
|
491
|
+
m = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: right)
|
492
|
+
|
493
|
+
expect(n==m).to eq(false)
|
494
|
+
end
|
495
|
+
|
496
|
+
it "tests equality of matrices with different shapes" do
|
497
|
+
n = NMatrix.new([2,2], [1,2, 3,4], stype: left)
|
498
|
+
m = NMatrix.new([2,3], [1,2, 3,4, 5,6], stype: right)
|
499
|
+
x = NMatrix.new([1,4], [1,2, 3,4], stype: right)
|
500
|
+
|
501
|
+
expect{n==m}.to raise_error(ShapeError)
|
502
|
+
expect{n==x}.to raise_error(ShapeError)
|
487
503
|
end
|
504
|
+
|
505
|
+
it "tests equality of matrices with different dimension" do
|
506
|
+
n = NMatrix.new([2,1], [1,2], stype: left)
|
507
|
+
m = NMatrix.new([2], [1,2], stype: right)
|
508
|
+
|
509
|
+
expect{n==m}.to raise_error(ShapeError)
|
510
|
+
end if left != :yale && right != :yale # yale must have dimension 2
|
488
511
|
end
|
489
512
|
end
|
490
513
|
end
|
@@ -578,4 +601,130 @@ describe 'NMatrix' do
|
|
578
601
|
end
|
579
602
|
end
|
580
603
|
|
604
|
+
context "#index" do
|
605
|
+
it "returns index of first occurence of an element for a vector" do
|
606
|
+
n = NMatrix.new([5], [0,22,22,11,11])
|
607
|
+
|
608
|
+
expect(n.index(22)).to eq([1])
|
609
|
+
end
|
610
|
+
|
611
|
+
it "returns index of first occurence of an element for 2-D matrix" do
|
612
|
+
n = NMatrix.new([3,3], [23,11,23,
|
613
|
+
44, 2, 0,
|
614
|
+
33, 0, 32])
|
615
|
+
|
616
|
+
expect(n.index(0)).to eq([1,2])
|
617
|
+
end
|
618
|
+
|
619
|
+
it "returns index of first occerence of an element for N-D matrix" do
|
620
|
+
n = NMatrix.new([3,3,3], [23,11,23, 44, 2, 0, 33, 0, 32,
|
621
|
+
23,11,23, 44, 2, 0, 33, 0, 32,
|
622
|
+
23,11,23, 44, 2, 0, 33, 0, 32])
|
623
|
+
|
624
|
+
expect(n.index(44)).to eq([0,1,0])
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
context "#diagonal" do
|
629
|
+
ALL_DTYPES.each do |dtype|
|
630
|
+
before do
|
631
|
+
@square_matrix = NMatrix.new([3,3], [
|
632
|
+
23,11,23,
|
633
|
+
44, 2, 0,
|
634
|
+
33, 0, 32
|
635
|
+
], dtype: dtype
|
636
|
+
)
|
637
|
+
|
638
|
+
@rect_matrix = NMatrix.new([4,3], [
|
639
|
+
23,11,23,
|
640
|
+
44, 2, 0,
|
641
|
+
33, 0,32,
|
642
|
+
11,22,33
|
643
|
+
], dtype: dtype
|
644
|
+
)
|
645
|
+
end
|
646
|
+
|
647
|
+
it "returns main diagonal for square matrix" do
|
648
|
+
expect(@square_matrix.diagonal).to eq(NMatrix.new [3], [23,2,32])
|
649
|
+
end
|
650
|
+
|
651
|
+
it "returns main diagonal for rectangular matrix" do
|
652
|
+
expect(@rect_matrix.diagonal).to eq(NMatrix.new [3], [23,2,32])
|
653
|
+
end
|
654
|
+
|
655
|
+
it "returns anti-diagonal for square matrix" do
|
656
|
+
expect(@square_matrix.diagonal(false)).to eq(NMatrix.new [3], [23,2,33])
|
657
|
+
end
|
658
|
+
|
659
|
+
it "returns anti-diagonal for rectangular matrix" do
|
660
|
+
expect(@square_matrix.diagonal(false)).to eq(NMatrix.new [3], [23,2,33])
|
661
|
+
end
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
context "#repeat" do
|
666
|
+
before do
|
667
|
+
@sample_matrix = NMatrix.new([2, 2], [1, 2, 3, 4])
|
668
|
+
end
|
669
|
+
|
670
|
+
it "checks count argument" do
|
671
|
+
expect{@sample_matrix.repeat(1, 0)}.to raise_error(ArgumentError)
|
672
|
+
expect{@sample_matrix.repeat(-2, 0)}.to raise_error(ArgumentError)
|
673
|
+
end
|
674
|
+
|
675
|
+
it "returns repeated matrix" do
|
676
|
+
expect(@sample_matrix.repeat(2, 0)).to eq(NMatrix.new([4, 2], [1, 2, 3, 4, 1, 2, 3, 4]))
|
677
|
+
expect(@sample_matrix.repeat(2, 1)).to eq(NMatrix.new([2, 4], [1, 2, 1, 2, 3, 4, 3, 4]))
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
context "#meshgrid" do
|
682
|
+
before do
|
683
|
+
@x, @y, @z = [1, 2, 3], NMatrix.new([2, 1], [4, 5]), [6, 7]
|
684
|
+
@two_dim = NMatrix.new([2, 2], [1, 2, 3, 4])
|
685
|
+
@two_dim_array = [[4], [5]]
|
686
|
+
@expected_result = [NMatrix.new([2, 3], [1, 2, 3, 1, 2, 3]), NMatrix.new([2, 3], [4, 4, 4, 5, 5, 5])]
|
687
|
+
@expected_for_ij = [NMatrix.new([3, 2], [1, 1, 2, 2, 3, 3]), NMatrix.new([3, 2], [4, 5, 4, 5, 4, 5])]
|
688
|
+
@expected_for_sparse = [NMatrix.new([1, 3], [1, 2, 3]), NMatrix.new([2, 1], [4, 5])]
|
689
|
+
@expected_for_sparse_ij = [NMatrix.new([3, 1], [1, 2, 3]), NMatrix.new([1, 2], [4, 5])]
|
690
|
+
@expected_3dim = [NMatrix.new([1, 3, 1], [1, 2, 3]).repeat(2, 0).repeat(2, 2),
|
691
|
+
NMatrix.new([2, 1, 1], [4, 5]).repeat(3, 1).repeat(2, 2),
|
692
|
+
NMatrix.new([1, 1, 2], [6, 7]).repeat(2, 0).repeat(3, 1)]
|
693
|
+
@expected_3dim_sparse_ij = [NMatrix.new([3, 1, 1], [1, 2, 3]),
|
694
|
+
NMatrix.new([1, 2, 1], [4, 5]),
|
695
|
+
NMatrix.new([1, 1, 2], [6, 7])]
|
696
|
+
end
|
697
|
+
|
698
|
+
it "checks arrays count" do
|
699
|
+
expect{NMatrix.meshgrid([@x])}.to raise_error(ArgumentError)
|
700
|
+
expect{NMatrix.meshgrid([])}.to raise_error(ArgumentError)
|
701
|
+
end
|
702
|
+
|
703
|
+
it "flattens input arrays before use" do
|
704
|
+
expect(NMatrix.meshgrid([@two_dim, @two_dim_array])).to eq(NMatrix.meshgrid([@two_dim.to_flat_array, @two_dim_array.flatten]))
|
705
|
+
end
|
706
|
+
|
707
|
+
it "returns new NMatrixes" do
|
708
|
+
expect(NMatrix.meshgrid([@x, @y])).to eq(@expected_result)
|
709
|
+
end
|
710
|
+
|
711
|
+
it "has option :sparse" do
|
712
|
+
expect(NMatrix.meshgrid([@x, @y], sparse: true)).to eq(@expected_for_sparse)
|
713
|
+
end
|
714
|
+
|
715
|
+
it "has option :indexing" do
|
716
|
+
expect(NMatrix.meshgrid([@x, @y], indexing: :ij)).to eq(@expected_for_ij)
|
717
|
+
expect(NMatrix.meshgrid([@x, @y], indexing: :xy)).to eq(@expected_result)
|
718
|
+
expect{NMatrix.meshgrid([@x, @y], indexing: :not_ij_not_xy)}.to raise_error(ArgumentError)
|
719
|
+
end
|
720
|
+
|
721
|
+
it "works well with both options set" do
|
722
|
+
expect(NMatrix.meshgrid([@x, @y], sparse: true, indexing: :ij)).to eq(@expected_for_sparse_ij)
|
723
|
+
end
|
724
|
+
|
725
|
+
it "is able to take more than two arrays as arguments and works well with options" do
|
726
|
+
expect(NMatrix.meshgrid([@x, @y, @z])).to eq(@expected_3dim)
|
727
|
+
expect(NMatrix.meshgrid([@x, @y, @z], sparse: true, indexing: :ij)).to eq(@expected_3dim_sparse_ij)
|
728
|
+
end
|
729
|
+
end
|
581
730
|
end
|