nmatrix-atlas 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/ext/nmatrix/data/complex.h +364 -0
  3. data/ext/nmatrix/data/data.h +638 -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 +744 -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 +408 -0
  25. data/ext/nmatrix/ruby_constants.h +106 -0
  26. data/ext/nmatrix/storage/common.h +176 -0
  27. data/ext/nmatrix/storage/dense/dense.h +128 -0
  28. data/ext/nmatrix/storage/list/list.h +137 -0
  29. data/ext/nmatrix/storage/storage.h +98 -0
  30. data/ext/nmatrix/storage/yale/class.h +1139 -0
  31. data/ext/nmatrix/storage/yale/iterators/base.h +142 -0
  32. data/ext/nmatrix/storage/yale/iterators/iterator.h +130 -0
  33. data/ext/nmatrix/storage/yale/iterators/row.h +449 -0
  34. data/ext/nmatrix/storage/yale/iterators/row_stored.h +139 -0
  35. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +168 -0
  36. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +123 -0
  37. data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
  38. data/ext/nmatrix/storage/yale/yale.h +202 -0
  39. data/ext/nmatrix/types.h +54 -0
  40. data/ext/nmatrix/util/io.h +115 -0
  41. data/ext/nmatrix/util/sl_list.h +143 -0
  42. data/ext/nmatrix/util/util.h +78 -0
  43. data/ext/nmatrix_atlas/extconf.rb +250 -0
  44. data/ext/nmatrix_atlas/math_atlas.cpp +1206 -0
  45. data/ext/nmatrix_atlas/math_atlas/cblas_templates_atlas.h +72 -0
  46. data/ext/nmatrix_atlas/math_atlas/clapack_templates.h +332 -0
  47. data/ext/nmatrix_atlas/math_atlas/geev.h +82 -0
  48. data/ext/nmatrix_atlas/math_atlas/gesdd.h +83 -0
  49. data/ext/nmatrix_atlas/math_atlas/gesvd.h +81 -0
  50. data/ext/nmatrix_atlas/math_atlas/inc.h +47 -0
  51. data/ext/nmatrix_atlas/nmatrix_atlas.cpp +44 -0
  52. data/lib/nmatrix/atlas.rb +213 -0
  53. data/lib/nmatrix/lapack_ext_common.rb +69 -0
  54. data/spec/00_nmatrix_spec.rb +730 -0
  55. data/spec/01_enum_spec.rb +190 -0
  56. data/spec/02_slice_spec.rb +389 -0
  57. data/spec/03_nmatrix_monkeys_spec.rb +78 -0
  58. data/spec/2x2_dense_double.mat +0 -0
  59. data/spec/4x4_sparse.mat +0 -0
  60. data/spec/4x5_dense.mat +0 -0
  61. data/spec/blas_spec.rb +193 -0
  62. data/spec/elementwise_spec.rb +303 -0
  63. data/spec/homogeneous_spec.rb +99 -0
  64. data/spec/io/fortran_format_spec.rb +88 -0
  65. data/spec/io/harwell_boeing_spec.rb +98 -0
  66. data/spec/io/test.rua +9 -0
  67. data/spec/io_spec.rb +149 -0
  68. data/spec/lapack_core_spec.rb +482 -0
  69. data/spec/leakcheck.rb +16 -0
  70. data/spec/math_spec.rb +730 -0
  71. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  72. data/spec/nmatrix_yale_spec.rb +286 -0
  73. data/spec/plugins/atlas/atlas_spec.rb +242 -0
  74. data/spec/rspec_monkeys.rb +56 -0
  75. data/spec/rspec_spec.rb +34 -0
  76. data/spec/shortcuts_spec.rb +310 -0
  77. data/spec/slice_set_spec.rb +157 -0
  78. data/spec/spec_helper.rb +140 -0
  79. data/spec/stat_spec.rb +203 -0
  80. data/spec/test.pcd +20 -0
  81. data/spec/utm5940.mtx +83844 -0
  82. metadata +159 -0
