/* K M Briggs autocorrelation.c 
   2001 April 24; 
   revised 2003 Jun 10
   revised 2003 Sep 08
   revised 2005 Sep 12

   Online autocorrelation (no storage of data).
   Computes the ac at [0,s,2s,3s,4s,...,maxlag)
   (s=stride, default s=1)

   Input file format:
     x[1]
     x[2]
     ...
     x[m]

   Compile:
     gcc -O3 -Wall autocorrelation.c -o autocorrelation

   Usage:
      (optional dt sets time scale)
     ./autocorrelation [maxlag [stride [dt]]] < datafile
     or
     cat datafile | ./autocorrelation [maxlag [stride [dt]]]
     should give same answer as (using `delay' from TISEAN)
     cat datafile | delay -m maxlag | ./covariance maxlag

   Backup:
     mcopy -o autocorrelation.c a:
*/

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

typedef double F;

int main(int argc, char *argv[]) {
  int i,j,s=1,nl=0,m=0,lags,n=20,szdb=sizeof(F);
  double dt=1.0;
  F delta0,deltai,f,xi,*r,*mu,*zeta;
  const char *version=" "__DATE__" "__TIME__;
  if (argc>1) {
    if (argv[1][0]=='-' && argv[1][1]=='h') 
      fprintf(stderr,"Usage: %s [maxlag [stride [dt]]] < datafile\n",argv[0]), exit(0);
    n=atoi(argv[1]);
  }
  if (argc>2)  s=atoi(argv[2]);
  if (argc>3) dt=atof(argv[3]);
  if (s<1 || s>n) s=1;
  fprintf(stderr,"%s: K M Briggs %s\nmaximum lag=%d, stride=%d, dt=%f, ",argv[0],version,n,s,dt);
  if (n<1) 
    fprintf(stderr,"maxlag \n%d is too small\n",n), exit(1);
  lags=n/s;
  r   =malloc(   n*szdb); /* ring buffer */
  mu  =malloc(lags*szdb); /* means */
  zeta=malloc(lags*szdb); /* sums of squares */
  for (i=0; i<lags; i++) zeta[i]=mu[i]=0.0;
  for (i=0; i<n-1; i++) { /* preload the ring buffer */
    if (EOF==scanf("%lf",&xi))
      fprintf(stderr,"not enough data\n"), exit(2);
    r[nl++]=xi;
  }
  while (EOF!=scanf("%lf",&r[j=(nl%n)])) {
    m++;
    f=(m-1.0)/m;
    //f=1.0-1.0/m; // roundoff ??
    delta0=r[(j+1)%n]-mu[0];
    mu[0]+=delta0/m;
    zeta[0]+=f*delta0*delta0;
    for (i=1; i<lags; i++) {
      deltai=r[(j+s*i+1)%n]-mu[i];
      mu[i]+=deltai/m;
      zeta[i]+=f*delta0*deltai;
    }
    nl++;
  }
  fprintf(stderr,"%d rows read\n",nl);
  if (m<2)
    fprintf(stderr,"not enough data\n"), exit(1);
  fprintf(stderr,"autocorrelation:\n");
  dt*=s;
  for (i=0; i<lags; i++)
    printf("%f %10.5lg\n",dt*i,zeta[i]/zeta[0]);
  return 0;
}
