numbl 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,11 +54,20 @@ export interface BuiltinProfileBreakdown {
54
54
  /** Calls from JIT-compiled code (ib_* helpers). */
55
55
  jit: BuiltinProfileEntry;
56
56
  }
57
+ export interface HotLoopEntry {
58
+ file: string;
59
+ line: number;
60
+ kind: "for" | "while";
61
+ iterations: number;
62
+ callCount: number;
63
+ totalTimeMs: number;
64
+ }
57
65
  export interface ProfileData {
58
66
  executionTimeMs: number;
59
67
  jitCompileTimeMs: number;
60
68
  builtins: Record<string, BuiltinProfileBreakdown>;
61
69
  dispatches: Record<string, BuiltinProfileEntry>;
70
+ hotLoops: HotLoopEntry[];
62
71
  }
63
72
  export interface ExecResult {
64
73
  output: string[];
@@ -39,6 +39,10 @@ export type ResolvedTarget = {
39
39
  kind: "workspaceFunction";
40
40
  name: string;
41
41
  argTypes: ItemType[];
42
+ } | {
43
+ kind: "jsUserFunction";
44
+ name: string;
45
+ argTypes: ItemType[];
42
46
  } | {
43
47
  kind: "workspaceClassConstructor";
44
48
  className: string;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Core GMRES (Generalized Minimum Residual) algorithm.
3
+ *
4
+ * Callback-based interface so the same code handles both dense matrices
5
+ * (dispatched through the LAPACK bridge) and function-handle arguments
6
+ * (dispatched through the runtime).
7
+ */
8
+ export interface GmresResult {
9
+ x: Float64Array;
10
+ flag: number;
11
+ relres: number;
12
+ iter: [number, number];
13
+ resvec: Float64Array;
14
+ }
15
+ export type MatvecFn = (x: Float64Array) => Float64Array;
16
+ export type PrecSolveFn = (r: Float64Array) => Float64Array;
17
+ /**
18
+ * Restarted GMRES with left preconditioning and Givens rotations.
19
+ *
20
+ * @param matvec Computes A*x
21
+ * @param precSolve Computes M\x (or null for no preconditioning)
22
+ * @param b Right-hand side (length n)
23
+ * @param n System dimension
24
+ * @param restart Inner iteration count (use n for no restart)
25
+ * @param tol Convergence tolerance on relative preconditioned residual
26
+ * @param maxit Maximum number of outer iterations
27
+ * @param x0 Initial guess (or null for zeros)
28
+ */
29
+ export declare function gmresCore(matvec: MatvecFn, precSolve: PrecSolveFn | null, b: Float64Array, n: number, restart: number, tol: number, maxit: number, x0: Float64Array | null): GmresResult;
30
+ export interface ComplexVec {
31
+ re: Float64Array;
32
+ im: Float64Array;
33
+ }
34
+ export interface GmresComplexResult {
35
+ x: ComplexVec;
36
+ flag: number;
37
+ relres: number;
38
+ iter: [number, number];
39
+ resvec: Float64Array;
40
+ }
41
+ export type ComplexMatvecFn = (x: ComplexVec) => ComplexVec;
42
+ export type ComplexPrecSolveFn = (r: ComplexVec) => ComplexVec;
43
+ /** Restarted GMRES for complex systems. */
44
+ export declare function gmresCoreComplex(matvec: ComplexMatvecFn, precSolve: ComplexPrecSolveFn | null, b: ComplexVec, n: number, restart: number, tol: number, maxit: number, x0: ComplexVec | null): GmresComplexResult;
45
+ /** Complex LU solve in-place (split re/im). LU and ipiv from zgetrf-style factorization. */
46
+ export declare function complexLuSolveInPlace(n: number, LURe: Float64Array, LUIm: Float64Array, ipiv: Int32Array, rhsRe: Float64Array, rhsIm: Float64Array): void;
47
+ /**
48
+ * Apply row permutation + forward/back substitution to solve a pre-factored
49
+ * LU system in-place. LU and ipiv come from dgetrf (1-based pivots).
50
+ */
51
+ export declare function luSolveInPlace(n: number, LU: Float64Array, ipiv: Int32Array, rhs: Float64Array): void;
@@ -119,6 +119,9 @@ export declare class Interpreter {
119
119
  interpretWorkspaceFunction: (target: Extract<ResolvedTarget, {
120
120
  kind: "workspaceFunction";
121
121
  }>, args: unknown[], nargout: number) => unknown;
122
+ interpretJsUserFunction: (target: Extract<ResolvedTarget, {
123
+ kind: "jsUserFunction";
124
+ }>, args: unknown[], nargout: number) => unknown;
122
125
  interpretClassMethod: (target: Extract<ResolvedTarget, {
123
126
  kind: "classMethod";
124
127
  }>, args: unknown[], nargout: number) => unknown;
@@ -9,6 +9,9 @@ import { Environment, type FunctionDef } from "./types.js";
9
9
  import type { Interpreter } from "./interpreter.js";
10
10
  export declare function callFunction(this: Interpreter, name: string, args: unknown[], nargout: number): unknown;
11
11
  export declare function interpretTarget(this: Interpreter, target: ResolvedTarget, args: unknown[], nargout: number): unknown;
12
+ export declare function interpretJsUserFunction(this: Interpreter, target: Extract<ResolvedTarget, {
13
+ kind: "jsUserFunction";
14
+ }>, args: unknown[], nargout: number): unknown;
12
15
  export declare function interpretLocalFunction(this: Interpreter, target: Extract<ResolvedTarget, {
13
16
  kind: "localFunction";
14
17
  }>, args: unknown[], nargout: number): unknown;
@@ -12,9 +12,14 @@ export interface InterpreterContext {
12
12
  evalInLocalScope: (codeArg: unknown, fileName?: string) => unknown;
13
13
  callFunction: (name: string, args: unknown[], nargout: number) => unknown;
14
14
  rt: Runtime;
15
- /** Resolve a workspace function or class name to its source file path,
16
- * or undefined if no workspace file provides that name. */
17
- lookupWorkspaceFile: (name: string) => string | undefined;
15
+ /** Resolve a workspace function or class name to its source file,
16
+ * or undefined if no workspace file provides that name.
17
+ * `kind` distinguishes a regular .m function from a .numbl.js
18
+ * user function (treated as a MEX-equivalent) or a class file. */
19
+ lookupWorkspaceFile: (name: string) => {
20
+ path: string;
21
+ kind: "function" | "jsfunction" | "class";
22
+ } | undefined;
18
23
  }
19
24
  export declare const FALL_THROUGH: unique symbol;
20
25
  export type InterpreterSpecialBuiltinHandler = (ctx: InterpreterContext, args: unknown[], nargout: number) => unknown | typeof FALL_THROUGH;
@@ -3,3 +3,12 @@
3
3
  * Passed as `$h` to generated functions.
4
4
  */
5
5
  export declare const jitHelpers: Record<string, unknown>;
6
+ import type { IBuiltin } from "../builtins/index.js";
7
+ /**
8
+ * Build a per-runtime jitHelpers map for an execution that has .numbl.js
9
+ * user functions. The result is a clone of the global jitHelpers extended
10
+ * with `ib_<name>` entries (single-output fast path) for each js user
11
+ * function and an overridden `ibcall` (multi-output) that consults the
12
+ * js user function map first before falling back to the global registry.
13
+ */
14
+ export declare function buildPerRuntimeJitHelpers(jsUserFunctions: ReadonlyMap<string, IBuiltin>): Record<string, any>;
@@ -1,25 +1,40 @@
1
1
  /**
2
- * Loader for .js user functions.
2
+ * Loader for .numbl.js user functions.
3
3
  *
4
- * Evaluates .js files that define IBuiltins via register({ resolve, jitEmit? }).
4
+ * Evaluates .numbl.js files that define IBuiltins via
5
+ * register({ resolve, jitEmit? }).
5
6
  * Supports optional WASM and native shared library bindings via directives:
6
7
  * // wasm: <name>
7
8
  * // native: <name>
9
+ *
10
+ * The `.numbl.js` extension distinguishes numbl user functions from
11
+ * unrelated `.js` files (config files, source maps, etc.) so that they can
12
+ * be auto-discovered from the current working directory like `.m` files.
8
13
  */
9
14
  import type { WorkspaceFile, NativeBridge } from "./workspace/index.js";
10
15
  import type { IBuiltin } from "./interpreter/builtins/types.js";
16
+ /** A loaded JS user function ready for registration in the workspace. */
17
+ export interface LoadedJsUserFunction {
18
+ name: string;
19
+ fileName: string;
20
+ builtin: IBuiltin;
21
+ }
22
+ /** Returns true if the file is a numbl JS user function file (`*.numbl.js`). */
23
+ export declare function isNumblJsFile(fileName: string): boolean;
11
24
  /**
12
- * Load .js user function files and return them as IBuiltin objects.
25
+ * Load .numbl.js user function files and return them as LoadedJsUserFunction
26
+ * records. Each loaded record carries the function name, source file name,
27
+ * and the IBuiltin object built from the file's `register()` call.
13
28
  *
14
- * Each .js file calls register({ resolve, jitEmit? }) to define an IBuiltin.
15
- * resolve(argTypes, nargout) returns { outputTypes, apply } or null.
29
+ * Each .numbl.js file calls register({ resolve, jitEmit? }) to define an
30
+ * IBuiltin. resolve(argTypes, nargout) returns { outputTypes, apply } or null.
16
31
  *
17
- * A .js file can specify bindings via directives at the top of the file:
32
+ * A .numbl.js file can specify bindings via directives at the top of the file:
18
33
  * // wasm: <name> — load a WASM module (looked up by name in wasmFiles)
19
- * // native: <name> — load a native shared library (resolved relative to .js file)
34
+ * // native: <name> — load a native shared library (resolved relative to file)
20
35
  *
21
36
  * Files whose basename starts with `_` are library files. They must not call
22
- * register() and instead export values via `return`. Other .js files can import
23
- * them with `importJS("_name")`.
37
+ * register() and instead export values via `return`. Other .numbl.js files
38
+ * can import them with `importJS("_name")`.
24
39
  */
25
- export declare function loadJsUserFunctions(jsFiles: WorkspaceFile[], wasmFiles?: WorkspaceFile[], nativeBridge?: NativeBridge): IBuiltin[];
40
+ export declare function loadJsUserFunctions(jsFiles: WorkspaceFile[], wasmFiles?: WorkspaceFile[], nativeBridge?: NativeBridge): LoadedJsUserFunction[];
@@ -5,6 +5,7 @@
5
5
  * building, and on-demand context creation for workspace/class files.
6
6
  */
7
7
  import { type AbstractSyntaxTree, type Stmt } from "../parser/index.js";
8
+ import type { IBuiltin } from "../interpreter/builtins/index.js";
8
9
  import type { WorkspaceFile } from "../../numbl-core/workspace/index.js";
9
10
  import { type ClassInfo } from "./classInfo.js";
10
11
  import { type ExternalAccessDirectives } from "../externalAccessDirective.js";
@@ -17,6 +18,11 @@ interface WorkspaceRegistry {
17
18
  fileName: string;
18
19
  source: string;
19
20
  }>;
21
+ /** JS user functions (.numbl.js): functionName → { fileName, builtin } */
22
+ jsUserFunctionsByName: Map<string, {
23
+ fileName: string;
24
+ builtin: IBuiltin;
25
+ }>;
20
26
  /** Per-workspace-file lowering contexts (created on demand) */
21
27
  fileContexts: Map<string, LoweringContext>;
22
28
  /** Workspace classes: qualifiedName → ClassInfo */
@@ -138,6 +144,11 @@ export declare class LoweringContext {
138
144
  isWorkspaceFunction(name: string): boolean;
139
145
  /** Clear workspace-level registrations so they can be rebuilt after addpath/rmpath. */
140
146
  clearWorkspaceRegistrations(): void;
147
+ /**
148
+ * Register a JS user function (.numbl.js) in the workspace registry.
149
+ * Uses first-wins semantics so search-path priority is honored.
150
+ */
151
+ registerJsUserFunction(funcName: string, fileName: string, builtin: IBuiltin): void;
141
152
  /**
142
153
  * Get the effective directory for this context's file, used for
143
154
  * private function resolution. If the file is inside a private/ folder,
@@ -200,7 +211,7 @@ export declare class LoweringContext {
200
211
  * Should be called once after registerWorkspaceFiles() and registerLocalFunctionAST().
201
212
  * Parses all workspace files eagerly to discover subfunctions.
202
213
  */
203
- buildFunctionIndex(jsUserFunctionNames?: string[]): FunctionIndex;
214
+ buildFunctionIndex(): FunctionIndex;
204
215
  /** Get the function index (must call buildFunctionIndex() first on any context sharing the same registry). */
205
216
  get functionIndex(): FunctionIndex;
206
217
  }
@@ -18,7 +18,7 @@
18
18
  * Expected native addon version. Bump this whenever the C++ addon API changes
19
19
  * (must match ADDON_VERSION in numbl_addon.cpp).
20
20
  */
21
- export declare const NATIVE_ADDON_EXPECTED_VERSION = 1;
21
+ export declare const NATIVE_ADDON_EXPECTED_VERSION = 2;
22
22
  export interface LapackBridge {
23
23
  /** Returns the native addon's version number. */
24
24
  addonVersion?(): number;
@@ -395,6 +395,38 @@ export interface LapackBridge {
395
395
  elemwise?(a: Float64Array, b: Float64Array, op: number): Float64Array;
396
396
  /** Scalar-tensor element-wise op. scalarOnLeft: true → scalar op arr[i], false → arr[i] op scalar */
397
397
  elemwiseScalar?(scalar: number, arr: Float64Array, op: number, scalarOnLeft: boolean): Float64Array;
398
+ /**
399
+ * Restarted GMRES solver for A*x = b (real, dense matrices only).
400
+ * Uses BLAS dgemv for matvec and LAPACK dgetrf+dgetrs for preconditioner.
401
+ * @param A Column-major Float64Array of length n*n (not modified).
402
+ * @param n System dimension.
403
+ * @param b Right-hand side Float64Array of length n.
404
+ * @param restart Inner iterations per restart cycle (use n for no restart).
405
+ * @param tol Convergence tolerance on relative preconditioned residual.
406
+ * @param maxit Maximum number of outer iterations.
407
+ * @param M1 Preconditioner factor 1 (n×n column-major), or null.
408
+ * @param M2 Preconditioner factor 2 (n×n column-major), or null.
409
+ * @param x0 Initial guess (length n), or null for zeros.
410
+ * @returns Object with x, flag, relres, iter (Int32Array[2]), resvec.
411
+ */
412
+ gmres?(A: Float64Array, n: number, b: Float64Array, restart: number, tol: number, maxit: number, M1: Float64Array | null, M2: Float64Array | null, x0: Float64Array | null): {
413
+ x: Float64Array;
414
+ flag: number;
415
+ relres: number;
416
+ iter: Int32Array;
417
+ resvec: Float64Array;
418
+ };
419
+ /**
420
+ * Complex restarted GMRES solver for A*x = b (split real/imag dense matrices).
421
+ */
422
+ gmresComplex?(ARe: Float64Array, AIm: Float64Array, n: number, bRe: Float64Array, bIm: Float64Array, restart: number, tol: number, maxit: number, M1Re: Float64Array | null, M1Im: Float64Array | null, M2Re: Float64Array | null, M2Im: Float64Array | null, x0Re: Float64Array | null, x0Im: Float64Array | null): {
423
+ xRe: Float64Array;
424
+ xIm: Float64Array;
425
+ flag: number;
426
+ relres: number;
427
+ iter: Int32Array;
428
+ resvec: Float64Array;
429
+ };
398
430
  /** Element-wise binary op on complex Float64Arrays. op: 0=add, 1=sub, 2=mul, 3=div */
399
431
  elemwiseComplex?(aRe: Float64Array, aIm: Float64Array | null, bRe: Float64Array, bIm: Float64Array | null, op: number): {
400
432
  re: Float64Array;
@@ -46,6 +46,8 @@ export declare class RuntimeError extends Error {
46
46
  * Format error with location and snippet context.
47
47
  */
48
48
  toString(): string;
49
+ /** Format error with MATLAB-style call stack. */
50
+ private _formatWithCallStack;
49
51
  /** Look up a single trimmed source line from fileSources. */
50
52
  private _getSourceLine;
51
53
  }
@@ -5,8 +5,8 @@
5
5
  * plot(X1,Y1,LineSpec1,...), and Name-Value pairs like 'Color','r','LineWidth',2.
6
6
  */
7
7
  import { type RuntimeValue } from "./types.js";
8
- export type { PlotTrace, Plot3Trace, SurfTrace, ImagescTrace, ContourTrace, BarTrace, Bar3Trace, ErrorBarTrace, BoxTrace, PieTrace, HeatmapTrace, } from "../../graphics/types.js";
9
- import type { PlotTrace, Plot3Trace, SurfTrace, ImagescTrace, ContourTrace, BarTrace, Bar3Trace, ErrorBarTrace, BoxTrace, PieTrace, HeatmapTrace } from "../../graphics/types.js";
8
+ export type { PlotTrace, Plot3Trace, SurfTrace, ImagescTrace, PcolorTrace, ContourTrace, BarTrace, Bar3Trace, ErrorBarTrace, BoxTrace, PieTrace, HeatmapTrace, } from "../../graphics/types.js";
9
+ import type { PlotTrace, Plot3Trace, SurfTrace, ImagescTrace, PcolorTrace, ContourTrace, BarTrace, Bar3Trace, ErrorBarTrace, BoxTrace, PieTrace, HeatmapTrace } from "../../graphics/types.js";
10
10
  export interface ParsedLineSpec {
11
11
  color?: string;
12
12
  lineStyle?: string;
@@ -35,6 +35,15 @@ export declare function parsePlot3Args(args: RuntimeValue[]): Plot3Trace[];
35
35
  * surf(..., Name, Value) — name-value pairs
36
36
  */
37
37
  export declare function parseSurfArgs(args: RuntimeValue[]): SurfTrace;
38
+ /**
39
+ * Parse pcolor() arguments.
40
+ *
41
+ * Supported forms:
42
+ * pcolor(C) — C is m×n, X = 1:n, Y = 1:m
43
+ * pcolor(X, Y, C) — X, Y, C are m×n matrices (or X is 1×n / Y is m×1)
44
+ * pcolor(..., Name, Value) — name-value pairs (EdgeColor, FaceAlpha)
45
+ */
46
+ export declare function parsePcolorArgs(args: RuntimeValue[]): PcolorTrace;
38
47
  /**
39
48
  * Parse scatter() arguments.
40
49
  *
@@ -80,6 +80,7 @@ export declare class Runtime {
80
80
  system?: SystemAdapter;
81
81
  builtins: Record<string, (nargout: number, args: unknown[]) => unknown>;
82
82
  customBuiltins: Record<string, (nargout: number, args: unknown[]) => unknown>;
83
+ jitHelpers: Record<string, any> | null;
83
84
  compileSpecialized: ((name: string, argTypes: ItemType[], callSite: CallSite) => ((...args: any[]) => any) | null) | null;
84
85
  evalLocalCallback: ((code: string, initialVars: Record<string, RuntimeValue>, onOutput: (text: string) => void, fileName?: string) => {
85
86
  returnValue: unknown;
@@ -94,6 +95,14 @@ export declare class Runtime {
94
95
  private profileStack;
95
96
  private profileAccum;
96
97
  private profileCounts;
98
+ hotLoops: Map<string, {
99
+ file: string;
100
+ line: number;
101
+ kind: "for" | "while";
102
+ iterations: number;
103
+ callCount: number;
104
+ totalTimeMs: number;
105
+ }>;
97
106
  constructor(options: ExecOptions, initialVariableValues?: Record<string, RuntimeValue> | undefined);
98
107
  private initBuiltins;
99
108
  profileEnter(key: string): void;
@@ -284,6 +293,7 @@ export declare class Runtime {
284
293
  surf_call(args: RuntimeValue[]): void;
285
294
  scatter_call(args: RuntimeValue[]): void;
286
295
  imagesc_call(args: RuntimeValue[]): void;
296
+ pcolor_call(args: RuntimeValue[]): void;
287
297
  contour_call(args: RuntimeValue[], filled: boolean): void;
288
298
  mesh_call(args: RuntimeValue[]): void;
289
299
  bar_call(args: RuntimeValue[]): void;
@@ -50,18 +50,24 @@ export declare function plotInstr(plotInstructions: PlotInstruction[], instr: {
50
50
  } | {
51
51
  type: "set_colorbar";
52
52
  value: unknown;
53
+ location?: unknown;
53
54
  } | {
54
55
  type: "set_colormap";
55
56
  name: unknown;
57
+ data?: number[][];
56
58
  } | {
57
59
  type: "set_axis";
58
60
  value: unknown;
61
+ } | {
62
+ type: "set_caxis";
63
+ limits: [number, number];
59
64
  }): void;
60
65
  export declare function viewCall(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
61
66
  export declare function plotCall(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
62
67
  export declare function plot3Call(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
63
68
  export declare function surfCall(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
64
69
  export declare function imagescCall(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
70
+ export declare function pcolorCall(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
65
71
  export declare function contourCall(plotInstructions: PlotInstruction[], args: RuntimeValue[], filled: boolean): void;
66
72
  export declare function meshCall(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
67
73
  export declare function scatterCall(plotInstructions: PlotInstruction[], args: RuntimeValue[]): void;
@@ -1,2 +1,2 @@
1
1
  /** Numbl version, used for JIT disk cache invalidation. */
2
- export declare const NUMBL_VERSION = "0.1.4";
2
+ export declare const NUMBL_VERSION = "0.1.6";