Files
railwaysystem/RuoYi-Vue/ruoyi-ui/node_modules2/ml-matrix/src/symmetricMatrix.js
T
2026-09-10 15:40:10 +08:00

249 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @typedef {0 | 1 | number | boolean} Mask
*/
import Matrix, { AbstractMatrix } from './matrix';
export class SymmetricMatrix extends AbstractMatrix {
/** @type {Matrix} */
#matrix;
get size() {
return this.#matrix.size;
}
get rows() {
return this.#matrix.rows;
}
get columns() {
return this.#matrix.columns;
}
get diagonalSize() {
return this.rows;
}
/**
* not the same as matrix.isSymmetric()
* Here is to check if it's instanceof SymmetricMatrix without bundling issues
*
* @param value
* @returns {boolean}
*/
static isSymmetricMatrix(value) {
return Matrix.isMatrix(value) && value.klassType === 'SymmetricMatrix';
}
/**
* @param diagonalSize
* @return {SymmetricMatrix}
*/
static zeros(diagonalSize) {
return new this(diagonalSize);
}
/**
* @param diagonalSize
* @return {SymmetricMatrix}
*/
static ones(diagonalSize) {
return new this(diagonalSize).fill(1);
}
/**
* @param {number | AbstractMatrix | ArrayLike<ArrayLike<number>>} diagonalSize
* @return {this}
*/
constructor(diagonalSize) {
super();
if (Matrix.isMatrix(diagonalSize)) {
if (!diagonalSize.isSymmetric()) {
throw new TypeError('not symmetric data');
}
this.#matrix = Matrix.copy(
diagonalSize,
new Matrix(diagonalSize.rows, diagonalSize.rows),
);
} else if (Number.isInteger(diagonalSize) && diagonalSize >= 0) {
this.#matrix = new Matrix(diagonalSize, diagonalSize);
} else {
this.#matrix = new Matrix(diagonalSize);
if (!this.isSymmetric()) {
throw new TypeError('not symmetric data');
}
}
}
clone() {
const matrix = new SymmetricMatrix(this.diagonalSize);
for (const [row, col, value] of this.upperRightEntries()) {
matrix.set(row, col, value);
}
return matrix;
}
toMatrix() {
return new Matrix(this);
}
get(rowIndex, columnIndex) {
return this.#matrix.get(rowIndex, columnIndex);
}
set(rowIndex, columnIndex, value) {
// symmetric set
this.#matrix.set(rowIndex, columnIndex, value);
this.#matrix.set(columnIndex, rowIndex, value);
return this;
}
removeCross(index) {
// symmetric remove side
this.#matrix.removeRow(index);
this.#matrix.removeColumn(index);
return this;
}
addCross(index, array) {
if (array === undefined) {
array = index;
index = this.diagonalSize;
}
const row = array.slice();
row.splice(index, 1);
this.#matrix.addRow(index, row);
this.#matrix.addColumn(index, array);
return this;
}
/**
* @param {Mask[]} mask
*/
applyMask(mask) {
if (mask.length !== this.diagonalSize) {
throw new RangeError('Mask size do not match with matrix size');
}
// prepare sides to remove from matrix from mask
/** @type {number[]} */
const sidesToRemove = [];
for (const [index, passthroughs] of mask.entries()) {
if (passthroughs) continue;
sidesToRemove.push(index);
}
// to remove from highest to lowest for no mutation shifting
sidesToRemove.reverse();
// remove sides
for (const sideIndex of sidesToRemove) {
this.removeCross(sideIndex);
}
return this;
}
/**
* Compact format upper-right corner of matrix
* iterate from left to right, from top to bottom.
*
* ```
* A B C D
* A 1 2 3 4
* B 2 5 6 7
* C 3 6 8 9
* D 4 7 9 10
* ```
*
* will return compact 1D array `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`
*
* length is S(i=0, n=sideSize) => 10 for a 4 sideSized matrix
*
* @returns {number[]}
*/
toCompact() {
const { diagonalSize } = this;
/** @type {number[]} */
const compact = new Array((diagonalSize * (diagonalSize + 1)) / 2);
for (let col = 0, row = 0, index = 0; index < compact.length; index++) {
compact[index] = this.get(row, col);
if (++col >= diagonalSize) col = ++row;
}
return compact;
}
/**
* @param {number[]} compact
* @return {SymmetricMatrix}
*/
static fromCompact(compact) {
const compactSize = compact.length;
// compactSize = (sideSize * (sideSize + 1)) / 2
// https://mathsolver.microsoft.com/fr/solve-problem/y%20%3D%20%20x%20%60cdot%20%20%20%60frac%7B%20%20%60left(%20x%2B1%20%20%60right)%20%20%20%20%7D%7B%202%20%20%7D
// sideSize = (Sqrt(8 × compactSize + 1) - 1) / 2
const diagonalSize = (Math.sqrt(8 * compactSize + 1) - 1) / 2;
if (!Number.isInteger(diagonalSize)) {
throw new TypeError(
`This array is not a compact representation of a Symmetric Matrix, ${JSON.stringify(
compact,
)}`,
);
}
const matrix = new SymmetricMatrix(diagonalSize);
for (let col = 0, row = 0, index = 0; index < compactSize; index++) {
matrix.set(col, row, compact[index]);
if (++col >= diagonalSize) col = ++row;
}
return matrix;
}
/**
* half iterator upper-right-corner from left to right, from top to bottom
* yield [row, column, value]
*
* @returns {Generator<[number, number, number], void, void>}
*/
*upperRightEntries() {
for (let row = 0, col = 0; row < this.diagonalSize; void 0) {
const value = this.get(row, col);
yield [row, col, value];
// at the end of row, move cursor to next row at diagonal position
if (++col >= this.diagonalSize) col = ++row;
}
}
/**
* half iterator upper-right-corner from left to right, from top to bottom
* yield value
*
* @returns {Generator<[number, number, number], void, void>}
*/
*upperRightValues() {
for (let row = 0, col = 0; row < this.diagonalSize; void 0) {
const value = this.get(row, col);
yield value;
// at the end of row, move cursor to next row at diagonal position
if (++col >= this.diagonalSize) col = ++row;
}
}
}
SymmetricMatrix.prototype.klassType = 'SymmetricMatrix';