🦚

Numo::NArray の使い方

2023/07/16に公開

デバッグ系

inspect

人間向け表記

NArray[5, 6].inspect  # => "Numo::Int32#shape=[2]\n[5, 6]"

.inspect_cols=, .inspect_cols

inspect 時の幅を設定する

v = NArray.inspect_cols   # => 80
NArray.inspect_cols = 16  # => 16
Int8.new(8).seq.inspect   # => "Numo::Int8#shape=[8]\n[0, 1, 2, ...]"
NArray.inspect_cols = v

.inspect_rows=, .inspect_rows

inspect 時の高さを設定する

v = NArray.inspect_rows     # => 20
NArray.inspect_rows = 2     # => 2
Int8.new(3, 2).seq.inspect  # => "Numo::Int8#shape=[3,2]\n[[0, 1], \n [2, 3], \n ..."
NArray.inspect_rows = v

.debug=

デバッグ表示の切り替え

NArray.debug = true
# Int8.new.seq
NArray.debug = false
NArray.debug rescue $!  # => #<NoMethodError: undefined method `debug' for Numo::NArray:Class>

debug_info

デバッグ情報を表示する

# Int8[5, 6].debug_info  # => nil

NArray.debug = true にしなくても表示する

.profile, .profile=

?

NArray.profile      # => 0.0
NArray.profile = 1  # => 1
NArray.profile      # => 1.0

生成

.new

次元を指定して作る

a = Int8.new(2, 3)  # => Numo::Int8#shape=[2,3](empty)

空の状態では参照できない

a[0] rescue $!  # => #<RuntimeError: cannot read unallocated NArray>

.[]

値を渡して作る

Int8[5, 6].inspect    # => "Numo::Int8#shape=[2]\n[5, 6]"
Int16[5, 6].inspect   # => "Numo::Int16#shape=[2]\n[5, 6]"
Int32[5, 6].inspect   # => "Numo::Int32#shape=[2]\n[5, 6]"
Int64[5, 6].inspect   # => "Numo::Int64#shape=[2]\n[5, 6]"
SFloat[5, 6].inspect  # => "Numo::SFloat#shape=[2]\n[5, 6]"
DFloat[5, 6].inspect  # => "Numo::DFloat#shape=[2]\n[5, 6]"

NArray[] を使うと適切な型が自動的に決まる

NArray[5].class            # => Numo::Int32
NArray[10000000000].class  # => Numo::Int64
NArray[5.0].class          # => Numo::DFloat
NArray[1.to_c].class       # => Numo::DComplex
NArray[true].class         # => Numo::Bit
NArray["a"].class          # => Numo::RObject

.cast

値を渡して作る

Int8.cast([5, 6]).to_a       # => [5, 6]
Int8.cast(Int64[5, 6]).to_a  # => [5, 6]

引数は1つだけなところが .[] と異なる

Int8.cast(5, 6) rescue $!  # => #<ArgumentError: wrong number of arguments (given 2, expected 1)>
Int8[5, 6].to_a            # => [5, 6]

cast_to

他の NArray から作る

Int8[5, 6].cast_to(Int64)  # => Numo::Int64#shape=[2]

元を破壊しない

この2つは同じ意味

Int64.cast(Int8[5, 6])     # => Numo::Int64#shape=[2]
Int8[5, 6].cast_to(Int64)  # => Numo::Int64#shape=[2]

.zeros

全部 0 で作る

Int8.zeros(5).to_a  # => [0, 0, 0, 0, 0]

.ones

全部 1 で作る

Int8.ones(5).to_a  # => [1, 1, 1, 1, 1]

.linspace

線型で作る

Int8.linspace(0, 100, 3).to_a  # => [0, 50, 100]

.logspace

累乗で作る

DFloat.logspace(2, 4, 3).to_a  # => [100.0, 1000.0, 10000.0]
[10.0**2, 10.0**3, 10.0**4]    # => [100.0, 1000.0, 10000.0]
Int64.logspace(2, 4, 3) rescue $!  # => #<NoMethodError: undefined method `logseq' for Numo::Int64#shape=[3](empty):Numo::Int64>

.parse

文字列から作る

NArray.parse(<<~EOT).to_a  # => [[1, 2, 3], [4, 5, 6]]
1 2 3
4 5 6
EOT

カンマ区切りの場合

NArray.parse("1, 2, 3", split1d: ",").to_a  # => [[1, 2, 3]]

.asarray

いろんな型の差異を吸収して NArray 化する

NArray.asarray(NArray[5, 6])    # => Numo::Int32#shape=[2]
NArray.asarray([5, 6])          # => Numo::Int32#shape=[2]
NArray.asarray(5..6)            # => Numo::Int32#shape=[2]
NArray.asarray(5)               # => Numo::Int32#shape=[1]
NArray.asarray(5, 6) rescue $!  # => #<ArgumentError: wrong number of arguments (given 2, expected 1)>
NArray.asarray("A") rescue $!   # => #<TypeError: invalid type for NArray>

.eye

単位行列を作る

a = Int8.eye(3).to_a
a[0]  # => [1, 0, 0]
a[1]  # => [0, 1, 0]
a[2]  # => [0, 0, 1]

.new_like

値から「未割り当て」の NArray を作る

NArray.new_like([1, 2])      # => Numo::Int32#shape=[2](empty)
NArray.new_like([1.0, 2.0])  # => Numo::DFloat#shape=[2](empty)
Int64.new_like([1, 2])       # => Numo::Int64#shape=[2](empty)

.[] や .cast と似ているが値は入っていない

埋める系

全部レシーバを破壊してしまうので注意する

seq, indgen

連番で埋める

a = Int8.new(4)
a.seq   # => Numo::Int8#shape=[4]
a.to_a  # => [0, 1, 2, 3]

元を破壊する

1 + i

Int8.new(4).seq(1).to_a  # => [1, 2, 3, 4]

10 + i * 2

Int8.new(4).seq(10, 2).to_a  # => [10, 12, 14, 16]

fill

塗り潰す

a = Int8.new(3)
a.fill(5)
a.to_a  # => [5, 5, 5]

元を破壊する

store

指定の値の羅列で埋める

a = Int8.new(3)
a.store(5)
a.to_a  # => [5, 5, 5]

要素が一つだと fill と変わらない。元を破壊する。

配列の場合は要素数が合っていなくても 0 で埋めたり切り捨てたりする

Int8.new(2).store([5]).to_a        # => [5, 0]
Int8.new(2).store([5, 6]).to_a     # => [5, 6]
Int8.new(2).store([5, 6, 7]).to_a  # => [5, 6]

だいたいビューに対して行う

a = Int8.ones(5)
a[1..3]           # => Numo::Int8(view)#shape=[3]
a[1..3].store(8)  # => Numo::Int8(view)#shape=[3]
a.to_a            # => [1, 8, 8, 8, 1]

logseq

べき乗で埋める

a = DFloat.new(3)
a.logseq(0, 2)
a.to_a           # => [1.0, 100.0, 10000.0]

10**(0 + 0 * 2)  # => 1
10**(0 + 1 * 2)  # => 100
10**(0 + 2 * 2)  # => 10000

