nmatrix 0.1.0 → 0.2.0
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 +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/spec/math_spec.rb
CHANGED
@@ -28,16 +28,13 @@
|
|
28
28
|
|
29
29
|
require 'spec_helper'
|
30
30
|
|
31
|
-
ALL_DTYPES = [:byte,:int8,:int16,:int32,:int64, :float32,:float64, :object,
|
32
|
-
:rational32,:rational64,:rational128, :complex64, :complex128]
|
33
|
-
|
34
31
|
describe "math" do
|
35
32
|
context "elementwise math functions" do
|
36
33
|
|
37
34
|
[:dense,:list,:yale].each do |stype|
|
38
35
|
context stype do
|
39
36
|
|
40
|
-
[:int64,:float64
|
37
|
+
[:int64,:float64].each do |dtype|
|
41
38
|
context dtype do
|
42
39
|
before :each do
|
43
40
|
@size = [2,2]
|
@@ -146,7 +143,7 @@ describe "math" do
|
|
146
143
|
expect(@m.send(meth).integer_dtype?).to eq true
|
147
144
|
end
|
148
145
|
end
|
149
|
-
elsif dtype.to_s.match(/float/)
|
146
|
+
elsif dtype.to_s.match(/float/)
|
150
147
|
it "should return dtype int64 for #{dtype}" do
|
151
148
|
|
152
149
|
expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| e.send(meth) }, dtype: dtype, stype: stype)
|
@@ -177,13 +174,23 @@ describe "math" do
|
|
177
174
|
@ans = @mat.to_a.flatten
|
178
175
|
end
|
179
176
|
|
180
|
-
it "rounds
|
177
|
+
it "rounds" do
|
181
178
|
expect(@mat.round).to eq(N.new(@size, @ans.map { |a| a.round},
|
182
179
|
dtype: dtype, stype: stype))
|
183
180
|
end unless(/complex/ =~ dtype)
|
184
181
|
|
185
|
-
it "rounds
|
186
|
-
|
182
|
+
it "rounds with args" do
|
183
|
+
expect(@mat.round(2)).to eq(N.new(@size, @ans.map { |a| a.round(2)},
|
184
|
+
dtype: dtype, stype: stype))
|
185
|
+
end unless(/complex/ =~ dtype)
|
186
|
+
|
187
|
+
it "rounds complex with args" do
|
188
|
+
puts @mat.round(2)
|
189
|
+
expect(@mat.round(2)).to be_within(0.0001).of(N.new [2,2], @ans.map {|a|
|
190
|
+
Complex(a.real.round(2), a.imag.round(2))},dtype: dtype, stype: stype)
|
191
|
+
end if(/complex/ =~ dtype)
|
192
|
+
|
193
|
+
it "rounds complex" do
|
187
194
|
expect(@mat.round).to eq(N.new [2,2], @ans.map {|a|
|
188
195
|
Complex(a.real.round, a.imag.round)},dtype: dtype, stype: stype)
|
189
196
|
end if(/complex/ =~ dtype)
|
@@ -195,65 +202,139 @@ describe "math" do
|
|
195
202
|
end
|
196
203
|
end
|
197
204
|
|
198
|
-
|
205
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
206
|
+
next if dtype == :object
|
199
207
|
context dtype do
|
208
|
+
before do
|
209
|
+
@m = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype)
|
210
|
+
@err = case dtype
|
211
|
+
when :float32, :complex64
|
212
|
+
1e-6
|
213
|
+
when :float64, :complex128
|
214
|
+
1e-14
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
#haven't check this spec yet. Also it doesn't check all the elements of the matrix.
|
200
219
|
it "should correctly factorize a matrix" do
|
201
|
-
|
202
|
-
a
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
expect(a
|
209
|
-
|
220
|
+
a = @m.factorize_lu
|
221
|
+
expect(a).to be_within(@err).of(NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype))
|
222
|
+
end
|
223
|
+
|
224
|
+
it "also returns the permutation matrix" do
|
225
|
+
a, p = @m.factorize_lu perm_matrix: true
|
226
|
+
|
227
|
+
expect(a).to be_within(@err).of(NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype))
|
228
|
+
|
229
|
+
p_true = NMatrix.new([3,3], [0,0,1,1,0,0,0,1,0], dtype: dtype)
|
230
|
+
expect(p).to eq(p_true)
|
210
231
|
end
|
211
232
|
end
|
233
|
+
end
|
212
234
|
|
235
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
236
|
+
next if dtype == :object
|
213
237
|
context dtype do
|
214
|
-
|
215
|
-
|
216
|
-
|
238
|
+
|
239
|
+
it "calculates cholesky decomposition using potrf (lower)" do
|
240
|
+
#a = NMatrix.new([3,3],[1,1,1, 1,2,2, 1,2,6], dtype: dtype)
|
241
|
+
# We use the matrix
|
242
|
+
# 1 1 1
|
243
|
+
# 1 2 2
|
244
|
+
# 1 2 6
|
245
|
+
# which is symmetric and positive-definite as required, but
|
246
|
+
# we need only store the lower-half of the matrix.
|
247
|
+
a = NMatrix.new([3,3],[1,0,0, 1,2,0, 1,2,6], dtype: dtype)
|
217
248
|
begin
|
218
|
-
a.
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
249
|
+
r = a.potrf!(:lower)
|
250
|
+
|
251
|
+
b = NMatrix.new([3,3],[1,0,0, 1,1,0, 1,1,2], dtype: dtype)
|
252
|
+
expect(a).to eq(b)
|
253
|
+
expect(r).to eq(b)
|
254
|
+
rescue NotImplementedError
|
255
|
+
pending "potrf! not implemented without plugins"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
it "calculates cholesky decomposition using potrf (upper)" do
|
260
|
+
a = NMatrix.new([3,3],[1,1,1, 0,2,2, 0,0,6], dtype: dtype)
|
261
|
+
begin
|
262
|
+
r = a.potrf!(:upper)
|
263
|
+
|
264
|
+
b = NMatrix.new([3,3],[1,1,1, 0,1,1, 0,0,2], dtype: dtype)
|
265
|
+
expect(a).to eq(b)
|
266
|
+
expect(r).to eq(b)
|
267
|
+
rescue NotImplementedError
|
268
|
+
pending "potrf! not implemented without plugins"
|
225
269
|
end
|
226
|
-
expect(a.round).to eq(b)
|
227
270
|
end
|
228
271
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
272
|
+
it "calculates cholesky decomposition using #factorize_cholesky" do
|
273
|
+
a = NMatrix.new([3,3],[1,2,1, 2,13,5, 1,5,6], dtype: dtype)
|
274
|
+
begin
|
275
|
+
u,l = a.factorize_cholesky
|
276
|
+
|
277
|
+
l_true = NMatrix.new([3,3],[1,0,0, 2,3,0, 1,1,2], dtype: dtype)
|
278
|
+
u_true = l_true.transpose
|
279
|
+
expect(u).to eq(u_true)
|
280
|
+
expect(l).to eq(l_true)
|
281
|
+
rescue NotImplementedError
|
282
|
+
pending "potrf! not implemented without plugins"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
ALL_DTYPES.each do |dtype|
|
289
|
+
next if dtype == :byte #doesn't work for unsigned types
|
290
|
+
next if dtype == :object
|
291
|
+
|
292
|
+
context dtype do
|
293
|
+
err = case dtype
|
294
|
+
when :float32, :complex64
|
295
|
+
1e-4
|
296
|
+
else #integer matrices will return :float64
|
297
|
+
1e-13
|
298
|
+
end
|
299
|
+
|
300
|
+
it "should correctly invert a matrix in place (bang)" do
|
301
|
+
a = NMatrix.new(:dense, 5, [1, 8,-9, 7, 5,
|
302
|
+
0, 1, 0, 4, 4,
|
303
|
+
0, 0, 1, 2, 5,
|
304
|
+
0, 0, 0, 1,-5,
|
305
|
+
0, 0, 0, 0, 1 ], dtype)
|
306
|
+
b = NMatrix.new(:dense, 5, [1,-8, 9, 7, 17,
|
307
|
+
0, 1, 0,-4,-24,
|
308
|
+
0, 0, 1,-2,-15,
|
309
|
+
0, 0, 0, 1, 5,
|
310
|
+
0, 0, 0, 0, 1,], dtype)
|
311
|
+
if a.integer_dtype?
|
312
|
+
expect{a.invert!}.to raise_error(DataTypeError)
|
313
|
+
else
|
314
|
+
#should return inverse as well as modifying a
|
315
|
+
r = a.invert!
|
316
|
+
expect(a).to be_within(err).of(b)
|
317
|
+
expect(r).to be_within(err).of(b)
|
242
318
|
end
|
243
319
|
end
|
244
320
|
|
245
321
|
it "should correctly invert a matrix out-of-place" do
|
246
322
|
a = NMatrix.new(:dense, 3, [1,2,3,0,1,4,5,6,0], dtype)
|
247
|
-
b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], dtype)
|
248
323
|
|
249
|
-
|
324
|
+
if a.integer_dtype?
|
325
|
+
b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], :float64)
|
326
|
+
else
|
327
|
+
b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], dtype)
|
328
|
+
end
|
329
|
+
|
330
|
+
expect(a.invert).to be_within(err).of(b)
|
250
331
|
end
|
251
332
|
end
|
252
333
|
end
|
253
334
|
|
254
335
|
# TODO: Get it working with ROBJ too
|
255
|
-
[:byte,:int8,:int16,:int32,:int64,:float32,:float64
|
256
|
-
[:byte,:int8,:int16,:int32,:int64,:float32,:float64
|
336
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype|
|
337
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype|
|
257
338
|
|
258
339
|
# Won't work if they're both 1-byte, due to overflow.
|
259
340
|
next if [:byte,:int8].include?(left_dtype) && [:byte,:int8].include?(right_dtype)
|
@@ -266,16 +347,12 @@ describe "math" do
|
|
266
347
|
|
267
348
|
nary = if left_dtype.to_s =~ /complex/
|
268
349
|
COMPLEX_MATRIX43A_ARRAY
|
269
|
-
elsif left_dtype.to_s =~ /rational/
|
270
|
-
RATIONAL_MATRIX43A_ARRAY
|
271
350
|
else
|
272
351
|
MATRIX43A_ARRAY
|
273
352
|
end
|
274
353
|
|
275
354
|
mary = if right_dtype.to_s =~ /complex/
|
276
355
|
COMPLEX_MATRIX32A_ARRAY
|
277
|
-
elsif right_dtype.to_s =~ /rational/
|
278
|
-
RATIONAL_MATRIX32A_ARRAY
|
279
356
|
else
|
280
357
|
MATRIX32A_ARRAY
|
281
358
|
end
|
@@ -309,8 +386,8 @@ describe "math" do
|
|
309
386
|
end
|
310
387
|
end
|
311
388
|
|
312
|
-
[:byte,:int8,:int16,:int32,:int64,:float32,:float64
|
313
|
-
[:byte,:int8,:int16,:int32,:int64,:float32,:float64
|
389
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype|
|
390
|
+
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype|
|
314
391
|
|
315
392
|
# Won't work if they're both 1-byte, due to overflow.
|
316
393
|
next if [:byte,:int8].include?(left_dtype) && [:byte,:int8].include?(right_dtype)
|
@@ -343,4 +420,311 @@ describe "math" do
|
|
343
420
|
end
|
344
421
|
end
|
345
422
|
end
|
423
|
+
|
424
|
+
ALL_DTYPES.each do |dtype|
|
425
|
+
next if integer_dtype?(dtype)
|
426
|
+
context "#cov dtype #{dtype}" do
|
427
|
+
before do
|
428
|
+
@n = NMatrix.new( [5,3], [4.0,2.0,0.60,
|
429
|
+
4.2,2.1,0.59,
|
430
|
+
3.9,2.0,0.58,
|
431
|
+
4.3,2.1,0.62,
|
432
|
+
4.1,2.2,0.63], dtype: dtype)
|
433
|
+
end
|
434
|
+
|
435
|
+
it "calculates variance co-variance matrix (sample)" do
|
436
|
+
expect(@n.cov).to be_within(0.0001).of(NMatrix.new([3,3],
|
437
|
+
[0.025 , 0.0075, 0.00175,
|
438
|
+
0.0075, 0.007 , 0.00135,
|
439
|
+
0.00175, 0.00135 , 0.00043 ], dtype: dtype)
|
440
|
+
)
|
441
|
+
end
|
442
|
+
|
443
|
+
it "calculates variance co-variance matrix (population)" do
|
444
|
+
expect(@n.cov(for_sample_data: false)).to be_within(0.0001).of(NMatrix.new([3,3],
|
445
|
+
[2.0000e-02, 6.0000e-03, 1.4000e-03,
|
446
|
+
6.0000e-03, 5.6000e-03, 1.0800e-03,
|
447
|
+
1.4000e-03, 1.0800e-03, 3.4400e-04], dtype: dtype)
|
448
|
+
)
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
context "#corr #{dtype}" do
|
453
|
+
it "calculates the correlation matrix" do
|
454
|
+
n = NMatrix.new([5,3], [4.0,2.0,0.60,
|
455
|
+
4.2,2.1,0.59,
|
456
|
+
3.9,2.0,0.58,
|
457
|
+
4.3,2.1,0.62,
|
458
|
+
4.1,2.2,0.63], dtype: dtype)
|
459
|
+
expect(n.corr).to be_within(0.001).of(NMatrix.new([3,3],
|
460
|
+
[1.00000, 0.56695, 0.53374,
|
461
|
+
0.56695, 1.00000, 0.77813,
|
462
|
+
0.53374, 0.77813, 1.00000], dtype: dtype))
|
463
|
+
end unless dtype =~ /complex/
|
464
|
+
end
|
465
|
+
|
466
|
+
context "#symmetric? for #{dtype}" do
|
467
|
+
it "should return true for symmetric matrix" do
|
468
|
+
n = NMatrix.new([3,3], [1.00000, 0.56695, 0.53374,
|
469
|
+
0.56695, 1.00000, 0.77813,
|
470
|
+
0.53374, 0.77813, 1.00000], dtype: dtype)
|
471
|
+
expect(n.symmetric?).to be_truthy
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
context "#hermitian? for #{dtype}" do
|
476
|
+
it "should return true for complex hermitian or non-complex symmetric matrix" do
|
477
|
+
n = NMatrix.new([3,3], [1.00000, 0.56695, 0.53374,
|
478
|
+
0.56695, 1.00000, 0.77813,
|
479
|
+
0.53374, 0.77813, 1.00000], dtype: dtype) unless dtype =~ /complex/
|
480
|
+
n = NMatrix.new([3,3], [1.1, Complex(1.2,1.3), Complex(1.4,1.5),
|
481
|
+
Complex(1.2,-1.3), 1.9, Complex(1.8,1.7),
|
482
|
+
Complex(1.4,-1.5), Complex(1.8,-1.7), 1.3], dtype: dtype) if dtype =~ /complex/
|
483
|
+
expect(n.hermitian?).to be_truthy
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
context "#permute_columns for #{dtype}" do
|
488
|
+
it "check that #permute_columns works correctly by considering every premutation of a 3x3 matrix" do
|
489
|
+
n = NMatrix.new([3,3], [1,0,0,
|
490
|
+
0,2,0,
|
491
|
+
0,0,3], dtype: dtype)
|
492
|
+
expect(n.permute_columns([0,1,2], {convention: :intuitive})).to eq(NMatrix.new([3,3], [1,0,0,
|
493
|
+
0,2,0,
|
494
|
+
0,0,3], dtype: dtype))
|
495
|
+
expect(n.permute_columns([0,2,1], {convention: :intuitive})).to eq(NMatrix.new([3,3], [1,0,0,
|
496
|
+
0,0,2,
|
497
|
+
0,3,0], dtype: dtype))
|
498
|
+
expect(n.permute_columns([1,0,2], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,1,0,
|
499
|
+
2,0,0,
|
500
|
+
0,0,3], dtype: dtype))
|
501
|
+
expect(n.permute_columns([1,2,0], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,0,1,
|
502
|
+
2,0,0,
|
503
|
+
0,3,0], dtype: dtype))
|
504
|
+
expect(n.permute_columns([2,0,1], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,1,0,
|
505
|
+
0,0,2,
|
506
|
+
3,0,0], dtype: dtype))
|
507
|
+
expect(n.permute_columns([2,1,0], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,0,1,
|
508
|
+
0,2,0,
|
509
|
+
3,0,0], dtype: dtype))
|
510
|
+
expect(n.permute_columns([0,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [1,0,0,
|
511
|
+
0,2,0,
|
512
|
+
0,0,3], dtype: dtype))
|
513
|
+
expect(n.permute_columns([0,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [1,0,0,
|
514
|
+
0,0,2,
|
515
|
+
0,3,0], dtype: dtype))
|
516
|
+
expect(n.permute_columns([1,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,1,0,
|
517
|
+
2,0,0,
|
518
|
+
0,0,3], dtype: dtype))
|
519
|
+
expect(n.permute_columns([1,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,0,1,
|
520
|
+
2,0,0,
|
521
|
+
0,3,0], dtype: dtype))
|
522
|
+
expect(n.permute_columns([2,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,1,0,
|
523
|
+
0,0,2,
|
524
|
+
3,0,0], dtype: dtype))
|
525
|
+
expect(n.permute_columns([2,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,0,1,
|
526
|
+
0,2,0,
|
527
|
+
3,0,0], dtype: dtype))
|
528
|
+
end
|
529
|
+
it "additional tests for #permute_columns with convention :intuitive" do
|
530
|
+
m = NMatrix.new([1,4], [0,1,2,3], dtype: dtype)
|
531
|
+
perm = [1,0,3,2]
|
532
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,4], perm, dtype: dtype))
|
533
|
+
|
534
|
+
m = NMatrix.new([1,5], [0,1,2,3,4], dtype: dtype)
|
535
|
+
perm = [1,0,4,3,2]
|
536
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,5], perm, dtype: dtype))
|
537
|
+
|
538
|
+
m = NMatrix.new([1,6], [0,1,2,3,4,5], dtype: dtype)
|
539
|
+
perm = [2,4,1,0,5,3]
|
540
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,6], perm, dtype: dtype))
|
541
|
+
|
542
|
+
m = NMatrix.new([1,7], [0,1,2,3,4,5,6], dtype: dtype)
|
543
|
+
perm = [1,3,5,6,0,2,4]
|
544
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,7], perm, dtype: dtype))
|
545
|
+
|
546
|
+
m = NMatrix.new([1,8], [0,1,2,3,4,5,6,7], dtype: dtype)
|
547
|
+
perm = [6,7,5,4,1,3,0,2]
|
548
|
+
expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,8], perm, dtype: dtype))
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
context "#solve" do
|
554
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
555
|
+
next if dtype == :object # LU factorization doesnt work for :object yet
|
556
|
+
it "solves linear equation for dtype #{dtype}" do
|
557
|
+
a = NMatrix.new [2,2], [3,1,1,2], dtype: dtype
|
558
|
+
b = NMatrix.new [2,1], [9,8], dtype: dtype
|
559
|
+
|
560
|
+
expect(a.solve(b)).to eq(NMatrix.new [2,1], [2,3], dtype: dtype)
|
561
|
+
end
|
562
|
+
|
563
|
+
it "solves linear equation for #{dtype} (non-symmetric matrix)" do
|
564
|
+
a = NMatrix.new [3,3], [1,1,1, -1,0,1, 3,4,6], dtype: dtype
|
565
|
+
b = NMatrix.new [3,1], [6,2,29], dtype: dtype
|
566
|
+
|
567
|
+
err = case dtype
|
568
|
+
when :float32, :complex64
|
569
|
+
1e-5
|
570
|
+
else
|
571
|
+
1e-14
|
572
|
+
end
|
573
|
+
|
574
|
+
expect(a.solve(b)).to be_within(err).of(NMatrix.new([3,1], [1,2,3], dtype: dtype))
|
575
|
+
end
|
576
|
+
|
577
|
+
it "solves linear equation for dtype #{dtype} (non-vector rhs)" do
|
578
|
+
a = NMatrix.new [3,3], [1,0,0, -1,0,1, 2,1,1], dtype: dtype
|
579
|
+
b = NMatrix.new [3,2], [1,0, 1,2, 4,2], dtype: dtype
|
580
|
+
|
581
|
+
expect(a.solve(b)).to eq(NMatrix.new [3,2], [1,0, 0,0, 2,2], dtype: dtype)
|
582
|
+
end
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
context "#hessenberg" do
|
587
|
+
FLOAT_DTYPES.each do |dtype|
|
588
|
+
context dtype do
|
589
|
+
before do
|
590
|
+
@n = NMatrix.new [5,5],
|
591
|
+
[0, 2, 0, 1, 1,
|
592
|
+
2, 2, 3, 2, 2,
|
593
|
+
4,-3, 0, 1, 3,
|
594
|
+
6, 1,-6,-5, 4,
|
595
|
+
5, 6, 4, 1, 5], dtype: dtype
|
596
|
+
end
|
597
|
+
|
598
|
+
it "transforms a matrix to Hessenberg form" do
|
599
|
+
expect(@n.hessenberg).to be_within(0.0001).of(NMatrix.new([5,5],
|
600
|
+
[0.00000,-1.66667, 0.79432,-0.45191,-1.54501,
|
601
|
+
-9.00000, 2.95062,-6.89312, 3.22250,-0.19012,
|
602
|
+
0.00000,-8.21682,-0.57379, 5.26966,-1.69976,
|
603
|
+
0.00000, 0.00000,-3.74630,-0.80893, 3.99708,
|
604
|
+
0.00000, 0.00000, 0.00000, 0.04102, 0.43211], dtype: dtype))
|
605
|
+
end
|
606
|
+
end
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
ALL_DTYPES.each do |dtype|
|
611
|
+
[:dense, :yale].each do |stype|
|
612
|
+
answer_dtype = integer_dtype?(dtype) ? :int64 : dtype
|
613
|
+
next if dtype == :byte
|
614
|
+
|
615
|
+
context "#pow #{dtype} #{stype}" do
|
616
|
+
before do
|
617
|
+
@n = NMatrix.new [4,4], [0, 2, 0, 1,
|
618
|
+
2, 2, 3, 2,
|
619
|
+
4,-3, 0, 1,
|
620
|
+
6, 1,-6,-5], dtype: dtype, stype: stype
|
621
|
+
end
|
622
|
+
|
623
|
+
it "raises a square matrix to even power" do
|
624
|
+
expect(@n.pow(4)).to eq(NMatrix.new([4,4], [292, 28,-63, -42,
|
625
|
+
360, 96, 51, -14,
|
626
|
+
448,-231,-24,-87,
|
627
|
+
-1168, 595,234, 523],
|
628
|
+
dtype: answer_dtype,
|
629
|
+
stype: stype))
|
630
|
+
end
|
631
|
+
|
632
|
+
it "raises a square matrix to odd power" do
|
633
|
+
expect(@n.pow(9)).to eq(NMatrix.new([4,4],[-275128, 279917, 176127, 237451,
|
634
|
+
-260104, 394759, 166893, 296081,
|
635
|
+
-704824, 285700, 186411, 262002,
|
636
|
+
3209256,-1070870,-918741,-1318584],
|
637
|
+
dtype: answer_dtype, stype: stype))
|
638
|
+
end
|
639
|
+
|
640
|
+
it "raises a sqaure matrix to negative power" do
|
641
|
+
expect(@n.pow(-3)).to be_within(0.00001).of (NMatrix.new([4,4],
|
642
|
+
[1.0647e-02, 4.2239e-04,-6.2281e-05, 2.7680e-03,
|
643
|
+
-1.6415e-02, 2.1296e-02, 1.0718e-02, 4.8589e-03,
|
644
|
+
8.6956e-03,-8.6569e-03, 2.8993e-02, 7.2015e-03,
|
645
|
+
5.0034e-02,-1.7500e-02,-3.6777e-02,-1.2128e-02], dtype: answer_dtype,
|
646
|
+
stype: stype))
|
647
|
+
end unless stype =~ /yale/ or dtype == :object or ALL_DTYPES.grep(/int/).include? dtype
|
648
|
+
|
649
|
+
it "raises a square matrix to zero" do
|
650
|
+
expect(@n.pow(0)).to eq(NMatrix.eye([4,4], dtype: answer_dtype,
|
651
|
+
stype: stype))
|
652
|
+
end
|
653
|
+
|
654
|
+
it "raises a square matrix to one" do
|
655
|
+
expect(@n.pow(1)).to eq(@n)
|
656
|
+
end
|
657
|
+
end
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
ALL_DTYPES.each do |dtype|
|
662
|
+
[:dense, :yale].each do |stype|
|
663
|
+
context "#kron_prod #{dtype} #{stype}" do
|
664
|
+
before do
|
665
|
+
@a = NMatrix.new([2,2], [1,2,
|
666
|
+
3,4], dtype: dtype, stype: stype)
|
667
|
+
@b = NMatrix.new([2,3], [1,1,1,
|
668
|
+
1,1,1], dtype: dtype, stype: stype)
|
669
|
+
@c = NMatrix.new([4,6], [1, 1, 1, 2, 2, 2,
|
670
|
+
1, 1, 1, 2, 2, 2,
|
671
|
+
3, 3, 3, 4, 4, 4,
|
672
|
+
3, 3, 3, 4, 4, 4], dtype: dtype, stype: stype)
|
673
|
+
end
|
674
|
+
it "Compute the Kronecker product of two NMatrix" do
|
675
|
+
expect(@a.kron_prod(@b)).to eq(@c)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
context "determinants" do
|
682
|
+
ALL_DTYPES.each do |dtype|
|
683
|
+
next if dtype == :object
|
684
|
+
context dtype do
|
685
|
+
before do
|
686
|
+
@a = NMatrix.new([2,2], [1,2,
|
687
|
+
3,4], dtype: dtype)
|
688
|
+
@b = NMatrix.new([3,3], [1,2,3,
|
689
|
+
5,0,1,
|
690
|
+
4,1,3], dtype: dtype)
|
691
|
+
@c = NMatrix.new([4,4], [1, 0, 1, 1,
|
692
|
+
1, 2, 3, 1,
|
693
|
+
3, 3, 3, 1,
|
694
|
+
1, 2, 3, 4], dtype: dtype)
|
695
|
+
@err = case dtype
|
696
|
+
when :float32, :complex64
|
697
|
+
1e-6
|
698
|
+
when :float64, :complex128
|
699
|
+
1e-14
|
700
|
+
else
|
701
|
+
1e-64 # FIXME: should be 0, but be_within(0) does not work.
|
702
|
+
end
|
703
|
+
end
|
704
|
+
it "computes the determinant of 2x2 matrix" do
|
705
|
+
expect(@a.det).to be_within(@err).of(-2)
|
706
|
+
end
|
707
|
+
it "computes the determinant of 3x3 matrix" do
|
708
|
+
expect(@b.det).to be_within(@err).of(-8)
|
709
|
+
end
|
710
|
+
it "computes the determinant of 4x4 matrix" do
|
711
|
+
expect(@c.det).to be_within(@err).of(-18)
|
712
|
+
end
|
713
|
+
it "computes the exact determinant of 2x2 matrix" do
|
714
|
+
if dtype == :byte
|
715
|
+
expect{@a.det_exact}.to raise_error(DataTypeError)
|
716
|
+
else
|
717
|
+
expect(@a.det_exact).to be_within(@err).of(-2)
|
718
|
+
end
|
719
|
+
end
|
720
|
+
it "computes the exact determinant of 3x3 matrix" do
|
721
|
+
if dtype == :byte
|
722
|
+
expect{@a.det_exact}.to raise_error(DataTypeError)
|
723
|
+
else
|
724
|
+
expect(@b.det_exact).to be_within(@err).of(-8)
|
725
|
+
end
|
726
|
+
end
|
727
|
+
end
|
728
|
+
end
|
729
|
+
end
|
346
730
|
end
|