start . me .
Directory path . code , ai , nets .

HTML Document File : som_interactive.html

<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Self-Organizing Maps (SOM) - Esempio Interattivo</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            min-height: 100vh;
        }
        
        .container {
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            padding: 30px;
            box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
        }
        
        h1 {
            text-align: center;
            margin-bottom: 30px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
        }
        
        .explanation {
            background: rgba(255, 255, 255, 0.15);
            padding: 20px;
            border-radius: 15px;
            margin-bottom: 30px;
            border-left: 4px solid #64ffda;
        }
        
        .controls {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 30px;
        }
        
        .control-group {
            background: rgba(255, 255, 255, 0.1);
            padding: 15px;
            border-radius: 10px;
        }
        
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        
        input[type="range"] {
            width: 100%;
            margin-bottom: 10px;
        }
        
        button {
            background: linear-gradient(45deg, #64ffda, #00bcd4);
            border: none;
            color: white;
            padding: 12px 20px;
            border-radius: 25px;
            cursor: pointer;
            font-weight: bold;
            transition: all 0.3s ease;
            width: 100%;
            margin: 5px 0;
        }
        
        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.3);
        }
        
        button:disabled {
            background: #666;
            cursor: not-allowed;
            transform: none;
        }
        
        .visualization {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }
        
        .canvas-container {
            background: rgba(255, 255, 255, 0.9);
            border-radius: 15px;
            padding: 20px;
            text-align: center;
        }
        
        .canvas-container h3 {
            color: #333;
            margin-top: 0;
        }
        
        canvas {
            border: 2px solid #333;
            border-radius: 10px;
            cursor: crosshair;
        }
        
        .stats {
            background: rgba(255, 255, 255, 0.15);
            padding: 20px;
            border-radius: 15px;
            margin-top: 20px;
        }
        
        .info-panel {
            background: rgba(255, 255, 255, 0.1);
            padding: 20px;
            border-radius: 15px;
            margin-top: 20px;
        }
        
        @media (max-width: 768px) {
            .visualization {
                grid-template-columns: 1fr;
            }
            .controls {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🧠 Mappe Auto Organizzanti (SOM)</h1>
        
        <div class="explanation">
            <h3>💡 Cosa sono le SOM?</h3>
            <p>Le Self-Organizing Maps sono reti neurali che imparano a organizzare dati complessi in una mappa bidimensionale ordinata. Ogni neurone nella griglia ha un "peso" che rappresenta un punto nello spazio dei dati.</p>
            <p><strong>Come funzionano:</strong> Quando presenti un dato, il neurone più simile (vincitore) si aggiorna per assomigliare di più al dato, e anche i neuroni vicini si aggiustano gradualmente.</p>
        </div>
        
        <div class="controls">
            <div class="control-group">
                <label>Dimensione Griglia: <span id="gridSizeValue">10x10</span></label>
                <input type="range" id="gridSize" min="5" max="20" value="10">
            </div>
            
            <div class="control-group">
                <label>Tasso di Apprendimento: <span id="learningRateValue">0.1</span></label>
                <input type="range" id="learningRate" min="0.01" max="0.5" step="0.01" value="0.1">
            </div>
            
            <div class="control-group">
                <label>Raggio Vicinato: <span id="neighborhoodValue">3</span></label>
                <input type="range" id="neighborhood" min="1" max="8" value="3">
            </div>
            
            <div class="control-group">
                <button id="resetBtn">🔄 Reset Rete</button>
                <button id="trainBtn">🎯 Addestra (100 step)</button>
                <button id="autoTrainBtn">⚡ Auto-Addestramento</button>
                <button id="clearDataBtn">🗑️ Cancella Dati</button>
            </div>
        </div>
        
        <div class="visualization">
            <div class="canvas-container">
                <h3>📊 Spazio dei Dati (Clicca per aggiungere punti)</h3>
                <canvas id="dataCanvas" width="300" height="300"></canvas>
                <p style="color: #666; font-size: 12px;">Clicca per aggiungere punti dati colorati</p>
            </div>
            
            <div class="canvas-container">
                <h3>🗺️ Mappa SOM (Neuroni)</h3>
                <canvas id="somCanvas" width="300" height="300"></canvas>
                <p style="color: #666; font-size: 12px;">I colori rappresentano i pesi dei neuroni</p>
            </div>
        </div>
        
        <div class="stats">
            <h3>📈 Statistiche</h3>
            <div id="statsContent">
                <p>Iterazioni di addestramento: <span id="iterations">0</span></p>
                <p>Punti dati: <span id="dataCount">0</span></p>
                <p>Errore quantizzazione: <span id="quantError">N/A</span></p>
            </div>
        </div>
        
        <div class="info-panel">
            <h3>🎓 Come usare questa demo:</h3>
            <ol>
                <li><strong>Aggiungi dati:</strong> Clicca nel riquadro sinistro per creare punti colorati</li>
                <li><strong>Osserva la rete:</strong> I neuroni (riquadro destro) iniziano con colori casuali</li>
                <li><strong>Addestra:</strong> Usa i pulsanti per far imparare la rete</li>
                <li><strong>Risultato:</strong> I neuroni si organizzeranno per rappresentare i tuoi dati!</li>
            </ol>
            
            <h4>🔍 Cosa osservare:</h4>
            <ul>
                <li>I neuroni vicini sviluppano colori simili (proprietà topologica)</li>
                <li>La mappa preserva le relazioni di vicinanza dei dati originali</li>
                <li>Aree dense di dati avranno più neuroni dedicati</li>
            </ul>
        </div>
    </div>

    <script>
        class SOM {
            constructor(width, height, inputDim) {
                this.width = width;
                this.height = height;
                this.inputDim = inputDim;
                this.neurons = [];
                this.learningRate = 0.1;
                this.neighborhoodRadius = 3;
                this.iteration = 0;
                
                this.initializeNeurons();
            }
            
            initializeNeurons() {
                this.neurons = [];
                for (let i = 0; i < this.height; i++) {
                    this.neurons[i] = [];
                    for (let j = 0; j < this.width; j++) {
                        this.neurons[i][j] = {
                            weights: [
                                Math.random() * 255, // R
                                Math.random() * 255, // G
                                Math.random() * 255  // B
                            ],
                            x: j,
                            y: i
                        };
                    }
                }
            }
            
            findBMU(input) {
                let minDistance = Infinity;
                let bmu = { x: 0, y: 0 };
                
                for (let i = 0; i < this.height; i++) {
                    for (let j = 0; j < this.width; j++) {
                        const distance = this.euclideanDistance(input, this.neurons[i][j].weights);
                        if (distance < minDistance) {
                            minDistance = distance;
                            bmu = { x: j, y: i };
                        }
                    }
                }
                
                return { bmu, distance: minDistance };
            }
            
            euclideanDistance(a, b) {
                return Math.sqrt(a.reduce((sum, val, i) => sum + Math.pow(val - b[i], 2), 0));
            }
            
            getNeighborhoodInfluence(distance) {
                return Math.exp(-(distance * distance) / (2 * this.neighborhoodRadius * this.neighborhoodRadius));
            }
            
            updateWeights(input, bmu) {
                for (let i = 0; i < this.height; i++) {
                    for (let j = 0; j < this.width; j++) {
                        const neuronDistance = Math.sqrt(Math.pow(j - bmu.x, 2) + Math.pow(i - bmu.y, 2));
                        
                        if (neuronDistance <= this.neighborhoodRadius) {
                            const influence = this.getNeighborhoodInfluence(neuronDistance);
                            const learningInfluence = this.learningRate * influence;
                            
                            for (let k = 0; k < this.inputDim; k++) {
                                this.neurons[i][j].weights[k] += learningInfluence * (input[k] - this.neurons[i][j].weights[k]);
                            }
                        }
                    }
                }
            }
            
            train(dataPoints) {
                if (dataPoints.length === 0) return 0;
                
                let totalError = 0;
                
                for (const point of dataPoints) {
                    const { bmu, distance } = this.findBMU(point);
                    this.updateWeights(point, bmu);
                    totalError += distance;
                }
                
                this.iteration++;
                return totalError / dataPoints.length;
            }
        }
        
        class SOMVisualizer {
            constructor() {
                this.som = new SOM(10, 10, 3);
                this.dataPoints = [];
                this.isAutoTraining = false;
                this.autoTrainInterval = null;
                
                this.initializeCanvases();
                this.setupEventListeners();
                this.updateDisplay();
            }
            
            initializeCanvases() {
                this.dataCanvas = document.getElementById('dataCanvas');
                this.dataCtx = this.dataCanvas.getContext('2d');
                this.somCanvas = document.getElementById('somCanvas');
                this.somCtx = this.somCanvas.getContext('2d');
                
                // Disegna sfondo griglia per i dati
                this.drawDataBackground();
            }
            
            setupEventListeners() {
                // Controlli
                document.getElementById('gridSize').addEventListener('input', (e) => {
                    const size = parseInt(e.target.value);
                    document.getElementById('gridSizeValue').textContent = `${size}x${size}`;
                    this.som = new SOM(size, size, 3);
                    this.updateDisplay();
                });
                
                document.getElementById('learningRate').addEventListener('input', (e) => {
                    this.som.learningRate = parseFloat(e.target.value);
                    document.getElementById('learningRateValue').textContent = e.target.value;
                });
                
                document.getElementById('neighborhood').addEventListener('input', (e) => {
                    this.som.neighborhoodRadius = parseInt(e.target.value);
                    document.getElementById('neighborhoodValue').textContent = e.target.value;
                });
                
                // Pulsanti
                document.getElementById('resetBtn').addEventListener('click', () => {
                    this.som.initializeNeurons();
                    this.som.iteration = 0;
                    this.updateDisplay();
                });
                
                document.getElementById('trainBtn').addEventListener('click', () => {
                    this.trainSteps(100);
                });
                
                document.getElementById('autoTrainBtn').addEventListener('click', () => {
                    this.toggleAutoTraining();
                });
                
                document.getElementById('clearDataBtn').addEventListener('click', () => {
                    this.dataPoints = [];
                    this.updateDisplay();
                });
                
                // Click su canvas dati
                this.dataCanvas.addEventListener('click', (e) => {
                    this.addDataPoint(e);
                });
            }
            
            drawDataBackground() {
                this.dataCtx.fillStyle = '#f0f0f0';
                this.dataCtx.fillRect(0, 0, this.dataCanvas.width, this.dataCanvas.height);
                
                // Griglia
                this.dataCtx.strokeStyle = '#ddd';
                this.dataCtx.lineWidth = 1;
                
                for (let i = 0; i <= 10; i++) {
                    const x = (i / 10) * this.dataCanvas.width;
                    const y = (i / 10) * this.dataCanvas.height;
                    
                    this.dataCtx.beginPath();
                    this.dataCtx.moveTo(x, 0);
                    this.dataCtx.lineTo(x, this.dataCanvas.height);
                    this.dataCtx.stroke();
                    
                    this.dataCtx.beginPath();
                    this.dataCtx.moveTo(0, y);
                    this.dataCtx.lineTo(this.dataCanvas.width, y);
                    this.dataCtx.stroke();
                }
            }
            
            addDataPoint(event) {
                const rect = this.dataCanvas.getBoundingClientRect();
                const x = ((event.clientX - rect.left) / this.dataCanvas.width) * 255;
                const y = ((event.clientY - rect.top) / this.dataCanvas.height) * 255;
                
                // Crea un colore basato sulla posizione
                const r = x;
                const g = y;
                const b = 128 + Math.sin(x * 0.02) * 127;
                
                this.dataPoints.push([r, g, b]);
                this.updateDisplay();
            }
            
            trainSteps(steps) {
                let totalError = 0;
                for (let i = 0; i < steps; i++) {
                    const error = this.som.train(this.dataPoints);
                    totalError += error;
                }
                this.updateDisplay();
            }
            
            toggleAutoTraining() {
                const btn = document.getElementById('autoTrainBtn');
                
                if (this.isAutoTraining) {
                    clearInterval(this.autoTrainInterval);
                    this.isAutoTraining = false;
                    btn.textContent = '⚡ Auto-Addestramento';
                    btn.style.background = 'linear-gradient(45deg, #64ffda, #00bcd4)';
                } else {
                    this.isAutoTraining = true;
                    btn.textContent = '⏹️ Stop Auto';
                    btn.style.background = 'linear-gradient(45deg, #ff6b6b, #ff8e53)';
                    
                    this.autoTrainInterval = setInterval(() => {
                        this.trainSteps(5);
                    }, 100);
                }
            }
            
            updateDisplay() {
                this.drawDataPoints();
                this.drawSOM();
                this.updateStats();
            }
            
            drawDataPoints() {
                this.drawDataBackground();
                
                this.dataPoints.forEach(point => {
                    const x = (point[0] / 255) * this.dataCanvas.width;
                    const y = (point[1] / 255) * this.dataCanvas.height;
                    
                    this.dataCtx.fillStyle = `rgb(${Math.round(point[0])}, ${Math.round(point[1])}, ${Math.round(point[2])})`;
                    this.dataCtx.beginPath();
                    this.dataCtx.arc(x, y, 6, 0, 2 * Math.PI);
                    this.dataCtx.fill();
                    
                    this.dataCtx.strokeStyle = '#333';
                    this.dataCtx.lineWidth = 1;
                    this.dataCtx.stroke();
                });
            }
            
            drawSOM() {
                const cellWidth = this.somCanvas.width / this.som.width;
                const cellHeight = this.somCanvas.height / this.som.height;
                
                for (let i = 0; i < this.som.height; i++) {
                    for (let j = 0; j < this.som.width; j++) {
                        const weights = this.som.neurons[i][j].weights;
                        const color = `rgb(${Math.round(weights[0])}, ${Math.round(weights[1])}, ${Math.round(weights[2])})`;
                        
                        this.somCtx.fillStyle = color;
                        this.somCtx.fillRect(j * cellWidth, i * cellHeight, cellWidth, cellHeight);
                        
                        this.somCtx.strokeStyle = '#333';
                        this.somCtx.lineWidth = 1;
                        this.somCtx.strokeRect(j * cellWidth, i * cellHeight, cellWidth, cellHeight);
                    }
                }
            }
            
            updateStats() {
                document.getElementById('iterations').textContent = this.som.iteration;
                document.getElementById('dataCount').textContent = this.dataPoints.length;
                
                if (this.dataPoints.length > 0) {
                    let totalError = 0;
                    this.dataPoints.forEach(point => {
                        const { distance } = this.som.findBMU(point);
                        totalError += distance;
                    });
                    document.getElementById('quantError').textContent = (totalError / this.dataPoints.length).toFixed(2);
                } else {
                    document.getElementById('quantError').textContent = 'N/A';
                }
            }
        }
        
        // Inizializza l'applicazione
        window.addEventListener('load', () => {
            new SOMVisualizer();
        });
    </script>
</body>
</html>