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.
- checksums.yaml +7 -0
- data/ext/nmatrix/data/complex.h +364 -0
- data/ext/nmatrix/data/data.h +638 -0
- data/ext/nmatrix/data/meta.h +64 -0
- data/ext/nmatrix/data/ruby_object.h +389 -0
- data/ext/nmatrix/math/asum.h +120 -0
- data/ext/nmatrix/math/cblas_enums.h +36 -0
- data/ext/nmatrix/math/cblas_templates_core.h +507 -0
- data/ext/nmatrix/math/gemm.h +241 -0
- data/ext/nmatrix/math/gemv.h +178 -0
- data/ext/nmatrix/math/getrf.h +255 -0
- data/ext/nmatrix/math/getrs.h +121 -0
- data/ext/nmatrix/math/imax.h +79 -0
- data/ext/nmatrix/math/laswp.h +165 -0
- data/ext/nmatrix/math/long_dtype.h +49 -0
- data/ext/nmatrix/math/math.h +744 -0
- data/ext/nmatrix/math/nrm2.h +160 -0
- data/ext/nmatrix/math/rot.h +117 -0
- data/ext/nmatrix/math/rotg.h +106 -0
- data/ext/nmatrix/math/scal.h +71 -0
- data/ext/nmatrix/math/trsm.h +332 -0
- data/ext/nmatrix/math/util.h +148 -0
- data/ext/nmatrix/nm_memory.h +60 -0
- data/ext/nmatrix/nmatrix.h +408 -0
- data/ext/nmatrix/ruby_constants.h +106 -0
- data/ext/nmatrix/storage/common.h +176 -0
- data/ext/nmatrix/storage/dense/dense.h +128 -0
- data/ext/nmatrix/storage/list/list.h +137 -0
- data/ext/nmatrix/storage/storage.h +98 -0
- data/ext/nmatrix/storage/yale/class.h +1139 -0
- data/ext/nmatrix/storage/yale/iterators/base.h +142 -0
- data/ext/nmatrix/storage/yale/iterators/iterator.h +130 -0
- data/ext/nmatrix/storage/yale/iterators/row.h +449 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored.h +139 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +168 -0
- data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +123 -0
- data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
- data/ext/nmatrix/storage/yale/yale.h +202 -0
- data/ext/nmatrix/types.h +54 -0
- data/ext/nmatrix/util/io.h +115 -0
- data/ext/nmatrix/util/sl_list.h +143 -0
- data/ext/nmatrix/util/util.h +78 -0
- data/ext/nmatrix_atlas/extconf.rb +250 -0
- data/ext/nmatrix_atlas/math_atlas.cpp +1206 -0
- data/ext/nmatrix_atlas/math_atlas/cblas_templates_atlas.h +72 -0
- data/ext/nmatrix_atlas/math_atlas/clapack_templates.h +332 -0
- data/ext/nmatrix_atlas/math_atlas/geev.h +82 -0
- data/ext/nmatrix_atlas/math_atlas/gesdd.h +83 -0
- data/ext/nmatrix_atlas/math_atlas/gesvd.h +81 -0
- data/ext/nmatrix_atlas/math_atlas/inc.h +47 -0
- data/ext/nmatrix_atlas/nmatrix_atlas.cpp +44 -0
- data/lib/nmatrix/atlas.rb +213 -0
- data/lib/nmatrix/lapack_ext_common.rb +69 -0
- data/spec/00_nmatrix_spec.rb +730 -0
- data/spec/01_enum_spec.rb +190 -0
- data/spec/02_slice_spec.rb +389 -0
- data/spec/03_nmatrix_monkeys_spec.rb +78 -0
- data/spec/2x2_dense_double.mat +0 -0
- data/spec/4x4_sparse.mat +0 -0
- data/spec/4x5_dense.mat +0 -0
- data/spec/blas_spec.rb +193 -0
- data/spec/elementwise_spec.rb +303 -0
- data/spec/homogeneous_spec.rb +99 -0
- data/spec/io/fortran_format_spec.rb +88 -0
- data/spec/io/harwell_boeing_spec.rb +98 -0
- data/spec/io/test.rua +9 -0
- data/spec/io_spec.rb +149 -0
- data/spec/lapack_core_spec.rb +482 -0
- data/spec/leakcheck.rb +16 -0
- data/spec/math_spec.rb +730 -0
- data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
- data/spec/nmatrix_yale_spec.rb +286 -0
- data/spec/plugins/atlas/atlas_spec.rb +242 -0
- data/spec/rspec_monkeys.rb +56 -0
- data/spec/rspec_spec.rb +34 -0
- data/spec/shortcuts_spec.rb +310 -0
- data/spec/slice_set_spec.rb +157 -0
- data/spec/spec_helper.rb +140 -0
- data/spec/stat_spec.rb +203 -0
- data/spec/test.pcd +20 -0
- data/spec/utm5940.mtx +83844 -0
- 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
|