行列の積と性質——AB≠BA の世界
行列の積
「行列の掛け算は普通の数と違う——『行と列のペアリング』で計算する」。普通の掛け算なら はただの 12 ですが、行列では「左の行ベクトルと右の列ベクトルの内積をとる」という独特の計算方法を使います。
が 行列、 が 行列のとき、積 は 行列で:
つまり「 の第 行」と「 の第 列」の内積が です——「行の数字を横に、列の数字を縦に並べて、対応するものを掛けて全部足す」。
重要な条件: の列数 の行数——「左の行列の幅と、右の行列の高さが一致しないと計算できない」
2×2 行列の積の例
「実際に手を動かして計算してみましょう」——各成分を「左の行と右の列を掛け合わせて足す」手順で求めます:
積の可視化アニメーション
マウスを動かして、どの行と列が組み合わさって積が計算されているかを確認してください。
var t, highlightRow, highlightCol, cw, ch, ox1, ox2, ox3, oy;
var A = [[1,2],[3,4]];
var B = [[5,6],[7,8]];
var C = [[0,0],[0,0]];
for (var ii = 0; ii < 2; ii++)
for (var jj = 0; jj < 2; jj++) {
C[ii][jj] = 0;
for (var kk = 0; kk < 2; kk++) C[ii][jj] += A[ii][kk] * B[kk][jj];
}
t = 0;
function drawMat(mat, ox, oy, rowHL, colHL, hlColor, label) {
var n = mat.length, m = mat[0].length;
var cellW = 52, cellH = 52;
ctx.fillStyle = '#64748b';
ctx.font = '13px monospace';
ctx.textAlign = 'center';
ctx.fillText(label, ox + m*cellW/2, oy - 10);
// brackets
ctx.strokeStyle = '#60a5fa';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(ox+5, oy); ctx.lineTo(ox, oy); ctx.lineTo(ox, oy+n*cellH); ctx.lineTo(ox+5, oy+n*cellH);
ctx.moveTo(ox+m*cellW-5, oy); ctx.lineTo(ox+m*cellW, oy); ctx.lineTo(ox+m*cellW, oy+n*cellH); ctx.lineTo(ox+m*cellW-5, oy+n*cellH);
ctx.stroke();
for (var i = 0; i < n; i++) {
for (var j = 0; j < m; j++) {
var cx = ox + j*cellW + cellW/2;
var cy = oy + i*cellH + cellH/2;
var isHL = (rowHL !== undefined && i === rowHL) || (colHL !== undefined && j === colHL);
if (isHL) {
ctx.fillStyle = hlColor + '44';
ctx.fillRect(ox+j*cellW+2, oy+i*cellH+2, cellW-4, cellH-4);
ctx.fillStyle = hlColor;
} else {
ctx.fillStyle = '#cbd5e1';
}
ctx.font = 'bold 17px monospace';
ctx.textAlign = 'center';
ctx.fillText(mat[i][j], cx, cy + 6);
}
}
}
function loop() {
ctx.clearRect(0, 0, W, H);
t++;
var period = 180;
var idx = Math.floor(t / period) % 4;
var hi = Math.floor(idx / 2);
var hj = idx % 2;
// animate
if (t % period === 0) { /* cycle */ }
ox1 = 20; ox2 = 170; ox3 = 370;
oy = 80;
drawMat(A, ox1, oy, hi, undefined, '#f87171', 'A');
drawMat(B, ox2, oy, undefined, hj, '#60a5fa', 'B');
drawMat(C, ox3, oy, hi, hj, '#22c55e', 'C = AB');
// × and = symbols
ctx.fillStyle = '#94a3b8';
ctx.font = 'bold 28px monospace';
ctx.textAlign = 'center';
ctx.fillText('×', 158, oy + 60);
ctx.fillText('=', 345, oy + 60);
// show current computation
var aRow = A[hi];
var bCol = [B[0][hj], B[1][hj]];
ctx.fillStyle = '#e2e8f0';
ctx.font = '13px monospace';
ctx.textAlign = 'left';
ctx.fillText('C[' + (hi+1) + '][' + (hj+1) + '] = ' +
aRow[0] + '×' + bCol[0] + ' + ' + aRow[1] + '×' + bCol[1] + ' = ' + C[hi][hj],
20, 240);
ctx.fillStyle = '#fbbf24';
ctx.fillText('行 ' + (hi+1) + '(赤)× 列 ' + (hj+1) + '(青)→ 緑', 20, 262);
// non-commutativity
var BA = [[0,0],[0,0]];
for (var i2 = 0; i2 < 2; i2++)
for (var j2 = 0; j2 < 2; j2++)
for (var k2 = 0; k2 < 2; k2++) BA[i2][j2] += B[i2][k2]*A[k2][j2];
ctx.fillStyle = '#94a3b8';
ctx.font = '12px monospace';
ctx.fillText('AB = [[' + C[0] + '],[' + C[1] + ']]', 20, 292);
ctx.fillText('BA = [[' + BA[0] + '],[' + BA[1] + ']]', 20, 310);
ctx.fillStyle = '#f87171';
ctx.fillText('AB ≠ BA ← 非可換!', 20, 328);
requestAnimationFrame(loop);
}
loop(); AB ≠ BA(非可換性)
「行列の掛け算では順序が大事——入れ替えると答えが変わる!」。スカラー(普通の数)の掛け算では (可換)ですが、行列では一般に:
これが行列の最も重要な特徴の一つです——「靴下を履いてから靴を履く」と「靴を履いてから靴下を履く」が違うのと同じです。
例:
が確認できます——「先に を掛けるか を掛けるかで結果が変わる」。
行列の積の性質
「結合法則と分配法則は成り立つ——ただし交換法則だけは要注意」:
| 性質 | 式 |
|---|---|
| 結合法則 | ✓ |
| 左分配法則 | ✓ |
| 右分配法則 | ✓ |
| スカラーとの可換 | ✓ |
| 交換法則 | 一般に× |
| 単位行列 | ✓ |
| 零行列 | ✓ |
行列の積の幾何学的意味
「行列の積 は『変換を連続して施す』こと」—— 行列は 次元ベクトルに作用する線形変換です。
- 積 は「変換 を施してから、変換 を施す」合成変換
- 順序が逆になるので は自然——「回転してから拡大」と「拡大してから回転」は一般に異なる
| 行列 | 変換の意味 |
|---|---|
| 角度 回転 | |
| 倍拡大 | |
| 軸反転 |
計算量
「 が大きくなると計算が急激に増える」—— 行列の積の朴素な計算量は ( の成分それぞれに 回の乗算)。
シュトラッセンのアルゴリズム(1969年)は 。現在の最良は約 ですが、実用的でないため通常は が使われます——「理論上は速くできるが、現実には単純な方法が使われる」。
まとめ
- 行列の積 は「 の 行と の 列の内積」——「横と縦を掛けて足す」
- 型の条件: の列数 の行数——「サイズが合わないと計算できない」
- 非可換: が一般に成立(行列算術の最重要ポイント)——「順序を変えると答えが変わる」
- 結合法則・分配法則は成立する
- 幾何学的には行列の積 線形変換の合成——「2つの変換を続けて施すこと」
次回は逆行列——行列で「割り算」に相当する操作と、連立方程式への応用を学びます。