core/properties/det.js

/* eslint-disable prefer-destructuring */
const Matrix = require('../..');
const { INVALID_SQUARE_MATRIX } = require('../../Error');

/**
 * Calculates the determinant of square Matrix.
 * If the Matrix size is larger than 3, it calculates the determinant using
 * LU decomposition, otherwise, using Leibniz Formula.<br><br>
 * The determinant is cached.
 * @memberof Matrix
 * @instance
 * @returns {number} Returns the determinant of square matrirx
 */
function det() {
  if (!this.isSquare()) {
    throw new Error(INVALID_SQUARE_MATRIX);
  }

  if (this._det !== undefined) {
    return this._det;
  }

  const matrix = this._matrix;
  const size = matrix.length;

  if (size === 0) {
    this._det = 1;
    return 1; // the determinant of 0x0 matrix must be 1
  }

  if (size === 1) {
    this._det = matrix[0][0];
    return this._det;
  }

  if (size === 2) {
    this._det = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
    return this._det;
  }

  if (size === 3) {
    this._det = matrix[0][0] * matrix[1][1] * matrix[2][2]
    + matrix[0][1] * matrix[1][2] * matrix[2][0]
    + matrix[0][2] * matrix[1][0] * matrix[2][1]
    - matrix[0][2] * matrix[1][1] * matrix[2][0]
    - matrix[0][1] * matrix[1][0] * matrix[2][2]
    - matrix[0][0] * matrix[1][2] * matrix[2][1];
    return this._det;
  }

  const [P, LU] = Matrix.LU(this, true);
  const matrixLU = LU._matrix;

  // count whether the number of permutations <swap> is odd or even
  // O(n^2)
  let swap = 0;
  for (let i = 0; i < size; i++) {
    if (P[i] === i) {
      continue;
    }
    while (P[i] !== i) {
      const target = P[i];
      P[i] = P[target];
      P[target] = target;
      swap++;
    }
  }

  let result = 1;
  for (let i = 0; i < size; i++) {
    result *= matrixLU[i][i];
  }

  if (swap % 2 === 1) {
    this._det = result * -1;
    return this._det;
  }
  this._det = result;
  return result;
};

module.exports = det;