46 lines
1.7 KiB
TypeScript
46 lines
1.7 KiB
TypeScript
import { test, expect } from "bun:test";
|
|
import { dtw } from "../../src/align/dtw.ts";
|
|
|
|
// Ground-truth path: diagonal with a kink (j runs ahead by 10 after i=50).
|
|
function truthJ(i: number): number { return i < 50 ? i : i + 10; }
|
|
const N = 100, M = 110;
|
|
// Path cells cost 0, others grow with distance from the true path.
|
|
const cost = (i: number, j: number) => {
|
|
const t = truthJ(i);
|
|
return Math.min(1, Math.abs(j - t) * 0.2);
|
|
};
|
|
|
|
test("dtw recovers diagonal-with-kink path", () => {
|
|
const p = dtw(cost, N, M);
|
|
expect(p[0]).toEqual([0, 0]);
|
|
expect(p[p.length - 1]).toEqual([N - 1, M - 1]);
|
|
for (const [i, j] of p) if (i !== 49 && i !== 50) expect(Math.abs(j - truthJ(i))).toBeLessThanOrEqual(1);
|
|
for (let k = 1; k < p.length; k++) {
|
|
const di = p[k]![0] - p[k - 1]![0], dj = p[k]![1] - p[k - 1]![1];
|
|
expect(di >= 0 && di <= 1 && dj >= 0 && dj <= 1 && di + dj >= 1).toBe(true);
|
|
}
|
|
});
|
|
|
|
test("banded dtw equals unbanded when the band covers the path", () => {
|
|
const full = dtw(cost, N, M);
|
|
const banded = dtw(cost, N, M, { center: (i) => truthJ(i), width: 15 });
|
|
expect(banded).toEqual(full);
|
|
});
|
|
|
|
test("banded dtw only visits cells in the band", () => {
|
|
let calls = 0;
|
|
const p = dtw((i, j) => { calls++; return Math.abs(i - j) * 0.1; }, 200, 200, { center: (i) => i, width: 5 });
|
|
expect(calls).toBeLessThanOrEqual(200 * 11);
|
|
expect(p[p.length - 1]).toEqual([199, 199]);
|
|
});
|
|
|
|
test("3000x3000 unbanded dtw finishes in < 5 s", () => {
|
|
const n = 3000;
|
|
const t0 = performance.now();
|
|
const p = dtw((i, j) => Math.abs(i - j) * 0.001 + ((i * 7 + j * 13) % 5) * 0.0001, n, n);
|
|
const ms = performance.now() - t0;
|
|
console.log(`dtw 3000x3000: ${ms.toFixed(0)} ms`);
|
|
expect(p[p.length - 1]).toEqual([n - 1, n - 1]);
|
|
expect(ms).toBeLessThan(5000);
|
|
});
|