nmatrix-fftw 0.2.1 → 0.2.3
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/data.h +7 -8
- data/ext/nmatrix/data/ruby_object.h +1 -4
- data/ext/nmatrix/math/asum.h +10 -31
- data/ext/nmatrix/math/cblas_templates_core.h +10 -10
- data/ext/nmatrix/math/getrf.h +2 -2
- data/ext/nmatrix/math/imax.h +12 -9
- data/ext/nmatrix/math/laswp.h +3 -3
- data/ext/nmatrix/math/long_dtype.h +16 -3
- data/ext/nmatrix/math/magnitude.h +54 -0
- data/ext/nmatrix/math/nrm2.h +19 -14
- data/ext/nmatrix/math/trsm.h +40 -36
- data/ext/nmatrix/math/util.h +14 -0
- data/ext/nmatrix/nmatrix.h +39 -1
- data/ext/nmatrix/storage/common.h +9 -3
- data/ext/nmatrix/storage/yale/class.h +1 -1
- data/ext/nmatrix_fftw/extconf.rb +1 -71
- data/spec/00_nmatrix_spec.rb +50 -1
- data/spec/02_slice_spec.rb +21 -21
- data/spec/blas_spec.rb +25 -3
- data/spec/math_spec.rb +233 -5
- data/spec/shortcuts_spec.rb +145 -5
- data/spec/spec_helper.rb +24 -1
- metadata +18 -7
data/spec/02_slice_spec.rb
CHANGED
@@ -127,9 +127,9 @@ describe "Slice operation" do
|
|
127
127
|
it "should have #is_ref? method" do
|
128
128
|
a = stype_matrix[0..1, 0..1]
|
129
129
|
b = stype_matrix.slice(0..1, 0..1)
|
130
|
-
expect(stype_matrix.is_ref?).to
|
131
|
-
expect(a.is_ref?).to
|
132
|
-
expect(b.is_ref?).to
|
130
|
+
expect(stype_matrix.is_ref?).to be false
|
131
|
+
expect(a.is_ref?).to be true
|
132
|
+
expect(b.is_ref?).to be false
|
133
133
|
end
|
134
134
|
|
135
135
|
it "reference should compare with non-reference" do
|
@@ -141,7 +141,7 @@ describe "Slice operation" do
|
|
141
141
|
context "with copying" do
|
142
142
|
it 'should return an NMatrix' do
|
143
143
|
n = stype_matrix.slice(0..1,0..1)
|
144
|
-
expect(nm_eql(n, NMatrix.new([2,2], [0,1,3,4], dtype: :int32))).to
|
144
|
+
expect(nm_eql(n, NMatrix.new([2,2], [0,1,3,4], dtype: :int32))).to be true
|
145
145
|
end
|
146
146
|
|
147
147
|
it 'should return a copy of 2x2 matrix to self elements' do
|
@@ -183,19 +183,19 @@ describe "Slice operation" do
|
|
183
183
|
|
184
184
|
[:dense, :list, :yale].each do |cast_type|
|
185
185
|
it "should cast copied slice from #{stype.upcase} to #{cast_type.upcase}" do
|
186
|
-
expect(nm_eql(stype_matrix.slice(1..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(1..2,1..2))).to
|
187
|
-
expect(nm_eql(stype_matrix.slice(0..1, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..1,1..2))).to
|
188
|
-
expect(nm_eql(stype_matrix.slice(1..2, 0..1).cast(cast_type, :int32), stype_matrix.slice(1..2,0..1))).to
|
189
|
-
expect(nm_eql(stype_matrix.slice(0..1, 0..1).cast(cast_type, :int32), stype_matrix.slice(0..1,0..1))).to
|
186
|
+
expect(nm_eql(stype_matrix.slice(1..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(1..2,1..2))).to be true
|
187
|
+
expect(nm_eql(stype_matrix.slice(0..1, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..1,1..2))).to be true
|
188
|
+
expect(nm_eql(stype_matrix.slice(1..2, 0..1).cast(cast_type, :int32), stype_matrix.slice(1..2,0..1))).to be true
|
189
|
+
expect(nm_eql(stype_matrix.slice(0..1, 0..1).cast(cast_type, :int32), stype_matrix.slice(0..1,0..1))).to be true
|
190
190
|
|
191
191
|
# Non square
|
192
|
-
expect(nm_eql(stype_matrix.slice(0..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..2,1..2))).to
|
192
|
+
expect(nm_eql(stype_matrix.slice(0..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..2,1..2))).to be true
|
193
193
|
#require 'pry'
|
194
194
|
#binding.pry if cast_type == :yale
|
195
|
-
expect(nm_eql(stype_matrix.slice(1..2, 0..2).cast(cast_type, :int32), stype_matrix.slice(1..2,0..2))).to
|
195
|
+
expect(nm_eql(stype_matrix.slice(1..2, 0..2).cast(cast_type, :int32), stype_matrix.slice(1..2,0..2))).to be true
|
196
196
|
|
197
197
|
# Full
|
198
|
-
expect(nm_eql(stype_matrix.slice(0..2, 0..2).cast(cast_type, :int32), stype_matrix)).to
|
198
|
+
expect(nm_eql(stype_matrix.slice(0..2, 0..2).cast(cast_type, :int32), stype_matrix)).to be true
|
199
199
|
end
|
200
200
|
end
|
201
201
|
end
|
@@ -214,7 +214,7 @@ describe "Slice operation" do
|
|
214
214
|
context "by reference" do
|
215
215
|
it 'should return an NMatrix' do
|
216
216
|
n = stype_matrix[0..1,0..1]
|
217
|
-
expect(nm_eql(n, NMatrix.new([2,2], [0,1,3,4], dtype: :int32))).to
|
217
|
+
expect(nm_eql(n, NMatrix.new([2,2], [0,1,3,4], dtype: :int32))).to be true
|
218
218
|
end
|
219
219
|
|
220
220
|
it 'should return a 2x2 matrix with refs to self elements' do
|
@@ -246,7 +246,7 @@ describe "Slice operation" do
|
|
246
246
|
|
247
247
|
it 'should slice again' do
|
248
248
|
n = stype_matrix[1..2, 1..2]
|
249
|
-
expect(nm_eql(n[1,0..1], NVector.new(2, [7,8], dtype: :int32).transpose)).to
|
249
|
+
expect(nm_eql(n[1,0..1], NVector.new(2, [7,8], dtype: :int32).transpose)).to be true
|
250
250
|
end
|
251
251
|
|
252
252
|
it 'should be correct slice for range 0..2 and 0...3' do
|
@@ -320,7 +320,7 @@ describe "Slice operation" do
|
|
320
320
|
end
|
321
321
|
|
322
322
|
it "compares slices to scalars" do
|
323
|
-
(stype_matrix[1, 0..2] > 2).each { |e| expect(e != 0).to
|
323
|
+
(stype_matrix[1, 0..2] > 2).each { |e| expect(e != 0).to be true }
|
324
324
|
end
|
325
325
|
|
326
326
|
it "iterates only over elements in the slice" do
|
@@ -367,20 +367,20 @@ describe "Slice operation" do
|
|
367
367
|
|
368
368
|
[:dense, :list, :yale].each do |cast_type|
|
369
369
|
it "should cast a square reference-slice from #{stype.upcase} to #{cast_type.upcase}" do
|
370
|
-
expect(nm_eql(stype_matrix[1..2, 1..2].cast(cast_type), stype_matrix[1..2,1..2])).to
|
371
|
-
expect(nm_eql(stype_matrix[0..1, 1..2].cast(cast_type), stype_matrix[0..1,1..2])).to
|
372
|
-
expect(nm_eql(stype_matrix[1..2, 0..1].cast(cast_type), stype_matrix[1..2,0..1])).to
|
373
|
-
expect(nm_eql(stype_matrix[0..1, 0..1].cast(cast_type), stype_matrix[0..1,0..1])).to
|
370
|
+
expect(nm_eql(stype_matrix[1..2, 1..2].cast(cast_type), stype_matrix[1..2,1..2])).to be true
|
371
|
+
expect(nm_eql(stype_matrix[0..1, 1..2].cast(cast_type), stype_matrix[0..1,1..2])).to be true
|
372
|
+
expect(nm_eql(stype_matrix[1..2, 0..1].cast(cast_type), stype_matrix[1..2,0..1])).to be true
|
373
|
+
expect(nm_eql(stype_matrix[0..1, 0..1].cast(cast_type), stype_matrix[0..1,0..1])).to be true
|
374
374
|
end
|
375
375
|
|
376
376
|
it "should cast a rectangular reference-slice from #{stype.upcase} to #{cast_type.upcase}" do
|
377
377
|
# Non square
|
378
|
-
expect(nm_eql(stype_matrix[0..2, 1..2].cast(cast_type), stype_matrix[0..2,1..2])).to
|
379
|
-
expect(nm_eql(stype_matrix[1..2, 0..2].cast(cast_type), stype_matrix[1..2,0..2])).to
|
378
|
+
expect(nm_eql(stype_matrix[0..2, 1..2].cast(cast_type), stype_matrix[0..2,1..2])).to be true # FIXME: memory problem.
|
379
|
+
expect(nm_eql(stype_matrix[1..2, 0..2].cast(cast_type), stype_matrix[1..2,0..2])).to be true # this one is fine
|
380
380
|
end
|
381
381
|
|
382
382
|
it "should cast a square full-matrix reference-slice from #{stype.upcase} to #{cast_type.upcase}" do
|
383
|
-
expect(nm_eql(stype_matrix[0..2, 0..2].cast(cast_type), stype_matrix)).to
|
383
|
+
expect(nm_eql(stype_matrix[0..2, 0..2].cast(cast_type), stype_matrix)).to be true
|
384
384
|
end
|
385
385
|
end
|
386
386
|
end
|
data/spec/blas_spec.rb
CHANGED
@@ -69,6 +69,18 @@ describe NMatrix::BLAS do
|
|
69
69
|
expect(b[0]).to eq(-15.0/2)
|
70
70
|
expect(b[1]).to eq(5)
|
71
71
|
expect(b[2]).to eq(-13)
|
72
|
+
|
73
|
+
NMatrix::BLAS::cblas_trsm(:row, :left, :lower, :transpose, :nounit, 3, 1, 1.0, a, 3, b, 1)
|
74
|
+
|
75
|
+
expect(b[0]).to eq(307.0/8)
|
76
|
+
expect(b[1]).to eq(57.0/2)
|
77
|
+
expect(b[2]).to eq(26.0)
|
78
|
+
|
79
|
+
NMatrix::BLAS::cblas_trsm(:row, :left, :upper, :transpose, :unit, 3, 1, 1.0, a, 3, b, 1)
|
80
|
+
|
81
|
+
expect(b[0]).to eq(307.0/8)
|
82
|
+
expect(b[1]).to eq(763.0/16)
|
83
|
+
expect(b[2]).to eq(4269.0/64)
|
72
84
|
end
|
73
85
|
|
74
86
|
# trmm multiplies two matrices, where one of the two is required to be
|
@@ -174,9 +186,17 @@ describe NMatrix::BLAS do
|
|
174
186
|
|
175
187
|
it "exposes nrm2" do
|
176
188
|
pending("broken for :object") if dtype == :object
|
177
|
-
pending("Temporarily disable because the internal implementation of nrm2 is broken -WL 2015-05-17") if dtype == :complex64 || dtype == :complex128
|
178
189
|
|
179
|
-
|
190
|
+
if dtype =~ /complex/
|
191
|
+
x = NMatrix.new([3,1], [Complex(1,2),Complex(3,4),Complex(0,6)], dtype: dtype)
|
192
|
+
y = NMatrix.new([3,1], [Complex(0,0),Complex(0,0),Complex(0,0)], dtype: dtype)
|
193
|
+
nrm2 = 8.12403840463596
|
194
|
+
else
|
195
|
+
x = NMatrix.new([4,1], [2,-4,3,5], dtype: dtype)
|
196
|
+
y = NMatrix.new([3,1], [0,0,0], dtype: dtype)
|
197
|
+
nrm2 = 5.385164807134504
|
198
|
+
end
|
199
|
+
|
180
200
|
err = case dtype
|
181
201
|
when :float32, :complex64
|
182
202
|
1e-6
|
@@ -185,7 +205,9 @@ describe NMatrix::BLAS do
|
|
185
205
|
else
|
186
206
|
1e-14
|
187
207
|
end
|
188
|
-
|
208
|
+
|
209
|
+
expect(NMatrix::BLAS.nrm2(x, 1, 3)).to be_within(err).of(nrm2)
|
210
|
+
expect(NMatrix::BLAS.nrm2(y, 1, 3)).to be_within(err).of(0)
|
189
211
|
end
|
190
212
|
|
191
213
|
end
|
data/spec/math_spec.rb
CHANGED
@@ -285,6 +285,152 @@ describe "math" do
|
|
285
285
|
end
|
286
286
|
end
|
287
287
|
|
288
|
+
NON_INTEGER_DTYPES.each do |dtype|
|
289
|
+
next if dtype == :object
|
290
|
+
context dtype do
|
291
|
+
|
292
|
+
it "calculates QR decomposition using factorize_qr for a square matrix" do
|
293
|
+
|
294
|
+
a = NMatrix.new(3, [12.0, -51.0, 4.0,
|
295
|
+
6.0, 167.0, -68.0,
|
296
|
+
-4.0, 24.0, -41.0] , dtype: dtype)
|
297
|
+
|
298
|
+
q_solution = NMatrix.new([3,3], Q_SOLUTION_ARRAY_2, dtype: dtype)
|
299
|
+
|
300
|
+
r_solution = NMatrix.new([3,3], [-14.0, -21.0, 14,
|
301
|
+
0.0, -175, 70,
|
302
|
+
0.0, 0.0, -35] , dtype: dtype)
|
303
|
+
|
304
|
+
err = case dtype
|
305
|
+
when :float32, :complex64
|
306
|
+
1e-4
|
307
|
+
when :float64, :complex128
|
308
|
+
1e-13
|
309
|
+
end
|
310
|
+
|
311
|
+
begin
|
312
|
+
q,r = a.factorize_qr
|
313
|
+
|
314
|
+
expect(q).to be_within(err).of(q_solution)
|
315
|
+
expect(r).to be_within(err).of(r_solution)
|
316
|
+
|
317
|
+
rescue NotImplementedError
|
318
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
it "calculates QR decomposition using factorize_qr for a tall and narrow rectangular matrix" do
|
323
|
+
|
324
|
+
a = NMatrix.new([4,2], [34.0, 21.0,
|
325
|
+
23.0, 53.0,
|
326
|
+
26.0, 346.0,
|
327
|
+
23.0, 121.0] , dtype: dtype)
|
328
|
+
|
329
|
+
q_solution = NMatrix.new([4,4], Q_SOLUTION_ARRAY_1, dtype: dtype)
|
330
|
+
|
331
|
+
r_solution = NMatrix.new([4,2], [-53.75872022286244, -255.06559574252242,
|
332
|
+
0.0, 269.34836526051555,
|
333
|
+
0.0, 0.0,
|
334
|
+
0.0, 0.0] , dtype: dtype)
|
335
|
+
|
336
|
+
err = case dtype
|
337
|
+
when :float32, :complex64
|
338
|
+
1e-4
|
339
|
+
when :float64, :complex128
|
340
|
+
1e-13
|
341
|
+
end
|
342
|
+
|
343
|
+
begin
|
344
|
+
q,r = a.factorize_qr
|
345
|
+
|
346
|
+
expect(q).to be_within(err).of(q_solution)
|
347
|
+
expect(r).to be_within(err).of(r_solution)
|
348
|
+
|
349
|
+
rescue NotImplementedError
|
350
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
it "calculates QR decomposition using factorize_qr for a short and wide rectangular matrix" do
|
355
|
+
|
356
|
+
a = NMatrix.new([3,4], [123,31,57,81,92,14,17,36,42,34,11,28], dtype: dtype)
|
357
|
+
|
358
|
+
q_solution = NMatrix.new([3,3], Q_SOLUTION_ARRAY_3, dtype: dtype)
|
359
|
+
|
360
|
+
r_solution = NMatrix.new([3,4], R_SOLUTION_ARRAY, dtype: dtype)
|
361
|
+
|
362
|
+
err = case dtype
|
363
|
+
when :float32, :complex64
|
364
|
+
1e-4
|
365
|
+
when :float64, :complex128
|
366
|
+
1e-13
|
367
|
+
end
|
368
|
+
|
369
|
+
begin
|
370
|
+
q,r = a.factorize_qr
|
371
|
+
|
372
|
+
expect(q).to be_within(err).of(q_solution)
|
373
|
+
expect(r).to be_within(err).of(r_solution)
|
374
|
+
|
375
|
+
rescue NotImplementedError
|
376
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
it "calculates QR decomposition such that A - QR ~ 0" do
|
381
|
+
|
382
|
+
a = NMatrix.new([3,3], [ 9.0, 0.0, 26.0,
|
383
|
+
12.0, 0.0, -7.0,
|
384
|
+
0.0, 4.0, 0.0] , dtype: dtype)
|
385
|
+
|
386
|
+
err = case dtype
|
387
|
+
when :float32, :complex64
|
388
|
+
1e-4
|
389
|
+
when :float64, :complex128
|
390
|
+
1e-13
|
391
|
+
end
|
392
|
+
|
393
|
+
begin
|
394
|
+
q,r = a.factorize_qr
|
395
|
+
a_expected = q.dot(r)
|
396
|
+
|
397
|
+
expect(a_expected).to be_within(err).of(a)
|
398
|
+
|
399
|
+
rescue NotImplementedError
|
400
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
|
405
|
+
it "calculates the orthogonal matrix Q in QR decomposition" do
|
406
|
+
|
407
|
+
a = N.new([2,2], [34.0, 21, 23, 53] , dtype: dtype)
|
408
|
+
|
409
|
+
err = case dtype
|
410
|
+
when :float32, :complex64
|
411
|
+
1e-4
|
412
|
+
when :float64, :complex128
|
413
|
+
1e-13
|
414
|
+
end
|
415
|
+
|
416
|
+
begin
|
417
|
+
q,r = a.factorize_qr
|
418
|
+
|
419
|
+
#Q is orthogonal if Q x Q.transpose = I
|
420
|
+
product = q.dot(q.transpose)
|
421
|
+
|
422
|
+
expect(product[0,0]).to be_within(err).of(1)
|
423
|
+
expect(product[1,0]).to be_within(err).of(0)
|
424
|
+
expect(product[0,1]).to be_within(err).of(0)
|
425
|
+
expect(product[1,1]).to be_within(err).of(1)
|
426
|
+
|
427
|
+
rescue NotImplementedError
|
428
|
+
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
288
434
|
ALL_DTYPES.each do |dtype|
|
289
435
|
next if dtype == :byte #doesn't work for unsigned types
|
290
436
|
next if dtype == :object
|
@@ -332,6 +478,49 @@ describe "math" do
|
|
332
478
|
end
|
333
479
|
end
|
334
480
|
|
481
|
+
ALL_DTYPES.each do |dtype|
|
482
|
+
next if dtype == :byte #doesn't work for unsigned types
|
483
|
+
next if dtype == :object
|
484
|
+
|
485
|
+
context dtype do
|
486
|
+
err = case dtype
|
487
|
+
when :float32, :complex64
|
488
|
+
1e-4
|
489
|
+
else #integer matrices will return :float64
|
490
|
+
1e-13
|
491
|
+
end
|
492
|
+
|
493
|
+
it "should correctly find adjugate a matrix in place (bang)" do
|
494
|
+
a = NMatrix.new(:dense, 2, [2, 3, 3, 5], dtype)
|
495
|
+
b = NMatrix.new(:dense, 2, [5, -3, -3, 2], dtype)
|
496
|
+
|
497
|
+
if a.integer_dtype?
|
498
|
+
expect{a.adjugate!}.to raise_error(DataTypeError)
|
499
|
+
else
|
500
|
+
#should return adjugate as well as modifying a
|
501
|
+
r = a.adjugate!
|
502
|
+
expect(a).to be_within(err).of(b)
|
503
|
+
expect(r).to be_within(err).of(b)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
|
508
|
+
it "should correctly find adjugate of a matrix out-of-place" do
|
509
|
+
a = NMatrix.new(:dense, 3, [-3, 2, -5, -1, 0, -2, 3, -4, 1], dtype)
|
510
|
+
|
511
|
+
if a.integer_dtype?
|
512
|
+
b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], :float64)
|
513
|
+
else
|
514
|
+
b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], dtype)
|
515
|
+
end
|
516
|
+
|
517
|
+
expect(a.adjoint).to be_within(err).of(b)
|
518
|
+
expect(a.adjugate).to be_within(err).of(b)
|
519
|
+
end
|
520
|
+
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
335
524
|
# TODO: Get it working with ROBJ too
|
336
525
|
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype|
|
337
526
|
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype|
|
@@ -702,7 +891,7 @@ describe "math" do
|
|
702
891
|
360, 96, 51, -14,
|
703
892
|
448,-231,-24,-87,
|
704
893
|
-1168, 595,234, 523],
|
705
|
-
dtype: answer_dtype,
|
894
|
+
dtype: answer_dtype,
|
706
895
|
stype: stype))
|
707
896
|
end
|
708
897
|
|
@@ -757,7 +946,6 @@ describe "math" do
|
|
757
946
|
|
758
947
|
context "determinants" do
|
759
948
|
ALL_DTYPES.each do |dtype|
|
760
|
-
next if dtype == :object
|
761
949
|
context dtype do
|
762
950
|
before do
|
763
951
|
@a = NMatrix.new([2,2], [1,2,
|
@@ -779,13 +967,19 @@ describe "math" do
|
|
779
967
|
end
|
780
968
|
end
|
781
969
|
it "computes the determinant of 2x2 matrix" do
|
782
|
-
|
970
|
+
if dtype != :object
|
971
|
+
expect(@a.det).to be_within(@err).of(-2)
|
972
|
+
end
|
783
973
|
end
|
784
974
|
it "computes the determinant of 3x3 matrix" do
|
785
|
-
|
975
|
+
if dtype != :object
|
976
|
+
expect(@b.det).to be_within(@err).of(-8)
|
977
|
+
end
|
786
978
|
end
|
787
979
|
it "computes the determinant of 4x4 matrix" do
|
788
|
-
|
980
|
+
if dtype != :object
|
981
|
+
expect(@c.det).to be_within(@err).of(-18)
|
982
|
+
end
|
789
983
|
end
|
790
984
|
it "computes the exact determinant of 2x2 matrix" do
|
791
985
|
if dtype == :byte
|
@@ -804,4 +998,38 @@ describe "math" do
|
|
804
998
|
end
|
805
999
|
end
|
806
1000
|
end
|
1001
|
+
|
1002
|
+
context "#scale and #scale!" do
|
1003
|
+
[:dense,:list,:yale].each do |stype|
|
1004
|
+
ALL_DTYPES.each do |dtype|
|
1005
|
+
next if dtype == :object
|
1006
|
+
context "for #{dtype}" do
|
1007
|
+
before do
|
1008
|
+
@m = NMatrix.new([3, 3], [0, 1, 2,
|
1009
|
+
3, 4, 5,
|
1010
|
+
6, 7, 8], stype: stype, dtype: dtype)
|
1011
|
+
end
|
1012
|
+
it "scales the matrix by a given factor and return the result" do
|
1013
|
+
if integer_dtype? dtype
|
1014
|
+
expect{@m.scale 2.0}.to raise_error(DataTypeError)
|
1015
|
+
else
|
1016
|
+
expect(@m.scale 2.0).to eq(NMatrix.new([3, 3], [0, 2, 4,
|
1017
|
+
6, 8, 10,
|
1018
|
+
12, 14, 16], stype: stype, dtype: dtype))
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
it "scales the matrix in place by a given factor" do
|
1022
|
+
if dtype == :int8
|
1023
|
+
expect{@m.scale! 2}.to raise_error(DataTypeError)
|
1024
|
+
else
|
1025
|
+
@m.scale! 2
|
1026
|
+
expect(@m).to eq(NMatrix.new([3, 3], [0, 2, 4,
|
1027
|
+
6, 8, 10,
|
1028
|
+
12, 14, 16], stype: stype, dtype: dtype))
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
end
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
end
|
807
1035
|
end
|
data/spec/shortcuts_spec.rb
CHANGED
@@ -50,10 +50,45 @@ describe NMatrix do
|
|
50
50
|
expect(m).to eq identity3
|
51
51
|
end
|
52
52
|
|
53
|
+
it "hilbert() creates an hilbert matrix" do
|
54
|
+
m = NMatrix.hilbert(8)
|
55
|
+
expect(m[4, 0]).to be_within(0.000001).of(0.2)
|
56
|
+
expect(m[4, 1]).to be_within(0.000001).of(0.16666666666666666)
|
57
|
+
expect(m[4, 2]).to be_within(0.000001).of(0.14285714285714285)
|
58
|
+
expect(m[4, 3]).to be_within(0.000001).of(0.125)
|
59
|
+
|
60
|
+
m = NMatrix.hilbert(3)
|
61
|
+
hilbert3 = NMatrix.new([3, 3], [1.0, 0.5, 0.3333333333333333,\
|
62
|
+
0.5, 0.3333333333333333, 0.25, 0.3333333333333333, 0.25, 0.2])
|
63
|
+
expect(m).to eq hilbert3
|
64
|
+
0.upto(2) do |i|
|
65
|
+
0.upto(2) do |j|
|
66
|
+
expect(m[i, j]).to be_within(0.000001).of(hilbert3[i,j])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "inv_hilbert() creates an inverse hilbert matrix" do
|
72
|
+
m = NMatrix.inv_hilbert(6)
|
73
|
+
inv_hilbert6 = [3360.0, -88200.0, 564480.0, -1411200.0]
|
74
|
+
expect(m[2,0]).to be_within(0.000001).of(inv_hilbert6[0])
|
75
|
+
expect(m[2,1]).to be_within(0.000001).of(inv_hilbert6[1])
|
76
|
+
expect(m[2,2]).to be_within(0.000001).of(inv_hilbert6[2])
|
77
|
+
expect(m[2,3]).to be_within(0.000001).of(inv_hilbert6[3])
|
78
|
+
|
79
|
+
m = NMatrix.inv_hilbert(3)
|
80
|
+
inv_hilbert3 = NMatrix.new([3, 3], [ 9.0, -36.0, 30.0, -36.0, 192.0, -180.0, 30.0, -180.0, 180.0] )
|
81
|
+
0.upto(2) do |i|
|
82
|
+
0.upto(2) do |j|
|
83
|
+
expect(m[i, j]).to be_within(0.000001).of(inv_hilbert3[i,j])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
53
88
|
it "diag() creates a matrix with pre-supplied diagonal" do
|
54
89
|
arr = [1,2,3,4]
|
55
90
|
m = NMatrix.diag(arr)
|
56
|
-
expect(m.is_a?(NMatrix)).to
|
91
|
+
expect(m.is_a?(NMatrix)).to be true
|
57
92
|
end
|
58
93
|
|
59
94
|
it "diagonals() contains the seeded values on the diagonal" do
|
@@ -123,6 +158,112 @@ describe NMatrix do
|
|
123
158
|
expect { NMatrix.random("not an array or integer") }.to raise_error
|
124
159
|
end
|
125
160
|
end
|
161
|
+
|
162
|
+
context "::magic" do
|
163
|
+
|
164
|
+
ALL_DTYPES.each do |dtype|
|
165
|
+
context dtype do
|
166
|
+
it "creates a matrix with numbers from 1 to n^n(n squared)" do
|
167
|
+
a = NMatrix.magic(3, dtype: dtype)
|
168
|
+
magic3 = NMatrix.new([3,3], [4, 9, 2, 3, 5, 7, 8, 1, 6], dtype: dtype)
|
169
|
+
expect(a).to eq magic3
|
170
|
+
|
171
|
+
b = NMatrix.magic(4, dtype: dtype)
|
172
|
+
magic4 = NMatrix.new([4,4], [1, 15, 14, 4, 12, 6, 7, 9, 8, 10, 11, 5, 13, 3, 2, 16], dtype: dtype)
|
173
|
+
expect(b).to eq magic4
|
174
|
+
|
175
|
+
c = NMatrix.magic(6, dtype: dtype)
|
176
|
+
magic6 = NMatrix.new([6,6], [31, 9, 2, 22, 27, 20, 3, 32, 7, 21, 23, 25, 35, 1, 6, 26, 19, 24, 4, 36, 29, 13, 18, 11, 30, 5, 34, 12, 14, 16, 8, 28, 33, 17, 10, 15], dtype: dtype)
|
177
|
+
expect(c).to eq magic6
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it "shape of two is not allowed" do
|
183
|
+
expect { NMatrix.magic(2) }.to raise_error(ArgumentError)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "Only accepts an integer as dimension" do
|
187
|
+
expect { NMatrix.magic(3.0) }.to raise_error(ArgumentError)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "::linspace" do
|
192
|
+
it "creates a row vector when given only one shape parameter" do
|
193
|
+
v = NMatrix.linspace(1, 10, 4)
|
194
|
+
#Expect a row vector only
|
195
|
+
expect(v.shape.length).to eq(1)
|
196
|
+
|
197
|
+
ans = [1.0,4.0,7.0,10.0]
|
198
|
+
|
199
|
+
expect(v[0]).to be_within(0.000001).of(ans[0])
|
200
|
+
expect(v[1]).to be_within(0.000001).of(ans[1])
|
201
|
+
expect(v[2]).to be_within(0.000001).of(ans[2])
|
202
|
+
expect(v[3]).to be_within(0.000001).of(ans[3])
|
203
|
+
end
|
204
|
+
|
205
|
+
it "creates a matrix of input shape with each entry linearly spaced in row major order" do
|
206
|
+
v = NMatrix.linspace(1, Math::PI, [2,2])
|
207
|
+
expect(v.dtype).to eq(:float64)
|
208
|
+
|
209
|
+
ans = [1.0, 1.7138642072677612, 2.4277284145355225, 3.1415927410125732]
|
210
|
+
|
211
|
+
expect(v[0,0]).to be_within(0.000001).of(ans[0])
|
212
|
+
expect(v[0,1]).to be_within(0.000001).of(ans[1])
|
213
|
+
expect(v[1,0]).to be_within(0.000001).of(ans[2])
|
214
|
+
expect(v[1,1]).to be_within(0.000001).of(ans[3])
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context "::logspace" do
|
219
|
+
it "creates a logarithmically spaced vector" do
|
220
|
+
v = NMatrix.logspace(1, 2, 10)
|
221
|
+
|
222
|
+
expect(v.shape.length).to eq(1)
|
223
|
+
|
224
|
+
#Unit test taken from Matlab R2015b output of logspace(1,2,10)
|
225
|
+
ans = [10.0000, 12.9155, 16.6810, 21.5443, 27.8256, 35.9381, 46.4159, 59.9484, 77.4264, 100.0000]
|
226
|
+
|
227
|
+
expect(v[0].round(4)).to be_within(0.000001).of(ans[0])
|
228
|
+
expect(v[1].round(4)).to be_within(0.000001).of(ans[1])
|
229
|
+
expect(v[2].round(4)).to be_within(0.000001).of(ans[2])
|
230
|
+
expect(v[3].round(4)).to be_within(0.000001).of(ans[3])
|
231
|
+
expect(v[4].round(4)).to be_within(0.000001).of(ans[4])
|
232
|
+
expect(v[5].round(4)).to be_within(0.000001).of(ans[5])
|
233
|
+
expect(v[6].round(4)).to be_within(0.000001).of(ans[6])
|
234
|
+
expect(v[7].round(4)).to be_within(0.000001).of(ans[7])
|
235
|
+
expect(v[8].round(4)).to be_within(0.000001).of(ans[8])
|
236
|
+
expect(v[9].round(4)).to be_within(0.000001).of(ans[9])
|
237
|
+
end
|
238
|
+
|
239
|
+
it "creates a logarithmically spaced vector bounded by Math::PI if :pi is pre-supplied" do
|
240
|
+
v = NMatrix.logspace(1, :pi, 7)
|
241
|
+
|
242
|
+
#Unit test taken from Matlab R2015b output of logspace(1,pi,10)
|
243
|
+
ans = [10.0000, 8.2450, 6.7980, 5.6050, 4.6213, 3.8103, 3.1416]
|
244
|
+
|
245
|
+
expect(v[0].round(4)).to be_within(0.000001).of(ans[0])
|
246
|
+
expect(v[1].round(4)).to be_within(0.000001).of(ans[1])
|
247
|
+
expect(v[2].round(4)).to be_within(0.000001).of(ans[2])
|
248
|
+
expect(v[3].round(4)).to be_within(0.000001).of(ans[3])
|
249
|
+
expect(v[4].round(4)).to be_within(0.000001).of(ans[4])
|
250
|
+
expect(v[5].round(4)).to be_within(0.000001).of(ans[5])
|
251
|
+
expect(v[6].round(4)).to be_within(0.000001).of(ans[6])
|
252
|
+
end
|
253
|
+
|
254
|
+
it "creates a matrix of input shape with each entry logarithmically spaced in row major order" do
|
255
|
+
v = NMatrix.logspace(1, 2, [3,2])
|
256
|
+
|
257
|
+
ans = [10.0, 15.8489, 25.1189, 39.8107, 63.0957, 100.0]
|
258
|
+
|
259
|
+
expect(v[0,0].round(4)).to be_within(0.000001).of(ans[0])
|
260
|
+
expect(v[0,1].round(4)).to be_within(0.000001).of(ans[1])
|
261
|
+
expect(v[1,0].round(4)).to be_within(0.000001).of(ans[2])
|
262
|
+
expect(v[1,1].round(4)).to be_within(0.000001).of(ans[3])
|
263
|
+
expect(v[2,0].round(4)).to be_within(0.000001).of(ans[4])
|
264
|
+
expect(v[2,1].round(4)).to be_within(0.000001).of(ans[5])
|
265
|
+
end
|
266
|
+
end
|
126
267
|
|
127
268
|
it "seq() creates a matrix of integers, sequentially" do
|
128
269
|
m = NMatrix.seq(2) # 2x2 matrix.
|
@@ -136,7 +277,6 @@ describe NMatrix do
|
|
136
277
|
end
|
137
278
|
end
|
138
279
|
|
139
|
-
|
140
280
|
it "indgen() creates a matrix of integers as well as seq()" do
|
141
281
|
m = NMatrix.indgen(2) # 2x2 matrix.
|
142
282
|
value = 0
|
@@ -189,19 +329,19 @@ describe NMatrix do
|
|
189
329
|
it "column() returns a NMatrix" do
|
190
330
|
m = NMatrix.random(3)
|
191
331
|
|
192
|
-
expect(m.column(2).is_a?(NMatrix)).to
|
332
|
+
expect(m.column(2).is_a?(NMatrix)).to be true
|
193
333
|
end
|
194
334
|
|
195
335
|
it "row() returns a NMatrix" do
|
196
336
|
m = NMatrix.random(3)
|
197
337
|
|
198
|
-
expect(m.row(2).is_a?(NMatrix)).to
|
338
|
+
expect(m.row(2).is_a?(NMatrix)).to be true
|
199
339
|
end
|
200
340
|
|
201
341
|
it "diagonals() creates an NMatrix" do
|
202
342
|
arr = [1,2,3,4]
|
203
343
|
m = NMatrix.diagonals(arr)
|
204
|
-
expect(m.is_a?(NMatrix)).to
|
344
|
+
expect(m.is_a?(NMatrix)).to be true
|
205
345
|
end
|
206
346
|
|
207
347
|
it "diagonals() contains the seeded values on the diagonal" do
|