import type { MathNumericType, MathArray, Unit } from '../types.js'; /** * An event function `g(t, y)` whose zero crossings `solveODE` locates. May carry scipy-style * `terminal`/`direction` attributes directly on the function object. * * - `terminal`: `true` (stop at the first crossing), a positive integer (stop after that many * crossings), or omitted/`false` (record every crossing, never stop). * - `direction`: `+1` (trigger only on `−`→`+` crossings), `−1` (only `+`→`−`), or `0`/omitted * (either direction). * * The state `y` is passed in the same shape the forcing function receives it (a `number[]` — a * length-1 array for a scalar ODE). */ interface EventFunction { (t: number, y: number[]): number; terminal?: boolean | number; direction?: number; } /** Object form of an ODE event: the function plus its `terminal`/`direction` attributes. */ interface EventSpec { event: (t: number, y: number[]) => number; terminal?: boolean | number; direction?: number; } /** One event, or an array of events, accepted by the `events` option. */ type ODEEvents = EventFunction | EventSpec | Array; /** * Options for ODE solver */ interface ODEOptions { method?: 'RK23' | 'RK45' | 'Rosenbrock' | 'RODAS' | 'BDF' | 'Radau'; tol?: number; firstStep?: number | Unit; minStep?: number | Unit; maxStep?: number | Unit; minDelta?: number; maxDelta?: number; maxIter?: number; /** * Analytic Jacobian ∂fᵢ/∂yⱼ of the forcing function, used by the stiff methods (`Rosenbrock` * and `RODAS`) in place of the default finite-difference Jacobian. Must return an n×n matrix * (n = state dimension). Ignored by the explicit RK23/RK45 methods. */ jac?: (t: number, y: number[]) => number[][]; /** * Event detection (scipy `solve_ivp`-style). One event function `g(t, y)` or an array of them; * `solveODE` locates each zero crossing between accepted steps and reports it in `tEvents`/ * `yEvents`. A `terminal` event stops the integration at its crossing; `direction` filters the * crossing sign. Requires plain-number state (throws otherwise). See {@link EventFunction}. */ events?: ODEEvents; } /** * Forcing function type for ODE */ type ForcingFunction = (t: MathNumericType, y: MathNumericType | MathArray) => MathNumericType | MathArray; /** * Return a solver for `A·x = b` reused across the 3–6 right-hand sides a single stiff step solves * against the same iteration matrix (W for Rosenbrock, E for RODAS). * * Small systems (n < {@link LU_ROUTE_THRESHOLD}) use the allocation-light inline elimination. * Large systems factor `A` **once** with the matrix `lu()` primitive (per * project-two-decomposition-layers-prefer-matrix) and solve each RHS with `luSolve` — one O(n³) * factorisation instead of the old inline's re-factorisation per RHS. * * Numerics are unchanged on the small path (identical inline code) and, on the large path, the * matrix `lu()` uses the same partial-pivoting strategy and elimination arithmetic, so results * match to rounding (well within the solver's `tol`). The one edge case — a singular iteration * matrix — made the inline solve emit NaN/Inf (division by zero), which fails the embedded error * test and rejects the step (h is then reduced); the matrix `lu()` throws "singular" instead, so * we catch it and return a NaN vector to preserve that step-rejection behaviour. */ export declare function _factorSolver(A: number[][], n: number): (b: number[]) => number[]; /** * Rosenbrock stiff ODE solver — the linearly-implicit ode23s method (Shampine & Reichelt), * L-stable, with an embedded error estimate for adaptive stepping. Unlike the explicit RK23/RK45 * methods, it stays stable on stiff systems (chemical kinetics, circuits, control) where explicit * methods need vanishingly small steps or blow up. One finite-difference Jacobian and one LU * factorisation of `W = I − h·γ·J` per step, reused for its three stage solves. Plain-number * state only (the Jacobian/linear solve are numeric). * * This form omits the `h·γ·∂f/∂t` term, so it is exact-2nd-order for **autonomous** systems * `f(y)`; for time-dependent `f(t, y)` it drops to 1st order (the adaptive stepper still holds * the result to `tol`, just with more steps). The default maxIter is 1e5 for this reason. * * Module-level (not factory-nested) so it can be called directly both by `createSolveODE`'s * `Rosenbrock` method branch and by `stiffODESolver` (`functions/src/typed/numeric.ts`) — a * single shared engine instead of two divergent implementations. */ export declare function rosenbrockSolve(f: ForcingFunction, tspan: unknown[], y0raw: unknown[], options?: ODEOptions): { t: number[]; y: number[][]; }; /** * RODAS stiff ODE solver — Hairer & Wanner's 4th-order, 6-stage, L-stable Rosenbrock method. Like * the 2nd-order `rosenbrockSolve` (ode23s) it is linearly implicit: it forms the iteration matrix * `E = I/(γh) − J` once per step (Jacobian J analytic via `options.jac` or finite-differenced), * LU-factorises it, and solves it against six successive right-hand sides. Being 4th order it * reaches tight tolerances (rtol < 1e-6) in far fewer steps than ode23s, whose 2nd order forces * many small steps there. It retains the `h·d_i·∂f/∂t` term (∂f/∂t finite-differenced once per * step) so it stays 4th order on non-autonomous systems `f(t, y)`. * * Module-level (not factory-nested) for the same reason as `rosenbrockSolve`: pure numeric helpers * with no factory-scope dependency. Plain-number state only (the Jacobian/linear solve are numeric). */ export declare function rodasSolve(f: ForcingFunction, tspan: unknown[], y0raw: unknown[], options?: ODEOptions): { t: number[]; y: number[][]; }; /** * BDF variable-order (1–5) variable-step stiff solver — scipy's default `method='BDF'`. Adaptive * local-error control drives step size and order (1–5) automatically; Newton iteration on the * implicit BDF formula reuses the shared Jacobian machinery and the `(I − c·J)` dense LU solve * (`_factorSolver`) the Rosenbrock/RODAS paths use. Plain-number state only. * * Module-level for the same reason as `rosenbrockSolve`/`rodasSolve`: a pure-numeric engine with no * factory-scope dependency, routed from `createSolveODE`'s `BDF` method branch. */ export declare function bdfSolve(f: ForcingFunction, tspan: unknown[], y0raw: unknown[], options?: ODEOptions): { t: number[]; y: number[][]; }; /** * Radau IIA (order-5, L-stable) stiff solver — scipy's `method='Radau'`. Simplified-Newton on the * real 3n×3n collocation system per step (Jacobian analytic via `options.jac` or finite-differenced, * reused across the step's Newton iterations), third-order embedded error estimate for adaptive * stepping. Plain-number state only. * * Module-level for the same reason as `rosenbrockSolve`/`rodasSolve`/`bdfSolve`. */ export declare function radauSolve(f: ForcingFunction, tspan: unknown[], y0raw: unknown[], options?: ODEOptions): { t: number[]; y: number[][]; }; export declare const createSolveODE: import("../utils/factory.js").FactoryFunction; export {}; //# sourceMappingURL=solveODE.d.ts.map