@@ -0,0 +1,69 @@
1
+ #--
2
+ # = NMatrix
3
+ #
4
+ # A linear algebra library for scientific computation in Ruby.
5
+ # NMatrix is part of SciRuby.
6
+ #
7
+ # NMatrix was originally inspired by and derived from NArray, by
8
+ # Masahiro Tanaka: http://narray.rubyforge.org
9
+ #
10
+ # == Copyright Information
11
+ #
12
+ # SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
13
+ # NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
14
+ #
15
+ # Please see LICENSE.txt for additional copyright notices.
16
+ #
17
+ # == Contributing
18
+ #
19
+ # By contributing source code to SciRuby, you agree to be bound by
20
+ # our Contributor Agreement:
21
+ #
22
+ # * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
+ #
24
+ # == lapack_ext_common.rb
25
+ #
26
+ # Contains functions shared by nmatrix-atlas and nmatrix-lapacke gems.
27
+ #++
28
+
29
+ class NMatrix
30
+ def NMatrix.register_lapack_extension(name)
31
+ if (defined? @@lapack_extension)
32
+ raise "Attempting to load #{name} when #{@@lapack_extension} is already loaded. You can only load one LAPACK extension."
33
+ end
34
+
35
+ @@lapack_extension = name
36
+ end
37
+
38
+ alias_method :internal_dot, :dot
39
+
40
+ def dot(right_v)
41
+ if (right_v.is_a?(NMatrix) && self.stype == :dense && right_v.stype == :dense &&
42
+ self.dim == 2 && right_v.dim == 2 && self.shape[1] == right_v.shape[0])
43
+
44
+ result_dtype = NMatrix.upcast(self.dtype,right_v.dtype)
45
+ left = self.dtype == result_dtype ? self : self.cast(dtype: result_dtype)
46
+ right = right_v.dtype == result_dtype ? right_v : right_v.cast(dtype: result_dtype)
47
+
48
+ left = left.clone if left.is_ref?
49
+ right = right.clone if right.is_ref?
50
+
51
+ result_m = left.shape[0]
52
+ result_n = right.shape[1]
53
+ left_n = left.shape[1]
54
+ vector = result_n == 1
55
+ result = NMatrix.new([result_m,result_n], dtype: result_dtype)
56
+
57
+ if vector
58
+ NMatrix::BLAS.cblas_gemv(false, result_m, left_n, 1, left, left_n, right, 1, 0, result, 1)
59
+ else
60
+ NMatrix::BLAS.cblas_gemm(:row, false, false, result_m, result_n, left_n, 1, left, left_n, right, result_n, 0, result, result_n)
61
+ end
62
+ return result
63
+ else
64
+ #internal_dot will handle non-dense matrices (and also dot-products for NMatrix's with dim=1),
65
+ #and also all error-handling if the input is not valid
66
+ self.internal_dot(right_v)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,730 @@
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
+ # == 00_nmatrix_spec.rb
24
+ #
25
+ # Basic tests for NMatrix. These should load first, as they're
26
+ # essential to NMatrix operation.
27
+ #
28
+ require 'spec_helper'
29
+
30
+ describe NMatrix do
31
+ it "creates a matrix with the new constructor" do
32
+ n = NMatrix.new([2,2], [0,1,2,3], dtype: :int64)
33
+ expect(n.shape).to eq([2,2])
34
+ expect(n.entries).to eq([0,1,2,3])
35
+ expect(n.dtype).to eq(:int64)
36
+ end
37
+
38
+ it "adequately requires information to access a single entry of a dense matrix" do
39
+ n = NMatrix.new(:dense, 4, [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], :float64)
40
+ expect(n[0,0]).to eq(0)
41
+ expect { n[0] }.to raise_error(ArgumentError)
42
+ end
43
+
44
+ it "calculates exact determinants on small square matrices" do
45
+ expect(NMatrix.new(2, [1,2,3,4], stype: :dense, dtype: :int64).det_exact).to eq(-2)
46
+ end
47
+
48
+ it "calculates determinants" do
49
+ expect(NMatrix.new(3, [-2,2,3,-1,1,3,2,0,-1], stype: :dense, dtype: :int64).det).to eq(6)
50
+ end
51
+
52
+ it "allows casting to Ruby objects" do
53
+ m = NMatrix.new([3,3], [0,0,1,0,2,0,3,4,5], dtype: :int64, stype: :dense)
54
+ n = m.cast(:dense, :object)
55
+ expect(n).to eq(m)
56
+ end
57
+
58
+ it "allows casting from Ruby objects" do
59
+ m = NMatrix.new(:dense, [3,3], [0,0,1,0,2,0,3,4,5], :object)
60
+ n = m.cast(:dense, :int64)
61
+ expect(m).to eq(n)
62
+ end
63
+
64
+ it "allows stype casting of a dim 2 matrix between dense, sparse, and list (different dtypes)" do
65
+ m = NMatrix.new(:dense, [3,3], [0,0,1,0,2,0,3,4,5], :int64).
66
+ cast(:yale, :int32).
67
+ cast(:dense, :float64).
68
+ cast(:list, :object).
69
+ cast(:dense, :int16).
70
+ cast(:list, :int32).
71
+ cast(:yale, :int64) #.
72
+ #cast(:list, :int32).
73
+ #cast(:dense, :int16)
74
+ #m.should.equal?(original)
75
+ # For some reason this causes some weird garbage collector problems when we uncomment these. The above lines won't
76
+ # work at all in IRB, but work fine when run in a regular Ruby session.
77
+ end
78
+
79
+ it "fills dense Ruby object matrix with nil" do
80
+ n = NMatrix.new([4,3], dtype: :object)
81
+ expect(n[0,0]).to eq(nil)
82
+ end
83
+
84
+ it "fills dense with individual assignments" do
85
+ n = NMatrix.new([4,3], dtype: :float64)
86
+ n[0,0] = 14.0
87
+ n[0,1] = 9.0
88
+ n[0,2] = 3.0
89
+ n[1,0] = 2.0
90
+ n[1,1] = 11.0
91
+ n[1,2] = 15.0
92
+ n[2,0] = 0.0
93
+ n[2,1] = 12.0
94
+ n[2,2] = 17.0
95
+ n[3,0] = 5.0
96
+ n[3,1] = 2.0
97
+ n[3,2] = 3.0
98
+
99
+ expect(n[0,0]).to eq(14.0)
100
+ expect(n[0,1]).to eq(9.0)
101
+ expect(n[0,2]).to eq(3.0)
102
+ expect(n[1,0]).to eq(2.0)
103
+ expect(n[1,1]).to eq(11.0)
104
+ expect(n[1,2]).to eq(15.0)
105
+ expect(n[2,0]).to eq(0.0)
106
+ expect(n[2,1]).to eq(12.0)
107
+ expect(n[2,2]).to eq(17.0)
108
+ expect(n[3,0]).to eq(5.0)
109
+ expect(n[3,1]).to eq(2.0)
110
+ expect(n[3,2]).to eq(3.0)
111
+ end
112
+
113
+ it "fills dense with a single mass assignment" do
114
+ n = NMatrix.new([4,3], [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0])
115
+
116
+ expect(n[0,0]).to eq(14.0)
117
+ expect(n[0,1]).to eq(9.0)
118
+ expect(n[0,2]).to eq(3.0)
119
+ expect(n[1,0]).to eq(2.0)
120
+ expect(n[1,1]).to eq(11.0)
121
+ expect(n[1,2]).to eq(15.0)
122
+ expect(n[2,0]).to eq(0.0)
123
+ expect(n[2,1]).to eq(12.0)
124
+ expect(n[2,2]).to eq(17.0)
125
+ expect(n[3,0]).to eq(5.0)
126
+ expect(n[3,1]).to eq(2.0)
127
+ expect(n[3,2]).to eq(3.0)
128
+ end
129
+
130
+ it "fills dense with a single mass assignment, with dtype specified" do
131
+ m = NMatrix.new([4,3], [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0], dtype: :float32)
132
+
133
+ expect(m[0,0]).to eq(14.0)
134
+ expect(m[0,1]).to eq(9.0)
135
+ expect(m[0,2]).to eq(3.0)
136
+ expect(m[1,0]).to eq(2.0)
137
+ expect(m[1,1]).to eq(11.0)
138
+ expect(m[1,2]).to eq(15.0)
139
+ expect(m[2,0]).to eq(0.0)
140
+ expect(m[2,1]).to eq(12.0)
141
+ expect(m[2,2]).to eq(17.0)
142
+ expect(m[3,0]).to eq(5.0)
143
+ expect(m[3,1]).to eq(2.0)
144
+ expect(m[3,2]).to eq(3.0)
145
+ end
146
+
147
+ it "dense handles missing initialization value" do
148
+ n = NMatrix.new(3, dtype: :int8)
149
+ expect(n.stype).to eq(:dense)
150
+ expect(n.dtype).to eq(:int8)
151
+
152
+ m = NMatrix.new(4, dtype: :float64)
153
+ expect(m.stype).to eq(:dense)
154
+ expect(m.dtype).to eq(:float64)
155
+ end
156
+
157
+ [:dense, :list, :yale].each do |storage_type|
158
+ context storage_type do
159
+ it "can be duplicated" do
160
+ n = NMatrix.new([2,3], 1.1, stype: storage_type, dtype: :float64)
161
+ expect(n.stype).to eq(storage_type)
162
+
163
+ n[0,0] = 0.0
164
+ n[0,1] = 0.1
165
+ n[1,0] = 1.0
166
+
167
+ m = n.dup
168
+ expect(m.shape).to eq(n.shape)
169
+ expect(m.dim).to eq(n.dim)
170
+ expect(m.object_id).not_to eq(n.object_id)
171
+ expect(m.stype).to eq(storage_type)
172
+ expect(m[0,0]).to eq(n[0,0])
173
+ m[0,0] = 3.0
174
+ expect(m[0,0]).not_to eq(n[0,0])
175
+ end
176
+
177
+ it "enforces shape boundaries" do
178
+ expect { NMatrix.new([1,10], 0, dtype: :int8, stype: storage_type, default: 0)[1,0] }.to raise_error(RangeError)
179
+ expect { NMatrix.new([1,10], 0, dtype: :int8, stype: storage_type, default: 0)[0,10] }.to raise_error(RangeError)
180
+ end
181
+
182
+ it "sets and gets" do
183
+ n = NMatrix.new(2, 0, stype: storage_type, dtype: :int8)
184
+ n[0,1] = 1
185
+ expect(n[0,0]).to eq(0)
186
+ expect(n[1,0]).to eq(0)
187
+ expect(n[0,1]).to eq(1)
188
+ expect(n[1,1]).to eq(0)
189
+ end
190
+
191
+ it "sets and gets references" do
192
+ n = NMatrix.new(2, stype: storage_type, dtype: :int8, default: 0)
193
+ expect(n[0,1] = 1).to eq(1)
194
+ expect(n[0,1]).to eq(1)
195
+ end
196
+
197
+ # Tests Ruby object versus any C dtype (in this case we use :int64)
198
+ [:object, :int64].each do |dtype|
199
+ c = dtype == :object ? "Ruby object" : "non-Ruby object"
200
+ context c do
201
+ it "allows iteration of matrices" do
202
+ n = nil
203
+ if storage_type == :dense
204
+ n = NMatrix.new(:dense, [3,3], [1,2,3,4,5,6,7,8,9], dtype)
205
+ else
206
+ n = NMatrix.new([3,4], 0, stype: storage_type, dtype: dtype)
207
+ n[0,0] = 1
208
+ n[0,1] = 2
209
+ n[2,3] = 4
210
+ n[2,0] = 3
211
+ end
212
+
213
+ ary = []
214
+ n.each do |x|
215
+ ary << x
216
+ end
217
+
218
+ if storage_type == :dense
219
+ expect(ary).to eq([1,2,3,4,5,6,7,8,9])
220
+ else
221
+ expect(ary).to eq([1,2,0,0,0,0,0,0,3,0,0,4])
222
+ end
223
+ end
224
+
225
+ it "allows storage-based iteration of matrices" do
226
+ STDERR.puts storage_type.inspect
227
+ STDERR.puts dtype.inspect
228
+ n = NMatrix.new([3,3], 0, stype: storage_type, dtype: dtype)
229
+ n[0,0] = 1
230
+ n[0,1] = 2
231
+ n[2,0] = 5 if storage_type == :yale
232
+ n[2,1] = 4
233
+ n[2,2] = 3
234
+
235
+ values = []
236
+ is = []
237
+ js = []
238
+
239
+ n.each_stored_with_indices do |v,i,j|
240
+ values << v
241
+ is << i
242
+ js << j
243
+ end
244
+
245
+ if storage_type == :yale
246
+ expect(is).to eq([0,1,2,0,2,2])
247
+ expect(js).to eq([0,1,2,1,0,1])
248
+ expect(values).to eq([1,0,3,2,5,4])
249
+ elsif storage_type == :list
250
+ expect(values).to eq([1,2,4,3])
251
+ expect(is).to eq([0,0,2,2])
252
+ expect(js).to eq([0,1,1,2])
253
+ elsif storage_type == :dense
254
+ expect(values).to eq([1,2,0,0,0,0,0,4,3])
255
+ expect(is).to eq([0,0,0,1,1,1,2,2,2])
256
+ expect(js).to eq([0,1,2,0,1,2,0,1,2])
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ # dense and list, not yale
264
+ context "(storage: #{storage_type})" do
265
+ it "gets default value" do
266
+ expect(NMatrix.new(3, 0, stype: storage_type)[1,1]).to eq(0)
267
+ expect(NMatrix.new(3, 0.1, stype: storage_type)[1,1]).to eq(0.1)
268
+ expect(NMatrix.new(3, 1, stype: storage_type)[1,1]).to eq(1)
269
+
270
+ end
271
+ it "returns shape and dim" do
272
+ expect(NMatrix.new([3,2,8], 0, stype: storage_type).shape).to eq([3,2,8])
273
+ expect(NMatrix.new([3,2,8], 0, stype: storage_type).dim).to eq(3)
274
+ end
275
+
276
+ it "returns number of rows and columns" do
277
+ expect(NMatrix.new([7, 4], 3, stype: storage_type).rows).to eq(7)
278
+ expect(NMatrix.new([7, 4], 3, stype: storage_type).cols).to eq(4)
279
+ end
280
+ end unless storage_type == :yale
281
+ end
282
+
283
+
284
+ it "handles dense construction" do
285
+ expect(NMatrix.new(3,0)[1,1]).to eq(0)
286
+ expect(lambda { NMatrix.new(3,dtype: :int8)[1,1] }).to_not raise_error
287
+ end
288
+
289
+ it "converts from list to yale properly" do
290
+ m = NMatrix.new(3, 0, stype: :list)
291
+ m[0,2] = 333
292
+ m[2,2] = 777
293
+ n = m.cast(:yale, :int32)
294
+ #puts n.capacity
295
+ #n.extend NMatrix::YaleFunctions
296
+ #puts n.yale_ija.inspect
297
+ #puts n.yale_a.inspect
298
+
299
+ expect(n[0,0]).to eq(0)
300
+ expect(n[0,1]).to eq(0)
301
+ expect(n[0,2]).to eq(333)
302
+ expect(n[1,0]).to eq(0)
303
+ expect(n[1,1]).to eq(0)
304
+ expect(n[1,2]).to eq(0)
305
+ expect(n[2,0]).to eq(0)
306
+ expect(n[2,1]).to eq(0)
307
+ expect(n[2,2]).to eq(777)
308
+ end
309
+
310
+ it "should return an enumerator when each is called without a block" do
311
+ a = NMatrix.new(2, 1)
312
+ b = NMatrix.new(2, [-1,0,1,0])
313
+ enums = [a.each, b.each]
314
+
315
+ begin
316
+ atans = []
317
+ atans << Math.atan2(*enums.map(&:next)) while true
318
+ rescue StopIteration
319
+ end
320
+ end
321
+
322
+ context "dense" do
323
+ it "should return the matrix being iterated over when each is called with a block" do
324
+ a = NMatrix.new(2, 1)
325
+ val = (a.each { })
326
+ expect(val).to eq(a)
327
+ end
328
+
329
+ it "should return the matrix being iterated over when each_stored_with_indices is called with a block" do
330
+ a = NMatrix.new(2,1)
331
+ val = (a.each_stored_with_indices { })
332
+ expect(val).to eq(a)
333
+ end
334
+ end
335
+
336
+ [:list, :yale].each do |storage_type|
337
+ context storage_type do
338
+ it "should return the matrix being iterated over when each_stored_with_indices is called with a block" do
339
+ n = NMatrix.new([2,3], 1.1, stype: storage_type, dtype: :float64, default: 0)
340
+ val = (n.each_stored_with_indices { })
341
+ expect(val).to eq(n)
342
+ end
343
+
344
+ it "should return an enumerator when each_stored_with_indices is called without a block" do
345
+ n = NMatrix.new([2,3], 1.1, stype: storage_type, dtype: :float64, default: 0)
346
+ val = n.each_stored_with_indices
347
+ expect(val).to be_a Enumerator
348
+ end
349
+ end
350
+ end
351
+
352
+ it "should iterate through element 256 without a segfault" do
353
+ t = NVector.random(256)
354
+ t.each { |x| x + 0 }
355
+ end
356
+ end
357
+
358
+
359
+ describe 'NMatrix' do
360
+ context "#upper_triangle" do
361
+ it "should create a copy with the lower corner set to zero" do
362
+ n = NMatrix.seq(4)+1
363
+ expect(n.upper_triangle).to eq(NMatrix.new(4, [1,2,3,4,0,6,7,8,0,0,11,12,0,0,0,16]))
364
+ expect(n.upper_triangle(2)).to eq(NMatrix.new(4, [1,2,3,4,5,6,7,8,9,10,11,12,0,14,15,16]))
365
+ end
366
+ end
367
+
368
+ context "#lower_triangle" do
369
+ it "should create a copy with the lower corner set to zero" do
370
+ n = NMatrix.seq(4)+1
371
+ expect(n.lower_triangle).to eq(NMatrix.new(4, [1,0,0,0,5,6,0,0,9,10,11,0,13,14,15,16]))
372
+ expect(n.lower_triangle(2)).to eq(NMatrix.new(4, [1,2,3,0,5,6,7,8,9,10,11,12,13,14,15,16]))
373
+ end
374
+ end
375
+
376
+ context "#upper_triangle!" do
377
+ it "should create a copy with the lower corner set to zero" do
378
+ n = NMatrix.seq(4)+1
379
+ expect(n.upper_triangle!).to eq(NMatrix.new(4, [1,2,3,4,0,6,7,8,0,0,11,12,0,0,0,16]))
380
+ n = NMatrix.seq(4)+1
381
+ expect(n.upper_triangle!(2)).to eq(NMatrix.new(4, [1,2,3,4,5,6,7,8,9,10,11,12,0,14,15,16]))
382
+ end
383
+ end
384
+
385
+ context "#lower_triangle!" do
386
+ it "should create a copy with the lower corner set to zero" do
387
+ n = NMatrix.seq(4)+1
388
+ expect(n.lower_triangle!).to eq(NMatrix.new(4, [1,0,0,0,5,6,0,0,9,10,11,0,13,14,15,16]))
389
+ n = NMatrix.seq(4)+1
390
+ expect(n.lower_triangle!(2)).to eq(NMatrix.new(4, [1,2,3,0,5,6,7,8,9,10,11,12,13,14,15,16]))
391
+ end
392
+ end
393
+
394
+ context "#rank" do
395
+ it "should get the rank of a 2-dimensional matrix" do
396
+ n = NMatrix.seq([2,3])
397
+ expect(n.rank(0, 0)).to eq(N[[0,1,2]])
398
+ end
399
+
400
+ it "should raise an error when the rank is out of bounds" do
401
+ n = NMatrix.seq([2,3])
402
+ expect { n.rank(2, 0) }.to raise_error(RangeError)
403
+ end
404
+ end
405
+
406
+ context "#reshape" do
407
+ it "should change the shape of a matrix without the contents changing" do
408
+ n = NMatrix.seq(4)+1
409
+ expect(n.reshape([8,2]).to_flat_array).to eq(n.to_flat_array)
410
+ end
411
+
412
+ it "should permit a change of dimensionality" do
413
+ n = NMatrix.seq(4)+1
414
+ expect(n.reshape([8,1,2]).to_flat_array).to eq(n.to_flat_array)
415
+ end
416
+
417
+ it "should prevent a resize" do
418
+ n = NMatrix.seq(4)+1
419
+ expect { n.reshape([5,2]) }.to raise_error(ArgumentError)
420
+ end
421
+
422
+ it "should do the reshape operation in place" do
423
+ n = NMatrix.seq(4)+1
424
+ expect(n.reshape!([8,2]).eql?(n)).to eq(true) # because n itself changes
425
+ end
426
+
427
+ it "reshape and reshape! must produce same result" do
428
+ n = NMatrix.seq(4)+1
429
+ a = NMatrix.seq(4)+1
430
+ expect(n.reshape!([8,2])==a.reshape(8,2)).to eq(true) # because n itself changes
431
+ end
432
+
433
+ it "should prevent a resize in place" do
434
+ n = NMatrix.seq(4)+1
435
+ expect { n.reshape([5,2]) }.to raise_error(ArgumentError)
436
+ end
437
+ end
438
+
439
+ context "#transpose" do
440
+ [:dense, :list, :yale].each do |stype|
441
+ context(stype) do
442
+ it "should transpose a #{stype} matrix (2-dimensional)" do
443
+ n = NMatrix.seq(4, stype: stype)
444
+ expect(n.transpose.to_a.flatten).to eq([0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15])
445
+ end
446
+ end
447
+ end
448
+
449
+ [:dense, :list].each do |stype|
450
+ context(stype) do
451
+ it "should transpose a #{stype} matrix (3-dimensional)" do
452
+ n = NMatrix.new([4,4,1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], stype: stype)
453
+ expect(n.transpose([2,1,0]).to_flat_array).to eq([0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15])
454
+ expect(n.transpose([1,0,2]).to_flat_array).to eq([0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15])
455
+ expect(n.transpose([0,2,1]).to_flat_array).to eq(n.to_flat_array) # for dense, make this reshape!
456
+ end
457
+ end
458
+
459
+ it "should just copy a 1-dimensional #{stype} matrix" do
460
+ n = NMatrix.new([3], [1,2,3], stype: stype)
461
+ expect(n.transpose).to eq n
462
+ expect(n.transpose).not_to be n
463
+ end
464
+ end
465
+ end
466
+
467
+ context "#dot_product" do
468
+ [:dense].each do |stype| # list storage transpose not yet implemented
469
+ context(stype) do # yale support only 2-dim matrix
470
+ it "should work like vector product on a #{stype} (1-dimensional)" do
471
+ m = NMatrix.new([3], [1,2,3], stype: stype)
472
+ expect(m.dot(m)).to eq (NMatrix.new([1],[14]))
473
+ end
474
+ end
475
+ end
476
+ end
477
+
478
+ context "#==" do
479
+ [:dense, :list, :yale].each do |left|
480
+ [:dense, :list, :yale].each do |right|
481
+ context ("#{left}?#{right}") do
482
+ it "tests equality of two equal matrices" do
483
+ n = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: left)
484
+ m = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: right)
485
+
486
+ expect(n==m).to eq(true)
487
+ end
488
+
489
+ it "tests equality of two unequal matrices" do
490
+ n = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,1], stype: left)
491
+ m = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: right)
492
+
493
+ expect(n==m).to eq(false)
494
+ end
495
+
496
+ it "tests equality of matrices with different shapes" do
497
+ n = NMatrix.new([2,2], [1,2, 3,4], stype: left)
498
+ m = NMatrix.new([2,3], [1,2, 3,4, 5,6], stype: right)
499
+ x = NMatrix.new([1,4], [1,2, 3,4], stype: right)
500
+
501
+ expect{n==m}.to raise_error(ShapeError)
502
+ expect{n==x}.to raise_error(ShapeError)
503
+ end
504
+
505
+ it "tests equality of matrices with different dimension" do
506
+ n = NMatrix.new([2,1], [1,2], stype: left)
507
+ m = NMatrix.new([2], [1,2], stype: right)
508
+
509
+ expect{n==m}.to raise_error(ShapeError)
510
+ end if left != :yale && right != :yale # yale must have dimension 2
511
+ end
512
+ end
513
+ end
514
+ end
515
+
516
+ context "#concat" do
517
+ it "should default to horizontal concatenation" do
518
+ n = NMatrix.new([1,3], [1,2,3])
519
+ expect(n.concat(n)).to eq(NMatrix.new([1,6], [1,2,3,1,2,3]))
520
+ end
521
+
522
+ it "should permit vertical concatenation" do
523
+ n = NMatrix.new([1,3], [1,2,3])
524
+ expect(n.vconcat(n)).to eq(NMatrix.new([2,3], [1,2,3]))
525
+ end
526
+
527
+ it "should permit depth concatenation on tensors" do
528
+ n = NMatrix.new([1,3,1], [1,2,3])
529
+ expect(n.dconcat(n)).to eq(NMatrix.new([1,3,2], [1,1,2,2,3,3]))
530
+ end
531
+ end
532
+
533
+ context "#[]" do
534
+ it "should return values based on indices" do
535
+ n = NMatrix.new([2,5], [1,2,3,4,5,6,7,8,9,0])
536
+ expect(n[1,0]).to eq 6
537
+ expect(n[1,0..3]).to eq NMatrix.new([1,4],[6,7,8,9])
538
+ end
539
+
540
+ it "should work for negative indices" do
541
+ n = NMatrix.new([1,5], [1,2,3,4,5])
542
+ expect(n[-1]).to eq(5)
543
+ expect(n[0,0..-2]).to eq(NMatrix.new([1,4],[1,2,3,4]))
544
+ end
545
+ end
546
+
547
+ context "#complex_conjugate!" do
548
+ [:dense, :yale, :list].each do |stype|
549
+ context(stype) do
550
+ it "should work in-place for complex dtypes" do
551
+ pending("not yet implemented for list stype") if stype == :list
552
+ n = NMatrix.new([2,3], [Complex(2,3)], stype: stype, dtype: :complex128)
553
+ n.complex_conjugate!
554
+ expect(n).to eq(NMatrix.new([2,3], [Complex(2,-3)], stype: stype, dtype: :complex128))
555
+ end
556
+
557
+ [:object, :int64].each do |dtype|
558
+ it "should work in-place for non-complex dtypes" do
559
+ pending("not yet implemented for list stype") if stype == :list
560
+ n = NMatrix.new([2,3], 1, stype: stype, dtype: dtype)
561
+ n.complex_conjugate!
562
+ expect(n).to eq(NMatrix.new([2,3], [1], stype: stype, dtype: dtype))
563
+ end
564
+ end
565
+ end
566
+ end
567
+ end
568
+
569
+ context "#complex_conjugate" do
570
+ [:dense, :yale, :list].each do |stype|
571
+ context(stype) do
572
+ it "should work out-of-place for complex dtypes" do
573
+ pending("not yet implemented for list stype") if stype == :list
574
+ n = NMatrix.new([2,3], [Complex(2,3)], stype: stype, dtype: :complex128)
575
+ expect(n.complex_conjugate).to eq(NMatrix.new([2,3], [Complex(2,-3)], stype: stype, dtype: :complex128))
576
+ end
577
+
578
+ [:object, :int64].each do |dtype|
579
+ it "should work out-of-place for non-complex dtypes" do
580
+ pending("not yet implemented for list stype") if stype == :list
581
+ n = NMatrix.new([2,3], 1, stype: stype, dtype: dtype)
582
+ expect(n.complex_conjugate).to eq(NMatrix.new([2,3], [1], stype: stype, dtype: dtype))
583
+ end
584
+ end
585
+ end
586
+ end
587
+ end
588
+
589
+ context "#inject" do
590
+ it "should sum columns of yale matrix correctly" do
591
+ n = NMatrix.new([4, 3], stype: :yale, default: 0)
592
+ n[0,0] = 1
593
+ n[1,1] = 2
594
+ n[2,2] = 4
595
+ n[3,2] = 8
596
+ column_sums = []
597
+ n.cols.times do |i|
598
+ column_sums << n.col(i).inject(:+)
599
+ end
600
+ expect(column_sums).to eq([1, 2, 12])
601
+ end
602
+ end
603
+
604
+ context "#index" do
605
+ it "returns index of first occurence of an element for a vector" do
606
+ n = NMatrix.new([5], [0,22,22,11,11])
607
+
608
+ expect(n.index(22)).to eq([1])
609
+ end
610
+
611
+ it "returns index of first occurence of an element for 2-D matrix" do
612
+ n = NMatrix.new([3,3], [23,11,23,
613
+ 44, 2, 0,
614
+ 33, 0, 32])
615
+
616
+ expect(n.index(0)).to eq([1,2])
617
+ end
618
+
619
+ it "returns index of first occerence of an element for N-D matrix" do
620
+ n = NMatrix.new([3,3,3], [23,11,23, 44, 2, 0, 33, 0, 32,
621
+ 23,11,23, 44, 2, 0, 33, 0, 32,
622
+ 23,11,23, 44, 2, 0, 33, 0, 32])
623
+
624
+ expect(n.index(44)).to eq([0,1,0])
625
+ end
626
+ end
627
+
628
+ context "#diagonal" do
629
+ ALL_DTYPES.each do |dtype|
630
+ before do
631
+ @square_matrix = NMatrix.new([3,3], [
632
+ 23,11,23,
633
+ 44, 2, 0,
634
+ 33, 0, 32
635
+ ], dtype: dtype
636
+ )
637
+
638
+ @rect_matrix = NMatrix.new([4,3], [
639
+ 23,11,23,
640
+ 44, 2, 0,
641
+ 33, 0,32,
642
+ 11,22,33
643
+ ], dtype: dtype
644
+ )
645
+ end
646
+
647
+ it "returns main diagonal for square matrix" do
648
+ expect(@square_matrix.diagonal).to eq(NMatrix.new [3], [23,2,32])
649
+ end
650
+
651
+ it "returns main diagonal for rectangular matrix" do
652
+ expect(@rect_matrix.diagonal).to eq(NMatrix.new [3], [23,2,32])
653
+ end
654
+
655
+ it "returns anti-diagonal for square matrix" do
656
+ expect(@square_matrix.diagonal(false)).to eq(NMatrix.new [3], [23,2,33])
657
+ end
658
+
659
+ it "returns anti-diagonal for rectangular matrix" do
660
+ expect(@square_matrix.diagonal(false)).to eq(NMatrix.new [3], [23,2,33])
661
+ end
662
+ end
663
+ end
664
+
665
+ context "#repeat" do
666
+ before do
667
+ @sample_matrix = NMatrix.new([2, 2], [1, 2, 3, 4])
668
+ end
669
+
670
+ it "checks count argument" do
671
+ expect{@sample_matrix.repeat(1, 0)}.to raise_error(ArgumentError)
672
+ expect{@sample_matrix.repeat(-2, 0)}.to raise_error(ArgumentError)
673
+ end
674
+
675
+ it "returns repeated matrix" do
676
+ expect(@sample_matrix.repeat(2, 0)).to eq(NMatrix.new([4, 2], [1, 2, 3, 4, 1, 2, 3, 4]))
677
+ expect(@sample_matrix.repeat(2, 1)).to eq(NMatrix.new([2, 4], [1, 2, 1, 2, 3, 4, 3, 4]))
678
+ end
679
+ end
680
+
681
+ context "#meshgrid" do
682
+ before do
683
+ @x, @y, @z = [1, 2, 3], NMatrix.new([2, 1], [4, 5]), [6, 7]
684
+ @two_dim = NMatrix.new([2, 2], [1, 2, 3, 4])
685
+ @two_dim_array = [[4], [5]]
686
+ @expected_result = [NMatrix.new([2, 3], [1, 2, 3, 1, 2, 3]), NMatrix.new([2, 3], [4, 4, 4, 5, 5, 5])]
687
+ @expected_for_ij = [NMatrix.new([3, 2], [1, 1, 2, 2, 3, 3]), NMatrix.new([3, 2], [4, 5, 4, 5, 4, 5])]
688
+ @expected_for_sparse = [NMatrix.new([1, 3], [1, 2, 3]), NMatrix.new([2, 1], [4, 5])]
689
+ @expected_for_sparse_ij = [NMatrix.new([3, 1], [1, 2, 3]), NMatrix.new([1, 2], [4, 5])]
690
+ @expected_3dim = [NMatrix.new([1, 3, 1], [1, 2, 3]).repeat(2, 0).repeat(2, 2),
691
+ NMatrix.new([2, 1, 1], [4, 5]).repeat(3, 1).repeat(2, 2),
692
+ NMatrix.new([1, 1, 2], [6, 7]).repeat(2, 0).repeat(3, 1)]
693
+ @expected_3dim_sparse_ij = [NMatrix.new([3, 1, 1], [1, 2, 3]),
694
+ NMatrix.new([1, 2, 1], [4, 5]),
695
+ NMatrix.new([1, 1, 2], [6, 7])]
696
+ end
697
+
698
+ it "checks arrays count" do
699
+ expect{NMatrix.meshgrid([@x])}.to raise_error(ArgumentError)
700
+ expect{NMatrix.meshgrid([])}.to raise_error(ArgumentError)
701
+ end
702
+
703
+ it "flattens input arrays before use" do
704
+ expect(NMatrix.meshgrid([@two_dim, @two_dim_array])).to eq(NMatrix.meshgrid([@two_dim.to_flat_array, @two_dim_array.flatten]))
705
+ end
706
+
707
+ it "returns new NMatrixes" do
708
+ expect(NMatrix.meshgrid([@x, @y])).to eq(@expected_result)
709
+ end
710
+
711
+ it "has option :sparse" do
712
+ expect(NMatrix.meshgrid([@x, @y], sparse: true)).to eq(@expected_for_sparse)
713
+ end
714
+
715
+ it "has option :indexing" do
716
+ expect(NMatrix.meshgrid([@x, @y], indexing: :ij)).to eq(@expected_for_ij)
717
+ expect(NMatrix.meshgrid([@x, @y], indexing: :xy)).to eq(@expected_result)
718
+ expect{NMatrix.meshgrid([@x, @y], indexing: :not_ij_not_xy)}.to raise_error(ArgumentError)
719
+ end
720
+
721
+ it "works well with both options set" do
722
+ expect(NMatrix.meshgrid([@x, @y], sparse: true, indexing: :ij)).to eq(@expected_for_sparse_ij)
723
+ end
724
+
725
+ it "is able to take more than two arrays as arguments and works well with options" do
726
+ expect(NMatrix.meshgrid([@x, @y, @z])).to eq(@expected_3dim)
727
+ expect(NMatrix.meshgrid([@x, @y, @z], sparse: true, indexing: :ij)).to eq(@expected_3dim_sparse_ij)
728
+ end
729
+ end
730
+ end