pnmatrix 1.2.4 → 2.0.1
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/extconf.rb +6 -6
- data/ext/nmatrix/math/math.h +2 -2
- data/ext/nmatrix/nmatrix.h +10 -1
- data/ext/nmatrix/ruby_nmatrix.c +44 -9
- data/ext/nmatrix/storage/dense/dense.cpp +35 -12
- data/ext/nmatrix/storage/list/list.cpp +6 -2
- data/ext/nmatrix/storage/yale/class.h +71 -16
- data/ext/nmatrix/storage/yale/iterators/row.h +5 -5
- data/ext/nmatrix/storage/yale/yale.cpp +23 -4
- data/lib/nmatrix/homogeneous.rb +3 -3
- data/lib/nmatrix/mkmf.rb +6 -3
- data/lib/nmatrix/nmatrix.rb +3 -3
- data/lib/nmatrix/shortcuts.rb +12 -15
- data/lib/nmatrix/version.rb +3 -4
- data/spec/io_spec.rb +3 -1
- data/spec/lapack_core_spec.rb +13 -8
- data/spec/math_spec.rb +33 -13
- data/spec/stress_test_spec.rb +181 -0
- metadata +14 -14
data/lib/nmatrix/shortcuts.rb
CHANGED
|
@@ -196,11 +196,8 @@ class NMatrix
|
|
|
196
196
|
i += 1
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
-
# A row vector should be stored as 1xN, not N
|
|
200
|
-
#shape.unshift(1) if shape.size == 1
|
|
201
|
-
|
|
202
199
|
# Then flatten the array.
|
|
203
|
-
NMatrix.new(shape, params.flatten, options)
|
|
200
|
+
NMatrix.new(shape, params.flatten, **options)
|
|
204
201
|
end
|
|
205
202
|
|
|
206
203
|
#
|
|
@@ -230,7 +227,7 @@ class NMatrix
|
|
|
230
227
|
# NMatrix.zeros([1, 5], dtype: :int32) # => 0 0 0 0 0
|
|
231
228
|
#
|
|
232
229
|
def zeros(shape, opts = {})
|
|
233
|
-
NMatrix.new(shape, 0, {:dtype => :float64}.merge(opts))
|
|
230
|
+
NMatrix.new(shape, 0, **{:dtype => :float64}.merge(opts))
|
|
234
231
|
end
|
|
235
232
|
alias :zeroes :zeros
|
|
236
233
|
|
|
@@ -255,7 +252,7 @@ class NMatrix
|
|
|
255
252
|
# 1 1 1
|
|
256
253
|
#
|
|
257
254
|
def ones(shape, opts={})
|
|
258
|
-
NMatrix.new(shape, 1, {:dtype => :float64
|
|
255
|
+
NMatrix.new(shape, 1, **{:dtype => :float64}.merge(opts))
|
|
259
256
|
end
|
|
260
257
|
|
|
261
258
|
# call-seq:
|
|
@@ -268,7 +265,7 @@ class NMatrix
|
|
|
268
265
|
# @return [NMatrix] a new nmatrix filled with ones.
|
|
269
266
|
#
|
|
270
267
|
def ones_like(nm)
|
|
271
|
-
NMatrix.ones(nm.shape, dtype: nm.dtype, stype: nm.stype, capacity: nm.capacity
|
|
268
|
+
NMatrix.ones(nm.shape, dtype: nm.dtype, stype: nm.stype, capacity: nm.capacity)
|
|
272
269
|
end
|
|
273
270
|
|
|
274
271
|
# call-seq:
|
|
@@ -281,7 +278,7 @@ class NMatrix
|
|
|
281
278
|
# @return [NMatrix] a new nmatrix filled with zeros.
|
|
282
279
|
#
|
|
283
280
|
def zeros_like(nm)
|
|
284
|
-
NMatrix.zeros(nm.shape, dtype: nm.dtype, stype: nm.stype, capacity: nm.capacity
|
|
281
|
+
NMatrix.zeros(nm.shape, dtype: nm.dtype, stype: nm.stype, capacity: nm.capacity)
|
|
285
282
|
end
|
|
286
283
|
|
|
287
284
|
#
|
|
@@ -345,7 +342,7 @@ class NMatrix
|
|
|
345
342
|
# 0.3333333333333333 0.25 0.2
|
|
346
343
|
#
|
|
347
344
|
def hilbert(shape, opts={})
|
|
348
|
-
m = NMatrix.new([shape,shape], {:dtype => :float64}.merge(opts))
|
|
345
|
+
m = NMatrix.new([shape,shape], **{:dtype => :float64}.merge(opts))
|
|
349
346
|
0.upto(shape - 1) do |i|
|
|
350
347
|
0.upto(i) do |j|
|
|
351
348
|
m[i,j] = 1.0 / (j + i + 1)
|
|
@@ -378,8 +375,8 @@ class NMatrix
|
|
|
378
375
|
#
|
|
379
376
|
def inv_hilbert(shape, opts={})
|
|
380
377
|
opts = {:dtype => :float64}.merge(opts)
|
|
381
|
-
m = NMatrix.new([shape,shape],opts)
|
|
382
|
-
combination = NMatrix.new([2*shape,2*shape],opts)
|
|
378
|
+
m = NMatrix.new([shape,shape], **opts)
|
|
379
|
+
combination = NMatrix.new([2*shape,2*shape], **opts)
|
|
383
380
|
#combinations refers to the combination of n things taken k at a time
|
|
384
381
|
0.upto(2*shape-1) do |i|
|
|
385
382
|
0.upto(i) do |j|
|
|
@@ -553,7 +550,7 @@ class NMatrix
|
|
|
553
550
|
NMatrix.size(shape).times { |i| random_values << rng.rand(scale) }
|
|
554
551
|
end
|
|
555
552
|
|
|
556
|
-
NMatrix.new(shape, random_values, {:dtype => :float64, :stype => :dense}.merge(opts))
|
|
553
|
+
NMatrix.new(shape, random_values, **{:dtype => :float64, :stype => :dense}.merge(opts))
|
|
557
554
|
end
|
|
558
555
|
alias :rand :random
|
|
559
556
|
|
|
@@ -595,7 +592,7 @@ class NMatrix
|
|
|
595
592
|
#
|
|
596
593
|
def magic(shape, opts={})
|
|
597
594
|
raise(ArgumentError, "shape of two is not allowed") if shape == 2
|
|
598
|
-
nm = NMatrix.new([shape,shape], 0, {:dtype => :float64}.merge(opts))
|
|
595
|
+
nm = NMatrix.new([shape,shape], 0, **{:dtype => :float64}.merge(opts))
|
|
599
596
|
if shape % 2 != 0
|
|
600
597
|
MagicHelpers.odd_magic nm, shape
|
|
601
598
|
elsif shape % 4 == 0
|
|
@@ -841,7 +838,7 @@ class NMatrix
|
|
|
841
838
|
values = (0 ... NMatrix.size(shape)).to_a
|
|
842
839
|
|
|
843
840
|
# It'll produce :int32, except if a dtype is provided.
|
|
844
|
-
NMatrix.new(shape, values, {:stype => :dense}.merge(options))
|
|
841
|
+
NMatrix.new(shape, values, **{:stype => :dense}.merge(options))
|
|
845
842
|
end
|
|
846
843
|
|
|
847
844
|
{:bindgen => :byte, :indgen => :int64, :findgen => :float32, :dindgen => :float64,
|
|
@@ -969,7 +966,7 @@ module NVector #:nodoc:
|
|
|
969
966
|
random_values = []
|
|
970
967
|
size.times { |i| random_values << rng.rand }
|
|
971
968
|
|
|
972
|
-
NMatrix.new([size,1], random_values, opts)
|
|
969
|
+
NMatrix.new([size,1], random_values, **opts)
|
|
973
970
|
end
|
|
974
971
|
|
|
975
972
|
#
|
data/lib/nmatrix/version.rb
CHANGED
|
@@ -27,13 +27,12 @@ class NMatrix
|
|
|
27
27
|
# native IO. If you change the format, please make sure that native
|
|
28
28
|
# IO can still understand NMatrix::VERSION.
|
|
29
29
|
module VERSION #:nodoc:
|
|
30
|
-
MAJOR =
|
|
31
|
-
MINOR =
|
|
32
|
-
TINY =
|
|
30
|
+
MAJOR = 2
|
|
31
|
+
MINOR = 0
|
|
32
|
+
TINY = 1
|
|
33
33
|
#PRE = "a"
|
|
34
34
|
|
|
35
35
|
STRING = [MAJOR, MINOR, TINY].compact.join(".")
|
|
36
36
|
#STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
|
-
|
data/spec/io_spec.rb
CHANGED
|
@@ -51,6 +51,7 @@ describe NMatrix::IO do
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
it "reads MATLAB .mat file containing a single square sparse matrix" do
|
|
54
|
+
skip "Mat5Reader was removed from pnmatrix" unless defined?(NMatrix::IO::Matlab::Mat5Reader)
|
|
54
55
|
pending("not yet implemented for NMatrix-JRuby") if jruby?
|
|
55
56
|
n = NMatrix::IO::Matlab.load_mat("spec/4x4_sparse.mat")
|
|
56
57
|
expect(n[0,0]).to eq(2)
|
|
@@ -62,19 +63,20 @@ describe NMatrix::IO do
|
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
it "reads MATLAB .mat file containing a single dense integer matrix" do
|
|
66
|
+
skip "Mat5Reader was removed from pnmatrix" unless defined?(NMatrix::IO::Matlab::Mat5Reader)
|
|
65
67
|
n = NMatrix::IO::Matlab.load_mat("spec/4x5_dense.mat")
|
|
66
68
|
m = NMatrix.new([4,5], [16,17,18,19,20,15,14,13,12,11,6,7,8,9,10,5,4,3,2,1])
|
|
67
69
|
expect(n).to eq(m)
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
it "reads MATLAB .mat file containing a single dense double matrix" do
|
|
73
|
+
skip "Mat5Reader was removed from pnmatrix" unless defined?(NMatrix::IO::Matlab::Mat5Reader)
|
|
71
74
|
n = NMatrix::IO::Matlab.load_mat("spec/2x2_dense_double.mat")
|
|
72
75
|
m = NMatrix.new(2, [1.1, 2.0, 3.0, 4.0], dtype: :float64)
|
|
73
76
|
expect(n).to eq(m)
|
|
74
77
|
end
|
|
75
78
|
|
|
76
79
|
it "loads and saves MatrixMarket .mtx file containing a single large sparse double matrix" do
|
|
77
|
-
pending "spec disabled because it's so slow"
|
|
78
80
|
n = NMatrix::IO::Market.load("spec/utm5940.mtx")
|
|
79
81
|
NMatrix::IO::Market.save(n, "spec/utm5940.saved.mtx")
|
|
80
82
|
expect(`wc -l spec/utm5940.mtx`.split[0]).to eq(`wc -l spec/utm5940.saved.mtx`.split[0])
|
data/spec/lapack_core_spec.rb
CHANGED
|
@@ -273,8 +273,9 @@ describe "NMatrix::LAPACK functions with internal implementations" do
|
|
|
273
273
|
end
|
|
274
274
|
|
|
275
275
|
expect(s).to be_within(err).of(s_true)
|
|
276
|
-
|
|
277
|
-
expect(
|
|
276
|
+
# Singular vectors are only defined up to sign (or complex phase).
|
|
277
|
+
expect(u.abs).to be_within(err).of(u_true.abs)
|
|
278
|
+
expect(vt.abs).to be_within(err).of(vt_true.abs)
|
|
278
279
|
|
|
279
280
|
expect(s.dtype).to eq(a.abs_dtype)
|
|
280
281
|
expect(u.dtype).to eq(dtype)
|
|
@@ -306,8 +307,9 @@ describe "NMatrix::LAPACK functions with internal implementations" do
|
|
|
306
307
|
end
|
|
307
308
|
|
|
308
309
|
expect(s).to be_within(err).of(s_true)
|
|
309
|
-
|
|
310
|
-
expect(
|
|
310
|
+
# Singular vectors are only defined up to sign (or complex phase).
|
|
311
|
+
expect(u.abs).to be_within(err).of(u_true.abs)
|
|
312
|
+
expect(vt.abs).to be_within(err).of(vt_true.abs)
|
|
311
313
|
end
|
|
312
314
|
|
|
313
315
|
|
|
@@ -337,8 +339,9 @@ describe "NMatrix::LAPACK functions with internal implementations" do
|
|
|
337
339
|
end
|
|
338
340
|
|
|
339
341
|
expect(eigenvalues).to be_within(err).of(eigenvalues_true)
|
|
340
|
-
|
|
341
|
-
expect(
|
|
342
|
+
# Eigenvectors are only defined up to sign (or complex phase).
|
|
343
|
+
expect(vr.abs).to be_within(err).of(vr_true.abs)
|
|
344
|
+
expect(vl.abs).to be_within(err).of(vl_true.abs)
|
|
342
345
|
|
|
343
346
|
expect(eigenvalues.dtype).to eq(NMatrix.upcast(dtype, :complex64))
|
|
344
347
|
expect(vr.dtype).to eq(NMatrix.upcast(dtype, :complex64))
|
|
@@ -384,7 +387,8 @@ describe "NMatrix::LAPACK functions with internal implementations" do
|
|
|
384
387
|
end
|
|
385
388
|
|
|
386
389
|
expect(eigenvalues).to be_within(err).of(eigenvalues_true)
|
|
387
|
-
|
|
390
|
+
# Eigenvectors are only defined up to sign (or complex phase).
|
|
391
|
+
expect(vr.abs).to be_within(err).of(vr_true.abs)
|
|
388
392
|
expect(vl).to be_within(err).of(vl_true)
|
|
389
393
|
|
|
390
394
|
expect(eigenvalues.dtype).to eq(dtype)
|
|
@@ -441,7 +445,8 @@ describe "NMatrix::LAPACK functions with internal implementations" do
|
|
|
441
445
|
end
|
|
442
446
|
|
|
443
447
|
expect(eigenvalues).to be_within(err).of(eigenvalues_true)
|
|
444
|
-
|
|
448
|
+
# Eigenvectors are only defined up to sign (or complex phase).
|
|
449
|
+
expect(vr.abs).to be_within(err).of(vr_true.abs)
|
|
445
450
|
end
|
|
446
451
|
end
|
|
447
452
|
end
|
data/spec/math_spec.rb
CHANGED
|
@@ -82,8 +82,10 @@ describe "math" do
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
it "should correctly apply elementwise natural log" do
|
|
85
|
-
expect(@m.log).to
|
|
86
|
-
|
|
85
|
+
expect(@m.log).to be_within(1e-14).of(
|
|
86
|
+
N.new(@size, [0, Math.log(2), Math.log(3), Math.log(4)],
|
|
87
|
+
dtype: :float64, stype: stype)
|
|
88
|
+
)
|
|
87
89
|
end
|
|
88
90
|
|
|
89
91
|
it "should correctly apply elementwise log with arbitrary base" do
|
|
@@ -264,6 +266,7 @@ describe "math" do
|
|
|
264
266
|
expect(r).to eq(b)
|
|
265
267
|
rescue NotImplementedError
|
|
266
268
|
pending "potrf! not implemented without plugins"
|
|
269
|
+
raise
|
|
267
270
|
end
|
|
268
271
|
end
|
|
269
272
|
|
|
@@ -280,6 +283,7 @@ describe "math" do
|
|
|
280
283
|
expect(r).to eq(b)
|
|
281
284
|
rescue NotImplementedError
|
|
282
285
|
pending "potrf! not implemented without plugins"
|
|
286
|
+
raise
|
|
283
287
|
end
|
|
284
288
|
end
|
|
285
289
|
|
|
@@ -295,6 +299,7 @@ describe "math" do
|
|
|
295
299
|
expect(l).to eq(l_true)
|
|
296
300
|
rescue NotImplementedError
|
|
297
301
|
pending "potrf! not implemented without plugins"
|
|
302
|
+
raise
|
|
298
303
|
end
|
|
299
304
|
end
|
|
300
305
|
end
|
|
@@ -325,11 +330,13 @@ describe "math" do
|
|
|
325
330
|
begin
|
|
326
331
|
q,r = a.factorize_qr
|
|
327
332
|
|
|
328
|
-
|
|
329
|
-
expect(
|
|
333
|
+
# QR factors are only defined up to matched column/row signs.
|
|
334
|
+
expect(q.abs).to be_within(err).of(q_solution.abs)
|
|
335
|
+
expect(r.abs).to be_within(err).of(r_solution.abs)
|
|
330
336
|
|
|
331
337
|
rescue NotImplementedError
|
|
332
338
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
339
|
+
raise
|
|
333
340
|
end
|
|
334
341
|
end
|
|
335
342
|
|
|
@@ -359,11 +366,13 @@ describe "math" do
|
|
|
359
366
|
begin
|
|
360
367
|
q,r = a.factorize_qr
|
|
361
368
|
|
|
362
|
-
|
|
363
|
-
expect(
|
|
369
|
+
# QR factors are only defined up to matched column/row signs.
|
|
370
|
+
expect(q.abs).to be_within(err).of(q_solution.abs)
|
|
371
|
+
expect(r.abs).to be_within(err).of(r_solution.abs)
|
|
364
372
|
|
|
365
373
|
rescue NotImplementedError
|
|
366
374
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
375
|
+
raise
|
|
367
376
|
end
|
|
368
377
|
end
|
|
369
378
|
|
|
@@ -387,11 +396,13 @@ describe "math" do
|
|
|
387
396
|
begin
|
|
388
397
|
q,r = a.factorize_qr
|
|
389
398
|
|
|
390
|
-
|
|
391
|
-
expect(
|
|
399
|
+
# QR factors are only defined up to matched column/row signs.
|
|
400
|
+
expect(q.abs).to be_within(err).of(q_solution.abs)
|
|
401
|
+
expect(r.abs).to be_within(err).of(r_solution.abs)
|
|
392
402
|
|
|
393
403
|
rescue NotImplementedError
|
|
394
404
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
405
|
+
raise
|
|
395
406
|
end
|
|
396
407
|
end
|
|
397
408
|
|
|
@@ -416,6 +427,7 @@ describe "math" do
|
|
|
416
427
|
|
|
417
428
|
rescue NotImplementedError
|
|
418
429
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
430
|
+
raise
|
|
419
431
|
end
|
|
420
432
|
end
|
|
421
433
|
|
|
@@ -444,6 +456,7 @@ describe "math" do
|
|
|
444
456
|
|
|
445
457
|
rescue NotImplementedError
|
|
446
458
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
459
|
+
raise
|
|
447
460
|
end
|
|
448
461
|
end
|
|
449
462
|
end
|
|
@@ -461,7 +474,7 @@ describe "math" do
|
|
|
461
474
|
end
|
|
462
475
|
|
|
463
476
|
it "should correctly invert a matrix in place (bang)" do
|
|
464
|
-
pending("not yet implemented for :object dtype") if dtype == :object
|
|
477
|
+
pending("not yet implemented for :object dtype") if dtype == :object && defined?(NMatrix::LAPACKE)
|
|
465
478
|
a = NMatrix.new(:dense, 5, [1, 8,-9, 7, 5,
|
|
466
479
|
0, 1, 0, 4, 4,
|
|
467
480
|
0, 0, 1, 2, 5,
|
|
@@ -529,6 +542,7 @@ describe "math" do
|
|
|
529
542
|
expect(a.dot(a.pinv)).to be_within(err).of(b)
|
|
530
543
|
rescue NotImplementedError
|
|
531
544
|
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
545
|
+
raise
|
|
532
546
|
end
|
|
533
547
|
|
|
534
548
|
else
|
|
@@ -539,6 +553,7 @@ describe "math" do
|
|
|
539
553
|
expect(a.dot(a.pinv)).to be_within(err).of(b)
|
|
540
554
|
rescue NotImplementedError
|
|
541
555
|
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
556
|
+
raise
|
|
542
557
|
end
|
|
543
558
|
end
|
|
544
559
|
end
|
|
@@ -556,6 +571,7 @@ describe "math" do
|
|
|
556
571
|
expect(b.dot(a.dot(b))).to be_within(err).of(b)
|
|
557
572
|
rescue NotImplementedError
|
|
558
573
|
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
574
|
+
raise
|
|
559
575
|
end
|
|
560
576
|
|
|
561
577
|
else
|
|
@@ -567,6 +583,7 @@ describe "math" do
|
|
|
567
583
|
expect(b.dot(a.dot(b))).to be_within(err).of(b)
|
|
568
584
|
rescue NotImplementedError
|
|
569
585
|
pending "Suppressing a NotImplementedError when the atlas plugin is not available"
|
|
586
|
+
raise
|
|
570
587
|
end
|
|
571
588
|
end
|
|
572
589
|
end
|
|
@@ -1134,7 +1151,6 @@ describe "math" do
|
|
|
1134
1151
|
expect(@c.det).to be_within(@err).of(-18)
|
|
1135
1152
|
end
|
|
1136
1153
|
it "computes the exact determinant of 2x2 matrix" do
|
|
1137
|
-
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1138
1154
|
if dtype == :byte
|
|
1139
1155
|
expect{@a.det_exact}.to raise_error(DataTypeError)
|
|
1140
1156
|
else
|
|
@@ -1166,7 +1182,6 @@ describe "math" do
|
|
|
1166
1182
|
end
|
|
1167
1183
|
|
|
1168
1184
|
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
1185
|
if integer_dtype? dtype
|
|
1171
1186
|
expect{@m.scale 2.0}.to raise_error(DataTypeError)
|
|
1172
1187
|
else
|
|
@@ -1178,7 +1193,6 @@ describe "math" do
|
|
|
1178
1193
|
end
|
|
1179
1194
|
|
|
1180
1195
|
it "scales the matrix in place by a given factor" do
|
|
1181
|
-
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1182
1196
|
if dtype == :int8
|
|
1183
1197
|
expect{@m.scale! 2}.to raise_error(DataTypeError)
|
|
1184
1198
|
else
|
|
@@ -1196,7 +1210,6 @@ describe "math" do
|
|
|
1196
1210
|
context "matrix_norm" do
|
|
1197
1211
|
ALL_DTYPES.each do |dtype|
|
|
1198
1212
|
context dtype do
|
|
1199
|
-
pending("not yet implemented for :object dtype") if dtype == :object
|
|
1200
1213
|
before do
|
|
1201
1214
|
@n = NMatrix.new([3,3], [-4,-3,-2,
|
|
1202
1215
|
-1, 0, 1,
|
|
@@ -1215,6 +1228,7 @@ describe "math" do
|
|
|
1215
1228
|
|
|
1216
1229
|
rescue NotImplementedError
|
|
1217
1230
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1231
|
+
raise
|
|
1218
1232
|
end
|
|
1219
1233
|
end
|
|
1220
1234
|
end
|
|
@@ -1240,6 +1254,7 @@ describe "math" do
|
|
|
1240
1254
|
expect(@n.matrix_norm(-2)).to be_within(@matrix_norm_TOLERANCE).of(0.0)
|
|
1241
1255
|
rescue NotImplementedError
|
|
1242
1256
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1257
|
+
raise
|
|
1243
1258
|
end
|
|
1244
1259
|
expect(@n.matrix_norm(-1)).to eq(6)
|
|
1245
1260
|
end
|
|
@@ -1293,6 +1308,7 @@ describe "math" do
|
|
|
1293
1308
|
|
|
1294
1309
|
rescue NotImplementedError
|
|
1295
1310
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1311
|
+
raise
|
|
1296
1312
|
end
|
|
1297
1313
|
end
|
|
1298
1314
|
|
|
@@ -1308,6 +1324,7 @@ describe "math" do
|
|
|
1308
1324
|
|
|
1309
1325
|
rescue NotImplementedError
|
|
1310
1326
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1327
|
+
raise
|
|
1311
1328
|
end
|
|
1312
1329
|
end
|
|
1313
1330
|
|
|
@@ -1323,6 +1340,7 @@ describe "math" do
|
|
|
1323
1340
|
|
|
1324
1341
|
rescue NotImplementedError
|
|
1325
1342
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1343
|
+
raise
|
|
1326
1344
|
end
|
|
1327
1345
|
end
|
|
1328
1346
|
|
|
@@ -1338,6 +1356,7 @@ describe "math" do
|
|
|
1338
1356
|
|
|
1339
1357
|
rescue NotImplementedError
|
|
1340
1358
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1359
|
+
raise
|
|
1341
1360
|
end
|
|
1342
1361
|
end
|
|
1343
1362
|
|
|
@@ -1353,6 +1372,7 @@ describe "math" do
|
|
|
1353
1372
|
|
|
1354
1373
|
rescue NotImplementedError
|
|
1355
1374
|
pending "Suppressing a NotImplementedError when the lapacke plugin is not available"
|
|
1375
|
+
raise
|
|
1356
1376
|
end
|
|
1357
1377
|
end
|
|
1358
1378
|
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe NMatrix do
|
|
4
|
+
def force_gc
|
|
5
|
+
20.times do
|
|
6
|
+
Array.new(1_000) { |i| "gc-pressure-#{i}" }
|
|
7
|
+
GC.start
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def build_dense_object_reference
|
|
12
|
+
values = Array.new(64 * 64) { |i| "dense-object-#{i}" }
|
|
13
|
+
matrix = NMatrix.new([64, 64], values, stype: :dense, dtype: :object)
|
|
14
|
+
|
|
15
|
+
matrix[50...64, 45...64]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def build_yale_object_reference
|
|
19
|
+
rng = Random.new(5678)
|
|
20
|
+
matrix = NMatrix.new([35, 35], nil, stype: :yale, dtype: :object, capacity: 1)
|
|
21
|
+
|
|
22
|
+
700.times do |i|
|
|
23
|
+
matrix[rng.rand(35), rng.rand(35)] = "yale-object-#{i}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
matrix[3...30, 4...32]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def build_nested_yale_object_reference
|
|
30
|
+
rng = Random.new(6789)
|
|
31
|
+
matrix = NMatrix.new([45, 45], nil, stype: :yale, dtype: :object, capacity: 1)
|
|
32
|
+
|
|
33
|
+
1_000.times do |i|
|
|
34
|
+
matrix[rng.rand(45), rng.rand(45)] = "nested-yale-object-#{i}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
matrix[5...40, 6...39][7...28, 8...30]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def build_list_object_reference
|
|
41
|
+
matrix = NMatrix.new([30, 30], nil, stype: :list, dtype: :object)
|
|
42
|
+
|
|
43
|
+
30.times do |i|
|
|
44
|
+
matrix[i, (i * 7) % 30] = "list-object-#{i}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
matrix[4...28, 2...29]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def mutate_dense_object_matrix_without_external_references
|
|
51
|
+
rng = Random.new(555)
|
|
52
|
+
matrix = NMatrix.new([80, 80], nil, stype: :dense, dtype: :object)
|
|
53
|
+
|
|
54
|
+
5_000.times do |i|
|
|
55
|
+
matrix[rng.rand(80), rng.rand(80)] = "mut-dense-#{i}"
|
|
56
|
+
GC.start if (i % 25).zero?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
matrix
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def mutate_yale_object_matrix_without_external_references
|
|
63
|
+
rng = Random.new(333)
|
|
64
|
+
matrix = NMatrix.new([80, 80], nil, stype: :yale, dtype: :object, capacity: 1)
|
|
65
|
+
|
|
66
|
+
5_000.times do |i|
|
|
67
|
+
matrix[rng.rand(80), rng.rand(80)] = "mut-yale-#{i}"
|
|
68
|
+
GC.start if (i % 25).zero?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
matrix
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def mutate_list_object_matrix_without_external_references
|
|
75
|
+
rng = Random.new(888)
|
|
76
|
+
matrix = NMatrix.new([30, 30], nil, stype: :list, dtype: :object)
|
|
77
|
+
|
|
78
|
+
500.times do |i|
|
|
79
|
+
matrix[rng.rand(30), rng.rand(30)] = "mut-list-#{i}"
|
|
80
|
+
GC.start if (i % 10).zero?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
matrix
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def touch_reference(reference)
|
|
87
|
+
reference.each_stored_with_indices do |value, _i, _j|
|
|
88
|
+
value.to_s.hash
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
specify do
|
|
93
|
+
200.times do |i|
|
|
94
|
+
size = rand(500..1000)
|
|
95
|
+
m1 = NMatrix.new([size, size], 0, stype: :yale, dtype: :int32)
|
|
96
|
+
m2 = m1.clone
|
|
97
|
+
|
|
98
|
+
rand(1000).times do |j|
|
|
99
|
+
m1[rand(size), rand(size)] = 1
|
|
100
|
+
m2[rand(size), rand(size)] = 1
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
(m1*m2).det
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
specify "does not segfault when iterating a GC-stressed object Yale reference" do
|
|
108
|
+
reference = build_yale_object_reference
|
|
109
|
+
|
|
110
|
+
force_gc
|
|
111
|
+
|
|
112
|
+
touch_reference(reference)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
specify "does not segfault when iterating a GC-stressed nested object Yale reference" do
|
|
116
|
+
reference = build_nested_yale_object_reference
|
|
117
|
+
|
|
118
|
+
force_gc
|
|
119
|
+
|
|
120
|
+
touch_reference(reference)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
specify "does not segfault when iterating a GC-stressed object dense reference" do
|
|
124
|
+
reference = build_dense_object_reference
|
|
125
|
+
|
|
126
|
+
force_gc
|
|
127
|
+
|
|
128
|
+
reference.each_with_indices do |value, _i, _j|
|
|
129
|
+
value.to_s.hash
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
specify "does not segfault when iterating a GC-stressed object list reference" do
|
|
134
|
+
reference = build_list_object_reference
|
|
135
|
+
|
|
136
|
+
force_gc
|
|
137
|
+
|
|
138
|
+
touch_reference(reference)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
specify "does not segfault after GC-stressed object dense mutation" do
|
|
142
|
+
matrix = mutate_dense_object_matrix_without_external_references
|
|
143
|
+
|
|
144
|
+
force_gc
|
|
145
|
+
|
|
146
|
+
matrix.each do |value|
|
|
147
|
+
value.to_s.hash
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
specify "does not segfault after GC-stressed object Yale mutation" do
|
|
152
|
+
matrix = mutate_yale_object_matrix_without_external_references
|
|
153
|
+
|
|
154
|
+
force_gc
|
|
155
|
+
|
|
156
|
+
touch_reference(matrix)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
specify "does not segfault after GC-stressed object list mutation" do
|
|
160
|
+
matrix = mutate_list_object_matrix_without_external_references
|
|
161
|
+
|
|
162
|
+
force_gc
|
|
163
|
+
|
|
164
|
+
touch_reference(matrix)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
specify "does not expose partially built Yale object storage during a cast" do
|
|
168
|
+
previous_gc_stress = GC.stress
|
|
169
|
+
GC.stress = true
|
|
170
|
+
|
|
171
|
+
current_stock = NMatrix.new([30, 1], 0, stype: :yale, dtype: :float64)
|
|
172
|
+
current_stock[3] = -4
|
|
173
|
+
current_stock[7] = 10
|
|
174
|
+
current_stock[11] = 50
|
|
175
|
+
|
|
176
|
+
quantity_made = (current_stock < 0).cast(dtype: :int32) * current_stock * -1
|
|
177
|
+
expect(quantity_made[3]).to eq(4)
|
|
178
|
+
ensure
|
|
179
|
+
GC.stress = previous_gc_stress
|
|
180
|
+
end
|
|
181
|
+
end
|