pnmatrix 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/ext/nmatrix/binary_format.txt +53 -0
  3. data/ext/nmatrix/data/complex.h +388 -0
  4. data/ext/nmatrix/data/data.cpp +274 -0
  5. data/ext/nmatrix/data/data.h +651 -0
  6. data/ext/nmatrix/data/meta.h +64 -0
  7. data/ext/nmatrix/data/ruby_object.h +386 -0
  8. data/ext/nmatrix/extconf.rb +70 -0
  9. data/ext/nmatrix/math/asum.h +99 -0
  10. data/ext/nmatrix/math/cblas_enums.h +36 -0
  11. data/ext/nmatrix/math/cblas_templates_core.h +507 -0
  12. data/ext/nmatrix/math/gemm.h +241 -0
  13. data/ext/nmatrix/math/gemv.h +178 -0
  14. data/ext/nmatrix/math/getrf.h +255 -0
  15. data/ext/nmatrix/math/getrs.h +121 -0
  16. data/ext/nmatrix/math/imax.h +82 -0
  17. data/ext/nmatrix/math/laswp.h +165 -0
  18. data/ext/nmatrix/math/long_dtype.h +62 -0
  19. data/ext/nmatrix/math/magnitude.h +54 -0
  20. data/ext/nmatrix/math/math.h +751 -0
  21. data/ext/nmatrix/math/nrm2.h +165 -0
  22. data/ext/nmatrix/math/rot.h +117 -0
  23. data/ext/nmatrix/math/rotg.h +106 -0
  24. data/ext/nmatrix/math/scal.h +71 -0
  25. data/ext/nmatrix/math/trsm.h +336 -0
  26. data/ext/nmatrix/math/util.h +162 -0
  27. data/ext/nmatrix/math.cpp +1368 -0
  28. data/ext/nmatrix/nm_memory.h +60 -0
  29. data/ext/nmatrix/nmatrix.cpp +285 -0
  30. data/ext/nmatrix/nmatrix.h +476 -0
  31. data/ext/nmatrix/ruby_constants.cpp +151 -0
  32. data/ext/nmatrix/ruby_constants.h +106 -0
  33. data/ext/nmatrix/ruby_nmatrix.c +3130 -0
  34. data/ext/nmatrix/storage/common.cpp +77 -0
  35. data/ext/nmatrix/storage/common.h +183 -0
  36. data/ext/nmatrix/storage/dense/dense.cpp +1096 -0
  37. data/ext/nmatrix/storage/dense/dense.h +129 -0
  38. data/ext/nmatrix/storage/list/list.cpp +1628 -0
  39. data/ext/nmatrix/storage/list/list.h +138 -0
  40. data/ext/nmatrix/storage/storage.cpp +730 -0
  41. data/ext/nmatrix/storage/storage.h +99 -0
  42. data/ext/nmatrix/storage/yale/class.h +1139 -0
  43. data/ext/nmatrix/storage/yale/iterators/base.h +143 -0
  44. data/ext/nmatrix/storage/yale/iterators/iterator.h +131 -0
  45. data/ext/nmatrix/storage/yale/iterators/row.h +450 -0
  46. data/ext/nmatrix/storage/yale/iterators/row_stored.h +140 -0
  47. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +169 -0
  48. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +124 -0
  49. data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
  50. data/ext/nmatrix/storage/yale/yale.cpp +2074 -0
  51. data/ext/nmatrix/storage/yale/yale.h +203 -0
  52. data/ext/nmatrix/types.h +55 -0
  53. data/ext/nmatrix/util/io.cpp +279 -0
  54. data/ext/nmatrix/util/io.h +115 -0
  55. data/ext/nmatrix/util/sl_list.cpp +627 -0
  56. data/ext/nmatrix/util/sl_list.h +144 -0
  57. data/ext/nmatrix/util/util.h +78 -0
  58. data/lib/nmatrix/blas.rb +378 -0
  59. data/lib/nmatrix/cruby/math.rb +744 -0
  60. data/lib/nmatrix/enumerate.rb +253 -0
  61. data/lib/nmatrix/homogeneous.rb +241 -0
  62. data/lib/nmatrix/io/fortran_format.rb +138 -0
  63. data/lib/nmatrix/io/harwell_boeing.rb +221 -0
  64. data/lib/nmatrix/io/market.rb +263 -0
  65. data/lib/nmatrix/io/point_cloud.rb +189 -0
  66. data/lib/nmatrix/jruby/decomposition.rb +24 -0
  67. data/lib/nmatrix/jruby/enumerable.rb +13 -0
  68. data/lib/nmatrix/jruby/error.rb +4 -0
  69. data/lib/nmatrix/jruby/math.rb +501 -0
  70. data/lib/nmatrix/jruby/nmatrix_java.rb +840 -0
  71. data/lib/nmatrix/jruby/operators.rb +283 -0
  72. data/lib/nmatrix/jruby/slice.rb +264 -0
  73. data/lib/nmatrix/lapack_core.rb +181 -0
  74. data/lib/nmatrix/lapack_plugin.rb +44 -0
  75. data/lib/nmatrix/math.rb +953 -0
  76. data/lib/nmatrix/mkmf.rb +100 -0
  77. data/lib/nmatrix/monkeys.rb +137 -0
  78. data/lib/nmatrix/nmatrix.rb +1172 -0
  79. data/lib/nmatrix/rspec.rb +75 -0
  80. data/lib/nmatrix/shortcuts.rb +1163 -0
  81. data/lib/nmatrix/version.rb +39 -0
  82. data/lib/nmatrix/yale_functions.rb +118 -0
  83. data/lib/nmatrix.rb +28 -0
  84. data/spec/00_nmatrix_spec.rb +892 -0
  85. data/spec/01_enum_spec.rb +196 -0
  86. data/spec/02_slice_spec.rb +407 -0
  87. data/spec/03_nmatrix_monkeys_spec.rb +80 -0
  88. data/spec/2x2_dense_double.mat +0 -0
  89. data/spec/4x4_sparse.mat +0 -0
  90. data/spec/4x5_dense.mat +0 -0
  91. data/spec/blas_spec.rb +215 -0
  92. data/spec/elementwise_spec.rb +311 -0
  93. data/spec/homogeneous_spec.rb +100 -0
  94. data/spec/io/fortran_format_spec.rb +88 -0
  95. data/spec/io/harwell_boeing_spec.rb +98 -0
  96. data/spec/io/test.rua +9 -0
  97. data/spec/io_spec.rb +159 -0
  98. data/spec/lapack_core_spec.rb +482 -0
  99. data/spec/leakcheck.rb +16 -0
  100. data/spec/math_spec.rb +1363 -0
  101. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  102. data/spec/nmatrix_yale_spec.rb +286 -0
  103. data/spec/rspec_monkeys.rb +56 -0
  104. data/spec/rspec_spec.rb +35 -0
  105. data/spec/shortcuts_spec.rb +474 -0
  106. data/spec/slice_set_spec.rb +162 -0
  107. data/spec/spec_helper.rb +172 -0
  108. data/spec/stat_spec.rb +214 -0
  109. data/spec/test.pcd +20 -0
  110. data/spec/utm5940.mtx +83844 -0
  111. metadata +295 -0
