From 09dd7f9bacb91ee00c1ec377b87a523914a69746 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 15 Jun 2026 15:17:23 +0000 Subject: [PATCH 1/2] Pre-allocate nns_arma recursive forecast buffer Replace the per-step np.concatenate in the nns_arma recursive forecast loop with a pre-allocated buffer and a length pointer. The previous approach reallocated and copied the entire series on every horizon step (O(N^2) over the horizon); writing into a fixed buffer and passing a view of the populated prefix to the helpers is O(1) per step and leaves the forecast math unchanged. --- src/nns/arma.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/nns/arma.py b/src/nns/arma.py index 88176072..53b29051 100644 --- a/src/nns/arma.py +++ b/src/nns/arma.py @@ -433,9 +433,18 @@ def _finish( ) return _finish(estimates) - current = values + # Pre-allocate the full history-plus-horizon buffer once and fill it by + # index. Appending the recursive estimate via np.concatenate at every step + # reallocates and copies the entire series each iteration, which is O(N^2) + # over a long horizon; writing into a fixed buffer and advancing a length + # pointer is O(1) per step. The helpers receive a view of the populated + # prefix, so the math is identical to the growing-array version. + buffer = np.empty(values.size + horizon, dtype=np.float64) + buffer[: values.size] = values + current_len = values.size lin_regression_estimates = np.array([], dtype=np.float64) for index in range(horizon): + current = buffer[:current_len] if dynamic: lags, lag_weights = _resolve_lags_and_weights( current, @@ -496,7 +505,8 @@ def _finish( estimate = 0.0 estimates[index] = estimate - current = np.concatenate((current, np.array([estimate], dtype=np.float64))) + buffer[current_len] = estimate + current_len += 1 lin_resid = 0.0 if pred_int is not None and method_l != "means" and lin_regression_estimates.size: From 18353831cbd2694f182a51f126ead325a85005b6 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 15 Jun 2026 15:17:58 +0000 Subject: [PATCH 2/2] Sync uv.lock ovvo-nns version to 1.0.4 The editable package version recorded in the lockfile was stale (1.0.0a0); uv refreshed it to match pyproject.toml during a local test run. --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index b8da99c9..64535ad1 100644 --- a/uv.lock +++ b/uv.lock @@ -718,7 +718,7 @@ wheels = [ [[package]] name = "ovvo-nns" -version = "1.0.0a0" +version = "1.0.4" source = { editable = "." } dependencies = [ { name = "matplotlib" },