# Feature: Reduce Per-Step Allocation ## Overview Remove the heap allocations every accepted step performs. ## Why This Feature Matters Each call to `step()` allocates a `Vec` for the stage values (`vec![SVector::zeros(); STAGES]`) and a second `Vec` for the dense output coefficients. `Problem::solve` then wraps the latter in a `RefCell` and pushes it onto a growing vector. That is two allocations per step against roughly 150 ns of arithmetic. Measured 2026-09-29 on the harmonic oscillator at 1e-10, where the right-hand side is two flops so the timing is almost entirely integrator overhead: | Method | Steps | Total | Per step | |--------|-------|-------|----------| | BS3 | 13,927 | 1.58 ms | 113 ns | | DP45 | 722 | 112 us | 155 ns | | Vern7 | 124 | 26.6 us | 215 ns | `BS3::step` in isolation is 44.6 ns for four stages. The gain is largest exactly where it is least important: problems with cheap right-hand sides. For the orbit propagation this crate is aimed at, a spherical-harmonic gravity evaluation dominates and per-step overhead is rounding error. Worth doing, not worth doing first. ## Dependencies None. `STAGES` is already an associated const, so the stage array can be a fixed-size array rather than a `Vec`. ## Implementation Approach (To be detailed.) Sketch: stage storage becomes `[SVector; STAGES]` if const generics allow it at the trait level, or a caller-supplied scratch buffer threaded through `step()`. Dense coefficients want a pre-reserved buffer sized from an estimate of the step count, or a flat `Vec>` indexed by stride rather than a `Vec` of `Vec`s. Note the interaction with the `RefCell` in `Solution::dense`: it exists so Vern7 can append its lazily computed extra stages. A flat buffer has to keep that possible. ## Implementation Tasks - [ ] Core implementation - [ ] Integration with existing code - [ ] Testing - [ ] Benchmarking ## Testing Requirements Numerics must not change. The existing benches plus a step-count and final-state comparison against the previous release are sufficient: results should be bit-identical. ## References 1. Julia implementation: OrdinaryDiffEq.jl, which caches stage storage in the integrator rather than allocating per step ## Complexity Estimate **Effort**: Medium **Risk**: Low - no change to the numerics, so the test suite is a strong guard ## Success Criteria - [ ] No allocation in the steady-state step loop - [ ] Bit-identical results against the previous release - [ ] Measurable improvement on the cheap-RHS benchmarks ## Future Enhancements Supersedes the "Optimize memory allocation in step method" bullet under Future Enhancements in `01-bs3-method.md`.