Repository navigation
gpuGranger: every pair in double by the Frisch-Waugh route; NA where unresolvable - #52
Merged
Merged
Conversation
… = 0, where unresolvable The old kernels fitted one regression per pair by single-pass Gram-Schmidt in the requested precision (single by default) on uncentred data, with memory growing as the square of the number of series, and set F = 0, p = 1 for any pair whose arithmetic produced a non-finite value: a collinear design, a constant series, a cause identical to the effect all came back as 'no causality'. Single precision was off by more than 10 percent on long random walks. Now, following widestats' granger: each effect's restricted design is orthonormalised once (Cholesky-QR2 on the GPU, Householder on the host above condition 1e7); every cause's test against it comes from the products C = Q'L, L'e, Q'e as G = L'L - C'C, g = L'e - C'(Q'e), checked pair by pair (cond(G) / left * RSS_r / RSS_u below 1e6) and recomputed from the explicit residual lags where the cancellation cannot be trusted; all in double, series centred and scaled. A pair the effect's design (cond > 1e10), the cause's G (> 1e12) or the fraction left (< 1e-20) rules out is NA with a warning; a series on itself or a constant series NA without one. lag checked (1 to 16); the precision argument is accepted but ignored, as documented. Verified on an RTX 2080 Ti and an A5500: lm() to 1e-7 on walks, drifting walks and trends at lag 1 and 3 (n = 5,000; 50 series x 20,000 across two tiles), near-copies to 1e-6 (lm with tol 1e-12), I(3) at lag 5 flagged or within 1e-3; against widestats on the same panels, max relative difference 8e-11 (walks, drift, white noise) and 2e-6 (I(2), lag 3, both on the explicit path), NaN sets identical. Review fixes: a NaN-propagating minimum for left, device buffers freed before the error check, lag validated before coercion. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Oct 20, 2026
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.
First of the backports from widestats (its reviewed and verified
granger).The bug.
gpuGrangersetF = 0, p = 1for any pair whose arithmetic went non-finite (collinear lags, a constant series, a cause identical to the effect): an undefined test reported as "no causality", silently. It also computed in single precision by default on uncentred data (F off by more than 10% on long random walks) and fitted one regression per pair with device memory growing ascols² · 2(lag+1) · n.The method now. Each effect's restricted design
[1, own lags]is orthonormalised once (Cholesky-QR2 on the GPU; Householder on the host above condition 1e7). Every cause's test against it comes from the productsC = Q'L,L'e,Q'easG = L'L − C'C,g = L'e − C'(Q'e), judged pair by pair (cond(G)/left · RSS_r/RSS_u < 1e6) and recomputed from the explicit residual lagsM = L − QQ'Lwhere that cancellation can't be trusted. All in double, series centred and scaled (changes no F). A pair ruled out by the effect design's condition (> 1e10), the cause'sG(> 1e12) or the fraction of the cause left after projection (< 1e-20) isNAwith a warning; a series against itself or a constant series isNAwithout one.lagis validated (1–16).precisionis accepted but ignored, as the help page says.Verification (RTX 2080 Ti and A5500, CUDA 12.6):
lm()to 1e-7 on random walks, drifting walks and trends at lags 1 and 3 (n = 5,000), and on 50 white-noise series × 20,000 times, which spans two tiles of effects; near-copies (cause = effect + 1e-6 noise) to 1e-6 againstlm(tol = 1e-12)(lm's default rank tolerance drops the cause as aliased there); I(3) at lag 5: every pair flagged or within 1e-3.R CMD INSTALLclean.Review (CUDA and host code transcribed to NumPy and checked): index arithmetic, cuBLAS strides, in-thread Cholesky/inverse/solve, bounds at lag 16, Householder, the weak rule all clean; fixed from it: the "NaN-propagating" minimum for
leftwasn't, device buffers are now freed before the error check that can longjmp,lag = 1e10gets the intended message, a multi-tile test and deterministic assertions for the flagged cases.Also:
man/gpuGranger.Rdrewritten (formula, df, the conditioning rules, differencing advice, no more "single precision" in\value), NEWS for 2.1.1, a precision caveat in the benchmarks vignette (its Granger timings predate this change and will be re-measured).🤖 Generated with Claude Code