https://github.com/cran/dtw
Raw File
Tip revision: e5274988af4af0e65de75ac6ae8092578d89f1b4 authored by Toni Giorgino on 22 August 2012, 00:00:00 UTC
version 1.15
Tip revision: e527498
computeCM.c
/* 
 * Compute global cost matrix - companion
 * to the dtw R package
 * (c) Toni Giorgino  2007-2012
 * Distributed under GPL-2 with NO WARRANTY.
 *
 * $Id: computeCM.c 268 2012-08-12 15:01:18Z tonig $
 *  
 */


#include <stdlib.h>
#include <stdio.h>
#include <math.h>


#ifdef TEST_UNIT
// Define R-like functions - a bad idea
     #define R_alloc(n,size) malloc((n)*(size))
     #define my_R_free(ptr) free((ptr))
     #define error(...) { fprintf (stderr, __VA_ARGS__); exit(-1); }
#else
     #include <R.h>
     #define my_R_free(ptr) 
#endif



#include "computeCM.h"

#ifndef NAN
#error "This code requires native IEEE NAN support. Possible solutions: 1) verify you are using gcc with -std=gnu99; 2) use the fallback interpreted DTW version (should happen automatically); 3) ask the author"
#endif


/* undo R indexing */
#define EP(ii,jj) ((jj)*nsteps+(ii))
#define EM(ii,jj) ((jj)*n+(ii))

#define CLEARCLIST { \
  for(int z=0; z<npats; z++) \
    clist[z]=NAN; }


/* 
 *  Compute cumulative cost matrix: replaces kernel in globalCostMatrix.R
 */


/* For now, this code is also valid outside R, as a test unit (the
   TEST_UNIT will be defined). This means that we have to refrain to
   use R-specific functions, such as R_malloc, or conditionally
   provide replacements when TEST_UNIT is defined */

/* R matrix fastest index is row */

void computeCM(			/* IN */
	       int *s,		/* mtrx dimensions */
	       int *wm,		/* windowing matrix */
	       double *lm,	/* local cost mtrx */
	       int *nstepsp,	/* no of steps in stepPattern */
	       double *dir,	/* stepPattern description */
				/* OUT */
	       double *cm,	/* cost matrix */
	       int *sm		/* direction mtrx */
				) {

  /* recover matrix dim */
  int n=s[0],m=s[1];		/* query,template as usual*/
  int nsteps=*nstepsp;


  /* copy steppattern description to ints,
     so we'll do indexing arithmetic on ints 
  */
  int *pn,*di,*dj;
  double *sc;

  pn=(int*) R_alloc(nsteps,sizeof(int)); /* pattern id */
  di=(int*) R_alloc(nsteps,sizeof(int)); /* delta i */
  dj=(int*) R_alloc(nsteps,sizeof(int)); /* delta j */
  sc=(double*) R_alloc(nsteps,sizeof(double)); /* step cost */

  for(int i=0; i<nsteps; i++) {
    pn[i]=dir[EP(i,0)];
    di[i]=dir[EP(i,1)];
    dj[i]=dir[EP(i,2)];
    sc[i]=dir[EP(i,3)];

    if(pn[i]<0 || pn[i]>=nsteps) {
      error("Error on pattern row %d, pattern number %d out of bounds\n",
	      i,pn[i]);
    }
  }

  /* assuming pattern ids are in ascending order */
  int npats=pn[nsteps-1];



  /* prepare a cost list per pattern */
  double *clist=(double*)
    R_alloc(npats,sizeof(double));


  /* we do not initialize the seed - the caller is supposed
     to do so
     cm[0]=lm[0];
   */


  /* lets go */
  for(int j=0; j<m; j++) {
    for(int i=0; i<n; i++) {

      /* out of window? */
      if(!wm[EM(i,j)])
	continue;

      /* already initialized? */
      if(!isnan(cm[EM(i,j)]))
	  continue;

      CLEARCLIST;
      for(int s=0; s<nsteps; s++) {
	int p=pn[s]-1;		/* indexing C-way */

	int ii=i-di[s];
	int jj=j-dj[s];
	if(ii>=0 && jj>=0) {	/* address ok? C convention */
	  double cc=sc[s];
	  if(cc==-1.0) {
	    clist[p]=cm[EM(ii,jj)];
	  } else {		/* we rely on NAN to propagate */
	    clist[p] += cc*lm[EM(ii,jj)];
	  }
	}
      }

      int minc=argmin(clist,npats);
      if(minc>-1) {
	cm[EM(i,j)]=clist[minc];
	sm[EM(i,j)]=minc+1;	/* convert to 1-based  */
      }
    }
  }


  /* Memory alloc'd by R_alloc is automatically freed */
  my_R_free(clist);
  my_R_free(sc);
  my_R_free(di);
  my_R_free(dj);
  my_R_free(pn);



}



/* return the arg min, ignoring NANs,
   -1 if all NANs */
int argmin(double *list, int n) {
  int ii=-1;
  double vv=INFINITY;
  for(int i=0; i<n; i++) {
    if(!isnan(list[i]) && list[i]<vv) {
      ii=i;
      vv=list[i];
    }
  }
  return ii;
}



/*  Unit test - made for debuggers
 ***********************************************************
*/


#ifdef TEST_UNIT

/* test main  equivalent to the following
   mylm<-outer(1:10,1:10)
   globalCostNative(mylm)->myg2
*/


#define TS 10
#define TSS (TS*TS)
int main(int argc,char **argv) {
  int ts[]={TS,TS};
  int *twm;
  double *tlm;
  int tnstepsp[]={6};
  double tdir[]={1, 1, 2, 2, 3, 3, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,-1, 1,-1, 1,-1, 1};
  double *tcm;
  int *tsm;

  int i,j;

  twm=malloc(TSS*sizeof(int));
   for( i=0;i<TSS;i++)
    twm[i]=1;

  tlm=malloc(TSS*sizeof(double));
  for( i=0;i<TS;i++)
    for( j=0;j<TS;j++)
      tlm[i*TS+j]=(i+1)*(j+1);


  tcm=malloc(TSS*sizeof(double));
  for( i=0;i<TS;i++)
    for( j=0;j<TS;j++)
      tcm[i*TS+j]=NAN;
  tcm[0]=tlm[0];

  tsm=malloc(TSS*sizeof(int));


  double r=-2;

  tm_print(ts,tlm,&r);

  /* pretend we'r R */
  computeCM(ts,twm,tlm,tnstepsp,
	    tdir,tcm,tsm);

  tm_print(ts,tcm,&r);

  free(twm);
  free(tlm);
  free(tcm);
  free(tsm);

}



 
/*
 * Printout a matrix. 
 * int *s: s[0] - no. of rows
 *         s[1] - no. of columns
 * double *mm: matrix to print
 * double *r: return value
 */

void tm_print(int *s, double *mm, double *r) {
  int i,j;
  int n=s[0],m=s[1];
  FILE *f=stdout;

  for(i=0;i<n;i++) {
    for(j=0;j<m;j++) {
      double val=mm[j*n+i];
      if(isnan(val)) {
	//	printf("NAN %d %d\n",i,j);
      }
      fprintf(f,"[%2d,%2d] = %4.2lf    ",i,j,val);
    }
    fprintf(f,"\n");
  }
  *r=-1;
  // fclose(f);
  printf("** tm dump end **\n");
}


 #endif
back to top