All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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