/**
* @fileoverview Perceptron-Datensätze für das Perceptron-Playground.
*
* Jeder Datensatz enthält:
* - `name` {string} Anzeigename
* - `icon` {string} Emoji/Icon-Platzhalter
* - `description` {string} Kurzbeschreibung für Info-Box
* - `axisLabels` {{ x: string, y: string }} Achsenbeschriftungen
* - `featureNames` {{ x: string, y: string }} Klartextnamen der Features (Tabelle)
* - `classLabels` {[string, string]} Beschriftungen für Klasse 0/1
* - `points` {Array<{ x: number, y: number, label: 0|1 }>} Datenpunkte
* - `xRange` {[number, number]} Min/Max für x-Achse
* - `yRange` {[number, number]} Min/Max für y-Achse
* - `isGenerated` {boolean=} Wenn true, werden Punkte per Generator erzeugt
*
* Konvention: Alle numerischen Werte bereits normalisiert auf sinnvolle
* Bereiche, damit der Perceptron ohne Feature-Scaling konvergiert.
*
* @module perceptron-datasets
* @author Alexander Wolf
*/
'use strict';
/**
* @typedef {Object} PerceptronDataPoint
* @property {number} x - Feature 1 (x-Achse)
* @property {number} y - Feature 2 (y-Achse)
* @property {0|1} label - Klasse
*/
/**
* @typedef {Object} PerceptronDataset
* @property {string} name
* @property {string} icon
* @property {string} description
* @property {{ x: string, y: string }} axisLabels
* @property {{ x: string, y: string }} featureNames
* @property {[string, string]} classLabels
* @property {PerceptronDataPoint[]} points
* @property {[number, number]} xRange
* @property {[number, number]} yRange
* @property {boolean} [isGenerated]
*/
/** @type {Object<string, PerceptronDataset>} */
const PERCEPTRON_DATASETS = {
// ===================================================================
// 1) Schwimmen & Sinken – Dichte-Schwelle bei ρ = 1.0 g/cm³
// x = Volumen (cm³), y = Masse (g)
// Schwimmt (label 0) ↔ m/v < 1 → m < v → y < x
// Sinkt (label 1) ↔ m/v ≥ 1 → m ≥ v → y ≥ x
// → lineare Trenngrenze: y = x (perfekt separierbar)
// ===================================================================
schwimmen: {
name: 'Schwimmen & Sinken',
icon: '🏊',
description: 'Gegenstände (Volumen vs. Masse). Schwimmt ein Objekt oder sinkt es? ' +
'Trennlinie = Dichte 1,0 g/cm³ → m = V.',
axisLabels: { x: 'Volumen (cm³)', y: 'Masse (g)' },
featureNames: { x: 'Volumen', y: 'Masse' },
classLabels: ['Schwimmt', 'Sinkt'],
xRange: [0, 10],
yRange: [0, 10],
points: [
// Schwimmt (ρ < 1 → y < x)
{ x: 2.0, y: 0.5, label: 0 }, // Kork
{ x: 5.0, y: 2.5, label: 0 }, // Holz
{ x: 3.0, y: 1.0, label: 0 }, // Styropor
{ x: 7.0, y: 4.0, label: 0 }, // Großer Holzblock
{ x: 4.0, y: 1.5, label: 0 }, // Plastikente
{ x: 8.0, y: 6.0, label: 0 }, // Balsa-Platte
{ x: 6.0, y: 3.0, label: 0 }, // Kanu-Miniatur
{ x: 1.5, y: 0.3, label: 0 }, // Wachskugel
{ x: 9.0, y: 5.5, label: 0 }, // Große Boje
// Sinkt (ρ ≥ 1 → y ≥ x)
{ x: 1.0, y: 3.0, label: 1 }, // Stein
{ x: 2.0, y: 5.0, label: 1 }, // Metallstück
{ x: 3.0, y: 8.0, label: 1 }, // Bleigewicht
{ x: 4.0, y: 7.0, label: 1 }, // Münze
{ x: 1.5, y: 4.0, label: 1 }, // Kiesel
{ x: 5.0, y: 9.0, label: 1 }, // Stahlkugel
{ x: 2.5, y: 6.0, label: 1 }, // Glasmurmel
{ x: 6.0, y: 8.5, label: 1 }, // Eisenblock
{ x: 3.5, y: 5.5, label: 1 }, // Kupfermünze
],
},
// ===================================================================
// 2) Krabben-Klassifikation
// x = Panzergröße (cm), y = Frontallappen-Breite (cm)
// Blaukrabbe (0) vs. Orangenkrabbe (1)
// Fast linear separierbar, mit leichter Überlappung in der Mitte.
// ===================================================================
krabben: {
name: 'Krabben-Klassifikation',
icon: '🦀',
description: 'Zwei Krabbenarten nach Panzergröße und Frontallappen-Breite ' +
'klassifizieren. Fast linear trennbar – mit leichter Überlappung.',
axisLabels: { x: 'Panzergröße (cm)', y: 'Frontallappen (cm)' },
featureNames: { x: 'Panzer', y: 'Frontallappen' },
classLabels: ['Blaukrabbe', 'Orangenkrabbe'],
xRange: [0, 10],
yRange: [0, 10],
points: [
// Blaukrabbe (0) – eher kleiner Panzer, größerer Frontallappen
{ x: 2.0, y: 5.0, label: 0 },
{ x: 2.5, y: 6.5, label: 0 },
{ x: 3.0, y: 5.5, label: 0 },
{ x: 1.5, y: 4.5, label: 0 },
{ x: 3.5, y: 7.0, label: 0 },
{ x: 2.0, y: 6.0, label: 0 },
{ x: 4.0, y: 6.5, label: 0 },
{ x: 3.0, y: 7.5, label: 0 },
{ x: 1.0, y: 5.5, label: 0 },
// Orangenkrabbe (1) – eher größerer Panzer, kleinerer Frontallappen
{ x: 6.0, y: 3.0, label: 1 },
{ x: 7.0, y: 2.5, label: 1 },
{ x: 5.5, y: 4.0, label: 1 },
{ x: 8.0, y: 3.5, label: 1 },
{ x: 7.5, y: 2.0, label: 1 },
{ x: 6.5, y: 1.5, label: 1 },
{ x: 9.0, y: 3.0, label: 1 },
{ x: 5.0, y: 3.5, label: 1 },
{ x: 8.5, y: 4.0, label: 1 },
// Überlappungszone – Grenzfälle (fast gleich große Tiere)
{ x: 4.8, y: 5.0, label: 0 }, // Blaukrabbe im Grenzbereich
{ x: 5.2, y: 4.8, label: 1 }, // Orangenkrabbe im Grenzbereich
{ x: 5.0, y: 5.2, label: 0 }, // Messunsicherheit
],
},
// ===================================================================
// 3) Haustier-Debatte (Nicht linear separierbar!)
// Katzen- vs. Hunde-Fans nach Alter und Kaffeekonsum.
// Überlappende Cluster → Perceptron kann NICHT konvergieren.
// Didaktisch wertvoll: zeigt Grenzen des Perceptrons.
// ===================================================================
haustier: {
name: 'Haustier-Debatte',
icon: '🐾',
description: 'Katzen- vs. Hunde-Fans nach Alter und Kaffeekonsum. ' +
'Stark überlappend – NICHT linear trennbar! ' +
'Zeigt die Grenzen des einfachen Perceptrons.',
axisLabels: { x: 'Alter (Dekaden)', y: 'Kaffee (Tassen/Tag)' },
featureNames: { x: 'Alter', y: 'Kaffee' },
classLabels: ['Katzenfan 🐱', 'Hundefan 🐶'],
xRange: [0, 10],
yRange: [0, 10],
points: [
// Katzenfan (0) – Zufällig gemischt
{ x: 3.0, y: 4.0, label: 0 },
{ x: 5.0, y: 6.0, label: 0 },
{ x: 4.5, y: 3.5, label: 0 },
{ x: 6.0, y: 5.0, label: 0 },
{ x: 2.5, y: 5.5, label: 0 },
{ x: 7.0, y: 4.5, label: 0 },
{ x: 3.5, y: 7.0, label: 0 },
{ x: 5.5, y: 3.0, label: 0 },
{ x: 4.0, y: 5.0, label: 0 },
// Hundefan (1) – Überlappend
{ x: 4.0, y: 3.0, label: 1 },
{ x: 6.5, y: 5.5, label: 1 },
{ x: 3.5, y: 5.0, label: 1 },
{ x: 5.0, y: 4.0, label: 1 },
{ x: 7.5, y: 6.0, label: 1 },
{ x: 2.0, y: 4.5, label: 1 },
{ x: 5.5, y: 7.0, label: 1 },
{ x: 6.0, y: 3.5, label: 1 },
{ x: 4.5, y: 6.0, label: 1 },
],
},
// ===================================================================
// 4) Generischer Datensatz – Punkte per Normalverteilungs-Generator
// Zwei Cluster mit einstellbaren Parametern (μ, σ, N).
// Default-Punkte als Fallback, können aber regeneriert werden.
// ===================================================================
generisch: {
name: 'Generator',
icon: '⚙️',
description: 'Zwei Cluster per Normalverteilung generieren. ' +
'Parameter (μ, σ, N) über Schieberegler einstellen.',
axisLabels: { x: 'x₁', y: 'x₂' },
featureNames: { x: 'x₁', y: 'x₂' },
classLabels: ['Klasse 0', 'Klasse 1'],
xRange: [0, 10],
yRange: [0, 10],
isGenerated: true,
points: [
// Default-Cluster links-unten (0)
{ x: 1.0, y: 1.5, label: 0 },
{ x: 2.0, y: 1.0, label: 0 },
{ x: 1.5, y: 2.5, label: 0 },
{ x: 3.0, y: 2.0, label: 0 },
{ x: 2.5, y: 3.0, label: 0 },
{ x: 1.0, y: 3.0, label: 0 },
{ x: 2.0, y: 2.0, label: 0 },
{ x: 3.5, y: 1.5, label: 0 },
{ x: 0.5, y: 2.0, label: 0 },
// Default-Cluster rechts-oben (1)
{ x: 7.0, y: 7.0, label: 1 },
{ x: 8.0, y: 6.5, label: 1 },
{ x: 6.5, y: 8.0, label: 1 },
{ x: 9.0, y: 7.5, label: 1 },
{ x: 7.5, y: 9.0, label: 1 },
{ x: 8.5, y: 8.0, label: 1 },
{ x: 6.0, y: 7.5, label: 1 },
{ x: 9.5, y: 8.5, label: 1 },
{ x: 7.0, y: 8.0, label: 1 },
],
},
};
// ===== Universeller Export =====
(function (root) {
root.PERCEPTRON_DATASETS = PERCEPTRON_DATASETS;
})(typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : this);