home *** CD-ROM | disk | FTP | other *** search
- /*
- NAME
- smooth - split linear smoothing
-
- SYNOPSIS
- smooth [file] [options]
-
- options are:
- -a [step [start]] automatic abscissas
- -b break smooth after each label
- -c general curve
- -f <num> fraction of points to use for each fitted value
- (default .5)
- -n <num> number of points to use for each fitted value
- (default 50%)
- -r print residuals rather than smoothed values
- -s split linear fit rather than "lowness"
- -xl take logs of x values before smoothing
- -yl take logs of y values before smoothing
- -zl take logs of z values before interpolating
- (implies -3)
- -3 3D case: x, y, and z given for each point
-
- Default smoothing method is "lowness": robust locally weighted
- regression & smoothing
-
- METHODS
- Lowness by W. S. Cleveland, and split linear fit by A. Owen
-
- AUTHOR
- James Van Zandt (jrv@mbunix.mitre.org)
-
- */
-
- #include <stdio.h>
- #include <math.h>
-
- #define VERSION "1.10"
-
- #define MAX_WINDOWS 6
- #define MAX_POINTS 800
- #define MAXLABELS 25
-
- int resid=0; /* nonzero if residuals are requested */
- int fraction_specified=1; /* nonzero if fit is to a specified fraction of
- the given data points */
- int number_specified=0; /* nonzero if fit is to a specified number of
- the given data points */
- double fraction_fitted=.5; /* fraction of points used for each fitted value */
- int num_fitted; /* number of points used for each fitted value */
-
- char *gmem();
-
- /*
- Split Linear Smoothing Algorithm
-
- Given:
- A list of window sizes, SizeList, and n pairs (x[i],y[i]) sorted on x,
-
- Return:
- the split linear smooth of y on x.
-
-
- The general technique is due to Art Owen, who offers this discussion:
-
- "You should feel free to experiment with the algorithm,
- since it has some ad hoc parts. The essentials are: to use
- uncentered windows of varying sizes along with the central
- ones, to get zero weight on the worst fitting lines, and to
- make the weight attached to a particular line size and
- orientation vary smoothly as one traverses the data. We
- tried to find a simple way to meet all of these goals; the
- algorithm we settled on was the simplest that worked for
- us.
- ...
-
- "West and Chan et. al. are useful for getting numerically
- stable updating formulae for the regressions."
-
- references...
-
- John Alan McDonald and Art B. Owen, "Smoothing with Split
- Linear Fits", LCS Technical Report No. 7, SLAC-PUB 3423,
- AD-A149032, Laboratory for Computational Statistics, Dept.
- of Statistics, Stanford University, July 1984.
-
-
- West, D.H.D., 1979, Updating Mean and Variance Estimates:
- An Improved Method, Communications of the ACM, v 22, no. 9
- p 532-535 (1979).
-
- Chan, T.F., Golub, G.H., and Leveque, R.J., 1983,
- Algorithms for Computing the Sample Variance: Analysis and
- Recommendations, The American Statistician v 37, p 242-247
- (1983).
-
- IMPLEMENTATION
- For general curves, the given x- and y- (and z-, if present)
- points are regarded as functions of the distance along a
- smoothed path.
-
- The arrays take a lot of space. For n points, the number of
- doubles is approximately 38*n, plus 2*n for general curve, plus
- 2*n for 3D case. For 100 points and 8 byte doubles, this means
- at least 8*38*100=30400 bytes.
-
- Execution time... 101 points took 151 seconds on 7.5 MHz V-20,
- no 8087.
-
-
- The updating formulas mentioned above are not used in this
- program. The selection of window sizes (a geometric sequence)
- is my own. -JVZ
-
- */
-
- SplitLinearSmooth(SizeList,x,y,Smooth) int SizeList; double Smooth[],x[],y[];
- { int i;
- BasicSplitLinearSmooth( SizeList, x, y, Smooth );
- BasicSplitLinearSmooth( SizeList, x, Smooth, Smooth );
- if(resid)
- for (i=0; i<SizeList; i++)
- Smooth[i] = y[i]-Smooth[i];
- }
-
- /*
- Basic Split Linear Smooth Algorithm by Art Owen <owen@su-score>
-
- Given:
- A list of window sizes and n pairs (x[i],y[i]) sorted on x,
-
- Return:
- the basic split linear smooth of y on x.
- */
- #define f(x,y,z) ff[((x)*sizes+(y))*3+(z)]
- #define pmse(x,y,z) errors[((x)*sizes+(y))*3+(z)]
- #define left 0
- #define center 1
- #define right 2
-
- static double *ff, *errors;
-
- BasicSplitLinearSmooth(n, x, y, Smooth) int n; double x[], y[], Smooth[];
- { int k, C, L, R, i, sizes, num, start, finish, o, ws;
- int window_size[MAX_WINDOWS];
- double err, del, alpha, beta, w_total, w, s, c;
- double sum, sumx, sumxx, sumy, sumxy;
-
- /*
- window sizes must be _odd_ in this implementation
- sizes are: 5, 11, 23, 47, ... 6*2^k-1
- or else: 7, 15, 31, 63, ... 8*2^k-1
- depending on the maximum number of points to be fitted
- */
- for (i = num_fitted+1; i >= 8; i/=2) {}
- if(i >= 6) i=6; else i=8;
- for (sizes=0; i-1 <= num_fitted && sizes < MAX_WINDOWS; i *= 2)
- window_size[sizes++]=i-1;
-
- /* most of the memory is allocated by these two statements */
- ff=(double *)gmem(n*sizes*3*sizeof(double));
- errors=(double *)gmem(n*sizes*3*sizeof(double));
- for (k=0; k<sizes; k++)
- {sum=sumx=sumxx=sumy=sumxy=0.;
- /* Initialize the regression-window data structure */
- ws=window_size[k];
- C = -(ws/2);
- L = C - ws/2;
- R = C + ws/2;
- for ( ; L<n ; L++, C++, R++)
- {
- if ( R < n )
- {/* update the regression-window with (x[R],y[R]) */
- /* Update routines are described in West (1979) */
- /* these are my guesses -JVZ */
- sum+=1.; sumx+=x[R]; sumxx+=x[R]*x[R];
- sumy+=y[R]; sumxy+=x[R]*y[R];
- }
- if ( L-1 >= 0 )
- {/* downdate the regression-window with (x[L-1],y[L-1]) */
- sum-=1.; sumx-=x[L-1]; sumxx-=x[L-1]*x[L-1];
- sumy-=y[L-1]; sumxy-=x[L-1]*y[L-1];
- }
- if ( sum>=ws ) /* the window covers enough points */
- {/* Fit linear regression coefs. alpha, beta */
- alpha=(sumy*sumxx - sumx*sumxy)/(sum*sumxx - sumx*sumx);
- beta=(sumxy - alpha*sumx)/sumxx;
- if ( 0 <= R && R < n )
- {f(R,k,left)= alpha + beta*x[R];
- /* compute pmse(R,k,left) */
- /*
- pmse(i,k,o) =
- ( sum{j in W(i,k,o)-{i}} (y[j]-alpha-beta*x[j])^2) / ( |W(i,k,o)|-3 )
- where W is the window of points.
- */
- start=R-ws;
- if(start<0) start=0;
- if(R-start>3)
- {err=0.;
- for (i=start; i<R; i++)
- {del = y[i]-alpha-beta*x[i];
- err += del*del;
- }
- pmse(R,k,left) = err/(R-start-3);
- }
- }
- if ( 0 <= C && C < n )
- {f(C,k,center)= alpha + beta*x[C];
- /* compute pmse(C,k,center) */
- start=C-ws/2;
- if(start<0) start=0;
- finish=C+ws/2+1;
- if(finish>n) finish=n;
- if(finish-start>3)
- {err=0.;
- for (i=start; i<finish; i++)
- {if(i==C) continue;
- del = y[i]-alpha-beta*x[i];
- err += del*del;
- }
- pmse(C,k,center) = err/(finish-start-3);
- }
- }
- if ( 0 <= L )
- {f(L,k,right)= alpha + beta*x[L];
- /* compute pmse(L,k,right) */
- err=0.;
- finish=L+ws;
- if(finish>n) finish=n;
- if(finish-L>3)
- {for (i=L; i<finish; i++)
- {del = y[i]-alpha-beta*x[i];
- err += del*del;
- }
- pmse(L,k,right) = err/(finish-L-3);
- }
- }
- }
- else /* window doesn't cover enough points */
- {if( R<n ) pmse(R,k,left) = -1;
- if( 0<=C && C<n ) pmse(C,k,center) = -1;
- if( 0<=L ) pmse(L,k,right) = -1;
- }
- }
- }
- for (i=0; i<n; i++)
- {/* pmse cutoff: c = Average{k,o} pmse(i,k,o) */
- err=0.;
- num=0;
- for (k=0; k<sizes; k++)
- for (o=0; o<3; o++)
- if(pmse(i,k,o)>=0.) {err += pmse(i,k,o); num++;}
- c=err/num;
- s = w_total = 0.;
- for (k=0; k<sizes; k++)
- for (o=0; o<3; o++)
- {err=pmse(i,k,o);
- if(err>=0. && err<c) /* pmse is present, and below cutoff */
- {w = (err-c)*(err-c);
- s += w*f(i,k,o);
- w_total += w;
- }
- }
- /* Smooth[i] = sum{k,o} w(i,k,o)*f(i,k,o) / sum{k,o} w(i,k,o) */
- Smooth[i]=s/w_total;
- }
- free(errors);
- free(ff);
- }
-
- double abscissa=0.;
- double abscissa_step=1.;
- double *x, *y, *z, *xs, *ys, *zs, *path;
-
- int xlog=0; /* nonzero if taking log of x values */
- int ylog=0; /* nonzero if taking log of y values */
- int zlog=0; /* nonzero if taking log of z values */
- int debugging=0;
- int split=0; /* nonzero if split linear smooth is requested */
- int breaking=0; /* nonzero if breaking at labels */
- int labels=0; /* number of labels in input data */
- int threed=0; /* nonzero if 3D case (x, y, and z given for each point) */
- int automatic_abscissas=0;
- int abscissa_arguments=0;
- int curve=0; /* nonzero if general curve permitted */
- int x_arguments=0;
- int n; /* number of MAX_POINTS in x, y, and ys */
- int index_array[MAXLABELS]; /* indexes into x and y */
- int *p_data=index_array;
- int total=100;
-
- FILE *ifile;
-
- char *label_array[MAXLABELS];
- char **p_text=label_array;
-
- main(argc,argv) int argc; char **argv;
- { int nn,origin;
- read_data(argc,argv);
-
- /* check switch arguments */
- if(fraction_specified)
- {if(fraction_fitted<0. || fraction_fitted>1.)
- {fprintf(stderr, "fraction fitted=%f must be in range 0 to 1\n",
- fraction_fitted);
- exit(1);
- }
- num_fitted = floor(fraction_fitted*n+.5);
- }
- nn = 1;
- if(split) nn = 11;
- if(num_fitted < nn || num_fitted > n)
- {fprintf(stderr, "number of points fitted=%d must be in range %d...%d",
- num_fitted, nn, n);
- exit(1);
- }
-
- if(breaking && labels)
- {origin=0;
- while(labels--)
- {p_data[0] -= origin;
- nn=p_data[0]+1;
- if(nn) curv0(nn,total);
- origin += nn;
- path += nn;
- x += nn;
- y += nn;
- p_data++;
- p_text++;
- }
- }
- else
- {curv0(n,total);
- }
- exit(0);
- }
-
- curv0(n,requested)
- int n,requested;
- { int i, j, each, stop, seg=0;
- double s, ds, xx, yy, zz;
- if(n<5) /* just copy a short file */
- {for (j=0; j<n; j++)
- {if(!automatic_abscissas)
- {xx=x[n-1]; if(xlog) xx=exp(xx);
- printf("%g ", xx);
- }
- yy=y[n-1]; if(ylog) yy=exp(yy);
- printf("%g ", yy);
- if(threed)
- {zz=z[n-1]; if(zlog) zz=exp(zz);
- printf("%g ",zz);
- }
- if(j==p_data[seg]) printf(p_text[seg++]);
- putchar('\n');
- }
- return;
- }
- if(split)
- {if(curve)
- {SplitLinearSmooth( n, path, x, xs);
- SplitLinearSmooth( n, path, y, ys);
- if(threed) SplitLinearSmooth(n, path, z, zs);
- }
- else
- {SplitLinearSmooth( n, x, y, ys);
- if(threed) SplitLinearSmooth( n, x, z, zs);
- }
- }
- else /* lowness smooth */
- {if(curve)
- {lowness( n, path, x, xs);
- lowness( n, path, y, ys);
- if(threed) lowness(n, path, z, zs);
- }
- else
- {lowness( n, x, y, ys);
- if(threed) lowness( n, x, z, zs);
- }
- }
- for (j=0; j<n; j++)
- {if(!automatic_abscissas)
- {xx = curve ? xs[j] : x[j];
- printf("%g ", xlog ? exp(xx) : xx);
- }
- printf("%g ", ylog ? exp(ys[j]) : ys[j] );
- if(threed) printf("%g ", zlog ? exp(zs[j]) : zs[j] );
- if(j==p_data[seg]) printf(p_text[seg++]);
- putchar('\n');
- }
- }
-
- double mylog(x) double x;
- { if(x<=0.)
- {fprintf(stderr, "can\'t take log of %f\n", x);
- exit(1);
- }
- return log(x);
- }
-
- read_data(argc,argv) int argc; char **argv;
- { int i, j, length, skipping, ac;
- double xx, yy, zz, d, *pd, sum, xp, yp, zp, xq, yq, zq;
- char *s,*t, **av, *strchr();
- #define BUFSIZE 256
- static char buf[BUFSIZE+2];
-
- argc--; argv++;
- ac=argc; av=argv; argc=0;
- while(ac>0)
- {if(**av=='?') help();
- else if(**av=='-' && (i=get_parameter( ac, av )) && i > 0)
- {ac-=i; av+=i;
- }
- else {argv[argc++] = *av++; ac--;}
- }
-
- if(argc<1 || **argv=='-') ifile=stdin;
- else
- {if(argc>=1)
- {ifile=fopen(argv[0],"r");
- if(ifile==NULL) {printf("file %s not found\n",argv[0]); exit(1);}
- argc--; argv++;
- }
- else help();
- }
- x=path=(double *)gmem(MAX_POINTS*sizeof(double));
- y=(double *)gmem(MAX_POINTS*sizeof(double));
- if(threed) z=(double *)gmem(MAX_POINTS*sizeof(double));
- p_data[0]=-1;
- skipping=2;
- if(automatic_abscissas) skipping--;
- if(threed) skipping++;
- i=0;
- while(i<MAX_POINTS)
- {if(fgets(buf,BUFSIZE,ifile)==0)break;
- buf[strlen(buf)-1]=0; /* zero out the line feed */
- if(buf[0]==';') {printf("%s\n",buf); continue;} /* skip comment */
- if(t = strchr(buf, ';')) *t=0; /* zap same-line comment */
- for (t=buf; *t && isspace(*t); t++) {} /* find first nonblank char */
- if(*t == 0) continue; /* skip blank lines */
- if(automatic_abscissas)
- {x[i]=abscissa;
- abscissa+=abscissa_step;
- if(threed) sscanf(buf,"%lf %lf",&y[i],&z[i]);
- else sscanf(buf,"%lf",&y[i]);
- if(ylog) y[i]=mylog(y[i]);
- if(zlog) z[i]=mylog(z[i]);
- }
- else
- {if(threed) sscanf(buf,"%lf %lf %lf",&x[i],&y[i],&z[i]);
- else sscanf(buf,"%lf %lf",&x[i],&y[i]);
- if(xlog) x[i]=mylog(x[i]);
- if(ylog) y[i]=mylog(y[i]);
- if(zlog) z[i]=mylog(z[i]);
- }
- s=buf; /* start looking for label */
- for (j=skipping; j--; )
- {while(*s==' ')s++; /* skip a number */
- while(*s && (*s!=' '))s++;
- }
- while(*s==' ')s++;
- if((length=strlen(s))&&(labels<MAXLABELS))
- {if(*s=='\"') /* label in quotes */
- {t=s+1;
- while(*t && (*t!='\"')) t++;
- t++;
- }
- else /* label without quotes */
- {t=s;
- while(*t && (*t!=' '))t++;
- }
- *t=0;
- length=t-s;
- p_data[labels]=i;
- p_text[labels]=gmem(length+1);
- if(p_text[labels]) strcpy(p_text[labels++],s);
- }
- i++;
- }
- n=i;
- if(n <= 1) {fprintf(stderr, "too little data"); exit(1);}
- if(breaking && (!labels || p_data[labels-1]!=n-1))
- {p_data[labels]=i-1;
- if(p_text[labels]=gmem(1)) *p_text[labels++]=0;
- }
- ys=(double *)gmem(n*sizeof(double));
- if(threed) zs=(double *)gmem(n*sizeof(double));
- if(curve)
- {xs=(double *)gmem(n*sizeof(double));
- path=(double *)gmem(n*sizeof(double));
- path[0]=sum=0.;
- if(threed)
- {xp=4.*x[0]; yp=4.*y[0]; zp=4.*z[0];
- for (i=1; i<n; i++)
- {xq=x[i-1]+2.*x[i]+x[i+1];
- yq=y[i-1]+2.*y[i]+y[i+1];
- zq=z[i-1]+2.*z[i]+z[i+1];
- xx=xq-xp;
- yy=yq-yp;
- zz=zq-zp;
- path[i]=(sum+=sqrt(xx*xx + yy*yy + zz*zz));
- xp=xq; yp=yq; zp=zq;
- }
- xq=4.*x[n-1]; yq=4.*y[n-1]; zq=4.*y[n-1];
- xx=xq-xp;
- yy=yq-yp;
- zz=zq-zp;
- path[i]=(sum+=sqrt(xx*xx + yy*yy + zz*zz));
- }
- else
- {xp=4.*x[0]; yp=4.*y[0];
- for (i=1; i<n-1; i++)
- {xq=x[i-1]+2.*x[i]+x[i+1];
- yq=y[i-1]+2.*y[i]+y[i+1];
- xx=xq-xp;
- yy=yq-yp;
- path[i]=(sum+=sqrt(xx*xx + yy*yy));
- xp=xq; yp=yq;
- }
- xq=4.*x[n-1]; yq=4.*y[n-1];
- xx=xq-xp;
- yy=yq-yp;
- path[i]=(sum+=sqrt(xx*xx + yy*yy));
- }
- }
- else if(split)
- {for(i=1; i<n; i++)
- {if(x[i]<=x[i-1])
- {fprintf(stderr,
- "ERROR: independent variable not strictly increasing\n");
- exit(1);
- }
- }
- }
- else
- {for(i=1; i<n; i++)
- {if(x[i]<x[i-1])
- {fprintf(stderr,
- "ERROR: data must be sorted on x value\n");
- exit(1);
- }
- }
- }
- }
-
-
- /* get_parameter - process one command line option
- (return # parameters used) */
- get_parameter(argc,argv) int argc; char **argv;
- { int i, permitted;
- double temp;
- if(strcmp(*argv,"-a")==0)
- {automatic_abscissas=1;
- if(argc<2 || *argv[1]=='-') return 1; /* no negative step */
- permitted=2;
- if(argc<3 || *argv[2]=='-') permitted=1; /* no neg. starting abscissa */
- i=get_double(argc,argv,permitted,&abscissa_step,&abscissa,&abscissa);
- abscissa_arguments=i-1;
- return i;
- }
- else if(strcmp(*argv, "-f")==0)
- {i=get_double(argc, argv, 1, &fraction_fitted, &fraction_fitted, &fraction_fitted);
- fraction_specified=1;
- number_specified=0;
- return i;
- }
- else if(strcmp(*argv, "-n")==0)
- {i=get_double(argc, argv, 1, &temp, &temp, &temp);
- fraction_specified=0;
- number_specified=1;
- num_fitted = temp;
- return i;
- }
- else if(strcmp(*argv, "-b")==0) {breaking=1; return 1;}
- else if(strcmp(*argv, "-c")==0) {curve=1; return 1;}
- else if(strcmp(*argv, "-d")==0) {debugging=1; return 1;}
- else if(strcmp(*argv, "-r")==0) {resid=1; return 1;}
- else if(strcmp(*argv, "-s")==0) {split=1; return 1;}
- else if(strcmp(*argv,"-xl")==0) {xlog++; return 1;}
- else if(strcmp(*argv,"-yl")==0) {ylog++; return 1;}
- else if(strcmp(*argv,"-zl")==0) {zlog++; threed++; return 1;}
- else if(strcmp(*argv, "-3")==0) {threed++; return 1;}
- else gripe(argv);
- }
-
- get_double(argc,argv,permitted,a,b,c)
- int argc,permitted; char **argv; double *a,*b,*c;
- { int i=1;
- if((permitted--)>0 && (argc>i) && numeric(argv[i])) *a=atof(argv[i++]);
- if((permitted--)>0 && (argc>i) && numeric(argv[i])) *b=atof(argv[i++]);
- if((permitted--)>0 && (argc>i) && numeric(argv[i])) *c=atof(argv[i++]);
- return i;
- }
-
- gripe_arg(s) char *s;
- { fprintf(stderr,"argument missing for switch %s",s);
- help();
- }
-
- gripe(argv) char **argv;
- { fprintf(stderr,*argv); fprintf(stderr," isn\'t a legal argument \n\n");
- help();
- }
-
- char *msg[]=
- {"smooth version ", VERSION, "\n",
- "\nusage: smooth [file] [options]\n",
- "options are:\n",
- " -a [step [start]] automatic abscissas \n",
- " -b break smooth after each label \n",
- " -c general curve \n",
- " -f <num> fraction of points to use for each fitted value (default .5)\n",
- " -n <num> number of points to use for each fitted value (default 50%%)\n",
- " -r print residuals rather than smoothed values\n",
- " -s split linear fit rather than \"lowness\"\n",
- " -xl take logs of x values before smoothing \n",
- " -yl take logs of y values before smoothing \n",
- " -zl take logs of z values before interpolating \n",
- " (implies -3)\n",
- " -3 3D case: x, y, and z given for each point\n",
- "\n",
- "Default smoothing method is \"lowness\": robust locally weighted \n",
- "regression & smoothing \n",
- 0
- };
-
- help()
- { char **s;
- s=msg;
- while(*s) printf(*s++);
- exit(1);
- }
-
- numeric(s) char *s;
- { char c;
- while(c=*s++)
- {if((c<='9' && c>='0') || c=='+' || c=='-' || c=='.') continue;
- return 0;
- }
- return 1;
- }
-
- char *gmem(size) unsigned int size;
- { char *p;
- void *malloc();
- p=(char *)malloc(size);
- if(!p)
- {fprintf(stderr,"can\'t allocate temporary storage of %u\n",size);
- exit(1);
- }
- return p;
- }
-
- fpcompare(r, s) double *r, *s;
- { double d;
- d=*r-*s;
- if(d<0.) return -1;
- if(d>0.) return 1;
- return 0;
- }
-
- /*
- Lowness
-
- Robust locally weighted regression is a method for smoothing a
- scatterplot, (x[i], y[i]), i=1,...,n, in which the fitted value
- at x[k] is the value of a polynomial fit to the data using
- weighted least squares, where the weight for (x[i], y[i]) is
- large if x[i] is close to x[k]. Robustness is added by
- calculating residuals and repeating the procedure with reduced
- weights on points with large residuals.
-
- Reference:
- W. S. Cleveland, "Robust Locally Weighted Regression and
- Smoothing Scatterplots", Journal of the American Statistical
- Association, v74, n368, p829 (Dec 79)
-
- */
-
- lowness(n, x, y, ys) int n; double *x, *y, *ys;
- { double *t, *r, *w, d, d1, u, m, m6i, sum, a[2];
- int i, j, k;
-
- num_fitted=floor(fraction_fitted*n+.5);
- t=(double *)gmem(num_fitted*sizeof(double));
- r=w=(double *)gmem(n*sizeof(double)); /* r and w share space */
- k=0;
- for (i=0; i<n; i++)
- {if(i==0 || x[i]!=x[i-1])
- {while(k+num_fitted<n && (x[i]-x[k] > x[k+num_fitted]-x[i])) k++;
- d=x[i]-x[k]; d1=x[k+num_fitted-1]-x[i];
- if(d1>d) d=d1;
- if(d==0.)
- {sum=0.;
- for (j=0; j<num_fitted; j++) sum += y[i+j];
- a[0]=sum/num_fitted; a[1]=0.;
- }
- else
- {for (j=0; j<num_fitted; j++) /* calculate tricube weighting */
- {u=fabs(x[i]-x[k+j])/d; u=1.-u*u*u; t[j]=u*u*u;
- }
- lin(num_fitted, x+k, t, y+k, a);
- }
- }
- ys[i]=r[i]=fabs(y[i]-(a[0]+a[1]*x[i]));
- }
- /* sorting to find median value - although it's overkill */
- qsort(ys, n, sizeof(double), fpcompare);
- m=ys[n/2];
- if(m==0.) /* input function is already linear - can't smooth any more */
- {for (i=0; i<n; i++) ys[i]=y[i];
- free(t); free(w);
- return;
- }
- m6i=1./(6.*m);
- for (i=0; i<n; i++)
- {u=r[i]*m6i;
- if(u<1.) {u=1.-u*u; w[i]=u*u;}
- else w[i]=0.;
- }
- k=0;
- for (i=0; i<n; i++)
- {if(i==0 || x[i]!=x[i-1])
- {while(k+num_fitted<n && (x[i]-x[k] > x[k+num_fitted]-x[i])) k++;
- d=x[i]-x[k]; d1=x[k+num_fitted-1]-x[i];
- if(d1>d) d=d1;
- if(d==0.)
- {sum=0.;
- for (j=0; j<num_fitted; j++) sum += y[i+j];
- a[0]=sum/num_fitted; a[1]=0.;
- }
- else
- {for (j=0; j<num_fitted; j++) /* calculate tricube weighting */
- {u=fabs(x[i]-x[k+j])/d; u=1.-u*u*u; t[j]=u*u*u*w[k+j];
- }
- lin(num_fitted, x+k, t, y+k, a);
- }
- }
- ys[i]=a[0] + a[1]*x[i];
- if(resid) ys[i]=y[i]-ys[i];
- }
- free(t); free(w);
- }
-
- /* lin - linear least squares fit */
-
- lin(n, x, w, y, a)
- int n; /* # points in x, w, or y */
- double *x, /* independent variables */
- *w, /* weights */
- *y, /* dependent variables */
- *a; /* resulting coeficients... y[i] = a[1]*x[i] + a[0] (approx) */
- { int i, j;
- double sum, sumx, sumxx, sumy, sumxy, xw, cond, decomp();
- static double d[2][2];
- static int ipvt[2];
-
- sum=sumx=sumxx=sumy=sumxy=0.;
- for (i=0; i<n; i++)
- {sum += *w;
- sumx += (xw = *x * *w);
- sumxx += *x * xw;
- sumy += *y * *w;
- sumxy += *y * xw;
- x++; y++; w++;
- }
- d[0][0]=sum; d[0][1]=sumx; a[0]=sumy;
- d[1][0]=sumx; d[1][1]=sumxx; a[1]=sumxy;
- cond=decomp(2, 2, d, ipvt);
- if(cond==(cond+1.))
- {fprintf(stderr, "ill conditioned matrix");
- /********
- **********/
- showv("x=", x-n, n);
- showv("w=", w-n, n);
- showv("y=", y-n, n);
- printf("cond=%9.3e\n", cond);
- exit(1);
- }
- solve(2, 2, d, a, ipvt);
- }
-
- showv(s,a,n) char *s; double a[]; int n;
- { int i,j;
- printf("%s \n",s);
- for (i=0; i<n; i++)
- {printf("%8.4f ",a[i]);
- if(i%8==7) printf("\n");
- }
- printf("\n");
- }
-