@@ -0,0 +1,482 @@
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
+ # == lapack_core_spec.rb
24
+ #
25
+ # Tests for LAPACK functions that have internal implementations (i.e. they
26
+ # don't rely on external libraries) and also functions that are implemented
27
+ # by both nmatrix-atlas and nmatrix-lapacke. These tests will also be run for the
28
+ # plugins that do use external libraries, since they will override the
29
+ # internal implmentations.
30
+ #
31
+
32
+ require 'spec_helper'
33
+
34
+ describe "NMatrix::LAPACK functions with internal implementations" do
35
+ # where integer math is allowed
36
+ [:byte, :int8, :int16, :int32, :int64, :float32, :float64, :complex64, :complex128].each do |dtype|
37
+ context dtype do
38
+ # This spec seems a little weird. It looks like laswp ignores the last
39
+ # element of piv, though maybe I misunderstand smth. It would make
40
+ # more sense if piv were [2,1,3,3]
41
+ it "exposes clapack laswp" do
42
+ a = NMatrix.new(:dense, [3,4], [1,2,3,4,5,6,7,8,9,10,11,12], dtype)
43
+ NMatrix::LAPACK::clapack_laswp(3, a, 4, 0, 3, [2,1,3,0], 1)
44
+ b = NMatrix.new(:dense, [3,4], [3,2,4,1,7,6,8,5,11,10,12,9], dtype)
45
+ expect(a).to eq(b)
46
+ end
47
+
48
+ # This spec is OK, because the default behavior for permute_columns
49
+ # is :intuitive, which is different from :lapack (default laswp behavior)
50
+ it "exposes NMatrix#permute_columns and #permute_columns! (user-friendly laswp)" do
51
+ a = NMatrix.new(:dense, [3,4], [1,2,3,4,5,6,7,8,9,10,11,12], dtype)
52
+ b = NMatrix.new(:dense, [3,4], [3,2,4,1,7,6,8,5,11,10,12,9], dtype)
53
+ piv = [2,1,3,0]
54
+ r = a.permute_columns(piv)
55
+ expect(r).not_to eq(a)
56
+ expect(r).to eq(b)
57
+ a.permute_columns!(piv)
58
+ expect(a).to eq(b)
59
+ end
60
+ end
61
+ end
62
+
63
+ # where integer math is not allowed
64
+ [:float32, :float64, :complex64, :complex128].each do |dtype|
65
+ context dtype do
66
+
67
+ # clapack_getrf performs a LU decomposition, but unlike the
68
+ # standard LAPACK getrf, it's the upper matrix that has unit diagonals
69
+ # and the permutation is done in columns not rows. See the code for
70
+ # details.
71
+ # Also the rows in the pivot vector are indexed starting from 0,
72
+ # rather than 1 as in LAPACK
73
+ it "calculates LU decomposition using clapack_getrf (row-major, square)" do
74
+ a = NMatrix.new(3, [4,9,2,3,5,7,8,1,6], dtype: dtype)
75
+ ipiv = NMatrix::LAPACK::clapack_getrf(:row, a.shape[0], a.shape[1], a, a.shape[1])
76
+ b = NMatrix.new(3,[9, 2.0/9, 4.0/9,
77
+ 5, 53.0/9, 7.0/53,
78
+ 1, 52.0/9, 360.0/53], dtype: dtype)
79
+ ipiv_true = [1,2,2]
80
+
81
+ # delta varies for different dtypes
82
+ err = case dtype
83
+ when :float32, :complex64
84
+ 1e-6
85
+ when :float64, :complex128
86
+ 1e-15
87
+ end
88
+
89
+ expect(a).to be_within(err).of(b)
90
+ expect(ipiv).to eq(ipiv_true)
91
+ end
92
+
93
+ it "calculates LU decomposition using clapack_getrf (row-major, rectangular)" do
94
+ a = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype)
95
+ ipiv = NMatrix::LAPACK::clapack_getrf(:row, a.shape[0], a.shape[1], a, a.shape[1])
96
+ #we can't use GETRF_SOLUTION_ARRAY here, because of the different
97
+ #conventions of clapack_getrf
98
+ b = NMatrix.new([3,4],[10.0, -0.1, 0.0, 0.4,
99
+ 3.0, 9.3, 20.0/93, 38.0/93,
100
+ 1.0, 7.1, 602.0/93, 251.0/602], dtype: dtype)
101
+ ipiv_true = [2,2,2]
102
+
103
+ # delta varies for different dtypes
104
+ err = case dtype
105
+ when :float32, :complex64
106
+ 1e-6
107
+ when :float64, :complex128
108
+ 1e-15
109
+ end
110
+
111
+ expect(a).to be_within(err).of(b)
112
+ expect(ipiv).to eq(ipiv_true)
113
+ end
114
+
115
+ #Normally we wouldn't check column-major routines, since all our matrices
116
+ #are row-major, but we use the column-major version in #getrf!, so we
117
+ #want to test it here.
118
+ it "calculates LU decomposition using clapack_getrf (col-major, rectangular)" do
119
+ #this is supposed to represent the 3x2 matrix
120
+ # -1 2
121
+ # 0 3
122
+ # 1 -2
123
+ a = NMatrix.new([1,6], [-1,0,1,2,3,-2], dtype: dtype)
124
+ ipiv = NMatrix::LAPACK::clapack_getrf(:col, 3, 2, a, 3)
125
+ b = NMatrix.new([1,6], [-1,0,-1,2,3,0], dtype: dtype)
126
+ ipiv_true = [0,1]
127
+
128
+ # delta varies for different dtypes
129
+ err = case dtype
130
+ when :float32, :complex64
131
+ 1e-6
132
+ when :float64, :complex128
133
+ 1e-15
134
+ end
135
+
136
+ expect(a).to be_within(err).of(b)
137
+ expect(ipiv).to eq(ipiv_true)
138
+ end
139
+
140
+ it "calculates LU decomposition using #getrf! (rectangular)" do
141
+ a = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype)
142
+ ipiv = a.getrf!
143
+ b = NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype)
144
+ ipiv_true = [2,3,3]
145
+
146
+ # delta varies for different dtypes
147
+ err = case dtype
148
+ when :float32, :complex64
149
+ 1e-6
150
+ when :float64, :complex128
151
+ 1e-14
152
+ end
153
+
154
+ expect(a).to be_within(err).of(b)
155
+ expect(ipiv).to eq(ipiv_true)
156
+ end
157
+
158
+ it "calculates LU decomposition using #getrf! (square)" do
159
+ a = NMatrix.new([4,4], [0,1,2,3, 1,1,1,1, 0,-1,-2,0, 0,2,0,2], dtype: dtype)
160
+ ipiv = a.getrf!
161
+
162
+ b = NMatrix.new([4,4], [1,1,1,1, 0,2,0,2, 0,-0.5,-2,1, 0,0.5,-1,3], dtype: dtype)
163
+ ipiv_true = [2,4,3,4]
164
+
165
+ expect(a).to eq(b)
166
+ expect(ipiv).to eq(ipiv_true)
167
+ end
168
+
169
+ # Together, these calls are basically xGESV from LAPACK: http://www.netlib.org/lapack/double/dgesv.f
170
+ it "exposes clapack_getrs" do
171
+ a = NMatrix.new(3, [-2,4,-3, 3,-2,1, 0,-4,3], dtype: dtype)
172
+ ipiv = NMatrix::LAPACK::clapack_getrf(:row, 3, 3, a, 3)
173
+ b = NMatrix.new([3,1], [-1, 17, -9], dtype: dtype)
174
+
175
+ NMatrix::LAPACK::clapack_getrs(:row, false, 3, 1, a, 3, ipiv, b, 3)
176
+
177
+ expect(b[0]).to eq(5)
178
+ expect(b[1]).to eq(-15.0/2)
179
+ expect(b[2]).to eq(-13)
180
+ end
181
+
182
+ it "solves matrix equation (non-vector rhs) using clapack_getrs" do
183
+ a = NMatrix.new(3, [-2,4,-3, 3,-2,1, 0,-4,3], dtype: dtype)
184
+ b = NMatrix.new([3,2], [-1,2, 17,1, -9,-4], dtype: dtype)
185
+
186
+ n = a.shape[0]
187
+ nrhs = b.shape[1]
188
+
189
+ ipiv = NMatrix::LAPACK::clapack_getrf(:row, n, n, a, n)
190
+ # Even though we pass :row to clapack_getrs, it still interprets b as
191
+ # column-major, so need to transpose b before and after:
192
+ b = b.transpose
193
+ NMatrix::LAPACK::clapack_getrs(:row, false, n, nrhs, a, n, ipiv, b, n)
194
+ b = b.transpose
195
+
196
+ b_true = NMatrix.new([3,2], [5,1, -7.5,1, -13,0], dtype: dtype)
197
+ expect(b).to eq(b_true)
198
+ end
199
+
200
+ #posv is like potrf+potrs
201
+ #posv is implemented in both nmatrix-atlas and nmatrix-lapacke, so the spec
202
+ #needs to be shared here
203
+ it "solves a (symmetric positive-definite) matrix equation using posv (vector rhs)" do
204
+ a = NMatrix.new(3, [4, 0,-1,
205
+ 0, 2, 1,
206
+ 0, 0, 1], dtype: dtype)
207
+ b = NMatrix.new([3,1], [4,2,0], dtype: dtype)
208
+
209
+ begin
210
+ x = NMatrix::LAPACK::posv(:upper, a, b)
211
+ rescue NotImplementedError => e
212
+ pending e.to_s
213
+ end
214
+
215
+ x_true = NMatrix.new([3,1], [1, 1, 0], dtype: dtype)
216
+
217
+ err = case dtype
218
+ when :float32, :complex64
219
+ 1e-5
220
+ when :float64, :complex128
221
+ 1e-14
222
+ end
223
+
224
+ expect(x).to be_within(err).of(x_true)
225
+ end
226
+
227
+ it "solves a (symmetric positive-definite) matrix equation using posv (non-vector rhs)" do
228
+ a = NMatrix.new(3, [4, 0,-1,
229
+ 0, 2, 1,
230
+ 0, 0, 1], dtype: dtype)
231
+ b = NMatrix.new([3,2], [4,-1, 2,-1, 0,0], dtype: dtype)
232
+
233
+ begin
234
+ x = NMatrix::LAPACK::posv(:upper, a, b)
235
+ rescue NotImplementedError => e
236
+ pending e.to_s
237
+ end
238
+
239
+ x_true = NMatrix.new([3,2], [1,0, 1,-1, 0,1], dtype: dtype)
240
+
241
+ err = case dtype
242
+ when :float32, :complex64
243
+ 1e-5
244
+ when :float64, :complex128
245
+ 1e-14
246
+ end
247
+
248
+ expect(x).to be_within(err).of(x_true)
249
+ end
250
+
251
+ it "calculates the singular value decomposition with NMatrix#gesvd" do
252
+ #example from Wikipedia
253
+ m = 4
254
+ n = 5
255
+ mn_min = [m,n].min
256
+ a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype)
257
+
258
+ begin
259
+ u, s, vt = a.gesvd
260
+ rescue NotImplementedError => e
261
+ pending e.to_s
262
+ end
263
+
264
+ s_true = NMatrix.new([mn_min,1], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype)
265
+ u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype)
266
+ vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype)
267
+
268
+ err = case dtype
269
+ when :float32, :complex64
270
+ 1e-5
271
+ when :float64, :complex128
272
+ 1e-14
273
+ end
274
+
275
+ expect(s).to be_within(err).of(s_true)
276
+ expect(u).to be_within(err).of(u_true)
277
+ expect(vt).to be_within(err).of(vt_true)
278
+
279
+ expect(s.dtype).to eq(a.abs_dtype)
280
+ expect(u.dtype).to eq(dtype)
281
+ expect(vt.dtype).to eq(dtype)
282
+ end
283
+
284
+ it "calculates the singular value decomposition with NMatrix#gesdd" do
285
+ #example from Wikipedia
286
+ m = 4
287
+ n = 5
288
+ mn_min = [m,n].min
289
+ a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype)
290
+
291
+ begin
292
+ u, s, vt = a.gesdd
293
+ rescue NotImplementedError => e
294
+ pending e.to_s
295
+ end
296
+
297
+ s_true = NMatrix.new([mn_min,1], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype)
298
+ u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype)
299
+ vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype)
300
+
301
+ err = case dtype
302
+ when :float32, :complex64
303
+ 1e-5
304
+ when :float64, :complex128
305
+ 1e-14
306
+ end
307
+
308
+ expect(s).to be_within(err).of(s_true)
309
+ expect(u).to be_within(err).of(u_true)
310
+ expect(vt).to be_within(err).of(vt_true)
311
+ end
312
+
313
+
314
+ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (real matrix, complex eigenvalues)" do
315
+ n = 3
316
+ a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype)
317
+
318
+ begin
319
+ eigenvalues, vl, vr = NMatrix::LAPACK.geev(a)
320
+ rescue NotImplementedError => e
321
+ pending e.to_s
322
+ end
323
+
324
+ eigenvalues_true = NMatrix.new([n,1], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64))
325
+ vr_true = NMatrix.new([n,n],[0,0,1,
326
+ 2/Math.sqrt(6),2/Math.sqrt(6),0,
327
+ Complex(1,-1)/Math.sqrt(6),Complex(1,1)/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64))
328
+ vl_true = NMatrix.new([n,n],[0,0,1,
329
+ Complex(-1,1)/Math.sqrt(6),Complex(-1,-1)/Math.sqrt(6),0,
330
+ 2/Math.sqrt(6),2/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64))
331
+
332
+ err = case dtype
333
+ when :float32, :complex64
334
+ 1e-6
335
+ when :float64, :complex128
336
+ 1e-15
337
+ end
338
+
339
+ expect(eigenvalues).to be_within(err).of(eigenvalues_true)
340
+ expect(vr).to be_within(err).of(vr_true)
341
+ expect(vl).to be_within(err).of(vl_true)
342
+
343
+ expect(eigenvalues.dtype).to eq(NMatrix.upcast(dtype, :complex64))
344
+ expect(vr.dtype).to eq(NMatrix.upcast(dtype, :complex64))
345
+ expect(vl.dtype).to eq(NMatrix.upcast(dtype, :complex64))
346
+ end
347
+
348
+ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (real matrix, real eigenvalues)" do
349
+ n = 3
350
+ a = NMatrix.new([n,n], [2,0,0, 0,3,2, 0,1,2], dtype: dtype)
351
+
352
+ begin
353
+ eigenvalues, vl, vr = NMatrix::LAPACK.geev(a)
354
+ rescue NotImplementedError => e
355
+ pending e.to_s
356
+ end
357
+
358
+ eigenvalues_true = NMatrix.new([n,1], [1, 4, 2], dtype: dtype)
359
+
360
+ # For some reason, some of the eigenvectors have different signs
361
+ # when we use the complex versions of geev. This is totally fine, since
362
+ # they are still normalized eigenvectors even with the sign flipped.
363
+ if a.complex_dtype?
364
+ vr_true = NMatrix.new([n,n],[0,0,1,
365
+ 1/Math.sqrt(2),2/Math.sqrt(5),0,
366
+ -1/Math.sqrt(2),1/Math.sqrt(5),0], dtype: dtype)
367
+ vl_true = NMatrix.new([n,n],[0,0,1,
368
+ -1/Math.sqrt(5),1/Math.sqrt(2),0,
369
+ 2/Math.sqrt(5),1/Math.sqrt(2),0], dtype: dtype)
370
+ else
371
+ vr_true = NMatrix.new([n,n],[0,0,1,
372
+ 1/Math.sqrt(2),-2/Math.sqrt(5),0,
373
+ -1/Math.sqrt(2),-1/Math.sqrt(5),0], dtype: dtype)
374
+ vl_true = NMatrix.new([n,n],[0,0,1,
375
+ 1/Math.sqrt(5),-1/Math.sqrt(2),0,
376
+ -2/Math.sqrt(5),-1/Math.sqrt(2),0], dtype: dtype)
377
+ end
378
+
379
+ err = case dtype
380
+ when :float32, :complex64
381
+ 1e-6
382
+ when :float64, :complex128
383
+ 1e-15
384
+ end
385
+
386
+ expect(eigenvalues).to be_within(err).of(eigenvalues_true)
387
+ expect(vr).to be_within(err).of(vr_true)
388
+ expect(vl).to be_within(err).of(vl_true)
389
+
390
+ expect(eigenvalues.dtype).to eq(dtype)
391
+ expect(vr.dtype).to eq(dtype)
392
+ expect(vl.dtype).to eq(dtype)
393
+ end
394
+
395
+ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (left eigenvectors only)" do
396
+ n = 3
397
+ a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype)
398
+
399
+ begin
400
+ eigenvalues, vl = NMatrix::LAPACK.geev(a, :left)
401
+ rescue NotImplementedError => e
402
+ pending e.to_s
403
+ end
404
+
405
+ eigenvalues_true = NMatrix.new([n,1], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64))
406
+ vl_true = NMatrix.new([n,n],[0,0,1,
407
+ Complex(-1,1)/Math.sqrt(6),Complex(-1,-1)/Math.sqrt(6),0,
408
+ 2/Math.sqrt(6),2/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64))
409
+
410
+ err = case dtype
411
+ when :float32, :complex64
412
+ 1e-6
413
+ when :float64, :complex128
414
+ 1e-15
415
+ end
416
+
417
+ expect(eigenvalues).to be_within(err).of(eigenvalues_true)
418
+ expect(vl).to be_within(err).of(vl_true)
419
+ end
420
+
421
+ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (right eigenvectors only)" do
422
+ n = 3
423
+ a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype)
424
+
425
+ begin
426
+ eigenvalues, vr = NMatrix::LAPACK.geev(a, :right)
427
+ rescue NotImplementedError => e
428
+ pending e.to_s
429
+ end
430
+
431
+ eigenvalues_true = NMatrix.new([n,1], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64))
432
+ vr_true = NMatrix.new([n,n],[0,0,1,
433
+ 2/Math.sqrt(6),2/Math.sqrt(6),0,
434
+ Complex(1,-1)/Math.sqrt(6),Complex(1,1)/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64))
435
+
436
+ err = case dtype
437
+ when :float32, :complex64
438
+ 1e-6
439
+ when :float64, :complex128
440
+ 1e-15
441
+ end
442
+
443
+ expect(eigenvalues).to be_within(err).of(eigenvalues_true)
444
+ expect(vr).to be_within(err).of(vr_true)
445
+ end
446
+ end
447
+ end
448
+
449
+ [:complex64, :complex128].each do |dtype|
450
+ context dtype do
451
+ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (complex matrix)" do
452
+ n = 3
453
+ a = NMatrix.new([n,n], [Complex(0,1),0,0, 0,3,2, 0,1,2], dtype: dtype)
454
+
455
+ begin
456
+ eigenvalues, vl, vr = NMatrix::LAPACK.geev(a)
457
+ rescue NotImplementedError => e
458
+ pending e.to_s
459
+ end
460
+
461
+ eigenvalues_true = NMatrix.new([n,1], [1, 4, Complex(0,1)], dtype: dtype)
462
+ vr_true = NMatrix.new([n,n],[0,0,1,
463
+ 1/Math.sqrt(2),2/Math.sqrt(5),0,
464
+ -1/Math.sqrt(2),1/Math.sqrt(5),0], dtype: dtype)
465
+ vl_true = NMatrix.new([n,n],[0,0,1,
466
+ -1/Math.sqrt(5),1/Math.sqrt(2),0,
467
+ 2/Math.sqrt(5),1/Math.sqrt(2),0], dtype: dtype)
468
+
469
+ err = case dtype
470
+ when :float32, :complex64
471
+ 1e-6
472
+ when :float64, :complex128
473
+ 1e-15
474
+ end
475
+
476
+ expect(eigenvalues).to be_within(err).of(eigenvalues_true)
477
+ expect(vr).to be_within(err).of(vr_true)
478
+ expect(vl).to be_within(err).of(vl_true)
479
+ end
480
+ end
481
+ end
482
+ end
data/spec/leakcheck.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "./lib/nmatrix"
2
+
3
+ # Fixed:
4
+ #n = NMatrix.new(:yale, [8,2], :int64)
5
+ #m = NMatrix.new(:yale, [2,8], :int64)
6
+ #100.times do
7
+ # n.dot(m)
8
+ #end
9
+ #GC.start
10
+
11
+ # Remaining:
12
+ 100.times do |t|
13
+ n = NMatrix.new(:dense, 1000, :float64)
14
+ n[0,t] = 1.0
15
+ puts n[t,0]
16
+ end