元を破壊する

Int8.new(3).logseq(0, 2) rescue $!  # => #<NoMethodError: undefined method `logseq' for Numo::Int8#shape=[3](empty):Numo::Int8>

eye

単位行列にする

a = Int8.new(3, 3).seq
a.eye
a.to_a[0]  # => [1, 0, 0]
a.to_a[1]  # => [0, 1, 0]
a.to_a[2]  # => [0, 0, 1]

元を破壊する

乱数

rand

乱数で埋める

a = DFloat.new(2)
a.rand
a.to_a  # => [0.061754467473337606, 0.3730667918557394]
a.rand(5)
a.to_a  # => [3.974076127383806, 1.0052107667404373]

元を破壊する

rand_norm

正規乱数で埋める

a = DFloat.new(2)
a.rand_norm
a.to_a  # => [-0.8028018065626139, -0.32610562028036544]
a.rand_norm(5)
a.to_a  # => [5.282921532942489, 6.684267658020805]

元を破壊する

Int64.new(2).rand_norm rescue $!  # => #<NoMethodError: undefined method `rand_norm' for Numo::Int64#shape=[2](empty):Numo::Int64>

.srand

種を設定する

NArray.srand     # => nil
NArray.srand(0)  # => nil

次元を維持して作る

new_fill

新しく指定値で塗り潰したのを返す

a = Int8.new(3)
a.new_fill(1).to_a  # => [1, 1, 1]
a.to_a rescue $!    # => #<RuntimeError: cannot read unallocated NArray>

元を破壊しない

new_narray

shape を維持して新しい NArray を返す

a = Int8.new(3).seq
a.new_narray  # => Numo::Int8#shape=[3](empty)

以下と同じ

a.class.new(a.shape)  # => Numo::Int8#shape=[3](empty)

new_ones

新しく1で塗り潰したのを返す

a = Int8.new(3).seq
a.new_ones.to_a  # => [1, 1, 1]

new_zeros

新しく0で塗り潰したのを返す

a = Int8.new(3).seq
a.new_zeros.to_a  # => [0, 0, 0]

演算

数値に対する構文とほぼ同じ

a = NArray[1, 2]
b = NArray[3, 4]

(a + b).to_a             # => [4, 6]
(a - b).to_a             # => [-2, -2]
(a * b).to_a             # => [3, 8]
(a / b).to_a             # => [0, 0]
(a % b).to_a             # => [1, 2]
a.divmod(b).map(&:to_a)  # => [[0, 0], [1, 2]]
(a**b).to_a              # => [1, 16]
(-a).to_a                # => [-1, -2]
(-a).abs.to_a            # => [1, 2]

右辺があるメソッドは右辺が整数でもよいし入れ替えても動く

(a * 10).to_a  # => [10, 20]
(10 * a).to_a  # => [10, 20]

inplace

inplace 経由で演算するとなぜか元を更新できる

inplace

元を更新する (重要)

a = Int64[5, 6]
a.to_a          # => [5, 6]
a.object_id     # => 500
a.inplace * 10  # => Numo::Int64(view)#shape=[2]
a.to_a          # => [50, 60]
a.object_id     # => 500

結果的には次と同じだけど inplace を使った方が速い

a = Int64[5, 6]
a.object_id  # => 520
a *= 10
a.to_a       # => [50, 60]
a.object_id  # => 540

inplace!

inplace の破壊版

a = Int64[5, 6]
a.inplace!
a *= 10
a.to_a  # => [50, 60]

out_of_place! のし忘れに注意する

out_of_place!, not_inplace!

inplace を解除する

a = Int8[5, 6]
a.inplace!
a * 10
a.to_a  # => [50, 60]
a.out_of_place!
a * 10
a.to_a  # => [50, 60]

小数

ceil

上に近い整数 (を表す浮動小数点値を返す)

DFloat[5.1, 5.9].ceil.to_a  # => [6.0, 6.0]

floor

下に近い整数

DFloat[-1.1, -1.9].floor.to_a  # => [-2.0, -2.0]

round

四捨五入

DFloat[2.4, 2.5, 2.51].round.to_a  # => [2.0, 3.0, 3.0]
DFloat[0.1234].round(2) rescue $!  # => #<ArgumentError: wrong number of arguments (given 1, expected 0)>

rint

最も近い整数

DFloat[2.4, 2.5, 2.51].rint.to_a  # => [2.0, 2.0, 3.0]

trunc

小数部を捨てる

DFloat[-5.1, -5.9].trunc.to_a  # => [-5.0, -5.0]

nearly_eq

小数の誤差を考慮した同値比較

a = DFloat[1.000000000000001]
b = DFloat[1.000000000000002]
a.to_a  # => [1.000000000000001]
b.to_a  # => [1.000000000000002]

値同士の比較では一致しない

a.to_a == b.to_a  # => false

eq でも一致しない

a.eq(b).to_a  # => [0]

nearly_eq では一致する

a.nearly_eq(b).to_a  # => [1]

DFloat::Math

frexp を除いてすべて DFloat 型を返す

DFloat::Math.module_eval do
  acos(0.5).to_a                # => [1.0471975511965976]
  acosh(1.5).to_a               # => [0.9624236501192069]
  asin(0.5).to_a                # => [0.5235987755982988]
  asinh(0.5).to_a               # => [0.48121182505960347]
  atan(0.5).to_a                # => [0.46364760900080615]
  atan2(2, 4).to_a              # => [0.4636476090008061]
  atanh(0.5).to_a               # => [0.5493061443340549]
  cbrt(0.5).to_a                # => [0.7937005259840998]
  cos(0.5).to_a                 # => [0.8775825618903728]
  cosh(0.5).to_a                # => [1.1276259652063807]
  erf(0.5).to_a                 # => [0.5204998778130465]
  erfc(0.5).to_a                # => [0.4795001221869535]
  exp(0.5).to_a                 # => [1.6487212707001282]
  exp10(2).to_a                 # => [100.0]
  exp2(8).to_a                  # => [256.0]
  expm1(0.5).to_a               # => [0.6487212707001282]
  frexp(2.34).flat_map(&:to_a)  # => [0.585, 2]
  hypot(2, 3).to_a              # => [3.605551275463989]
  ldexp(1, 8).to_a              # => [256.0]
  log(3).to_a                   # => [1.0986122886681098]
  log10(8).to_a                 # => [0.9030899869919435]
  log1p(0.5).to_a               # => [0.4054651081081644]
  log2(256).to_a                # => [8.0]
  sin(0.5).to_a                 # => [0.479425538604203]
  sinc(0.5).to_a                # => [0.958851077208406]
  sinh(0.5).to_a                # => [0.5210953054937474]
  sqrt(4).to_a                  # => [2.0]
  tan(0.5).to_a                 # => [0.5463024898437905]
  tanh(0.5).to_a                # => [0.46211715726000974]
end

NMath は DFloat::Math に委譲する

NMath.log2(256)         # => Numo::DFloat#shape=[]
DFloat::Math.log2(256)  # => Numo::DFloat#shape=[]

統計

mean

平均

DFloat[1, 5, 7, 1000].mean  # => 253.25

median

中央値

