
com.fastdtw.dtw.DTW Maven / Gradle / Ivy
The newest version!
/*
* DTW.java Jul 14, 2004
*
* Copyright (c) 2004 Stan Salvador
* [email protected]
*/
package com.fastdtw.dtw;
import java.util.Enumeration;
import com.fastdtw.dtw.matrix.CostMatrix;
import com.fastdtw.dtw.matrix.PartialWindowMatrix;
import com.fastdtw.dtw.matrix.WindowMatrix;
import com.fastdtw.dtw.window.SearchWindow;
import com.fastdtw.matrix.ColMajorCell;
import com.fastdtw.timeseries.TimeSeries;
import com.fastdtw.util.DistanceFunction;
public final class DTW
{
public static double calcWarpCost(WarpPath path, TimeSeries tsI, TimeSeries tsJ, DistanceFunction distFn)
{
double totalCost = 0.0;
for (int p=0; p0) || (j>0))
{
// Find the costs of moving in all three possible directions (left,
// down, and diagonal (down and left at the same time).
final double diagCost;
final double leftCost;
final double downCost;
if ((i>0) && (j>0))
diagCost = costMatrix[i-1][j-1];
else
diagCost = Double.POSITIVE_INFINITY;
if (i > 0)
leftCost = costMatrix[i-1][j];
else
leftCost = Double.POSITIVE_INFINITY;
if (j > 0)
downCost = costMatrix[i][j-1];
else
downCost = Double.POSITIVE_INFINITY;
// Determine which direction to move in. Prefer moving diagonally and
// moving towards the i==j axis of the matrix if there are ties.
if ((diagCost<=leftCost) && (diagCost<=downCost))
{
i--;
j--;
}
else if ((leftCost diagCost
j--;
else // leftCost==rightCost > diagCost
i--;
// Add the current step to the warp path.
minCostPath.addFirst(i, j);
} // end while loop
return new TimeWarpInfo(minimumCost, minCostPath);
} // end DynamicTimeWarp(..)
public static double distanceBetween(TimeSeries tsI, TimeSeries tsJ, SearchWindow window, DistanceFunction distFn)
{
// COST MATRIX:
// 5|_|_|_|_|_|_|E| E = min Global Cost
// 4|_|_|_|_|_|_|_| S = Start point
// 3|_|_|_|_|_|_|_| each cell = min global cost to get to that point
// j 2|_|_|_|_|_|_|_|
// 1|_|_|_|_|_|_|_|
// 0|S|_|_|_|_|_|_|
// 0 1 2 3 4 5 6
// i
// access is M(i,j)... column-row
final CostMatrix costMatrix = new PartialWindowMatrix(window);
final int maxI = tsI.size()-1;
final int maxJ = tsJ.size()-1;
// Get an iterator that traverses the window cells in the order that the cost matrix is filled.
// (first to last row (1..maxI), bottom to top (1..MaxJ)
final Enumeration matrixIterator = window.enumeration();
while (matrixIterator.hasMoreElements())
{
final ColMajorCell currentCell = matrixIterator.nextElement(); // current cell being filled
final int i = currentCell.getCol();
final int j = currentCell.getRow();
if ( (i==0) && (j==0) ) // bottom left cell (first row AND first column)
costMatrix.put(i, j, distFn.calcDistance(tsI.getMeasurementVector(0), tsJ.getMeasurementVector(0)));
else if (i == 0) // first column
{
costMatrix.put(i, j, distFn.calcDistance(tsI.getMeasurementVector(0), tsJ.getMeasurementVector(j)) +
costMatrix.get(i, j-1));
}
else if (j == 0) // first row
{
costMatrix.put(i, j, distFn.calcDistance(tsI.getMeasurementVector(i), tsJ.getMeasurementVector(0)) +
costMatrix.get(i-1, j));
}
else // not first column or first row
{
final double minGlobalCost = Math.min(costMatrix.get(i-1, j),
Math.min(costMatrix.get(i-1, j-1),
costMatrix.get(i, j-1)));
costMatrix.put(i, j, minGlobalCost + distFn.calcDistance(tsI.getMeasurementVector(i),
tsJ.getMeasurementVector(j)));
} // end if
} // end while loop
// Minimum Cost is at (maxI, maxJ)
return costMatrix.get(maxI, maxJ);
} // end getWarpDistBetween(...)
public static TimeWarpInfo compare(TimeSeries tsI, TimeSeries tsJ, SearchWindow window, DistanceFunction distFn)
{
return constrainedTimeWarp(tsI, tsJ, window, distFn);
}
private static TimeWarpInfo constrainedTimeWarp(TimeSeries tsI, TimeSeries tsJ, SearchWindow window, DistanceFunction distFn) {
// COST MATRIX:
// 5|_|_|_|_|_|_|E| E = min Global Cost
// 4|_|_|_|_|_|_|_| S = Start point
// 3|_|_|_|_|_|_|_| each cell = min global cost to get to that point
// j 2|_|_|_|_|_|_|_|
// 1|_|_|_|_|_|_|_|
// 0|S|_|_|_|_|_|_|
// 0 1 2 3 4 5 6
// i
// access is M(i,j)... column-row
final WindowMatrix costMatrix = new WindowMatrix(window);
final int maxI = tsI.size() - 1;
final int maxJ = tsJ.size() - 1;
// Get an iterator that traverses the window cells in the order that the
// cost matrix is filled.
// (first to last row (1..maxI), bottom to top (1..MaxJ)
final Enumeration matrixIterator = window.enumeration();
while (matrixIterator.hasMoreElements()) {
// current cell being filled
final ColMajorCell currentCell = matrixIterator.nextElement();
final int i = currentCell.getCol();
final int j = currentCell.getRow();
if ((i == 0) && (j == 0)) // bottom left cell (first row AND first
// column)
costMatrix.put(
i,
j,
distFn.calcDistance(tsI.getMeasurementVector(0),
tsJ.getMeasurementVector(0)));
else if (i == 0) // first column
{
costMatrix.put(
i,
j,
distFn.calcDistance(tsI.getMeasurementVector(0),
tsJ.getMeasurementVector(j))
+ costMatrix.get(i, j - 1));
} else if (j == 0) // first row
{
costMatrix.put(
i,
j,
distFn.calcDistance(tsI.getMeasurementVector(i),
tsJ.getMeasurementVector(0))
+ costMatrix.get(i - 1, j));
} else // not first column or first row
{
final double minGlobalCost = Math.min(costMatrix.get(i - 1, j),
Math.min(costMatrix.get(i - 1, j - 1), costMatrix.get(i, j - 1)));
costMatrix.put(
i,
j,
minGlobalCost
+ distFn.calcDistance(tsI.getMeasurementVector(i),
tsJ.getMeasurementVector(j)));
} // end if
} // end while loop
// Minimum Cost is at (maxI, maxJ)
final double minimumCost = costMatrix.get(maxI, maxJ);
// Find the Warp Path by searching the matrix from the solution at
// (maxI, maxJ) to the beginning at (0,0). At each step move through
// the matrix 1 step left, down, or diagonal, whichever has the
// smallest cost. Favoer diagonal moves and moves towards the i==j
// axis to break ties.
final WarpPath minCostPath = new WarpPath(maxI + maxJ - 1);
int i = maxI;
int j = maxJ;
minCostPath.addFirst(i, j);
while ((i > 0) || (j > 0)) {
// Find the costs of moving in all three possible directions (left,
// down, and diagonal (down and left at the same time).
final double diagCost;
final double leftCost;
final double downCost;
if ((i > 0) && (j > 0))
diagCost = costMatrix.get(i - 1, j - 1);
else
diagCost = Double.POSITIVE_INFINITY;
if (i > 0)
leftCost = costMatrix.get(i - 1, j);
else
leftCost = Double.POSITIVE_INFINITY;
if (j > 0)
downCost = costMatrix.get(i, j - 1);
else
downCost = Double.POSITIVE_INFINITY;
// Determine which direction to move in. Prefer moving diagonally
// and
// moving towards the i==j axis of the matrix if there are ties.
if ((diagCost <= leftCost) && (diagCost <= downCost)) {
i--;
j--;
} else if ((leftCost < diagCost) && (leftCost < downCost))
i--;
else if ((downCost < diagCost) && (downCost < leftCost))
j--;
else if (i <= j) // leftCost==rightCost > diagCost
j--;
else
// leftCost==rightCost > diagCost
i--;
// Add the current step to the warp path.
minCostPath.addFirst(i, j);
} // end while loop
// Free any rescources associated with the costMatrix (a swap file may
// have been created if the swa file did not
// fit into main memory).
costMatrix.freeMem();
return new TimeWarpInfo(minimumCost, minCostPath);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy