core/properties/norm.js

const Matrix = require('../..');
const { INVALID_P_NORM } = require('../../Error');

/**
 * Calculates the Matrix norm of any Matrix with respect to the choice of norm.<br><br>
 * 
 * 1-norm: Maximum absolute column sum of the Matrix.<br>
 * 2-norm: The largest singular value of Matrix.<br>
 * Infinity-norm: Maximum absolute row sum of the Matrix.<br>
 * Frobenius-norm: Euclidean norm invloving all entries.<br><br>
 * 
 * The norms are not cached.
 * @memberof Matrix
 * @instance
 * @param {(1|2|Infinity|'F')} p - The choice of Matrix norm
 * @returns {number} The norm of the Matrix.
 */
function norm(p = 2) {
  const [row, col] = this.size();

  if (p !== 1 && p !== 2 && p !== Infinity && p !== 'F') {
    throw new Error(INVALID_P_NORM);
  }

  const matrix = this._matrix;
  let result = 0;

  if (p === 1) {
    // max of column sum
    for (let j = 0; j < col; j++) {
      let columnSum = 0;
      for (let i = 0; i < row; i++) {
        columnSum += Math.abs(matrix[i][j]);
      }
      if (columnSum > result) {
        result = columnSum;
      }
    }
    return result;
  }

  // largest singular value
  if (p === 2) {
    const transpose = Matrix.transpose(this);
    const M = Matrix.multiply(transpose, this);
    const eigenvalues = M.eigenvalues();

    for (let i = 0; i < eigenvalues.length; i++) {
      const value = eigenvalues[i].getModulus();
      if (value > result) {
        result = value;
      }
    }
    return Math.sqrt(result);
  }

  if (p === Infinity) {
    // max of row sum
    for (let i = 0; i < row; i++) {
      let rowSum = 0;
      for (let j = 0; j < col; j++) {
        rowSum += Math.abs(matrix[i][j]);
      }
      if (rowSum > result) {
        result = rowSum;
      }
    }
    return result;
  }

  // F
  for (let i = 0; i < row; i++) {
    for (let j = 0; j < col; j++) {
      result += matrix[i][j] ** 2;
    }
  }
  return Math.sqrt(result);
};

module.exports = norm;