DFloat[1, 5, 7, 1000].median  # => 6.0

square

2乗

a = DFloat[3, 4]
a.square.to_a     # => [9.0, 16.0]
a.to_a            # => [3.0, 4.0]
[3.0**2, 4.0**2]  # => [9.0, 16.0]

元を破壊しない

var

不偏分散

DFloat[3, 6, 9].var  # => 9.0

次と同じ

a = [3, 6, 9]
n = a.size
平均 = a.sum.fdiv(n)
a.sum { |e| (e - 平均)**2 } / (n - 1)  # => 9.0

stddev

標準偏差

DFloat[3, 6, 9].stddev          # => 3.0
Math.sqrt(DFloat[3, 6, 9].var)  # => 3.0

不偏分散のルート

sum

総和

DFloat[2, 3, 4].sum  # => 9.0

精度が低いけど速い

kahan_sum

カハンの加算アルゴリズムを使った総和

a = DFloat.ones(10000000) - 0.8
a.sum        # => 1999999.9996779507
a.kahan_sum  # => 1999999.9999999995

精度が高いけど遅い

x = Benchmark.ms { a.sum }        # => 9.209000039845705
y = Benchmark.ms { a.kahan_sum }  # => 140.67599992267787
y / x                             # => 15.275925650341822

https://ja.wikipedia.org/wiki/カハンの加算アルゴリズム

trace

斜めの合計

a = Int16.new(3, 3).seq
a.to_a[0]      # => [0, 1, 2]
a.to_a[1]      # => [3, 4, 5]
a.to_a[2]      # => [6, 7, 8]
a.trace        # => 12
[0, 4, 8].sum  # => 12

デバッグ用のメソッドかと思ったけど numpy にも同じのがあった

cumsum

累積和

Int8[2, 3, 4].cumsum.to_a                                # => [2, 5, 9]
[2, 3, 4].inject([]) { |a, e| [*a, (a.last || 0) + e] }  # => [2, 5, 9]

prod

総積

DFloat[2, 3, 4].prod   # => 24.0
[2, 3, 4].inject(&:*)  # => 24

cumprod

累積積

Int8[2, 3, 4].cumprod.to_a                               # => [2, 6, 24]
[2, 3, 4].inject([]) { |a, e| [*a, (a.last || 1) * e] }  # => [2, 6, 24]

mulsum

a = DFloat[2, 3]
b = DFloat[4, 5]
a.mulsum(b)    # => 23.0
2 * 4 + 3 * 5  # => 23

rms

二乗平均平方根

DFloat[5, 6, 7].rms  # => 6.0553007081949835

以下と同じ

v = [5, 6, 7]           # => [5, 6, 7]
v = v.map { |e| e**2 }  # => [25, 36, 49]
v = v.sum.fdiv(v.size)  # => 36.666666666666664
v = Math.sqrt(v)        # => 6.0553007081949835

reciprocal

逆数

DFloat[2, 3].reciprocal.to_a  # => [0.5, 0.3333333333333333]
[1.0 / 2, 1.0 / 3]            # => [0.5, 0.3333333333333333]

abs

絶対値

DFloat[-5, 6].abs.to_a  # => [5.0, 6.0]

max, max_index

最大値とインデックス

Int8[5, 6, 7].max        # => 7
Int8[5, 6, 7].max_index  # => 2

min, min_index

最小値とインデックス

Int8[5, 6, 7].min        # => 5
Int8[5, 6, 7].min_index  # => 0

minmax

最小・最大

Int8[5, 6, 7].minmax  # => [5, 7]

ptp

範囲の大きさを返す

a = DFloat[5, 6, 7]
a.ptp          # => 2.0
a.max - a.min  # => 2.0

sort

a = Int8[7, 6, 5]
a.sort.to_a  # => [5, 6, 7]
a.to_a       # => [7, 6, 5]

元を破壊しない

sort_index

並び換えることができるインデックス順を返す

a = Int8[8, 6, 9, 7]
a.to_a             # => [8, 6, 9, 7]
a.sort_index.to_a  # => [1, 3, 0, 2]
a[a.sort_index].to_a                # => [6, 7, 8, 9]
a.sort_index.map { |i| a[i] }.to_a  # => [6, 7, 8, 9]

format

文字列化して RObject を返す

DFloat[5, 6].format("%d %%")       # => Numo::RObject#shape=[2]
DFloat[5, 6].format("%d %%").to_a  # => ["5 %", "6 %"]

format_to_a

文字列化して Array を返す

DFloat[5, 6].format_to_a("%d %%")  # => ["5 %", "6 %"]

なんとか積

dot

内積

Int8[2, 3].dot(4)             # => 20
2 * 4 + 3 * 4                 # => 20
Int8[2, 3].dot([4, 5])        # => 23
2 * 4 + 3 * 5                 # => 23
Int8[2, 3].inner(Int8[4, 5])  # => 23

いろんな引数を解釈する。inner と似ているけど inner は NArray 型しか受け付けない。

inner

内積

Int8[2, 3].inner(Int8[4, 5])  # => 23
2 * 4 + 3 * 5                 # => 23

相手は NArray 型でないとだめ

Int8[2, 3].inner([4, 5]) rescue $!  # => #<TypeError: wrong argument type Array (expected Numo::NArray)>

outer

直積

Int64[2, 3].outer(Int64[4, 5]).to_a  # => [[8, 10], [12, 15]]
[[2 * 4, 2 * 5], [3 * 4, 3 * 5]]     # => [[8, 10], [12, 15]]
Int64[2, 3].kron(Int64[4, 5]).to_a   # => [8, 10, 12, 15]

kron のフラットにしない版

kron

クロネッカー積

Int64[2, 3].kron(Int64[4, 5]).to_a  # => [8, 10, 12, 15]
[2 * 4, 2 * 5, 3 * 4, 3 * 5]        # => [8, 10, 12, 15]

https://ja.wikipedia.org/wiki/クロネッカー積

角度

deg2rad

度数 → ラジアン

Int64[180].deg2rad.to_a  # => [3.141592653589793]

rad2deg

ラジアン → 度数

NArray[Math::PI].rad2deg.to_a  # => [180.0]

繰り返し

Int8[5, 6].each               rescue $!  # => #<LocalJumpError: no block given>
Int8[5, 6].map                rescue $!  # => #<LocalJumpError: no block given>
Int8[5, 6].each_with_index(1) rescue $!  # => #<ArgumentError: wrong number of arguments (given 1, expected 0)>
Int8[5, 6].map_with_index(1)  rescue $!  # => #<ArgumentError: wrong number of arguments (given 1, expected 0)>

each

a = []
Int8.new(2, 2).seq.each { |*e| a << e }
a  # => [[0], [1], [2], [3]]

each_with_index

a = []
Int8.new(2, 2).seq.each_with_index { |e, y, x| a << [e, y, x] }
a  # => [[0, 0, 0], [1, 0, 1], [2, 1, 0], [3, 1, 1]]

map

DFloat[5, 6].map(&:itself).to_a  # => [5.0, 6.0]
DFloat[5, 6].map(&:to_s) rescue $!  # => #<TypeError: no implicit conversion to float from string>

