Skip to content

Zero kriging-matrix diagonal so the nugget is not placed on it#2922

Merged
brendancol merged 2 commits into
mainfrom
deep-sweep-accuracy-interpolate-kriging-2026-06-04
Jun 4, 2026
Merged

Zero kriging-matrix diagonal so the nugget is not placed on it#2922
brendancol merged 2 commits into
mainfrom
deep-sweep-accuracy-interpolate-kriging-2026-06-04

Conversation

@brendancol

Copy link
Copy Markdown
Contributor

Closes #2915

_build_kriging_matrix set the variogram block to vario_func(D), where D has a zero diagonal. vario_func(0) returns the nugget c0, so a non-zero nugget ended up on the matrix diagonal. The semivariogram is gamma(0) = 0 by definition (the nugget is the one-sided limit as h -> 0+), and standard ordinary-kriging implementations zero that diagonal.

The bug only bit when the fitted nugget was non-zero: it forced exact interpolation of noisy data and shrank the kriging variance. The existing tests use trend-dominated data that fits a near-zero nugget, so they never exercised it.

Changes:

  • Zero the variogram-block diagonal with np.fill_diagonal in _build_kriging_matrix.
  • Add two regression tests: the matrix diagonal stays 0 under a non-zero nugget, and a non-zero nugget now smooths predictions and lifts the variance above the nugget floor.

Backends: _build_kriging_matrix is shared by all four backends (numpy / cupy / dask+numpy / dask+cupy), which build K_inv on the host before dispatch, so the fix applies uniformly.

Test plan:

  • pytest xrspatial/tests/test_interpolation.py -k "Kriging or kriging" (16 passed, includes cupy and dask+cupy parity)
  • New tests fail on the pre-fix code and pass after the fix

The semivariogram has gamma(0)=0 by definition; vario_func(0) returns
the nugget c0 (the one-sided limit as h->0+), not the value at h=0.
_build_kriging_matrix set the variogram block to vario_func(D) where D
has a zero diagonal, so a non-zero nugget landed on the matrix diagonal.
That forced exact interpolation of noisy data and biased the kriging
variance downward.

Force the variogram-block diagonal to 0 with np.fill_diagonal. Add two
regression tests: the matrix diagonal stays 0 under a non-zero nugget,
and a non-zero nugget now smooths predictions and lifts the variance
above the nugget floor.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Jun 4, 2026

@brendancol brendancol left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: Zero kriging-matrix diagonal so the nugget is not placed on it

Blockers

None.

Suggestions

None.

Nits

None.

What looks good

  • The fix matches the standard ordinary-kriging formulation: the semivariogram is gamma(0)=0, and the nugget is the one-sided limit as h -> 0+, so it should not sit on the matrix diagonal. PyKrige does the same.
  • The change is minimal and well-commented, touching only _build_kriging_matrix.
  • _build_kriging_matrix runs in numpy on the host before backend dispatch, so all four backends (numpy / cupy / dask+numpy / dask+cupy) consume the corrected K_inv. The fix is uniform without per-backend edits.
  • The existing post-failure regularizer (K[:n,:n] += 1e-10 * np.eye(n)) is a separate Tikhonov term applied only when inv raises; it is unaffected and still correct.
  • Both new tests were confirmed to fail on the pre-fix code and pass after, so they are genuine regression guards rather than tautologies.

Notes

  • The new tests exercise _build_kriging_matrix / _kriging_predict directly in numpy rather than across all four backends. That is appropriate here: the corrected line is shared host code, and the existing test_cupy_* / test_dask_cupy_* parity tests already cover dispatch. Adding nugget-specific backend variants would not increase coverage of the fix.

Checklist

  • Algorithm matches reference (ordinary kriging, gamma(0)=0)
  • All implemented backends consume the corrected matrix
  • NaN handling unchanged
  • Regression tests fail before / pass after the fix
  • No premature materialization or unnecessary copies
  • Benchmark not needed (bug fix, no perf-sensitive change)
  • README feature matrix unchanged (no new API)
  • Docstrings/comments present and accurate

@brendancol brendancol merged commit 641a606 into main Jun 4, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kriging(): nugget lands on the kriging-matrix diagonal (should be gamma(0)=0)

1 participant