tahamajs's picture
download
raw
6.29 kB
/**
* interactive/svd_decay.js
* =========================
* Singular Value Spectrum Decay Visualizer & Low-Rank Energy Preservation Engine.
* Visually charts the singular values σ_i of weight matrices in log10 space,
* dynamic rank cutoff thresholds, and cumulative Frobenius energy retention.
*/
import { escapeHtml } from '../utils/dom.js';
/**
* Generates synthetic or real singular value spectrum with exponential decay.
* @param {number} dim - Matrix dimension (e.g. 768)
* @param {number} [decayRate=0.035] - Decay sharpness
* @returns {number[]} Sorted singular values (descending)
*/
export function generateSingularValues(dim = 64, decayRate = 0.045) {
const values = [];
for (let i = 0; i < dim; i++) {
// Power-law plus exponential decay mimicking empirical transformer weight spectra
const v = Math.exp(-decayRate * i) * Math.pow(i + 1, -0.4);
values.push(Math.max(1e-6, v));
}
return values;
}
/**
* Computes energy preservation ratio (Frobenius norm retention) at rank r.
*/
export function computeSpectralEnergy(singularValues, r) {
const totalEnergy = singularValues.reduce((acc, v) => acc + v * v, 0);
const retained = singularValues.slice(0, r).reduce((acc, v) => acc + v * v, 0);
return totalEnergy > 0 ? (retained / totalEnergy) : 0;
}
/**
* Renders the Singular Value Decay SVG chart and interactive inspector into a DOM container.
* @param {HTMLElement} container - DOM target container
* @param {number[]} singularValues - Sorted array of singular values
* @param {number} currentRank - Active low-rank cutoff r
* @param {Object} [options] - Callbacks and customization
*/
export function renderSVDDecay(container, singularValues, currentRank = 32, options = {}) {
if (!container) return;
const values = singularValues || generateSingularValues(64);
const N = values.length;
const r = Math.min(N, Math.max(1, currentRank));
const energy = computeSpectralEnergy(values, r);
const energyPct = (energy * 100).toFixed(2);
const W = 420;
const H = 180;
const padL = 40;
const padR = 20;
const padT = 20;
const padB = 30;
const plotW = W - padL - padR;
const plotH = H - padT - padB;
const logVals = values.map(v => Math.log10(v));
const yMin = Math.min(...logVals) * 1.05;
const yMax = Math.max(...logVals) * 1.05;
const scaleX = (idx) => padL + (idx / (N - 1)) * plotW;
const scaleY = (logV) => padT + plotH - ((logV - yMin) / (yMax - yMin)) * plotH;
const cutoffX = scaleX(r - 1);
// Spectrum curve path
const pathD = values.map((v, i) => `${i === 0 ? 'M' : 'L'} ${scaleX(i).toFixed(1)} ${scaleY(logVals[i]).toFixed(1)}`).join(' ');
// Area under retained spectrum
const retainedAreaD = `${pathD.split(' ').slice(0, r * 2).join(' ')} L ${cutoffX.toFixed(1)} ${(padT + plotH).toFixed(1)} L ${padL} ${(padT + plotH).toFixed(1)} Z`;
container.innerHTML = `
<div class="svd-decay-widget" style="display:flex; flex-direction:column; gap:10px; font-family:var(--font-mono); font-size:11px; background:#040911; padding:14px; border:1px solid var(--line); border-radius:10px;">
<div style="display:flex; justify-content:space-between; align-items:center;">
<span class="hud-badge" style="background:#a855f7; color:#fff; font-weight:800;">SINGULAR VALUE SPECTRUM</span>
<span style="color:#22d5f7;">Energy Retained: <b>${energyPct}%</b></span>
</div>
<!-- SVG Decay Chart -->
<svg id="svd-decay-svg" width="100%" height="180" viewBox="0 0 ${W} ${H}" style="background:#02060d; border:1px solid rgba(255,255,255,0.06); border-radius:6px; overflow:visible;">
<!-- Axes -->
<line x1="${padL}" y1="${padT + plotH}" x2="${W - padR}" y2="${padT + plotH}" stroke="rgba(255,255,255,0.15)" stroke-width="1" />
<line x1="${padL}" y1="${padT}" x2="${padL}" y2="${padT + plotH}" stroke="rgba(255,255,255,0.15)" stroke-width="1" />
<!-- Retained Area Gradient Fill -->
<defs>
<linearGradient id="retainedGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#a855f7" stop-opacity="0.4" />
<stop offset="100%" stop-color="#a855f7" stop-opacity="0.02" />
</linearGradient>
</defs>
<path d="${retainedAreaD}" fill="url(#retainedGrad)" />
<!-- Full Spectrum Path -->
<path d="${pathD}" fill="none" stroke="#64748b" stroke-width="1.5" stroke-dasharray="3,3" />
<!-- Retained Spectrum Segment -->
<path d="${values.slice(0, r).map((v, i) => `${i === 0 ? 'M' : 'L'} ${scaleX(i).toFixed(1)} ${scaleY(logVals[i]).toFixed(1)}`).join(' ')}"
fill="none" stroke="#c084fc" stroke-width="2.5" stroke-linecap="round" />
<!-- Cutoff Line at Rank r -->
<line x1="${cutoffX}" y1="${padT}" x2="${cutoffX}" y2="${padT + plotH}" stroke="#22d5f7" stroke-width="2" stroke-dasharray="4,2">
<animate attributeName="opacity" values="0.7;1.0;0.7" dur="2s" repeatCount="indefinite" />
</line>
<text x="${cutoffX + 4}" y="${padT + 12}" fill="#22d5f7" font-size="9" font-weight="bold">r=${r}</text>
<!-- Axis Labels -->
<text x="${padL}" y="${H - 8}" fill="#64748b" font-size="8">i=1</text>
<text x="${W - padR - 20}" y="${H - 8}" fill="#64748b" font-size="8">i=${N}</text>
<text x="${padL - 32}" y="${padT + 10}" fill="#64748b" font-size="8">log σ</text>
</svg>
<!-- Telemetry Footer -->
<div style="display:flex; justify-content:space-between; align-items:center; font-size:10px; color:var(--text-muted);">
<span>First Value: <b style="color:#fff;">σ₁ = ${values[0].toFixed(3)}</b></span>
<span>Cutoff: <b style="color:#22d5f7;">σ_${r} = ${values[r - 1].toFixed(4)}</b></span>
<span>Tail: <b style="color:#64748b;">σ_${N} = ${values[N - 1].toFixed(5)}</b></span>
</div>
</div>
`;
}

Xet Storage Details

Size:
6.29 kB
·
Xet hash:
1ed70cf60238491ee3fadb52b1e6ed246b9ca964605b294f3ff9f8feb905ca61

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.