JavaScriptで実装する行列乗算アルゴリズムの完全ガイド
はじめに
本記事では、2つの2次元数値配列(行列)を受け取り、その行列乗算の結果を返すJavaScript関数を実装していきます。
行列乗算の基本ルール
行列AがX行Z列、行列BがZ行Y列である場合、乗算結果はX行Y列の行列になります。したがって、最初の行列の列数と2番目の行列の行数は必ず一致している必要があり、一致しない場合は計算できません。
実装コード
以下が実際のコードです。
const multiplyMatrices = (a, b) => {
if (!Array.isArray(a) || !Array.isArray(b) || !a.length || !b.length) {
throw new Error('引数は2次元配列形式である必要があります');
}
let x = a.length,
z = a[0].length,
y = b[0].length;
if (b.length !== z) {
// XxZ & ZxY => XxY
throw new Error('1つ目の行列の列数は、
2つ目の行列の行数と同じである必要があります');
}
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));出力結果
コンソールには次のように表示されます。
[
[ 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 ]
]
コードの解説
この関数の処理の流れは以下の通りです。
1. 入力値の検証:まず、両方の引数が空でない配列かどうかをチェックし、不正な場合はエラーを投げます。
2. 行列サイズの整合性チェック:1つ目の行列の列数(z)と2つ目の行列の行数が一致していることを確認します。これにより、「XxZ × ZxY = XxY」という行列乗算のルールが満たされます。
3. 結果行列の初期化:すべての要素を0で埋めたX行Y列の2次元配列を作成し、結果の格納先として準備します。
4. 三重ループによる計算:i・j・kの3つのインデックスを使ったネストされたループの中で、「product[i][j] += a[i][k] * b[k][j]」という式により内積を累積していくのが核心部分です。
なお、この素朴な実装の計算量はO(X×Y×Z)であり、大規模な行列を扱う場合はStrassen法などの高速化アルゴリズムや、専用の数値計算ライブラリの利用も検討するとよいでしょう。
-
JavaScriptのconstとletの違いを徹底解説!ブロックスコープ変数の基本と使い方
JavaScriptにおけるconstとletの基本const と let は、ES2015(ES6)で導入された変数宣言用のキーワードです。どちらもブロックスコープ(波括弧 { } で囲まれた範囲)に対応しているのが特徴で、関数スコープしか持たなかった従来の var とは異なる挙動を示します。両者の大きな違いは再代入の可否です。letで宣言した変数は後から何度でも値を再代入できますが、constで宣言した変数は再代入しようとするとエラー(TypeError)が発生します。letとconstの主な違い項目letconst再代入可能不可(エラー発生)スコープブロックスコープブロックスコープ宣言時
-
JavaScriptの「for...in」ステートメントとは?オブジェクトのプロパティをループ処理する方法を解説
JavaScriptのfor...in文は、オブジェクトが持つすべてのプロパティ(列挙可能なプロパティ)を順番に取り出して処理するためのループ構文です。オブジェクト内の各キー(プロパティ名)にアクセスしながら、対応する値を取得したい場合に非常に便利です。for...inの基本的な構文for (let 変数名 in オブジェクト) { // 各プロパティに対して実行したい処理 }ループ変数には、各反復ごとにオブジェクトのプロパティ名(キー)が文字列として代入されます。値そのものを取得するには、「オブジェクト[変数名]」のようにブラケット記法を使ってアクセスします。サンプルコード以下は、for