feat: add EwmaChangeDetector, an EWMA control chart for streams - #7600
Merged
DenizAltunkapan merged 1 commit intoSep 9, 2026
Merged
Conversation
Adds an exponentially weighted moving average control chart that flags level shifts in a stream in O(1) time and memory per sample, with an exact variance-based control band so that the warm-up does not trip false alarms. It builds on a new reusable ExponentialMovingAverage (alpha, span or half-life parameterisation, and the exponentially weighted variance of the same stream) and shares the ShiftSignal verdict enum with CusumDetector, out of which it is extracted to the package level so that both detectors report the same type. Co-authored-by: Oleksandr Klymenko <19151554+alxkm@users.noreply.github.com> Signed-off-by: alxkm <19151554+alxkm@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #7600 +/- ##
============================================
+ Coverage 80.92% 80.99% +0.07%
- Complexity 7680 7737 +57
============================================
Files 822 825 +3
Lines 24490 24594 +104
Branches 4800 4810 +10
============================================
+ Hits 19818 19920 +102
- Misses 3906 3907 +1
- Partials 766 767 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
DenizAltunkapan
approved these changes
Sep 9, 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.
Adds an EWMA control chart, the exponentially weighted counterpart of the CUSUM chart that went in with #7593: it smooths the stream with an average seeded at the expected level and raises an alarm as soon as the smoothed value leaves a band around that level.
The band is the exact standard deviation of
zunder the null hypothesis, scaled by the desired width in sigmas, so it starts narrow and widens towards its asymptotewidth * sigma * sqrt(alpha / (2 - alpha)). Using that asymptote from the first sample onwards -- the usual shortcut -- leaves the chart far too tolerant while the average is still warming up, whereas the exact limit keeps the false alarm rate steady from the very first sample. On an alarm the average is returned to the target, so the detector starts fresh on the next change instead of latching and reporting the same shift forever.Where a CUSUM chart accumulates evidence without limit and so excels at small persistent shifts, an EWMA chart looks at a decaying window of the recent past:
alphaaround 0.1 to 0.3 is a good compromise, larger values reacting faster to big jumps and smaller ones being more sensitive to slow drifts. Three sigmas is the customary width, and both are the defaults.ExponentialMovingAveragecarries the recurrence and is the reusable half of this:alphacan be given directly, as a span (2 / (span + 1), matching the responsiveness of a simple moving average of that many samples) or as a half-life (1 - exp(-ln2 / halfLife)), and the class tracks the exponentially weighted variance of the same stream in the same O(1) state. It seeds itself with the first sample rather than with zero, which avoids the warm-up bias a zero seed introduces, or with an explicit resting level, which is what a control chart wants.The
ShiftSignalverdict enum, until now nested insideCusumDetector, becomes a top-level enum of the package so that both detectors report the same type;CusumDetectorand its test are updated to it, and nothing else in the repository referred to the nested enum.Each sample costs O(1) time and neither class allocates anything after construction.
EwmaChangeDetectorTestcovers 17 cases andExponentialMovingAverageTest31;CusumDetectorTestkeeps its 16. Among them: the control limit is checked against its closed form and against its asymptote, upward and downward shifts are found both in a clean step and buried in noise, in-control Gaussian noise rarely trips the band, an alarm returns the statistic to the target, a stream sitting on target never alarms, the mean and variance recurrences are checked against direct computation,alpha == 1keeps only the latest sample, and on stationary noise the estimates sit close to the true moments.Checklist
clang-format -i --style=file path/to/your/file.java