map_with_index

DFloat[5, 6].map_with_index { |e, i| e * i }.to_a  # => [0.0, 6.0]

each_over_axis

行毎または列毎に each する

a = Int8.new(3, 3).seq

行毎

v = []
a.each_over_axis(0) { |e| v << e }
v[0].inspect  # => "Numo::Int8(view)#shape=[3]\n[0, 1, 2]"
v[1].inspect  # => "Numo::Int8(view)#shape=[3]\n[3, 4, 5]"
v[2].inspect  # => "Numo::Int8(view)#shape=[3]\n[6, 7, 8]"

列毎

v = []
a.each_over_axis(1) { |e| v << e }
v[0].inspect  # => "Numo::Int8(view)#shape=[3]\n[0, 3, 6]"
v[1].inspect  # => "Numo::Int8(view)#shape=[3]\n[1, 4, 7]"
v[2].inspect  # => "Numo::Int8(view)#shape=[3]\n[2, 5, 8]"

反転

reverse

反転したビューを返す

a = Int8.new(3, 3).seq
a.to_a  # => [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

上下左右

a.reverse.to_a  # => [[8, 7, 6], [5, 4, 3], [2, 1, 0]]

上下

a.reverse(0).to_a  # => [[6, 7, 8], [3, 4, 5], [0, 1, 2]]

左右

a.reverse(1).to_a  # => [[2, 1, 0], [5, 4, 3], [8, 7, 6]]

flipud

上下反転

a = Int8.new(3, 3).seq
a.flipud.to_a      # => [[6, 7, 8], [3, 4, 5], [0, 1, 2]]
a.reverse(0).to_a  # => [[6, 7, 8], [3, 4, 5], [0, 1, 2]]

reverse(0) と同じ

fliplr

左右反転

a = Int8.new(3, 3).seq
a.fliplr.to_a      # => [[2, 1, 0], [5, 4, 3], [8, 7, 6]]
a.reverse(1).to_a  # => [[2, 1, 0], [5, 4, 3], [8, 7, 6]]

reverse(1) と同じ

三角系

.tril_indices

斜めに切ったときの左下△のインデックスを返す

a = Int8.new(3, 3).seq.to_a
a[0]                                # => [0, 1, 2]
a[1]                                # => [3, 4, 5]
a[2]                                # => [6, 7, 8]
NArray.tril_indices(3, 3, -2).to_a  # => [6]
NArray.tril_indices(3, 3, -1).to_a  # => [3, 6, 7]
NArray.tril_indices(3, 3, 0).to_a   # => [0, 3, 4, 6, 7, 8]
NArray.tril_indices(3, 3, 1).to_a   # => [0, 1, 3, 4, 5, 6, 7, 8]
NArray.tril_indices(3, 3, 2).to_a   # => [0, 1, 2, 3, 4, 5, 6, 7, 8]

.triu_indices

斜めに切ったときの右上△のインデックスを返す

a = Int8.new(3, 3).seq.to_a
a[0]                                # => [0, 1, 2]
a[1]                                # => [3, 4, 5]
a[2]                                # => [6, 7, 8]
NArray.triu_indices(3, 3, -2).to_a  # => [0, 1, 2, 3, 4, 5, 6, 7, 8]
NArray.triu_indices(3, 3, -1).to_a  # => [0, 1, 2, 3, 4, 5, 7, 8]
NArray.triu_indices(3, 3, 0).to_a   # => [0, 1, 2, 4, 5, 8]
NArray.triu_indices(3, 3, 1).to_a   # => [1, 2, 5]
NArray.triu_indices(3, 3, 2).to_a   # => [2]

tril

左下三角形を除いて 0 にしたのを返す

a = Int8.new(3, 3).seq(1)
a.tril.to_a[0]  # => [1, 0, 0]
a.tril.to_a[1]  # => [4, 5, 0]
a.tril.to_a[2]  # => [7, 8, 9]

tril!

trilの破壊版

a = Int8.new(3, 3).seq(1)
a.tril!
a.to_a[0]  # => [1, 0, 0]
a.to_a[1]  # => [4, 5, 0]
a.to_a[2]  # => [7, 8, 9]

tril_indices

左下三角形の領域のインデックスたちを返す

a = Int8.new(3, 3)
a.tril_indices.to_a  # => [0, 3, 4, 6, 7, 8]

triu

右上三角形を除いて 0 にしたのを返す

a = Int8.new(3, 3).seq(1)
a.triu.to_a[0]  # => [1, 2, 3]
a.triu.to_a[1]  # => [0, 5, 6]
a.triu.to_a[2]  # => [0, 0, 9]

triu!

triuの破壊版

a = Int8.new(3, 3).seq(1)
a.triu!
a.to_a[0]  # => [1, 2, 3]
a.to_a[1]  # => [0, 5, 6]
a.to_a[2]  # => [0, 0, 9]

triu_indices

右上三角形の領域のインデックスたちを返す

a = Int8.new(3, 3)
a.triu_indices.to_a  # => [0, 1, 2, 4, 5, 8]

入れ替え

transpose

横と縦を入れ替える

a = Int8.new(3, 3).seq
a.to_a[0]        # => [0, 1, 2]
a.to_a[1]        # => [3, 4, 5]
a.to_a[2]        # => [6, 7, 8]
a = a.transpose  # => Numo::Int8(view)#shape=[3,3]
a.to_a[0]        # => [0, 3, 6]
a.to_a[1]        # => [1, 4, 7]
a.to_a[2]        # => [2, 5, 8]

rot90 とは異なる。元は破壊しない。

swapaxes

並びを入れ替える

a = Int8.new(3, 3).seq
a.to_a[0]  # => [0, 1, 2]
a.to_a[1]  # => [3, 4, 5]
a.to_a[2]  # => [6, 7, 8]
b = a.swapaxes(0, 1)
b.to_a[0]  # => [0, 3, 6]
b.to_a[1]  # => [1, 4, 7]
b.to_a[2]  # => [2, 5, 8]
c = a.transpose
c.to_a[0]  # => [0, 3, 6]
c.to_a[1]  # => [1, 4, 7]
c.to_a[2]  # => [2, 5, 8]

swapaxes(0, 1) だと transpose と同じ結果になる

rot90

90度左回転する

a = Int8.new(3, 3).seq
a.to_a[0]    # => [0, 1, 2]
a.to_a[1]    # => [3, 4, 5]
a.to_a[2]    # => [6, 7, 8]
b = a.rot90  # => Numo::Int8(view)#shape=[3,3]
b.to_a[0]    # => [2, 5, 8]
b.to_a[1]    # => [1, 4, 7]
b.to_a[2]    # => [0, 3, 6]

180度回転する場合は rot90(2) とする

transpose とは走査の順が異なる

c = a.transpose  # => Numo::Int8(view)#shape=[3,3]
c.to_a[0]        # => [0, 3, 6]
c.to_a[1]        # => [1, 4, 7]
c.to_a[2]        # => [2, 5, 8]

結合

.concatenate

合体したのを返す

a = Int8.new(2, 2).seq(0)
b = Int8.new(2, 2).seq(4)
Int8.concatenate([a, b]).to_a  # => [[0, 1], [2, 3], [4, 5], [6, 7]]

