"use client"; import { motion } from "framer-motion"; import { COLORS, VizFrame } from "./common"; function rng(seed: number) { let s = seed; return () => { s = (s * 1664525 + 1013904223) % 4294967296; return s / 4294967296; }; } function genWave() { const r = rng(7); const N = 30; return Array.from({ length: N }, (_, i) => { const x = i / (N - 1); const y = Math.sin(x * Math.PI * 2) * 0.7 + 1.5 + (r() - 0.5) * 0.4; return { x, y }; }); } function plot(label: string, fit: (x: number) => number, points: { x: number; y: number }[]) { const W = 280; const H = 220; const padX = 18; const padY = 16; const sx = (x: number) => padX + x * (W - padX * 2); const sy = (y: number) => H - padY - (y / 3) * (H - padY * 2); const pts = Array.from({ length: 80 }, (_, i) => i / 79); return ( {label} {points.map((p, i) => ( ))} `${sx(x)},${sy(fit(x))}`).join(" L ")}`} fill="none" stroke={COLORS.accent} strokeWidth={1.5} /> ); } export function BiasVariance({ width = 880, height = 280 }: { width?: number; height?: number }) { const points = genWave(); const W = 280; const padX = 30; const gap = (width - padX * 2 - W * 3) / 2; const linear = (x: number) => 1.4 + 0.05 * x; const cubic = (x: number) => Math.sin(x * Math.PI * 2) * 0.7 + 1.5; const wiggly = (x: number) => { let acc = 0; points.forEach((p) => { const d = Math.abs(p.x - x); const w = Math.exp(-d * d * 220); acc += w * p.y; }); const norm = points.reduce((a, p) => a + Math.exp(-((p.x - x) ** 2) * 220), 0); return acc / norm; }; const labels = ["Underfit", "Good fit", "Overfit"]; const fits = [linear, cubic, wiggly]; return ( {fits.map((f, i) => ( {plot(labels[i], f, points)} ))} ); }