numo-narray-alt 0.9.3
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/Gemfile +14 -0
- data/LICENSE +30 -0
- data/README.md +71 -0
- data/Rakefile +24 -0
- data/ext/numo/narray/SFMT-params.h +97 -0
- data/ext/numo/narray/SFMT-params19937.h +48 -0
- data/ext/numo/narray/SFMT.c +602 -0
- data/ext/numo/narray/SFMT.h +147 -0
- data/ext/numo/narray/array.c +575 -0
- data/ext/numo/narray/data.c +958 -0
- data/ext/numo/narray/extconf.rb +84 -0
- data/ext/numo/narray/index.c +1092 -0
- data/ext/numo/narray/kwargs.c +142 -0
- data/ext/numo/narray/math.c +133 -0
- data/ext/numo/narray/narray.c +1976 -0
- data/ext/numo/narray/narray.def +28 -0
- data/ext/numo/narray/ndloop.c +1840 -0
- data/ext/numo/narray/numo/compat.h +23 -0
- data/ext/numo/narray/numo/intern.h +115 -0
- data/ext/numo/narray/numo/narray.h +480 -0
- data/ext/numo/narray/numo/ndloop.h +93 -0
- data/ext/numo/narray/numo/template.h +149 -0
- data/ext/numo/narray/numo/types/bit.h +38 -0
- data/ext/numo/narray/numo/types/complex.h +404 -0
- data/ext/numo/narray/numo/types/complex_macro.h +384 -0
- data/ext/numo/narray/numo/types/dcomplex.h +42 -0
- data/ext/numo/narray/numo/types/dfloat.h +44 -0
- data/ext/numo/narray/numo/types/float_def.h +34 -0
- data/ext/numo/narray/numo/types/float_macro.h +202 -0
- data/ext/numo/narray/numo/types/int16.h +27 -0
- data/ext/numo/narray/numo/types/int32.h +23 -0
- data/ext/numo/narray/numo/types/int64.h +23 -0
- data/ext/numo/narray/numo/types/int8.h +23 -0
- data/ext/numo/narray/numo/types/int_macro.h +66 -0
- data/ext/numo/narray/numo/types/real_accum.h +481 -0
- data/ext/numo/narray/numo/types/robj_macro.h +78 -0
- data/ext/numo/narray/numo/types/robject.h +25 -0
- data/ext/numo/narray/numo/types/scomplex.h +42 -0
- data/ext/numo/narray/numo/types/sfloat.h +45 -0
- data/ext/numo/narray/numo/types/uint16.h +24 -0
- data/ext/numo/narray/numo/types/uint32.h +20 -0
- data/ext/numo/narray/numo/types/uint64.h +20 -0
- data/ext/numo/narray/numo/types/uint8.h +20 -0
- data/ext/numo/narray/numo/types/uint_macro.h +57 -0
- data/ext/numo/narray/numo/types/xint_macro.h +166 -0
- data/ext/numo/narray/rand.c +40 -0
- data/ext/numo/narray/src/t_bit.c +3236 -0
- data/ext/numo/narray/src/t_dcomplex.c +6776 -0
- data/ext/numo/narray/src/t_dfloat.c +9417 -0
- data/ext/numo/narray/src/t_int16.c +5757 -0
- data/ext/numo/narray/src/t_int32.c +5757 -0
- data/ext/numo/narray/src/t_int64.c +5759 -0
- data/ext/numo/narray/src/t_int8.c +5355 -0
- data/ext/numo/narray/src/t_robject.c +5567 -0
- data/ext/numo/narray/src/t_scomplex.c +6731 -0
- data/ext/numo/narray/src/t_sfloat.c +9374 -0
- data/ext/numo/narray/src/t_uint16.c +5753 -0
- data/ext/numo/narray/src/t_uint32.c +5753 -0
- data/ext/numo/narray/src/t_uint64.c +5755 -0
- data/ext/numo/narray/src/t_uint8.c +5351 -0
- data/ext/numo/narray/step.c +266 -0
- data/ext/numo/narray/struct.c +814 -0
- data/lib/numo/narray/extra.rb +1266 -0
- data/lib/numo/narray.rb +4 -0
- metadata +106 -0
@@ -0,0 +1,1266 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Numo
|
4
|
+
class NArray
|
5
|
+
# Return an unallocated array with the same shape and type as self.
|
6
|
+
def new_narray
|
7
|
+
self.class.new(*shape)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Return an array of zeros with the same shape and type as self.
|
11
|
+
def new_zeros
|
12
|
+
self.class.zeros(*shape)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return an array of ones with the same shape and type as self.
|
16
|
+
def new_ones
|
17
|
+
self.class.ones(*shape)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return an array filled with value with the same shape and type as self.
|
21
|
+
def new_fill(value)
|
22
|
+
self.class.new(*shape).fill(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Convert angles from radians to degrees.
|
26
|
+
def rad2deg
|
27
|
+
self * (180 / Math::PI)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Convert angles from degrees to radians.
|
31
|
+
def deg2rad
|
32
|
+
self * (Math::PI / 180)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Flip each row in the left/right direction.
|
36
|
+
# Same as `a[true, (-1..0).step(-1), ...]`.
|
37
|
+
def fliplr
|
38
|
+
reverse(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Flip each column in the up/down direction.
|
42
|
+
# Same as `a[(-1..0).step(-1), ...]`.
|
43
|
+
def flipud
|
44
|
+
reverse(0)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Rotate in the plane specified by axes.
|
48
|
+
# @example
|
49
|
+
# a = Numo::Int32.new(2,2).seq
|
50
|
+
# # => Numo::Int32#shape=[2,2]
|
51
|
+
# # [[0, 1],
|
52
|
+
# # [2, 3]]
|
53
|
+
#
|
54
|
+
# a.rot90
|
55
|
+
# # => Numo::Int32(view)#shape=[2,2]
|
56
|
+
# # [[1, 3],
|
57
|
+
# # [0, 2]]
|
58
|
+
#
|
59
|
+
# a.rot90(2)
|
60
|
+
# # => Numo::Int32(view)#shape=[2,2]
|
61
|
+
# # [[3, 2],
|
62
|
+
# # [1, 0]]
|
63
|
+
#
|
64
|
+
# a.rot90(3)
|
65
|
+
# # => Numo::Int32(view)#shape=[2,2]
|
66
|
+
# # [[2, 0],
|
67
|
+
# # [3, 1]]
|
68
|
+
def rot90(k = 1, axes = [0, 1])
|
69
|
+
case k % 4
|
70
|
+
when 0
|
71
|
+
view
|
72
|
+
when 1
|
73
|
+
swapaxes(*axes).reverse(axes[0])
|
74
|
+
when 2
|
75
|
+
reverse(*axes)
|
76
|
+
when 3
|
77
|
+
swapaxes(*axes).reverse(axes[1])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_i
|
82
|
+
# convert to Int?
|
83
|
+
raise TypeError, "can't convert #{self.class} into Integer" unless size == 1
|
84
|
+
|
85
|
+
self[0].to_i
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_f
|
89
|
+
# convert to DFloat?
|
90
|
+
raise TypeError, "can't convert #{self.class} into Float" unless size == 1
|
91
|
+
|
92
|
+
self[0].to_f
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_c
|
96
|
+
# convert to DComplex?
|
97
|
+
raise TypeError, "can't convert #{self.class} into Complex" unless size == 1
|
98
|
+
|
99
|
+
Complex(self[0])
|
100
|
+
end
|
101
|
+
|
102
|
+
# Convert the argument to an narray if not an narray.
|
103
|
+
def self.cast(a)
|
104
|
+
case a
|
105
|
+
when NArray
|
106
|
+
a
|
107
|
+
when Array, Numeric
|
108
|
+
NArray.array_type(a).cast(a)
|
109
|
+
else
|
110
|
+
raise TypeError, 'invalid type for NArray' unless a.respond_to?(:to_a)
|
111
|
+
|
112
|
+
a = a.to_a
|
113
|
+
NArray.array_type(a).cast(a)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.asarray(a)
|
118
|
+
case a
|
119
|
+
when NArray
|
120
|
+
a.ndim == 0 ? a[:new] : a
|
121
|
+
when Numeric, Range
|
122
|
+
self[a]
|
123
|
+
else
|
124
|
+
cast(a)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# parse matrix like matlab, octave
|
129
|
+
# @example
|
130
|
+
# a = Numo::DFloat.parse %[
|
131
|
+
# 2 -3 5
|
132
|
+
# 4 9 7
|
133
|
+
# 2 -1 6
|
134
|
+
# ]
|
135
|
+
# # => Numo::DFloat#shape=[3,3]
|
136
|
+
# # [[2, -3, 5],
|
137
|
+
# # [4, 9, 7],
|
138
|
+
# # [2, -1, 6]]
|
139
|
+
|
140
|
+
def self.parse(str, split1d: /\s+/, split2d: /;?$|;/,
|
141
|
+
split3d: /\s*\n(\s*\n)+/m)
|
142
|
+
a = []
|
143
|
+
str.split(split3d).each do |block|
|
144
|
+
b = []
|
145
|
+
# print "b"; p block
|
146
|
+
block.split(split2d).each do |line|
|
147
|
+
# p line
|
148
|
+
line.strip!
|
149
|
+
next if line.empty?
|
150
|
+
|
151
|
+
c = []
|
152
|
+
line.split(split1d).each do |item|
|
153
|
+
c << eval(item.strip) unless item.empty? # rubocop:disable Security/Eval
|
154
|
+
end
|
155
|
+
b << c unless c.empty?
|
156
|
+
end
|
157
|
+
a << b unless b.empty?
|
158
|
+
end
|
159
|
+
if a.size == 1
|
160
|
+
cast(a[0])
|
161
|
+
else
|
162
|
+
cast(a)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Iterate over an axis
|
167
|
+
# @example
|
168
|
+
# > a = Numo::DFloat.new(2,2,2).seq
|
169
|
+
# > p a
|
170
|
+
# Numo::DFloat#shape=[2,2,2]
|
171
|
+
# [[[0, 1],
|
172
|
+
# [2, 3]],
|
173
|
+
# [[4, 5],
|
174
|
+
# [6, 7]]]
|
175
|
+
#
|
176
|
+
# > a.each_over_axis{|i| p i}
|
177
|
+
# Numo::DFloat(view)#shape=[2,2]
|
178
|
+
# [[0, 1],
|
179
|
+
# [2, 3]]
|
180
|
+
# Numo::DFloat(view)#shape=[2,2]
|
181
|
+
# [[4, 5],
|
182
|
+
# [6, 7]]
|
183
|
+
#
|
184
|
+
# > a.each_over_axis(1){|i| p i}
|
185
|
+
# Numo::DFloat(view)#shape=[2,2]
|
186
|
+
# [[0, 1],
|
187
|
+
# [4, 5]]
|
188
|
+
# Numo::DFloat(view)#shape=[2,2]
|
189
|
+
# [[2, 3],
|
190
|
+
# [6, 7]]
|
191
|
+
|
192
|
+
def each_over_axis(axis = 0)
|
193
|
+
return to_enum(:each_over_axis, axis) unless block_given?
|
194
|
+
|
195
|
+
if ndim == 0
|
196
|
+
raise ArgumentError, "axis=#{axis} is invalid" if axis != 0
|
197
|
+
|
198
|
+
niter = 1
|
199
|
+
else
|
200
|
+
axis = check_axis(axis)
|
201
|
+
niter = shape[axis]
|
202
|
+
end
|
203
|
+
idx = [true] * ndim
|
204
|
+
niter.times do |i|
|
205
|
+
idx[axis] = i
|
206
|
+
yield(self[*idx])
|
207
|
+
end
|
208
|
+
self
|
209
|
+
end
|
210
|
+
|
211
|
+
# Append values to the end of an narray.
|
212
|
+
# @example
|
213
|
+
# a = Numo::DFloat[1, 2, 3]
|
214
|
+
# a.append([[4, 5, 6], [7, 8, 9]])
|
215
|
+
# # => Numo::DFloat#shape=[9]
|
216
|
+
# # [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
217
|
+
#
|
218
|
+
# a = Numo::DFloat[[1, 2, 3]]
|
219
|
+
# a.append([[4, 5, 6], [7, 8, 9]],axis:0)
|
220
|
+
# # => Numo::DFloat#shape=[3,3]
|
221
|
+
# # [[1, 2, 3],
|
222
|
+
# # [4, 5, 6],
|
223
|
+
# # [7, 8, 9]]
|
224
|
+
#
|
225
|
+
# a = Numo::DFloat[[1, 2, 3], [4, 5, 6]]
|
226
|
+
# a.append([7, 8, 9], axis:0)
|
227
|
+
# # in `append': dimension mismatch (Numo::NArray::DimensionError)
|
228
|
+
|
229
|
+
def append(other, axis: nil)
|
230
|
+
other = self.class.cast(other)
|
231
|
+
if axis
|
232
|
+
raise DimensionError, 'dimension mismatch' if ndim != other.ndim
|
233
|
+
|
234
|
+
concatenate(other, axis: axis)
|
235
|
+
else
|
236
|
+
a = self.class.zeros(size + other.size)
|
237
|
+
a[0...size] = self[true]
|
238
|
+
a[size..-1] = other[true]
|
239
|
+
a
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Return a new array with sub-arrays along an axis deleted.
|
244
|
+
# If axis is not given, obj is applied to the flattened array.
|
245
|
+
|
246
|
+
# @example
|
247
|
+
# a = Numo::DFloat[[1,2,3,4], [5,6,7,8], [9,10,11,12]]
|
248
|
+
# a.delete(1,0)
|
249
|
+
# # => Numo::DFloat(view)#shape=[2,4]
|
250
|
+
# # [[1, 2, 3, 4],
|
251
|
+
# # [9, 10, 11, 12]]
|
252
|
+
#
|
253
|
+
# a.delete((0..-1).step(2),1)
|
254
|
+
# # => Numo::DFloat(view)#shape=[3,2]
|
255
|
+
# # [[2, 4],
|
256
|
+
# # [6, 8],
|
257
|
+
# # [10, 12]]
|
258
|
+
#
|
259
|
+
# a.delete([1,3,5])
|
260
|
+
# # => Numo::DFloat(view)#shape=[9]
|
261
|
+
# # [1, 3, 5, 7, 8, 9, 10, 11, 12]
|
262
|
+
|
263
|
+
def delete(indice, axis = nil)
|
264
|
+
if axis
|
265
|
+
bit = Bit.ones(shape[axis])
|
266
|
+
bit[indice] = 0
|
267
|
+
idx = [true] * ndim
|
268
|
+
idx[axis] = bit.where
|
269
|
+
self[*idx].copy
|
270
|
+
else
|
271
|
+
bit = Bit.ones(size)
|
272
|
+
bit[indice] = 0
|
273
|
+
self[bit.where].copy
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# Insert values along the axis before the indices.
|
278
|
+
# @example
|
279
|
+
# a = Numo::DFloat[[1, 2], [3, 4]]
|
280
|
+
# a = Numo::Int32[[1, 1], [2, 2], [3, 3]]
|
281
|
+
#
|
282
|
+
# a.insert(1,5)
|
283
|
+
# # => Numo::Int32#shape=[7]
|
284
|
+
# # [1, 5, 1, 2, 2, 3, 3]
|
285
|
+
#
|
286
|
+
# a.insert(1, 5, axis:1)
|
287
|
+
# # => Numo::Int32#shape=[3,3]
|
288
|
+
# # [[1, 5, 1],
|
289
|
+
# # [2, 5, 2],
|
290
|
+
# # [3, 5, 3]]
|
291
|
+
#
|
292
|
+
# a.insert([1], [[11],[12],[13]], axis:1)
|
293
|
+
# # => Numo::Int32#shape=[3,3]
|
294
|
+
# # [[1, 11, 1],
|
295
|
+
# # [2, 12, 2],
|
296
|
+
# # [3, 13, 3]]
|
297
|
+
#
|
298
|
+
# a.insert(1, [11, 12, 13], axis:1)
|
299
|
+
# # => Numo::Int32#shape=[3,3]
|
300
|
+
# # [[1, 11, 1],
|
301
|
+
# # [2, 12, 2],
|
302
|
+
# # [3, 13, 3]]
|
303
|
+
#
|
304
|
+
# a.insert([1], [11, 12, 13], axis:1)
|
305
|
+
# # => Numo::Int32#shape=[3,5]
|
306
|
+
# # [[1, 11, 12, 13, 1],
|
307
|
+
# # [2, 11, 12, 13, 2],
|
308
|
+
# # [3, 11, 12, 13, 3]]
|
309
|
+
#
|
310
|
+
# b = a.flatten
|
311
|
+
# # => Numo::Int32(view)#shape=[6]
|
312
|
+
# # [1, 1, 2, 2, 3, 3]
|
313
|
+
#
|
314
|
+
# b.insert(2,[15,16])
|
315
|
+
# # => Numo::Int32#shape=[8]
|
316
|
+
# # [1, 1, 15, 16, 2, 2, 3, 3]
|
317
|
+
#
|
318
|
+
# b.insert([2,2],[15,16])
|
319
|
+
# # => Numo::Int32#shape=[8]
|
320
|
+
# # [1, 1, 15, 16, 2, 2, 3, 3]
|
321
|
+
#
|
322
|
+
# b.insert([2,1],[15,16])
|
323
|
+
# # => Numo::Int32#shape=[8]
|
324
|
+
# # [1, 16, 1, 15, 2, 2, 3, 3]
|
325
|
+
#
|
326
|
+
# b.insert([2,0,1],[15,16,17])
|
327
|
+
# # => Numo::Int32#shape=[9]
|
328
|
+
# # [16, 1, 17, 1, 15, 2, 2, 3, 3]
|
329
|
+
#
|
330
|
+
# b.insert(2..3, [15, 16])
|
331
|
+
# # => Numo::Int32#shape=[8]
|
332
|
+
# # [1, 1, 15, 2, 16, 2, 3, 3]
|
333
|
+
#
|
334
|
+
# b.insert(2, [7.13, 0.5])
|
335
|
+
# # => Numo::Int32#shape=[8]
|
336
|
+
# # [1, 1, 7, 0, 2, 2, 3, 3]
|
337
|
+
#
|
338
|
+
# x = Numo::DFloat.new(2,4).seq
|
339
|
+
# # => Numo::DFloat#shape=[2,4]
|
340
|
+
# # [[0, 1, 2, 3],
|
341
|
+
# # [4, 5, 6, 7]]
|
342
|
+
#
|
343
|
+
# x.insert([1,3],999,axis:1)
|
344
|
+
# # => Numo::DFloat#shape=[2,6]
|
345
|
+
# # [[0, 999, 1, 2, 999, 3],
|
346
|
+
# # [4, 999, 5, 6, 999, 7]]
|
347
|
+
|
348
|
+
def insert(indice, values, axis: nil)
|
349
|
+
if axis
|
350
|
+
values = self.class.asarray(values)
|
351
|
+
nd = values.ndim
|
352
|
+
midx = ([:new] * (ndim - nd)) + ([true] * nd)
|
353
|
+
case indice
|
354
|
+
when Numeric
|
355
|
+
midx[-nd - 1] = true
|
356
|
+
midx[axis] = :new
|
357
|
+
end
|
358
|
+
values = values[*midx]
|
359
|
+
else
|
360
|
+
values = self.class.asarray(values).flatten
|
361
|
+
end
|
362
|
+
idx = Int64.asarray(indice)
|
363
|
+
nidx = idx.size
|
364
|
+
if nidx == 1
|
365
|
+
nidx = values.shape[axis || 0]
|
366
|
+
idx += Int64.new(nidx).seq
|
367
|
+
else
|
368
|
+
sidx = idx.sort_index
|
369
|
+
idx[sidx] += Int64.new(nidx).seq
|
370
|
+
end
|
371
|
+
if axis
|
372
|
+
bit = Bit.ones(shape[axis] + nidx)
|
373
|
+
bit[idx] = 0
|
374
|
+
new_shape = shape
|
375
|
+
new_shape[axis] += nidx
|
376
|
+
a = self.class.zeros(new_shape)
|
377
|
+
mdidx = [true] * ndim
|
378
|
+
mdidx[axis] = bit.where
|
379
|
+
a[*mdidx] = self
|
380
|
+
mdidx[axis] = idx
|
381
|
+
a[*mdidx] = values
|
382
|
+
else
|
383
|
+
bit = Bit.ones(size + nidx)
|
384
|
+
bit[idx] = 0
|
385
|
+
a = self.class.zeros(size + nidx)
|
386
|
+
a[bit.where] = flatten
|
387
|
+
a[idx] = values
|
388
|
+
end
|
389
|
+
a
|
390
|
+
end
|
391
|
+
|
392
|
+
class << self
|
393
|
+
# @example
|
394
|
+
# a = Numo::DFloat[[1, 2], [3, 4]]
|
395
|
+
# # => Numo::DFloat#shape=[2,2]
|
396
|
+
# # [[1, 2],
|
397
|
+
# # [3, 4]]
|
398
|
+
#
|
399
|
+
# b = Numo::DFloat[[5, 6]]
|
400
|
+
# # => Numo::DFloat#shape=[1,2]
|
401
|
+
# # [[5, 6]]
|
402
|
+
#
|
403
|
+
# Numo::NArray.concatenate([a,b],axis:0)
|
404
|
+
# # => Numo::DFloat#shape=[3,2]
|
405
|
+
# # [[1, 2],
|
406
|
+
# # [3, 4],
|
407
|
+
# # [5, 6]]
|
408
|
+
#
|
409
|
+
# Numo::NArray.concatenate([a,b.transpose], axis:1)
|
410
|
+
# # => Numo::DFloat#shape=[2,3]
|
411
|
+
# # [[1, 2, 5],
|
412
|
+
# # [3, 4, 6]]
|
413
|
+
|
414
|
+
def concatenate(arrays, axis: 0)
|
415
|
+
klass = self == NArray ? NArray.array_type(arrays) : self
|
416
|
+
nd = 0
|
417
|
+
arrays = arrays.map do |a|
|
418
|
+
case a
|
419
|
+
when NArray
|
420
|
+
# ok
|
421
|
+
when Numeric
|
422
|
+
a = klass[a]
|
423
|
+
when Array
|
424
|
+
a = klass.cast(a)
|
425
|
+
else
|
426
|
+
raise TypeError, "not Numo::NArray: #{a.inspect[0..48]}"
|
427
|
+
end
|
428
|
+
nd = a.ndim if a.ndim > nd
|
429
|
+
a
|
430
|
+
end
|
431
|
+
axis += nd if axis < 0
|
432
|
+
raise ArgumentError, 'axis is out of range' if axis < 0 || axis >= nd
|
433
|
+
|
434
|
+
new_shape = nil
|
435
|
+
sum_size = 0
|
436
|
+
arrays.each do |a|
|
437
|
+
a_shape = a.shape
|
438
|
+
a_shape = ([1] * (nd - a_shape.size)) + a_shape if nd != a_shape.size # rubocop:disable Performance/CollectionLiteralInLoop
|
439
|
+
sum_size += a_shape.delete_at(axis)
|
440
|
+
if new_shape
|
441
|
+
raise ShapeError, 'shape mismatch' if new_shape != a_shape
|
442
|
+
else
|
443
|
+
new_shape = a_shape
|
444
|
+
end
|
445
|
+
end
|
446
|
+
new_shape.insert(axis, sum_size)
|
447
|
+
result = klass.zeros(*new_shape)
|
448
|
+
lst = 0
|
449
|
+
refs = [true] * nd
|
450
|
+
arrays.each do |a|
|
451
|
+
fst = lst
|
452
|
+
lst = fst + (a.shape[axis - nd] || 1)
|
453
|
+
if lst > fst
|
454
|
+
refs[axis] = fst...lst
|
455
|
+
result[*refs] = a
|
456
|
+
end
|
457
|
+
end
|
458
|
+
result
|
459
|
+
end
|
460
|
+
|
461
|
+
# Stack arrays vertically (row wise).
|
462
|
+
# @example
|
463
|
+
# a = Numo::Int32[1,2,3]
|
464
|
+
# b = Numo::Int32[2,3,4]
|
465
|
+
# Numo::NArray.vstack([a,b])
|
466
|
+
# # => Numo::Int32#shape=[2,3]
|
467
|
+
# # [[1, 2, 3],
|
468
|
+
# # [2, 3, 4]]
|
469
|
+
#
|
470
|
+
# a = Numo::Int32[[1],[2],[3]]
|
471
|
+
# b = Numo::Int32[[2],[3],[4]]
|
472
|
+
# Numo::NArray.vstack([a,b])
|
473
|
+
# # => Numo::Int32#shape=[6,1]
|
474
|
+
# # [[1],
|
475
|
+
# # [2],
|
476
|
+
# # [3],
|
477
|
+
# # [2],
|
478
|
+
# # [3],
|
479
|
+
# # [4]]
|
480
|
+
|
481
|
+
def vstack(arrays)
|
482
|
+
arys = arrays.map do |a|
|
483
|
+
_atleast_2d(cast(a))
|
484
|
+
end
|
485
|
+
concatenate(arys, axis: 0)
|
486
|
+
end
|
487
|
+
|
488
|
+
# Stack arrays horizontally (column wise).
|
489
|
+
# @example
|
490
|
+
# a = Numo::Int32[1,2,3]
|
491
|
+
# b = Numo::Int32[2,3,4]
|
492
|
+
# Numo::NArray.hstack([a,b])
|
493
|
+
# # => Numo::Int32#shape=[6]
|
494
|
+
# # [1, 2, 3, 2, 3, 4]
|
495
|
+
#
|
496
|
+
# a = Numo::Int32[[1],[2],[3]]
|
497
|
+
# b = Numo::Int32[[2],[3],[4]]
|
498
|
+
# Numo::NArray.hstack([a,b])
|
499
|
+
# # => Numo::Int32#shape=[3,2]
|
500
|
+
# # [[1, 2],
|
501
|
+
# # [2, 3],
|
502
|
+
# # [3, 4]]
|
503
|
+
|
504
|
+
def hstack(arrays)
|
505
|
+
klass = self == NArray ? NArray.array_type(arrays) : self
|
506
|
+
nd = 0
|
507
|
+
arys = arrays.map do |a|
|
508
|
+
a = klass.cast(a)
|
509
|
+
nd = a.ndim if a.ndim > nd
|
510
|
+
a
|
511
|
+
end
|
512
|
+
dim = nd >= 2 ? 1 : 0
|
513
|
+
concatenate(arys, axis: dim)
|
514
|
+
end
|
515
|
+
|
516
|
+
# Stack arrays in depth wise (along third axis).
|
517
|
+
# @example
|
518
|
+
# a = Numo::Int32[1,2,3]
|
519
|
+
# b = Numo::Int32[2,3,4]
|
520
|
+
# Numo::NArray.dstack([a,b])
|
521
|
+
# # => Numo::Int32#shape=[1,3,2]
|
522
|
+
# # [[[1, 2],
|
523
|
+
# # [2, 3],
|
524
|
+
# # [3, 4]]]
|
525
|
+
#
|
526
|
+
# a = Numo::Int32[[1],[2],[3]]
|
527
|
+
# b = Numo::Int32[[2],[3],[4]]
|
528
|
+
# Numo::NArray.dstack([a,b])
|
529
|
+
# # => Numo::Int32#shape=[3,1,2]
|
530
|
+
# # [[[1, 2]],
|
531
|
+
# # [[2, 3]],
|
532
|
+
# # [[3, 4]]]
|
533
|
+
|
534
|
+
def dstack(arrays)
|
535
|
+
arys = arrays.map do |a|
|
536
|
+
_atleast_3d(cast(a))
|
537
|
+
end
|
538
|
+
concatenate(arys, axis: 2)
|
539
|
+
end
|
540
|
+
|
541
|
+
# Stack 1-d arrays into columns of a 2-d array.
|
542
|
+
# @example
|
543
|
+
# x = Numo::Int32[1,2,3]
|
544
|
+
# y = Numo::Int32[2,3,4]
|
545
|
+
# Numo::NArray.column_stack([x,y])
|
546
|
+
# # => Numo::Int32#shape=[3,2]
|
547
|
+
# # [[1, 2],
|
548
|
+
# # [2, 3],
|
549
|
+
# # [3, 4]]
|
550
|
+
|
551
|
+
def column_stack(arrays)
|
552
|
+
arys = arrays.map do |a|
|
553
|
+
a = cast(a)
|
554
|
+
case a.ndim
|
555
|
+
when 0 then a[:new, :new]
|
556
|
+
when 1 then a[true, :new]
|
557
|
+
else; a
|
558
|
+
end
|
559
|
+
end
|
560
|
+
concatenate(arys, axis: 1)
|
561
|
+
end
|
562
|
+
|
563
|
+
private
|
564
|
+
|
565
|
+
# Return an narray with at least two dimension.
|
566
|
+
def _atleast_2d(a)
|
567
|
+
case a.ndim
|
568
|
+
when 0 then a[:new, :new]
|
569
|
+
when 1 then a[:new, true]
|
570
|
+
else; a
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
# Return an narray with at least three dimension.
|
575
|
+
def _atleast_3d(a)
|
576
|
+
case a.ndim
|
577
|
+
when 0 then a[:new, :new, :new]
|
578
|
+
when 1 then a[:new, true, :new]
|
579
|
+
when 2 then a[true, true, :new]
|
580
|
+
else; a
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
# @example
|
586
|
+
# a = Numo::DFloat[[1, 2], [3, 4]]
|
587
|
+
# # => Numo::DFloat#shape=[2,2]
|
588
|
+
# # [[1, 2],
|
589
|
+
# # [3, 4]]
|
590
|
+
#
|
591
|
+
# b = Numo::DFloat[[5, 6]]
|
592
|
+
# # => Numo::DFloat#shape=[1,2]
|
593
|
+
# # [[5, 6]]
|
594
|
+
#
|
595
|
+
# a.concatenate(b,axis:0)
|
596
|
+
# # => Numo::DFloat#shape=[3,2]
|
597
|
+
# # [[1, 2],
|
598
|
+
# # [3, 4],
|
599
|
+
# # [5, 6]]
|
600
|
+
#
|
601
|
+
# a.concatenate(b.transpose, axis:1)
|
602
|
+
# # => Numo::DFloat#shape=[2,3]
|
603
|
+
# # [[1, 2, 5],
|
604
|
+
# # [3, 4, 6]]
|
605
|
+
|
606
|
+
def concatenate(*arrays, axis: 0)
|
607
|
+
axis = check_axis(axis)
|
608
|
+
self_shape = shape
|
609
|
+
self_shape.delete_at(axis)
|
610
|
+
sum_size = shape[axis]
|
611
|
+
arrays.map! do |a|
|
612
|
+
case a
|
613
|
+
when NArray
|
614
|
+
# ok
|
615
|
+
when Numeric
|
616
|
+
a = self.class.new(1).store(a)
|
617
|
+
when Array
|
618
|
+
a = self.class.cast(a)
|
619
|
+
else
|
620
|
+
raise TypeError, "not Numo::NArray: #{a.inspect[0..48]}"
|
621
|
+
end
|
622
|
+
raise ShapeError, 'dimension mismatch' if a.ndim > ndim
|
623
|
+
|
624
|
+
a_shape = a.shape
|
625
|
+
sum_size += a_shape.delete_at(axis - ndim) || 1
|
626
|
+
raise ShapeError, 'shape mismatch' if self_shape != a_shape
|
627
|
+
|
628
|
+
a
|
629
|
+
end
|
630
|
+
self_shape.insert(axis, sum_size)
|
631
|
+
result = self.class.zeros(*self_shape)
|
632
|
+
lst = shape[axis]
|
633
|
+
refs = [true] * ndim
|
634
|
+
if lst > 0
|
635
|
+
refs[axis] = 0...lst
|
636
|
+
result[*refs] = self
|
637
|
+
end
|
638
|
+
arrays.each do |a|
|
639
|
+
fst = lst
|
640
|
+
lst = fst + (a.shape[axis - ndim] || 1)
|
641
|
+
if lst > fst
|
642
|
+
refs[axis] = fst...lst
|
643
|
+
result[*refs] = a
|
644
|
+
end
|
645
|
+
end
|
646
|
+
result
|
647
|
+
end
|
648
|
+
|
649
|
+
# @example
|
650
|
+
# x = Numo::DFloat.new(9).seq
|
651
|
+
# # => Numo::DFloat#shape=[9]
|
652
|
+
# # [0, 1, 2, 3, 4, 5, 6, 7, 8]
|
653
|
+
#
|
654
|
+
# x.split(3)
|
655
|
+
# # => [Numo::DFloat(view)#shape=[3]
|
656
|
+
# # [0, 1, 2],
|
657
|
+
# # Numo::DFloat(view)#shape=[3]
|
658
|
+
# # [3, 4, 5],
|
659
|
+
# # Numo::DFloat(view)#shape=[3]
|
660
|
+
# # [6, 7, 8]]
|
661
|
+
#
|
662
|
+
# x = Numo::DFloat.new(8).seq
|
663
|
+
# # => Numo::DFloat#shape=[8]
|
664
|
+
# # [0, 1, 2, 3, 4, 5, 6, 7]
|
665
|
+
#
|
666
|
+
# x.split([3, 5, 6, 10])
|
667
|
+
# # => [Numo::DFloat(view)#shape=[3]
|
668
|
+
# # [0, 1, 2],
|
669
|
+
# # Numo::DFloat(view)#shape=[2]
|
670
|
+
# # [3, 4],
|
671
|
+
# # Numo::DFloat(view)#shape=[1]
|
672
|
+
# # [5],
|
673
|
+
# # Numo::DFloat(view)#shape=[2]
|
674
|
+
# # [6, 7],
|
675
|
+
# # Numo::DFloat(view)#shape=[0][]]
|
676
|
+
|
677
|
+
def split(indices_or_sections, axis: 0)
|
678
|
+
axis = check_axis(axis)
|
679
|
+
size_axis = shape[axis]
|
680
|
+
case indices_or_sections
|
681
|
+
when Integer
|
682
|
+
div_axis, mod_axis = size_axis.divmod(indices_or_sections)
|
683
|
+
refs = [true] * ndim
|
684
|
+
beg_idx = 0
|
685
|
+
Array.new(mod_axis) do |_i|
|
686
|
+
end_idx = beg_idx + div_axis + 1
|
687
|
+
refs[axis] = beg_idx...end_idx
|
688
|
+
beg_idx = end_idx
|
689
|
+
self[*refs]
|
690
|
+
end +
|
691
|
+
Array.new(indices_or_sections - mod_axis) do |_i|
|
692
|
+
end_idx = beg_idx + div_axis
|
693
|
+
refs[axis] = beg_idx...end_idx
|
694
|
+
beg_idx = end_idx
|
695
|
+
self[*refs]
|
696
|
+
end
|
697
|
+
when NArray
|
698
|
+
split(indices_or_sections.to_a, axis: axis)
|
699
|
+
when Array
|
700
|
+
refs = [true] * ndim
|
701
|
+
fst = 0
|
702
|
+
(indices_or_sections + [size_axis]).map do |lst|
|
703
|
+
lst = size_axis if lst > size_axis
|
704
|
+
refs[axis] = fst < size_axis ? fst...lst : -1...-1
|
705
|
+
fst = lst
|
706
|
+
self[*refs]
|
707
|
+
end
|
708
|
+
else
|
709
|
+
raise TypeError, 'argument must be Integer or Array'
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
# @example
|
714
|
+
# x = Numo::DFloat.new(4,4).seq
|
715
|
+
# # => Numo::DFloat#shape=[4,4]
|
716
|
+
# # [[0, 1, 2, 3],
|
717
|
+
# # [4, 5, 6, 7],
|
718
|
+
# # [8, 9, 10, 11],
|
719
|
+
# # [12, 13, 14, 15]]
|
720
|
+
#
|
721
|
+
# x.hsplit(2)
|
722
|
+
# # => [Numo::DFloat(view)#shape=[4,2]
|
723
|
+
# # [[0, 1],
|
724
|
+
# # [4, 5],
|
725
|
+
# # [8, 9],
|
726
|
+
# # [12, 13]],
|
727
|
+
# # Numo::DFloat(view)#shape=[4,2]
|
728
|
+
# # [[2, 3],
|
729
|
+
# # [6, 7],
|
730
|
+
# # [10, 11],
|
731
|
+
# # [14, 15]]]
|
732
|
+
#
|
733
|
+
# x.hsplit([3, 6])
|
734
|
+
# # => [Numo::DFloat(view)#shape=[4,3]
|
735
|
+
# # [[0, 1, 2],
|
736
|
+
# # [4, 5, 6],
|
737
|
+
# # [8, 9, 10],
|
738
|
+
# # [12, 13, 14]],
|
739
|
+
# # Numo::DFloat(view)#shape=[4,1]
|
740
|
+
# # [[3],
|
741
|
+
# # [7],
|
742
|
+
# # [11],
|
743
|
+
# # [15]],
|
744
|
+
# # Numo::DFloat(view)#shape=[4,0][]]
|
745
|
+
|
746
|
+
def vsplit(indices_or_sections)
|
747
|
+
split(indices_or_sections, axis: 0)
|
748
|
+
end
|
749
|
+
|
750
|
+
def hsplit(indices_or_sections)
|
751
|
+
split(indices_or_sections, axis: 1)
|
752
|
+
end
|
753
|
+
|
754
|
+
def dsplit(indices_or_sections)
|
755
|
+
split(indices_or_sections, axis: 2)
|
756
|
+
end
|
757
|
+
|
758
|
+
# @example
|
759
|
+
# a = Numo::NArray[0,1,2]
|
760
|
+
# # => Numo::Int32#shape=[3]
|
761
|
+
# # [0, 1, 2]
|
762
|
+
#
|
763
|
+
# a.tile(2)
|
764
|
+
# # => Numo::Int32#shape=[6]
|
765
|
+
# # [0, 1, 2, 0, 1, 2]
|
766
|
+
#
|
767
|
+
# a.tile(2,2)
|
768
|
+
# # => Numo::Int32#shape=[2,6]
|
769
|
+
# # [[0, 1, 2, 0, 1, 2],
|
770
|
+
# # [0, 1, 2, 0, 1, 2]]
|
771
|
+
#
|
772
|
+
# a.tile(2,1,2)
|
773
|
+
# # => Numo::Int32#shape=[2,1,6]
|
774
|
+
# # [[[0, 1, 2, 0, 1, 2]],
|
775
|
+
# # [[0, 1, 2, 0, 1, 2]]]
|
776
|
+
#
|
777
|
+
# b = Numo::NArray[[1, 2], [3, 4]]
|
778
|
+
# # => Numo::Int32#shape=[2,2]
|
779
|
+
# # [[1, 2],
|
780
|
+
# # [3, 4]]
|
781
|
+
#
|
782
|
+
# b.tile(2)
|
783
|
+
# # => Numo::Int32#shape=[2,4]
|
784
|
+
# # [[1, 2, 1, 2],
|
785
|
+
# # [3, 4, 3, 4]]
|
786
|
+
#
|
787
|
+
# b.tile(2,1)
|
788
|
+
# # => Numo::Int32#shape=[4,2]
|
789
|
+
# # [[1, 2],
|
790
|
+
# # [3, 4],
|
791
|
+
# # [1, 2],
|
792
|
+
# # [3, 4]]
|
793
|
+
#
|
794
|
+
# c = Numo::NArray[1,2,3,4]
|
795
|
+
# # => Numo::Int32#shape=[4]
|
796
|
+
# # [1, 2, 3, 4]
|
797
|
+
#
|
798
|
+
# c.tile(4,1)
|
799
|
+
# # => Numo::Int32#shape=[4,4]
|
800
|
+
# # [[1, 2, 3, 4],
|
801
|
+
# # [1, 2, 3, 4],
|
802
|
+
# # [1, 2, 3, 4],
|
803
|
+
# # [1, 2, 3, 4]]
|
804
|
+
|
805
|
+
def tile(*arg)
|
806
|
+
arg.each do |i|
|
807
|
+
raise ArgumentError, 'argument should be positive integer' if !i.is_a?(Integer) || i < 1
|
808
|
+
end
|
809
|
+
ns = arg.size
|
810
|
+
nd = ndim
|
811
|
+
shp = shape
|
812
|
+
new_shp = []
|
813
|
+
src_shp = []
|
814
|
+
res_shp = []
|
815
|
+
(nd - ns).times do
|
816
|
+
new_shp << 1
|
817
|
+
new_shp << (n = shp.shift)
|
818
|
+
src_shp << :new
|
819
|
+
src_shp << true
|
820
|
+
res_shp << n
|
821
|
+
end
|
822
|
+
(ns - nd).times do
|
823
|
+
new_shp << (m = arg.shift)
|
824
|
+
new_shp << 1
|
825
|
+
src_shp << :new
|
826
|
+
src_shp << :new
|
827
|
+
res_shp << m
|
828
|
+
end
|
829
|
+
[nd, ns].min.times do
|
830
|
+
new_shp << (m = arg.shift)
|
831
|
+
new_shp << (n = shp.shift)
|
832
|
+
src_shp << :new
|
833
|
+
src_shp << true
|
834
|
+
res_shp << (n * m)
|
835
|
+
end
|
836
|
+
self.class.new(*new_shp).store(self[*src_shp]).reshape(*res_shp)
|
837
|
+
end
|
838
|
+
|
839
|
+
# @example
|
840
|
+
# Numo::NArray[3].repeat(4)
|
841
|
+
# # => Numo::Int32#shape=[4]
|
842
|
+
# # [3, 3, 3, 3]
|
843
|
+
#
|
844
|
+
# x = Numo::NArray[[1,2],[3,4]]
|
845
|
+
# # => Numo::Int32#shape=[2,2]
|
846
|
+
# # [[1, 2],
|
847
|
+
# # [3, 4]]
|
848
|
+
#
|
849
|
+
# x.repeat(2)
|
850
|
+
# # => Numo::Int32#shape=[8]
|
851
|
+
# # [1, 1, 2, 2, 3, 3, 4, 4]
|
852
|
+
#
|
853
|
+
# x.repeat(3,axis:1)
|
854
|
+
# # => Numo::Int32#shape=[2,6]
|
855
|
+
# # [[1, 1, 1, 2, 2, 2],
|
856
|
+
# # [3, 3, 3, 4, 4, 4]]
|
857
|
+
#
|
858
|
+
# x.repeat([1,2],axis:0)
|
859
|
+
# # => Numo::Int32#shape=[3,2]
|
860
|
+
# # [[1, 2],
|
861
|
+
# # [3, 4],
|
862
|
+
# # [3, 4]]
|
863
|
+
|
864
|
+
def repeat(arg, axis: nil)
|
865
|
+
case axis
|
866
|
+
when Integer
|
867
|
+
axis = check_axis(axis)
|
868
|
+
c = self
|
869
|
+
when NilClass
|
870
|
+
c = flatten
|
871
|
+
axis = 0
|
872
|
+
else
|
873
|
+
raise ArgumentError, 'invalid axis'
|
874
|
+
end
|
875
|
+
case arg
|
876
|
+
when Integer
|
877
|
+
raise ArgumentError, 'argument should be positive integer' if !arg.is_a?(Integer) || arg < 1
|
878
|
+
|
879
|
+
idx = Array.new(c.shape[axis]) { |i| [i] * arg }.flatten
|
880
|
+
else
|
881
|
+
arg = arg.to_a
|
882
|
+
raise ArgumentError, 'repeat size shoud be equal to size along axis' if arg.size != c.shape[axis]
|
883
|
+
|
884
|
+
arg.each do |i|
|
885
|
+
raise ArgumentError, 'argument should be non-negative integer' if !i.is_a?(Integer) || i < 0
|
886
|
+
end
|
887
|
+
idx = arg.each_with_index.map { |a, i| [i] * a }.flatten
|
888
|
+
end
|
889
|
+
ref = [true] * c.ndim
|
890
|
+
ref[axis] = idx
|
891
|
+
c[*ref].copy
|
892
|
+
end
|
893
|
+
|
894
|
+
# Calculate the n-th discrete difference along given axis.
|
895
|
+
# @example
|
896
|
+
# x = Numo::DFloat[1, 2, 4, 7, 0]
|
897
|
+
# # => Numo::DFloat#shape=[5]
|
898
|
+
# # [1, 2, 4, 7, 0]
|
899
|
+
#
|
900
|
+
# x.diff
|
901
|
+
# # => Numo::DFloat#shape=[4]
|
902
|
+
# # [1, 2, 3, -7]
|
903
|
+
#
|
904
|
+
# x.diff(2)
|
905
|
+
# # => Numo::DFloat#shape=[3]
|
906
|
+
# # [1, 1, -10]
|
907
|
+
#
|
908
|
+
# x = Numo::DFloat[[1, 3, 6, 10], [0, 5, 6, 8]]
|
909
|
+
# # => Numo::DFloat#shape=[2,4]
|
910
|
+
# # [[1, 3, 6, 10],
|
911
|
+
# # [0, 5, 6, 8]]
|
912
|
+
#
|
913
|
+
# x.diff
|
914
|
+
# # => Numo::DFloat#shape=[2,3]
|
915
|
+
# # [[2, 3, 4],
|
916
|
+
# # [5, 1, 2]]
|
917
|
+
#
|
918
|
+
# x.diff(axis:0)
|
919
|
+
# # => Numo::DFloat#shape=[1,4]
|
920
|
+
# # [[-1, 2, 0, -2]]
|
921
|
+
|
922
|
+
def diff(n = 1, axis: -1)
|
923
|
+
axis = check_axis(axis)
|
924
|
+
raise ShapeError, "n=#{n} is invalid for shape[#{axis}]=#{shape[axis]}" if n < 0 || n >= shape[axis]
|
925
|
+
|
926
|
+
# calculate polynomial coefficient
|
927
|
+
c = self.class[-1, 1]
|
928
|
+
2.upto(n) do |i|
|
929
|
+
x = self.class.zeros(i + 1)
|
930
|
+
x[0..-2] = c
|
931
|
+
y = self.class.zeros(i + 1)
|
932
|
+
y[1..-1] = c
|
933
|
+
c = y - x
|
934
|
+
end
|
935
|
+
s = [true] * ndim
|
936
|
+
s[axis] = n..-1
|
937
|
+
result = self[*s].dup
|
938
|
+
sum = result.inplace
|
939
|
+
(n - 1).downto(0) do |i|
|
940
|
+
s = [true] * ndim
|
941
|
+
s[axis] = i..(-n - 1 + i)
|
942
|
+
sum + (self[*s] * c[i]) # inplace addition
|
943
|
+
end
|
944
|
+
result
|
945
|
+
end
|
946
|
+
|
947
|
+
# Upper triangular matrix.
|
948
|
+
# Return a copy with the elements below the k-th diagonal filled with zero.
|
949
|
+
def triu(k = 0)
|
950
|
+
dup.triu!(k)
|
951
|
+
end
|
952
|
+
|
953
|
+
# Upper triangular matrix.
|
954
|
+
# Fill the self elements below the k-th diagonal with zero.
|
955
|
+
def triu!(k = 0)
|
956
|
+
raise NArray::ShapeError, 'must be >= 2-dimensional array' if ndim < 2
|
957
|
+
|
958
|
+
if contiguous?
|
959
|
+
*shp, m, n = shape
|
960
|
+
idx = tril_indices(k - 1)
|
961
|
+
reshape!(*shp, m * n)
|
962
|
+
self[false, idx] = 0
|
963
|
+
reshape!(*shp, m, n)
|
964
|
+
else
|
965
|
+
store(triu(k))
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
# Return the indices for the upper-triangle on and above the k-th diagonal.
|
970
|
+
def triu_indices(k = 0)
|
971
|
+
raise NArray::ShapeError, 'must be >= 2-dimensional array' if ndim < 2
|
972
|
+
|
973
|
+
m, n = shape[-2..]
|
974
|
+
NArray.triu_indices(m, n, k)
|
975
|
+
end
|
976
|
+
|
977
|
+
# Return the indices for the upper-triangle on and above the k-th diagonal.
|
978
|
+
def self.triu_indices(m, n, k = 0)
|
979
|
+
x = Numo::Int64.new(m, 1).seq + k
|
980
|
+
y = Numo::Int64.new(1, n).seq
|
981
|
+
(x <= y).where
|
982
|
+
end
|
983
|
+
|
984
|
+
# Lower triangular matrix.
|
985
|
+
# Return a copy with the elements above the k-th diagonal filled with zero.
|
986
|
+
def tril(k = 0)
|
987
|
+
dup.tril!(k)
|
988
|
+
end
|
989
|
+
|
990
|
+
# Lower triangular matrix.
|
991
|
+
# Fill the self elements above the k-th diagonal with zero.
|
992
|
+
def tril!(k = 0)
|
993
|
+
raise NArray::ShapeError, 'must be >= 2-dimensional array' if ndim < 2
|
994
|
+
|
995
|
+
if contiguous?
|
996
|
+
idx = triu_indices(k + 1)
|
997
|
+
*shp, m, n = shape
|
998
|
+
reshape!(*shp, m * n)
|
999
|
+
self[false, idx] = 0
|
1000
|
+
reshape!(*shp, m, n)
|
1001
|
+
else
|
1002
|
+
store(tril(k))
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
# Return the indices for the lower-triangle on and below the k-th diagonal.
|
1007
|
+
def tril_indices(k = 0)
|
1008
|
+
raise NArray::ShapeError, 'must be >= 2-dimensional array' if ndim < 2
|
1009
|
+
|
1010
|
+
m, n = shape[-2..]
|
1011
|
+
NArray.tril_indices(m, n, k)
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
# Return the indices for the lower-triangle on and below the k-th diagonal.
|
1015
|
+
def self.tril_indices(m, n, k = 0)
|
1016
|
+
x = Numo::Int64.new(m, 1).seq + k
|
1017
|
+
y = Numo::Int64.new(1, n).seq
|
1018
|
+
(x >= y).where
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
# Return the k-th diagonal indices.
|
1022
|
+
def diag_indices(k = 0)
|
1023
|
+
raise NArray::ShapeError, 'must be >= 2-dimensional array' if ndim < 2
|
1024
|
+
|
1025
|
+
m, n = shape[-2..]
|
1026
|
+
NArray.diag_indices(m, n, k)
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
# Return the k-th diagonal indices.
|
1030
|
+
def self.diag_indices(m, n, k = 0)
|
1031
|
+
x = Numo::Int64.new(m, 1).seq + k
|
1032
|
+
y = Numo::Int64.new(1, n).seq
|
1033
|
+
(x.eq y).where
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
# Return a matrix whose diagonal is constructed by self along the last axis.
|
1037
|
+
def diag(k = 0)
|
1038
|
+
*shp, n = shape
|
1039
|
+
n += k.abs
|
1040
|
+
a = self.class.zeros(*shp, n, n)
|
1041
|
+
a.diagonal(k).store(self)
|
1042
|
+
a
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
# Return the sum along diagonals of the array.
|
1046
|
+
#
|
1047
|
+
# If 2-D array, computes the summation along its diagonal with the
|
1048
|
+
# given offset, i.e., sum of `a[i,i+offset]`.
|
1049
|
+
# If more than 2-D array, the diagonal is determined from the axes
|
1050
|
+
# specified by axis argument. The default is axis=[-2,-1].
|
1051
|
+
# @param offset [Integer] (optional, default=0) diagonal offset
|
1052
|
+
# @param axis [Array] (optional, default=[-2,-1]) diagonal axis
|
1053
|
+
# @param nan [Bool] (optional, default=false) nan-aware algorithm, i.e., if true then it ignores nan.
|
1054
|
+
|
1055
|
+
def trace(offset = nil, axis = nil, nan: false)
|
1056
|
+
diagonal(offset, axis).sum(nan: nan, axis: -1)
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
@@warn_slow_dot = false
|
1060
|
+
|
1061
|
+
# Dot product of two arrays.
|
1062
|
+
# @param b [Numo::NArray]
|
1063
|
+
# @return [Numo::NArray] return dot product
|
1064
|
+
|
1065
|
+
def dot(b)
|
1066
|
+
t = self.class::UPCAST[b.class]
|
1067
|
+
if defined?(Linalg) && [SFloat, DFloat, SComplex, DComplex].include?(t)
|
1068
|
+
Linalg.dot(self, b)
|
1069
|
+
else
|
1070
|
+
b = self.class.asarray(b)
|
1071
|
+
case b.ndim
|
1072
|
+
when 1
|
1073
|
+
mulsum(b, axis: -1)
|
1074
|
+
else
|
1075
|
+
case ndim
|
1076
|
+
when 0
|
1077
|
+
b.mulsum(self, axis: -2)
|
1078
|
+
when 1
|
1079
|
+
self[true, :new].mulsum(b, axis: -2)
|
1080
|
+
else
|
1081
|
+
unless @@warn_slow_dot
|
1082
|
+
nx = 200
|
1083
|
+
ns = 200_000
|
1084
|
+
am, an = shape[-2..]
|
1085
|
+
bm, bn = b.shape[-2..]
|
1086
|
+
if am > nx && an > nx && bm > nx && bn > nx &&
|
1087
|
+
size > ns && b.size > ns
|
1088
|
+
@@warn_slow_dot = true
|
1089
|
+
warn "\nwarning: Built-in matrix dot is slow. Consider installing Numo::Linalg.\n\n"
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
self[false, :new].mulsum(b[false, :new, true, true], axis: -2)
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
# Inner product of two arrays.
|
1099
|
+
# Same as `(a*b).sum(axis:-1)`.
|
1100
|
+
# @param b [Numo::NArray]
|
1101
|
+
# @param axis [Integer] applied axis
|
1102
|
+
# @return [Numo::NArray] return (a*b).sum(axis:axis)
|
1103
|
+
|
1104
|
+
def inner(b, axis: -1)
|
1105
|
+
mulsum(b, axis: axis)
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
# Outer product of two arrays.
|
1109
|
+
# Same as `self[false,:new] * b[false,:new,true]`.
|
1110
|
+
#
|
1111
|
+
# @param b [Numo::NArray]
|
1112
|
+
# @param axis [Integer] applied axis (default=-1)
|
1113
|
+
# @return [Numo::NArray] return outer product
|
1114
|
+
# @example
|
1115
|
+
# a = Numo::DFloat.ones(5)
|
1116
|
+
# # => Numo::DFloat#shape=[5]
|
1117
|
+
# # [1, 1, 1, 1, 1]
|
1118
|
+
#
|
1119
|
+
# b = Numo::DFloat.linspace(-2,2,5)
|
1120
|
+
# # => Numo::DFloat#shape=[5]
|
1121
|
+
# # [-2, -1, 0, 1, 2]
|
1122
|
+
#
|
1123
|
+
# a.outer(b)
|
1124
|
+
# # => Numo::DFloat#shape=[5,5]
|
1125
|
+
# # [[-2, -1, 0, 1, 2],
|
1126
|
+
# # [-2, -1, 0, 1, 2],
|
1127
|
+
# # [-2, -1, 0, 1, 2],
|
1128
|
+
# # [-2, -1, 0, 1, 2],
|
1129
|
+
# # [-2, -1, 0, 1, 2]]
|
1130
|
+
|
1131
|
+
def outer(b, axis: nil)
|
1132
|
+
b = NArray.cast(b)
|
1133
|
+
if axis.nil?
|
1134
|
+
self[false, :new] * (b.ndim == 0 ? b : b[false, :new, true])
|
1135
|
+
else
|
1136
|
+
md, nd = [ndim, b.ndim].minmax
|
1137
|
+
axis = check_axis(axis) - nd
|
1138
|
+
raise ArgumentError, "axis=#{axis} is out of range" if axis < -md
|
1139
|
+
|
1140
|
+
adim = [true] * ndim
|
1141
|
+
adim[axis + ndim + 1, 0] = :new
|
1142
|
+
bdim = [true] * b.ndim
|
1143
|
+
bdim[axis + b.ndim, 0] = :new
|
1144
|
+
self[*adim] * b[*bdim]
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
# Percentile
|
1149
|
+
#
|
1150
|
+
# @param q [Numo::NArray]
|
1151
|
+
# @param axis [Integer] applied axis
|
1152
|
+
# @return [Numo::NArray] return percentile
|
1153
|
+
def percentile(q, axis: nil)
|
1154
|
+
raise ArgumentError, 'q is out of range' if q < 0 || q > 100
|
1155
|
+
|
1156
|
+
x = self
|
1157
|
+
unless axis
|
1158
|
+
axis = 0
|
1159
|
+
x = x.flatten
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
sorted = x.sort(axis: axis)
|
1163
|
+
x = q / 100.0 * (sorted.shape[axis] - 1)
|
1164
|
+
r = x % 1
|
1165
|
+
i = x.floor
|
1166
|
+
refs = [true] * sorted.ndim
|
1167
|
+
refs[axis] = i
|
1168
|
+
if i == sorted.shape[axis] - 1
|
1169
|
+
sorted[*refs]
|
1170
|
+
else
|
1171
|
+
refs_upper = refs.dup
|
1172
|
+
refs_upper[axis] = i + 1
|
1173
|
+
sorted[*refs] + (r * (sorted[*refs_upper] - sorted[*refs]))
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
# Kronecker product of two arrays.
|
1178
|
+
#
|
1179
|
+
# kron(a,b)[k_0, k_1, ...] = a[i_0, i_1, ...] * b[j_0, j_1, ...]
|
1180
|
+
# where: k_n = i_n * b.shape[n] + j_n
|
1181
|
+
#
|
1182
|
+
# @param b [Numo::NArray]
|
1183
|
+
# @return [Numo::NArray] return Kronecker product
|
1184
|
+
# @example
|
1185
|
+
# Numo::DFloat[1,10,100].kron([5,6,7])
|
1186
|
+
# # => Numo::DFloat#shape=[9]
|
1187
|
+
# # [5, 6, 7, 50, 60, 70, 500, 600, 700]
|
1188
|
+
#
|
1189
|
+
# Numo::DFloat[5,6,7].kron([1,10,100])
|
1190
|
+
# # => Numo::DFloat#shape=[9]
|
1191
|
+
# # [5, 50, 500, 6, 60, 600, 7, 70, 700]
|
1192
|
+
#
|
1193
|
+
# Numo::DFloat.eye(2).kron(Numo::DFloat.ones(2,2))
|
1194
|
+
# # => Numo::DFloat#shape=[4,4]
|
1195
|
+
# # [[1, 1, 0, 0],
|
1196
|
+
# # [1, 1, 0, 0],
|
1197
|
+
# # [0, 0, 1, 1],
|
1198
|
+
# # [0, 0, 1, 1]]
|
1199
|
+
|
1200
|
+
def kron(b)
|
1201
|
+
b = NArray.cast(b)
|
1202
|
+
nda = ndim
|
1203
|
+
ndb = b.ndim
|
1204
|
+
shpa = shape
|
1205
|
+
shpb = b.shape
|
1206
|
+
adim = ([:new] * (2 * [ndb - nda, 0].max)) + ([true, :new] * nda)
|
1207
|
+
bdim = ([:new] * (2 * [nda - ndb, 0].max)) + ([:new, true] * ndb)
|
1208
|
+
shpr = (-[nda, ndb].max..-1).map { |i| (shpa[i] || 1) * (shpb[i] || 1) }
|
1209
|
+
(self[*adim] * b[*bdim]).reshape(*shpr)
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
# under construction
|
1213
|
+
def cov(y = nil, ddof: 1, fweights: nil, aweights: nil)
|
1214
|
+
m = if y
|
1215
|
+
NArray.vstack([self, y])
|
1216
|
+
else
|
1217
|
+
self
|
1218
|
+
end
|
1219
|
+
w = nil
|
1220
|
+
if fweights
|
1221
|
+
f = fweights
|
1222
|
+
w = f
|
1223
|
+
end
|
1224
|
+
if aweights
|
1225
|
+
a = aweights
|
1226
|
+
w = w ? w * a : a
|
1227
|
+
end
|
1228
|
+
if w
|
1229
|
+
w_sum = w.sum(axis: -1, keepdims: true)
|
1230
|
+
if ddof == 0
|
1231
|
+
fact = w_sum
|
1232
|
+
elsif aweights.nil?
|
1233
|
+
fact = w_sum - ddof
|
1234
|
+
else
|
1235
|
+
wa_sum = (w * a).sum(axis: -1, keepdims: true)
|
1236
|
+
fact = w_sum - (ddof * wa_sum / w_sum)
|
1237
|
+
end
|
1238
|
+
raise StandardError, 'Degrees of freedom <= 0 for slice' if (fact <= 0).any?
|
1239
|
+
else
|
1240
|
+
fact = m.shape[-1] - ddof
|
1241
|
+
end
|
1242
|
+
if w
|
1243
|
+
m -= (m * w).sum(axis: -1, keepdims: true) / w_sum
|
1244
|
+
mw = m * w
|
1245
|
+
else
|
1246
|
+
m -= m.mean(axis: -1, keepdims: true)
|
1247
|
+
mw = m
|
1248
|
+
end
|
1249
|
+
mt = m.ndim < 2 ? m : m.swapaxes(-2, -1)
|
1250
|
+
mw.dot(mt.conj) / fact
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
private
|
1254
|
+
|
1255
|
+
# @!visibility private
|
1256
|
+
def check_axis(axis)
|
1257
|
+
raise ArgumentError, "axis=#{axis} must be Integer" unless axis.is_a?(Integer)
|
1258
|
+
|
1259
|
+
a = axis
|
1260
|
+
a += ndim if a < 0
|
1261
|
+
raise ArgumentError, "axis=#{axis} is invalid" if a < 0 || a >= ndim
|
1262
|
+
|
1263
|
+
a
|
1264
|
+
end
|
1265
|
+
end
|
1266
|
+
end
|