.hstack, .vstack, .dstack

結合

a = Int8[1, 2]
b = Int8[3, 4]
c = Int8[5, 6]
Int8.hstack([a, b, c]).to_a  # => [1, 2, 3, 4, 5, 6]
Int8.vstack([a, b, c]).to_a  # => [[1, 2], [3, 4], [5, 6]]
Int8.dstack([a, b, c]).to_a  # => [[[1, 3, 5], [2, 4, 6]]]

内部で .concatenate を呼んでいる

concatenate

合体する

a = Int8.new(2, 2).seq(0)
b = Int8.new(2, 2).seq(4)
a.concatenate(b)       # => Numo::Int8#shape=[4,2]
a.concatenate(b).to_a  # => [[0, 1], [2, 3], [4, 5], [6, 7]]
a.to_a                 # => [[0, 1], [2, 3]]

元を破壊しない

(a + b).to_a  # => [[4, 6], [8, 10]]

クラスメソッドにも似たのがある

Int8.concatenate([a, b]).to_a  # => [[0, 1], [2, 3], [4, 5], [6, 7]]

append

合体する

a = Int8.new(2, 2).seq(0)
b = Int8.new(2, 2).seq(4)
a.append(b)       # => Numo::Int8#shape=[8]
a.append(b).to_a  # => [0, 1, 2, 3, 4, 5, 6, 7]
a.to_a            # => [[0, 1], [2, 3]]

元を破壊しない。フラットになる点が concatenate と違う

バイトオーダー

名前 何 endian ? 備考
vacs little 固定
network big 固定
host little ビルド方法によって変わる
swap_byte すると big ビルド方法によって変わる

byte_swapped?

big endian か?

Int16[1].byte_swapped?   # => false
Int16[1].network_order?  # => false

host_order?

little endian か?

Int16[1].host_order?     # => true
Int16[1].little_endian?  # => true
Int16[1].vacs_order?     # => true

swap_byte, hton

big endian 化する

Int16[1].to_a            # => [1]
Int16[1].swap_byte.to_a  # => [256]
Int16[1].hton.to_a       # => [256]

to_vacs

必ず little endian 化する

Int16[1].to_vacs.to_a  # => [1]

もともと little endian だから変化していない

to_network

必ず big endian 化する

Int16[1].to_network.to_a  # => [256]

to_swapped

big endian 化する

Int16[1].to_swapped.to_a  # => [256]

to_host

little endian 化する

Int16[1].to_host.to_a  # => [1]

シリアライズ

to_binary, to_string

バイナリ表現を返す

a = Int8.new(2, 3).seq
a.to_binary  # => "\x00\x01\x02\x03\x04\x05"
a.to_string  # => "\x00\x01\x02\x03\x04\x05"

store_binary

to_binary から復元する

bin = Int8.new(2, 3).seq.to_binary  # => "\x00\x01\x02\x03\x04\x05"
a = Int8.new(3, 2)
a.store_binary(bin)                 # => 6
a.to_a                              # => [[0, 1], [2, 3], [4, 5]]

from_binary と読み替えると挙動をイメージしやすい。shape は違っていてもいいけど size が足りないとエラーになる。元を破壊する。

.from_binary

バイナリから1次元な NArray を返す

bin = Int8.new(2, 3).seq.to_binary  # => "\x00\x01\x02\x03\x04\x05"
Int8.from_binary(bin).to_a          # => [0, 1, 2, 3, 4, 5]

shape を作ってから取り込む場合は store_binary の方を使う

marshal_dump

Marshal.dump 用

a = Int8[5, 6]
a.marshal_dump  # => [1, [2], 0, "\x05\x06"]

marshal_load

Marshal.load 用

d = Int8[5, 6].marshal_dump    # => [1, [2], 0, "\x05\x06"]
Int8.new.marshal_load(d).to_a  # => [5, 6]

シリアライズと復元の例

a = Int8[5, 6]
bin = Marshal.dump(a)      # => "\x04\bU:\x0FNumo::Int8[\ti\x06[\x06i\ai\x00I\"\a\x05\x06\x06:\x06EF"
Marshal.load(bin).inspect  # => "Numo::Int8#shape=[2]\n[5, 6]"

メタ情報

shape

次元の形を返す

Int8.new(2, 3, 4).shape  # => [2, 3, 4]

new で生成したときの引数に相当する

ndim, rank

次元数

Int8.new(2, 3, 4).ndim  # => 3
Int8.new(2, 3, 4).rank  # => 3

new で生成したときの引数の数に相当する

size, length, total

要素数を返す

Int8.new(2, 3, 4).size    # => 24
Int8.new(2, 3, 4).length  # => 24
Int8.new(2, 3, 4).total   # => 24

new で生成したときの引数の積に相当する

byte_size

総バイト数を返す

a = Int16.new(3)
a.byte_size                          # => 6
a.class::ELEMENT_BYTE_SIZE           # => 2
a.size                               # => 3
a.class::ELEMENT_BYTE_SIZE * a.size  # => 6

内部データの並び

[[0, 1], [2, 3]] のとき

内部 名称
[0, 1, 2, 3] row_major
[0, 2, 1, 3] column_major

row_major?

内部データは行毎か? (フラグで判定)

Int8.new.row_major?  # => true

column_major?

内部データは列毎か? (フラグで判定)

Int8.new.column_major?  # => false

contiguous?

内部データは行毎か? (動的判定)

Int8.new.contiguous?  # => true

fortran_contiguous?

内部データは列毎か? (動的判定)

Int8.new.fortran_contiguous?  # => false

NArrayのその他のクラスメソッド

それぞれの型に継承している

.column_stack

transpose のクラスメソッド版

a = Int8[1, 2]
b = Int8[3, 4]
Int8.column_stack([a, b]).to_a  # => [[1, 3], [2, 4]]
Int8[a, b].transpose.to_a       # => [[1, 3], [2, 4]]

.array_type

要素に合った型のクラスを返す

NArray.array_type(0.0)          # => Numo::DFloat
NArray.array_type(0)            # => Numo::Int32
NArray.array_type(10000000000)  # => Numo::Int64

RObject 型にはならなかった

NArray.array_type("a") rescue $!  # => #<TypeError: invalid type for NArray: String>

.byte_size

要素のバイト数を返す

Int8.byte_size            # => 1
Int8::ELEMENT_BYTE_SIZE   # => 1

Int16.byte_size           # => 2
Int16::ELEMENT_BYTE_SIZE  # => 2

ELEMENT_BYTE_SIZE 定数と同じ値になっている

.diag_indices

対角インデックスを返す

NArray.diag_indices(3, 3).to_a  # => [0, 4, 8]

実体がなくても shape からインデックスは取れる。diagonal で使われていると思われる。

.upcast

両方が収まる型を返す

Int8.upcast(Int16)  # => Numo::Int16
Int16.upcast(Int8)  # => Numo::Int16

NArray から継承するその他のインスタンスメソッド

to_i, to_f, to_c

想定通りの値を返す

