"use client"; import { motion } from "framer-motion"; import { useEffect, useState } from "react"; import { COLORS, VizFrame } from "./common"; import { useReducedMotion } from "@/lib/hooks/useReducedMotion"; export function GradDescent1D({ width = 720, height = 360, }: { width?: number; height?: number; }) { const padX = 50; const padY = 30; const sx = (x: number) => padX + ((x + 4) / 8) * (width - padX * 2); const sy = (y: number) => height - padY - (y / 18) * (height - padY * 2); const f = (x: number) => 1 + (x - 1) ** 2 + 0.6 * Math.sin(x * 1.5); const grad = (x: number) => 2 * (x - 1) + 0.9 * Math.cos(x * 1.5); const pts = Array.from({ length: 120 }, (_, i) => -4 + (i / 119) * 8); const path = `M ${pts.map((x) => `${sx(x)},${sy(f(x))}`).join(" L ")}`; const [lr, setLr] = useState(0.15); const [pos, setPos] = useState(-3); const reduce = useReducedMotion(); useEffect(() => { if (reduce) { setPos(1); return; } const id = setInterval(() => { setPos((p) => { const next = p - lr * grad(p); return Math.abs(next - 1) < 0.02 ? -3 : next; }); }, 80); return () => clearInterval(id); }, [lr, reduce]); return (
learning rate η = {lr.toFixed(2)} setLr(parseFloat(e.target.value))} className="mt-1 w-full accent-ink" />
); }