nhamid289's picture
Deploy autodiff ff35e9c
b9499ab verified
Raw History Blame Contribute Delete
4.19 kB
import { AppLayout, Divider, Dropdown, InputField, InputSection, SegmentedControl } from "@elvis/ui";
import ComputationGraph from "./ComputationGraph";
import EvaluationTable from "./EvaluationTable";
import MathText from "./MathText";
import RunResult from "./RunResult";
import TimelineControls from "./TimelineControls";
import type { Mode, RunSettings } from "./types";
import useAutodiff from "./useAutodiff";
import useRunResults from "./useRunResults";
const MODE_OPTIONS: { value: Mode; label: string }[] = [
{ value: "forward", label: "Forward" },
{ value: "reverse", label: "Reverse" },
];
function runCaption(run: RunSettings): string {
const values = Object.entries(run.inputs).map(([name, value]) => `${name} = ${value}`);
return `${values.join(", ")}${run.mode === "forward" ? `, differentiating by ${run.seed}` : ""}`;
}
export default function App() {
const app = useAutodiff();
const prefix = `f(${app.graph?.inputs.join(", ") ?? "x"}) =`;
const { flow, state } = app.snapshot;
const results = useRunResults(app.graph, app.snapshot);
// Labels follow the run on screen, not a control just changed
const shownMode = app.run?.mode ?? app.mode;
const shownSeed = app.run?.mode === "forward" ? app.run.seed : app.seed;
return (
<AppLayout
title="Automatic Differentiation"
panel={
<>
<InputSection label="Function">
<InputField
label="Function"
hideLabel
prefix={prefix}
value={app.expression}
onChange={app.setExpression}
error={app.functionError}
mono
rows={2}
/>
</InputSection>
{app.graph && (
<>
<Divider />
<InputSection label="Inputs">
<div className="grid grid-cols-2 gap-2">
{app.inputs.map((input) => (
<InputField
key={input.name}
label={`Value of ${input.name}`}
hideLabel
prefix={`${input.name} =`}
value={input.text}
onChange={(text) => app.setInput(input.name, text)}
error={input.value === null ? "Enter a number." : null}
mono
/>
))}
</div>
{app.runError && <p className="font-semibold text-red-600">{app.runError}</p>}
</InputSection>
<Divider />
<InputSection label="Mode">
<SegmentedControl label="Mode" options={MODE_OPTIONS} value={app.mode} onChange={app.setMode} />
{app.mode === "forward" && app.graph.inputs.length > 1 && (
<Dropdown label="Differentiate by" options={app.graph.inputs} activeOption={app.seed} onChange={app.setSeed} />
)}
</InputSection>
<Divider />
<RunResult graph={app.graph} results={results} mode={shownMode} />
</>
)}
</>
}
footer={
<>
{app.status === "loading" && (
<p className="text-sm text-ink-muted">Loading Python… actions will run once it is ready.</p>
)}
{app.status === "failed" && <p className="font-semibold text-red-600">Python failed to load.</p>}
<TimelineControls timeline={app.timeline} snapshot={app.snapshot} animated={app.animated} onAnimatedChange={app.setAnimated} />
</>
}
>
{app.graph && (
<div className="flex min-h-0 flex-1 flex-col gap-4">
<ComputationGraph graph={app.graph} state={state} flow={flow} timeline={app.timeline} />
<Divider />
<EvaluationTable graph={app.graph} state={state} mode={shownMode} seed={shownSeed} />
{app.run && (
<p className="text-sm text-ink-muted">
{shownMode === "forward" ? "Forward" : "Reverse"} mode at <span className="font-mono"><MathText text={runCaption(app.run)} /></span>
</p>
)}
</div>
)}
</AppLayout>
);
}