DFloat[5.6].to_i  # => 5
Int8[5].to_f      # => 5.0
Int8[5].to_c      # => (5+0i)
Int8[5, 6].to_i rescue $!  # => #<TypeError: can't convert Numo::Int8 into Complex>

[]

参照

a = Int8.new(3, 3).seq
a.to_a[0]  # => [0, 1, 2]
a.to_a[1]  # => [3, 4, 5]
a.to_a[2]  # => [6, 7, 8]

2次元の場合は (行, 列) つまり (y, x) の順になる

a[1, 2]  # => 5

1次元としてもアクセスできる

a[6]  # => 6
a[9] rescue $!  # => #<IndexError: index=9 out of shape[0]=9>

Range

a[1..2].to_a  # => [1, 2]

Array

a[[1, 2]].to_a  # => [1, 2]

フラットになる

a[0..-1].to_a  # => [0, 1, 2, 3, 4, 5, 6, 7, 8]
a[true].to_a   # => [0, 1, 2, 3, 4, 5, 6, 7, 8]

列でアクセスする。true は 0..-1 と同じ。

a[true, 0].to_a  # => [0, 3, 6]
a[true, 1].to_a  # => [1, 4, 7]
a[true, 2].to_a  # => [2, 5, 8]

3次元目を取り除く場合

a[0..1, 0].to_a  # => [0, 3]
a[0..1, 1].to_a  # => [1, 4]
a[0..1, 2].to_a  # => [2, 5]

at

指定位置のビューを取得する

Int8[5, 6, 7, 8].at([1, 2])  # => Numo::Int8(view)#shape=[2]
Int8[5, 6, 7, 8].at(1..2)    # => Numo::Int8(view)#shape=[2]

指定できるのは配列と Range だけだった

Int8[5, 6, 7, 8].at(1) rescue $!     # => #<IndexError: not allowed type>
Int8[5, 6, 7, 8].at(1, 2) rescue $!  # => #<ArgumentError: the number of argument must be same as dimension>

[]=

ビューに対して更新する

a = Int8[5, 6, 7, 8]
a[1..2]  # => Numo::Int8(view)#shape=[2]
a[1..2] = [0, 1]
a.to_a   # => [5, 0, 1, 8]

ビューを更新すると元を更新する

slice

次元数が変わらない以外は [] と同じ

a = Int8.new(3, 3).seq
a.to_a                 # => [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
a.slice(0..1, 0).to_a  # => [[0], [3]]

[] で書いたときは次元が減っている

a[0..1, 0].to_a  # => [0, 3]

==

比較する

DFloat[5.0, 6.0] == Int64[5, 6]  # => true

eq とは違う

DFloat[5.0, 6.0].eq Int64[5, 6]  # => Numo::Bit#shape=[2]

cov

共分散

DFloat[[5, 6, 7], [5, 6, 7]].cov.to_a  # => [[1.0, 1.0], [1.0, 1.0]]

https://ja.wikipedia.org/wiki/共分散

delete

インデックスで値や列や行を削除する

a = Int64[5, 6, 7]
a.delete(1).to_a  # => [5, 7]
a.to_a            # => [5, 6, 7]

列や行を削除する場合

a = Int64.new(3, 3).seq
a.to_a[0]  # => [0, 1, 2]
a.to_a[1]  # => [3, 4, 5]
a.to_a[2]  # => [6, 7, 8]

0行目の削除

a.delete(0, 0).to_a  # => [[3, 4, 5], [6, 7, 8]]

0列目の削除

a.delete(0, 1).to_a  # => [[1, 2], [4, 5], [7, 8]]

diag

?

a = Int8.new(3, 3).seq
a.to_a[0]  # => [0, 1, 2]
a.to_a[1]  # => [3, 4, 5]
a.to_a[2]  # => [6, 7, 8]
a = a.diag.to_a
a[0]       # => [[0, 0, 0], [0, 1, 0], [0, 0, 2]]
a[1]       # => [[3, 0, 0], [0, 4, 0], [0, 0, 5]]
a[2]       # => [[6, 0, 0], [0, 7, 0], [0, 0, 8]]

列毎に分解されてでっかくなった。よくわかってない。

diag_indices

斜めのインデックスを返す

a = Int8.new(3, 3).seq(10)
a.to_a[0]                # => [10, 11, 12]
a.to_a[1]                # => [13, 14, 15]
a.to_a[2]                # => [16, 17, 18]

a.diag_indices(-2).to_a  # => [6]
a.diag_indices(-1).to_a  # => [3, 7]
a.diag_indices(0).to_a   # => [0, 4, 8]
a.diag_indices(1).to_a   # => [1, 5]
a.diag_indices(2).to_a   # => [2]

diagonal

斜めのビューを返す

a = Int8.new(3, 3).seq(10)
a.to_a[0]            # => [10, 11, 12]
a.to_a[1]            # => [13, 14, 15]
a.to_a[2]            # => [16, 17, 18]

a.diagonal(-2).to_a  # => [16]
a.diagonal(-1).to_a  # => [13, 17]
a.diagonal(0).to_a   # => [10, 14, 18]
a.diagonal(1).to_a   # => [11, 15]
a.diagonal(2).to_a   # => [12]

diff

隣りとの差を返す

a = Int8[10, 7, 9]
a.diff.to_a                               # => [-3, 2]
a.to_a.each_cons(2).map { |a, b| b - a }  # => [-3, 2]

empty?

空か?

Int8[].empty?  # => true

値の有無は見てない

Int8.new(3).empty?  # => false

expand_dims

次元を増やす

a = Int8.new(5)
a.shape                 # => [5]
a.expand_dims(0).shape  # => [1, 5]
a.expand_dims(1).shape  # => [5, 1]
a.shape                 # => [5]

元を破壊しない

flatten

平らにする

Int8.new(3, 3).seq.flatten.to_a  # => [0, 1, 2, 3, 4, 5, 6, 7, 8]

代替は [true] でいいはず

Int8.new(3, 3).seq[true].to_a  # => [0, 1, 2, 3, 4, 5, 6, 7, 8]

free

空の状態にする

a = Int8[1]  # => Numo::Int8#shape=[1]
a.free       # => Numo::Int8#shape=[1](empty)
a            # => Numo::Int8#shape=[1](empty)

破壊的。new したときの状態になる。

insert

指定のインデックスに入れる

a = Int64[5, 6]
a.insert(1, 10).to_a  # => [5, 10, 6]
a.to_a                # => [5, 6]

repeat

指定回数繰り返したのを生成する

a = Int8.new(2, 2).seq
a.to_a                     # => [[0, 1], [2, 3]]
a.repeat(2).to_a           # => [0, 0, 1, 1, 2, 2, 3, 3]
a.repeat(2, axis: 0).to_a  # => [[0, 1], [0, 1], [2, 3], [2, 3]]
a.repeat(2, axis: 1).to_a  # => [[0, 0, 1, 1], [2, 2, 3, 3]]

tile

タイルを敷き詰めるように広げる

a = Int8.new(2, 2).seq
a.to_a[0]  # => [0, 1]
a.to_a[1]  # => [2, 3]

縦横2倍する

