多次元配列#
Rustでの多次元配列の扱いを学ぶ
参考#
// 配列処理
:dep ndarray = { version = "0.15.6" }
use ndarray::{Array, array};
配列の生成#
Array::from_vec(vec![
vec![1, 2, 3],
vec![4, 5, 6],
])
[[1, 2, 3], [4, 5, 6]], shape=[2], strides=[1], layout=CFcf (0xf), const ndim=1
// 不揃いでも良いっぽい?
Array::from_vec(vec![
vec![1, 2, 3],
vec![4, 5]
])
[[1, 2, 3], [4, 5]], shape=[2], strides=[1], layout=CFcf (0xf), const ndim=1
// array! マクロでも可
array![
[3, 1, 4],
[1, 5, 9],
[2, 6, 5],
]
[[3, 1, 4],
[1, 5, 9],
[2, 6, 5]], shape=[3, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2
Array::from_shape_vec
で1次元配列をshape
形式に変形して生成できる.(結果はResult
型)
Array::from_shape_vec((1,), vec![1])
Ok([1], shape=[1], strides=[1], layout=CFcf (0xf), const ndim=1)
Array::from_shape_vec((2, 3), vec![1, 2, 3, 4, 5, 6])?
[[1, 2, 3],
[4, 5, 6]], shape=[2, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2
関数からも生成できるらしい
Array::from_shape_fn((4, 5), |(i, j)| 4 * i + j)
[[0, 1, 2, 3, 4],
[4, 5, 6, 7, 8],
[8, 9, 10, 11, 12],
[12, 13, 14, 15, 16]], shape=[4, 5], strides=[5, 1], layout=Cc (0x5), const ndim=2
スライス#
use ndarray::s;
let A = array![
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
&A
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], shape=[3, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2
// インデックス
A.slice(s![1, 1])
5, shape=[], strides=[], layout=CFcf (0xf), const ndim=0
// 複数指定
A.slice(s![.., 1..])
[[2, 3],
[5, 6],
[8, 9]], shape=[3, 2], strides=[3, 1], layout=c (0x4), const ndim=2
// ステップ
A.slice(s![..;-1, ..])
[[7, 8, 9],
[4, 5, 6],
[1, 2, 3]], shape=[3, 3], strides=[-3, 1], layout=c (0x4), const ndim=2
演算#
let W = array![[1, 2, 3], [4, 5, 6]];
let X = array![[0, 1, 2], [3, 4, 5]];
// 要素ごとの和
&W + &X
[[1, 3, 5],
[7, 9, 11]], shape=[2, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2
// 要素ごとの差
&W - &X
[[1, 1, 1],
[1, 1, 1]], shape=[2, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2
// 要素ごとの積
&W * &X
[[0, 2, 6],
[12, 20, 30]], shape=[2, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2
// 転置
W.t()
[[1, 4],
[2, 5],
[3, 6]], shape=[3, 2], strides=[1, 3], layout=Ff (0xa), const ndim=2
// ドット積
W.t().dot(&X)
[[12, 17, 22],
[15, 22, 29],
[18, 27, 36]], shape=[3, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2
// 形状が一致しない場合
W.dot(&X)
thread '<unnamed>' panicked at /home/powell/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ndarray-0.15.6/src/linalg/impl_linalg.rs:299:5:
ndarray: inputs 2 × 3 and 2 × 3 are not compatible for matrix multiplication
stack backtrace:
0: rust_begin_unwind
at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:647:5
1: core::panicking::panic_fmt
at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/panicking.rs:72:14
2: ndarray::linalg::impl_linalg::dot_shape_error
3: ndarray::linalg::impl_linalg::<impl ndarray::ArrayBase<S,ndarray::dimension::dim::Dim<[usize; 2]>>>::dot
4: std::panicking::try
5: run_user_code_15
6: evcxr::runtime::Runtime::run_loop
7: evcxr::runtime::runtime_hook
8: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
線形代数#
:dep ndarray-linalg = { version = "0.16.0", features = ["openblas"] }
use ndarray_linalg::{Determinant, Inverse};
行列式#
let A = array![[3.0, 4.0], [5.0, 6.0]];
A.det()
Ok(-2.0)
逆行列#
A.inv()
Ok([[-3.0, 2.0],
[2.5, -1.5]], shape=[2, 2], strides=[2, 1], layout=Cc (0x5), const ndim=2)