UNPKG

typescript-ds-lib

Version:

A collection of TypeScript data structure implementations

355 lines 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Matrix = void 0; const base_collection_1 = require("./base-collection"); class Matrix extends base_collection_1.BaseCollection { data; numRows; numCols; constructor(rows, cols) { super(); this.numRows = rows; this.numCols = cols; this.data = Array(rows).fill(null).map(() => Array(cols).fill(undefined)); } /** * Gets the value at the specified position. The value at [row,col] or undefined if out of bounds. */ get(row, col) { if (!this.isValidPosition(row, col)) return undefined; return this.data[row][col]; } /** * Sets a value at the specified position. */ set(row, col, value) { if (!this.isValidPosition(row, col)) return; this.data[row][col] = value; } /** * Returns the number of rows in the matrix. */ rows() { return this.numRows; } /** * Returns the number of columns in the matrix. */ columns() { return this.numCols; } /** * Fills the entire matrix with a value. */ fill(value) { this.data = Array(this.numRows).fill(null).map(() => Array(this.numCols).fill(value)); } /** * Clears the matrix by setting all elements to undefined. */ clear() { this.data = Array(this.numRows).fill(null).map(() => Array(this.numCols).fill(undefined)); } /** * Checks if the matrix is empty (has zero dimensions). */ isEmpty() { return this.numRows === 0 || this.numCols === 0; } /** * Returns the total number of elements in the matrix. */ size() { return this.numRows * this.numCols; } /** * Checks if the matrix is square (same number of rows and columns). */ isSquare() { return this.numRows === this.numCols; } /** * Checks if the matrix is symmetric (equal to its transpose). */ isSymmetric() { if (!this.isSquare()) return false; for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < i; j++) { if (this.data[i][j] !== this.data[j][i]) return false; } } return true; } /** * Creates a new matrix that is the transpose of this matrix. */ transpose() { const result = new Matrix(this.numCols, this.numRows); for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { result.set(j, i, this.data[i][j]); } } return result; } /** * Adds another matrix to this one. */ add(other) { if (this.numRows !== other.rows() || this.numCols !== other.columns()) { throw new Error('Matrix dimensions must match for addition'); } const result = new Matrix(this.numRows, this.numCols); for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { const sum = this.data[i][j] + other.get(i, j); result.set(i, j, sum); } } return result; } /** * Subtracts another matrix from this one. */ subtract(other) { if (this.numRows !== other.rows() || this.numCols !== other.columns()) { throw new Error('Matrix dimensions must match for subtraction'); } const result = new Matrix(this.numRows, this.numCols); for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { const diff = this.data[i][j] - other.get(i, j); result.set(i, j, diff); } } return result; } /** * Multiplies this matrix with another matrix. */ multiply(other) { if (this.numCols !== other.rows()) { throw new Error('Matrix dimensions must be compatible for multiplication'); } const result = new Matrix(this.numRows, other.columns()); for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < other.columns(); j++) { let sum = 0; for (let k = 0; k < this.numCols; k++) { sum += this.data[i][k] * other.get(k, j); } result.set(i, j, sum); } } return result; } /** * Multiplies the matrix by a scalar value. */ scalarMultiply(scalar) { const result = new Matrix(this.numRows, this.numCols); for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { const product = this.data[i][j] * scalar; result.set(i, j, product); } } return result; } /** * Applies a function to each element and returns a new matrix. */ map(fn) { const result = new Matrix(this.numRows, this.numCols); for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { result.set(i, j, fn(this.data[i][j], i, j)); } } return result; } /** * Executes a function for each element in the matrix. */ forEach(fn) { for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { fn(this.data[i][j], i, j); } } } /** * Creates a deep copy of this matrix. */ clone() { const result = new Matrix(this.numRows, this.numCols); for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { result.set(i, j, this.data[i][j]); } } return result; } /** * Converts the matrix to a 2D array. */ toArray() { return this.data.map(row => [...row]); } /** * Checks if this matrix equals another matrix. */ equals(other) { if (this.numRows !== other.rows() || this.numCols !== other.columns()) { return false; } for (let i = 0; i < this.numRows; i++) { for (let j = 0; j < this.numCols; j++) { if (this.data[i][j] !== other.get(i, j)) return false; } } return true; } /** * Gets a copy of the specified row. */ getRow(row) { if (row < 0 || row >= this.numRows) { return []; } return [...this.data[row]]; } /** * Gets a copy of the specified column. */ getColumn(col) { if (col < 0 || col >= this.numCols) { return []; } return this.data.map(row => row[col]); } /** * Sets values for an entire row. */ setRow(row, values) { if (row < 0 || row >= this.numRows || values.length !== this.numCols) { return; } this.data[row] = [...values]; } /** * Sets values for an entire column. */ setColumn(col, values) { if (col < 0 || col >= this.numCols || values.length !== this.numRows) { return; } for (let i = 0; i < this.numRows; i++) { this.data[i][col] = values[i]; } } /** * Swaps two rows in the matrix. */ swapRows(row1, row2) { if (!this.isValidPosition(row1, 0) || !this.isValidPosition(row2, 0)) return; [this.data[row1], this.data[row2]] = [this.data[row2], this.data[row1]]; } /** * Swaps two columns in the matrix. */ swapColumns(col1, col2) { if (!this.isValidPosition(0, col1) || !this.isValidPosition(0, col2)) return; for (let i = 0; i < this.numRows; i++) { [this.data[i][col1], this.data[i][col2]] = [this.data[i][col2], this.data[i][col1]]; } } /** * Extracts a submatrix from this matrix. */ submatrix(startRow, startCol, endRow, endCol) { if (!this.isValidPosition(startRow, startCol) || !this.isValidPosition(endRow, endCol)) { throw new Error('Invalid submatrix bounds'); } const rows = endRow - startRow + 1; const cols = endCol - startCol + 1; const result = new Matrix(rows, cols); for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { result.set(i, j, this.data[startRow + i][startCol + j]); } } return result; } /** * Inserts another matrix into this matrix at the specified position. */ insertMatrix(other, startRow, startCol) { if (!this.isValidPosition(startRow, startCol)) return; const maxRows = Math.min(other.rows(), this.numRows - startRow); const maxCols = Math.min(other.columns(), this.numCols - startCol); for (let i = 0; i < maxRows; i++) { for (let j = 0; j < maxCols; j++) { this.data[startRow + i][startCol + j] = other.get(i, j); } } } /** * Gets the diagonal elements of the matrix. */ getDiagonal() { const size = Math.min(this.numRows, this.numCols); const result = []; for (let i = 0; i < size; i++) { result.push(this.data[i][i]); } return result; } /** * Sets the diagonal elements of the matrix. */ setDiagonal(values) { const size = Math.min(this.numRows, this.numCols, values.length); for (let i = 0; i < size; i++) { this.data[i][i] = values[i]; } } /** * Calculates the trace (sum of diagonal elements) of the matrix. */ trace() { if (!this.isSquare() || this.isEmpty()) { throw new Error('Trace is only defined for non-empty square matrices'); } return this.getDiagonal().reduce((sum, val) => sum + val); } /** * Resizes the matrix to new dimensions, preserving existing values where possible. */ resize(rows, cols) { const newData = Array(rows).fill(null).map(() => Array(cols).fill(undefined)); const minRows = Math.min(rows, this.numRows); const minCols = Math.min(cols, this.numCols); for (let i = 0; i < minRows; i++) { for (let j = 0; j < minCols; j++) { newData[i][j] = this.data[i][j]; } } this.data = newData; this.numRows = rows; this.numCols = cols; } isValidPosition(row, col) { return row >= 0 && row < this.numRows && col >= 0 && col < this.numCols; } } exports.Matrix = Matrix; //# sourceMappingURL=matrix.js.map