// Runs one solver at one resolution on one instance and measures it. // The timing protocol (see docs/problems/laplace-dirichlet-2d.md): one // untimed warmup run absorbs JIT compilation, then `repeats` timed runs // whose median is the reported solve time. The warmup itself is timed // and reported as the cold time. All timing is MATLAB tic/toc inside the // numbl session, so browser and node measure the same thing. import { runNumblScript } from "./numblRun"; import type { Laplace2dInstance } from "../problems/laplace2d/spec"; import { evalErrors } from "../problems/laplace2d/exact"; export interface MatlabSources { /** build_problem.m source */ buildProblem: string; /** laplace2d_bdata.m source */ bdata: string; /** solver.m source of the solver under test */ solver: string; } export interface RunPointRequest { instance: Laplace2dInstance; n: number; /** Timed repeats after the warmup (default 3). */ repeats?: number; /** Also evaluate the solution on the visualization grid. */ wantGrid?: boolean; sources: MatlabSources; } export interface RunPoint { n: number; solveSeconds: number; solveSecondsAll: number[]; coldSeconds: number; relMax: number; relL2: number; uEval: Float64Array; uGrid: Float64Array | null; } function numLiteral(x: number): string { if (!Number.isFinite(x)) throw new Error(`bad numeric literal: ${x}`); return String(x); } export function runPoint(req: RunPointRequest): RunPoint { const { instance, n } = req; const repeats = req.repeats ?? 3; const wantGrid = req.wantGrid ?? false; const main = [ "% generated by the fastandaccurate harness", `prob = build_problem(${numLiteral(instance.a)}, ${numLiteral(instance.k)}, ${numLiteral(instance.d)}, ${wantGrid ? 1 : 0});`, `tic; out = solver(prob, ${n}); res_cold = toc;`, `res_times = zeros(${repeats}, 1);`, `for irep = 1:${repeats}`, ` tic; out = solver(prob, ${n}); res_times(irep) = toc;`, "end", "res_ueval = out.uEval;", "res_ugrid = out.uGrid;", "", ].join("\n"); const { vars } = runNumblScript( main, { "build_problem.m": req.sources.buildProblem, "laplace2d_bdata.m": req.sources.bdata, "solver.m": req.sources.solver, }, ["res_cold", "res_times", "res_ueval", "res_ugrid"] ); const times = Array.from(vars.res_times); const sorted = [...times].sort((x, y) => x - y); const median = sorted.length % 2 === 1 ? sorted[(sorted.length - 1) / 2] : (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2; const { relMax, relL2 } = evalErrors(instance, vars.res_ueval); return { n, solveSeconds: median, solveSecondsAll: times, coldSeconds: vars.res_cold[0], relMax, relL2, uEval: vars.res_ueval, uGrid: wantGrid ? vars.res_ugrid : null, }; }