import * as utils from "./utils.js";
/**
* Helper class for handling matrix data from multiple modalities.
* In particular, it simplifies memory management of the assorted {@linkplain ScranMatrix} instances containing data for different features in the same set of cells.
*/
export class MultiMatrix {
#store;
#ncols;
/**
* @param {object} [options={}] - Optional parameters.
* @param {object} [options.store={}] - Existing store of {@linkplain ScranMatrix} objects.
* Each matrix should correspond to a different modality, named according to its key.
* All matrices should have data for the same set of cells, i.e., same number of columns.
*/
constructor(options = {}) {
const { store = {}, ...others } = options;
utils.checkOtherOptions(others);
this.#store = store;
this.#ncols = null;
let keys = Object.keys(store);
for (var k = 0; k < keys.length; k++) {
let current = store[keys[k]];
if (k == 0) {
this.#ncols = current.numberOfColumns();
} else if (current.numberOfColumns() != this.#ncols) {
throw new Error("all matrices should have the same number of columns");
}
}
}
/**
* @return {?number} Number of columns in the matrices.
* If no matrices are available, `null` is returned.
*/
numberOfColumns() {
return this.#ncols;
}
/**
* @return {Array} Names of the available modalities.
*/
available() {
return Object.keys(this.#store);
}
/**
* @param {string} i - Name of a modality.
* @return {boolean} Whether modality `i` is available.
*/
has(i) {
return (i in this.#store);
}
/**
* @param {string} i - Name of a modality.
* @return {ScranMatrix} The matrix data for modality `i`.
*/
get(i) {
return this.#store[i];
}
/**
* @param {string} i - Name of a modality.
* @param {ScranMatrix} matrix - The matrix data for modality `i`.
*
* @return `matrix` is added to the MultiMatrix with name `i`.
*/
add(i, matrix) {
if (this.#ncols === null) {
this.#ncols = matrix.numberOfColumns();
} else if (matrix.numberOfColumns() != this.#ncols) {
throw new Error("all matrices should have the same number of columns");
}
if (i in this.#store) {
let old = this.#store[i];
utils.free(old);
}
this.#store[i] = matrix;
}
/**
* @param {string} i - Name of a modality.
* @return Modality `i` is removed from the MultiMatrix.
*/
remove(i) {
utils.free(this.#store[i]);
delete this.#store[i];
if (Object.keys(this.#store).length == 0) {
this.#ncols = null;
}
}
/**
* @param {string} i - Name of a modality.
* @return {MultiMatrix} A deep copy of the current object.
*/
clone() {
let new_matrix = new MultiMatrix;
try {
for (const [k, v] of Object.entries(this.#store)) {
new_matrix.add(k, v.clone());
}
} catch (e) {
new_matrix.free();
throw e;
}
return new_matrix;
}
/**
* @param {string} from - Old name of the modality.
* @param {string} to - New name for the modality.
*
* @return The modality `from` is renamed to `to`, possibly replacing any existing modality at `to`.
*/
rename(from, to) {
if (from !== to) {
if (to in this.#store) {
utils.free(this.#store[to]);
}
this.#store[to] = this.#store[from];
delete this.#store[from];
}
}
/**
* @return Frees memory for all modalities in this MultiMatrix.
*/
free() {
for (const [x, v] of Object.entries(this.#store)) {
utils.free(v);
}
return;
}
}