1import type { MethodDefinition } from "./methods/types";
3/**
4 * Wall-time estimate for grid-based methods. This is a calibration, not
5 * physics: the plan (cell count, steps) comes from the method's plan function
6 * running in numbl; only the seconds-per-cell-step constant lives here, seeded
7 * from the method definition and refined by each finished run.
8 */
9export class CostModel {
10 private us = new Map<string, number>();
11 private readonly overheadMs = 150;
13 private rate(method: MethodDefinition): number {
14 return this.us.get(method.id) ?? method.usPerCellStep;
15 }
17 estimateMs(method: MethodDefinition, cellSteps: number): number {
18 return (cellSteps * this.rate(method)) / 1000 + this.overheadMs;
19 }
21 /** Blend a measurement in, weighting recent runs more. */
22 observe(method: MethodDefinition, cellSteps: number, wallMs: number): void {
23 if (cellSteps <= 0 || wallMs <= 0) return;
24 const measured = ((wallMs - this.overheadMs) * 1000) / cellSteps;
25 if (!Number.isFinite(measured) || measured <= 0) return;
26 this.us.set(method.id, 0.5 * this.rate(method) + 0.5 * measured);
27 }
28}