package weka.core; /** Basic DTW implementation for Weka. /Each instance is assumed to be a time series. Basically we pull all the data out and proceed as usual! NOTE: Need to implement the early abandon, no point doing all the sums. Also nee to implement a pre calculated version Needs black box debug. **/ import java.util.Enumeration; import weka.core.neighboursearch.PerformanceStats; public class DTW_DistanceSpaceEfficient extends DTW_DistanceBasic{ double[] row1; double[] row2; /* DTW Distance: * * This implementation is more memory efficient in that it only stores * two rows. */ public double distance(double[] a,double[] b, double cutoff){ double dist=0, minDist; // Set the longest series to a double[] temp; if(a.length<b.length){ temp=a; a=b; b=temp; } int n=a.length; int m=b.length; int r = (int)(Math.floor(this.r*n)+1); row1=new double[m]; row2=new double[m]; //Set all to max // double[][] matrixD = new double[n][m]; for(int i=0;i<m;i++){ row1[i]=Double.MAX_VALUE; } row1[0]=(a[0]-b[0])*(a[0]-b[0]); //Base cases for warping 0 to all along row 1 //Warp a[0] onto all b[1]...b[r+1] for(int j=1;j<=r && j<m;j++) row1[j]=row1[j-1]+(a[0]-b[j])*(a[0]-b[j]); double rowMinDist; int start,end; if(r>=m) end=m-1; else end=r; rowMinDist=row1[end]; // System.out.println(" First row distance ="+rowMinDist); int rowMinPos=0; //For each remaining row, warp row i for (int i=1;i<n;i++){ row2=new double[m]; // warp a[i] onto b[0] row2[0]=row1[0]+(a[i]-b[0])*(a[i]-b[0]); //Set all the rest of row 2 to max for(int j=1;j<m;j++) row2[j]=Double.MAX_VALUE; //Find the interval for warping if(i-r<1) start=1; else start=i-r; if(i+r>m) end=m; else end=i+r; //Warp a[i] onto b[j=start..end] for (int j = start;j<end;j++) { //Find the min of row2[j-1],row1[j] and row1[j-1] minDist=row2[j-1]; if(row1[j]<minDist) minDist=row1[j]; if(row1[j-1]<minDist) minDist=row1[j-1]; row2[j]=minDist+(a[i]-b[j])*(a[i]-b[j]); } //Record the min dist of the end of the row // System.out.println(i+" end row distance ="+row2[end-1]); if(rowMinDist<row2[end-1]){ rowMinDist=row2[end-1]; rowMinPos=i; } //Swap row 2 into row 1. row1=row2; } //Find min distance overall dist=rowMinDist; for(int j=0;j<m;j++){ // System.out.println(j+" end col distance ="+row2[j]); if(row2[j]<dist){ dist=row2[j]; } } return dist; } /* OLD IMPLEMENTATION double r=0.05; //Warping window size percentage, between 0 and 1 protected DynamicTimeWarping(){} public DynamicTimeWarping(double r){this.r=r;} public double distance(Complex[] a,Complex[] b){ double dist=0, minDist; // Set the longest series to a Complex[] temp; if(a.length<b.length) { temp=a; a=b; b=temp; } int n=a.length; int m=b.length; //Use this to make it the same as Euclidean when this.r=0 int r = (int)(Math.floor(this.r*n)+1); //Set all to max double[][] matrixD = new double[n][m]; for(int i=0;i<n;i++) for(int j=0;j<m;j++) matrixD[i][j]=Double.MAX_VALUE; matrixD[0][0]=Complex.distance(a[0],b[0]); //Base cases for warping 0 to all //Warp a[0] onto all b[1]...b[r+1] for(int j=1;j<=r && j<n;j++) matrixD[0][j]=matrixD[0][j-1]+Complex.distance(a[0],b[j]); // Warp b[0] onto all a[1]...a[r+1] for(int i=1;i<=r && i<n;i++) matrixD[i][0]=matrixD[i-1][0]+Complex.distance(a[i],b[0]); //Warp the rest, int start,end; for (int i=1;i<n;i++) { if(i-r<1) start=1; else start=i-r; if(i+r>m) end=m; else end=i+r; for (int j = start;j<end;j++) { //Find the min of matrixD[i][j-1],matrixD[i-1][j] and matrixD[i-1][j-1] minDist=matrixD[i][j-1]; if(matrixD[i-1][j]<minDist) minDist=matrixD[i-1][j]; if(matrixD[i-1][j-1]<minDist) minDist=matrixD[i-1][j-1]; matrixD[i][j]=minDist+Complex.distance(a[i],b[j]); } } //Find the minimum distance dist=matrixD[n-1][0]; for(int j=1;j<m;j++) if(matrixD[n-1][j]<dist) dist=matrixD[n-1][j]; for(int i=0;i<n;i++) if(matrixD[i][m-1]<dist) dist=matrixD[i][m-1]; return dist; } public double distance(DataPoint dp1,DataPoint dp2){ double[] a = dp1.getData(); double[] b= dp2.getData(); return distance(a,b); } public double distance(ComplexDataPoint dp1,ComplexDataPoint dp2){ double[] a1 = dp1.getReal(); double[] a2 = dp1.getImaginary(); double[] b1= dp2.getReal(); double[] b2= dp2.getImaginary(); Complex[] a = new Complex[a1.length]; for(int i=0;i<a.length;i++) a[i]=new Complex((float)a1[i],(float)a2[i]); Complex[] b = new Complex[b1.length]; for(int i=0;i<b.length;i++) b[i]=new Complex((float)b1[i],(float)b2[i]); return distance(a,b); } public double distance(double[] a,double[] b){ double dist=0, minDist; // Set the longest series to a double[] temp; if(a.length<b.length) { temp=a; a=b; b=temp; } int n=a.length; int m=b.length; int r = (int)(Math.floor(this.r*n)+1); // int r = (int)Math.ceil(this.r*n); // System.out.println(" r = "+r); //Set all to max double[][] matrixD = new double[n][m]; for(int i=0;i<n;i++) for(int j=0;j<m;j++) matrixD[i][j]=Double.MAX_VALUE; matrixD[0][0]=(a[0]-b[0])*(a[0]-b[0]); //Base cases for warping 0 to all //Warp a[0] onto all b[1]...b[r+1] for(int j=1;j<=r && j<n;j++) matrixD[0][j]=matrixD[0][j-1]+(a[0]-b[j])*(a[0]-b[j]); // Warp b[0] onto all a[1]...a[r+1] for(int i=1;i<=r && i<n;i++) matrixD[i][0]=matrixD[i-1][0]+(a[i]-b[0])*(a[i]-b[0]); //Warp the rest, int start,end; for (int i=1;i<n;i++) { if(i-r<1) start=1; else start=i-r; if(i+r>m) end=m; else end=i+r; for (int j = start;j<end;j++) { //Find the min of matrixD[i][j-1],matrixD[i-1][j] and matrixD[i-1][j-1] minDist=matrixD[i][j-1]; if(matrixD[i-1][j]<minDist) minDist=matrixD[i-1][j]; if(matrixD[i-1][j-1]<minDist) minDist=matrixD[i-1][j-1]; matrixD[i][j]=minDist+(a[i]-b[j])*(a[i]-b[j]); } } //Find the minimum distance dist=matrixD[n-1][0]; for(int j=1;j<m;j++) if(matrixD[n-1][j]<dist) dist=matrixD[n-1][j]; for(int i=0;i<n;i++) if(matrixD[i][m-1]<dist) dist=matrixD[i][m-1]; return dist; } public double distance(short[] a,short[] b){ short dist=0, minDist; // Set the longest series to a short[] temp; if(a.length<b.length) { temp=a; a=b; b=temp; } int n=a.length; int m=b.length; int r = (int)(Math.floor(this.r*n)+1); // int r = (int)Math.ceil(this.r*n); // System.out.println(" r = "+r); //Set all to max short[][] matrixD = new short[n][m]; for(int i=0;i<n;i++) for(int j=0;j<m;j++) matrixD[i][j]=Short.MAX_VALUE; matrixD[0][0]=(short)((a[0]-b[0])*(a[0]-b[0])); //Base cases for warping 0 to all //Warp a[0] onto all b[1]...b[r+1] for(int j=1;j<=r && j<n;j++) matrixD[0][j]=(short)(matrixD[0][j-1]+(short)((a[0]-b[j])*(a[0]-b[j]))); // Warp b[0] onto all a[1]...a[r+1] for(int i=1;i<=r && i<n;i++) matrixD[i][0]=(short)(matrixD[i-1][0]+(short)((a[i]-b[0])*(a[i]-b[0]))); //Warp the rest, int start,end; for (int i=1;i<n;i++) { if(i-r<1) start=1; else start=i-r; if(i+r>m) end=m; else end=i+r; for (int j = start;j<end;j++) { //Find the min of matrixD[i][j-1],matrixD[i-1][j] and matrixD[i-1][j-1] minDist=matrixD[i][j-1]; if(matrixD[i-1][j]<minDist) minDist=matrixD[i-1][j]; if(matrixD[i-1][j-1]<minDist) minDist=matrixD[i-1][j-1]; matrixD[i][j]=(short)(minDist+(a[i]-b[j])*(a[i]-b[j])); } } //Find the minimum distance dist=matrixD[n-1][0]; for(int j=1;j<m;j++) if(matrixD[n-1][j]<dist) dist=matrixD[n-1][j]; for(int i=0;i<n;i++) if(matrixD[i][m-1]<dist) dist=matrixD[i][m-1]; return dist; } public static void main(String[] args) { System.out.println(" Very basic test for DTW distance"); double[] a ={1,2,3,4,5,6,7,8}; double[] b ={2,3,4,5,6,7,8,9}; for(int i=0;i<a.length;i++) System.out.print(a[i]+","); System.out.println("\n************"); for(int i=0;i<b.length;i++) System.out.print(b[i]+","); System.out.println("\n Euclidean distance is 8, DTW should be 0??"); DynamicTimeWarping dtw= new DynamicTimeWarping(0.05); System.out.println(" DTW Distance ="+dtw.distance(a,b)); } */ }