v = a.tile(2, 2).to_a
v[0]  # => [0, 1, 0, 1]
v[1]  # => [2, 3, 2, 3]
v[2]  # => [0, 1, 0, 1]
v[3]  # => [2, 3, 2, 3]

元は破壊していない

a.size  # => 4

reshape

shape を変形したコピーを返す

a = Int8.new(2, 3).seq
a.to_a                # => [[0, 1, 2], [3, 4, 5]]
a.reshape(3, 2).to_a  # => [[0, 1], [2, 3], [4, 5]]

size が同じのときだけ使える

reshape!

reshape の破壊版

a = Int8.new(2, 3).seq
a.to_a  # => [[0, 1, 2], [3, 4, 5]]
a.reshape!(3, 2)
a.to_a  # => [[0, 1], [2, 3], [4, 5]]

split, vsplit, hsplit, dsplit

分割する

a = Int8.new(7).seq

インデックスで分割する

a.split([2])[0].to_a  # => [0, 1]
a.split([2])[1].to_a  # => [2, 3, 4, 5, 6]

N分割する (半分にできない場合、前の方が多くなる)

a.split(2)[0].to_a  # => [0, 1, 2, 3]
a.split(2)[1].to_a  # => [4, 5, 6]

axis 0 から 2 を初期値にした別メソッドがある

Int8.new(4, 4, 4).seq.vsplit(2)  # => [Numo::Int8(view)#shape=[2,4,4]
Int8.new(4, 4, 4).seq.hsplit(2)  # => [Numo::Int8(view)#shape=[4,2,4]
Int8.new(4, 4, 4).seq.dsplit(2)  # => [Numo::Int8(view)#shape=[4,4,2]

coerce

両者を適切な型にして [other, self] を返す

v = Int8[5].coerce([6])
v[0]  # => Numo::Int8#shape=[1]
v[1]  # => Numo::Int8#shape=[1]

v = Int16[5].coerce(Int8[6])
v[0]  # => Numo::Int16#shape=[1]
v[1]  # => Numo::Int16#shape=[1]

view

単にビューを返す

Int8.new.view  # => Numo::Int8(view)#shape=[](empty)

サブクラスのその他のインスタンスメソッド

NArray を継承している

allocate

?

DFloat.new.allocate       # => Numo::DFloat#shape=[]
DFloat.new.allocate.to_a  # => [0.0]

0 が入ってた。

argmin, argmax

最小値・最大値のインデックスを返す

a = DFloat.new(3, 3).seq(0)
a.to_a[0]  # => [0.0, 1.0, 2.0]
a.to_a[1]  # => [3.0, 4.0, 5.0]
a.to_a[2]  # => [6.0, 7.0, 8.0]
a.argmin   # => 0
a.argmax   # => 8

引数がないときは min_index, max_index と変わらない

a.min_index  # => 0
a.max_index  # => 8

axis があると結果が変わる

a.argmin(axis: 0).to_a     # => [0, 0, 0]
a.min_index(axis: 0).to_a  # => [0, 1, 2]

a.argmax(axis: 0).to_a     # => [2, 2, 2]
a.max_index(axis: 0).to_a  # => [6, 7, 8]

clip

clip というより clamp

a = DFloat.new(5).seq
a.clip(1, 4).to_a  # => [1.0, 1.0, 2.0, 3.0, 4.0]
a.to_a             # => [0.0, 1.0, 2.0, 3.0, 4.0]

coerce_cast

?

DFloat[5].coerce_cast(Int64)  # => nil

ただ nil を返すだけ

copysign

dup して引数の符号を適用する

a = DFloat[-5, 6]
a.copysign([1, -2]).to_a  # => [5.0, -6.0]
a.to_a                    # => [-5.0, 6.0]

元を破壊しない

divmod

割って商と剰余を返す

q, r = DFloat[5, 6].divmod(2)
q.to_a  # => [2.5, 3.0]
r.to_a  # => [1.0, 0.0]

extract

0次元のときだけ抽出する (?)

Int8[].ndim              # => 1
Int8.new(0).ndim         # => 1
Int8.allocate.ndim       # => 0
# Int8.allocate.extract  # => [BUG] Segmentation fault at 0x0000000000000000
Int8[5].inspect          # => "Numo::Int8#shape=[1]\n[5]"
Int8[5].extract.inspect  # => "Numo::Int8#shape=[1]\n[5]"

modf

小数と整数に分離する

a, b = DFloat[5.1, 6.2].modf
a.to_a  # => [0.09999999999999964, 0.20000000000000018]
b.to_a  # => [5.0, 6.0]

poly

多項式の係数を求める

# DFloat[2].poly(3)  # =>

sign

符号だけにする

DFloat[5, -6, 7].sign.to_a  # => [1.0, -1.0, 1.0]

signbit

マイナスを true とした Bit 型にする

DFloat[5, -6, 7].signbit       # => Numo::Bit#shape=[3]
DFloat[5, -6, 7].signbit.to_a  # => [0, 1, 0]

to_a

Array 化

DFloat[5, 6, 7].to_a  # => [5.0, 6.0, 7.0]

isnan, isinf, isfinite

DFloat[0.0 / 0].isnan.to_a      # => [1]
DFloat[5.0 / 0].isinf.to_a      # => [1]
DFloat[-5.0 / 0].isneginf.to_a  # => [1]
DFloat[+5.0 / 0].isposinf.to_a  # => [1]
DFloat[5].isfinite.to_a         # => [1]

nan? infinite? finite? に相当する

eq, ne, ge, gt, le, lt

DFloat[5, 6].eq DFloat[5, 7]   # => Numo::Bit#shape=[2]
DFloat[5, 6].ne DFloat[5, 7]   # => Numo::Bit#shape=[2]
DFloat[5, 6] >= DFloat[5, 7]   # => Numo::Bit#shape=[2]
DFloat[5, 6] >  DFloat[5, 7]   # => Numo::Bit#shape=[2]
DFloat[5, 6] <= DFloat[5, 7]   # => Numo::Bit#shape=[2]
DFloat[5, 6] <  DFloat[5, 7]   # => Numo::Bit#shape=[2]
DFloat[5, 6].ge(DFloat[5, 7])  # => Numo::Bit#shape=[2]
DFloat[5, 6].gt(DFloat[5, 7])  # => Numo::Bit#shape=[2]
DFloat[5, 6].le(DFloat[5, 7])  # => Numo::Bit#shape=[2]
DFloat[5, 6].lt(DFloat[5, 7])  # => Numo::Bit#shape=[2]

eq ne== != は異なる

DFloat[5, 6] == DFloat[5, 7]  # => false
DFloat[5, 6] != DFloat[5, 7]  # => true

Bit 型

演算すると勝手にできる

a = Int8.new(5).seq(5)
a.to_a          # => [5, 6, 7, 8, 9]
(a >= 8)        # => Numo::Bit#shape=[5]
(a >= 8).to_a   # => [0, 0, 0, 1, 1]
a[a >= 8].to_a  # => [8, 9]

&| でマージできる

c = (a >= 8) | (a.eq 5)  # => Numo::Bit#shape=[5]
c                        # => Numo::Bit#shape=[5]
c.to_a                   # => [1, 0, 0, 1, 1]
a[c].to_a                # => [5, 8, 9]

