@allmaps/stdlib
Version:
Allmaps Standard Library
110 lines (109 loc) • 4.53 kB
JavaScript
import { isEqualArray } from './main.js';
/**
* Create and fill a ArrayMatrix: an Arrays of Arrays, that can later be loaded as a ml-matrix Matrix
*/
export function newArrayMatrix(rows, cols, value = 0) {
if (rows <= 0 || cols <= 0) {
throw new Error('Empty ArrayMatrix not supported');
}
return Array.from(Array(rows), (_) => Array(cols).fill(value));
}
export function arrayMatrixSize(arrayMatrix) {
if (arrayMatrix.length === 0) {
throw new Error('ArrayMatrix may not be empty, but rows are empty');
}
const rowLengths = arrayMatrix.map((row) => row.length);
if (rowLengths.some((rowLength) => rowLength === 0)) {
throw new Error('ArrayMatrix may not be empty, but at least one row is empty');
}
if (!rowLengths.every((rowLength) => rowLength === rowLengths[0])) {
throw new Error('Rows of unequal length');
}
const rows = arrayMatrix.length;
const cols = rowLengths[0];
return [rows, cols];
}
export function shallowCopyArrayMatrix(arrayMatrix) {
return arrayMatrix.map((row) => [...row]);
}
// Slice specific rows and columns of an arrayMatrix.
// Just like slice, this returns a copy!
export function sliceArrayMatrix(arrayMatrix, rowsStart, colsStart, rowsEnd, colsEnd) {
return arrayMatrix
.slice(rowsStart, rowsEnd)
.map((row) => row.slice(colsStart, colsEnd));
}
// Get a submatrix at specified rows and columns.
// This is more flexible the the range, like in sliceArrayMatrix.
export function subArrayMatrix(arrayMatrix, rows, cols) {
const size = [rows.length, cols.length];
const result = newArrayMatrix(...size);
for (let i = 0; i < size[0]; i++) {
for (let j = 0; j < size[1]; j++) {
result[i][j] = arrayMatrix[rows[i]][cols[j]];
}
}
return result;
}
// Pointwise multiplication. For Matrix multiplication, see ml-matrix
export function multiplyArrayMatrix(arrayMatrix, factor) {
const size = arrayMatrixSize(arrayMatrix);
const result = newArrayMatrix(...size);
for (let i = 0; i < size[0]; i++) {
for (let j = 0; j < size[1]; j++) {
result[i][j] = factor * arrayMatrix[i][j];
}
}
return result;
}
// Pastes a arrayMatrix inside an arrayMatrix at a specific location.
// Returns a copy with the pasted subArray.
export function pasteArrayMatrix(arrayMatrix, rowsStart, colsStart, subArrayMatrix) {
const subSize = arrayMatrixSize(subArrayMatrix);
const result = shallowCopyArrayMatrix(arrayMatrix);
for (let i = 0; i < subSize[0]; i++) {
for (let j = 0; j < subSize[1]; j++) {
result[rowsStart + i][colsStart + j] = subArrayMatrix[i][j];
}
}
return result;
}
export function transposeArrayMatrix(arrayMatrix) {
return arrayMatrix[0].map((_, colIndex) => arrayMatrix.map((row) => row[colIndex]));
}
export function newBlockArrayMatrix(blocks, emptyValue = 0) {
const size = arrayMatrixSize(blocks);
const sizesArrayMatrix = blocks.map((row) => row.map((block) => arrayMatrixSize(block)));
const rowsArrayMatrix = sizesArrayMatrix.map((row) => row.map((dims) => dims[0]));
const transposedRowsArrayMatrix = transposeArrayMatrix(rowsArrayMatrix);
const rowsArray = transposedRowsArrayMatrix[0];
if (!transposedRowsArrayMatrix.every((array) => isEqualArray(array, transposedRowsArrayMatrix[0]))) {
throw new Error('The blocks, by block column, must have the same sequence of rows.');
}
const rowsTrailingCumulativeArray = [];
let sum = 0;
rowsArray.forEach((e) => {
rowsTrailingCumulativeArray.push(sum);
sum = sum + e;
});
const rowsCumulative = sum;
const colsArrayMatrix = sizesArrayMatrix.map((row) => row.map((dims) => dims[1]));
const colsArray = colsArrayMatrix[0];
if (!colsArrayMatrix.every((array) => isEqualArray(array, colsArray))) {
throw new Error('The blocks, by block row, must have the same sequence of columns.');
}
const colsTrailingCumulativeArray = [];
sum = 0;
colsArrayMatrix[0].forEach((e) => {
colsTrailingCumulativeArray.push(sum);
sum = sum + e;
});
const colsCumulative = sum;
let result = newArrayMatrix(rowsCumulative, colsCumulative, emptyValue);
for (let i = 0; i < size[0]; i++) {
for (let j = 0; j < size[1]; j++) {
result = pasteArrayMatrix(result, rowsTrailingCumulativeArray[i], rowsTrailingCumulativeArray[j], blocks[i][j]);
}
}
return result;
}