nmatrix-fftw 0.2.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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/ext/nmatrix/data/complex.h +388 -0
  3. data/ext/nmatrix/data/data.h +652 -0
  4. data/ext/nmatrix/data/meta.h +64 -0
  5. data/ext/nmatrix/data/ruby_object.h +389 -0
  6. data/ext/nmatrix/math/asum.h +120 -0
  7. data/ext/nmatrix/math/cblas_enums.h +36 -0
  8. data/ext/nmatrix/math/cblas_templates_core.h +507 -0
  9. data/ext/nmatrix/math/gemm.h +241 -0
  10. data/ext/nmatrix/math/gemv.h +178 -0
  11. data/ext/nmatrix/math/getrf.h +255 -0
  12. data/ext/nmatrix/math/getrs.h +121 -0
  13. data/ext/nmatrix/math/imax.h +79 -0
  14. data/ext/nmatrix/math/laswp.h +165 -0
  15. data/ext/nmatrix/math/long_dtype.h +49 -0
  16. data/ext/nmatrix/math/math.h +745 -0
  17. data/ext/nmatrix/math/nrm2.h +160 -0
  18. data/ext/nmatrix/math/rot.h +117 -0
  19. data/ext/nmatrix/math/rotg.h +106 -0
  20. data/ext/nmatrix/math/scal.h +71 -0
  21. data/ext/nmatrix/math/trsm.h +332 -0
  22. data/ext/nmatrix/math/util.h +148 -0
  23. data/ext/nmatrix/nm_memory.h +60 -0
  24. data/ext/nmatrix/nmatrix.h +438 -0
  25. data/ext/nmatrix/ruby_constants.h +106 -0
  26. data/ext/nmatrix/storage/common.h +177 -0
  27. data/ext/nmatrix/storage/dense/dense.h +129 -0
  28. data/ext/nmatrix/storage/list/list.h +138 -0
  29. data/ext/nmatrix/storage/storage.h +99 -0
  30. data/ext/nmatrix/storage/yale/class.h +1139 -0
  31. data/ext/nmatrix/storage/yale/iterators/base.h +143 -0
  32. data/ext/nmatrix/storage/yale/iterators/iterator.h +131 -0
  33. data/ext/nmatrix/storage/yale/iterators/row.h +450 -0
  34. data/ext/nmatrix/storage/yale/iterators/row_stored.h +140 -0
  35. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +169 -0
  36. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +124 -0
  37. data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
  38. data/ext/nmatrix/storage/yale/yale.h +203 -0
  39. data/ext/nmatrix/types.h +55 -0
  40. data/ext/nmatrix/util/io.h +115 -0
  41. data/ext/nmatrix/util/sl_list.h +144 -0
  42. data/ext/nmatrix/util/util.h +78 -0
  43. data/ext/nmatrix_fftw/extconf.rb +122 -0
  44. data/ext/nmatrix_fftw/nmatrix_fftw.cpp +274 -0
  45. data/lib/nmatrix/fftw.rb +343 -0
  46. data/spec/00_nmatrix_spec.rb +736 -0
  47. data/spec/01_enum_spec.rb +190 -0
  48. data/spec/02_slice_spec.rb +389 -0
  49. data/spec/03_nmatrix_monkeys_spec.rb +78 -0
  50. data/spec/2x2_dense_double.mat +0 -0
  51. data/spec/4x4_sparse.mat +0 -0
  52. data/spec/4x5_dense.mat +0 -0
  53. data/spec/blas_spec.rb +193 -0
  54. data/spec/elementwise_spec.rb +303 -0
  55. data/spec/homogeneous_spec.rb +99 -0
  56. data/spec/io/fortran_format_spec.rb +88 -0
  57. data/spec/io/harwell_boeing_spec.rb +98 -0
  58. data/spec/io/test.rua +9 -0
  59. data/spec/io_spec.rb +149 -0
  60. data/spec/lapack_core_spec.rb +482 -0
  61. data/spec/leakcheck.rb +16 -0
  62. data/spec/math_spec.rb +807 -0
  63. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  64. data/spec/nmatrix_yale_spec.rb +286 -0
  65. data/spec/plugins/fftw/fftw_spec.rb +348 -0
  66. data/spec/rspec_monkeys.rb +56 -0
  67. data/spec/rspec_spec.rb +34 -0
  68. data/spec/shortcuts_spec.rb +310 -0
  69. data/spec/slice_set_spec.rb +157 -0
  70. data/spec/spec_helper.rb +149 -0
  71. data/spec/stat_spec.rb +203 -0
  72. data/spec/test.pcd +20 -0
  73. data/spec/utm5940.mtx +83844 -0
  74. metadata +151 -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