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_DistanceEfficient extends DTW_DistanceBasic{
double[] row1;
double[] row2;
public DTW_DistanceEfficient(){
super();
m_DontNormalize=true;
}
public DTW_DistanceEfficient(Instances data) {
super(data);
m_DontNormalize=true;
}
/* DTW Distance:
*
* This implementation is more memory efficient in that it only stores
* two rows. It also implements the early abandon. If all of row 2 are above the cuttoff then
* we can ditch the distance
*/
public double distance(double[] a,double[] b, double cutoff){
double dist=0, minDist;
boolean tooBig=true;
// System.out.println("\t\t\tIn Efficient with cutoff ="+cutoff);
// 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;
//No Warp: windowSize=1, full warp: windowSize=m
int windowSize = getWindowSize(0,0,m);
row1=new double[m];
row2=new double[m];
//Set all to max
row1[0]=(a[0]-b[0])*(a[0]-b[0]);
if(row1[0]<cutoff)
tooBig=false;
for(int j=1;j<n&&j<=windowSize;j++){
row1[j]=Double.MAX_VALUE;
}
//Warp a[0] onto all b[1]...b[WindowSize]
for(int j=1;j<windowSize && j<m;j++){
row1[j]=row1[j-1]+(a[0]-b[j])*(a[0]-b[j]);
if(row1[j]<cutoff)
tooBig=false;
}
if(tooBig){
return Double.MAX_VALUE;
}
int start,end;
//For each remaining row, warp row i
for (int i=1;i<n;i++){
tooBig=true;
row2=new double[m];
//Find point to start from
if(i-windowSize<1)
start=0;
else
start=i-windowSize+1;
if(start==0){
row2[0]=row1[0]+(a[i]-b[0])*(a[i]-b[0]);
start=1;
}
else
row2[start-1]=Double.MAX_VALUE;
//Find end point
if(start+windowSize>=m)
end=m;
else
end=start+windowSize;
//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]);
if(tooBig&&row2[j]<cutoff)
tooBig=false;
}
if(end<m)
row2[end]=Double.MAX_VALUE;
//Swap row 2 into row 1.
if(tooBig){
return Double.MAX_VALUE;
}
row1=row2;
}
return row1[m-1];
}
public String toString() {
return "DTW EFFICIENT";
}
/* Test Harness to check the outputs are the same with DTW Basic and TW_DistanceSpaceEfficient
*/
public static void main(String[] args){
DTW_DistanceBasic b=new DTW_DistanceBasic();
DTW_DistanceEfficient c=new DTW_DistanceEfficient();
double[] a1={1,1,1,6};
double[] a2={1,6,6,6};
b.setR(0);
c.setR(0);
System.out.println("***************** TEST 1: Two small arrays *******************");
//Zero warp distance should be 50,
System.out.println("\nZero warp full matrix ="+b.distance(a1,a2,Double.MAX_VALUE));
System.out.println("Zero warp limited matrix ="+c.distance(a1,a2,Double.MAX_VALUE));
// Full warp should be 0
b.setR(1);
c.setR(1);
System.out.println("\nFull warp full matrix ="+b.distance(a1,a2,Double.MAX_VALUE));
System.out.println("Full warp limited matrix ="+c.distance(a1,a2,Double.MAX_VALUE));
// System.out.println("Full warp full matrix JML version="+b.measure(a1,a2));
// 1/4 Warp should be 25
b.setR(0.25);
c.setR(0.25);
System.out.println("\nQuarter warp full matrix ="+b.distance(a1,a2,Double.MAX_VALUE));
System.out.println("Quarter warp limited matrix ="+c.distance(a1,a2,Double.MAX_VALUE));
System.out.println("***************** TEST2: Longer arrays *******************");
//Longer arrays
double[] a3={1,10,11,15,1,2,4,56,6,7,8};
double[] a4={10,11,10,1,1,2,4,56,6,7,8};
double d=0;
for(int i=0;i<a3.length;i++)
d+=(a3[i]-a4[i])*(a3[i]-a4[i]);
System.out.println("\nEuclidean distance ="+d);
//Zero warp distance should be
b.setR(0);
c.setR(0);
System.out.println("Zero warp full matrix ="+b.distance(a3,a4,Double.MAX_VALUE));
System.out.println("Zero warp limited matrix ="+c.distance(a3,a4,100));
// b.printPath();
// Full warp should be
b.setR(1);
c.setR(1);
System.out.println("\nFull warp full matrix ="+b.distance(a3,a4,100));
// b.printPath();
// System.out.println("Full warp full matrix JML version="+b.measure(a3,a4));
System.out.println("Full warp limited matrix ="+c.distance(a3,a4,100));
// 1/4 Warp should be
b.setR(0.25);
c.setR(0.25);
System.out.println("\nQuarter warp full matrix ="+b.distance(a3,a4,Double.MAX_VALUE));
System.out.println("Quarter warp limited matrix ="+c.distance(a3,a4,Double.MAX_VALUE));
// 1/2 Warp should be
b.setR(0.5);
c.setR(0.5);
System.out.println("Half warp full matrix ="+b.distance(a3,a4,Double.MAX_VALUE));
System.out.println("Half warp limited matrix ="+c.distance(a3,a4,Double.MAX_VALUE));
// b.printPath();
System.out.println("***************** TEST3: Variable length arrays *******************");
System.out.println("NOT IMPLEMENTED FOR VARIABLE LENGTH");
/* double[] a5={1,10,11};
double[] a6={1,10,11,15,1};
//Zero warp distance should be 50,
System.out.println("Zero warp full matrix ="+b.distance(a5,a6,0));
// System.out.println("Zero warp limited matrix ="+c.distance(a1,a2,0));
// Full warp should be 0
b.setR(1);
c.setR(1);
System.out.println("Full warp full matrix ="+b.distance(a5,a6,0));
// System.out.println("Full warp full matrix JML version="+b.measure(a1,a2));
// System.out.println("Full warp limited matrix ="+c.distance(a1,a2,0));
// 1/4 Warp should be 25
b.setR(0.25);
c.setR(0.25);
System.out.println("Quarter warp full matrix ="+b.distance(a5,a6,0));
// System.out.println("Quarter warp limited matrix ="+c.distance(a1,a2,0));
*/
//Variable length arrays
}
}