Skip to content

feat: add Adwin, an adaptive window that cuts itself when the stream changes - #7606

Open
alxkm wants to merge 1 commit into
TheAlgorithms:masterfrom
alxkm:feat/adwin
Open

alxkm wants to merge 1 commit into
TheAlgorithms:masterfrom
alxkm:feat/adwin

Conversation

@alxkm

@alxkm alxkm commented Sep 16, 2026

Copy link
Copy Markdown
Member

Adds ADWIN, adaptive windowing, after Bifet and Gavalda: an average over a window whose length is not a parameter but a result.

Every windowed estimator forces the same bad choice. A long window is accurate while nothing changes and hopelessly slow once something does; a short one reacts immediately and is noisy the rest of the time. ADWIN refuses the choice. It keeps a window of recent values and, after every sample, looks for a way to split it into an old part and a recent part whose means are too far apart to be explained by chance. When it finds one, the old part is dropped. The window therefore grows on its own while the stream is stationary and collapses as soon as the stream moves, and the length it settles at is an estimate of how long the current regime has been running.

"Too far apart" is a variance sensitive Hoeffding bound. For a cut into sub-windows of n0 and n1 elements, with v the variance of the whole window:

m       = 1 / (n0 - minLength + 1) + 1 / (n1 - minLength + 1)
d       = ln( 2 * ln(width) / delta )
epsilon = sqrt(2 * m * v * d) + 2/3 * d * m
cut when |mean0 - mean1| > epsilon

delta is a confidence level: the probability of cutting a window that never changed is bounded by it, which is what makes the resulting window length trustworthy rather than merely plausible.

Keeping every sample would cost O(n) memory, so the window is stored as an exponential histogram: buckets of 1, 2, 4, 8 ... elements, at most five of each size, each holding the sum and the variance of the elements it covers. That is O(log n) buckets for a window of n elements, and cuts are tried only at bucket boundaries, which is what keeps a sample O(log n) instead of O(n) at the cost of a bounded loss of resolution. The merge of two buckets carries the variance exactly, through the usual n0 * n1 * (u0 - u1)^2 / (n0 + n1) correction.

AdwinTest covers 19 cases. The one that matters most checks the arithmetic rather than the behaviour: over 2000 samples of stationary noise the mean and the variance recovered from the bucket histogram are compared with a direct computation over the raw samples, and they agree to 1e-9. Among the others: a constant stream is never cut and the window holds all of it, a step in the level cuts the window within 50 samples and leaves exactly the samples that followed the step, the window follows a level that changes four times, the bucket count stays inside (MAX_BUCKETS + 1) * (log2(width) + 1) for a window of 5000, the width never exceeds the number of samples seen, and a smaller delta never cuts more eagerly than a larger one.

Checklist

  • I have read CONTRIBUTING.md.
  • This pull request is all my own work -- I have not plagiarized it.
  • All filenames are in PascalCase.
  • All functions and variable names follow Java naming conventions.
  • All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
  • All new algorithms include a corresponding test class that validates their functionality.
  • All new code is formatted with clang-format -i --style=file path/to/your/file.java

…changes

ADWIN keeps a window of recent values and, after every sample, looks for a split into an old and a recent part whose means differ by more than a variance sensitive Hoeffding bound. When it finds one the old part is dropped, so the window grows while the stream is stationary and collapses as soon as it moves, and its length becomes an estimate of how long the current regime has lasted rather than a parameter to tune.

The window is stored as an exponential histogram, buckets of 1, 2, 4 ... elements with at most five of each size, so a window of n elements needs O(log n) buckets and cuts are tried only at bucket boundaries. The bucket merge carries the sum and the variance exactly, which the tests check against a direct computation over 2000 samples.

Signed-off-by: alxkm <19151554+alxkm@users.noreply.github.com>
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.68293% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.17%. Comparing base (b6fb8ad) to head (1090a27).

Files with missing lines Patch % Lines
...c/main/java/com/thealgorithms/streaming/Adwin.java 92.68% 3 Missing and 6 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #7606      +/-   ##
============================================
+ Coverage     81.10%   81.17%   +0.06%     
- Complexity     7813     7852      +39     
============================================
  Files           827      828       +1     
  Lines         24742    24865     +123     
  Branches       4833     4849      +16     
============================================
+ Hits          20068    20184     +116     
- Misses         3907     3910       +3     
- Partials        767      771       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants