ai/neural/datasets/perceptron-datasets.js

/**
 * @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);