File size: 2,903 Bytes
b9499ab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import { adjointFormula, formatNumber, tangentFormula } from "./formula";
import { expressionOf } from "./layout";
import MathText from "./MathText";
import type { Graph, Mode, State } from "./types";

// z-10 keeps it above the rows' subscripts, which sit in their own layer
const headerClass = "sticky top-0 z-10 whitespace-nowrap bg-white pb-2 text-xs font-semibold uppercase tracking-widest text-ink-muted";

// Rounded for reading; a cell's title holds the full value
function NumberCell({ value, className }: { value: number | undefined; className: string }) {
  return (
    <td className={`py-1 ${className}`} title={value === undefined ? undefined : String(value)}>
      {value === undefined ? "—" : formatNumber(value)}
    </td>
  );
}

export default function EvaluationTable({
  graph,
  state,
  mode,
  seed,
}: {
  graph: Graph;
  state: State | undefined;
  mode: Mode;
  seed: string;
}) {
  const forward = mode === "forward";
  const symbolName = forward ? "Tangent" : "Adjoint";
  return (
    <div className="max-h-[45%] shrink-0 overflow-auto">
      <table className="w-full border-collapse text-sm">
        <thead>
          <tr>
            <th aria-label="Node" className={`${headerClass} pr-4 text-left`} />
            <th className={`${headerClass} pr-4 text-left`}>Definition</th>
            <th className={`${headerClass} pr-6 text-right`}>Value</th>
            <th aria-label={symbolName} className={`${headerClass} border-l border-grid pl-6 pr-4 text-left`} />
            <th className={`${headerClass} text-left`}>Rule</th>
            <th className={`${headerClass} pl-6 text-left`}>Value</th>
          </tr>
        </thead>
        <tbody className="font-mono">
          {graph.nodes.map((node) => {
            const [derivative, rule] = (forward ? tangentFormula(graph, node, seed) : adjointFormula(graph, node)).split(" = ");
            return (
            <tr
              key={node.id}
              data-row={node.id}
              ref={node.id === state?.step?.node ? (row) => row?.scrollIntoView({ block: "nearest" }) : undefined}
              className={`scroll-mt-8 border-t border-grid ${node.id === state?.step?.node ? "bg-marker-soft" : ""}`}
            >
              <td className={`py-1 pr-4 ${node.id === graph.output ? "font-medium" : ""}`}><MathText text={node.id} /></td>
              <td className="py-1 pr-4 text-ink-muted"><MathText text={expressionOf(node)} /></td>
              <NumberCell value={state?.values[node.id]} className="pr-6 text-right" />
              <td className="border-l border-grid py-1 pl-6 pr-4"><MathText text={derivative} /></td>
              <td className="py-1 text-ink-muted"><MathText text={rule} /></td>
              <NumberCell value={state?.derivatives[node.id]} className="pl-6 text-left" />
            </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}