/ concept-collection / fastandaccurate
Sign in
concept-collection / fastandaccurate
fastandaccurate / src / harness / runner.ts
89 lines · 2.8 KBBlameHistoryRaw
1// Runs one solver at one resolution on one instance and measures it.
2// The timing protocol (see docs/problems/laplace-dirichlet-2d.md): one
3// untimed warmup run absorbs JIT compilation, then `repeats` timed runs
4// whose median is the reported solve time. The warmup itself is timed
5// and reported as the cold time. All timing is MATLAB tic/toc inside the
6// numbl session, so browser and node measure the same thing.
8import { runNumblScript } from "./numblRun";
9import type { Laplace2dInstance } from "../problems/laplace2d/spec";
10import { evalErrors } from "../problems/laplace2d/exact";
12export interface MatlabSources {
13 /** build_problem.m source */
14 buildProblem: string;
15 /** laplace2d_bdata.m source */
16 bdata: string;
17 /** solver.m source of the solver under test */
18 solver: string;
21export interface RunPointRequest {
22 instance: Laplace2dInstance;
23 n: number;
24 /** Timed repeats after the warmup (default 3). */
25 repeats?: number;
26 /** Also evaluate the solution on the visualization grid. */
27 wantGrid?: boolean;
28 sources: MatlabSources;
31export interface RunPoint {
32 n: number;
33 solveSeconds: number;
34 solveSecondsAll: number[];
35 coldSeconds: number;
36 relMax: number;
37 relL2: number;
38 uEval: Float64Array;
39 uGrid: Float64Array | null;
42function numLiteral(x: number): string {
43 if (!Number.isFinite(x)) throw new Error(`bad numeric literal: ${x}`);
44 return String(x);
47export function runPoint(req: RunPointRequest): RunPoint {
48 const { instance, n } = req;
49 const repeats = req.repeats ?? 3;
50 const wantGrid = req.wantGrid ?? false;
51 const main = [
52 "% generated by the fastandaccurate harness",
53 `prob = build_problem(${numLiteral(instance.a)}, ${numLiteral(instance.k)}, ${numLiteral(instance.d)}, ${wantGrid ? 1 : 0});`,
54 `tic; out = solver(prob, ${n}); res_cold = toc;`,
55 `res_times = zeros(${repeats}, 1);`,
56 `for irep = 1:${repeats}`,
57 ` tic; out = solver(prob, ${n}); res_times(irep) = toc;`,
58 "end",
59 "res_ueval = out.uEval;",
60 "res_ugrid = out.uGrid;",
61 "",
62 ].join("\n");
63 const { vars } = runNumblScript(
64 main,
65 {
66 "build_problem.m": req.sources.buildProblem,
67 "laplace2d_bdata.m": req.sources.bdata,
68 "solver.m": req.sources.solver,
69 },
70 ["res_cold", "res_times", "res_ueval", "res_ugrid"]
71 );
72 const times = Array.from(vars.res_times);
73 const sorted = [...times].sort((x, y) => x - y);
74 const median =
75 sorted.length % 2 === 1
76 ? sorted[(sorted.length - 1) / 2]
77 : (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2;
78 const { relMax, relL2 } = evalErrors(instance, vars.res_ueval);
79 return {
80 n,
81 solveSeconds: median,
82 solveSecondsAll: times,
83 coldSeconds: vars.res_cold[0],
84 relMax,
85 relL2,
86 uEval: vars.res_ueval,
87 uGrid: wantGrid ? vars.res_ugrid : null,
88 };
moveopenescclose