JS實現矩陣相乘、行列式、逆矩陣

一、矩陣運算

1.1 矩陣相乘

  • Am×p{\rm A_{m \times p}}Bp×n{\rm B_{p \times n}}
  • Cm×n=Am×p×Bp×n{\rm C_{m \times n}} = {\rm A_{m \times p}} \times {\rm B_{p \times n}}
  • Cij=k=1paikbkj{\rm C_{ij}} = \sum_{ \rm k=1}^{\rm p} a_{\rm ik} \cdot b_{\rm kj}
function multiply(a, b) {
    // 相乘約束
    if (a[0].length !== b.length) {
        throw new Error();
    }
    let m = a.length;
    let p = a[0].length;
    let n = b[0].length;

    // 初始化 m*n 全 0 二維數組
    let c = new Array(m).fill(0).map(arr => new Array(n).fill(0));

    for (let i = 0; i < m; i++) {
        for (let j = 0; j < n; j++) {
            for (let k = 0; k < p; k++) {
                c[i][j] += a[i][k] * b[k][j];
            }
        }
    }

    return c;
}

1.2 行列式

  • 1 階:a11=a11\begin{vmatrix} a_{11} \end{vmatrix} = a_{11}

  • 2 階:a11a12a21a22=a11a22a12a21\begin{vmatrix}a_{11} & a_{12} \\a_{21} & a_{22}\end{vmatrix} = a_{11} \cdot a_{22} - a_{12} \cdot a_{21}

  • 3 階:a11a12a13a21a22a23a31a32a33=a11a22a33+a12a23a31+a13a21a32a13a22a31a12a21a33a11a23a32\begin{vmatrix}a_{11} & a_{12} & a_{13} \\a_{21} & a_{22} & a_{23} \\a_{31} & a_{32} & a_{33}\end{vmatrix} = a_{11} a_{22} a_{33} +a_{12} a_{23} a_{31} +a_{13} a_{21} a_{32} -a_{13} a_{22} a_{31} -a_{12} a_{21} a_{33} - a_{11} a_{23} a_{32}

  • n 階:任意某行(或某列)的各元素與其對應的代數餘子式乘積之和

  • 3 階行列式:對應行平移後公式也可認爲『主對角線元素積與副對角線元素積之差

  • 代數餘子式:『(1)i+j(-1)^{\rm i+j} 』乘以『去掉方陣第 i 行第 j 列的元素後構成的方陣的行列式』的值

n 階行列式可取第 1 行的各元素與其對應的代數餘子式乘積之和,如:
a11a12a13a14a21a22a23a24a31a32a33a34a41a42a43a44=a11(1)1+1a22a23a24a32a33a34a42a43a44+a12(1)1+2a21a23a24a31a33a34a41a43a44+a13(1)1+3a21a22a24a31a32a34a41a42a44+a14(1)1+4a21a22a23a31a32a33a41a42a43 \begin{vmatrix}a_{11} & a_{12} & a_{13} & a_{14} \\a_{21} & a_{22} & a_{23} & a_{24} \\a_{31} & a_{32} & a_{33} & a_{34} \\a_{41} & a_{42} & a_{43} & a_{44}\end{vmatrix}= a_{11} \cdot (-1)^{1+1} \cdot \begin{vmatrix}a_{22} & a_{23} & a_{24}\\ a_{32} &a_{33}& a_{34} \\a_{42} & a_{43} & a_{44} \end{vmatrix} + a_{12} \cdot (-1)^{1+2} \cdot \begin{vmatrix}a_{21} & a_{23} & a_{24}\\ a_{31} & a_{33}& a_{34} \\a_{41} & a_{43} & a_{44} \end{vmatrix} +a_{13} \cdot (-1)^{1+3} \cdot \begin{vmatrix}a_{21} & a_{22} & a_{24}\\ a_{31} & a_{32}& a_{34} \\a_{41} & a_{42} & a_{44}\end{vmatrix} +a_{14} \cdot (-1)^{1+4} \cdot \begin{vmatrix}a_{21} & a_{22} & a_{23}\\ a_{31} & a_{32}& a_{33} \\a_{41} & a_{42} & a_{43} \end{vmatrix} \\

function det(square) {
    // 方陣約束
    if (square.length !== square[0].length) {
        throw new Error();
    }
    // 方陣階數
    let n = square.length;

    let result = 0;
    if (n > 3) {
        // n 階
        for (let column = 0; column < n; column++) {
            // 去掉第 0 行第 column 列的矩陣
            let matrix = new Array(n - 1).fill(0).map(arr => new Array(n - 1).fill(0));
            for (let i = 0; i < n - 1; i++) {
                for (let j = 0; j < n - 1; j++) {
                    if (j < column) {
                        matrix[i][j] = square[i + 1][j];
                    } else {
                        matrix[i][j] = square[i + 1][j + 1];
                    }
                }
            }
            result += square[0][column] * Math.pow(-1, 0 + column) * det(matrix);
        }
    } else if (n === 3) {
        // 3 階
        result = square[0][0] * square[1][1] * square[2][2] +
                 square[0][1] * square[1][2] * square[2][0] +
                 square[0][2] * square[1][0] * square[2][1] -
                 square[0][2] * square[1][1] * square[2][0] -
                 square[0][1] * square[1][0] * square[2][2] -
                 square[0][0] * square[1][2] * square[2][1];
    } else if (n === 2) {
        // 2 階
        result = square[0][0] * square[1][1] - square[0][1] * square[1][0];
    } else if (n === 1) {
        // 1 階
        result = square[0][0];
    }
    return result;
}

1.2 轉置矩陣

function transpose(matrix) {
    let result = new Array(matrix.length).fill(0).map(arr => new Array(matrix[0].length).fill(0));
    for (let i = 0; i < result.length; i++) {
        for (let j = 0; j < result[0].length; j++) {
            result[i][j] = matrix[j][i];
        }
    }
    return result;
}

1.3 伴隨矩陣

  • 伴隨矩陣:矩陣中每個元素對應的代數餘子式所構成矩陣的轉置矩陣
function adjoint(square) {
    // 方陣約束
    if (square[0].length !== square.length) {
        throw new Error();
    }

    let n = square.length;

    let result = new Array(n).fill(0).map(arr => new Array(n).fill(0));
    for (let row = 0; row < n; row++) {
        for (let column = 0; column < n; column++) {
            // 去掉第 row 行第 column 列的矩陣
            let matrix = [];
            for (let i = 0; i < square.length; i++) {
                if (i !== row) {
                    let arr = [];
                    for (let j = 0; j < square.length; j++) {
                        if (j !== column) {
                            arr.push(square[i][j]);
                        }
                    }
                    matrix.push(arr);
                }
            }
            result[row][column] = Math.pow(-1, row + column) * det(matrix);
        }
    }
    return transpose(result);
}

PS

det()函數裏求『去掉第 0 行第 column 列矩陣』的複製方法相比較,求『去掉第 row 行第 column 列矩陣』裏採用尾插法相對更加簡潔可讀一些。不過還是太 low …


1.4 逆矩陣

  • [AE][EA1]\rm [A \quad E] \stackrel{初等變換}{\longrightarrow} [E \quad A^{-1}]

  • A1=1AAA^{-1} = \frac{1}{|\rm A|} \cdot \rm A^{*}

function inv(square) {
    if (square[0].length !== square.length) {
        throw new Error();
    }
    let detValue = det(square);
    let result = adjoint(square);
    
    for (let i = 0; i < result.length; i++) {
        for (let j = 0; j < result.length; j++) {
            result[i][j] /= detValue;
        }
    }
    return result;
}

1.5 秩

// TODO

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章