typescript-ds-lib
Version:
A collection of TypeScript data structure implementations
355 lines • 10.9 kB
JavaScript
"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