/**
* @fileoverview Wiederverwendbarer Normalverteilungs-Generator (Box-Muller).
*
* Erzeugt 2D-Datenpunkte für zwei Klassen basierend auf konfigurierbaren
* Gauß-Parametern (μx, μy, σx, σy, N). Kann in jedem Modul verwendet
* werden, das normalverteilte Cluster benötigt.
*
* @module gaussian-generator
* @author Alexander Wolf
*/
'use strict';
/**
* @typedef {Object} GaussianClusterConfig
* @property {number} muX - Mittelwert x
* @property {number} muY - Mittelwert y
* @property {number} sigmaX - Standardabweichung x
* @property {number} sigmaY - Standardabweichung y
* @property {number} n - Anzahl Punkte
* @property {0|1} label - Klassen-Label
*/
/**
* @typedef {Object} GeneratedPoint
* @property {number} x
* @property {number} y
* @property {0|1} label
*/
const GaussianGenerator = (() => {
/**
* Box-Muller-Transformation: erzeugt zwei standardnormalverteilte Werte.
* @private
* @returns {[number, number]}
*/
function _boxMuller() {
let u1 = 0;
let u2 = 0;
// Vermeidet log(0)
while (u1 === 0) { u1 = Math.random(); }
while (u2 === 0) { u2 = Math.random(); }
const mag = Math.sqrt(-2.0 * Math.log(u1));
const angle = 2.0 * Math.PI * u2;
return [mag * Math.cos(angle), mag * Math.sin(angle)];
}
/**
* Erzeugt einen einzelnen normalverteilten Cluster.
* @param {GaussianClusterConfig} config
* @returns {GeneratedPoint[]}
*/
function generateCluster(config) {
const { muX, muY, sigmaX, sigmaY, n, label } = config;
/** @type {GeneratedPoint[]} */
const points = [];
for (let i = 0; i < n; i++) {
const [z1, z2] = _boxMuller();
points.push({
x: Math.round((muX + z1 * sigmaX) * 100) / 100,
y: Math.round((muY + z2 * sigmaY) * 100) / 100,
label,
});
}
return points;
}
/**
* Erzeugt Datenpunkte für zwei Cluster (Klasse 0 + Klasse 1).
*
* @param {GaussianClusterConfig} cluster0 - Parameter für Klasse 0
* @param {GaussianClusterConfig} cluster1 - Parameter für Klasse 1
* @returns {GeneratedPoint[]} Kombinierte, gemischte Punkteliste
*/
function generateTwoClusters(cluster0, cluster1) {
const c0 = generateCluster({ ...cluster0, label: 0 });
const c1 = generateCluster({ ...cluster1, label: 1 });
return [...c0, ...c1];
}
/**
* Erzeugt Default-Konfiguration für zwei gut getrennte Cluster.
* @param {number} [n=10] - Punkte pro Cluster
* @returns {{ cluster0: GaussianClusterConfig, cluster1: GaussianClusterConfig }}
*/
function defaultConfig(n) {
const count = n || 10;
return {
cluster0: { muX: 3, muY: 3, sigmaX: 1.0, sigmaY: 1.0, n: count, label: 0 },
cluster1: { muX: 7, muY: 7, sigmaX: 1.0, sigmaY: 1.0, n: count, label: 1 },
};
}
return {
generateCluster,
generateTwoClusters,
defaultConfig,
};
})();
// ===== Universeller Export =====
(function (root) {
root.GaussianGenerator = GaussianGenerator;
})(typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : this);