function parameterPareto(models) { return models.filter(m => !models.some(other => other.params <= m.params && indexScore(other) >= indexScore(m) && (other.params < m.params || indexScore(other) > indexScore(m)) )).sort((a,b) => a.params-b.params); } function renderParameterChart(selection) { const models = selection.filter(m => m.params > 0 && indexScore(m) !== null && !m.excludedSizeComparison); const container = document.getElementById('parameter-chart'); document.getElementById('parameter-count').textContent = `${models.length} selected models`; document.getElementById('parameter-legend').innerHTML = [...new Set(models.map(m=>m.org))].map(id => `${escape(ORGS[id].name)}`).join(''); if (!models.length) { container.innerHTML = '

Select models to compare intelligence and parameter count.

'; return; } const left=66, top=24, width=950, height=350; const logs=models.map(m=>Math.log10(m.params)); const minLog=Math.floor((Math.min(...logs)-.06)*4)/4; const maxLog=Math.max(minLog+.5,Math.ceil((Math.max(...logs)+.08)*4)/4); const scores=models.map(indexScore); const bottomScore=Math.max(0,Math.floor((Math.min(...scores)-5)/10)*10); const topScore=Math.min(100,Math.max(bottomScore+20,Math.ceil((Math.max(...scores)+5)/10)*10)); const x=p=>left+(Math.log10(p)-minLog)/(maxLog-minLog)*width; const y=s=>top+height-(s-bottomScore)/(topScore-bottomScore)*height; const median=values=>{const a=[...values].sort((a,b)=>a-b);return (a[Math.floor((a.length-1)/2)]+a[Math.ceil((a.length-1)/2)])/2;}; const midX=x(median(models.map(m=>m.params))),midY=y(median(scores)); const formatParams=p=>p>=1e9?`${+(p/1e9).toFixed(2)}B`:p>=1e6?`${+(p/1e6).toFixed(2)}M`:`${+(p/1e3).toFixed(2)}K`; let axes=''; for(let score=bottomScore;score<=topScore;score+=10){ axes+=`${score}`; } let lastTick=-Infinity; for(let power=Math.floor(minLog);power<=Math.ceil(maxLog);power++)for(const multiplier of [1,2,3,5,7]){ const p=multiplier*10**power,px=x(p); if(pxleft+width||px-lastTick<48)continue; lastTick=px; axes+=`${formatParams(p)}`; } const pareto=parameterPareto(models); const labelBoxes=[]; const points=[...models].sort((a,b)=>Number(pareto.includes(b))-Number(pareto.includes(a))).map(m=>{ const px=x(m.params),py=y(indexScore(m)); const labelWidth=m.name.length*6.3; let label=''; // Prefer frontier labels; avoid overlapping the labels already placed. for(const dy of [-12,18,-28,34]){ const labelX=px+labelWidth+14>left+width?px-labelWidth-10:px+10; const box={x:labelX,y:py+dy-10,w:labelWidth,h:14}; if(box.xtop+height||labelBoxes.some(b=>box.xb.x&&box.yb.y))continue; labelBoxes.push(box);label=`${escape(m.name)}`;break; } const title=`${m.name} · ${m.params.toLocaleString()} parameters · Index ${indexScore(m).toFixed(2)}${pareto.includes(m)?' · Pareto frontier':''}`; return `${escape(title)}${label}`; }).join(''); container.innerHTML=`Intelligence Index versus parameter count${models.length} models. Logarithmic parameter axis. Higher index and fewer parameters are preferred. Each point links to its model details.${axes}${points}Parameters (log scale)Intelligence Index`; }