Skip to content

feat: add DynamicTimeWarping, alignment distance with a Sakoe-Chiba band - #7619

Merged
DenizAltunkapan merged 2 commits into
TheAlgorithms:masterfrom
alxkm:feat/dynamic-time-warping
Sep 27, 2026
Merged

DenizAltunkapan merged 2 commits into
TheAlgorithms:masterfrom
alxkm:feat/dynamic-time-warping

Conversation

@alxkm

@alxkm alxkm commented Sep 26, 2026

Copy link
Copy Markdown
Member

Adds dynamic time warping: how far apart two series are once one of them is allowed to be stretched and squeezed in time.

The Euclidean distance compares sample i with sample i and nothing else, so two recordings of the same gesture, one performed slightly faster, come out as far apart as two unrelated ones. Dynamic time warping instead looks for the cheapest way to line the two series up: every point of the first has to be matched to at least one point of the second and the other way round, the matching may never go backwards, and the cost is the sum over the matched pairs. That alignment is a shortest path through a grid, and the dynamic program is the obvious one:

D[i][j] = |a[i] - b[j]| + min( D[i-1][j], D[i][j-1], D[i-1][j-1] )

The three predecessors are exactly the three legal moves: consume a point of the first series, of the second, or of both.

Left alone, the alignment may match one point of a series against an arbitrarily long stretch of the other, which is rarely meaningful. The Sakoe-Chiba band is offered alongside: it forbids matches further apart in time than a given width, which both rules out those degenerate alignments and narrows the grid that has to be filled. A band narrower than the difference in length admits no alignment at all, and that is rejected with a clear message rather than returned as an infinity for the caller to puzzle over.

The distance runs in O(min(n, m)) memory over two rows. The warping path itself needs the whole grid, so it is a separate method and returns the matched pairs of indices. The Javadoc also notes what the result is not: it does not satisfy the triangle inequality, so it ranks candidates but cannot be used to index them without further care.

DynamicTimeWarpingTest covers 18 cases. The ones worth naming:

  • the cost of the returned path, summed independently in the test, equals the distance the other method reports;
  • the path starts at (0, 0), ends at the two last indices, never steps back and never stands still;
  • warping never costs more than matching sample by sample, checked over 50 random pairs;
  • a band of zero reduces exactly to that sample by sample comparison, and a narrower band never costs less than a wider one;
  • a sine shifted by a third of a period costs less than a quarter of what the straight comparison does, and a series stretched to twice its length still matches its original at a distance below 1.0;
  • the distance is symmetric over 20 random pairs of different lengths.

Two of those tests started out asserting the wrong thing, which is worth mentioning because the intuition is easy to get backwards: warping is cheaper than a sample by sample comparison even for a constant offset, because a point may be reused, so {1,2,3,4} against {3,4,5,6} costs 6 and not 8. There is now a test pinning exactly that.

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

The Euclidean distance compares sample i with sample i and nothing else, so two recordings of the same gesture, one performed slightly faster, come out as far apart as two unrelated ones. Dynamic time warping looks for the cheapest way to line the two series up instead: every point of each series is matched to at least one point of the other, the matching never goes backwards, and the cost is the sum over the matched pairs. That alignment is a shortest path through a grid, and the dynamic program has one line.

Left alone the alignment may match one point against an arbitrarily long stretch of the other, so the Sakoe-Chiba band is offered as well: it forbids matches further apart in time than a given width, which rules out those degenerate alignments and narrows the grid that has to be filled. The band has to be at least the difference in length or no alignment exists, and that is rejected rather than returned as infinity.

The distance runs in O(min(n, m)) memory over two rows; the warping path itself needs the whole grid and is returned as index pairs. The Javadoc notes that the result is not a metric, so it ranks candidates but cannot be indexed without further care.

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

codecov-commenter commented Sep 26, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.48485% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81.45%. Comparing base (743ff5e) to head (5b305f8).

Files with missing lines Patch % Lines
...om/thealgorithms/streaming/DynamicTimeWarping.java 98.48% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #7619      +/-   ##
============================================
+ Coverage     81.40%   81.45%   +0.04%     
- Complexity     8030     8051      +21     
============================================
  Files           834      835       +1     
  Lines         25321    25387      +66     
  Branches       4938     4950      +12     
============================================
+ Hits          20613    20679      +66     
  Misses         3921     3921              
  Partials        787      787              

☔ 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.

@DenizAltunkapan
DenizAltunkapan merged commit d291e7d into TheAlgorithms:master Sep 27, 2026
7 checks passed
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.

3 participants