5de86388db
Sync to site1 / sync (push) Has been cancelled
- Created planning_explainer.html to demonstrate orthogonal invariance and optimal planning with interactive controls and visualizations. - Created spectral_explainer.html to illustrate spectral decomposition and linear identifiability, featuring adjustable spectral weights and real-time correlation calculations.
428 lines
20 KiB
HTML
428 lines
20 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Hermite 多项式 × OU 衰减 — 交互式探索</title>
|
||
|
||
<!--
|
||
设计系统决策(合同)
|
||
─────────────────────────────────────────────
|
||
调性:科学可视化 / 学术交互工具(非营销页)
|
||
背景:石墨黑 #0e1116 | 面板 #161b22 | 描边 #232b36
|
||
语义色:
|
||
· 线性 d=1("想要的成分") → 青蓝 var(--linear) #4cc9f0
|
||
· 高阶非线性 d≥2(被衰减) → 暖橙 var(--nl) #f4a261
|
||
· 高斯密度底纹 → 冷灰青 半透明
|
||
文字:主 #e6edf3 | 次 #8b949e | 弱 #5c6672
|
||
字体:正文衬线 'Spectral',界面无衬线 'Sora',数据/公式等宽 'JetBrains Mono'
|
||
原则:无启动页、自动演示 + 可手动接管、ρ 滑块与阶数为核心交互
|
||
-->
|
||
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,400;0,600;1,400&family=Sora:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
|
||
|
||
<style>
|
||
:root{
|
||
--bg:#0e1116; --panel:#161b22; --panel-2:#1b222c; --line:#232b36;
|
||
--txt:#e6edf3; --txt-2:#8b949e; --txt-3:#5c6672;
|
||
--linear:#4cc9f0; --linear-soft:rgba(76,201,240,.16);
|
||
--nl:#f4a261; --nl-soft:rgba(244,162,97,.16);
|
||
--gauss:rgba(150,170,190,.12);
|
||
--grid:#1c2530;
|
||
--r:14px;
|
||
}
|
||
*{box-sizing:border-box;}
|
||
html,body{margin:0;height:100%;}
|
||
body{
|
||
background:
|
||
radial-gradient(1200px 700px at 78% -8%, rgba(76,201,240,.06), transparent 60%),
|
||
var(--bg);
|
||
color:var(--txt);
|
||
font-family:'Sora',system-ui,sans-serif;
|
||
-webkit-font-smoothing:antialiased;
|
||
overflow:hidden;
|
||
}
|
||
.app{
|
||
height:100vh; display:grid;
|
||
grid-template-columns: 300px 1fr 320px;
|
||
grid-template-rows: auto 1fr;
|
||
grid-template-areas:
|
||
"head head head"
|
||
"ctrl stage read";
|
||
gap:18px; padding:22px 26px;
|
||
}
|
||
|
||
/* ── header ── */
|
||
header{grid-area:head; display:flex; align-items:baseline; gap:18px; flex-wrap:wrap;}
|
||
header .kicker{
|
||
font:500 12px/1 'JetBrains Mono',monospace; letter-spacing:.32em;
|
||
color:var(--linear); text-transform:uppercase;
|
||
}
|
||
header h1{
|
||
margin:0; font-family:'Spectral',serif; font-weight:600;
|
||
font-size:30px; letter-spacing:.01em;
|
||
}
|
||
header h1 em{color:var(--txt-2); font-style:italic; font-weight:400;}
|
||
header .sub{font-size:13px; color:var(--txt-2); max-width:560px; line-height:1.5;}
|
||
|
||
.card{background:var(--panel); border:1px solid var(--line); border-radius:var(--r);}
|
||
|
||
/* ── left controls ── */
|
||
.controls{grid-area:ctrl; padding:20px; display:flex; flex-direction:column; gap:22px; overflow-y:auto;}
|
||
.block .label{
|
||
font:600 11px/1 'JetBrains Mono',monospace; letter-spacing:.18em;
|
||
color:var(--txt-3); text-transform:uppercase; margin-bottom:12px;
|
||
}
|
||
/* rho slider */
|
||
.rho-val{font:700 40px/1 'JetBrains Mono',monospace; color:var(--linear); letter-spacing:.02em;}
|
||
.rho-val small{font-size:14px; color:var(--txt-2); font-weight:400;}
|
||
input[type=range]{
|
||
-webkit-appearance:none; width:100%; height:4px; border-radius:4px;
|
||
background:linear-gradient(90deg,var(--linear) 0%, var(--linear) var(--fill,70%), #2a323d var(--fill,70%));
|
||
margin-top:14px; cursor:pointer;
|
||
}
|
||
input[type=range]::-webkit-slider-thumb{
|
||
-webkit-appearance:none; width:18px; height:18px; border-radius:50%;
|
||
background:#eaf6fb; border:3px solid var(--linear);
|
||
box-shadow:0 0 0 4px var(--linear-soft); cursor:grab;
|
||
}
|
||
input[type=range]::-moz-range-thumb{
|
||
width:18px;height:18px;border-radius:50%;background:#eaf6fb;border:3px solid var(--linear);cursor:grab;
|
||
}
|
||
.hint{font-size:12px; color:var(--txt-3); line-height:1.55; margin-top:10px;}
|
||
|
||
/* degree toggles */
|
||
.degrees{display:flex; flex-direction:column; gap:8px;}
|
||
.deg{
|
||
display:flex; align-items:center; gap:12px; padding:10px 12px;
|
||
border:1px solid var(--line); border-radius:10px; cursor:pointer;
|
||
background:var(--panel-2); transition:.18s; -webkit-user-select:none; user-select:none;
|
||
}
|
||
.deg:hover{border-color:#36404d;}
|
||
.deg.on{border-color:currentColor; background:color-mix(in oklch, currentColor 12%, var(--panel-2));}
|
||
.deg .dot{width:11px;height:11px;border-radius:3px;background:currentColor; flex:none;}
|
||
.deg .nm{font:500 13px 'JetBrains Mono',monospace; color:var(--txt);}
|
||
.deg .eq{margin-left:auto; font:400 12px 'JetBrains Mono',monospace; color:var(--txt-2);}
|
||
.deg.d1{color:var(--linear);}
|
||
.deg.dN{color:var(--nl);}
|
||
|
||
.play{
|
||
margin-top:4px; display:flex; gap:8px;
|
||
}
|
||
.play button{
|
||
flex:1; padding:10px; border-radius:10px; border:1px solid var(--line);
|
||
background:var(--panel-2); color:var(--txt); font:500 13px 'Sora'; cursor:pointer; transition:.16s;
|
||
}
|
||
.play button:hover{border-color:var(--linear); color:var(--linear);}
|
||
.play button.live{background:var(--linear-soft); border-color:var(--linear); color:var(--linear);}
|
||
|
||
/* ── center stage ── */
|
||
.stage{grid-area:stage; padding:18px 20px 16px; display:flex; flex-direction:column; gap:14px; min-height:0;}
|
||
.stage .ttl{display:flex; align-items:baseline; justify-content:space-between;}
|
||
.stage .ttl h2{margin:0; font-family:'Spectral',serif; font-weight:600; font-size:18px;}
|
||
.stage .ttl span{font:400 12px 'JetBrains Mono',monospace; color:var(--txt-3);}
|
||
.canvas-wrap{position:relative; flex:1; min-height:0; border-radius:10px; overflow:hidden; background:#0b0e13; border:1px solid var(--line);}
|
||
canvas{display:block; width:100%; height:100%;}
|
||
.corr-wrap{height:150px; flex:none; border-radius:10px; overflow:hidden; background:#0b0e13; border:1px solid var(--line); position:relative;}
|
||
.corr-cap{position:absolute; top:10px; left:14px; font:400 12px 'JetBrains Mono',monospace; color:var(--txt-3);}
|
||
|
||
/* ── right reading ── */
|
||
.reading{grid-area:read; padding:22px; display:flex; flex-direction:column; gap:18px; overflow-y:auto;}
|
||
.reading h3{margin:0; font-family:'Spectral',serif; font-weight:600; font-size:17px;}
|
||
.takeaway{
|
||
background:var(--panel-2); border:1px solid var(--line); border-left:none;
|
||
border-radius:10px; padding:16px; font-size:13.5px; line-height:1.62; color:var(--txt);
|
||
}
|
||
.takeaway .big{font-family:'JetBrains Mono',monospace; color:var(--linear); font-weight:700;}
|
||
.formula{
|
||
font:500 15px 'JetBrains Mono',monospace; color:var(--txt);
|
||
background:#0b0e13; border:1px solid var(--line); border-radius:8px;
|
||
padding:14px 16px; line-height:1.7; letter-spacing:.01em;
|
||
}
|
||
.formula .hi{color:var(--linear);} .formula .hl{color:var(--nl);}
|
||
.verdict{
|
||
margin-top:auto; padding:16px; border-radius:10px;
|
||
background:linear-gradient(135deg, var(--linear-soft), transparent 70%);
|
||
border:1px solid color-mix(in oklch,var(--linear) 40%, var(--line));
|
||
font-family:'Spectral',serif; font-size:14px; line-height:1.6;
|
||
}
|
||
.verdict b{color:var(--linear);}
|
||
.src{font:400 11px 'JetBrains Mono',monospace; color:var(--txt-3);}
|
||
|
||
.navbar{position:fixed;bottom:14px;left:50%;transform:translateX(-50%);display:flex;gap:6px;background:rgba(22,27,34,.9);border:1px solid var(--line);border-radius:30px;padding:6px 10px;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:20;}
|
||
.navbar a{font:500 12px 'JetBrains Mono',monospace;color:var(--txt-2);text-decoration:none;padding:5px 11px;border-radius:20px;}
|
||
.navbar a:hover{color:var(--linear);}
|
||
.navbar a.on{background:var(--linear-soft);color:var(--linear);}
|
||
::-webkit-scrollbar{width:8px;height:8px;}
|
||
::-webkit-scrollbar-thumb{background:#2a323d;border-radius:8px;}
|
||
|
||
@media (max-width:1080px){
|
||
.app{grid-template-columns:1fr; grid-template-rows:auto auto auto auto; grid-template-areas:"head" "ctrl" "stage" "read"; overflow:auto; height:auto;}
|
||
body{overflow:auto;}
|
||
.canvas-wrap{height:340px;flex:none;}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app">
|
||
|
||
<header>
|
||
<div style="display:flex;flex-direction:column;gap:6px;">
|
||
<span class="kicker">LeJEPA · Topic 1</span>
|
||
<h1>Hermite 多项式 <em>与 OU 过程的 ρᵈ 衰减</em></h1>
|
||
</div>
|
||
<p class="sub">拖动相关性 <b style="color:var(--linear)">ρ</b>、切换不同阶数的 Hermite 成分,实时观察:为什么 LeJEPA 的对齐损失会<strong>只青睐线性成分</strong>——这正是「线性可识别性」定理 1 的核心直觉。</p>
|
||
</header>
|
||
|
||
<!-- 左:控制 -->
|
||
<section class="card controls">
|
||
<div class="block">
|
||
<div class="label">相关性 ρ(OU 过程)</div>
|
||
<div class="rho-val"><span id="rhoTxt">0.70</span><small> ∈ (0, 1)</small></div>
|
||
<input id="rho" type="range" min="0.05" max="0.97" step="0.01" value="0.70" aria-label="相关性 ρ" title="相关性 ρ" />
|
||
<div class="hint">ρ 越大,正样本对 (z, z′) 越相似。第 d 阶成分的时间相关性为 <b style="color:var(--txt)">ρᵈ</b>,高阶随 d 指数衰减。</div>
|
||
</div>
|
||
|
||
<div class="block">
|
||
<div class="label">显示哪些 Hermite 成分</div>
|
||
<div class="degrees" id="degList"></div>
|
||
</div>
|
||
|
||
<div class="block">
|
||
<div class="label">演示</div>
|
||
<div class="play">
|
||
<button id="autoBtn" class="live">⏸ 自动扫描 ρ</button>
|
||
<button id="resetBtn">↺ 复位</button>
|
||
</div>
|
||
<div class="hint">自动模式下 ρ 在 0.05↔0.97 之间往返,观察条形图的相对高度如何变化。</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 中:画布 -->
|
||
<section class="card stage">
|
||
<div class="ttl">
|
||
<h2>前几阶 Hermite 多项式 Heₙ(z)</h2>
|
||
<span>底纹 = 高斯密度 N(0,1),概率质量集中在 [-3, 3]</span>
|
||
</div>
|
||
<div class="canvas-wrap"><canvas id="curve"></canvas></div>
|
||
|
||
<div class="corr-wrap">
|
||
<div class="corr-cap">各阶成分对正样本对的相关性 = ρᵈ · (n! 归一化后)</div>
|
||
<canvas id="bars"></canvas>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 右:解读 -->
|
||
<section class="card reading">
|
||
<h3>实时解读</h3>
|
||
<div class="formula">
|
||
E[Heₙ(z′)·Heₙ(z)]<br>
|
||
= <span class="hi">ρ</span><sup>n</sup> · n!
|
||
</div>
|
||
<div class="takeaway" id="takeaway"></div>
|
||
|
||
<h3 style="margin-top:4px;">谱权重的含义</h3>
|
||
<div class="formula" style="font-size:13.5px;">
|
||
<span class="hi">w₁ = 1</span> → 100% 线性(想要的)<br>
|
||
<span class="hl">w_d>0 (d≥2)</span> → 残留非线性
|
||
</div>
|
||
|
||
<div class="verdict" id="verdict"></div>
|
||
<div class="src">来源:JEPA/math/01_hermite_polynomials.md</div>
|
||
</section>
|
||
|
||
</div>
|
||
|
||
<nav class="navbar" id="nav"></nav>
|
||
|
||
<script>
|
||
const NAV=[["01","Hermite","hermite_explainer.html"],["02","OU·Mehler","ou_mehler_explainer.html"],["03","谱分解","spectral_explainer.html"],["04","高斯唯一","gaussian_uniqueness_explainer.html"],["05","近似界","approx_bound_explainer.html"],["06","规划等价","planning_explainer.html"]];
|
||
const navEl=document.getElementById('nav');NAV.forEach(([n,t,f])=>{const a=document.createElement('a');a.href=f;a.textContent=n+' '+t;if(f==='hermite_explainer.html')a.className='on';navEl.appendChild(a);});
|
||
|
||
/* ───────── Hermite(概率论版 Heₙ)系数与求值 ───────── */
|
||
// 递推: He_{n+1} = z·He_n − n·He_{n-1}
|
||
function hermiteVal(n, z){
|
||
let h0 = 1, h1 = z;
|
||
if(n===0) return 1;
|
||
if(n===1) return z;
|
||
for(let k=1;k<n;k++){ const h2 = z*h1 - k*h0; h0=h1; h1=h2; }
|
||
return h1;
|
||
}
|
||
function factorial(n){ let f=1; for(let i=2;i<=n;i++) f*=i; return f; }
|
||
|
||
const DEGREES = [
|
||
{d:1, name:'He₁(z) = z', cls:'d1', color:'#4cc9f0', on:true, eq:'线性 ✓'},
|
||
{d:2, name:'He₂(z) = z²−1', cls:'dN', color:'#f4a261', on:true, eq:'二次'},
|
||
{d:3, name:'He₃(z) = z³−3z', cls:'dN', color:'#e76f51', on:false, eq:'三次'},
|
||
{d:4, name:'He₄(z) = z⁴−6z²+3', cls:'dN', color:'#bc6c8f', on:false, eq:'四次'},
|
||
];
|
||
|
||
/* ───────── 状态 ───────── */
|
||
let rho = 0.70;
|
||
let auto = true, autoDir = -1, lastTick = performance.now();
|
||
|
||
/* ───────── 构建阶数开关 ───────── */
|
||
const degList = document.getElementById('degList');
|
||
DEGREES.forEach((g,i)=>{
|
||
const el = document.createElement('div');
|
||
el.className = 'deg '+g.cls+(g.on?' on':'');
|
||
el.style.color = g.color;
|
||
el.innerHTML = `<span class="dot"></span><span class="nm">${g.name}</span><span class="eq">${g.eq}</span>`;
|
||
el.addEventListener('click', ()=>{ g.on=!g.on; el.classList.toggle('on',g.on); draw(); });
|
||
degList.appendChild(el);
|
||
});
|
||
|
||
/* ───────── 滑块 ───────── */
|
||
const rhoEl = document.getElementById('rho');
|
||
const rhoTxt = document.getElementById('rhoTxt');
|
||
function setRho(v, fromUser){
|
||
rho = Math.max(0.05, Math.min(0.97, v));
|
||
rhoEl.value = rho;
|
||
rhoTxt.textContent = rho.toFixed(2);
|
||
rhoEl.style.setProperty('--fill', ((rho-0.05)/(0.97-0.05)*100).toFixed(1)+'%');
|
||
if(fromUser){ auto=false; document.getElementById('autoBtn').classList.remove('live'); document.getElementById('autoBtn').textContent='▶ 自动扫描 ρ'; }
|
||
draw();
|
||
}
|
||
rhoEl.addEventListener('input', e=> setRho(+e.target.value, true));
|
||
|
||
document.getElementById('autoBtn').addEventListener('click', e=>{
|
||
auto = !auto;
|
||
e.target.classList.toggle('live', auto);
|
||
e.target.textContent = auto ? '⏸ 自动扫描 ρ' : '▶ 自动扫描 ρ';
|
||
lastTick = performance.now();
|
||
});
|
||
document.getElementById('resetBtn').addEventListener('click', ()=>{
|
||
DEGREES.forEach((g,i)=>{ g.on = (g.d<=2); degList.children[i].classList.toggle('on',g.on); });
|
||
setRho(0.70,false);
|
||
});
|
||
|
||
/* ───────── Canvas ───────── */
|
||
const curve = document.getElementById('curve'), cctx = curve.getContext('2d');
|
||
const bars = document.getElementById('bars'), bctx = bars.getContext('2d');
|
||
function fit(cv){ const r=cv.getBoundingClientRect(), dpr=devicePixelRatio||1; cv.width=r.width*dpr; cv.height=r.height*dpr; return {w:r.width,h:r.height,dpr};}
|
||
|
||
function drawCurves(){
|
||
const {w,h,dpr}=fit(curve); cctx.setTransform(dpr,0,0,dpr,0,0); cctx.clearRect(0,0,w,h);
|
||
const padL=44, padR=16, padT=14, padB=26;
|
||
const x0=padL, x1=w-padR, y0=padT, y1=h-padB;
|
||
const zMin=-3.2, zMax=3.2, vMin=-6, vMax=6;
|
||
const sx = z => x0 + (z-zMin)/(zMax-zMin)*(x1-x0);
|
||
const sy = v => y1 - (Math.max(vMin,Math.min(vMax,v))-vMin)/(vMax-vMin)*(y1-y0);
|
||
|
||
// 高斯密度底纹
|
||
cctx.beginPath();
|
||
for(let i=0;i<=240;i++){ const z=zMin+(zMax-zMin)*i/240; const g=Math.exp(-z*z/2); const v=g*9-0.2;
|
||
const px=sx(z), py=sy(v); i?cctx.lineTo(px,py):cctx.moveTo(px,py); }
|
||
cctx.lineTo(sx(zMax),sy(vMin)); cctx.lineTo(sx(zMin),sy(vMin)); cctx.closePath();
|
||
cctx.fillStyle='rgba(150,170,190,.10)'; cctx.fill();
|
||
|
||
// 网格 + 轴
|
||
cctx.strokeStyle='#1c2530'; cctx.lineWidth=1; cctx.font="11px 'JetBrains Mono',monospace"; cctx.fillStyle='#5c6672';
|
||
for(let v=vMin; v<=vMax; v+=3){ const py=sy(v); cctx.beginPath(); cctx.moveTo(x0,py); cctx.lineTo(x1,py); cctx.stroke(); cctx.fillText(v.toString().padStart(2,' '), 8, py+4); }
|
||
for(let z=-3; z<=3; z++){ const px=sx(z); cctx.beginPath(); cctx.moveTo(px,y0); cctx.lineTo(px,y1); cctx.strokeStyle='#161d27'; cctx.stroke(); cctx.fillText(z.toString(), px-4, y1+18); }
|
||
// 零轴
|
||
cctx.strokeStyle='#33404e'; cctx.lineWidth=1.5; cctx.beginPath(); cctx.moveTo(x0,sy(0)); cctx.lineTo(x1,sy(0)); cctx.stroke();
|
||
|
||
// 各阶曲线
|
||
DEGREES.filter(g=>g.on).forEach(g=>{
|
||
cctx.beginPath();
|
||
for(let i=0;i<=320;i++){ const z=zMin+(zMax-zMin)*i/320; const v=hermiteVal(g.d,z);
|
||
const px=sx(z), py=sy(v); i?cctx.lineTo(px,py):cctx.moveTo(px,py); }
|
||
cctx.lineWidth = g.d===1?3:2; cctx.strokeStyle=g.color;
|
||
cctx.shadowColor=g.color; cctx.shadowBlur = g.d===1?10:5; cctx.stroke(); cctx.shadowBlur=0;
|
||
// 标签
|
||
const lz=2.6, lv=hermiteVal(g.d,lz);
|
||
cctx.fillStyle=g.color; cctx.font="600 12px 'JetBrains Mono',monospace";
|
||
cctx.fillText('He'+g.d, sx(lz)+4, sy(lv));
|
||
});
|
||
}
|
||
|
||
function drawBars(){
|
||
const {w,h,dpr}=fit(bars); bctx.setTransform(dpr,0,0,dpr,0,0); bctx.clearRect(0,0,w,h);
|
||
const items = DEGREES.filter(g=>g.on);
|
||
const padT=34, padB=24, padL=18, padR=18;
|
||
const y0=padT, y1=h-padB;
|
||
const n=items.length || 1;
|
||
const gap=22, bw=Math.min(90,(w-padL-padR-gap*(n-1))/n);
|
||
const groupW=bw*n+gap*(n-1);
|
||
const startX=(w-groupW)/2;
|
||
// 基线(=ρ,线性成分的相关性,作为参考)
|
||
const refY = y1 - (rho)*(y1-y0);
|
||
bctx.strokeStyle='rgba(76,201,240,.45)'; bctx.setLineDash([5,4]); bctx.lineWidth=1.5;
|
||
bctx.beginPath(); bctx.moveTo(padL,refY); bctx.lineTo(w-padR,refY); bctx.stroke(); bctx.setLineDash([]);
|
||
bctx.fillStyle='rgba(76,201,240,.8)'; bctx.font="500 11px 'JetBrains Mono',monospace";
|
||
bctx.fillText('ρ¹ = '+rho.toFixed(2), w-padR-70, refY-6);
|
||
|
||
items.forEach((g,i)=>{
|
||
const val=Math.pow(rho,g.d); // ρ^d
|
||
const x=startX+i*(bw+gap);
|
||
const bh=val*(y1-y0);
|
||
const yTop=y1-bh;
|
||
// 柱
|
||
const grd=bctx.createLinearGradient(0,yTop,0,y1);
|
||
grd.addColorStop(0,g.color); grd.addColorStop(1,'color-mix' in CSS ? g.color : g.color);
|
||
bctx.fillStyle=g.color; bctx.globalAlpha = g.d===1?1:0.85;
|
||
bctx.fillRect(x,yTop,bw,bh); bctx.globalAlpha=1;
|
||
// 数值
|
||
bctx.fillStyle=g.color; bctx.font="700 13px 'JetBrains Mono',monospace"; bctx.textAlign='center';
|
||
bctx.fillText('ρ'+g.d+' = '+val.toFixed(3), x+bw/2, yTop-7);
|
||
bctx.fillStyle='#8b949e'; bctx.font="400 11px 'JetBrains Mono',monospace";
|
||
bctx.fillText('He'+g.d, x+bw/2, y1+15);
|
||
bctx.textAlign='left';
|
||
});
|
||
}
|
||
|
||
/* ───────── 文案更新 ───────── */
|
||
function updateText(){
|
||
const r=rho;
|
||
const r1=r, r2=r*r, r3=r*r*r;
|
||
const ratio=(r2/r1*100).toFixed(0); // ρ²/ρ
|
||
const take=document.getElementById('takeaway');
|
||
take.innerHTML =
|
||
`当前 ρ = <span class="big">${r.toFixed(2)}</span>:`+
|
||
`线性成分相关性 = ρ¹ = <b style="color:var(--linear)">${r1.toFixed(3)}</b>,`+
|
||
`二次成分仅 = ρ² = <b style="color:var(--nl)">${r2.toFixed(3)}</b>`+
|
||
`(保留约 <b>${ratio}%</b>),三次成分 ρ³ = <b style="color:var(--nl)">${r3.toFixed(3)}</b>。`+
|
||
`<br><br>阶数越高,<b style="color:var(--nl)">衰减越快</b>——对齐损失要<strong>最大化</strong>相关性,自然只会保留 <b style="color:var(--linear)">d=1 的线性成分</b>。`;
|
||
|
||
const v=document.getElementById('verdict');
|
||
v.innerHTML =
|
||
`因为非线性成分(d≥2)的贡献 <b>ρᵈ < ρ</b> 恒成立,`+
|
||
`LeJEPA 的唯一最优解就是 <b>h(z) = Q·z</b>(正交线性映射)。`+
|
||
`<br>这就是<b>线性可识别性(定理 1)</b>的全部直觉。`;
|
||
}
|
||
|
||
/* ───────── 主绘制 ───────── */
|
||
function draw(){ drawCurves(); drawBars(); updateText(); }
|
||
|
||
/* ───────── 自动扫描动画 ───────── */
|
||
function loop(now){
|
||
if(auto){
|
||
const dt=(now-lastTick)/1000; lastTick=now;
|
||
let v=rho + autoDir*dt*0.22;
|
||
if(v<=0.05){ v=0.05; autoDir=1; }
|
||
if(v>=0.97){ v=0.97; autoDir=-1; }
|
||
setRho(v,false);
|
||
} else { lastTick=now; }
|
||
requestAnimationFrame(loop);
|
||
}
|
||
|
||
/* ───────── 键盘热键 ───────── */
|
||
document.addEventListener('keydown', e=>{
|
||
if(e.code==='Space'){ e.preventDefault(); document.getElementById('autoBtn').click(); }
|
||
else if(e.key==='ArrowLeft'){ setRho(rho-0.03,true); }
|
||
else if(e.key==='ArrowRight'){ setRho(rho+0.03,true); }
|
||
else if(e.key==='0'){ document.getElementById('resetBtn').click(); }
|
||
});
|
||
|
||
window.addEventListener('resize', draw);
|
||
|
||
/* ───────── 初始化 ───────── */
|
||
setRho(0.70,false);
|
||
draw();
|
||
requestAnimationFrame(loop);
|
||
</script>
|
||
</body>
|
||
</html> |