[FIX] arima: skip large factors from SVD calls that don't use them#1148
Open
jbbqqf wants to merge 3 commits into
Open
[FIX] arima: skip large factors from SVD calls that don't use them#1148jbbqqf wants to merge 3 commits into
jbbqqf wants to merge 3 commits into
Conversation
`auto_arima_f` calls `np.linalg.svd` twice. Both call sites discard the unused factors, but the default `full_matrices=True` materialises a huge `U` for tall thin xreg matrices (and the rank-check call also spends time computing `U` and `V` only to throw them away). For a 30000x2 xreg this can OOM the process — the report describes a BSOD on Windows. - `arima.py:419` only reads `vt`; pass `full_matrices=False` so `U` shrinks from (m, m) to (m, k). `vt` is shape (k, k) in both modes, so downstream `np.matmul(xreg, vt)` is identical. - `arima.py:1611` only reads the singular values; switch to `compute_uv=False` so `U` and `V` are never formed. Behaviour is bit-equivalent on every input — covered by a direct numerical equivalence test plus the existing AutoARIMA-with-xreg suite. Fixes Nixtla#1006.
|
|
|
|
nasaul
approved these changes
Jun 24, 2026
nasaul
enabled auto-merge (squash)
June 24, 2026 01:22
Contributor
|
Hi @jbbqqf, please sign the CLA so we can merge your PR. Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
auto_arima_fmade twonp.linalg.svdcalls whose unused factors blow up memory on tall thin xreg matrices (the OP reported a BSOD on Windows for a 30000x2 xreg). Passfull_matrices=Falseto the first call (which only consumesVt) andcompute_uv=Falseto the second (which only consumes singular values). Output is bit-equivalent.Fixes #1006 — Memory crash/performance issue within arima.py when using exogenous regressors
Context
Both SVD call sites in
arima.pyalready discard most of whatnp.linalg.svdreturns:arima.py:419(insidemake_arima) does_, _, vt = np.linalg.svd(xreg[~nan_rows]); xreg = xreg @ vt. OnlyVtis used. Withfull_matrices=True(the default),Uis shape(m, m); form = n_observationsthat's a quadratic blow-up.Vthas the same shape(k, k)in both modes (wherek = min(m, n) = ncxregfor tall xreg), so the substitution is mathematically identical for the downstreamxreg @ vt.arima.py:1611(insideauto_arima_f's rank check) does_, sv, _ = np.linalg.svd(X); if sv.min() / sv.sum() < eps: raise. Only the singular values are read.compute_uv=Falsereturns just the SVs and skips computingUandVentirely.The OP cited the exact NumPy doc references and proposed this minimal change. I verified the equivalence numerically (see new test
test_svd_equivalence_for_thin_and_no_uv) and ran the full ARIMA test suite to confirm no regression.Changes
python/statsforecast/arima.py(line 419) —np.linalg.svd(..., full_matrices=False). Inline comment explains why the substitution is exact for the downstream usage.python/statsforecast/arima.py(line 1611) —np.linalg.svd(X, compute_uv=False). Inline comment ties the change to the rank check that's the only consumer.tests/test_arima.py— two regressions:test_svd_equivalence_for_thin_and_no_uvdirectly exercises the report's 30000x2 shape and asserts singular values match exactly andVtrows agree up to per-row sign (which is sign-invariant underxreg @ vt).test_auto_arima_with_multicolumn_xreg_equivalent_to_full_svdrunsauto_arima_fwith a 3-column xreg through the path that actually triggersorig_xreg=Falseand the SVD call, asserting the fitted coefficients are finite and contain the expectedex_1..ex_3keys.Reproduce BEFORE/AFTER yourself (copy-paste)
What I ran locally
pytest tests/test_arima.py -q --no-cov→ 22/22 passed (was 20; 2 added).np.linalg.svd(X)andnp.linalg.svd(X, full_matrices=False) / compute_uv=Falseagree to machine precision on a 30000x2 input — the exact shape from the report.Edge cases tested
test_svd_equivalence_for_thin_and_no_uvtest_auto_arima_with_multicolumn_xreg_equivalent_to_full_svdorig_xreg=Truepath)test_auto_arima_with_trendtest_AutoARIMA_edge_cases(constant series fit)Risk / blast radius
The thin-SVD substitution is a documented NumPy-API equivalence. Both call sites discard the components that
full_matrices=Falseandcompute_uv=Falseskip, so the substitution is exact on the consumer side. No public API change.Release note
PR drafted with assistance from Claude Code. The change matches the proposal in #1006 verbatim. The reproducer block above was used during development; it is the same one a reviewer can paste verbatim.