const maxVal = Number.MAX_VALUE
/**
* 返回一个mXn的矩阵
* @param {number} m
* @param {number} n
* @param {number} val 初始值
* @returns {number[][]}
*/
function matrix(m, n, val = 0) {
const arr = [[0]]
arr.splice(0, 1)
for(let i = 0; i < m; i++) {
const child = []
for (let j = 0; j < n; j++) {
child.push[val]
}
arr.push(child)
}
return arr
}
/**
* 寻找最近路径
* @param {number[][]} dis
*/
function findTrace(dis) {
let m = dis.length
let n = dis[0].length
let i = m - 1
let j = n - 1
const W = []
let left_down = maxVal
let left = maxVal
let down = maxVal
while(i > 0 || j > 0) {
W.push([i,j])
console.log(i,j)
if (i > 0 && j > 0) {
left_down = dis[i-1][j-1]
} else {
left_down = maxVal
}
if (i > 0) {
down = dis[i-1][j]
} else {
down = maxVal
}
if (j > 0) {
left = dis[i][j-1]
} else {
left = maxVal
}
const min_dis = Math.min(left_down, down, left)
if (min_dis === left_down) {
i--
j--
} else if (min_dis === down) {
i--
} else {
j--
}
}
W.push([0, 0])
W.reverse()
return W
}
/**
* C,Q数据格式需要一致
* @param {number[]|number[][]} C
* @param {number[]|number[][]} Q
*/
function dtw(C, Q) {
let m = C.length
let n = Q.length
let len2D = Array.isArray(C[0]) ? C[0].length : 0
const point_dis = matrix(m,n)
for (let i =0; i < m; i++) {
for (let j = 0; j < n; j++) {
let val = 0
if (len2D) {
val = 0
for (let k = 0; k < len2D; k++) {
val += Math.pow(C[i][k] - Q[j][k], 2)
}
} else {
val = Math.pow(C[i] - Q[j], 2)
}
point_dis[i][j] = Math.sqrt(val)
}
}
const warping_dis = matrix(m,n, maxVal)
for( let i = 0; i< m; i++) {
for(let j = 0; j < n; j++) {
if (i === 0 && j===0) {
warping_dis[0][0] = point_dis[0][0]
continue
}
let left_down = maxVal
let down = maxVal
let left = maxVal
if (i > 0 && j > 0) {
left_down = warping_dis[i-1][j-1]
}
if ( i > 0) {
down = warping_dis[i - 1][j]
}
if ( j > 0) {
left = warping_dis[i][ j - 1]
}
// console.log(i,j,left, left_down, down, point_dis[i][j]);
warping_dis[i][j] = point_dis[i][j] + Math.min(left, left_down, down)
}
}
// console.log(warping_dis)
const dis = warping_dis[m-1][n-1]
const W = findTrace(warping_dis)
return {dis, W}
}
以下为测试代码:
let C = [[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9]]
let Q = [[1,5],[2,-2],[3,-1],[4,0],[5,1],[6,2],[7,3],[8,4],[9,5],[10,6],[11,7]]
const result = dtw(C, Q)
console.log(result)
C = [0,1,2,3,4,5]
Q = [1,2,3,4,5,6]
const {W, dis} = dtw(C, Q)
console.log(dis, W)
for(const item of W) {
const [m, n] = item
console.log(m,n, C[m], Q[n])
}