import { Matrix } from "../matrix/index.js";
import { Randomizer } from "../util/index.js";
/**
* @class
* @alias DR
* @borrows DR#parameter as DR#para
* @borrows DR#parameter as DR#p
*/
export class DR {
/**
* Takes the default parameters and seals them, remembers the type of input {@link X}, and initializes the random number generator.
* @constructor
* @memberof module:dimensionality_reduction
* @alias DR
* @param {Matrix|number[][]} X - the high-dimensional data.
* @param {object} parameters - Object containing parameterization of the DR method.
* @param {number} [parameters.d = 2] - the dimensionality of the projection.
* @param {function} [parameters.metric = euclidean] - the metric which defines the distance between two points.
* @param {number} [parameters.seed = 1212] - the seed value for the random number generator.
* @returns {DR}
*/
constructor(X, default_parameters, parameters) {
this._parameters = Object.assign(Object.seal(default_parameters), parameters);
if (Array.isArray(X)) {
this._type = "array";
this.X = Matrix.from(X);
} else if (X instanceof Matrix) {
this._type = "matrix";
this.X = X;
} else {
throw new Error("No valid type for X!");
}
[this._N, this._D] = this.X.shape;
this._randomizer = new Randomizer(this._parameters.seed);
this._is_initialized = false;
return this;
}
/**
* Set and get parameters
* @param {string} [name = null] - Name of the parameter. If not given then returns all parameters as an Object.
* @param {any} [value = null] - Value of the parameter to set. If <code>name</code> is set and <code>value</code> is not given, returns the value of the respective parameter.
* @returns {DR|any|object}
* On setting a parameter, this function returns the DR object.
* If <code>name</code> is set and <code>value == null</code> then return actual parameter value.
* If <code>name</code> is not given, then returns all parameters as an Object.
*
* @example
* '''
* const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for <code>d</code> = 3.
* DR.parameter("d"); // returns 3,
* DR.parameter("d", 2); // sets parameter <code>d</code> to 2 and returns <code>DR</code>.
* '''
*/
parameter(name = null, value = null) {
if (name === null) {
return Object.assign({}, this._parameters);
}
if (!this._parameters.hasOwnProperty(name)) {
throw new Error(`${name} is not a valid parameter!`);
}
if (value !== null) {
this._parameters[name] = value;
this._is_initialized = false;
return this;
} else {
return this._parameters[name];
}
}
para(name = null, value = null) {
return this.parameter(name, value);
}
p(name = null, value = null) {
return this.parameter(name, value);
}
/**
* Computes the projection.
* @returns {Matrix} the projection.
*/
transform() {
this.check_init();
return this.projection;
}
/**
* Computes the projection.
* @yields {Matrix|number[][]} the intermediate steps of the projection.
*/
*generator() {
yield this.transform();
}
/**
* If the respective DR method has an <code>init</code> function, call it before <code>transform</code>.
* @returns {DR}
*/
check_init() {
if (!this._is_initialized && typeof this.init === "function") {
this.init();
this._is_initialized = true;
}
return this;
}
/**
* @returns {Matrix|number[][]} the projection in the type of input <code>X</code>.
*/
get projection() {
if (this.hasOwnProperty("Y")) {
this.check_init();
return this._type === "matrix" ? this.Y : this.Y.to2dArray;
} else {
throw new Error("The dataset is not transformed yet!");
}
}
/**
* Computes the projection.
* @param {...unknown} args - Arguments the transform method of the respective DR method takes.
* @returns {Promise<Matrix|number[][]>} the dimensionality reduced dataset.
*/
async transform_async(...args) {
return this.transform(...args);
}
/**
* Computes the projection.
* @static
* @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.
* @returns {Matrix|number[][]} the dimensionality reduced dataset.
*/
static transform(...args) {
let dr = new this(...args);
return dr.transform();
}
/**
* Computes the projection.
* @static
* @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.
* @returns {Promise} a promise yielding the dimensionality reduced dataset.
*/
static async transform_async(...args) {
return this.transform(...args);
}
/**
* Computes the projection.
* @static
* @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.
* @returns {Generator} a generator yielding the intermediate steps of the dimensionality reduction method.
*/
static *generator(...args) {
const dr = new this(...args);
const generator = dr.generator();
for (const result of generator) {
yield result;
}
}
}