【JavaScript】異なる次元の2つの行列を乗算する方法
本記事では、数値の2次元配列(行列)を2つ受け取り、その行列の積を計算して返すJavaScript関数を実装します。行列の掛け算は、機械学習やグラフィックス処理などでも頻繁に使われる基本的な演算です。
行列の乗算のルール
まず押さえておきたいのが、行列の積が成立する条件です。「1つ目の行列の列数」と「2つ目の行列の行数」が一致している必要があります。たとえば X×Z の行列と Z×Y の行列を掛けると、結果は X×Y の行列になります。
今回扱うのは、5行4列の行列 a と、4行6列の行列 b です。4列と4行が一致しているため、掛け算が可能で、結果は5行6列の行列になります。
// 5 x 4 の行列 let a = [ [1, 2, 3, 1], [4, 5, 6, 1], [7, 8, 9, 1], [1, 1, 1, 1], [5, 7, 2, 6] ]; // 4 x 6 の行列 let b = [ [1, 4, 7, 3, 4, 6], [2, 5, 8, 7, 3, 2], [3, 6, 9, 6, 7, 8], [1, 1, 1, 2, 3, 6] ];
実装コード
それでは、実際に関数を書いてみましょう。引数の形式チェックと次元の整合性チェックを行ったうえで、三重のループによって内積を計算します。
const multiplyMatrices = (a, b) => {
// 引数が2次元配列であることを確認
if (!Array.isArray(a) || !Array.isArray(b) || !a.length || !b.length) {
throw new Error('arguments should be in 2-dimensional array format');
}
let x = a.length, // 行列aの行数
z = a[0].length, // 行列aの列数
y = b[0].length; // 行列bの列数
// aの列数とbの行数が一致しない場合はエラー
if (b.length !== z) {
// XxZ & ZxY => XxY
throw new Error('number of columns in the first matrix should be the same as the number of rows in the second');
}
// 結果格納用の x×y のゼロ行列を作成
let productRow = Array.apply(null, new Array(y)).map(Number.prototype.valueOf, 0);
let product = new Array(x);
for (let p = 0; p < x; p++) {
product[p] = productRow.slice();
}
// 三重ループで各要素の内積を計算
for (let i = 0; i < x; i++) {
for (let j = 0; j < y; j++) {
for (let k = 0; k < z; k++) {
product[i][j] += a[i][k] * b[k][j];
}
}
}
return product;
}
// 5 x 4 の行列
let a = [
[1, 2, 3, 1],
[4, 5, 6, 1],
[7, 8, 9, 1],
[1, 1, 1, 1],
[5, 7, 2, 6]
];
// 4 x 6 の行列
let b = [
[1, 4, 7, 3, 4, 6],
[2, 5, 8, 7, 3, 2],
[3, 6, 9, 6, 7, 8],
[1, 1, 1, 2, 3, 6]
];
// 結果は 5 x 6 の行列になる
console.log(multiplyMatrices(a, b));コードのポイント
- 入力チェック: 引数が配列かどうか、さらに空でないかどうかを検証し、不正な入力にはエラーをスローします。
- 次元チェック: 行列aの列数(
z)と行列bの行数(b.length)が一致しない場合、乗算は定義されないためエラーを投げます。 - 結果の初期化: 計算結果を格納するためのゼロで埋められた配列を事前に用意し、
slice()で複製することで各行が独立した配列になるようにしています。 - 計算方法: 結果の要素
product[i][j]は、「行列aのi行目」と「行列bのj列目」の対応する要素同士を掛けて合計した値(内積)です。
実行結果
コンソールへの出力は以下のとおりです。期待どおり、5行6列の行列が得られます。
[ [ 15, 33, 51, 37, 34, 40 ], [ 33, 78, 123, 85, 76, 88 ], [ 51, 123, 195, 133, 118, 136 ], [ 7, 16, 25, 18, 17, 22 ], [ 31, 73, 115, 88, 73, 96 ] ]
まとめ
このように、JavaScriptではシンプルな三重ループを使うだけで、異なる次元を持つ行列同士の乗算を簡単に実装できます。計算量は O(X×Y×Z) となるため、大規模な行列を扱う場合はパフォーマンスに注意が必要ですが、小〜中規模のデータであれば十分に実用的です。必要に応じて、エラーメッセージを日本語にしたり、型チェックを強化したりしてカスタマイズしてみてください。
-
JavaScriptで2つの配列を結合する方法【concat()とスプレッド構文】
JavaScriptで2つの配列を1つにまとめたい場合、最も一般的なのが concat() メソッドです。このメソッドは、元の配列を変更することなく、複数の配列や値を連結した新しい配列を返します。 concat()メソッドの基本構文 let 新しい配列 = 配列A.concat(配列B); サンプルコード 以下は、ボタンをクリックすると2つの配列を結合し、その結果を画面に表示する完全なサンプルです。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8&
-
JavaScriptで2つの配列を乗算する方法|forループとmap()の実装例
JavaScriptで2つの配列の各要素同士を乗算し、その結果を新しい配列として取得する方法を解説します。基本的にはforループでインデックスを順番に処理しながら、対応する位置にある要素同士を掛け合わせていくシンプルなアプローチです。 2つの配列を乗算するサンプルコード 以下の例では、「CLICK HERE」ボタンをクリックすると、配列 arr と arr1 の対応する要素が乗算され、結果が新しい配列 multArray に格納された上で画面に表示されます。 <!DOCTYPE html> <html lang=en> <head> <meta ch