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
data/spec/math_spec.rb
ADDED
|
@@ -0,0 +1,1363 @@
|
|
|
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 - 2014, Ruby Science Foundation
|
|
12
|
+
# NMatrix is Copyright (c) 2012 - 2014, 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
|
+
# == math_spec.rb
|
|
24
|
+
#
|
|
25
|
+
# Tests for non-BLAS and non-LAPACK math functions, or for simplified
|
|
26
|
+
# versions of unfriendly BLAS and LAPACK functions.
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
require 'spec_helper'
|
|
30
|
+
|
|
31
|
+
describe "math" do
|
|
32
|
+
context "elementwise math functions" do
|
|
33
|
+
|
|
34
|
+
[:dense,:list,:yale].each do |stype|
|
|
35
|
+
context stype do
|
|
36
|
+
|
|
37
|
+
[:int64,:float64].each do |dtype|
|
|
38
|
+
context dtype do
|
|
39
|
+
before :each do
|
|
40
|
+
@size = [2,2]
|
|
41
|
+
@m = NMatrix.seq(@size, dtype: dtype, stype: stype)+1
|
|
42
|
+
@a = @m.to_a.flatten
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
NMatrix::NMMath::METHODS_ARITY_1.each do |meth|
|
|
46
|
+
#skip inverse regular trig functions
|
|
47
|
+
next if meth.to_s.start_with?('a') and (not meth.to_s.end_with?('h')) \
|
|
48
|
+
and NMatrix::NMMath::METHODS_ARITY_1.include?(
|
|
49
|
+
meth.to_s[1...meth.to_s.length].to_sym)
|
|
50
|
+
next if meth == :atanh
|
|
51
|
+
|
|
52
|
+
if meth == :-@
|
|
53
|
+
it "should correctly apply elementwise negation" do
|
|
54
|
+
expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| -e }, dtype: dtype, stype: stype)
|
|
55
|
+
end
|
|
56
|
+
next
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should correctly apply elementwise #{meth}" do
|
|
60
|
+
|
|
61
|
+
expect(@m.send(meth)).to eq N.new(@size, @a.map{ |e| Math.send(meth, e) },
|
|
62
|
+
dtype: :float64, stype: stype)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
NMatrix::NMMath::METHODS_ARITY_2.each do |meth|
|
|
67
|
+
next if meth == :atan2
|
|
68
|
+
it "should correctly apply elementwise #{meth}" do
|
|
69
|
+
expect(@m.send(meth, @m)).to eq N.new(@size, @a.map{ |e|
|
|
70
|
+
Math.send(meth, e, e) },
|
|
71
|
+
dtype: :float64,
|
|
72
|
+
stype: stype)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "should correctly apply elementwise #{meth} with a scalar first arg" do
|
|
76
|
+
expect(Math.send(meth, 1, @m)).to eq N.new(@size, @a.map { |e| Math.send(meth, 1, e) }, dtype: :float64, stype: stype)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "should correctly apply elementwise #{meth} with a scalar second arg" do
|
|
80
|
+
expect(@m.send(meth, 1)).to eq N.new(@size, @a.map { |e| Math.send(meth, e, 1) }, dtype: :float64, stype: stype)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should correctly apply elementwise natural log" do
|
|
85
|
+
expect(@m.log).to eq N.new(@size, [0, Math.log(2), Math.log(3), Math.log(4)],
|
|
86
|
+
dtype: :float64, stype: stype)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should correctly apply elementwise log with arbitrary base" do
|
|
90
|
+
expect(@m.log(3)).to eq N.new(@size, [0, Math.log(2,3), 1, Math.log(4,3)],
|
|
91
|
+
dtype: :float64, stype: stype)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context "inverse trig functions" do
|
|
95
|
+
before :each do
|
|
96
|
+
@m = NMatrix.seq(@size, dtype: dtype, stype: stype)/4
|
|
97
|
+
@a = @m.to_a.flatten
|
|
98
|
+
end
|
|
99
|
+
[:asin, :acos, :atan, :atanh].each do |atf|
|
|
100
|
+
|
|
101
|
+
it "should correctly apply elementwise #{atf}" do
|
|
102
|
+
expect(@m.send(atf)).to eq N.new(@size,
|
|
103
|
+
@a.map{ |e| Math.send(atf, e) },
|
|
104
|
+
dtype: :float64, stype: stype)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "should correctly apply elementtwise atan2" do
|
|
109
|
+
expect(@m.atan2(@m*0+1)).to eq N.new(@size,
|
|
110
|
+
@a.map { |e| Math.send(:atan2, e, 1) }, dtype: :float64, stype: stype)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should correctly apply elementwise atan2 with a scalar first arg" do
|
|
114
|
+
expect(Math.atan2(1, @m)).to eq N.new(@size, @a.map { |e| Math.send(:atan2, 1, e) }, dtype: :float64, stype: stype)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "should correctly apply elementwise atan2 with a scalar second arg" do
|
|
118
|
+
expect(@m.atan2(1)).to eq N.new(@size, @a.map { |e| Math.send(:atan2, e, 1) }, dtype: :float64, stype: stype)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context "Floor and ceil for #{stype}" do
|
|
125
|
+
|
|
126
|
+
[:floor, :ceil].each do |meth|
|
|
127
|
+
ALL_DTYPES.each do |dtype|
|
|
128
|
+
context dtype do
|
|
129
|
+
before :each do
|
|
130
|
+
@size = [2,2]
|
|
131
|
+
@m = NMatrix.seq(@size, dtype: dtype, stype: stype)+1 unless jruby? and dtype == :object
|
|
132
|
+
@a = @m.to_a.flatten
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if dtype.to_s.match(/int/) or [:byte, :object].include?(dtype)
|
|
136
|
+
it "should return #{dtype} for #{dtype}" do
|
|
137
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
138
|
+
|
|
139
|
+
expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| e.send(meth) }, dtype: dtype, stype: stype)
|
|
140
|
+
|
|
141
|
+
if dtype == :object
|
|
142
|
+
expect(@m.send(meth).dtype).to eq :object
|
|
143
|
+
else
|
|
144
|
+
expect(@m.send(meth).integer_dtype?).to eq true
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
elsif dtype.to_s.match(/float/)
|
|
148
|
+
it "should return dtype int64 for #{dtype}" do
|
|
149
|
+
|
|
150
|
+
expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| e.send(meth) }, dtype: dtype, stype: stype)
|
|
151
|
+
|
|
152
|
+
expect(@m.send(meth).dtype).to eq :int64
|
|
153
|
+
end
|
|
154
|
+
elsif dtype.to_s.match(/complex/)
|
|
155
|
+
it "should properly calculate #{meth} for #{dtype}" do
|
|
156
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
157
|
+
|
|
158
|
+
expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| e = Complex(e.real.send(meth), e.imag.send(meth)) }, dtype: dtype, stype: stype)
|
|
159
|
+
|
|
160
|
+
expect(@m.send(meth).dtype).to eq :complex64 if dtype == :complex64
|
|
161
|
+
expect(@m.send(meth).dtype).to eq :complex128 if dtype == :complex128
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
context "#round for #{stype}" do
|
|
170
|
+
ALL_DTYPES.each do |dtype|
|
|
171
|
+
context dtype do
|
|
172
|
+
before :each do
|
|
173
|
+
@size = [2,2]
|
|
174
|
+
@mat = NMatrix.new @size, [1.33334, 0.9998, 1.9999, -8.9999],
|
|
175
|
+
dtype: dtype, stype: stype
|
|
176
|
+
@ans = @mat.to_a.flatten unless jruby? and dtype == :object
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "rounds" do
|
|
180
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
181
|
+
expect(@mat.round).to eq(N.new(@size, @ans.map { |a| a.round},
|
|
182
|
+
dtype: dtype, stype: stype))
|
|
183
|
+
end unless(/complex/ =~ dtype)
|
|
184
|
+
|
|
185
|
+
it "rounds with args" do
|
|
186
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
187
|
+
expect(@mat.round(2)).to eq(N.new(@size, @ans.map { |a| a.round(2)},
|
|
188
|
+
dtype: dtype, stype: stype))
|
|
189
|
+
end unless(/complex/ =~ dtype)
|
|
190
|
+
|
|
191
|
+
it "rounds complex with args" do
|
|
192
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
193
|
+
puts @mat.round(2)
|
|
194
|
+
expect(@mat.round(2)).to be_within(0.0001).of(N.new [2,2], @ans.map {|a|
|
|
195
|
+
Complex(a.real.round(2), a.imag.round(2))},dtype: dtype, stype: stype)
|
|
196
|
+
end if(/complex/ =~ dtype)
|
|
197
|
+
|
|
198
|
+
it "rounds complex" do
|
|
199
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
200
|
+
expect(@mat.round).to eq(N.new [2,2], @ans.map {|a|
|
|
201
|
+
Complex(a.real.round, a.imag.round)},dtype: dtype, stype: stype)
|
|
202
|
+
end if(/complex/ =~ dtype)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
|
212
|
+
context dtype do
|
|
213
|
+
before do
|
|
214
|
+
@m = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype)
|
|
215
|
+
@err = case dtype
|
|
216
|
+
when :float32, :complex64
|
|
217
|
+
1e-6
|
|
218
|
+
when :float64, :complex128
|
|
219
|
+
1e-14
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
#haven't check this spec yet. Also it doesn't check all the elements of the matrix.
|
|
224
|
+
it "should correctly factorize a matrix" do
|
|
225
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
226
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
227
|
+
a = @m.factorize_lu
|
|
228
|
+
expect(a).to be_within(@err).of(NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it "also returns the permutation matrix" do
|
|
232
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
233
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
234
|
+
|
|
235
|
+
a, p = @m.factorize_lu perm_matrix: true
|
|
236
|
+
|
|
237
|
+
expect(a).to be_within(@err).of(NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype))
|
|
238
|
+
|
|
239
|
+
p_true = NMatrix.new([3,3], [0,0,1,1,0,0,0,1,0], dtype: dtype)
|
|
240
|
+
expect(p).to eq(p_true)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
|
246
|
+
context dtype do
|
|
247
|
+
|
|
248
|
+
it "calculates cholesky decomposition using potrf (lower)" do
|
|
249
|
+
#a = NMatrix.new([3,3],[1,1,1, 1,2,2, 1,2,6], dtype: dtype)
|
|
250
|
+
# We use the matrix
|
|
251
|
+
# 1 1 1
|
|
252
|
+
# 1 2 2
|
|
253
|
+
# 1 2 6
|
|
254
|
+
# which is symmetric and positive-definite as required, but
|
|
255
|
+
# we need only store the lower-half of the matrix.
|
|
256
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
257
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
258
|
+
a = NMatrix.new([3,3],[1,0,0, 1,2,0, 1,2,6], dtype: dtype)
|
|
259
|
+
begin
|
|
260
|
+
r = a.potrf!(:lower)
|
|
261
|
+
|
|
262
|
+
b = NMatrix.new([3,3],[1,0,0, 1,1,0, 1,1,2], dtype: dtype)
|
|
263
|
+
expect(a).to eq(b)
|
|
264
|
+
expect(r).to eq(b)
|
|
265
|
+
rescue NotImplementedError
|
|
266
|
+
pending "potrf! not implemented without plugins"
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it "calculates cholesky decomposition using potrf (upper)" do
|
|
271
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
272
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
273
|
+
|
|
274
|
+
a = NMatrix.new([3,3],[1,1,1, 0,2,2, 0,0,6], dtype: dtype)
|
|
275
|
+
begin
|
|
276
|
+
r = a.potrf!(:upper)
|
|
277
|
+
|
|
278
|
+
b = NMatrix.new([3,3],[1,1,1, 0,1,1, 0,0,2], dtype: dtype)
|
|
279
|
+
expect(a).to eq(b)
|
|
280
|
+
expect(r).to eq(b)
|
|
281
|
+
rescue NotImplementedError
|
|
282
|
+
pending "potrf! not implemented without plugins"
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it "calculates cholesky decomposition using #factorize_cholesky" do
|
|
287
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
288
|
+
a = NMatrix.new([3,3],[1,2,1, 2,13,5, 1,5,6], dtype: dtype)
|
|
289
|
+
begin
|
|
290
|
+
u,l = a.factorize_cholesky
|
|
291
|
+
|
|
292
|
+
l_true = NMatrix.new([3,3],[1,0,0, 2,3,0, 1,1,2], dtype: dtype)
|
|
293
|
+
u_true = l_true.transpose
|
|
294
|
+
expect(u).to eq(u_true)
|
|
295
|
+
expect(l).to eq(l_true)
|
|
296
|
+
rescue NotImplementedError
|
|
297
|
+
pending "potrf! not implemented without plugins"
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
|
304
|
+
context dtype do
|
|
305
|
+
|
|
306
|
+
it "calculates QR decomposition using factorize_qr for a square matrix" do
|
|
307
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
308
|
+
a = NMatrix.new(3, [12.0, -51.0, 4.0,
|
|
309
|
+
6.0, 167.0, -68.0,
|
|
310
|
+
-4.0, 24.0, -41.0] , dtype: dtype)
|
|
311
|
+
|
|
312
|
+
q_solution = NMatrix.new([3,3], Q_SOLUTION_ARRAY_2, dtype: dtype)
|
|
313
|
+
|
|
314
|
+
r_solution = NMatrix.new([3,3], [-14.0, -21.0, 14,
|
|
315
|
+
0.0, -175, 70,
|
|
316
|
+
0.0, 0.0, -35] , dtype: dtype)
|
|
317
|
+
|
|
318
|
+
err = case dtype
|
|
319
|
+
when :float32, :complex64
|
|
320
|
+
1e-4
|
|
321
|
+
when :float64, :complex128
|
|
322
|
+
1e-13
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
begin
|
|
326
|
+
q,r = a.factorize_qr
|
|
327
|
+
|
|
328
|
+
expect(q).to be_within(err).of(q_solution)
|
|
329
|
+
expect(r).to be_within(err).of(r_solution)
|
|
330
|
+
|
|
331
|
+
rescue NotImplementedError
|
|
332
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it "calculates QR decomposition using factorize_qr for a tall and narrow rectangular matrix" do
|
|
337
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
338
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
339
|
+
|
|
340
|
+
a = NMatrix.new([4,2], [34.0, 21.0,
|
|
341
|
+
23.0, 53.0,
|
|
342
|
+
26.0, 346.0,
|
|
343
|
+
23.0, 121.0] , dtype: dtype)
|
|
344
|
+
|
|
345
|
+
q_solution = NMatrix.new([4,4], Q_SOLUTION_ARRAY_1, dtype: dtype)
|
|
346
|
+
|
|
347
|
+
r_solution = NMatrix.new([4,2], [-53.75872022286244, -255.06559574252242,
|
|
348
|
+
0.0, 269.34836526051555,
|
|
349
|
+
0.0, 0.0,
|
|
350
|
+
0.0, 0.0] , dtype: dtype)
|
|
351
|
+
|
|
352
|
+
err = case dtype
|
|
353
|
+
when :float32, :complex64
|
|
354
|
+
1e-4
|
|
355
|
+
when :float64, :complex128
|
|
356
|
+
1e-13
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
begin
|
|
360
|
+
q,r = a.factorize_qr
|
|
361
|
+
|
|
362
|
+
expect(q).to be_within(err).of(q_solution)
|
|
363
|
+
expect(r).to be_within(err).of(r_solution)
|
|
364
|
+
|
|
365
|
+
rescue NotImplementedError
|
|
366
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
it "calculates QR decomposition using factorize_qr for a short and wide rectangular matrix" do
|
|
371
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
372
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
373
|
+
|
|
374
|
+
a = NMatrix.new([3,4], [123,31,57,81,92,14,17,36,42,34,11,28], dtype: dtype)
|
|
375
|
+
|
|
376
|
+
q_solution = NMatrix.new([3,3], Q_SOLUTION_ARRAY_3, dtype: dtype)
|
|
377
|
+
|
|
378
|
+
r_solution = NMatrix.new([3,4], R_SOLUTION_ARRAY, dtype: dtype)
|
|
379
|
+
|
|
380
|
+
err = case dtype
|
|
381
|
+
when :float32, :complex64
|
|
382
|
+
1e-4
|
|
383
|
+
when :float64, :complex128
|
|
384
|
+
1e-13
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
begin
|
|
388
|
+
q,r = a.factorize_qr
|
|
389
|
+
|
|
390
|
+
expect(q).to be_within(err).of(q_solution)
|
|
391
|
+
expect(r).to be_within(err).of(r_solution)
|
|
392
|
+
|
|
393
|
+
rescue NotImplementedError
|
|
394
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
it "calculates QR decomposition such that A - QR ~ 0" do
|
|
399
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
400
|
+
a = NMatrix.new([3,3], [ 9.0, 0.0, 26.0,
|
|
401
|
+
12.0, 0.0, -7.0,
|
|
402
|
+
0.0, 4.0, 0.0] , dtype: dtype)
|
|
403
|
+
|
|
404
|
+
err = case dtype
|
|
405
|
+
when :float32, :complex64
|
|
406
|
+
1e-4
|
|
407
|
+
when :float64, :complex128
|
|
408
|
+
1e-13
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
begin
|
|
412
|
+
q,r = a.factorize_qr
|
|
413
|
+
a_expected = q.dot(r)
|
|
414
|
+
|
|
415
|
+
expect(a_expected).to be_within(err).of(a)
|
|
416
|
+
|
|
417
|
+
rescue NotImplementedError
|
|
418
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
it "calculates the orthogonal matrix Q in QR decomposition" do
|
|
424
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
425
|
+
a = N.new([2,2], [34.0, 21, 23, 53] , dtype: dtype)
|
|
426
|
+
|
|
427
|
+
err = case dtype
|
|
428
|
+
when :float32, :complex64
|
|
429
|
+
1e-4
|
|
430
|
+
when :float64, :complex128
|
|
431
|
+
1e-13
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
begin
|
|
435
|
+
q,r = a.factorize_qr
|
|
436
|
+
|
|
437
|
+
#Q is orthogonal if Q x Q.transpose = I
|
|
438
|
+
product = q.dot(q.transpose)
|
|
439
|
+
|
|
440
|
+
expect(product[0,0]).to be_within(err).of(1)
|
|
441
|
+
expect(product[1,0]).to be_within(err).of(0)
|
|
442
|
+
expect(product[0,1]).to be_within(err).of(0)
|
|
443
|
+
expect(product[1,1]).to be_within(err).of(1)
|
|
444
|
+
|
|
445
|
+
rescue NotImplementedError
|
|
446
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
ALL_DTYPES.each do |dtype|
|
|
453
|
+
next if dtype == :byte #doesn't work for unsigned types
|
|
454
|
+
|
|
455
|
+
context dtype do
|
|
456
|
+
err = case dtype
|
|
457
|
+
when :float32, :complex64
|
|
458
|
+
1e-4
|
|
459
|
+
else #integer matrices will return :float64
|
|
460
|
+
1e-13
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
it "should correctly invert a matrix in place (bang)" do
|
|
464
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
465
|
+
a = NMatrix.new(:dense, 5, [1, 8,-9, 7, 5,
|
|
466
|
+
0, 1, 0, 4, 4,
|
|
467
|
+
0, 0, 1, 2, 5,
|
|
468
|
+
0, 0, 0, 1,-5,
|
|
469
|
+
0, 0, 0, 0, 1 ], dtype)
|
|
470
|
+
b = NMatrix.new(:dense, 5, [1,-8, 9, 7, 17,
|
|
471
|
+
0, 1, 0,-4,-24,
|
|
472
|
+
0, 0, 1,-2,-15,
|
|
473
|
+
0, 0, 0, 1, 5,
|
|
474
|
+
0, 0, 0, 0, 1,], dtype)
|
|
475
|
+
if a.integer_dtype?
|
|
476
|
+
expect{a.invert!}.to raise_error(DataTypeError)
|
|
477
|
+
else
|
|
478
|
+
#should return inverse as well as modifying a
|
|
479
|
+
r = a.invert!
|
|
480
|
+
expect(a).to be_within(err).of(b)
|
|
481
|
+
expect(r).to be_within(err).of(b)
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
it "should correctly invert a dense matrix out-of-place" do
|
|
487
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
488
|
+
a = NMatrix.new(:dense, 3, [1,2,3,0,1,4,5,6,0], dtype)
|
|
489
|
+
|
|
490
|
+
if a.integer_dtype?
|
|
491
|
+
b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], :float64)
|
|
492
|
+
else
|
|
493
|
+
b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], dtype)
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
expect(a.invert).to be_within(err).of(b)
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
it "should correctly find exact inverse" do
|
|
500
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
501
|
+
a = NMatrix.new(:dense, 3, [1,2,3,0,1,4,5,6,0], dtype)
|
|
502
|
+
b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], dtype)
|
|
503
|
+
|
|
504
|
+
expect(a.exact_inverse).to be_within(err).of(b)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
it "should correctly find exact inverse" do
|
|
508
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
509
|
+
a = NMatrix.new(:dense, 2, [1,3,3,8], dtype)
|
|
510
|
+
b = NMatrix.new(:dense, 2, [-8,3,3,-1], dtype)
|
|
511
|
+
|
|
512
|
+
expect(a.exact_inverse).to be_within(err).of(b)
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
|
518
|
+
context dtype do
|
|
519
|
+
err = Complex(1e-3, 1e-3)
|
|
520
|
+
it "should correctly invert a 2x2 matrix" do
|
|
521
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
522
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
523
|
+
if dtype == :complex64 || dtype == :complex128
|
|
524
|
+
a = NMatrix.new([2, 2], [Complex(16, 81), Complex(91, 51), \
|
|
525
|
+
Complex(13, 54), Complex(71, 24)], dtype: dtype)
|
|
526
|
+
b = NMatrix.identity(2, dtype: dtype)
|
|
527
|
+
|
|
528
|
+
begin
|
|
529
|
+
expect(a.dot(a.pinv)).to be_within(err).of(b)
|
|
530
|
+
rescue NotImplementedError
|
|
531
|
+
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
else
|
|
535
|
+
a = NMatrix.new([2, 2], [141, 612, 9123, 654], dtype: dtype)
|
|
536
|
+
b = NMatrix.identity(2, dtype: dtype)
|
|
537
|
+
|
|
538
|
+
begin
|
|
539
|
+
expect(a.dot(a.pinv)).to be_within(err).of(b)
|
|
540
|
+
rescue NotImplementedError
|
|
541
|
+
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
it "should verify a.dot(b.dot(a)) == a and b.dot(a.dot(b)) == b" do
|
|
547
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
548
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
549
|
+
if dtype == :complex64 || dtype == :complex128
|
|
550
|
+
a = NMatrix.new([3, 2], [Complex(94, 11), Complex(87, 51), Complex(82, 39), \
|
|
551
|
+
Complex(45, 16), Complex(25, 32), Complex(91, 43) ], dtype: dtype)
|
|
552
|
+
|
|
553
|
+
begin
|
|
554
|
+
b = a.pinv # pseudo inverse
|
|
555
|
+
expect(a.dot(b.dot(a))).to be_within(err).of(a)
|
|
556
|
+
expect(b.dot(a.dot(b))).to be_within(err).of(b)
|
|
557
|
+
rescue NotImplementedError
|
|
558
|
+
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
else
|
|
562
|
+
a = NMatrix.new([3, 3], [9, 4, 52, 12, 52, 1, 3, 55, 6], dtype: dtype)
|
|
563
|
+
|
|
564
|
+
begin
|
|
565
|
+
b = a.pinv # pseudo inverse
|
|
566
|
+
expect(a.dot(b.dot(a))).to be_within(err).of(a)
|
|
567
|
+
expect(b.dot(a.dot(b))).to be_within(err).of(b)
|
|
568
|
+
rescue NotImplementedError
|
|
569
|
+
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
570
|
+
end
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
ALL_DTYPES.each do |dtype|
|
|
578
|
+
next if dtype == :byte #doesn't work for unsigned types
|
|
579
|
+
|
|
580
|
+
context dtype do
|
|
581
|
+
err = case dtype
|
|
582
|
+
when :float32, :complex64
|
|
583
|
+
1e-4
|
|
584
|
+
else #integer matrices will return :float64
|
|
585
|
+
1e-13
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
it "should correctly find adjugate a matrix in place (bang)" do
|
|
589
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
590
|
+
a = NMatrix.new(:dense, 2, [2, 3, 3, 5], dtype)
|
|
591
|
+
b = NMatrix.new(:dense, 2, [5, -3, -3, 2], dtype)
|
|
592
|
+
|
|
593
|
+
if a.integer_dtype?
|
|
594
|
+
expect{a.adjugate!}.to raise_error(DataTypeError)
|
|
595
|
+
else
|
|
596
|
+
#should return adjugate as well as modifying a
|
|
597
|
+
r = a.adjugate!
|
|
598
|
+
expect(a).to be_within(err).of(b)
|
|
599
|
+
expect(r).to be_within(err).of(b)
|
|
600
|
+
end
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
it "should correctly find adjugate of a matrix out-of-place" do
|
|
605
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
606
|
+
a = NMatrix.new(:dense, 3, [-3, 2, -5, -1, 0, -2, 3, -4, 1], dtype)
|
|
607
|
+
|
|
608
|
+
if a.integer_dtype?
|
|
609
|
+
b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], :float64)
|
|
610
|
+
else
|
|
611
|
+
b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], dtype)
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
expect(a.adjoint).to be_within(err).of(b)
|
|
615
|
+
expect(a.adjugate).to be_within(err).of(b)
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
# TODO: Get it working with ROBJ too
|
|
623
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype|
|
|
624
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype|
|
|
625
|
+
|
|
626
|
+
# Won't work if they're both 1-byte, due to overflow.
|
|
627
|
+
next if [:byte,:int8].include?(left_dtype) && [:byte,:int8].include?(right_dtype)
|
|
628
|
+
|
|
629
|
+
# For now, don't bother testing int-int mult.
|
|
630
|
+
#next if [:int8,:int16,:int32,:int64].include?(left_dtype) && [:int8,:int16,:int32,:int64].include?(right_dtype)
|
|
631
|
+
it "dense handles #{left_dtype.to_s} dot #{right_dtype.to_s} matrix multiplication" do
|
|
632
|
+
#STDERR.puts "dtype=#{dtype.to_s}"
|
|
633
|
+
#STDERR.puts "2"
|
|
634
|
+
|
|
635
|
+
nary = if left_dtype.to_s =~ /complex/
|
|
636
|
+
COMPLEX_MATRIX43A_ARRAY
|
|
637
|
+
else
|
|
638
|
+
MATRIX43A_ARRAY
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
mary = if right_dtype.to_s =~ /complex/
|
|
642
|
+
COMPLEX_MATRIX32A_ARRAY
|
|
643
|
+
else
|
|
644
|
+
MATRIX32A_ARRAY
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
n = NMatrix.new([4,3], nary, dtype: left_dtype, stype: :dense)
|
|
648
|
+
m = NMatrix.new([3,2], mary, dtype: right_dtype, stype: :dense)
|
|
649
|
+
|
|
650
|
+
expect(m.shape[0]).to eq(3)
|
|
651
|
+
expect(m.shape[1]).to eq(2)
|
|
652
|
+
expect(m.dim).to eq(2)
|
|
653
|
+
|
|
654
|
+
expect(n.shape[0]).to eq(4)
|
|
655
|
+
expect(n.shape[1]).to eq(3)
|
|
656
|
+
expect(n.dim).to eq(2)
|
|
657
|
+
|
|
658
|
+
expect(n.shape[1]).to eq(m.shape[0])
|
|
659
|
+
|
|
660
|
+
r = n.dot m
|
|
661
|
+
|
|
662
|
+
expect(r[0,0]).to eq(273.0)
|
|
663
|
+
expect(r[0,1]).to eq(455.0)
|
|
664
|
+
expect(r[1,0]).to eq(243.0)
|
|
665
|
+
expect(r[1,1]).to eq(235.0)
|
|
666
|
+
expect(r[2,0]).to eq(244.0)
|
|
667
|
+
expect(r[2,1]).to eq(205.0)
|
|
668
|
+
expect(r[3,0]).to eq(102.0)
|
|
669
|
+
expect(r[3,1]).to eq(160.0)
|
|
670
|
+
|
|
671
|
+
#r.dtype.should == :float64 unless left_dtype == :float32 && right_dtype == :float32
|
|
672
|
+
end
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype|
|
|
677
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype|
|
|
678
|
+
|
|
679
|
+
# Won't work if they're both 1-byte, due to overflow.
|
|
680
|
+
next if [:byte,:int8].include?(left_dtype) && [:byte,:int8].include?(right_dtype)
|
|
681
|
+
|
|
682
|
+
it "dense handles #{left_dtype.to_s} dot #{right_dtype.to_s} vector multiplication" do
|
|
683
|
+
#STDERR.puts "dtype=#{dtype.to_s}"
|
|
684
|
+
#STDERR.puts "2"
|
|
685
|
+
n = NMatrix.new([4,3], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0], dtype: left_dtype)
|
|
686
|
+
|
|
687
|
+
m = NMatrix.new([3,1], [2.0, 1.0, 0.0], dtype: right_dtype)
|
|
688
|
+
|
|
689
|
+
expect(m.shape[0]).to eq(3)
|
|
690
|
+
expect(m.shape[1]).to eq(1)
|
|
691
|
+
|
|
692
|
+
expect(n.shape[0]).to eq(4)
|
|
693
|
+
expect(n.shape[1]).to eq(3)
|
|
694
|
+
expect(n.dim).to eq(2)
|
|
695
|
+
|
|
696
|
+
expect(n.shape[1]).to eq(m.shape[0])
|
|
697
|
+
|
|
698
|
+
r = n.dot m
|
|
699
|
+
# r.class.should == NVector
|
|
700
|
+
|
|
701
|
+
expect(r[0,0]).to eq(4)
|
|
702
|
+
expect(r[1,0]).to eq(13)
|
|
703
|
+
expect(r[2,0]).to eq(22)
|
|
704
|
+
expect(r[3,0]).to eq(31)
|
|
705
|
+
|
|
706
|
+
#r.dtype.should == :float64 unless left_dtype == :float32 && right_dtype == :float32
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
ALL_DTYPES.each do |dtype|
|
|
712
|
+
next if integer_dtype?(dtype)
|
|
713
|
+
context "#cov dtype #{dtype}" do
|
|
714
|
+
before do
|
|
715
|
+
@n = NMatrix.new( [5,3], [4.0,2.0,0.60,
|
|
716
|
+
4.2,2.1,0.59,
|
|
717
|
+
3.9,2.0,0.58,
|
|
718
|
+
4.3,2.1,0.62,
|
|
719
|
+
4.1,2.2,0.63], dtype: dtype)
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
it "calculates sample covariance matrix" do
|
|
723
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
724
|
+
expect(@n.cov).to be_within(0.0001).of(NMatrix.new([3,3],
|
|
725
|
+
[0.025 , 0.0075, 0.00175,
|
|
726
|
+
0.0075, 0.007 , 0.00135,
|
|
727
|
+
0.00175, 0.00135 , 0.00043 ], dtype: dtype)
|
|
728
|
+
)
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
it "calculates population covariance matrix" do
|
|
732
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
733
|
+
expect(@n.cov(for_sample_data: false)).to be_within(0.0001).of(NMatrix.new([3,3],
|
|
734
|
+
[2.0000e-02, 6.0000e-03, 1.4000e-03,
|
|
735
|
+
6.0000e-03, 5.6000e-03, 1.0800e-03,
|
|
736
|
+
1.4000e-03, 1.0800e-03, 3.4400e-04], dtype: dtype)
|
|
737
|
+
)
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
context "#corr #{dtype}" do
|
|
742
|
+
it "calculates the correlation matrix" do
|
|
743
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
744
|
+
n = NMatrix.new([5,3], [4.0,2.0,0.60,
|
|
745
|
+
4.2,2.1,0.59,
|
|
746
|
+
3.9,2.0,0.58,
|
|
747
|
+
4.3,2.1,0.62,
|
|
748
|
+
4.1,2.2,0.63], dtype: dtype)
|
|
749
|
+
expect(n.corr).to be_within(0.001).of(NMatrix.new([3,3],
|
|
750
|
+
[1.00000, 0.56695, 0.53374,
|
|
751
|
+
0.56695, 1.00000, 0.77813,
|
|
752
|
+
0.53374, 0.77813, 1.00000], dtype: dtype))
|
|
753
|
+
end unless dtype =~ /complex/
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
context "#symmetric? for #{dtype}" do
|
|
757
|
+
it "should return true for symmetric matrix" do
|
|
758
|
+
n = NMatrix.new([3,3], [1.00000, 0.56695, 0.53374,
|
|
759
|
+
0.56695, 1.00000, 0.77813,
|
|
760
|
+
0.53374, 0.77813, 1.00000], dtype: dtype)
|
|
761
|
+
expect(n.symmetric?).to be_truthy
|
|
762
|
+
end
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
context "#hermitian? for #{dtype}" do
|
|
766
|
+
it "should return true for complex hermitian or non-complex symmetric matrix" do
|
|
767
|
+
n = NMatrix.new([3,3], [1.00000, 0.56695, 0.53374,
|
|
768
|
+
0.56695, 1.00000, 0.77813,
|
|
769
|
+
0.53374, 0.77813, 1.00000], dtype: dtype) unless dtype =~ /complex/
|
|
770
|
+
n = NMatrix.new([3,3], [1.1, Complex(1.2,1.3), Complex(1.4,1.5),
|
|
771
|
+
Complex(1.2,-1.3), 1.9, Complex(1.8,1.7),
|
|
772
|
+
Complex(1.4,-1.5), Complex(1.8,-1.7), 1.3], dtype: dtype) if dtype =~ /complex/
|
|
773
|
+
expect(n.hermitian?).to be_truthy
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
context "#permute_columns for #{dtype}" do
|
|
778
|
+
it "check that #permute_columns works correctly by considering every premutation of a 3x3 matrix" do
|
|
779
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
780
|
+
n = NMatrix.new([3,3], [1,0,0,
|
|
781
|
+
0,2,0,
|
|
782
|
+
0,0,3], dtype: dtype)
|
|
783
|
+
expect(n.permute_columns([0,1,2], {convention: :intuitive})).to eq(NMatrix.new([3,3], [1,0,0,
|
|
784
|
+
0,2,0,
|
|
785
|
+
0,0,3], dtype: dtype))
|
|
786
|
+
expect(n.permute_columns([0,2,1], {convention: :intuitive})).to eq(NMatrix.new([3,3], [1,0,0,
|
|
787
|
+
0,0,2,
|
|
788
|
+
0,3,0], dtype: dtype))
|
|
789
|
+
expect(n.permute_columns([1,0,2], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,1,0,
|
|
790
|
+
2,0,0,
|
|
791
|
+
0,0,3], dtype: dtype))
|
|
792
|
+
expect(n.permute_columns([1,2,0], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,0,1,
|
|
793
|
+
2,0,0,
|
|
794
|
+
0,3,0], dtype: dtype))
|
|
795
|
+
expect(n.permute_columns([2,0,1], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,1,0,
|
|
796
|
+
0,0,2,
|
|
797
|
+
3,0,0], dtype: dtype))
|
|
798
|
+
expect(n.permute_columns([2,1,0], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,0,1,
|
|
799
|
+
0,2,0,
|
|
800
|
+
3,0,0], dtype: dtype))
|
|
801
|
+
expect(n.permute_columns([0,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [1,0,0,
|
|
802
|
+
0,2,0,
|
|
803
|
+
0,0,3], dtype: dtype))
|
|
804
|
+
expect(n.permute_columns([0,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [1,0,0,
|
|
805
|
+
0,0,2,
|
|
806
|
+
0,3,0], dtype: dtype))
|
|
807
|
+
expect(n.permute_columns([1,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,1,0,
|
|
808
|
+
2,0,0,
|
|
809
|
+
0,0,3], dtype: dtype))
|
|
810
|
+
expect(n.permute_columns([1,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,0,1,
|
|
811
|
+
2,0,0,
|
|
812
|
+
0,3,0], dtype: dtype))
|
|
813
|
+
expect(n.permute_columns([2,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,1,0,
|
|
814
|
+
0,0,2,
|
|
815
|
+
3,0,0], dtype: dtype))
|
|
816
|
+
expect(n.permute_columns([2,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,0,1,
|
|
817
|
+
0,2,0,
|
|
818
|
+
3,0,0], dtype: dtype))
|
|
819
|
+
end
|
|
820
|
+
it "additional tests for #permute_columns with convention :intuitive" do
|
|
821
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
822
|
+
m = NMatrix.new([1,4], [0,1,2,3], dtype: dtype)
|
|
823
|
+
perm = [1,0,3,2]
|
|
824
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,4], perm, dtype: dtype))
|
|
825
|
+
|
|
826
|
+
m = NMatrix.new([1,5], [0,1,2,3,4], dtype: dtype)
|
|
827
|
+
perm = [1,0,4,3,2]
|
|
828
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,5], perm, dtype: dtype))
|
|
829
|
+
|
|
830
|
+
m = NMatrix.new([1,6], [0,1,2,3,4,5], dtype: dtype)
|
|
831
|
+
perm = [2,4,1,0,5,3]
|
|
832
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,6], perm, dtype: dtype))
|
|
833
|
+
|
|
834
|
+
m = NMatrix.new([1,7], [0,1,2,3,4,5,6], dtype: dtype)
|
|
835
|
+
perm = [1,3,5,6,0,2,4]
|
|
836
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,7], perm, dtype: dtype))
|
|
837
|
+
|
|
838
|
+
m = NMatrix.new([1,8], [0,1,2,3,4,5,6,7], dtype: dtype)
|
|
839
|
+
perm = [6,7,5,4,1,3,0,2]
|
|
840
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,8], perm, dtype: dtype))
|
|
841
|
+
end
|
|
842
|
+
end
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
context "#solve" do
|
|
846
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
|
847
|
+
|
|
848
|
+
it "solves linear equation for dtype #{dtype}" do
|
|
849
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
850
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
851
|
+
a = NMatrix.new [2,2], [3,1,1,2], dtype: dtype
|
|
852
|
+
b = NMatrix.new [2,1], [9,8], dtype: dtype
|
|
853
|
+
|
|
854
|
+
expect(a.solve(b)).to eq(NMatrix.new [2,1], [2,3], dtype: dtype)
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
it "solves linear equation for #{dtype} (non-symmetric matrix)" do
|
|
858
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
859
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
860
|
+
|
|
861
|
+
a = NMatrix.new [3,3], [1,1,1, -1,0,1, 3,4,6], dtype: dtype
|
|
862
|
+
b = NMatrix.new [3,1], [6,2,29], dtype: dtype
|
|
863
|
+
|
|
864
|
+
err = case dtype
|
|
865
|
+
when :float32, :complex64
|
|
866
|
+
1e-5
|
|
867
|
+
else
|
|
868
|
+
1e-14
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
expect(a.solve(b)).to be_within(err).of(NMatrix.new([3,1], [1,2,3], dtype: dtype))
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
it "solves linear equation for dtype #{dtype} (non-vector rhs)" do
|
|
875
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
876
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
877
|
+
|
|
878
|
+
a = NMatrix.new [3,3], [1,0,0, -1,0,1, 2,1,1], dtype: dtype
|
|
879
|
+
b = NMatrix.new [3,2], [1,0, 1,2, 4,2], dtype: dtype
|
|
880
|
+
|
|
881
|
+
expect(a.solve(b)).to eq(NMatrix.new [3,2], [1,0, 0,0, 2,2], dtype: dtype)
|
|
882
|
+
end
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
FLOAT_DTYPES.each do |dtype|
|
|
886
|
+
context "when form: :lower_tri" do
|
|
887
|
+
let(:a) { NMatrix.new([3,3], [1, 0, 0, 2, 0.5, 0, 3, 3, 9], dtype: dtype) }
|
|
888
|
+
|
|
889
|
+
it "solves a lower triangular linear system A * x = b with vector b" do
|
|
890
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
891
|
+
b = NMatrix.new([3,1], [1,2,3], dtype: dtype)
|
|
892
|
+
x = a.solve(b, form: :lower_tri)
|
|
893
|
+
r = a.dot(x) - b
|
|
894
|
+
expect(r.abs.max).to be_within(1e-6).of(0.0)
|
|
895
|
+
end
|
|
896
|
+
|
|
897
|
+
it "solves a lower triangular linear system A * X = B with narrow B" do
|
|
898
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
899
|
+
b = NMatrix.new([3,2], [1,2,3,4,5,6], dtype: dtype)
|
|
900
|
+
x = a.solve(b, form: :lower_tri)
|
|
901
|
+
r = (a.dot(x) - b).abs.to_flat_a
|
|
902
|
+
expect(r.max).to be_within(1e-6).of(0.0)
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
it "solves a lower triangular linear system A * X = B with wide B" do
|
|
906
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
907
|
+
b = NMatrix.new([3,5], (1..15).to_a, dtype: dtype)
|
|
908
|
+
x = a.solve(b, form: :lower_tri)
|
|
909
|
+
r = (a.dot(x) - b).abs.to_flat_a
|
|
910
|
+
expect(r.max).to be_within(1e-6).of(0.0)
|
|
911
|
+
end
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
context "when form: :upper_tri" do
|
|
915
|
+
let(:a) { NMatrix.new([3,3], [3, 2, 1, 0, 2, 0.5, 0, 0, 9], dtype: dtype) }
|
|
916
|
+
|
|
917
|
+
it "solves an upper triangular linear system A * x = b with vector b" do
|
|
918
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
919
|
+
b = NMatrix.new([3,1], [1,2,3], dtype: dtype)
|
|
920
|
+
x = a.solve(b, form: :upper_tri)
|
|
921
|
+
r = a.dot(x) - b
|
|
922
|
+
expect(r.abs.max).to be_within(1e-6).of(0.0)
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
it "solves an upper triangular linear system A * X = B with narrow B" do
|
|
926
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
927
|
+
b = NMatrix.new([3,2], [1,2,3,4,5,6], dtype: dtype)
|
|
928
|
+
x = a.solve(b, form: :upper_tri)
|
|
929
|
+
r = (a.dot(x) - b).abs.to_flat_a
|
|
930
|
+
expect(r.max).to be_within(1e-6).of(0.0)
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
it "solves an upper triangular linear system A * X = B with a wide B" do
|
|
934
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
935
|
+
b = NMatrix.new([3,5], (1..15).to_a, dtype: dtype)
|
|
936
|
+
x = a.solve(b, form: :upper_tri)
|
|
937
|
+
r = (a.dot(x) - b).abs.to_flat_a
|
|
938
|
+
expect(r.max).to be_within(1e-6).of(0.0)
|
|
939
|
+
end
|
|
940
|
+
end
|
|
941
|
+
|
|
942
|
+
context "when form: :pos_def" do
|
|
943
|
+
let(:a) { NMatrix.new([3,3], [4, 1, 2, 1, 5, 3, 2, 3, 6], dtype: dtype) }
|
|
944
|
+
|
|
945
|
+
it "solves a linear system A * X = b with positive definite A and vector b" do
|
|
946
|
+
b = NMatrix.new([3,1], [6,4,8], dtype: dtype)
|
|
947
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
948
|
+
begin
|
|
949
|
+
x = a.solve(b, form: :pos_def)
|
|
950
|
+
expect(x).to be_within(1e-6).of(NMatrix.new([3,1], [1,0,1], dtype: dtype))
|
|
951
|
+
rescue NotImplementedError
|
|
952
|
+
"Suppressing a NotImplementedError when the lapacke or atlas plugin is not available"
|
|
953
|
+
end
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
it "solves a linear system A * X = B with positive definite A and matrix B" do
|
|
957
|
+
b = NMatrix.new([3,2], [8,3,14,13,14,19], dtype: dtype)
|
|
958
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
959
|
+
begin
|
|
960
|
+
x = a.solve(b, form: :pos_def)
|
|
961
|
+
expect(x).to be_within(1e-6).of(NMatrix.new([3,2], [1,-1,2,1,1,3], dtype: dtype))
|
|
962
|
+
rescue NotImplementedError
|
|
963
|
+
"Suppressing a NotImplementedError when the lapacke or atlas plugin is not available"
|
|
964
|
+
end
|
|
965
|
+
end
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
context "#least_squares" do
|
|
971
|
+
it "finds the least squares approximation to the equation A * X = B" do
|
|
972
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
973
|
+
a = NMatrix.new([3,2], [2.0, 0, -1, 1, 0, 2])
|
|
974
|
+
b = NMatrix.new([3,1], [1.0, 0, -1])
|
|
975
|
+
solution = NMatrix.new([2,1], [1.0 / 3 , -1.0 / 3], dtype: :float64)
|
|
976
|
+
|
|
977
|
+
begin
|
|
978
|
+
least_squares = a.least_squares(b)
|
|
979
|
+
expect(least_squares).to be_within(0.0001).of solution
|
|
980
|
+
rescue NotImplementedError
|
|
981
|
+
"Suppressing a NotImplementedError when the lapacke or atlas plugin is not available"
|
|
982
|
+
end
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
it "finds the least squares approximation to the equation A * X = B with high tolerance" do
|
|
986
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
987
|
+
a = NMatrix.new([4,2], [1.0, 1, 1, 2, 1, 3,1,4])
|
|
988
|
+
b = NMatrix.new([4,1], [6.0, 5, 7, 10])
|
|
989
|
+
solution = NMatrix.new([2,1], [3.5 , 1.4], dtype: :float64)
|
|
990
|
+
|
|
991
|
+
begin
|
|
992
|
+
least_squares = a.least_squares(b, tolerance: 10e-5)
|
|
993
|
+
expect(least_squares).to be_within(0.0001).of solution
|
|
994
|
+
rescue NotImplementedError
|
|
995
|
+
"Suppressing a NotImplementedError when the lapacke or atlas plugin is not available"
|
|
996
|
+
end
|
|
997
|
+
end
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
context "#hessenberg" do
|
|
1001
|
+
FLOAT_DTYPES.each do |dtype|
|
|
1002
|
+
context dtype do
|
|
1003
|
+
before do
|
|
1004
|
+
@n = NMatrix.new [5,5],
|
|
1005
|
+
[0, 2, 0, 1, 1,
|
|
1006
|
+
2, 2, 3, 2, 2,
|
|
1007
|
+
4,-3, 0, 1, 3,
|
|
1008
|
+
6, 1,-6,-5, 4,
|
|
1009
|
+
5, 6, 4, 1, 5], dtype: dtype
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
it "transforms a matrix to Hessenberg form" do
|
|
1013
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1014
|
+
expect(@n.hessenberg).to be_within(0.0001).of(NMatrix.new([5,5],
|
|
1015
|
+
[0.00000,-1.66667, 0.79432,-0.45191,-1.54501,
|
|
1016
|
+
-9.00000, 2.95062,-6.89312, 3.22250,-0.19012,
|
|
1017
|
+
0.00000,-8.21682,-0.57379, 5.26966,-1.69976,
|
|
1018
|
+
0.00000, 0.00000,-3.74630,-0.80893, 3.99708,
|
|
1019
|
+
0.00000, 0.00000, 0.00000, 0.04102, 0.43211], dtype: dtype))
|
|
1020
|
+
end
|
|
1021
|
+
end
|
|
1022
|
+
end
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
ALL_DTYPES.each do |dtype|
|
|
1026
|
+
[:dense, :yale].each do |stype|
|
|
1027
|
+
answer_dtype = integer_dtype?(dtype) ? :int64 : dtype
|
|
1028
|
+
next if dtype == :byte
|
|
1029
|
+
|
|
1030
|
+
context "#pow #{dtype} #{stype}" do
|
|
1031
|
+
before do
|
|
1032
|
+
@n = NMatrix.new [4,4], [0, 2, 0, 1,
|
|
1033
|
+
2, 2, 3, 2,
|
|
1034
|
+
4,-3, 0, 1,
|
|
1035
|
+
6, 1,-6,-5], dtype: dtype, stype: stype
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
it "raises a square matrix to even power" do
|
|
1039
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
1040
|
+
expect(@n.pow(4)).to eq(NMatrix.new([4,4], [292, 28,-63, -42,
|
|
1041
|
+
360, 96, 51, -14,
|
|
1042
|
+
448,-231,-24,-87,
|
|
1043
|
+
-1168, 595,234, 523],
|
|
1044
|
+
dtype: answer_dtype,
|
|
1045
|
+
stype: stype))
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
it "raises a square matrix to odd power" do
|
|
1049
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
1050
|
+
expect(@n.pow(9)).to eq(NMatrix.new([4,4],[-275128, 279917, 176127, 237451,
|
|
1051
|
+
-260104, 394759, 166893, 296081,
|
|
1052
|
+
-704824, 285700, 186411, 262002,
|
|
1053
|
+
3209256,-1070870,-918741,-1318584],
|
|
1054
|
+
dtype: answer_dtype, stype: stype))
|
|
1055
|
+
end
|
|
1056
|
+
|
|
1057
|
+
it "raises a sqaure matrix to negative power" do
|
|
1058
|
+
expect(@n.pow(-3)).to be_within(0.00001).of (NMatrix.new([4,4],
|
|
1059
|
+
[1.0647e-02, 4.2239e-04,-6.2281e-05, 2.7680e-03,
|
|
1060
|
+
-1.6415e-02, 2.1296e-02, 1.0718e-02, 4.8589e-03,
|
|
1061
|
+
8.6956e-03,-8.6569e-03, 2.8993e-02, 7.2015e-03,
|
|
1062
|
+
5.0034e-02,-1.7500e-02,-3.6777e-02,-1.2128e-02], dtype: answer_dtype,
|
|
1063
|
+
stype: stype))
|
|
1064
|
+
end unless stype =~ /yale/ or dtype == :object or ALL_DTYPES.grep(/int/).include? dtype
|
|
1065
|
+
|
|
1066
|
+
it "raises a square matrix to zero" do
|
|
1067
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
1068
|
+
expect(@n.pow(0)).to eq(NMatrix.eye([4,4], dtype: answer_dtype,
|
|
1069
|
+
stype: stype))
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
it "raises a square matrix to one" do
|
|
1073
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
1074
|
+
expect(@n.pow(1)).to eq(@n)
|
|
1075
|
+
end
|
|
1076
|
+
end
|
|
1077
|
+
end
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
ALL_DTYPES.each do |dtype|
|
|
1081
|
+
[:dense, :yale].each do |stype|
|
|
1082
|
+
context "#kron_prod #{dtype} #{stype}" do
|
|
1083
|
+
before do
|
|
1084
|
+
@a = NMatrix.new([2,2], [1,2,
|
|
1085
|
+
3,4], dtype: dtype, stype: stype)
|
|
1086
|
+
@b = NMatrix.new([2,3], [1,1,1,
|
|
1087
|
+
1,1,1], dtype: dtype, stype: stype)
|
|
1088
|
+
@c = NMatrix.new([4,6], [1, 1, 1, 2, 2, 2,
|
|
1089
|
+
1, 1, 1, 2, 2, 2,
|
|
1090
|
+
3, 3, 3, 4, 4, 4,
|
|
1091
|
+
3, 3, 3, 4, 4, 4], dtype: dtype, stype: stype)
|
|
1092
|
+
end
|
|
1093
|
+
it "computes the Kronecker product of two NMatrix objects" do
|
|
1094
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
1095
|
+
expect(@a.kron_prod(@b)).to eq(@c)
|
|
1096
|
+
end
|
|
1097
|
+
end
|
|
1098
|
+
end
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
context "determinants" do
|
|
1102
|
+
ALL_DTYPES.each do |dtype|
|
|
1103
|
+
context dtype do
|
|
1104
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1105
|
+
before do
|
|
1106
|
+
@a = NMatrix.new([2,2], [1,2,
|
|
1107
|
+
3,4], dtype: dtype)
|
|
1108
|
+
@b = NMatrix.new([3,3], [1,2,3,
|
|
1109
|
+
5,0,1,
|
|
1110
|
+
4,1,3], dtype: dtype)
|
|
1111
|
+
@c = NMatrix.new([4,4], [1, 0, 1, 1,
|
|
1112
|
+
1, 2, 3, 1,
|
|
1113
|
+
3, 3, 3, 1,
|
|
1114
|
+
1, 2, 3, 4], dtype: dtype)
|
|
1115
|
+
@err = case dtype
|
|
1116
|
+
when :float32, :complex64
|
|
1117
|
+
1e-6
|
|
1118
|
+
when :float64, :complex128
|
|
1119
|
+
1e-14
|
|
1120
|
+
else
|
|
1121
|
+
1e-64 # FIXME: should be 0, but be_within(0) does not work.
|
|
1122
|
+
end
|
|
1123
|
+
end
|
|
1124
|
+
it "computes the determinant of 2x2 matrix" do
|
|
1125
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1126
|
+
expect(@a.det).to be_within(@err).of(-2)
|
|
1127
|
+
end
|
|
1128
|
+
it "computes the determinant of 3x3 matrix" do
|
|
1129
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1130
|
+
expect(@b.det).to be_within(@err).of(-8)
|
|
1131
|
+
end
|
|
1132
|
+
it "computes the determinant of 4x4 matrix" do
|
|
1133
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1134
|
+
expect(@c.det).to be_within(@err).of(-18)
|
|
1135
|
+
end
|
|
1136
|
+
it "computes the exact determinant of 2x2 matrix" do
|
|
1137
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1138
|
+
if dtype == :byte
|
|
1139
|
+
expect{@a.det_exact}.to raise_error(DataTypeError)
|
|
1140
|
+
else
|
|
1141
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
1142
|
+
expect(@a.det_exact).to be_within(@err).of(-2)
|
|
1143
|
+
end
|
|
1144
|
+
end
|
|
1145
|
+
it "computes the exact determinant of 3x3 matrix" do
|
|
1146
|
+
pending("not yet implemented for :object dtype") if dtype == :objectx
|
|
1147
|
+
if dtype == :byte
|
|
1148
|
+
expect{@a.det_exact}.to raise_error(DataTypeError)
|
|
1149
|
+
else
|
|
1150
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object
|
|
1151
|
+
expect(@b.det_exact).to be_within(@err).of(-8)
|
|
1152
|
+
end
|
|
1153
|
+
end
|
|
1154
|
+
end
|
|
1155
|
+
end
|
|
1156
|
+
end
|
|
1157
|
+
|
|
1158
|
+
context "#scale and #scale!" do
|
|
1159
|
+
[:dense,:list,:yale].each do |stype|
|
|
1160
|
+
ALL_DTYPES.each do |dtype|
|
|
1161
|
+
context "for #{dtype}" do
|
|
1162
|
+
before do
|
|
1163
|
+
@m = NMatrix.new([3, 3], [0, 1, 2,
|
|
1164
|
+
3, 4, 5,
|
|
1165
|
+
6, 7, 8], stype: stype, dtype: dtype)
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
it "scales the matrix by a given factor and return the result" do
|
|
1169
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1170
|
+
if integer_dtype? dtype
|
|
1171
|
+
expect{@m.scale 2.0}.to raise_error(DataTypeError)
|
|
1172
|
+
else
|
|
1173
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and (dtype == :complex64 || dtype == :complex128)
|
|
1174
|
+
expect(@m.scale 2.0).to eq(NMatrix.new([3, 3], [0, 2, 4,
|
|
1175
|
+
6, 8, 10,
|
|
1176
|
+
12, 14, 16], stype: stype, dtype: dtype))
|
|
1177
|
+
end
|
|
1178
|
+
end
|
|
1179
|
+
|
|
1180
|
+
it "scales the matrix in place by a given factor" do
|
|
1181
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1182
|
+
if dtype == :int8
|
|
1183
|
+
expect{@m.scale! 2}.to raise_error(DataTypeError)
|
|
1184
|
+
else
|
|
1185
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby? and (dtype == :complex64 || dtype == :complex128)
|
|
1186
|
+
@m.scale! 2
|
|
1187
|
+
expect(@m).to eq(NMatrix.new([3, 3], [0, 2, 4,
|
|
1188
|
+
6, 8, 10,
|
|
1189
|
+
12, 14, 16], stype: stype, dtype: dtype))
|
|
1190
|
+
end
|
|
1191
|
+
end
|
|
1192
|
+
end
|
|
1193
|
+
end
|
|
1194
|
+
end
|
|
1195
|
+
end
|
|
1196
|
+
context "matrix_norm" do
|
|
1197
|
+
ALL_DTYPES.each do |dtype|
|
|
1198
|
+
context dtype do
|
|
1199
|
+
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1200
|
+
before do
|
|
1201
|
+
@n = NMatrix.new([3,3], [-4,-3,-2,
|
|
1202
|
+
-1, 0, 1,
|
|
1203
|
+
2, 3, 4], dtype: dtype)
|
|
1204
|
+
|
|
1205
|
+
@matrix_norm_TOLERANCE = 1.0e-10
|
|
1206
|
+
end
|
|
1207
|
+
|
|
1208
|
+
it "should default to 2-matrix_norm" do
|
|
1209
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1210
|
+
if(dtype == :byte)
|
|
1211
|
+
expect{@n.matrix_norm}.to raise_error(ArgumentError)
|
|
1212
|
+
else
|
|
1213
|
+
begin
|
|
1214
|
+
expect(@n.matrix_norm).to be_within(@matrix_norm_TOLERANCE).of(7.348469228349535)
|
|
1215
|
+
|
|
1216
|
+
rescue NotImplementedError
|
|
1217
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1218
|
+
end
|
|
1219
|
+
end
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
it "should reject invalid arguments" do
|
|
1223
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1224
|
+
|
|
1225
|
+
expect{@n.matrix_norm(0.5)}.to raise_error(ArgumentError)
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1228
|
+
it "should calculate 1 and 2(minus) matrix_norms correctly" do
|
|
1229
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1230
|
+
if(dtype == :byte)
|
|
1231
|
+
expect{@n.matrix_norm(1)}.to raise_error(ArgumentError)
|
|
1232
|
+
expect{@n.matrix_norm(-2)}.to raise_error(ArgumentError)
|
|
1233
|
+
expect{@n.matrix_norm(-1)}.to raise_error(ArgumentError)
|
|
1234
|
+
else
|
|
1235
|
+
expect(@n.matrix_norm(1)).to eq(7)
|
|
1236
|
+
begin
|
|
1237
|
+
|
|
1238
|
+
#FIXME: change to the correct value when overflow issue is resolved
|
|
1239
|
+
#expect(@n.matrix_norm(-2)).to eq(1.8628605857884395e-07)
|
|
1240
|
+
expect(@n.matrix_norm(-2)).to be_within(@matrix_norm_TOLERANCE).of(0.0)
|
|
1241
|
+
rescue NotImplementedError
|
|
1242
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1243
|
+
end
|
|
1244
|
+
expect(@n.matrix_norm(-1)).to eq(6)
|
|
1245
|
+
end
|
|
1246
|
+
end
|
|
1247
|
+
|
|
1248
|
+
it "should calculate infinity matrix_norms correctly" do
|
|
1249
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1250
|
+
if(dtype == :byte)
|
|
1251
|
+
expect{@n.matrix_norm(:inf)}.to raise_error(ArgumentError)
|
|
1252
|
+
expect{@n.matrix_norm(:'-inf')}.to raise_error(ArgumentError)
|
|
1253
|
+
else
|
|
1254
|
+
expect(@n.matrix_norm(:inf)).to eq(9)
|
|
1255
|
+
expect(@n.matrix_norm(:'-inf')).to eq(2)
|
|
1256
|
+
end
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1259
|
+
it "should calculate frobenius matrix_norms correctly" do
|
|
1260
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1261
|
+
if(dtype == :byte)
|
|
1262
|
+
expect{@n.matrix_norm(:fro)}.to raise_error(ArgumentError)
|
|
1263
|
+
else
|
|
1264
|
+
expect(@n.matrix_norm(:fro)).to be_within(@matrix_norm_TOLERANCE).of(7.745966692414834)
|
|
1265
|
+
end
|
|
1266
|
+
end
|
|
1267
|
+
end
|
|
1268
|
+
end
|
|
1269
|
+
end
|
|
1270
|
+
|
|
1271
|
+
context "#positive_definite?" do
|
|
1272
|
+
it "should return true for positive_definite? matrix" do
|
|
1273
|
+
n = NMatrix.new([3,3], [2, -1, -1,
|
|
1274
|
+
-1, 2, -1,
|
|
1275
|
+
-1, -1, 3])
|
|
1276
|
+
expect(n.positive_definite?).to be_truthy
|
|
1277
|
+
end
|
|
1278
|
+
end
|
|
1279
|
+
|
|
1280
|
+
context "#svd_rank" do
|
|
1281
|
+
FLOAT_DTYPES.each do |dtype|
|
|
1282
|
+
context dtype do
|
|
1283
|
+
#examples from https://www.cliffsnotes.com/study-guides/algebra/linear-algebra/real-euclidean-vector-spaces/the-rank-of-a-matrix
|
|
1284
|
+
it "calculates the rank of matrix using singular value decomposition with NMatrix on rectangular matrix without tolerence" do
|
|
1285
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1286
|
+
a = NMatrix.new([4,3],[2,-1,3, 1,0,1, 0,2,-1, 1,1,4], dtype: dtype)
|
|
1287
|
+
|
|
1288
|
+
begin
|
|
1289
|
+
rank = a.svd_rank()
|
|
1290
|
+
|
|
1291
|
+
rank_true = 3
|
|
1292
|
+
expect(rank).to eq (rank_true)
|
|
1293
|
+
|
|
1294
|
+
rescue NotImplementedError
|
|
1295
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1296
|
+
end
|
|
1297
|
+
end
|
|
1298
|
+
|
|
1299
|
+
it "calculates the rank of matrix using singular value decomposition with NMatrix on rectangular matrix with tolerence" do
|
|
1300
|
+
|
|
1301
|
+
a = NMatrix.new([4,3],[2,-1,3, 1,0,1, 0,2,-1, 1,1,4], dtype: dtype)
|
|
1302
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1303
|
+
begin
|
|
1304
|
+
rank = a.svd_rank(4)
|
|
1305
|
+
|
|
1306
|
+
rank_true = 1
|
|
1307
|
+
expect(rank).to eq (rank_true)
|
|
1308
|
+
|
|
1309
|
+
rescue NotImplementedError
|
|
1310
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1311
|
+
end
|
|
1312
|
+
end
|
|
1313
|
+
|
|
1314
|
+
it "calculates the rank of matrix using singular value decomposition with NMatrix on square matrix without tolerence" do
|
|
1315
|
+
|
|
1316
|
+
a = NMatrix.new([4,4],[1,-1,1,-1, -1,1,-1,1, 1,-1,1,-1, -1,1,-1,1], dtype: dtype)
|
|
1317
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1318
|
+
begin
|
|
1319
|
+
rank = a.svd_rank()
|
|
1320
|
+
|
|
1321
|
+
rank_true = 1
|
|
1322
|
+
expect(rank).to eq (rank_true)
|
|
1323
|
+
|
|
1324
|
+
rescue NotImplementedError
|
|
1325
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1326
|
+
end
|
|
1327
|
+
end
|
|
1328
|
+
|
|
1329
|
+
it "calculates the rank of matrix using singular value decomposition with NMatrix on square matrix with very small tolerence(for float32)" do
|
|
1330
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1331
|
+
a = NMatrix.new([4,4],[1,-1,1,-1, -1,1,-1,1, 1,-1,1,-1, -1,1,-1,1], dtype: :float32)
|
|
1332
|
+
|
|
1333
|
+
begin
|
|
1334
|
+
rank = a.svd_rank(1.7881389169360773e-08)
|
|
1335
|
+
|
|
1336
|
+
rank_true = 2
|
|
1337
|
+
expect(rank).to eq (rank_true)
|
|
1338
|
+
|
|
1339
|
+
rescue NotImplementedError
|
|
1340
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1341
|
+
end
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1344
|
+
it "calculates the rank of matrix using singular value decomposition with NMatrix on square matrix with very small tolerence(for float64)" do
|
|
1345
|
+
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
1346
|
+
a = NMatrix.new([4,4],[1,-1,1,-1, -1,1,-1,1, 1,-1,1,-1, -1,1,-1,1], dtype: :float64)
|
|
1347
|
+
|
|
1348
|
+
begin
|
|
1349
|
+
rank = a.svd_rank(1.7881389169360773e-08)
|
|
1350
|
+
|
|
1351
|
+
rank_true = 1
|
|
1352
|
+
expect(rank).to eq (rank_true)
|
|
1353
|
+
|
|
1354
|
+
rescue NotImplementedError
|
|
1355
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1356
|
+
end
|
|
1357
|
+
end
|
|
1358
|
+
|
|
1359
|
+
end
|
|
1360
|
+
end
|
|
1361
|
+
end
|
|
1362
|
+
|
|
1363
|
+
end
|