fix: clamp moving Pearson correlation distance to [0,2]#13152
Draft
Planeshifter wants to merge 5 commits into
Draft
fix: clamp moving Pearson correlation distance to [0,2]#13152Planeshifter wants to merge 5 commits into
Planeshifter wants to merge 5 commits into
Conversation
Welford-style accumulation of the Pearson correlation coefficient can
produce values slightly outside [-1, 1] due to floating-point rounding.
When r is a ULP above 1, `1 - r` becomes a small negative number; when
r is a ULP below -1, `1 - r` exceeds 2. Both are physically impossible
for a correlation distance, which must lie in [0, 2].
Clamp the computed distance in both code paths of the accumulator (the
no-argument "current value" path and the two-argument "update" path).
Remove the now-unreachable `if (actual < 0.0) { actual = 0.0; }` guard
from the incremental test, which was masking the underlying source bug.
Reviewed-by: CI routine
…lamping The "not guaranteed to be strictly on [0,2]" caveat is no longer correct now that the accumulator clamps its output. Replace with a note describing the clamping behaviour and its rationale (ULP-level Welford rounding).
Contributor
Coverage Report
The above coverage report was generated for the changes in this PR. |
…rage for d>2 clamp Two test improvements to go with the source clamping fix: 1. Tolerance floor: add `100 * EPS` as an absolute minimum tolerance in the incremental test (both unknown-means and known-means variants). The relative tolerance `1e6 * EPS * abs(expected)` becomes astronomically tight when `expected` is itself near machine epsilon (nearly perfect correlation), making the test non-deterministically flaky for those seeds. The floor kicks in only for `|expected| < 1e-4`, which covers only near-zero distances. 2. Coverage: add a test that exercises the `d > 2.0` clamp path. With W=2 and nearly anti-correlated data at scale 10, the Welford accumulator yields r = -1.0000000000000009 at the 8th datum, giving `1 - r = 2.0000000000000009` before clamping. The new test verifies the accumulator returns exactly 2.0 and that the no-argument query path is also clamped correctly.
…clamp test Collapse two-line comment to a single line to satisfy the `stdlib/empty-line-before-comment` rule (each `//` comment requires a blank line before it) and `stdlib/capitalized-comments` (comment must start with an uppercase character).
… clamp path Extend the floating-point clamp test to also exercise the no-argument accumulator path when Welford yields r > 1. With W=2 and nearly perfectly positively correlated data at scale 10, the 14th datum gives r = 1.0000000000000009, so `1 - r` drops below 0.0. Calling `acc()` after that update hits the previously uncovered no-arg `d < 0.0` branch.
kgryte
reviewed
Jun 26, 2026
kgryte
left a comment
Member
There was a problem hiding this comment.
This PR needs cleanup. And not clear we should be clamping in this package, rather than in mpcorr itself. Why should the distance be clamped but not the correlation coefficient? There may be reasons why the correlation coefficient was not clamped, but that should be investigated before moving forward with this PR.
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.
Resolves .
Description
This pull request:
@stdlib/stats/incr/mpcorrdistto clamp the computed moving Pearson correlation distance to its mathematically valid range[0, 2].Root cause: The accumulator uses Welford's online algorithm (via
@stdlib/stats/incr/mpcorr) to compute the Pearson correlation coefficientr. Due to floating-point rounding,rcan land a ULP or two outside[-1, 1], givingd = 1 - routside[0, 2](e.g.,-2.886e-15or2 + 2.886e-15). The CI failure on Node.js v16 observedexpected = 0.0(reference clamped) vsactual = 2.886e-15(accumulator not clamped), exceeding the10 * EPStolerance for theexpected === 0case.Changes:
lib/main.js— clampdto[0, 2]in both the no-argument (query) and two-argument (update) code paths of the inneraccumulatorfunction.test/test.js— remove the deadif (actual < 0.0) { actual = 0.0; }guard from the main incremental test, which was masking the source-level bug.README.md,docs/repl.txt— replace the "not guaranteed to be strictly on[0,2]" caveat with a note describing the clamping behaviour.Validation: 2424/2424 tests pass across 10 random datasets × 100 windows each.
Related Issues
This pull request has the following related issues:
Questions
No.
Other
The clamping is applied in
mpcorrdistrather than in the upstreamincrmpcorrpackage. Fixingincrmpcorrto returnr ∈ [-1, 1]would be more general, but is a separate, larger change. This fix is the minimal, contained change that resolves the CI failure.Checklist
AI Assistance
If you answered "yes" above, how did you use AI assistance?
Disclosure
This PR was written by an automated CI-fix routine running Claude Code (claude-sonnet-4-6). The routine identified the failure cluster, traced the root cause to missing output clamping, applied the fix, ran all 2424 package tests, and passed three-agent review (correctness, regression scope, style) before committing.
@stdlib-js/reviewers
Generated by Claude Code