import { useMemo } from "react"; import { formatNumber } from "./formula"; import { edgePath, layoutGraph, OUTPUT, SLOT_OFFSET, type PlacedEdge, type PlacedShape } from "./layout"; import MathText from "./MathText"; import StepFlow, { TOKEN_BASELINE } from "./StepFlow"; import type { Flow, Timeline } from "./Timeline"; import type { Graph, State } from "./types"; // Small graphs keep their size rather than filling the plot const MIN_VIEW_WIDTH = 560; const MIN_VIEW_HEIGHT = 240; // The baseline of an edge's name, relative to the edge const ABOVE_EDGE = -5; function SlotText({ x, y, number }: { x: number; y: number; number: number }) { return ( {formatNumber(number)} ); } // A shape with its name or operator in the middle, its value above and its derivative below function Shape({ shape, current, value, derivative }: { shape: PlacedShape; current: boolean; value: number | undefined; derivative: number | undefined }) { const fill = current ? "fill-marker-soft" : shape.kind === "op" ? "fill-white" : "fill-paper"; return ( {shape.kind === "op" ? ( ) : ( )} {value !== undefined && } {derivative !== undefined && } ); } export default function ComputationGraph({ graph, state, flow, timeline, }: { graph: Graph; state: State | undefined; flow: Flow | null; timeline: Timeline; }) { const layout = useMemo(() => layoutGraph(graph), [graph]); const viewWidth = Math.max(layout.width, MIN_VIEW_WIDTH); const viewHeight = Math.max(layout.height, MIN_VIEW_HEIGHT); const step = state?.step; const backward = step?.phase === "backward"; // The edges into the current node, or the edge from f when the backward pass starts const isActive = (edge: PlacedEdge) => step !== undefined && (backward && step.partials.length === 0 ? edge.to === OUTPUT : edge.to === step.node && edge.to !== OUTPUT); // Drawn last, so they sit on top const edges = [...layout.edges.filter((edge) => !isActive(edge)), ...layout.edges.filter(isActive)]; return ( {edges.map((edge) => { const active = isActive(edge); // The backward pass flows against the edge, so its arrow points back const flipped = active && backward; return ( ); })} {layout.shapes.map((shape) => ( ))} {layout.edges.map((edge) => ( ))} {flow && } ); }