true false は 1 0 で書いても同じ内部表現になるっぽい

Bit[true, false].to_a  # => [1, 0]
Bit[1, 0].to_a         # => [1, 0]

all? any? none?

Bit[true, false, true].all?   # => false
Bit[true, false, true].any?   # => true
Bit[true, false, true].none?  # => false

copy

おそらく deep copy と思われる

a = Bit.new(3, 3).fill(true)
b = a.copy

別のオブジェクトになっている

a.object_id  # => 500
b.object_id  # => 520

コピー元を更新する

a[1, 1] = 0
a.to_a[0]  # => [1, 1, 1]
a.to_a[1]  # => [1, 0, 1]
a.to_a[2]  # => [1, 1, 1]

コピー先は変化しない

b.to_a[0]  # => [1, 1, 1]
b.to_a[1]  # => [1, 1, 1]
b.to_a[2]  # => [1, 1, 1]

copy を dup に変更しても結果は変わらなかった

count_true, count_1

true の個数を返す

Bit[true, false, true].count_true  # => 2
Bit[true, false, true].count_1     # => 2

count_false, count_0

false の個数を返す

Bit[true, false, true].count_false  # => 1
Bit[true, false, true].count_0      # => 1

| &

論理和と論理積

a = Bit[1, 0, 1, 0]
b = Bit[1, 1, 0, 0]
(a & b).to_a  # => [1, 0, 0, 0]
(a | b).to_a  # => [1, 1, 1, 0]

mask

相手の該当要素を抽出する

a = Bit[1, 0, 1, 0]
a.mask([5, 6, 7, 8]).to_a  # => [5, 7]

これと同じ

NArray[5, 6, 7, 8][a].to_a  # => [5, 7]

where

真になる位置のインデックスを返す

a = Int8[5, 6, 7, 8]
a.to_a              # => [5, 6, 7, 8]
(a > 6).where.to_a  # => [2, 3]

where が返すのは該当した値ではない。該当した値がある位置のインデックスになっている。where をかまさないときは有効な位置が true になる行列がとれる。

(a > 6).to_a  # => [0, 0, 1, 1]

対象の値たちがほしい場合、再度 a を参照しないといけない

a[a > 6].to_a  # => [7, 8]

次のように書いても結果は同じなので、おそらく a[x] は x.where を呼んでいると思われる

a[(a > 6).where].to_a  # => [7, 8]

where2

真偽両方のインデックスを返す

a = Int8[5, 6, 7, 8]
a.to_a  # => [5, 6, 7, 8]

前側は条件にマッチした方のインデックスでこれがほしいだけなら where でいい

(a > 6).where2[0].to_a  # => [2, 3]

後側は条件にマッチしなかった方のインデックスになっている

(a > 6).where2[1].to_a  # => [0, 1]

整数専用

<<, >>

(Int8[1, 2, 3] << 1).to_a  # => [2, 4, 6]
(Int8[2, 4, 6] >> 1).to_a  # => [1, 2, 3]
DFloat[1] << 1 rescue $!  # => #<NoMethodError:"undefined method `<<' for Numo::DFloat#shape=[1]\n[1]:Numo::DFloat">

定数

NArray::VERSION  # => "0.9.2.1"

Bit

Bit::UPCAST             # => {Array=>Numo::Bit, Integer=>Numo::Bit, Float=>Numo::DFloat, Complex=>Numo::DComplex, false=>false, Numo::DComplex=>Numo::DComplex, Numo::SComplex=>Numo::SComplex, Numo::DFloat=>Numo::DFloat, Numo::SFloat=>Numo::SFloat, Numo::Int64=>Numo::Int64, Numo::Int32=>Numo::Int32, Numo::Int16=>Numo::Int16, Numo::Int8=>Numo::Int8, Numo::UInt64=>Numo::UInt64, Numo::UInt32=>Numo::UInt32, Numo::UInt16=>Numo::UInt16, Numo::UInt8=>Numo::UInt8}
Bit::ELEMENT_BIT_SIZE   # => 1
Bit::ELEMENT_BYTE_SIZE  # => 0.125
Bit::CONTIGUOUS_STRIDE  # => 1

Int8

Int8::UPCAST             # => {Array=>Numo::Int8, Integer=>Numo::Int8, Float=>Numo::DFloat, Complex=>Numo::DComplex, false=>Numo::Int16, Numo::DComplex=>Numo::DComplex, Numo::SComplex=>Numo::SComplex, Numo::DFloat=>Numo::DFloat, Numo::SFloat=>Numo::SFloat, Numo::Int64=>Numo::Int64, Numo::Int32=>Numo::Int32, Numo::Int16=>Numo::Int16, Numo::Int8=>Numo::Int8, Numo::UInt64=>Numo::Int64, Numo::UInt32=>Numo::Int64, Numo::UInt16=>Numo::Int32}
Int8::ELEMENT_BIT_SIZE   # => 8
Int8::ELEMENT_BYTE_SIZE  # => 1
Int8::CONTIGUOUS_STRIDE  # => 1
Int8::MAX                # => 127
Int8::MIN                # => -128

DFloat

DFloat::UPCAST             # => {Array=>Numo::DFloat, Integer=>Numo::DFloat, Float=>Numo::DFloat, Complex=>Numo::DComplex, false=>Numo::DFloat, Numo::DComplex=>Numo::DComplex, Numo::DFloat=>Numo::DFloat}
DFloat::ELEMENT_BIT_SIZE   # => 64
DFloat::ELEMENT_BYTE_SIZE  # => 8
DFloat::CONTIGUOUS_STRIDE  # => 8
DFloat::EPSILON            # => 2.220446049250313e-16
DFloat::MAX                # => 1.7976931348623157e+308
DFloat::MIN                # => 2.2250738585072014e-308

RObject 型

.[]

どんな型でも入る

a = RObject["a", 1, {}]        # => Numo::RObject#shape=[3]
a.to_a                         # => ["a", 1, {}]
a = a.map(&:size).map(&:to_s)  # => Numo::RObject#shape=[3]
a.to_a                         # => ["1", "8", "0"]
a[a.ne("0")].to_a              # => ["1", "8"]

空配列を入れると空配列が消えてしまう

RObject[[]].to_a  # => []

どこから nil が来た?

RObject[[], 1].to_a  # => [nil]

Struct 型

Struct        # => Struct
Numo::Struct  # => Numo::Struct

定義

color = Numo::Struct.new do
  uint8 "foo"
end

color                # => #<Class:0x0000000105907120>
color.new rescue $!  # => #<TypeError: allocator undefined for #<Class:0x0000000105907120>>
color[] rescue $!    # => #<TypeError: allocator undefined for #<Class:0x0000000105907120>>

つまづいた点

継承したクラスから .[] で生成すると親クラスで生成される

class Vec2 < Int64
  def x; self[0]; end
  def y; self[1]; end
end
Vec2[1, 2].x rescue $!  # => #<NoMethodError:"undefined method `x' for Numo::Int64#shape=[2]\n[1, 2]:Numo::Int64">
Vec2[].class            # => Numo::Int64

参照

Discussion