TPCCLIB
Loading...
Searching...
No Matches
llsqwt.c
Go to the documentation of this file.
1
5/******************************************************************************/
6#include "libtpcmodel.h"
7/******************************************************************************/
8/* Local function definitions */
10int _medianline_cmp(const void *e1, const void *e2);
12/******************************************************************************/
13
14/******************************************************************************/
50 double *x,
52 double *y,
54 int n,
56 double *wx,
58 double *wy,
60 double tol,
61 /* Input/output */
63 double *w,
64 /* Output */
66 double *ic,
68 double *slope,
70 double *nwss,
73 double *sic,
76 double *sslope,
79 double *cx,
82 double *cy
83) {
84 int i, j, niter=0, nn, calcVar=1;
85 double c, m, f, xb=0.0, yb=0.0, qa=0.0, qb=0.0, qc, ss=0.0, s1, s2, wsum=0.0;
86 double xsum=0.0, x2sum=0.0, ysum=0.0, xysum=0.0, delta, discr, sqdis;
87 double m_1, m_2, bcont, m2=0.0, w2;
88 double u, v, AA, BB, CC, DD, EE, FF, GG, HH, JJ;
89 double varc, varm, dmx, dmy, dcx, dcy;
90
91
92 /*
93 * Lets look what we got for arguments
94 */
95 if(0) {fprintf(stdout, "llsqwt()\n"); fflush(stdout);}
96 /* Check that there is some data */
97 if(n<2) return(1);
98 if(0) {
99 for(i=0; i<n; i++) printf("%e +- %e %e +- %e\n",
100 x[i], wx[i], y[i], wy[i]);
101 }
102 if(tol<1.0e-100) return(1);
103 if(w==NULL) return(1);
104 /* Check if variances and fitted data will be calculated */
105 if(sic==NULL || sslope==NULL || cx==NULL || cy==NULL) calcVar=0;
106 else calcVar=1;
107
108 /* If only 2 datapoints */
109 if(n==2) {
110 f=x[1]-x[0];
111 if(f==0.0) {*slope=*ic=*sic=*sslope=*nwss=w[0]=w[1]=0.0; return(0);}
112 *slope=(y[1]-y[0])/f; *ic=y[0]-(*slope)*x[0];
113 *sic=*sslope=0.; w[0]=1.0; w[1]=1.0; *nwss=0.0;
114 return(0);
115 }
116
117 /*
118 * Fit the LLSQ line
119 */
120
121 /* First estimation of the slope and intercept by unweighted regression */
122 for(i=0; i<n; i++) {
123 xsum+=x[i]; ysum+=y[i]; x2sum+=x[i]*x[i]; xysum+=x[i]*y[i];
124 }
125 delta=(double)n*x2sum - xsum*xsum;
126 /* Initial guesses of the slope and intercept */
127 if(delta==0.0) {
128 if(0) printf("x axis values contain only zeroes.\n");
129 *slope=*ic=*sic=*sslope=*nwss=w[0]=w[1]=0.0;
130 return(0);
131 }
132 m=((double)n*xysum - xsum*ysum)/delta;
133 c=(x2sum*ysum - xsum*xysum)/delta;
134 if(0) printf("initial guesses: a=%e b=%e\n", c, m);
135
136 /* Begin the iterations */
137 bcont=m+2.0*tol;
138 while(fabs(m-bcont)>tol && niter<20) {
139 if(0) printf(" %d. iteration, improvement=%g, tol=%g\n", niter, fabs(m-bcont), tol);
140 bcont=m; niter++;
141 /* Compute the weighting factors */
142 m2=m*m;
143 for(i=0, nn=0; i<n; i++) {
144 if(wx[i]<=0.0 || wy[i]<=0.0) w[i]=0.0;
145 else {w[i]=wx[i]*wy[i]/(m2*wy[i]+wx[i]); nn++;}
146 //printf("wx[i]=%g wy[i]=%g -> w[%d]=%g\n", wx[i], wy[i], i, w[i]);
147 }
148 if(nn<2) {
149 if(0) printf("less than two points with weight > 0.\n");
150 *slope=*ic=*sic=*sslope=*nwss=0.0;
151 return(0);
152 }
153 /* Compute the barycentre coordinates */
154 for(i=0, xb=yb=wsum=0.0; i<n; i++) {xb+=w[i]*x[i]; yb+=w[i]*y[i]; wsum+=w[i];}
155 if(wsum<=0.0) return(2);
156 xb/=wsum; yb/=wsum;
157 if(0) printf("barycentre: xb=%g yb=%g\n", xb, yb);
158 /* Estimate the slope as either of the roots of the quadratic */
159 /* compute the coefficients of the quadratic */
160 for(i=0, qa=qb=qc=0.0; i<n; i++) if(w[i]>0.0) {
161 u=x[i]-xb; v=y[i]-yb; w2=w[i]*w[i];
162 qa += w2*u*v/wx[i];
163 qb += w2*(u*u/wy[i] - v*v/wx[i]);
164 qc += -w2*u*v/wy[i];
165 }
166 if(0) printf("quadratic coefs: qa=%g qb=%g qc=%g\n", qa, qb, qc);
167 if(qa==0.0) {
168 m=0.0;
169 /* Calculate WSS */
170 for(i=0, ss=0.0; i<n; i++) {f=v=y[i]-yb; ss+=w[i]*f*f;}
171 } else if(qa==1.0) { /* check if quadratic reduces to a linear form */
172 m=-qc/qb;
173 /* Calculate WSS */
174 for(i=0, ss=0.0; i<n; i++) {u=x[i]-xb; v=y[i]-yb; f=v-m*u; ss+=w[i]*f*f;}
175 } else {
176 /* discriminant of quadratic */
177 discr=qb*qb-4.0*qa*qc; if(discr<=0.0) sqdis=0.0; else sqdis=sqrt(discr);
178 /* compute the two solutions of quadratic */
179 m_1=(-qb+sqdis)/(2.0*qa); m_2=(-qb-sqdis)/(2.0*qa);
180 /* Calculate WSS for both solutions */
181 for(i=0, s1=s2=0.0; i<n; i++) {
182 u=x[i]-xb; v=y[i]-yb;
183 f=v-m_1*u; s1+=w[i]*f*f;
184 f=v-m_2*u; s2+=w[i]*f*f;
185 }
186 /* choose the solution with lower WSS */
187 if(s1<=s2) {m=m_1; ss=s1;} else {m=m_2; ss=s2;}
188 }
189 /* Calculate the intercept */
190 c = yb - m*xb;
191 if(0) printf("iterated parameters: c=%e m=%e\n", c, m);
192
193 } /* end of iteration loop */
194 *ic=c; *slope=m; *nwss=sqrt(ss)/wsum; /* Set function return values */
195 if(0) {
196 fprintf(stdout, "c=%14.7e m=%14.7e ss=%14.7e niter=%d\n", c, m, ss, niter);
197 }
198
199 /* Return here, if variances are not to be calculated */
200 if(!calcVar) return(0);
201
202 /*
203 * Calculate the fitted line
204 */
205 for(i=0; i<n; i++) {
206 if(w[i]>0.0) {
207 f=w[i]*(c + m*x[i] - y[i]); /* Lagrangian multiplier */
208 cx[i]=x[i]-f*m/wx[i]; cy[i]=y[i]+f/wy[i];
209 } else {
210 cx[i]=x[i]; cy[i]=y[i];
211 }
212 }
213
214 /*
215 * Estimate the variances of the parameters (Reed 1992)
216 */
217 /* varm = var of slope ; varc = var of intercept */
218
219 /* Use the true nr of data points, i.e. exclude the ones with zero weight */
220 for(i=nn=0; i<n; i++) if(w[i]>0.0) nn++;
221 if(nn<3) {*sslope=*sic=0.0; return(0);}
222
223 /* Compute the barycentre coordinates again from computed data points */
224 for(i=0, xb=yb=wsum=0.0; i<n; i++) {xb+=w[i]*cx[i]; yb+=w[i]*cy[i]; wsum+=w[i];}
225 if(wsum<=0.0) return(2);
226 xb/=wsum; yb/=wsum;
227 if(0) printf("barycentre: xb=%g yb=%g\n", xb, yb);
228
229 /* common factors */
230 HH=JJ=qa=qb=qc=0.0;
231 for(i=0; i<n; i++) if(w[i]>0.0) {
232 u=cx[i]-xb; v=cy[i]-yb; w2=w[i]*w[i];
233 qa += w2*u*v/wx[i];
234 qb += w2*(u*u/wy[i] - v*v/wx[i]);
235 qc += -w2*u*v/wy[i];
236 HH += w2*v/wx[i];
237 JJ += w2*u/wx[i];
238 }
239 HH*=-2.0*m/wsum; JJ*=-2.0*m/wsum;
240 if(0) printf("quadratic coefs: qa=%g qb=%g qc=%g ; HH=%g JJ=%g\n", qa, qb, qc, HH, JJ);
241 AA=BB=CC=0.0;
242 for(i=0; i<n; i++) if(w[i]>0.0) {
243 u=cx[i]-xb; v=cy[i]-yb; w2=w[i]*w[i];
244 AA += w[i]*w[i]*w[i]*u*v / (wx[i]*wx[i]);
245 BB -= w2 * (4.0*m*(w[i]/wx[i])*(u*u/wy[i]-v*v/wx[i]) - 2.0*v*HH/wx[i] + 2.0*u*JJ/wy[i]);
246 CC -= (w2/wy[i]) * (4.0*m*w[i]*u*v/wx[i] + v*JJ + u*HH);
247 }
248 if(m!=0) AA = 4.0*m*AA - wsum*HH*JJ/m; else AA=0.0;
249 if(0) printf("AA=%g BB=%g CC=%g\n", AA, BB, CC);
250 /* sigmas */
251 varc=varm=0.0;
252 for(j=0; j<n; j++) if(w[j]>0.0) {
253 /* factors for this j */
254 DD=EE=FF=GG=0.0;
255 for(i=0; i<n; i++) if(w[i]>0.0) {
256 u=cx[i]-xb; v=cy[i]-yb; w2=w[i]*w[i];
257 if(i==j) delta=1.0; else delta=0.0; /* Kronecker delta */
258 f = delta - w[j]/wsum;
259 DD += (w2*v/wx[i])*f;
260 EE += (w2*u/wy[i])*f;
261 FF += (w2*v/wy[i])*f;
262 GG += (w2*u/wx[i])*f;
263 }
264 EE*=2.0;
265 /* derivatives at jth data point */
266 f = (2.0*m*qa + qb - AA*m2 + BB*m - CC); m2=m*m;
267 dmx = -(m2*DD + m*EE - FF) / f;
268 dmy = -(m2*GG - 2.0*m*DD - EE/2.0) / f;
269 dcx = (HH - m*JJ - xb)*dmx - m*w[j]/wsum;
270 dcy = (HH - m*JJ - xb)*dmy + w[j]/wsum;
271 /* sum terms for sigmas */
272 varm += dmy*dmy/wy[j] + dmx*dmx/wx[j];
273 varc += dcy*dcy/wy[j] + dcx*dcx/wx[j];
274 if(0)
275 printf("DD=%g EE=%g FF=%g GG=%g dmx=%g dmy=%g dcx=%g dcy=%g\n",
276 DD, EE, FF, GG, dmx, dmy, dcx, dcy);
277 }
278 varm *= ss/(double)(nn-2);
279 varc *= ss/(double)(nn-2);
280 if(0) printf("varm=%g varc=%g\n", varm, varc);
281 *sslope = sqrt(varm);
282 *sic = sqrt(varc);
283 if(0) {fprintf(stdout, "sslope=%14.7e sic=%14.7e\n", *sslope, *sic);}
284 return(0);
285}
286/******************************************************************************/
287
288/******************************************************************************/
296 double *x,
298 double *y,
300 double *wx,
302 double *wy,
304 int nr,
306 int min_nr,
308 int mode,
310 double *slope,
312 double *ic,
314 double *nwss,
316 double *sslope,
318 double *sic,
320 double *cx,
322 double *cy,
324 int *bnr
325) {
326 int from, to, ret, from_min, to_min;
327 double *w, lic, lslope, lnwss=1.0E+100, nwss_min=1.0E+100;
328
329 /* Check the data */
330 if(x==NULL || y==NULL || nr<min_nr || nr<2) return(1);
331 /* Check parameters */
332 if(min_nr<4 || (mode!=0 && mode!=1)) return(2);
333
334 /* Make room for work vector */
335 w=(double*)malloc(nr*sizeof(double)); if(w==NULL) return(3);
336
337 /* Search the plot range that gives the best nwss */
338 nwss_min=9.99E+99; from_min=to_min=-1;
339 if(mode==0) { /* Leave out plot data from the beginning */
340 for(from=0, to=nr-1; from<nr-min_nr; from++) {
341 ret=llsqwt(x+from, y+from, (to-from)+1, wx+from, wy+from, 1.0E-10, w,
342 &lic, &lslope, &lnwss, NULL, NULL, NULL, NULL);
343 /*lnwss/=(double)((to-from)+1);*/
344 if(0) printf(" range: %d-%d ; nwss=%g ; min=%g ; ret=%d\n", from, to, lnwss, nwss_min, ret);
345 if(ret==0 && lnwss<nwss_min) {nwss_min=lnwss; from_min=from; to_min=to;}
346 }
347 } else { /* Leave out plot data from the end */
348 for(from=0, to=min_nr-1; to<nr; to++) {
349 ret=llsqwt(x+from, y+from, (to-from)+1, wx+from, wy+from, 1.0E-10, w,
350 &lic, &lslope, &lnwss, NULL, NULL, NULL, NULL);
351 /*lnwss/=(double)((to-from)+1);*/
352 if(0) printf(" range: %d-%d ; nwss=%g ; min=%g ; ret=%d\n", from, to, lnwss, nwss_min, ret);
353 if(ret==0 && lnwss<nwss_min) {nwss_min=lnwss; from_min=from; to_min=to;}
354 }
355 }
356 if(from_min<0) {free(w); return(4);}
357
358 /* Run llsqwt() again with that range, now with better resolution */
359 /* and this time compute also SD's */
360 from=from_min; to=to_min;
361 ret=llsqwt(x+from, y+from, (to-from)+1, wx+from, wy+from, 1.0E-15, w,
362 ic, slope, nwss, sic, sslope, cx+from, cy+from);
363 free(w);
364 if(ret) return(5);
365 *bnr=(to-from)+1;
366
367 return(0);
368}
369/******************************************************************************/
370
371/******************************************************************************/
384 double *x,
386 double *y,
388 int nr,
390 double *slope,
392 double *ic,
394 double *ssd
395) {
396 int i, rnr;
397 double qxx, qyy, qxy, mx, my, a, b, c, d, m1, m2, ssd1, ssd2;
398
399 if(0) {fprintf(stdout, "llsqperp()\n"); fflush(stdout);}
400 /* Check the data */
401 if(nr<2 || x==NULL || y==NULL) return(1);
402 /* Calculate the means */
403 for(i=0, mx=my=0; i<nr; i++) {mx+=x[i]; my+=y[i];}
404 mx/=(double)nr; my/=(double)nr;
405 /* Calculate the Q's */
406 for(i=0, qxx=qyy=qxy=0; i<nr; i++) {
407 a=x[i]-mx; b=y[i]-my; qxx+=a*a; qyy+=b*b; qxy+=a*b;
408 }
409 if(qxx<1.0E-100 || qyy<1.0E-100) return(2);
410 /* Calculate the slope as real roots of quadratic equation */
411 a=qxy; b=qxx-qyy; c=-qxy;
412 rnr=quadratic(a, b, c, &m1, &m2);
413 if(0) {
414 fprintf(stdout, "%d quadratic roots", rnr);
415 if(rnr>0) fprintf(stdout, " %g", m1);
416 if(rnr>1) fprintf(stdout, " %g", m2);
417 fprintf(stdout, " ; traditional slope %g\n", qxy/qxx);
418 }
419 if(rnr==0) return(3);
420 /* Calculate the sum of squared distances for the first root */
421 a=m1; b=-1; c=my-m1*mx;
422 for(i=0, ssd1=0; i<nr; i++) {
423 /* calculate the distance from point (x[i],y[i]) to line ax+by+c=0 */
424 //d=(a*x[i]+b*y[i]+c)/sqrt(a*a+b*b);
425 d=(a*x[i]+b*y[i]+c)/hypot(a, b);
426 ssd1+=d*d;
427 }
428 /* Also to the 2nd root, if there is one */
429 if(rnr==2) {
430 a=m2; b=-1; c=my-m2*mx;
431 for(i=0, ssd2=0; i<nr; i++) {
432 /* calculate the distance from point (x[i],y[i]) to line ax+by+c=0 */
433 //d=(a*x[i]+b*y[i]+c)/sqrt(a*a+b*b);
434 d=(a*x[i]+b*y[i]+c)/hypot(a, b);
435 ssd2+=d*d;
436 }
437 } else ssd2=ssd1;
438 /* If there were 2 roots, select the one with smaller ssd */
439 if(rnr==2 && ssd2<ssd1) {ssd1=ssd2; m1=m2;}
440 /* Set the slope and intercept */
441 *slope=m1; *ic=my-m1*mx; *ssd=ssd1/(double)nr;
442
443 return(0);
444}
445/******************************************************************************/
446
447/******************************************************************************/
455 double *x,
457 double *y,
459 int nr,
461 double *slope,
463 double *ic,
465 double *ssd
466) {
467 int i, j;
468 double *nx, *ny;
469
470 /* Allocate memory for new data pointers */
471 nx=(double*)calloc(nr, sizeof(double)); if(nx==NULL) return 1;
472 ny=(double*)calloc(nr, sizeof(double));
473 if(ny==NULL) {free((char*)nx); return 1;}
474
475 /* Copy data to pointers */
476 for(i=0, j=0; i<nr; i++)
477 if(!isnan(x[i]) && !isnan(y[i])) {nx[j]=x[i]; ny[j]=y[i]; j++;}
478
479 /* Use llsqperp() */
480 i=llsqperp(nx, ny, j, slope, ic, ssd);
481 free((char*)nx); free((char*)ny);
482 return(i);
483}
484/******************************************************************************/
485
486/******************************************************************************/
492 double a,
494 double b,
496 double c,
498 double *m1,
500 double *m2
501) {
502 double discriminant, r, r1, r2, sgnb, temp;
503
504 if(a==0) {if(b==0) return(0); else {*m1=*m2=-c/b; return(1);}}
505 discriminant=b*b - 4*a*c;
506 if(discriminant>0) {
507 if(b==0) {r=fabs(0.5*sqrt(discriminant)/a); *m1=-r; *m2=r;}
508 else {
509 sgnb=(b>0 ? 1:-1); temp=-0.5*(b + sgnb*sqrt(discriminant));
510 r1=temp/a; r2=c/temp; if(r1<r2) {*m1=r1; *m2=r2;} else {*m1=r2; *m2=r1;}
511 }
512 return(2);
513 } else if(discriminant==0) {
514 *m1=-0.5*b/a; *m2=-0.5*b/a;
515 return(2);
516 } else {
517 return(0);
518 }
519}
520/******************************************************************************/
521
522/******************************************************************************/
535 double *x,
537 double *y,
539 int nr,
541 double *slope,
543 double *ic
544) {
545 int i, j, snr;
546 double *sp, *ip, d;
547
548 if(0) fprintf(stdout, "medianline()\n");
549 /* Check the data */
550 if(nr<2 || x==NULL || y==NULL) return(1);
551 /* Allocate memory for slopes and intercepts */
552 for(i=0, snr=0; i<nr-1; i++) for(j=i+1; j<nr; j++) snr++;
553 sp=(double*)malloc(snr*sizeof(double));
554 ip=(double*)malloc(snr*sizeof(double));
555 if(sp==NULL || ip==NULL) return(2);
556 /* Calculate the slopes and intercepts */
557 for(i=0, snr=0; i<nr-1; i++) for(j=i+1; j<nr; j++) {
558 if(isnan(x[i]) || isnan(x[j]) || isnan(y[i]) || isnan(y[j])) continue;
559 d=x[j]-x[i]; if(d==0) continue;
560 sp[snr]=(y[j]-y[i])/d; ip[snr]=y[i]-sp[snr]*x[i];
561 snr++;
562 }
563 if(snr<2) {free(sp); free(ip); return(3);}
564 /* Get the medians of slope and intercept */
565 qsort(sp, snr, sizeof(double), _medianline_cmp);
566 qsort(ip, snr, sizeof(double), _medianline_cmp);
567 if(snr%2==1) {*slope=sp[snr/2]; *ic=ip[snr/2];}
568 else {*slope=0.5*(sp[snr/2]+sp[(snr/2)-1]); *ic=0.5*(ip[snr/2]+ip[(snr/2)-1]);}
569 free(sp); free(ip);
570 return(0);
571}
572/******************************************************************************/
573
574/******************************************************************************/
576int _medianline_cmp(const void *e1, const void *e2)
577{
578 if(*((double*)e1) > *((double*)e2)) return(-1);
579 else if(*((double*)e1) < *((double*)e2)) return(1);
580 else return(0);
581}
583/******************************************************************************/
584
585/******************************************************************************/
Header file for libtpcmodel.
int llsqperp3(double *x, double *y, int nr, double *slope, double *ic, double *ssd)
Definition llsqwt.c:453
int medianline(double *x, double *y, int nr, double *slope, double *ic)
Definition llsqwt.c:533
int llsqperp(double *x, double *y, int nr, double *slope, double *ic, double *ssd)
Definition llsqwt.c:382
int llsqwt(double *x, double *y, int n, double *wx, double *wy, double tol, double *w, double *ic, double *slope, double *nwss, double *sic, double *sslope, double *cx, double *cy)
Definition llsqwt.c:48
int best_llsqwt(double *x, double *y, double *wx, double *wy, int nr, int min_nr, int mode, double *slope, double *ic, double *nwss, double *sslope, double *sic, double *cx, double *cy, int *bnr)
Definition llsqwt.c:294
int quadratic(double a, double b, double c, double *m1, double *m2)
Definition llsqwt.c:490