UNPKG

@railpath/finance-toolkit

Version:

Production-ready finance library for portfolio construction, risk analytics, quantitative metrics, and ML-based regime detection

272 lines (271 loc) 6.96 kB
"use strict"; /** * Matrix Operations Utilities * * Collection of utility functions for matrix operations commonly used in * mathematical optimization and portfolio analysis. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.matrixVectorMultiply = matrixVectorMultiply; exports.matrixTranspose = matrixTranspose; exports.matrixMatrixMultiply = matrixMatrixMultiply; exports.matrixTrace = matrixTrace; exports.isMatrixSymmetric = isMatrixSymmetric; exports.isMatrixPositiveDefinite = isMatrixPositiveDefinite; exports.createIdentityMatrix = createIdentityMatrix; exports.createZeroMatrix = createZeroMatrix; exports.matrixDiagonal = matrixDiagonal; exports.matrixFrobeniusNorm = matrixFrobeniusNorm; const vectorOperations_1 = require("./vectorOperations"); /** * Multiply a matrix by a vector * * @param A - Matrix (m×n) * @param x - Vector (n×1) * @returns Result vector (m×1) * * @example * ```typescript * const A = [[1, 2], [3, 4]]; * const x = [5, 6]; * const result = matrixVectorMultiply(A, x); // [17, 39] * ``` */ function matrixVectorMultiply(A, x) { if (A.length === 0 || A[0].length !== x.length) { throw new Error('Matrix columns must match vector length'); } return A.map(row => (0, vectorOperations_1.vectorDot)(row, x)); } /** * Calculate the transpose of a matrix * * @param A - Input matrix (m×n) * @returns Transpose matrix (n×m) * * @example * ```typescript * const A = [[1, 2, 3], [4, 5, 6]]; * const At = matrixTranspose(A); // [[1, 4], [2, 5], [3, 6]] * ``` */ function matrixTranspose(A) { if (A.length === 0) { return []; } const rows = A.length; const cols = A[0].length; const result = []; for (let j = 0; j < cols; j++) { result[j] = []; for (let i = 0; i < rows; i++) { result[j][i] = A[i][j]; } } return result; } /** * Multiply two matrices * * @param A - First matrix (m×k) * @param B - Second matrix (k×n) * @returns Result matrix (m×n) * * @example * ```typescript * const A = [[1, 2], [3, 4]]; * const B = [[5, 6], [7, 8]]; * const result = matrixMatrixMultiply(A, B); // [[19, 22], [43, 50]] * ``` */ function matrixMatrixMultiply(A, B) { if (A.length === 0 || B.length === 0) { throw new Error('Cannot multiply empty matrices'); } const rows = A.length; const cols = B[0].length; const inner = B.length; if (A[0].length !== inner) { throw new Error('Matrix dimensions must be compatible for multiplication'); } const result = []; for (let i = 0; i < rows; i++) { result[i] = []; for (let j = 0; j < cols; j++) { let sum = 0; for (let k = 0; k < inner; k++) { sum += A[i][k] * B[k][j]; } result[i][j] = sum; } } return result; } /** * Calculate the trace of a square matrix * * @param A - Square matrix (n×n) * @returns Trace (sum of diagonal elements) * * @example * ```typescript * const A = [[1, 2], [3, 4]]; * const trace = matrixTrace(A); // 5 * ``` */ function matrixTrace(A) { if (A.length === 0 || A.length !== A[0].length) { throw new Error('Matrix must be square'); } let trace = 0; for (let i = 0; i < A.length; i++) { trace += A[i][i]; } return trace; } /** * Check if a matrix is symmetric * * @param A - Matrix to check * @param tolerance - Tolerance for comparison (default: 1e-12) * @returns True if matrix is symmetric * * @example * ```typescript * const A = [[1, 2], [2, 3]]; * const symmetric = isMatrixSymmetric(A); // true * ``` */ function isMatrixSymmetric(A, tolerance = 1e-12) { if (A.length === 0 || A.length !== A[0].length) { return false; } for (let i = 0; i < A.length; i++) { for (let j = 0; j < A.length; j++) { if (Math.abs(A[i][j] - A[j][i]) > tolerance) { return false; } } } return true; } /** * Check if a matrix is positive definite (simplified check) * * @param A - Square matrix to check * @returns True if matrix appears to be positive definite * * @example * ```typescript * const A = [[2, -1], [-1, 2]]; // Positive definite * const pd = isMatrixPositiveDefinite(A); // true * ``` */ function isMatrixPositiveDefinite(A) { if (A.length === 0 || A.length !== A[0].length) { return false; } // Check if matrix is symmetric if (!isMatrixSymmetric(A)) { return false; } // Simple check: all diagonal elements should be positive for (let i = 0; i < A.length; i++) { if (A[i][i] <= 0) { return false; } } // For 2x2 matrices, check determinant if (A.length === 2) { const det = A[0][0] * A[1][1] - A[0][1] * A[1][0]; return det > 0; } // For larger matrices, this is a simplified check // In practice, you'd want to check all principal minors return true; } /** * Create an identity matrix of specified size * * @param size - Size of the identity matrix * @returns Identity matrix (n×n) * * @example * ```typescript * const I = createIdentityMatrix(3); * // [[1, 0, 0], [0, 1, 0], [0, 0, 1]] * ``` */ function createIdentityMatrix(size) { const I = []; for (let i = 0; i < size; i++) { I[i] = []; for (let j = 0; j < size; j++) { I[i][j] = i === j ? 1 : 0; } } return I; } /** * Create a zero matrix of specified dimensions * * @param rows - Number of rows * @param cols - Number of columns * @returns Zero matrix (m×n) * * @example * ```typescript * const Z = createZeroMatrix(2, 3); * // [[0, 0, 0], [0, 0, 0]] * ``` */ function createZeroMatrix(rows, cols) { const Z = []; for (let i = 0; i < rows; i++) { Z[i] = new Array(cols).fill(0); } return Z; } /** * Extract diagonal elements from a square matrix * * @param A - Square matrix * @returns Array of diagonal elements * * @example * ```typescript * const A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; * const diag = matrixDiagonal(A); // [1, 5, 9] * ``` */ function matrixDiagonal(A) { if (A.length === 0 || A.length !== A[0].length) { throw new Error('Matrix must be square'); } const diagonal = []; for (let i = 0; i < A.length; i++) { diagonal.push(A[i][i]); } return diagonal; } /** * Calculate the Frobenius norm of a matrix * * @param A - Matrix * @returns Frobenius norm (square root of sum of squares of all elements) * * @example * ```typescript * const A = [[1, 2], [3, 4]]; * const norm = matrixFrobeniusNorm(A); // √30 ≈ 5.477 * ``` */ function matrixFrobeniusNorm(A) { let sum = 0; for (let i = 0; i < A.length; i++) { for (let j = 0; j < A[i].length; j++) { sum += A[i][j] * A[i][j]; } } return Math.sqrt(sum); }