Mercurial > repos > vipints > rdiff
view rDiff/src/locfit/Source/liblfev.c @ 1:08d3a6143873
Deleted selected files
author | vipints |
---|---|
date | Tue, 08 Oct 2013 06:54:25 -0400 |
parents | 0f80a5141704 |
children |
line wrap: on
line source
/* * Copyright 1996-2006 Catherine Loader. */ #include "mex.h" /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" extern void fitoptions(); static double hmin, gmin, sig2, pen, vr, tb; static lfit *blf; static design *bdes; int procvbind(des,lf,v) design *des; lfit *lf; int v; { double s0, s1, bi; int i, ii, k; k = procv_var(des,lf,v); wdiag(&lf->lfd, &lf->sp, des,des->wd,&lf->dv,0,1,0); s0 = s1 = 0.0; for (i=0; i<des->n; i++) { ii = des->ind[i]; s0+= prwt(&lf->lfd,ii)*des->wd[i]*des->wd[i]; bi = prwt(&lf->lfd,ii)*fabs(des->wd[i]*ipower(dist(des,ii),deg(&lf->sp)+1)); s1+= bi*bi; } vr += s0; tb += s1; return(k); } double bcri(h,c,cri) double h; int c, cri; { double num, den, res[10]; int (*pv)(); if (c==DALP) blf->sp.nn = h; else blf->sp.fixh = h; if ((cri&63)==BIND) { pv = procvbind; vr = tb = 0.0; } else pv = procvstd; if (cri<64) startlf(bdes,blf,pv,0); switch(cri&63) { case BGCV: ressumm(blf,bdes,res); num = -2*blf->lfd.n*res[0]; den = blf->lfd.n-res[1]; return(num/(den*den)); case BCP: ressumm(blf,bdes,res); return(-2*res[0]/sig2-blf->lfd.n+pen*res[1]); case BIND: return(vr+pen*pen*tb); } LERR(("bcri: unknown criterion")); return(0.0); } void bsel2(h0,g0,ifact,c,cri) double h0, g0, ifact; int c, cri; { int done, inc; double h1, g1; h1 = h0; g1 = g0; done = inc = 0; while (!done) { h1 *= 1+ifact; g0 = g1; g1 = bcri(h1,c,cri); if (g1<gmin) { hmin = h1; gmin = g1; } if (g1>g0) inc++; else inc = 0; switch(cri) { case BIND: done = (inc>=4) & (vr<blf->fp.nv); break; default: done = (inc>=4); } } } void bsel3(h0,g0,ifact,c,cri) double h0, g0, ifact; int c, cri; { double h1, g1; int i; hmin = h0; gmin = g0; for (i=-1; i<=1; i++) if (i!=0) { h1 = h0*(1+i*ifact); g1 = bcri(h1,c,cri); if (g1<gmin) { hmin = h1; gmin = g1; } } return; } void bselect(lf,des,c,cri,pn) lfit *lf; design *des; int c, cri; double pn; { double h0, g0, ifact; int i; pen = pn; blf = lf; bdes = des; if (cri==BIND) pen /= factorial(deg(&lf->sp)+1); hmin = h0 = (c==DFXH) ? fixh(&lf->sp) : nn(&lf->sp); if (h0==0) LERR(("bselect: initial bandwidth is 0")); if (lf_error) return; sig2 = 1.0; gmin = g0 = bcri(h0,c,cri); if (cri==BCP) { sig2 = rv(&lf->fp); g0 = gmin = bcri(h0,c,cri+64); } ifact = 0.3; bsel2(h0,g0,ifact,c,cri); for (i=0; i<5; i++) { ifact = ifact/2; bsel3(hmin,gmin,ifact,c,cri); } if (c==DFXH) fixh(&lf->sp) = hmin; else nn(&lf->sp) = hmin; startlf(des,lf,procvstd,0); ressumm(lf,des,lf->fp.kap); } double compsda(x,h,n) double *x, h; int n; /* n/(n-1) * int( fhat''(x)^2 dx ); bandwidth h */ { int i, j; double ik, sd, z; ik = wint(1,NULL,0,WGAUS); sd = 0; for (i=0; i<n; i++) for (j=i; j<n; j++) { z = (x[i]-x[j])/h; sd += (2-(i==j))*Wconv4(z,WGAUS)/(ik*ik); } sd = sd/(n*(n-1)*h*h*h*h*h); return(sd); } double widthsj(x,lambda,n) double *x, lambda; int n; { double ik, a, b, td, sa, z, c, c1, c2, c3; int i, j; a = GFACT*0.920*lambda*exp(-log((double)n)/7)/SQRT2; b = GFACT*0.912*lambda*exp(-log((double)n)/9)/SQRT2; ik = wint(1,NULL,0,WGAUS); td = 0; for (i=0; i<n; i++) for (j=i; j<n; j++) { z = (x[i]-x[j])/b; td += (2-(i==j))*Wconv6(z,WGAUS)/(ik*ik); } td = -td/(n*(n-1)); j = 2.0; c1 = Wconv4(0.0,WGAUS); c2 = wint(1,&j,1,WGAUS); c3 = Wconv(0.0,WGAUS); /* (2*c1/(c2*c3))^(1/7)=1.357 */ sa = compsda(x,a,n); c = b*exp(log(c1*ik/(c2*c3*GFACT*GFACT*GFACT*GFACT)*sa/td)/7)*SQRT2; return(c); } void kdecri(x,h,res,c,k,ker,n) double *x, h, *res, c; int k, ker, n; { int i, j; double degfree, dfd, pen, s, r0, r1, d0, d1, ik, wij; if (h<=0) WARN(("kdecri, h = %6.4f",h)); res[0] = res[1] = 0.0; ik = wint(1,NULL,0,ker); switch(k) { case 1: /* aic */ pen = 2.0; for (i=0; i<n; i++) { r0 = d0 = 0.0; for (j=0; j<n; j++) { s = (x[i]-x[j])/h; r0 += W(s,ker); d0 += s*s*Wd(s,ker); } d0 = -(d0+r0)/(n*h*h*ik); /* d0 = d/dh fhat(xi) */ r0 /= n*h*ik; /* r0 = fhat(xi) */ res[0] += -2*log(r0)+pen*W(0.0,ker)/(n*h*ik*r0); res[1] += -2*d0/r0-pen*W(0.0,ker)/(n*h*ik*r0)*(d0/r0+1.0/h); } return; case 2: /* ocv */ for (i=0; i<n; i++) { r0 = 0.0; d0 = 0.0; for (j=0; j<n; j++) if (i!=j) { s = (x[i]-x[j])/h; r0 += W(s,ker); d0 += s*s*Wd(s,ker); } d0 = -(d0+r0)/((n-1)*h*h); r0 = r0/((n-1)*h); res[0] -= log(r0); res[1] -= d0/r0; } return; case 3: /* lscv */ r0 = r1 = d0 = d1 = degfree = 0.0; for (i=0; i<n; i++) { dfd = 0.0; for (j=0; j<n; j++) { s = (x[i]-x[j])/h; wij = W(s,ker); dfd += wij; /* * r0 = \int fhat * fhat = sum_{i,j} W*W( (Xi-Xj)/h ) / n^2 h. * d0 is it's derivative wrt h. * * r1 = 1/n sum( f_{-i}(X_i) ). * d1 is it's derivative wrt h. * * degfree = sum_i ( W_0 / sum_j W( (Xi-Xj)/h ) ) is fitted d.f. */ r0 += Wconv(s,ker); d0 += -s*s*Wconv1(s,ker); if (i != j) { r1 += wij; d1 += -s*s*Wd(s,ker); } } degfree += 1.0/dfd; } d1 -= r1; d0 -= r0; res[0] = r0/(n*n*h*ik*ik) - 2*r1/(n*(n-1)*h*ik); res[1] = d0/(n*n*h*h*ik*ik) - 2*d1/(n*(n-1)*h*h*ik); res[2] = degfree; return; case 4: /* bcv */ r0 = d0 = 0.0; for (i=0; i<n; i++) for (j=i+1; j<n; j++) { s = (x[i]-x[j])/h; r0 += 2*Wconv4(s,ker); d0 += 2*s*Wconv5(s,ker); } d0 = (-d0-r0)/(n*n*h*h*ik*ik); r0 = r0/(n*n*h*ik*ik); j = 2.0; d1 = wint(1,&j,1,ker); r1 = Wconv(0.0,ker); res[0] = (d1*d1*r0/4+r1/(n*h))/(ik*ik); res[1] = (d1*d1*d0/4-r1/(n*h*h))/(ik*ik); return; case 5: /* sjpi */ s = c*exp(5*log(h)/7)/SQRT2; d0 = compsda(x,s,n); res[0] = d0; /* this is S(alpha) in SJ */ res[1] = exp(log(Wikk(WGAUS,0)/(d0*n))/5)-h; return; case 6: /* gas-k-k */ s = exp(log(1.0*n)/10)*h; d0 = compsda(x,s,n); res[0] = d0; res[1] = exp(log(Wikk(WGAUS,0)/(d0*n))/5)-h; return; } LERR(("kdecri: what???")); return; } double esolve(x,j,h0,h1,k,c,ker,n) double *x, h0, h1, c; int j, k, ker, n; { double h[7], d[7], r[7], res[4], min, minh, fact; int i, nc; min = 1.0e30; minh = 0.0; fact = 1.00001; h[6] = h0; kdecri(x,h[6],res,c,j,ker,n); r[6] = res[0]; d[6] = res[1]; if (lf_error) return(0.0); nc = 0; for (i=0; i<k; i++) { h[5] = h[6]; r[5] = r[6]; d[5] = d[6]; h[6] = h0*exp((i+1)*log(h1/h0)/k); kdecri(x,h[6],res,c,j,ker,n); r[6] = res[0]; d[6] = res[1]; if (lf_error) return(0.0); if (d[5]*d[6]<0) { h[2] = h[0] = h[5]; d[2] = d[0] = d[5]; r[2] = r[0] = r[5]; h[3] = h[1] = h[6]; d[3] = d[1] = d[6]; r[3] = r[1] = r[6]; while ((h[3]>fact*h[2])|(h[2]>fact*h[3])) { h[4] = h[3]-d[3]*(h[3]-h[2])/(d[3]-d[2]); if ((h[4]<h[0]) | (h[4]>h[1])) h[4] = (h[0]+h[1])/2; kdecri(x,h[4],res,c,j,ker,n); r[4] = res[0]; d[4] = res[1]; if (lf_error) return(0.0); h[2] = h[3]; h[3] = h[4]; d[2] = d[3]; d[3] = d[4]; r[2] = r[3]; r[3] = r[4]; if (d[4]*d[0]>0) { h[0] = h[4]; d[0] = d[4]; r[0] = r[4]; } else { h[1] = h[4]; d[1] = d[4]; r[1] = r[4]; } } if (j>=4) return(h[4]); /* first min for BCV etc */ if (r[4]<=min) { min = r[4]; minh = h[4]; } nc++; } } if (nc==0) minh = (r[5]<r[6]) ? h0 : h1; return(minh); } void kdeselect(band,x,ind,h0,h1,meth,nm,ker,n) double h0, h1, *band, *x; int *ind, nm, ker, n, *meth; { double scale, c; int i, k; k = n/4; for (i=0; i<n; i++) ind[i] = i; scale = kordstat(x,n+1-k,n,ind) - kordstat(x,k,n,ind); c = widthsj(x,scale,n); for (i=0; i<nm; i++) band[i] = esolve(x,meth[i],h0,h1,10,c,ker,n); } /* * Copyright 1996-2006 Catherine Loader. */ /* * The function dens_integrate(lf,des,z) is used to integrate a density * estimate (z=1) or the density squared (z=2). This is used to renormalize * the estimate (function dens_renorm) or in the computation of LSCV * (in modlscv.c). The implementation is presently for d=1. * * The computation orders the fit points selected by locfit, and * integrates analytically over each interval. For the log-link, * the interpolant used is peicewise quadratic (with one knot in * the middle of each interval); this differs from the cubic interpolant * used elsewhere in Locfit. * * TODO: allow for xlim. What can be done simply in >=2 dimensions? */ #include "lfev.h" /* * Finds the order of observations in the array x, and * stores in integer array ind. * At input, lset l=0 and r=length(x)-1. * At output, x[ind[0]] <= x[ind[1]] <= ... */ void lforder(ind,x,l,r) int *ind, l, r; double *x; { double piv; int i, i0, i1; piv = (x[ind[l]]+x[ind[r]])/2; i0 = l; i1 = r; while (i0<=i1) { while ((i0<=i1) && (x[ind[i0]]<=piv)) i0++; while ((i0<=i1) && (x[ind[i1]]>piv)) i1--; if (i0<i1) { ISWAP(ind[i0],ind[i1]); i0++; i1--; } } /* now, x[ind[l..i1]] <= piv < x[ind[i0..r]]. put the ties in the middle */ while ((i1>=l) && (x[ind[i1]]==piv)) i1--; for (i=l; i<=i1; i++) if (x[ind[i]]==piv) { ISWAP(ind[i],ind[i1]); while (x[ind[i1]]==piv) i1--; } if (l<i1) lforder(ind,x,l,i1); if (i0<r) lforder(ind,x,i0,r); } /* * estdiv integrates the density between fit points x0 and x1. * f0, f1 are function values, d0, d1 are derivatives. */ double estdiv(x0,x1,f0,f1,d0,d1,lin) double x0, x1, f0, f1, d0, d1; int lin; { double cf[4], I[2], dlt, e0, e1; if (x0==x1) return(0.0); if (lin==LIDENT) { /* cf are integrals of hermite polynomials. * Then adjust for x1-x0. */ cf[0] = cf[1] = 0.5; cf[2] = 1.0/12.0; cf[3] = -cf[2]; return( (cf[0]*f0+cf[1]*f1)*(x1-x0) + (cf[2]*d0+cf[3]*d1)*(x1-x0)*(x1-x0) ); } /* * this is for LLOG */ dlt = (x1-x0)/2; cf[0] = f0; cf[1] = d0; cf[2] = ( 2*(f1-f0) - dlt*(d1+3*d0) )/(4*dlt*dlt); recurint(0.0,dlt,cf,I,0,WRECT); e0 = I[0]; cf[0] = f1; cf[1] = -d1; cf[2] = ( 2*(f0-f1) + dlt*(d0+3*d1) )/( 4*dlt*dlt ); recurint(0.0,dlt,cf,I,0,WRECT); e1 = I[0]; return(e0+e1); } /* * Evaluate the integral of the density estimate to the power z. * This would be severely messed up, if I ever implement parcomp * for densities. */ double dens_integrate(lf,des,z) lfit *lf; design *des; int z; { int has_deriv, i, i0, i1, nv, *ind; double *xev, *fit, *deriv, sum, term; double d0, d1, f0, f1; fitpt *fp; fp = &lf->fp; if (fp->d >= 2) { WARN(("dens_integrate requires d=1")); return(0.0); } has_deriv = (deg(&lf->sp) > 0); /* not right? */ fit = fp->coef; if (has_deriv) deriv = &fit[fp->nvm]; xev = evp(fp); /* * order the vertices */ nv = fp->nv; if (lf->lfd.n<nv) return(0.0); ind = des->ind; for (i=0; i<nv; i++) ind[i] = i; lforder(ind,xev,0,nv-1); sum = 0.0; /* * Estimate the contribution of the boundaries. * should really check flim here. */ i0 = ind[0]; i1 = ind[1]; f1 = fit[i0]; d1 = (has_deriv) ? deriv[i0] : (fit[i1]-fit[i0])/(xev[i1]-xev[i0]); if (d1 <= 0) WARN(("dens_integrate - ouch!")); if (z==2) { if (link(&lf->sp)==LLOG) { f1 *= 2; d1 *= 2; } else { d1 = 2*d1*f1; f1 = f1*f1; } } term = (link(&lf->sp)==LIDENT) ? f1*f1/(2*d1) : exp(f1)/d1; sum += term; i0 = ind[nv-2]; i1 = ind[nv-1]; f0 = fit[i1]; d0 = (has_deriv) ? deriv[i1] : (fit[i1]-fit[i0])/(xev[i1]-xev[i0]); if (d0 >= 0) WARN(("dens_integrate - ouch!")); if (z==2) { if (link(&lf->sp)==LLOG) { f0 *= 2; d0 *= 2; } else { d0 = 2*d0*f0; f0 = f0*f0; } } term = (link(&lf->sp)==LIDENT) ? -f0*f0/(2*d0) : exp(f0)/d0; sum += term; for (i=1; i<nv; i++) { i0 = ind[i-1]; i1 = ind[i]; f0 = fit[i0]; f1 = fit[i1]; d0 = (has_deriv) ? deriv[i0] : (f1-f0)/(xev[i1]-xev[i0]); d1 = (has_deriv) ? deriv[i1] : d0; if (z==2) { if (link(&lf->sp)==LLOG) { f0 *= 2; f1 *= 2; d0 *= 2; d1 *= 2; } else { d0 *= 2*f0; d1 *= 2*f1; f0 = f0*f0; f1 = f1*f1; } } term = estdiv(xev[i0],xev[i1],f0,f1,d0,d1,link(&lf->sp)); sum += term; } return(sum); } void dens_renorm(lf,des) lfit *lf; design *des; { int i; double sum; sum = dens_integrate(lf,des,1); if (sum==0.0) return; sum = log(sum); for (i=0; i<lf->fp.nv; i++) lf->fp.coef[i] -= sum; } /* * Copyright 1996-2006 Catherine Loader. */ /* * This file contains functions for constructing and * interpolating the adaptive tree structure. This is * the default evaluation structure used by Locfit. */ #include "lfev.h" /* Guess the number of fitting points. Needs improving! */ void atree_guessnv(evs,nvm,ncm,vc,d,alp) evstruc *evs; double alp; int *nvm, *ncm, *vc, d; { double a0, cu, ifl; int i, nv, nc; *ncm = 1<<30; *nvm = 1<<30; *vc = 1 << d; if (alp>0) { a0 = (alp > 1) ? 1 : 1/alp; if (cut(evs)<0.01) { WARN(("guessnv: cut too small.")); cut(evs) = 0.01; } cu = 1; for (i=0; i<d; i++) cu *= MIN(1.0,cut(evs)); nv = (int)((5*a0/cu)**vc); /* this allows 10*a0/cu splits */ nc = (int)(10*a0/cu+1); /* and 10*a0/cu cells */ if (nv<*nvm) *nvm = nv; if (nc<*ncm) *ncm = nc; } if (*nvm == 1<<30) /* by default, allow 100 splits */ { *nvm = 102**vc; *ncm = 201; } /* inflation based on mk */ ifl = mk(evs)/100.0; *nvm = *vc+(int)(ifl**nvm); *ncm = (int)(ifl**ncm); } /* Determine whether a cell in the tree needs splitting. If so, return the split variable (0..d-1). Otherwise, return -1. */ int atree_split(lf,ce,le,ll,ur) lfit *lf; int *ce; double *le, *ll, *ur; { int d, vc, i, is; double h, hmin, score[MXDIM]; d = lf->fp.d; vc = 1<<d; hmin = 0.0; for (i=0; i<vc; i++) { h = lf->fp.h[ce[i]]; if ((h>0) && ((hmin==0)|(h<hmin))) hmin = h; } is = 0; for (i=0; i<d; i++) { le[i] = (ur[i]-ll[i])/lf->lfd.sca[i]; if ((lf->lfd.sty[i]==STCPAR) || (hmin==0)) score[i] = 2*(ur[i]-ll[i])/(lf->evs.fl[i+d]-lf->evs.fl[i]); else score[i] = le[i]/hmin; if (score[i]>score[is]) is = i; } if (cut(&lf->evs)<score[is]) return(is); return(-1); } /* recursively grow the tree structure, begining with the parent cell. */ void atree_grow(des,lf,ce,ct,term,ll,ur) design *des; lfit *lf; int *ce, *ct, *term; double *ll, *ur; { int nce[1<<MXDIM]; int i, i0, i1, d, vc, pv, tk, ns; double le[MXDIM], z; d = lf->fp.d; vc = 1<<d; /* does this cell need splitting? If not, wrap up and return. */ ns = atree_split(lf,ce,le,ll,ur); if (ns==-1) { if (ct != NULL) /* reconstructing terminal cells */ { for (i=0; i<vc; i++) term[*ct*vc+i] = ce[i]; (*ct)++; } return; } /* split the cell at the midpoint on side ns */ tk = 1<<ns; for (i=0; i<vc; i++) { if ((i&tk)==0) nce[i] = ce[i]; else { i0 = ce[i]; i1 = ce[i-tk]; pv = (lf->lfd.sty[i]!=STCPAR) && (le[ns] < (cut(&lf->evs)*MIN(lf->fp.h[i0],lf->fp.h[i1]))); nce[i] = newsplit(des,lf,i0,i1,pv); if (lf_error) return; } } z = ur[ns]; ur[ns] = (z+ll[ns])/2; atree_grow(des,lf,nce,ct,term,ll,ur); if (lf_error) return; ur[ns] = z; for (i=0; i<vc; i++) nce[i] = ((i&tk)== 0) ? nce[i+tk] : ce[i]; z = ll[ns]; ll[ns] = (z+ur[ns])/2; atree_grow(des,lf,nce,ct,term,ll,ur); if (lf_error) return; ll[ns] = z; } void atree_start(des,lf) design *des; lfit *lf; { int d, i, j, k, vc, ncm, nvm; double ll[MXDIM], ur[MXDIM]; if (lf_debug>1) mut_printf(" In atree_start\n"); d = lf->fp.d; atree_guessnv(&lf->evs,&nvm,&ncm,&vc,d,nn(&lf->sp)); if (lf_debug>2) mut_printf(" atree_start: nvm %d ncm %d\n",nvm,ncm); trchck(lf,nvm,ncm,vc); /* Set the lower left, upper right limits. */ for (j=0; j<d; j++) { ll[j] = lf->evs.fl[j]; ur[j] = lf->evs.fl[j+d]; } /* Set the initial cell; fit at the vertices. */ for (i=0; i<vc; i++) { j = i; for (k=0; k<d; ++k) { evptx(&lf->fp,i,k) = (j%2) ? ur[k] : ll[k]; j >>= 1; } lf->evs.ce[i] = i; PROC_VERTEX(des,lf,i); if (lf_error) return; lf->evs.s[i] = 0; } lf->fp.nv = vc; /* build the tree */ atree_grow(des,lf,lf->evs.ce,NULL,NULL,ll,ur); lf->evs.nce = 1; } double atree_int(lf,x,what) lfit *lf; double *x; int what; { double vv[64][64], *ll, *ur, h, xx[MXDIM]; int lo, tk, ns, nv, nc, d, i, vc; int ce[64]; fitpt *fp; evstruc *evs; fp = &lf->fp; evs= &lf->evs; d = fp->d; vc = 1<<d; for (i=0; i<vc; i++) { setzero(vv[i],vc); nc = exvval(fp,vv[i],i,d,what,1); ce[i] = evs->ce[i]; } ns = 0; while(ns!=-1) { ll = evpt(fp,ce[0]); ur = evpt(fp,ce[vc-1]); ns = atree_split(lf,ce,xx,ll,ur); if (ns!=-1) { tk = 1<<ns; h = ur[ns]-ll[ns]; lo = (2*(x[ns]-ll[ns])) < h; for (i=0; i<vc; i++) if ((tk&i)==0) { nv = findpt(fp,evs,(int)ce[i],(int)ce[i+tk]); if (nv==-1) LERR(("Descend tree problem")); if (lf_error) return(0.0); if (lo) { ce[i+tk] = nv; if (evs->s[nv]) exvvalpv(vv[i+tk],vv[i],vv[i+tk],d,ns,h,nc); else exvval(fp,vv[i+tk],nv,d,what,1); } else { ce[i] = nv; if (evs->s[nv]) exvvalpv(vv[i],vv[i],vv[i+tk],d,ns,h,nc); else exvval(fp,vv[i],nv,d,what,1); } } } } ll = evpt(fp,ce[0]); ur = evpt(fp,ce[vc-1]); return(rectcell_interp(x,vv,ll,ur,d,nc)); } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" double linear_interp(h,d,f0,f1) double h, d, f0, f1; { if (d==0) return(f0); return( ( (d-h)*f0 + h*f1 ) / d ); } void hermite2(x,z,phi) double x, z, *phi; { double h; if (z==0) { phi[0] = 1.0; phi[1] = phi[2] = phi[3] = 0.0; return; } h = x/z; if (h<0) { phi[0] = 1; phi[1] = 0; phi[2] = h; phi[3] = 0; return; } if (h>1) { phi[0] = 0; phi[1] = 1; phi[2] = 0; phi[3] = h-1; return; } phi[1] = h*h*(3-2*h); phi[0] = 1-phi[1]; phi[2] = h*(1-h)*(1-h); phi[3] = h*h*(h - 1); } double cubic_interp(h,f0,f1,d0,d1) double h, f0, f1, d0, d1; { double phi[4]; hermite2(h,1.0,phi); return(phi[0]*f0+phi[1]*f1+phi[2]*d0+phi[3]*d1); } double cubintd(h,f0,f1,d0,d1) double h, f0, f1, d0, d1; { double phi[4]; phi[1] = 6*h*(1-h); phi[0] = -phi[1]; phi[2] = (1-h)*(1-3*h); phi[3] = h*(3*h-2); return(phi[0]*f0+phi[1]*f1+phi[2]*d0+phi[3]*d1); } /* interpolate over a rectangular cell. x = interpolation point. vv = array of vertex values. ll = lower left corner. ur = upper right corner. d = dimension. nc = no of coefficients. */ double rectcell_interp(x,vv,ll,ur,d,nc) double *x, vv[64][64], *ll, *ur; int d, nc; { double phi[4]; int i, j, k, tk; tk = 1<<d; for (i=0; i<tk; i++) if (vv[i][0]==NOSLN) return(NOSLN); /* no derivatives - use multilinear interpolation */ if (nc==1) { for (i=d-1; i>=0; i--) { tk = 1<<i; for (j=0; j<tk; j++) vv[j][0] = linear_interp(x[i]-ll[i],ur[i]-ll[i],vv[j][0],vv[j+tk][0]); } return(vv[0][0]); } /* with derivatives -- use cubic */ if (nc==d+1) { for (i=d-1; i>=0; i--) { hermite2(x[i]-ll[i],ur[i]-ll[i],phi); tk = 1<<i; phi[2] *= ur[i]-ll[i]; phi[3] *= ur[i]-ll[i]; for (j=0; j<tk; j++) { vv[j][0] = phi[0]*vv[j][0] + phi[1]*vv[j+tk][0] + phi[2]*vv[j][i+1] + phi[3]*vv[j+tk][i+1]; for (k=1; k<=i; k++) vv[j][k] = phi[0]*vv[j][k] + phi[1]*vv[j+tk][k]; } } return(vv[0][0]); } /* with all coefs -- use multicubic */ for (i=d-1; i>=0; i--) { hermite2(x[i]-ll[i],ur[i]-ll[i],phi); tk = 1<<i; phi[2] *= ur[i]-ll[i]; phi[3] *= ur[i]-ll[i]; for (j=0; j<tk; j++) for (k=0; k<tk; k++) vv[j][k] = phi[0]*vv[j][k] + phi[1]*vv[j+tk][k] + phi[2]*vv[j][k+tk] + phi[3]*vv[j+tk][k+tk]; } return(vv[0][0]); } int exvval(fp,vv,nv,d,what,z) fitpt *fp; double *vv; int nv, d, z, what; { int i, k; double *values; k = (z) ? 1<<d : d+1; for (i=1; i<k; i++) vv[i] = 0.0; switch(what) { case PCOEF: values = fp->coef; break; case PVARI: case PNLX: values = fp->nlx; break; case PT0: values = fp->t0; break; case PBAND: vv[0] = fp->h[nv]; return(1); case PDEGR: vv[0] = fp->deg[nv]; return(1); case PLIK: vv[0] = fp->lik[nv]; return(1); case PRDF: vv[0] = fp->lik[2*fp->nvm+nv]; return(1); default: LERR(("Invalid what in exvval")); return(0); } vv[0] = values[nv]; if (!fp->hasd) return(1); if (z) { for (i=0; i<d; i++) vv[1<<i] = values[(i+1)*fp->nvm+nv]; return(1<<d); } else { for (i=1; i<=d; i++) vv[i] = values[i*fp->nvm+nv]; return(d+1); } } void exvvalpv(vv,vl,vr,d,k,dl,nc) double *vv, *vl, *vr, dl; int d, k, nc; { int i, tk, td; double f0, f1; if (nc==1) { vv[0] = (vl[0]+vr[0])/2; return; } tk = 1<<k; td = 1<<d; for (i=0; i<td; i++) if ((i&tk)==0) { f0 = (vl[i]+vr[i])/2 + dl*(vl[i+tk]-vr[i+tk])/8; f1 = 1.5*(vr[i]-vl[i])/dl - (vl[i+tk]+vr[i+tk])/4; vv[i] = f0; vv[i+tk] = f1; } } double grid_int(fp,evs,x,what) fitpt *fp; evstruc *evs; double *x; int what; { int d, i, j, jj, nc, sk, v[MXDIM], vc, z0, nce[1<<MXDIM], *mg; double *ll, *ur, vv[64][64], z; d = fp->d; ll = evpt(fp,0); ur = evpt(fp,fp->nv-1); mg = mg(evs); z0 = 0; vc = 1<<d; for (j=d-1; j>=0; j--) { v[j] = (int)((mg[j]-1)*(x[j]-ll[j])/(ur[j]-ll[j])); if (v[j]<0) v[j]=0; if (v[j]>=mg[j]-1) v[j] = mg[j]-2; z0 = z0*mg[j]+v[j]; } nce[0] = z0; nce[1] = z0+1; sk = jj = 1; for (i=1; i<d; i++) { sk *= mg[i-1]; jj<<=1; for (j=0; j<jj; j++) nce[j+jj] = nce[j]+sk; } for (i=0; i<vc; i++) nc = exvval(fp,vv[i],nce[i],d,what,1); ll = evpt(fp,nce[0]); ur = evpt(fp,nce[vc-1]); z = rectcell_interp(x,vv,ll,ur,d,nc); return(z); } double fitp_int(fp,x,what,i) fitpt *fp; double *x; int what, i; { double vv[1+MXDIM]; exvval(fp,vv,i,fp->d,what,0); return(vv[0]); } double xbar_int(fp,x,what) fitpt *fp; double *x; int what; { int i, nc; double vv[1+MXDIM], f; nc = exvval(fp,vv,0,fp->d,what,0); f = vv[0]; if (nc>1) for (i=0; i<fp->d; i++) f += vv[i+1]*(x[i]-evptx(fp,0,i)); return(f); } double dointpoint(lf,x,what,ev,j) lfit *lf; double *x; int what, ev, j; { double xf, f, link[LLEN]; int i, rt; fitpt *fp; evstruc *evs; fp = &lf->fp; evs = &lf->evs; for (i=0; i<fp->d; i++) if (lf->lfd.sty[i]==STANGL) { xf = floor(x[i]/(2*PI*lf->lfd.sca[i])); x[i] -= xf*2*PI*lf->lfd.sca[i]; } if (what > 64) { rt = what-64; what = PCOEF; } else rt = 0; switch(ev) { case EGRID: f = grid_int(fp,evs,x,what); break; case EKDTR: f = kdtre_int(fp,evs,x,what); break; case ETREE: f = atree_int(lf,x,what); break; case EPHULL: f = triang_int(lf,x,what); break; case EFITP: f = fitp_int(fp,x,what,j); break; case EXBAR: f = xbar_int(fp,x,what); break; case ENONE: f = 0; break; case ESPHR: f = sphere_int(lf,x,what); break; default: LERR(("dointpoint: cannot interpolate structure %d",ev)); } if (((what==PT0)|(what==PNLX)) && (f<0)) f = 0.0; f += addparcomp(lf,x,what); if (rt>0) { stdlinks(link,&lf->lfd,&lf->sp,j,f,rsc(fp)); f = resid(resp(&lf->lfd,j),prwt(&lf->lfd,j),f,fam(&lf->sp),rt,link); } return(f); } /* * Copyright 1996-2006 Catherine Loader. */ /* * Routines for building and interpolating the kd tree. * Initially, this started from the loess code. * * Todo: EKDCE isn't working. */ #include "lfev.h" void newcell(); static int nterm; void kdtre_guessnv(evs,nvm,ncm,vc,n,d,alp) evstruc *evs; double alp; int *nvm, *ncm, *vc, n, d; { int k; if (ev(evs) == EKDTR) { nterm = (int)(cut(evs)/4 * n * MIN(alp,1.0) ); k = 2*n/nterm; *vc = 1<<d; *ncm = 2*k+1; *nvm = (k+2)**vc/2; return; } if (ev(evs) == EKDCE) { nterm = (int)(n * alp); *vc = 1; *nvm = 1+(int)(2*n/nterm); *ncm = 2**nvm+1; return; } *nvm = *ncm = *vc = 0; return; } /* Split x[pi[l..r]] into two equal sized sets. Let m=(l+r)/2. At return, x[pi[l..m]] < x[pi[m+1..r]]. Assuming no ties: If l+r is odd, the sets have the same size. If l+r is even, the low set is larger by 1. If there are ties, all ties go in the low set. */ int ksmall(l, r, m, x, pi) int l, r, m, *pi; double *x; { int il, ir, jl, jr; double t; while(l<r) { t = x[pi[m]]; /* permute the observations so that x[pi[l..il]] < t <= x[pi[ir..r]]. */ ir = l; il = r; while (ir<il) { while ((ir<=r) && (x[pi[ir]] < t)) ir++; while ((il>=l) && (x[pi[il]]>= t)) il--; if (ir<il) ISWAP(pi[ir],pi[il]); } /* move = t to the middle: x[pi[l..il]] < t x[pi[jl..jr]] = t x[pi[ir..r]] > t */ jl = ir; jr = r; while (ir<jr) { while ((ir<=r) && (x[pi[ir]]== t)) ir++; while ((jr>=jl) && (x[pi[jr]] > t)) jr--; if (ir<jr) ISWAP(pi[ir],pi[jr]); } /* we're done if m is in the middle, jl <= m <= jr. */ if ((jl<=m) & (jr>=m)) return(jr); /* update l or r. */ if (m>=ir) l = ir; if (m<=il) r = il; } if (l==r) return(l); LERR(("ksmall failure")); return(0); } int terminal(lf,p,pi,fc,d,m,split_val) lfit *lf; int p, d, fc, *m, *pi; double *split_val; { int i, k, lo, hi, split_var; double max, min, score, max_score, t; /* if there are fewer than fc points in the cell, this cell is terminal. */ lo = lf->evs.lo[p]; hi = lf->evs.hi[p]; if (hi-lo < fc) return(-1); /* determine the split variable */ max_score = 0.0; split_var = 0; for (k=0; k<d; k++) { max = min = datum(&lf->lfd, k, pi[lo]); for (i=lo+1; i<=hi; i++) { t = datum(&lf->lfd,k,pi[i]); if (t<min) min = t; if (t>max) max = t; } score = (max-min) / lf->lfd.sca[k]; if (score > max_score) { max_score = score; split_var = k; } } if (max_score==0) /* all points in the cell are equal */ return(-1); *m = ksmall(lo,hi,(lo+hi)/2, dvari(&lf->lfd,split_var), pi); *split_val = datum(&lf->lfd, split_var, pi[*m]); if (*m==hi) /* all observations go lo */ return(-1); return(split_var); } void kdtre_start(des,lf) design *des; lfit *lf; { int i, j, vc, d, nc, nv, ncm, nvm, k, m, n, p, *pi; double sv; d = lf->lfd.d; n = lf->lfd.n; pi = des->ind; kdtre_guessnv(&lf->evs,&nvm,&ncm,&vc,n,d,nn(&lf->sp)); trchck(lf,nvm,ncm,vc); nv = 0; if (ev(&lf->evs) != EKDCE) { for (i=0; i<vc; i++) { j = i; for (k=0; k<d; ++k) { evptx(&lf->fp,i,k) = lf->evs.fl[d*(j%2)+k]; j >>= 1; } } nv = vc; for (j=0; j<vc; j++) lf->evs.ce[j] = j; } for (i=0; i<n; i++) pi[i] = i; p = 0; nc = 1; lf->evs.lo[p] = 0; lf->evs.hi[p] = n-1; lf->evs.s[p] = -1; while (p<nc) { k = terminal(lf,p,pi,nterm,d,&m,&sv); if (k>=0) { if ((ncm<nc+2) | (2*nvm<2*nv+vc)) { WARN(("Insufficient space for full tree")); lf->evs.nce = nc; lf->fp.nv = nv; return; } /* new lo cell has obsn's lo[p]..m */ lf->evs.lo[nc] = lf->evs.lo[p]; lf->evs.hi[nc] = m; lf->evs.s[nc] = -1; /* new hi cell has obsn's m+1..hi[p] */ lf->evs.lo[nc+1] = m+1; lf->evs.hi[nc+1] = lf->evs.hi[p]; lf->evs.s[nc+1] = -1; /* cell p is split on variable k, value sv */ lf->evs.s[p] = k; lf->evs.sv[p] = sv; lf->evs.lo[p] = nc; lf->evs.hi[p] = nc+1; nc=nc+2; i = nv; /* now compute the new vertices. */ if (ev(&lf->evs) != EKDCE) newcell(&nv,vc,evp(&lf->fp), d, k, sv, &lf->evs.ce[p*vc], &lf->evs.ce[(nc-2)*vc], &lf->evs.ce[(nc-1)*vc]); } else if (ev(&lf->evs)==EKDCE) /* new vertex at cell center */ { sv = 0; for (i=0; i<d; i++) evptx(&lf->fp,nv,i) = 0; for (j=lf->evs.lo[p]; j<=lf->evs.hi[p]; j++) { sv += prwt(&lf->lfd,(int)pi[j]); for (i=0; i<d; i++) evptx(&lf->fp,nv,i) += datum(&lf->lfd,i,pi[j])*prwt(&lf->lfd,(int)pi[j]); } for (i=0; i<d; i++) evptx(&lf->fp,nv,i) /= sv; lf->lfd.n = lf->evs.hi[p] - lf->evs.lo[p] + 1; des->ind = &pi[lf->evs.lo[p]]; /* why? */ PROC_VERTEX(des,lf,nv); lf->lfd.n = n; des->ind = pi; nv++; } p++; } /* We've built the tree. Now do the fitting. */ if (ev(&lf->evs)==EKDTR) for (i=0; i<nv; i++) PROC_VERTEX(des,lf,i); lf->evs.nce = nc; lf->fp.nv = nv; return; } void newcell(nv,vc,xev, d, k, split_val, cpar, clef, crig) double *xev, split_val; int *cpar, *clef, *crig; int *nv, vc, d, k; { int i, ii, j, j2, tk, match; tk = 1<<k; for (i=0; i<vc; i++) { if ((i&tk) == 0) { for (j=0; j<d; j++) xev[*nv*d+j] = xev[d*cpar[i]+j]; xev[*nv*d+k] = split_val; match = 0; j = vc; /* no matches in first vc points */ while ((j<*nv) && (!match)) { j2 = 0; while ((j2<d) && (xev[*nv*d+j2] == xev[j*d+j2])) j2++; match = (j2==d); if (!match) j++; } ii = i+tk; clef[i] = cpar[i]; clef[ii]= crig[i] = j; crig[ii]= cpar[ii]; if (!match) (*nv)++; } } return; } extern void hermite2(); double blend(fp,evs,s,x,ll,ur,j,nt,t,what) fitpt *fp; evstruc *evs; double s, *x, *ll, *ur; int j, nt, *t, what; { int *ce, k, k1, m, nc, j0, j1; double v0, v1, xibar, g0[3], g1[3], gg[4], gp[4], phi[4]; ce = evs->ce; for (k=0; k<4; k++) /* North South East West */ { k1 = (k>1); v0 = ll[k1]; v1 = ur[k1]; j0 = ce[j+2*(k==0)+(k==2)]; j1 = ce[j+3-2*(k==1)-(k==3)]; xibar = (k%2==0) ? ur[k<2] : ll[k<2]; m = nt; while ((m>=0) && ((evs->s[t[m]] != (k<=1)) | (evs->sv[t[m]] != xibar))) m--; if (m >= 0) { m = (k%2==1) ? evs->lo[t[m]] : evs->hi[t[m]]; while (evs->s[m] != -1) m = (x[evs->s[m]] < evs->sv[m]) ? evs->lo[m] : evs->hi[m]; if (v0 < evptx(fp,ce[4*m+2*(k==1)+(k==3)],k1)) { j0 = ce[4*m+2*(k==1)+(k==3)]; v0 = evptx(fp,j0,k1); } if (evptx(fp,ce[4*m+3-2*(k==0)-(k==2)],k1) < v1) { j1 = ce[4*m+3-2*(k==0)-(k==2)]; v1 = evptx(fp,j1,k1); } } nc = exvval(fp,g0,j0,2,what,0); nc = exvval(fp,g1,j1,2,what,0); if (nc==1) gg[k] = linear_interp((x[(k>1)]-v0),v1-v0,g0[0],g1[0]); else { hermite2(x[(k>1)]-v0,v1-v0,phi); gg[k] = phi[0]*g0[0]+phi[1]*g1[0]+(phi[2]*g0[1+k1]+phi[3]*g1[1+k1])*(v1-v0); gp[k] = phi[0]*g0[2-k1] + phi[1]*g1[2-k1]; } } s = -s; if (nc==1) for (k=0; k<2; k++) s += linear_interp(x[k]-ll[k],ur[k]-ll[k],gg[3-2*k],gg[2-2*k]); else for (k=0; k<2; k++) /* EW NS */ { hermite2(x[k]-ll[k],ur[k]-ll[k],phi); s += phi[0]*gg[3-2*k] + phi[1]*gg[2-2*k] +(phi[2]*gp[3-2*k] + phi[3]*gp[2-2*k]) * (ur[k]-ll[k]); } return(s); } double kdtre_int(fp,evs,x,what) fitpt *fp; evstruc *evs; double *x; int what; { int *ce, k, vc, t[20], nt, nc, j, d; double *ll, *ur, ff, vv[64][64]; d = fp->d; vc = 1<<d; if (d > 6) { LERR(("d too large in kdint")); return(NOSLN); } /* descend the tree to find the terminal cell */ nt = 0; t[nt] = 0; k = 0; while (evs->s[k] != -1) { nt++; if (nt>=20) { LERR(("Too many levels in kdint")); return(NOSLN); } k = t[nt] = (x[evs->s[k]] < evs->sv[k]) ? evs->lo[k] : evs->hi[k]; } ce = &evs->ce[k*vc]; ll = evpt(fp,ce[0]); ur = evpt(fp,ce[vc-1]); nc = 0; for (j=0; j<vc; j++) nc = exvval(fp,vv[j],(int)ce[j],d,what,0); ff = rectcell_interp(x,vv,ll,ur,d,nc); if (d==2) ff = blend(fp,evs,ff,x,ll,ur,k*vc,nt,t,what); return(ff); } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" /* * convert eval. structure string to numeric code. */ #define NETYPE 11 static char *etype[NETYPE]= { "tree", "phull", "data", "grid", "kdtree", "kdcenter", "cross", "preset", "xbar", "none", "sphere" }; static int evals[NETYPE]= { ETREE, EPHULL, EDATA, EGRID, EKDTR, EKDCE, ECROS, EPRES, EXBAR, ENONE, ESPHR }; int lfevstr(char *z) { return(pmatch(z, etype, evals, NETYPE, -1)); } void evstruc_init(evs) evstruc *evs; { int i; ev(evs) = ETREE; mk(evs) = 100; cut(evs) = 0.8; for (i=0; i<MXDIM; i++) { evs->fl[i] = evs->fl[i+MXDIM] = 0.0; evs->mg[i] = 10; } evs->nce = evs->ncm = 0; } int evstruc_reqi(nvm,ncm,vc) int nvm, ncm, vc; { return(ncm*vc+3*MAX(ncm,nvm)); } /* al=1: allows dynamic allocation. * al=0: inhibit. use with caution. */ void evstruc_alloc(evs,nvm,ncm,vc,al) evstruc *evs; int nvm, ncm, vc, al; { int rw, *k; if (al) { rw = evstruc_reqi(nvm,ncm,vc); if (evs->liw<rw) { evs->iwk = (int *)calloc(rw,sizeof(int)); if ( evs->iwk == NULL ) { printf("Problem allocating memory for evs->iwk\n");fflush(stdout); } evs->liw = rw; } } k = evs->iwk; evs->ce = k; k += vc*ncm; evs->s = k; k += MAX(ncm,nvm); evs->lo = k; k += MAX(ncm,nvm); evs->hi = k; k += MAX(ncm,nvm); } void guessnv(evs,sp,mdl,n,d,lw,nvc) evstruc *evs; smpar *sp; module *mdl; int n, d, *lw, *nvc; { int i, nvm, ncm, vc; npar(sp) = calcp(sp,d); switch(ev(evs)) { case ETREE: atree_guessnv(evs,&nvm,&ncm,&vc,d,nn(sp)); break; case EPHULL: nvm = ncm = mk(evs)*d; vc = d+1; break; case EDATA: case ECROS: nvm = n; ncm = vc = 0; break; case EKDTR: case EKDCE: kdtre_guessnv(evs,&nvm,&ncm,&vc,n,d,nn(sp)); break; case EGRID: nvm = 1; for (i=0; i<d; i++) nvm *= evs->mg[i]; ncm = 0; vc = 1<<d; break; case EXBAR: case ENONE: nvm = 1; ncm = vc = 0; break; case EPRES: nvm = evs->mg[0]; ncm = vc = 0; break; default: LERR(("guessnv: I don't know this evaluation structure.")); nvm = ncm = vc = 0; } lw[0] = des_reqd(n,npar(sp)); lw[1] = lfit_reqd(d,nvm,ncm,mdl); lw[2] = evstruc_reqi(nvm,ncm,vc); lw[6] = des_reqi(n,npar(sp)); lw[3] = pc_reqd(d,npar(sp)); lw[4] = mdl->keepv; lw[5] = mdl->keepc; if (nvc==NULL) return; nvc[0] = nvm; nvc[1] = ncm; nvc[2] = vc; nvc[3] = nvc[4] = 0; } /* * trchck checks the working space on the lfit structure * has space for nvm vertices and ncm cells. */ void lfit_alloc(lf) lfit *lf; { lf->fp.lwk = lf->fp.lev = lf->evs.liw = lf->pc.lwk = 0; lf->lf_init_id = LF_INIT_ID; } int lfit_reqd(d,nvm,ncm,mdl) int d, nvm, ncm; module *mdl; { int z; z = mdl->keepv; return(nvm*z+ncm); } void trchck(lf,nvm,ncm,vc) lfit *lf; int nvm, ncm, vc; { int rw, d, *k; double *z; if (lf->lf_init_id != LF_INIT_ID) lfit_alloc(lf); lf->fp.nvm = nvm; lf->evs.ncm = ncm; d = lf->lfd.d; if (lf->fp.lev < d*nvm) { lf->fp.xev = (double *)calloc(d*nvm,sizeof(double)); if ( lf->fp.xev == NULL ) { printf("Problem allocating memory for lf->fp.xev\n");fflush(stdout); } lf->fp.lev = d*nvm; } rw = lfit_reqd(d,nvm,ncm,&lf->mdl); if (lf->fp.lwk < rw) { lf->fp.coef = (double *)calloc(rw,sizeof(double)); if ( lf->fp.coef == NULL ) { printf("Problem allocating memory for lf->fp.coef\n");fflush(stdout); } lf->fp.lwk = rw; } z = lf->fp.wk = lf->fp.coef; lf->fp.h = NULL; if (!lf->mdl.isset) mut_printf("module not set.\n"); else { if (lf->mdl.alloc!=NULL) lf->mdl.alloc(lf); z += KEEPV(lf) * nvm; } lf->evs.sv = z; z += ncm; evstruc_alloc(&lf->evs,nvm,ncm,vc,1); } void data_guessnv(nvm,ncm,vc,n) int *nvm, *ncm, *vc, n; { *nvm = n; *ncm = *vc = 0; } void dataf(des,lf) design *des; lfit *lf; { int d, i, j, ncm, nv, vc; d = lf->lfd.d; data_guessnv(&nv,&ncm,&vc,lf->lfd.n); trchck(lf,nv,ncm,vc); for (i=0; i<nv; i++) for (j=0; j<d; j++) evptx(&lf->fp,i,j) = datum(&lf->lfd,j,i); for (i=0; i<nv; i++) { PROC_VERTEX(des,lf,i); lf->evs.s[i] = 0; } lf->fp.nv = lf->fp.nvm = nv; lf->evs.nce = 0; } void xbar_guessnv(nvm,ncm,vc) int *nvm, *ncm, *vc; { *nvm = 1; *ncm = *vc = 0; return; } void xbarf(des,lf) design *des; lfit *lf; { int i, d, nvm, ncm, vc; d = lf->lfd.d; xbar_guessnv(&nvm,&ncm,&vc); trchck(lf,1,0,0); for (i=0; i<d; i++) evptx(&lf->fp,0,i) = lf->pc.xbar[i]; PROC_VERTEX(des,lf,0); lf->evs.s[0] = 0; lf->fp.nv = 1; lf->evs.nce = 0; } void preset(des,lf) design *des; lfit *lf; { int i, nv; nv = lf->fp.nvm; trchck(lf,nv,0,0); for (i=0; i<nv; i++) { PROC_VERTEX(des,lf,i); lf->evs.s[i] = 0; } lf->fp.nv = nv; lf->evs.nce = 0; } void crossf(des,lf) design *des; lfit *lf; { int d, i, j, n, nv, ncm, vc; double w; n = lf->lfd.n; d = lf->lfd.d; data_guessnv(&nv,&ncm,&vc,n); trchck(lf,nv,ncm,vc); if (lf->lfd.w==NULL) LERR(("crossf() needs prior weights")); for (i=0; i<n; i++) for (j=0; j<d; j++) evptx(&lf->fp,i,j) = datum(&lf->lfd,j,i); for (i=0; i<n; i++) { lf->evs.s[i] = 0; w = prwt(&lf->lfd,i); lf->lfd.w[i] = 0; PROC_VERTEX(des,lf,i); lf->lfd.w[i] = w; } lf->fp.nv = n; lf->evs.nce = 0; } void gridf(des,lf) design *des; lfit *lf; { int d, i, j, nv, u0, u1, z; nv = 1; d = lf->lfd.d; for (i=0; i<d; i++) { if (lf->evs.mg[i]==0) lf->evs.mg[i] = 2+(int)((lf->evs.fl[i+d]-lf->evs.fl[i])/(lf->lfd.sca[i]*cut(&lf->evs))); nv *= lf->evs.mg[i]; } trchck(lf,nv,0,1<<d); for (i=0; i<nv; i++) { z = i; for (j=0; j<d; j++) { u0 = z%lf->evs.mg[j]; u1 = lf->evs.mg[j]-1-u0; evptx(&lf->fp,i,j) = (lf->evs.mg[j]==1) ? lf->evs.fl[j] : (u1*lf->evs.fl[j]+u0*lf->evs.fl[j+d])/(lf->evs.mg[j]-1); z = z/lf->evs.mg[j]; } lf->evs.s[i] = 0; PROC_VERTEX(des,lf,i); } lf->fp.nv = nv; lf->evs.nce = 0; } int findpt(fp,evs,i0,i1) fitpt *fp; evstruc *evs; int i0, i1; { int i; if (i0>i1) ISWAP(i0,i1); for (i=i1+1; i<fp->nv; i++) if ((evs->lo[i]==i0) && (evs->hi[i]==i1)) return(i); return(-1); } /* add a new vertex at the midpoint of (x[i0],x[i1]). return the vertex number. */ int newsplit(des,lf,i0,i1,pv) design *des; lfit *lf; int i0, i1, pv; { int i, nv; i = findpt(&lf->fp,&lf->evs,i0,i1); if (i>=0) return(i); if (i0>i1) ISWAP(i0,i1); nv = lf->fp.nv; /* the point is new. Now check we have space for the new point. */ if (nv>=lf->fp.nvm) { LERR(("newsplit: out of vertex space")); return(-1); } /* compute the new point, and evaluate the fit */ lf->evs.lo[nv] = i0; lf->evs.hi[nv] = i1; for (i=0; i<lf->fp.d; i++) evptx(&lf->fp,nv,i) = (evptx(&lf->fp,i0,i)+evptx(&lf->fp,i1,i))/2; if (pv) /* pseudo vertex */ { lf->fp.h[nv] = (lf->fp.h[i0]+lf->fp.h[i1])/2; lf->evs.s[nv] = 1; /* pseudo-vertex */ } else /* real vertex */ { PROC_VERTEX(des,lf,nv); lf->evs.s[nv] = 0; } lf->fp.nv++; return(nv); } /* * Copyright 1996-2006 Catherine Loader. */ /* * Functions for constructing the fit and * interpolating on the circle/sphere. d=2 only. */ #include "lfev.h" /* * Guess the number of fitting points. */ void sphere_guessnv(nvm,ncm,vc,mg) int *nvm, *ncm, *vc, *mg; { *nvm = mg[1]*(mg[0]+1); *ncm = 0; *vc = 0; } void sphere_start(des,lf) design *des; lfit *lf; { int d, i, j, ct, nv, ncm, vc, *mg; double rmin, rmax, *orig, r, th, c, s; mg = mg(&lf->evs); sphere_guessnv(&nv,&ncm,&vc,mg); trchck(lf,nv,0,0); d = lf->lfd.d; rmin = lf->evs.fl[0]; rmax = lf->evs.fl[1]; orig = &lf->evs.fl[2]; rmin = 0; rmax = 1; orig[0] = orig[1] = 0.0; ct = 0; for (i=0; i<mg[1]; i++) { th = 2*PI*i/mg[1]; c = cos(th); s = sin(th); for (j=0; j<=mg[0]; j++) { r = rmin + (rmax-rmin)*j/mg[0]; evptx(&lf->fp,ct,0) = orig[0] + r*c; evptx(&lf->fp,ct,1) = orig[1] + r*s; PROC_VERTEX(des,lf,ct); ct++; } } lf->fp.nv = ct; lf->evs.nce = 0; } double sphere_int(lf,x,what) lfit *lf; double *x; int what; { double rmin, rmax, *orig, dx, dy, r, th, th0, th1; double v[64][64], c0, c1, s0, s1, r0, r1, d0, d1; double ll[2], ur[2], xx[2]; int i0, j0, i1, j1, *mg, nc, ce[4]; rmin = lf->evs.fl[0]; rmax = lf->evs.fl[1]; orig = &lf->evs.fl[2]; rmin = 0; rmax = 1; orig[0] = orig[1] = 0.0; mg = mg(&lf->evs); dx = x[0] - orig[0]; dy = x[1] - orig[1]; r = sqrt(dx*dx+dy*dy); th = atan2(dy,dx); /* between -pi and pi */ i0 = (int)floor(mg[1]*th/(2*PI)) % mg[1]; j0 = (int)(mg[0]*(r-rmin)/(rmax-rmin)); i1 = (i0+1) % mg[1]; j1 = j0+1; if (j1>mg[0]) { j0 = mg[0]-1; j1 = mg[0]; } ce[0] = i0*(mg[0]+1)+j0; ce[1] = i0*(mg[0]+1)+j1; ce[2] = i1*(mg[0]+1)+j0; ce[3] = i1*(mg[0]+1)+j1; nc = exvval(&lf->fp,v[0],ce[0],2,what,1); nc = exvval(&lf->fp,v[1],ce[1],2,what,1); nc = exvval(&lf->fp,v[2],ce[2],2,what,1); nc = exvval(&lf->fp,v[3],ce[3],2,what,1); th0 = 2*PI*i0/mg[1]; c0 = cos(th0); s0 = sin(th0); th1 = 2*PI*i1/mg[1]; c1 = cos(th1); s1 = sin(th1); r0 = rmin + j0*(rmax-rmin)/mg[0]; r1 = rmin + j1*(rmax-rmin)/mg[0]; d0 = c0*v[0][1] + s0*v[0][2]; d1 = r0*(c0*v[0][2]-s0*v[0][1]); v[0][1] = d0; v[0][2] = d1; d0 = c0*v[1][1] + s0*v[1][2]; d1 = r1*(c0*v[1][2]-s0*v[1][1]); v[1][1] = d0; v[1][2] = d1; d0 = c1*v[2][1] + s1*v[2][2]; d1 = r0*(c1*v[2][2]-s1*v[2][1]); v[2][1] = d0; v[2][2] = d1; d0 = c1*v[3][1] + s1*v[3][2]; d1 = r1*(c1*v[3][2]-s1*v[3][1]); v[3][1] = d0; v[3][2] = d1; xx[0] = r; xx[1] = th; ll[0] = r0; ll[1] = th0; ur[0] = r1; ur[1] = th1; return(rectcell_interp(xx,v,ll,ur,2,nc)); } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" void solve(A,b,d) /* this is crude! A organized by column. */ double *A, *b; int d; { int i, j, k; double piv; for (i=0; i<d; i++) { piv = A[(d+1)*i]; for (j=i; j<d; j++) A[j*d+i] /= piv; b[i] /= piv; for (j=0; j<d; j++) if (j != i) { piv = A[i*d+j]; A[i*d+j] = 0; for (k=i+1; k<d; k++) A[k*d+j] -= piv*A[k*d+i]; b[j] -= piv*b[i]; } } } void triang_guessnv(nvm,ncm,vc,d,mk) int *nvm, *ncm, *vc, d, mk; { *nvm = *ncm = mk*d; *vc = d+1; return; } int triang_split(lf,ce,le) lfit *lf; double *le; int *ce; { int d, i, j, k, nts, vc; double di, dfx[MXDIM]; nts = 0; d = lf->fp.d; vc = d+1; for (i=0; i<d; i++) for (j=i+1; j<=d; j++) { for (k=0; k<d; k++) dfx[k] = evptx(&lf->fp,ce[i],k)-evptx(&lf->fp,ce[j],k); di = rho(dfx,lf->lfd.sca,d,KSPH,NULL); le[i*vc+j] = le[j*vc+i] = di/MIN(lf->fp.h[ce[i]],lf->fp.h[ce[j]]); nts = nts || le[i*vc+j]>cut(&lf->evs); } return(nts); } void resort(pv,xev,dig) double *xev; int *pv, *dig; { double d0, d1, d2; int i; d0 = d1 = d2 = 0; for (i=0; i<3; i++) { d0 += (xev[3*pv[11]+i]-xev[3*pv[1]+i])*(xev[3*pv[11]+i]-xev[3*pv[1]+i]); d1 += (xev[3*pv[ 7]+i]-xev[3*pv[2]+i])*(xev[3*pv[ 7]+i]-xev[3*pv[2]+i]); d2 += (xev[3*pv[ 6]+i]-xev[3*pv[3]+i])*(xev[3*pv[ 6]+i]-xev[3*pv[3]+i]); } if ((d0<=d1) & (d0<=d2)) { dig[0] = pv[1]; dig[1] = pv[11]; dig[2] = pv[2]; dig[3] = pv[7]; dig[4] = pv[3]; dig[5] = pv[6]; } else if (d1<=d2) { dig[0] = pv[2]; dig[1] = pv[7]; dig[2] = pv[1]; dig[3] = pv[11]; dig[4] = pv[3]; dig[5] = pv[6]; } else { dig[0] = pv[3]; dig[1] = pv[6]; dig[2] = pv[2]; dig[3] = pv[7]; dig[4] = pv[1]; dig[5] = pv[11]; } } void triang_grow(des,lf,ce,ct,term) design *des; lfit *lf; int *ce, *ct, *term; { double le[(1+MXDIM)*(1+MXDIM)], ml; int d, i, j, im, jm, vc, pv[(1+MXDIM)*(1+MXDIM)], dig[6]; int nce[1+MXDIM]; if (lf_error) return; d = lf->fp.d; vc = d+1; if (!triang_split(lf,ce,le)) { if (ct != NULL) { for (i=0; i<vc; i++) term[*ct*vc+i] = ce[i]; (*ct)++; } return; } if (d>3) { ml = 0; for (i=0; i<d; i++) for (j=i+1; j<vc; j++) if (le[i*vc+j]>ml) { ml = le[i*vc+j]; im = i; jm = j; } pv[0] = newsplit(des,lf,(int)ce[im],(int)ce[jm],0); for (i=0; i<vc; i++) nce[i] = ce[i]; nce[im] = pv[0]; triang_grow(des,lf,nce,ct,term); nce[im] = ce[im]; nce[jm] = pv[0]; triang_grow(des,lf,nce,ct,term); return; } for (i=0; i<d; i++) for (j=i+1; j<=d; j++) pv[i*vc+j] = pv[j*vc+i] = newsplit(des,lf,(int)ce[i],(int)ce[j],le[i*vc+j]<=cut(&lf->evs)); for (i=0; i<=d; i++) /* corners */ { for (j=0; j<=d; j++) nce[j] = (j==i) ? ce[i] : pv[i*vc+j]; triang_grow(des,lf,nce,ct,term); } if (d==2) /* center for d=2 */ { nce[0] = pv[5]; nce[1] = pv[2]; nce[2] = pv[1]; triang_grow(des,lf,nce,ct,term); } if (d==3) /* center for d=3 */ { resort(pv,evp(&lf->fp),dig); nce[0] = dig[0]; nce[1] = dig[1]; nce[2] = dig[2]; nce[3] = dig[4]; triang_grow(des,lf,nce,ct,term); nce[2] = dig[5]; nce[3] = dig[3]; triang_grow(des,lf,nce,ct,term); nce[2] = dig[2]; nce[3] = dig[5]; triang_grow(des,lf,nce,ct,term); nce[2] = dig[4]; nce[3] = dig[3]; triang_grow(des,lf,nce,ct,term); } } void triang_descend(tr,xa,ce) lfit *tr; double *xa; int *ce; { double le[(1+MXDIM)*(1+MXDIM)], ml; int d, vc, i, j, im, jm, pv[(1+MXDIM)*(1+MXDIM)]; design *des; des = NULL; if (!triang_split(tr,ce,le)) return; d = tr->fp.d; vc = d+1; if (d>3) /* split longest edge */ { ml = 0; for (i=0; i<d; i++) for (j=i+1; j<vc; j++) if (le[i*vc+j]>ml) { ml = le[i*vc+j]; im = i; jm = j; } pv[0] = newsplit(des,tr,(int)ce[im],(int)ce[jm],0); if (xa[im]>xa[jm]) { xa[im] -= xa[jm]; xa[jm] *= 2; ce[jm] = pv[0]; } else { xa[jm] -= xa[im]; xa[im] *= 2; ce[im] = pv[0]; } triang_descend(tr,xa,ce); return; } for (i=0; i<d; i++) for (j=i+1; j<=d; j++) pv[i*vc+j] = pv[j*vc+i] = newsplit(des,tr,(int)ce[i],(int)ce[j],le[i*d+j]<=cut(&tr->evs)); for (i=0; i<=d; i++) if (xa[i]>=0.5) /* in corner */ { for (j=0; j<=d; j++) { if (i!=j) ce[j] = pv[i*vc+j]; xa[j] = 2*xa[j]; } xa[i] -= 1; triang_descend(tr,xa,ce); return; } if (d==1) { LERR(("weights sum to < 1")); } if (d==2) /* center */ { ce[0] = pv[5]; xa[0] = 1-2*xa[0]; ce[1] = pv[2]; xa[1] = 1-2*xa[1]; ce[2] = pv[1]; xa[2] = 1-2*xa[2]; triang_descend(tr,xa,ce); } if (d==3) /* center */ { double z; int dig[6]; resort(pv,evp(&tr->fp),dig); ce[0] = dig[0]; ce[1] = dig[1]; xa[0] *= 2; xa[1] *= 2; xa[2] *= 2; xa[3] *= 2; if (xa[0]+xa[2]>=1) { if (xa[0]+xa[3]>=1) { ce[2] = dig[2]; ce[3] = dig[4]; z = xa[0]; xa[3] += z-1; xa[2] += z-1; xa[0] = xa[1]; xa[1] = 1-z; } else { ce[2] = dig[2]; ce[3] = dig[5]; z = xa[3]; xa[3] = xa[1]+xa[2]-1; xa[1] = z; z = xa[2]; xa[2] += xa[0]-1; xa[0] = 1-z; } } else { if (xa[1]+xa[2]>=1) { ce[2] = dig[5]; ce[3] = dig[3]; xa[1] = 1-xa[1]; xa[2] -= xa[1]; xa[3] -= xa[1]; } else { ce[2] = dig[4]; ce[3] = dig[3]; z = xa[3]; xa[3] += xa[1]-1; xa[1] = xa[2]; xa[2] = z+xa[0]-1; xa[0] = 1-z; } } triang_descend(tr,xa,ce); } } void covrofdata(lfd,V,mn) /* covar of data; mean in mn */ lfdata *lfd; double *V, *mn; { int d, i, j, k; double s; s = 0; d = lfd->d; for (i=0; i<d*d; i++) V[i] = 0; for (i=0; i<lfd->n; i++) { s += prwt(lfd,i); for (j=0; j<d; j++) for (k=0; k<d; k++) V[j*d+k] += prwt(lfd,i)*(datum(lfd,j,i)-mn[j])*(datum(lfd,k,i)-mn[k]); } for (i=0; i<d*d; i++) V[i] /= s; } int intri(x,w,xev,xa,d) /* is x in triangle bounded by xd[0..d-1]? */ double *x, *xev, *xa; int *w, d; { int i, j; double eps, *r, xd[MXDIM*MXDIM]; eps = 1.0e-10; r = &xev[w[d]*d]; for (i=0; i<d; i++) { xa[i] = x[i]-r[i]; for (j=0; j<d; j++) xd[i*d+j] = xev[w[i]*d+j]-r[j]; } solve(xd,xa,d); xa[d] = 1.0; for (i=0; i<d; i++) xa[d] -= xa[i]; for (i=0; i<=d; i++) if ((xa[i]<-eps) | (xa[i]>1+eps)) return(0); return(1); } void triang_start(des,lf) /* Triangulation with polyhedral start */ design *des; lfit *lf; { int i, j, k, n, d, nc, nvm, ncm, vc; int *ce, ed[1+MXDIM]; double V[MXDIM*MXDIM], P[MXDIM*MXDIM], sigma, z[MXDIM], xa[1+MXDIM], *xev; xev = evp(&lf->fp); d = lf->lfd.d; n = lf->lfd.n; lf->fp.nv = nc = 0; triang_guessnv(&nvm,&ncm,&vc,d,mk(&lf->evs)); trchck(lf,nvm,ncm,vc); ce = lf->evs.ce; for (j=0; j<d; j++) xev[j] = lf->pc.xbar[j]; lf->fp.nv = 1; covrofdata(&lf->lfd,V,xev); /* fix this with scaling */ eig_dec(V,P,d); for (i=0; i<d; i++) /* add vertices +- 2sigma*eigenvect */ { sigma = sqrt(V[i*(d+1)]); for (j=0; j<d; j++) xev[lf->fp.nv*d+j] = xev[j]-2*sigma*P[j*d+i]; lf->fp.nv++; for (j=0; j<d; j++) xev[lf->fp.nv*d+j] = xev[j]+2*sigma*P[j*d+i]; lf->fp.nv++; } for (i=0; i<n; i++) /* is point i inside? */ { ed[0] = 0; for (j=0; j<d; j++) { z[j] = 0; for (k=0; k<d; k++) z[j] += P[k*d+j]*(datum(&lf->lfd,k,i)-xev[k]); ed[j+1] = 2*j+1+(z[j]>0); for (k=0; k<d; k++) z[j] = datum(&lf->lfd,j,i); } k = intri(z,ed,xev,xa,d); if (xa[0]<0) { for (j=1; j<=d; j++) for (k=0; k<d; k++) xev[ed[j]*d+k] = xa[0]*xev[k]+(1-xa[0])*xev[ed[j]*d+k]; } } nc = 1<<d; /* create initial cells */ for (i=0; i<nc; i++) { ce[i*vc] = 0; k = i; for (j=0; j<d; j++) { ce[i*vc+j+1] = 2*j+(k%2)+1; k>>=1; } } for (i=0; i<lf->fp.nv; i++) { PROC_VERTEX(des,lf,i); if (lf_error) return; lf->evs.s[i] = 0; } for (i=0; i<nc; i++) triang_grow(des,lf,&ce[i*vc],NULL,NULL); lf->evs.nce = nc; } double triang_cubicint(v,vv,w,d,nc,xxa) double *v, *vv, *xxa; int *w, d, nc; { double sa, lb, *vert0, *vert1, *vals0, *vals1, deriv0, deriv1; int i, j, k; if (nc==1) /* linear interpolate */ { sa = 0; for (i=0; i<=d; i++) sa += xxa[i]*vv[i]; return(sa); } sa = 1.0; for (j=d; j>0; j--) /* eliminate v[w[j]] */ { lb = xxa[j]/sa; for (k=0; k<j; k++) /* Interpolate edge v[w[k]],v[w[j]] */ { vert0 = &v[w[k]*d]; vert1 = &v[w[j]*d]; vals0 = &vv[k*nc]; vals1 = &vv[j*nc]; deriv0 = deriv1 = 0; for (i=0; i<d; i++) { deriv0 += (vert1[i]-vert0[i])*vals0[i+1]; deriv1 += (vert1[i]-vert0[i])*vals1[i+1]; } vals0[0] = cubic_interp(lb,vals0[0],vals1[0],deriv0,deriv1); for (i=1; i<=d; i++) vals0[i] = (1-lb)*((1-lb)*vals0[i]+lb*vals1[i]); } sa -= xxa[j]; if (sa<=0) j = 0; } return(vals0[0]); } double triang_clotoch(xev,vv,ce,p,xxa) double *xev, *vv, *xxa; int *ce, p; { double cfo[3], cfe[3], cg[9], *va, *vb, *vc, l0, nm[3], na, nb, nc, *xl, *xr, *xz, d0, d1, lb, dlt, gam; int i, w[3], cfl, cfr; if (p==1) return(xxa[0]*vv[0]+xxa[1]*vv[1]+xxa[2]*vv[2]); if (xxa[2]<=MIN(xxa[0],xxa[1])) { va = &xev[2*ce[0]]; vb = &xev[2*ce[1]]; vc = &xev[2*ce[2]]; w[0] = 0; w[1] = 3; w[2] = 6; } else if (xxa[1]<xxa[0]) { w[0] = 0; w[1] = 6; w[2] = 3; va = &xev[2*ce[0]]; vb = &xev[2*ce[2]]; vc = &xev[2*ce[1]]; lb = xxa[1]; xxa[1] = xxa[2]; xxa[2] = lb; } else { w[0] = 6; w[1] = 3; w[2] = 0; va = &xev[2*ce[2]]; vb = &xev[2*ce[1]]; vc = &xev[2*ce[0]]; lb = xxa[0]; xxa[0] = xxa[2]; xxa[2] = lb; } /* set cg to values and derivatives on standard triangle */ for (i=0; i<3; i++) { cg[3*i] = vv[w[i]]; cg[3*i+1] = ((vb[0]-va[0])*vv[w[i]+1] +(vb[1]-va[1])*vv[w[i]+2])/2; /* df/dx */ cg[3*i+2] = ((2*vc[0]-vb[0]-va[0])*vv[w[i]+1] +(2*vc[1]-vb[1]-va[1])*vv[w[i]+2])/2.0; /* sqrt{3} df/dy */ } dlt = (vb[0]-va[0])*(vc[1]-va[1])-(vc[0]-va[0])*(vb[1]-va[1]); /* Twice area; +ve if abc antic.wise -ve is abc c.wise */ cfo[0] = (cg[0]+cg[3]+cg[6])/3; cfo[1] = (2*cg[0]-cg[3]-cg[6])/4; cfo[2] = (2*cg[3]-cg[0]-cg[6])/4; na = -cg[1]+cg[2]; /* perp. deriv, rel. length 2 */ nb = -cg[4]-cg[5]; nc = 2*cg[7]; cfo[1] += (nb-nc)/16; cfo[2] += (nc-na)/16; na = -cg[1]-cg[2]/3.0; /* derivatives back to origin */ nb = cg[4]-cg[5]/3.0; nc = cg[8]/1.5; cfo[0] -= (na+nb+nc)*7/54; cfo[1] += 13*(nb+nc-2*na)/144; cfo[2] += 13*(na+nc-2*nb)/144; for (i=0; i<3; i++) { /* Outward normals by linear interpolation on original triangle. Convert to outward normals on standard triangle. Actually, computed to opposite corner */ switch(i) { case 0: xl = vc; xr = vb; xz = va; cfl = w[2]; cfr = w[1]; break; case 1: xl = va; xr = vc; xz = vb; cfl = w[0]; cfr = w[2]; break; case 2: xl = vb; xr = va; xz = vc; cfl = w[1]; cfr = w[0]; break; } na = xr[0]-xl[0]; nb = xr[1]-xl[1]; lb = na*na+nb*nb; d0 = 1.5*(vv[cfr]-vv[cfl]) - 0.25*(na*(vv[cfl+1]+vv[cfr+1]) +nb*(vv[cfl+2]+vv[cfr+2])); d1 = 0.5*( na*(vv[cfl+2]+vv[cfr+2])-nb*(vv[cfl+1]+vv[cfr+1]) ); l0 = (xz[0]-xl[0])*na+(xz[1]-xl[1])*nb-lb/2; nm[i] = (d1*dlt-l0*d0)/lb; } cfo[0] -= (nm[0]+nm[1]+nm[2])*4/81; cfo[1] += (2*nm[0]-nm[1]-nm[2])/27; cfo[2] += (2*nm[1]-nm[0]-nm[2])/27; gam = xxa[0]+xxa[1]-2*xxa[2]; if (gam==0) return(cfo[0]); lb = (xxa[0]-xxa[2])/gam; d0 = -2*cg[4]; d1 = -2*cg[1]; cfe[0] = cubic_interp(lb,cg[3],cg[0],d0,d1); cfe[1] = cubintd(lb,cg[3],cg[0],d0,d1); cfe[2] = -(1-lb)*(1-2*lb)*cg[5] + 4*lb*(1-lb)*nm[2] - lb*(2*lb-1)*cg[2]; d0 = 2*(lb*cfo[1]+(1-lb)*cfo[2]); d1 = (lb-0.5)*cfe[1]+cfe[2]/3.0; return(cubic_interp(gam,cfo[0],cfe[0],d0,d1)); } int triang_getvertexvals(fp,evs,vv,i,what) fitpt *fp; evstruc *evs; double *vv; int i, what; { double dx, P, le, vl[1+MXDIM], vh[1+MXDIM]; int d, il, ih, j, nc; d = fp->d; if (evs->s[i]==0) return(exvval(fp,vv,i,d,what,0)); il = evs->lo[i]; nc = triang_getvertexvals(fp,evs,vl,il,what); ih = evs->hi[i]; nc = triang_getvertexvals(fp,evs,vh,ih,what); vv[0] = (vl[0]+vh[0])/2; if (nc==1) return(nc); P = 1.5*(vh[0]-vl[0]); le = 0.0; for (j=0; j<d; j++) { dx = evptx(fp,ih,j)-evptx(fp,il,j); vv[0] += dx*(vl[j+1]-vh[j+1])/8; vv[j+1] = (vl[j+1]+vh[j+1])/2; P -= 1.5*dx*vv[j+1]; le += dx*dx; } for (j=0; j<d; j++) vv[j+1] += P*(evptx(fp,ih,j)-evptx(fp,il,j))/le; return(nc); } double triang_int(lf,x,what) lfit *lf; double *x; int what; { int d, i, j, k, vc, nc; int *ce, nce[1+MXDIM]; double xa[1+MXDIM], vv[(1+MXDIM)*(1+MXDIM)], lb; fitpt *fp; evstruc *evs; fp = &lf->fp; evs= &lf->evs; d = fp->d; vc = d+1; ce = evs->ce; i = 0; while ((i<evs->nce) && (!intri(x,&ce[i*vc],evp(fp),xa,d))) i++; if (i==evs->nce) return(NOSLN); i *= vc; for (j=0; j<vc; j++) nce[j] = ce[i+j]; triang_descend(lf,xa,nce); /* order the vertices -- needed for asymmetric interptr */ do { k=0; for (i=0; i<d; i++) if (nce[i]>nce[i+1]) { j=nce[i]; nce[i]=nce[i+1]; nce[i+1]=j; k=1; lb = xa[i]; xa[i] = xa[i+1]; xa[i+1] = lb; } } while(k); nc = 0; for (i=0; i<vc; i++) nc = triang_getvertexvals(fp,evs,&vv[i*nc],nce[i],what); return((d==2) ? triang_clotoch(evp(fp),vv,nce,nc,xa) : triang_cubicint(evp(fp),vv,nce,d,nc,xa)); } /* * Copyright 1996-2006 Catherine Loader. */ /* * Functions for computing residuals and fitted values from * the locfit object. * * fitted(lf,fit,what,cv,ty) computes fitted values from the * fit structure in lf. * resid(y,c,w,th,mi,ty) converts fitted values to residuals */ #include "lfev.h" #define NRT 8 static char *rtype[NRT] = { "deviance", "d2", "pearson", "raw", "ldot", "lddot", "fit", "mean" }; static int rvals[NRT] = { RDEV, RDEV2, RPEAR, RRAW, RLDOT, RLDDT, RFIT, RMEAN}; int restyp(z) char *z; { int val; val = pmatch(z, rtype, rvals, NRT, -1); if (val==-1) LERR(("Unknown type = %s",z)); return(val); } double resid(y,w,th,fam,ty,res) int fam, ty; double y, w, th, *res; { double raw; fam = fam & 63; if ((fam==TGAUS) | (fam==TROBT) | (fam==TCAUC)) raw = y-res[ZMEAN]; else raw = y-w*res[ZMEAN]; switch(ty) { case RDEV: if (res[ZDLL]>0) return(sqrt(-2*res[ZLIK])); else return(-sqrt(-2*res[ZLIK])); case RPEAR: if (res[ZDDLL]<=0) { if (res[ZDLL]==0) return(0); return(NOSLN); } return(res[ZDLL]/sqrt(res[ZDDLL])); case RRAW: return(raw); case RLDOT: return(res[ZDLL]); case RDEV2: return(-2*res[ZLIK]); case RLDDT: return(res[ZDDLL]); case RFIT: return(th); case RMEAN: return(res[ZMEAN]); default: LERR(("resid: unknown residual type %d",ty)); } return(0.0); } double studentize(res,inl,var,ty,link) double res, inl, var, *link; int ty; { double den; inl *= link[ZDDLL]; var = var*var*link[ZDDLL]; if (inl>1) inl = 1; if (var>inl) var = inl; den = 1-2*inl+var; if (den<0) return(0.0); switch(ty) { case RDEV: case RPEAR: case RRAW: case RLDOT: return(res/sqrt(den)); case RDEV2: return(res/den); default: return(res); } } void fitted(lf,fit,what,cv,st,ty) lfit *lf; double *fit; int what, cv, st, ty; { int i, j, d, n, evo; double xx[MXDIM], th, inl, var, link[LLEN]; n = lf->lfd.n; d = lf->lfd.d; evo = ev(&lf->evs); cv &= (evo!=ECROS); if ((evo==EDATA)|(evo==ECROS)) evo = EFITP; setfamily(&lf->sp); for (i=0; i<n; i++) { for (j=0; j<d; j++) xx[j] = datum(&lf->lfd,j,i); th = dointpoint(lf,xx,what,evo,i); if ((what==PT0)|(what==PVARI)) th = th*th; if (what==PCOEF) { th += base(&lf->lfd,i); stdlinks(link,&lf->lfd,&lf->sp,i,th,rsc(&lf->fp)); if ((cv)|(st)) { inl = dointpoint(lf,xx,PT0,evo,i); inl = inl*inl; if (cv) { th -= inl*link[ZDLL]; stdlinks(link,&lf->lfd,&lf->sp,i,th,rsc(&lf->fp)); } if (st) var = dointpoint(lf,xx,PNLX,evo,i); } fit[i] = resid(resp(&lf->lfd,i),prwt(&lf->lfd,i),th,fam(&lf->sp),ty,link); if (st) fit[i] = studentize(fit[i],inl,var,ty,link); } else fit[i] = th; if (lf_error) return; } } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" extern double robscale; /* special version of ressumm to estimate sigma^2, with derivative estimation */ void ressummd(lf) lfit *lf; { int i; double s0, s1; s0 = s1 = 0.0; if ((fam(&lf->sp)&64)==0) { rv(&lf->fp) = 1.0; return; } for (i=0; i<lf->fp.nv; i++) { s0 += lf->fp.lik[2*lf->fp.nvm+i]; s1 += lf->fp.lik[i]; } if (s0==0.0) rv(&lf->fp) = 0.0; else rv(&lf->fp) = -2*s1/s0; } /* * res[0] = log-likelihood. * res[1] = df0 = tr(H) * res[2] = df0 = tr(H'H) * res[3] = s^2. * res[5] = robustscale. */ void ressumm(lf,des,res) lfit *lf; design *des; double *res; { int i, j, evo, tg; double *oy, pw, r1, r2, rdf, t0, t1, u[MXDIM], link[LLEN]; fitpt *fp; res[0] = res[1] = res[2] = 0.0; evo = ev(&lf->evs); if ((evo==EKDCE) | (evo==EPRES)) { res[3] = 1.0; return; } if (lf->dv.nd>0) { ressummd(lf); return; } r1 = r2 = 0.0; if ((evo==EDATA) | (evo==ECROS)) evo = EFITP; for (i=0; i<lf->lfd.n; i++) { for (j=0; j<lf->lfd.d; j++) u[j] = datum(&lf->lfd,j,i); fitv(des,i) = base(&lf->lfd,i)+dointpoint(lf,u,PCOEF,evo,i); des->wd[i] = resp(&(lf->lfd),i) - fitv(des,i); wght(des,i) = 1.0; des->ind[i] = i; } tg = fam(&lf->sp); res[5] = 1.0; if ((tg==TROBT+64) | (tg==TCAUC+64)) /* global robust scale */ { oy = lf->lfd.y; lf->lfd.y = des->wd; des->xev = lf->pc.xbar; locfit(&lf->lfd,des,&lf->sp,1,0,0); lf->lfd.y = oy; res[5] = robscale; } for (i=0; i<lf->lfd.n; i++) { for (j=0; j<lf->lfd.d; j++) u[j] = datum(&lf->lfd,j,i); t0 = dointpoint(lf,u,PT0,evo,i); t1 = dointpoint(lf,u,PNLX,evo,i); stdlinks(link,&lf->lfd,&lf->sp,i,fitv(des,i),res[5]); t1 = t1*t1*link[ZDDLL]; t0 = t0*t0*link[ZDDLL]; if (t1>1) t1 = 1; if (t0>1) t0 = 1; /* no observation gives >1 deg.free */ res[0] += link[ZLIK]; res[1] += t0; res[2] += t1; pw = prwt(&lf->lfd,i); if (pw>0) { r1 += link[ZDLL]*link[ZDLL]/pw; r2 += link[ZDDLL]/pw; } } res[3] = 1.0; if ((fam(&lf->sp)&64)==64) /* quasi family */ { rdf = lf->lfd.n-2*res[1]+res[2]; if (rdf<1.0) { WARN(("Estimated rdf < 1.0; not estimating variance")); } else res[3] = r1/r2 * lf->lfd.n / rdf; } /* try to ensure consistency for family="circ"! */ if (((fam(&lf->sp)&63)==TCIRC) & (lf->lfd.d==1)) { int *ind, nv; double dlt, th0, th1; ind = des->ind; nv = fp->nv; for (i=0; i<nv; i++) ind[i] = i; lforder(ind,evp(fp),0,nv-1); for (i=1; i<nv; i++) { dlt = evptx(fp,ind[i],0)-evptx(fp,ind[i-1],0); th0 = fp->coef[ind[i]]-dlt*fp->coef[ind[i]+nv]-fp->coef[ind[i-1]]; th1 = fp->coef[ind[i]]-dlt*fp->coef[ind[i-1]+nv]-fp->coef[ind[i-1]]; if ((th0>PI)&(th1>PI)) { for (j=0; j<i; j++) fp->coef[ind[j]] += 2*PI; i--; } if ((th0<(-PI))&(th1<(-PI))) { for (j=0; j<i; j++) fp->coef[ind[j]] -= 2*PI; i--; } } } } double rss(lf,des,df) lfit *lf; design *des; double *df; { double ss, res[10]; ss = 0; ressumm(lf,des,res); *df = lf->lfd.n - 2*res[1] + res[2]; return(-2*res[0]); } /* * Copyright 1996-2006 Catherine Loader. */ /* * * Derivative corrections. The local slopes are not the derivatives * of the local likelihood estimate; the function dercor() computes * the adjustment to get the correct derivatives under the assumption * that h is constant. * * By differentiating the local likelihood equations, one obtains * * d ^ ^ T -1 T d . ^ * -- a = a - (X W V X) X -- W l( Y, X a) * dx 0 1 dx */ #include "lfev.h" extern double robscale; void dercor(lfd,sp,des,coef) lfdata *lfd; smpar *sp; design *des; double *coef; { double s1, dc[MXDIM], wd, link[LLEN]; int i, ii, j, m, d, p; if (fam(sp)<=THAZ) return; if (ker(sp)==WPARM) return; d = lfd->d; p = des->p; m = des->n; if (lf_debug>1) mut_printf(" Correcting derivatives\n"); fitfun(lfd, sp, des->xev,des->xev,des->f1,NULL); jacob_solve(&des->xtwx,des->f1); setzero(dc,d); /* correction term is e1^T (XTWVX)^{-1} XTW' ldot. */ for (i=0; i<m; i++) { s1 = innerprod(des->f1,d_xi(des,i),p); ii = des->ind[i]; stdlinks(link,lfd,sp,ii,fitv(des,ii),robscale); for (j=0; j<d; j++) { wd = wght(des,ii)*weightd(datum(lfd,j,ii)-des->xev[j],lfd->sca[j], d,ker(sp),kt(sp),des->h,lfd->sty[j],dist(des,ii)); dc[j] += s1*wd*link[ZDLL]; } } for (j=0; j<d; j++) coef[j+1] += dc[j]; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" void allocallcf(lf) lfit *lf; { lf->fp.coef = VVEC(lf,0); lf->fp.h = VVEC(lf,NPAR(lf)); } int procvallcf(des,lf,v) design *des; lfit *lf; int v; { int i, p, lf_status; lf_status = procv_nov(des,lf,v); if (lf_error) return(lf_status); p = NPAR(lf); for (i=0; i<p; i++) VVAL(lf,v,i) = des->cf[i]; lf->fp.h[v] = des->h; return(0); } void initallcf(lf) lfit *lf; { PROCV(lf) = procvallcf; ALLOC(lf) = allocallcf; PPROC(lf) = NULL; KEEPV(lf) = NPAR(lf)+1; KEEPC(lf) = 0; NOPC(lf) = 1; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" void pprocgam(lf,des,res) lfit *lf; design *des; double *res; { int i, j, n, evo, op; double *fv, *vr, df, t0, t1, u[MXDIM], link[LLEN]; n = lf->lfd.n; fv = res; vr = &res[n]; df = 0.0; evo = ev(&lf->evs); if (evo==EDATA) evo = EFITP; for (i=0; i<n; i++) { for (j=0; j<lf->lfd.d; j++) u[j] = datum(&lf->lfd,j,i); fitv(des,i) = base(&lf->lfd,i)+dointpoint(lf,u,PCOEF,evo,i); lf->lfd.y[i] -= fitv(des,i); wght(des,i) = 1.0; des->ind[i] = i; t0 = dointpoint(lf,u,PT0,evo,i); t1 = dointpoint(lf,u,PNLX,evo,i); stdlinks(link,&lf->lfd,&lf->sp,i,fitv(des,i),1.0); t0 = t0*t0*link[ZDDLL]; t1 = t1*t1*link[ZDDLL]; if (t0>1) t0 = 1; /* no observation gives >1 deg.free */ if (t1>1) t1 = 1; /* no observation gives >1 deg.free */ vr[i] = t1; df += t0; } des->n = n; deg(&lf->sp) = 1; op = npar(&lf->sp); npar(&lf->sp) = des->p = 1+lf->lfd.d; des->xev = lf->pc.xbar; locfit(&lf->lfd,des,&lf->sp,1,0,0); for (i=0; i<n; i++) fv[i] = resp(&lf->lfd,i) - fitv(des,i); for (i=0; i<=lf->lfd.d; i++) lf->pc.coef[i] += des->cf[i]; res[2*n] = df-2; npar(&lf->sp) = op; } void initgam(lf) lfit *lf; { initstd(lf); PPROC(lf) = pprocgam; KEEPC(lf) = 2*NOBS(lf)+1; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" int procvhatm(des,lf,v) design *des; lfit *lf; int v; { int k; double *l; l = &lf->fp.coef[v*lf->lfd.n]; if ((ker(&lf->sp)!=WPARM) | (!haspc(&lf->pc))) { k = procv_nov(des,lf,v); wdiag(&lf->lfd,&lf->sp,des,l,&lf->dv,0,1,1); } else wdiagp(&lf->lfd,&lf->sp,des,l,&lf->pc,&lf->dv,0,1,1); lf->fp.h[v] = des->h; return(k); } void allochatm(lf) lfit *lf; { lf->fp.coef = VVEC(lf,0); lf->fp.h = VVEC(lf,NOBS(lf)); } void pprochatm(lf,des,res) lfit *lf; design *des; double *res; { transpose(lf->fp.coef,lf->fp.nvm,lf->lfd.n); } void inithatm(lf) lfit *lf; { PROCV(lf) = procvhatm; ALLOC(lf) = allochatm; PPROC(lf) = pprochatm; KEEPV(lf) = NOBS(lf)+1; KEEPC(lf) = 1; NOPC(lf) = 1; /* could use pc if mi[MKER] == WPARM */ } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" static lfit *lf_scb; static lfdata *lfd_scb; static smpar *scb_sp; static design *des_scb; int scbfitter(x,l,reqd) double *x, *l; int reqd; { int m; des_scb->xev = x; if ((ker(scb_sp)!=WPARM) | (!haspc(&lf_scb->pc))) { locfit(lfd_scb,des_scb,&lf_scb->sp,1,1,0); m = wdiag(lfd_scb, scb_sp, des_scb,l,&lf_scb->dv,reqd,2,0); } else m = wdiagp(lfd_scb, scb_sp, des_scb,l,&lf_scb->pc,&lf_scb->dv,reqd,2,0); return(m); } int constants(lf,des,res) lfit *lf; design *des; double *res; { int d, m, nt; double *wk; evstruc *evs; lf_scb = lf; des_scb = des; lfd_scb = &lf->lfd; scb_sp = &lf->sp; evs = &lf->evs; d = lfd_scb->d; m = lfd_scb->n; trchck(lf,0,0,0); if (lf_error) return(0); if ((ker(scb_sp) != WPARM) && (lf->sp.nn>0)) WARN(("constants are approximate for varying h")); npar(scb_sp) = calcp(scb_sp,lf->lfd.d); des_init(des,m,npar(scb_sp)); set_scales(&lf->lfd); set_flim(&lf->lfd,&lf->evs); compparcomp(des,&lf->lfd,&lf->sp,&lf->pc,ker(scb_sp)!=WPARM); wk = &res[d+1]; nt = tube_constants(scbfitter,d,m,ev(evs),mg(evs),evs->fl, res,wk,(d>3) ? 4 : d+1,0); lf->evs.nce = nt; /* cheat way to return it to S. */ return(nt); } void initkappa(lf) lfit *lf; { PROCV(lf) = NULL; ALLOC(lf) = NULL; PPROC(lf) = (void *)constants; KEEPV(lf) = 0; KEEPC(lf) = NVAR(lf)+1+k0_reqd(NVAR(lf),NOBS(lf),0); NOPC(lf) = 0; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" /* fix df computation for link=IDENT. */ void pproclscv(lf,des,res) lfit *lf; design *des; double *res; { double df, fh, fh_cv, infl, z0, z1, x[MXDIM]; int i, n, j, evo; z1 = df = 0.0; evo = ev(&lf->evs); n = lf->lfd.n; if ((evo==EDATA) | (evo==ECROS)) evo = EFITP; z0 = dens_integrate(lf,des,2); for (i=0; i<n; i++) { for (j=0; j<lf->lfd.d; j++) x[j] = datum(&lf->lfd,j,i); fh = base(&lf->lfd,i)+dointpoint(lf,x,PCOEF,evo,i); if (link(&lf->sp)==LLOG) fh = exp(fh); infl = dointpoint(lf,x,PT0,evo,i); infl = infl * infl; if (infl>1) infl = 1; fh_cv = (link(&lf->sp) == LIDENT) ? (n*fh - infl) / (n-1.0) : fh*(1-infl)*n/(n-1.0); z1 += fh_cv; df += infl; } res[0] = z0-2*z1/n; res[1] = df; } void initlscv(lf) lfit *lf; { initstd(lf); KEEPC(lf) = 2; PPROC(lf) = pproclscv; NOPC(lf) = 1; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" static double pen, sig2; void goldensec(f,des,tr,eps,xm,ym,meth) double (*f)(), eps, *xm, *ym; int meth; design *des; lfit *tr; { double x[4], y[4], xx[11], yy[11]; int i, im; xx[0] = tr->sp.fixh; if (xx[0]<=0) { LERR(("regband: initialize h>0")); return; } for (i=0; i<=10; i++) { if (i>0) xx[i] = (1+gold_rat)*xx[i-1]; yy[i] = f(xx[i],des,tr,meth); if ((i==0) || (yy[i]<yy[im])) im = i; } if (im==0) im = 1; if (im==10)im = 9; x[0] = xx[im-1]; y[0] = yy[im-1]; x[1] = xx[im]; y[1] = yy[im]; x[3] = xx[im+1]; y[3] = yy[im+1]; x[2] = gold_rat*x[3]+(1-gold_rat)*x[0]; y[2] = f(x[2],des,tr,meth); while (x[3]-x[0]>eps) { if (y[1]<y[2]) { x[3] = x[2]; y[3] = y[2]; x[2] = x[1]; y[2] = y[1]; x[1] = gold_rat*x[0]+(1-gold_rat)*x[3]; y[1] = f(x[1],des,tr,meth); } else { x[0] = x[1]; y[0] = y[1]; x[1] = x[2]; y[1] = y[2]; x[2] = gold_rat*x[3]+(1-gold_rat)*x[0]; y[2] = f(x[2],des,tr,meth); } } im = 0; for (i=1; i<4; i++) if (y[i]<y[im]) im = i; *xm = x[im]; *ym = y[im]; } double dnk(x,k) double x; int k; { double f; switch(k) { case 0: f = 1; break; case 1: f = -x; break; case 2: f = x*x-1; break; case 3: f = x*(x*x-3); break; case 4: f = 3-x*x*(6-x*x); break; case 5: f = -x*(15-x*x*(10-x*x)); break; case 6: f = -15+x*x*(45-x*x*(15-x*x)); break; default: LERR(("dnk: k=%d too large",k)); return(0.0); } return(f*exp(-x*x/2)/S2PI); } double locai(h,des,lf) double h; design *des; lfit *lf; { double cp, res[10]; nn(&lf->sp) = h; lf->mdl.procv = procvstd; nstartlf(des,lf); ressumm(lf,des,res); cp = -2*res[0] + pen*res[1]; return(cp); } static int fc; double loccp(h,des,lf,m) /* m=1: cp m=2: gcv */ double h; design *des; lfit *lf; int m; { double cp, res[10]; int dg, n; n = lf->lfd.n; nn(&lf->sp) = 0; fixh(&lf->sp) = h; lf->mdl.procv = procvstd; nstartlf(des,lf); ressumm(lf,des,res); if (m==1) { if (fc) sig2 = res[3]; /* first call - set sig2 */ cp = -2*res[0]/sig2 - n + 2*res[1]; } else cp = -2*n*res[0]/((n-res[1])*(n-res[1])); fc = 0; return(cp); } double cp(des,lf,meth) design *des; lfit *lf; int meth; { double hm, ym; fc = 1; goldensec(loccp,des,lf,0.001,&hm,&ym,meth); return(hm); } double gkk(des,lf) design *des; lfit *lf; { double h, h5, nf, th; int i, j, n, dg0, dg1; ev(&lf->evs)= EDATA; nn(&lf->sp) = 0; n = lf->lfd.n; dg0 = deg0(&lf->sp); /* target degree */ dg1 = dg0+1+(dg0%2==0); /* pilot degree */ nf = exp(log(1.0*n)/10); /* bandwidth inflation factor */ h = lf->sp.fixh; /* start bandwidth */ for (i=0; i<=10; i++) { deg(&lf->sp) = dg1; lf->sp.fixh = h*nf; lf->mdl.procv = procvstd; nstartlf(des,lf); th = 0; for (j=10; j<n-10; j++) th += lf->fp.coef[dg1*n+j]*lf->fp.coef[dg1*n+j]; th *= n/(n-20.0); h5 = sig2 * Wikk(ker(&lf->sp),dg0) / th; h = exp(log(h5)/(2*dg1+1)); if (lf_error) return(0.0); /* mut_printf("pilot %8.5f sel %8.5f\n",lf->sp.fixh,h); */ } return(h); } double rsw(des,lf) design *des; lfit *lf; { int i, j, k, nmax, nvm, n, mk, evo, dg0, dg1; double rss[6], cp[6], th22, dx, d2, hh; nmax = 5; evo = ev(&lf->evs); ev(&lf->evs) = EGRID; mk = ker(&lf->sp); ker(&lf->sp) = WRECT; dg0 = deg0(&lf->sp); dg1 = 1 + dg0 + (dg0%2==0); deg(&lf->sp) = 4; for (k=nmax; k>0; k--) { lf->evs.mg[0] = k; lf->evs.fl[0] = 1.0/(2*k); lf->evs.fl[1] = 1-1.0/(2*k); nn(&lf->sp) = 0; fixh(&lf->sp) = 1.0/(2*k); lf->mdl.procv = procvstd; nstartlf(des,lf); nvm = lf->fp.nvm; rss[k] = 0; for (i=0; i<k; i++) rss[k] += -2*lf->fp.lik[i]; } n = lf->lfd.n; k = 1; for (i=1; i<=nmax; i++) { /* cp[i] = (n-5*nmax)*rss[i]/rss[nmax]-(n-10*i); */ cp[i] = rss[i]/sig2-(n-10*i); if (cp[i]<cp[k]) k = i; } lf->evs.mg[0] = k; lf->evs.fl[0] = 1.0/(2*k); lf->evs.fl[1] = 1-1.0/(2*k); nn(&lf->sp) = 0; fixh(&lf->sp) = 1.0/(2*k); lf->mdl.procv = procvstd; nstartlf(des,lf); ker(&lf->sp) = mk; ev(&lf->evs) = evo; nvm = lf->fp.nvm; th22 = 0; for (i=10; i<n-10; i++) { j = floor(k*datum(&lf->lfd,0,i)); if (j>=k) j = k-1; dx = datum(&lf->lfd,0,i)-evptx(&lf->fp,0,j); if (dg1==2) d2 = lf->fp.coef[2*nvm+j]+dx*lf->fp.coef[3*nvm+j]+dx*dx*lf->fp.coef[4*nvm+j]/2; else d2 = lf->fp.coef[4*nvm+j]; th22 += d2*d2; } hh = Wikk(mk,dg0)*sig2/th22*(n-20.0)/n; return(exp(log(hh)/(2*dg1+1))); } #define MAXMETH 10 void rband(lf,des,hhat) lfit *lf; design *des; double *hhat; { int i, dg, nmeth, meth[MAXMETH]; double h0, res[10]; nmeth = lf->dv.nd; for (i=0; i<nmeth; i++) meth[i] = lf->dv.deriv[i]; lf->dv.nd = 0; /* first, estimate sigma^2. * this is ridiculously bad. lf->sp.fixh = 0.05???? */ /* dg = deg(&lf->sp); deg(&lf->sp) = 2; h0 = lf->sp.fixh; lf->sp.fixh = 0.05; lf->mdl.procv = procvstd; nstartlf(des,lf); ressumm(lf,des,res); deg(&lf->sp) = dg; lf->sp.fixh = h0; sig2 = res[3]; */ for (i=0; i<nmeth; i++) { switch(meth[i]) { case 0: hhat[i] = cp(des,lf,1); break; case 1: hhat[i] = cp(des,lf,2); break; case 2: hhat[i] = gkk(des,lf); break; case 3: hhat[i] = rsw(des,lf); break; default: hhat[i] = 0; mut_printf("Unknown method %d\n",meth[i]); } if (lf_error) i = nmeth; } lf->dv.nd = nmeth; } void initrband(lf) lfit *lf; { initstd(lf); KEEPC(lf) = MAXMETH; PROCV(lf) = NULL; PPROC(lf) = rband; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" static double scb_crit, *x, c[10], kap[5], kaq[5], max_p2; static int side, type; design *scb_des; double covar_par(lf,des,x1,x2) lfit *lf; design *des; double x1, x2; { double *v1, *v2, *wk; paramcomp *pc; int i, j, p, ispar; v1 = des->f1; v2 = des->ss; wk = des->oc; ispar = (ker(&lf->sp)==WPARM) && (haspc(&lf->pc)); p = npar(&lf->sp); /* for parametric models, the covariance is * A(x1)^T (X^T W V X)^{-1} A(x2) * which we can find easily from the parametric component. */ if (ispar) { pc = &lf->pc; fitfun(&lf->lfd, &lf->sp, &x1,pc->xbar,v1,NULL); fitfun(&lf->lfd, &lf->sp, &x2,pc->xbar,v2,NULL); jacob_hsolve(&lf->pc.xtwx,v1); jacob_hsolve(&lf->pc.xtwx,v2); } /* for non-parametric models, we must use the cholseky decomposition * of M2 = X^T W^2 V X. Courtesy of lf_vcov caclulations, should have * des->P = M2^{1/2} M1^{-1}. */ if (!ispar) { fitfun(&lf->lfd, &lf->sp, &x1,des->xev,wk,NULL); for (i=0; i<p; i++) { v1[i] = 0; for (j=0; j<p; j++) v1[i] += des->P[i*p+j]*wk[j]; } fitfun(&lf->lfd, &lf->sp, &x2,des->xev,wk,NULL); for (i=0; i<p; i++) { v2[i] = 0; for (j=0; j<p; j++) v2[i] += des->P[i*p+j]*wk[j]; } } return(innerprod(v1,v2,p)); } void cumulant(lf,des,sd) lfit *lf; design *des; double sd; { double b2i, b3i, b3j, b4i; double ss, si, sj, uii, uij, ujj, k1; int ii, i, j, jj; for (i=1; i<10; i++) c[i] = 0.0; k1 = 0; /* ss = sd*sd; */ ss = covar_par(lf,des,des->xev[0],des->xev[0]); /* * this isn't valid for nonparametric models. At a minimum, * the sums would have to include weights. Still have to work * out the right way. */ for (i=0; i<lf->lfd.n; i++) { ii = des->ind[i]; b2i = b2(fitv(des,ii),fam(&lf->sp),prwt(&lf->lfd,ii)); b3i = b3(fitv(des,ii),fam(&lf->sp),prwt(&lf->lfd,ii)); b4i = b4(fitv(des,ii),fam(&lf->sp),prwt(&lf->lfd,ii)); si = covar_par(lf,des,des->xev[0],datum(&lf->lfd,0,ii)); uii= covar_par(lf,des,datum(&lf->lfd,0,ii),datum(&lf->lfd,0,ii)); if (lf_error) return; c[2] += b4i*si*si*uii; c[6] += b4i*si*si*si*si; c[7] += b3i*si*uii; c[8] += b3i*si*si*si; /* c[9] += b2i*si*si*si*si; c[9] += b2i*b2i*si*si*si*si; */ k1 += b3i*si*(si*si/ss-uii); /* i=j components */ c[1] += b3i*b3i*si*si*uii*uii; c[3] += b3i*b3i*si*si*si*si*uii; c[4] += b3i*b3i*si*si*uii*uii; for (j=i+1; j<lf->lfd.n; j++) { jj = des->ind[j]; b3j = b3(fitv(des,ii),fam(&lf->sp),prwt(&lf->lfd,jj)); sj = covar_par(lf,des,des->xev[0],datum(&lf->lfd,0,jj)); uij= covar_par(lf,des,datum(&lf->lfd,0,ii),datum(&lf->lfd,0,jj)); ujj= covar_par(lf,des,datum(&lf->lfd,0,jj),datum(&lf->lfd,0,jj)); c[1] += 2*b3i*b3j*si*sj*uij*uij; c[3] += 2*b3i*b3j*si*si*sj*sj*uij; c[4] += b3i*b3j*uij*(si*si*ujj+sj*sj*uii); if (lf_error) return; } } c[5] = c[1]; c[7] = c[7]*c[8]; c[8] = c[8]*c[8]; c[1] /= ss; c[2] /= ss; c[3] /= ss*ss; c[4] /= ss; c[5] /= ss; c[6] /= ss*ss; c[7] /= ss*ss; c[8] /= ss*ss*ss; c[9] /= ss*ss; /* constants used in p(x,z) computation */ kap[1] = k1/(2*sqrt(ss)); kap[2] = 1 + 0.5*(c[1]-c[2]+c[4]-c[7]) - 3*c[3] + c[6] + 1.75*c[8]; kap[4] = -9*c[3] + 3*c[6] + 6*c[8] + 3*c[9]; /* constants used in q(x,u) computation */ kaq[2] = c[3] - 1.5*c[8] - c[5] - c[4] + 0.5*c[7] + c[6] - c[2]; kaq[4] = -3*c[3] - 6*c[4] - 6*c[5] + 3*c[6] + 3*c[7] - 3*c[8] + 3*c[9]; } /* q2(u) := u+q2(x,u) in paper */ double q2(u) double u; { return(u-u*(36.0*kaq[2] + 3*kaq[4]*(u*u-3) + c[8]*((u*u-10)*u*u+15))/72.0); } /* p2(u) := p2(x,u) in paper */ double p2(u) double u; { return( -u*( 36*(kap[2]-1+kap[1]*kap[1]) + 3*(kap[4]+4*kap[1]*sqrt(kap[3]))*(u*u-3) + c[8]*((u*u-10)*u*u+15) ) / 72 ); } extern int likereg(); double gldn_like(a) double a; { int err; scb_des->fix[0] = 1; scb_des->cf[0] = a; max_nr(likereg, scb_des->cf, scb_des->oc, scb_des->res, scb_des->f1, &scb_des->xtwx, scb_des->p, lf_maxit, 1.0e-6, &err); scb_des->fix[0] = 0; return(scb_des->llk); } /* v1/v2 is correct for deg=0 only */ void get_gldn(fp,des,lo,hi,v) fitpt *fp; design *des; double *lo, *hi; int v; { double v1, v2, c, tlk; int err; v1 = fp->nlx[v]; v2 = fp->t0[v]; c = scb_crit * v1 / v2; tlk = des->llk - c*c/2; mut_printf("v %8.5f %8.5f c %8.5f tlk %8.5f llk %8.5f\n",v1,v2,c,tlk,des->llk); /* want: { a : l(a) >= l(a-hat) - c*c/2 } */ lo[v] = fp->coef[v] - scb_crit*v1; hi[v] = fp->coef[v] + scb_crit*v1; err = 0; mut_printf("lo %2d\n",v); lo[v] = solve_secant(gldn_like,tlk,lo[v],fp->coef[v],1e-8,BDF_EXPLEFT,&err); if (err>0) mut_printf("solve_secant error\n"); mut_printf("hi %2d\n",v); hi[v] = solve_secant(gldn_like,tlk,fp->coef[v],hi[v],1e-8,BDF_EXPRIGHT,&err); if (err>0) mut_printf("solve_secant error\n"); } int procvscb2(des,lf,v) design *des; lfit *lf; int v; { double thhat, sd, *lo, *hi, u; int err, st, tmp; x = des->xev = evpt(&lf->fp,v); tmp = haspc(&lf->pc); /* if ((ker(&lf->sp)==WPARM) && (haspc(&lf->pc))) { lf->coef[v] = thhat = addparcomp(lf,des->xev,PCOEF); lf->nlx[v] = lf->t0[v] = sd = addparcomp(lf,des->xev,PNLX); } else */ { haspc(&lf->pc) = 0; st = procvstd(des,lf,v); thhat = lf->fp.coef[v]; sd = lf->fp.nlx[v]; } if ((type==GLM2) | (type==GLM3) | (type==GLM4)) { if (ker(&lf->sp) != WPARM) WARN(("nonparametric fit; correction is invalid")); cumulant(lf,des,sd); } haspc(&lf->pc) = tmp; lo = lf->fp.t0; hi = &lo[lf->fp.nvm]; switch(type) { case GLM1: return(st); case GLM2: /* centered scr */ lo[v] = kap[1]; hi[v] = sqrt(kap[2]); return(st); case GLM3: /* corrected 2 */ lo[v] = solve_secant(q2,scb_crit,0.0,2*scb_crit,0.000001,BDF_NONE,&err); return(st); case GLM4: /* corrected 2' */ u = fabs(p2(scb_crit)); max_p2 = MAX(max_p2,u); return(st); case GLDN: get_gldn(&lf->fp,des,lo,hi,v); return(st); } LERR(("procvscb2: invalid type")); return(st); } void scb(lf,des,res) lfit *lf; design *des; double *res; { double k1, k2, *lo, *hi, sig, thhat, nlx, rss[10]; int i, nterms; scb_des= des; npar(&lf->sp) = calcp(&lf->sp,lf->lfd.d); des_init(des,lf->lfd.n,npar(&lf->sp)); type = geth(&lf->fp); if (type >= 80) /* simultaneous */ { nterms = constants(lf,des,res); scb_crit = critval(0.05,res,nterms,lf->lfd.d,TWO_SIDED,0.0,GAUSS); type -= 10; } else /* pointwise */ { res[0] = 1; scb_crit = critval(0.05,res,1,lf->lfd.d,TWO_SIDED,0.0,GAUSS); } max_p2 = 0.0; lf->mdl.procv = procvscb2; nstartlf(des,lf); if ((fam(&lf->sp)&64)==64) { i = haspc(&lf->pc); haspc(&lf->pc) = 0; ressumm(lf,des,rss); haspc(&lf->pc) = i; sig = sqrt(rss[3]); } else sig = 1.0; lo = lf->fp.t0; hi = &lo[lf->fp.nvm]; for (i=0; i<lf->fp.nv; i++) { thhat = lf->fp.coef[i]; nlx = lf->fp.nlx[i]; switch(type) { case GLM1: /* basic scb */ lo[i] = thhat - scb_crit * sig * nlx; hi[i] = thhat + scb_crit * sig * nlx; break; case GLM2: k1 = lo[i]; k2 = hi[i]; lo[i] = thhat - k1*nlx - scb_crit*nlx*k2; hi[i] = thhat - k1*nlx + scb_crit*nlx*k2; break; case GLM3: k1 = lo[i]; lo[i] = thhat - k1*nlx; hi[i] = thhat + k1*nlx; case GLM4: /* corrected 2' */ lo[i] = thhat - (scb_crit-max_p2)*lf->fp.nlx[i]; hi[i] = thhat + (scb_crit-max_p2)*lf->fp.nlx[i]; break; case GLDN: break; } } } void initscb(lf) lfit *lf; { initstd(lf); PROCV(lf) = NULL; KEEPC(lf) = NVAR(lf)+1+k0_reqd(NVAR(lf),NOBS(lf),0); PPROC(lf) = scb; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" int procvsimple(des,lf,v) design *des; lfit *lf; int v; { int lf_status; lf_status = procv_nov(des,lf,v); VVAL(lf,v,0) = des->cf[cfn(des,0)]; return(lf_status); } void allocsimple(lf) lfit *lf; { lf->fp.coef = VVEC(lf,0); lf->fp.h = NULL; } void initsimple(lf) lfit *lf; { PROCV(lf) = procvsimple; ALLOC(lf) = allocsimple; PPROC(lf) = NULL; KEEPV(lf) = 1; KEEPC(lf) = 1; NOPC(lf) = 1; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" /* 3d+8 variables to keep: * d+1 coef+derivs. * d+1 sd's + derivs. * d+1 infl + derivs. * 3 likelihood and d.f's. * 1 bandwidth h * 1 degree. */ void allocstd(lf) lfit *lf; { int d; d = NVAR(lf); lf->fp.coef = VVEC(lf,0); lf->fp.nlx = VVEC(lf,d+1); lf->fp.t0 = VVEC(lf,2*d+2); lf->fp.lik = VVEC(lf,3*d+3); lf->fp.h = VVEC(lf,3*d+6); lf->fp.deg = VVEC(lf,3*d+7); } int procvstd(des,lf,v) design *des; lfit *lf; int v; { int d, p, nvm, i, k; double t0[1+MXDIM], vari[1+MXDIM]; k = procv_var(des,lf,v); if (lf_error) return(k); d = lf->lfd.d; p = npar(&lf->sp); nvm = lf->fp.nvm; if (k != LF_OK) lf_status_msg(k); lf->fp.lik[v] = des->llk; lf->fp.lik[nvm+v] = des->tr2; lf->fp.lik[2*nvm+v] = des->tr0 - des->tr2; for (i=0; i<des->ncoef; i++) vari[i] = des->V[p*cfn(des,0) + cfn(des,i)]; vari[0] = sqrt(vari[0]); if (vari[0]>0) for (i=1; i<des->ncoef; i++) vari[i] /= vari[0]; t0[0] = sqrt(des->f1[0]); if (t0[0]>0) for (i=1; i<des->ncoef; i++) t0[i] = des->f1[i]/t0[0]; if (dc(&lf->fp)) dercor(&lf->lfd,&lf->sp,des,des->cf); subparcomp(des,lf,des->cf); for (i=0; i<des->ncoef; i++) lf->fp.coef[i*lf->fp.nvm+v] = des->cf[cfn(des,i)]; subparcomp2(des,lf,vari,t0); for (i=0; i<des->ncoef; i++) { lf->fp.nlx[i*nvm+v] = vari[i]; lf->fp.t0[i*nvm+v] = t0[i]; } lf->fp.deg[v] = deg(&lf->sp); return(k); } void pprocstd(lf,des,res) lfit *lf; design *des; double *res; { ressumm(lf,des,res); } void initstd(lf) lfit *lf; { PROCV(lf) = procvstd; ALLOC(lf) = allocstd; PPROC(lf) = pprocstd; KEEPV(lf) = 3*NVAR(lf) + 8; KEEPC(lf) = 6; NOPC(lf) = 0; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" extern void procstd(), allocstd(); extern double robscale; double vocri(lk,t0,t2,pen) double lk, t0, t2, pen; { if (pen==0) return(-2*t0*lk/((t0-t2)*(t0-t2))); return((-2*lk+pen*t2)/t0); } double intvo(des,lf,c0,c1,a,p,t0,t20,t21) design *des; lfit *lf; double *c0, *c1, a, t0, t20, t21; int p; { double th, lk, link[LLEN]; int i, ii; lk = 0; for (i=0; i<des->n; i++) { ii = des->ind[i]; th = (1-a)*innerprod(c0,d_xi(des,i),p) + a*innerprod(c1,d_xi(des,i),p); stdlinks(link,&lf->lfd,&lf->sp,ii,th,robscale); lk += wght(des,ii)*link[ZLIK]; } des->llk = lk; return(vocri(des->llk,t0,(1-a)*t20+a*t21,pen(&lf->sp))); } int procvvord(des,lf,v) design *des; lfit *lf; int v; { double tr[6], gcv, g0, ap, coef[4][10], t2[4], th, md; int i, j, k, d1, i0, p1, ip; des->xev = evpt(&lf->fp,v); ap = pen(&lf->sp); if ((ap==0) & ((fam(&lf->sp)&63)!=TGAUS)) ap = 2.0; d1 = deg(&lf->sp); p1 = npar(&lf->sp); for (i=0; i<p1; i++) coef[0][i] = coef[1][i] = coef[2][i] = coef[3][i] = 0.0; i0 = 0; g0 = 0; ip = 1; for (i=deg0(&lf->sp); i<=d1; i++) { deg(&lf->sp) = i; des->p = npar(&lf->sp) = calcp(&lf->sp,lf->lfd.d); k = locfit(&lf->lfd,des,&lf->sp,0, i==deg0(&lf->sp),0); local_df(&lf->lfd,&lf->sp,des,tr); gcv = vocri(des->llk,tr[0],tr[2],ap); if ((i==deg0(&lf->sp)) || (gcv<g0)) { i0 = i; g0 = gcv; md = i; } for (j=0; j<des->p; j++) coef[i][j] = des->cf[j]; t2[i] = tr[2]; #ifdef RESEARCH if ((ip) && (i>deg0(&lf->sp))) { for (j=1; j<10; j++) { gcv = intvo(des,lf,coef[i-1],coef[i],j/10.0,des->p,tr[0],t2[i-1],t2[i]); if (gcv<g0) { g0 = gcv; md = i-1+j/10.0; } } } #endif } lf->fp.h[v] = des->h; if (lf->fp.h[v]<=0) WARN(("zero bandwidth in procvvord")); if (i0<d1) /* recompute the best fit */ { deg(&lf->sp) = i0; des->p = npar(&lf->sp) = calcp(&lf->sp,lf->lfd.d); k = locfit(&lf->lfd,des,&lf->sp,0,0,0); for (i=npar(&lf->sp); i<p1; i++) des->cf[i] = 0.0; i0 = md; if (i0==d1) i0--; th = md-i0; for (i=0; i<p1; i++) des->cf[i] = (1-th)*coef[i0][i]+th*coef[i0+1][i]; deg(&lf->sp) = d1; npar(&lf->sp) = p1; } for (i=0; i<p1; i++) lf->fp.coef[i*lf->fp.nvm+v] = des->cf[i]; lf->fp.deg[v] = md; return(k); } void initvord(lf) lfit *lf; { initstd(lf); PROCV(lf) = procvvord; ALLOC(lf) = allocstd; PPROC(lf) = NULL; KEEPC(lf) = 0; NOPC(lf) = 1; } /* * Copyright 1996-2006 Catherine Loader. */ /* * functions for computing and subtracting, adding the * parametric component */ #include "lfev.h" int noparcomp(sp) smpar *sp; { int tg; if (ubas(sp)) return(1); tg = fam(sp) & 63; if (tg<=THAZ) return(1); if (tg==TROBT) return(1); if (tg==TCAUC) return(1); if (tg==TQUANT) return(1); return(0); } int pc_reqd(d,p) int d, p; { return(d + 2*p + jac_reqd(p)); } void pcchk(pc,d,p,lc) paramcomp *pc; int d, p, lc; { int rw; double *z; rw = pc_reqd(d,p); if (pc->lwk < rw) { pc->wk = (double *)calloc(rw,sizeof(double)); if ( pc->wk == NULL ) { printf("Problem allocating memory for pc->wk\n");fflush(stdout); } pc->lwk= rw; } z = pc->wk; pc->xbar = z; z += d; pc->coef = z; z += p; pc->f = z; z += p; z = jac_alloc(&pc->xtwx,p,z); pc->xtwx.p = p; } void compparcomp(des,lfd,sp,pc,nopc) design *des; lfdata *lfd; smpar *sp; paramcomp *pc; int nopc; { int i, j, k, p; double wt, sw; if (lf_debug>1) mut_printf(" compparcomp:\n"); p = des->p; pcchk(pc,lfd->d,p,1); for (i=0; i<lfd->d; i++) pc->xbar[i] = 0.0; sw = 0.0; for (i=0; i<lfd->n; i++) { wt = prwt(lfd,i); sw += wt; for (j=0; j<lfd->d; j++) pc->xbar[j] += datum(lfd,j,i)*wt; des->ind[i] = i; wght(des,i) = 1.0; } for (i=0; i<lfd->d; i++) pc->xbar[i] /= sw; if ((nopc) || noparcomp(sp)) { haspc(pc) = 0; return; } haspc(pc) = 1; des->xev = pc->xbar; k = locfit(lfd,des,sp,0,0,0); if (k != LF_OK) lf_status_msg(k); if (lf_error) return; switch(k) { case LF_NOPT: return; case LF_INFA: return; case LF_NCON: return; case LF_OOB: return; case LF_NSLN: return; case LF_PF: WARN(("compparcomp: perfect fit")); case LF_OK: case LF_DONE: for (i=0; i<p; i++) { pc->coef[i] = des->cf[i]; pc->xtwx.dg[i] = des->xtwx.dg[i]; pc->xtwx.wk[i] = des->xtwx.wk[i]; } for (i=0; i<p*p; i++) { pc->xtwx.Z[i] = des->xtwx.Z[i]; pc->xtwx.Q[i] = des->xtwx.Q[i]; } pc->xtwx.sm = des->xtwx.sm; pc->xtwx.st = des->xtwx.st; return; default: LERR(("compparcomp: locfit unknown return status %d",k)); return; } } void subparcomp(des,lf,coef) design *des; lfit *lf; double *coef; { int i, nd; deriv *dv; paramcomp *pc; pc = &lf->pc; if (!haspc(pc)) return; dv = &lf->dv; nd = dv->nd; fitfun(&lf->lfd, &lf->sp, des->xev,pc->xbar,des->f1,dv); coef[0] -= innerprod(pc->coef,des->f1,pc->xtwx.p); if (des->ncoef == 1) return; dv->nd = nd+1; for (i=0; i<lf->lfd.d; i++) { dv->deriv[nd] = i; fitfun(&lf->lfd, &lf->sp, des->xev,pc->xbar,des->f1,dv); coef[i+1] -= innerprod(pc->coef,des->f1,pc->xtwx.p); } dv->nd = nd; } void subparcomp2(des,lf,vr,il) design *des; lfit *lf; double *vr, *il; { double t0, t1; int i, nd; deriv *dv; paramcomp *pc; pc = &lf->pc; if (!haspc(pc)) return; dv = &lf->dv; nd = dv->nd; fitfun(&lf->lfd, &lf->sp, des->xev,pc->xbar,des->f1,dv); for (i=0; i<npar(&lf->sp); i++) pc->f[i] = des->f1[i]; jacob_solve(&pc->xtwx,des->f1); t0 = sqrt(innerprod(pc->f,des->f1,pc->xtwx.p)); vr[0] -= t0; il[0] -= t0; if ((t0==0) | (des->ncoef==1)) return; dv->nd = nd+1; for (i=0; i<lf->lfd.d; i++) { dv->deriv[nd] = i; fitfun(&lf->lfd, &lf->sp, des->xev,pc->xbar,pc->f,dv); t1 = innerprod(pc->f,des->f1,pc->xtwx.p)/t0; vr[i+1] -= t1; il[i+1] -= t1; } dv->nd = nd; } double addparcomp(lf,x,c) lfit *lf; double *x; int c; { double y; paramcomp *pc; pc = &lf->pc; if (!haspc(pc)) return(0.0); fitfun(&lf->lfd, &lf->sp, x,pc->xbar,pc->f,&lf->dv); if (c==PCOEF) return(innerprod(pc->coef,pc->f,pc->xtwx.p)); if ((c==PNLX)|(c==PT0)|(c==PVARI)) { y = sqrt(jacob_qf(&pc->xtwx,pc->f)); return(y); } return(0.0); } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" /* preplot(): interpolates the fit to a new set of points. lf -- the fit structure. x -- the points to predict at. f -- vector to return the predictions. se -- vector to return std errors (NULL if not req'd) band-- char for conf band type. ('n'=none, 'g'=global etc.) n -- no of predictions (or vector of margin lengths for grid) where -- where to predict: 1 = points in the array x. 2 = grid defined by margins in x. 3 = data points from lf (ignore x). 4 = fit points from lf (ignore x). what -- what to predict. (PCOEF etc; see lfcons.h file) */ #define NWH 8 static char *whtyp[NWH] = { "coef", "nlx", "infl", "band", "degr", "like", "rdf", "vari" }; static int whval[NWH] = { PCOEF, PNLX, PT0, PBAND, PDEGR, PLIK, PRDF, PVARI }; int ppwhat(z) char *z; { int val; val = pmatch(z, whtyp, whval, NWH, -1); if (val==-1) LERR(("Unknown what = %s",z)); return(val); } static char cb; double *sef, *fit, sigmahat; void predptall(lf,x,what,ev,i) lfit *lf; double *x; int what, ev, i; { double lik, rdf; fit[i] = dointpoint(lf,x,what,ev,i); if (cb=='n') return; sef[i] = dointpoint(lf,x,PNLX,ev,i); if (cb=='g') { sef[i] *= sigmahat; return; } if (cb=='l') { lik = dointpoint(lf,x,PLIK,ev,i); rdf = dointpoint(lf,x,PRDF,ev,i); sef[i] *= sqrt(-2*lik/rdf); return; } if (cb=='p') { sef[i] = sigmahat*sqrt(1+sef[i]*sef[i]); return; } } void predptdir(lf,des,x,what,i) lfit *lf; design *des; double *x; int what, i; { int needcv; des->xev = x; needcv = (what==PVARI) | (what==PNLX) | (what==PT0) | (what==PRDF); locfit(&lf->lfd,des,&lf->sp,0,1,needcv); switch(what) { case PCOEF: fit[i] = des->cf[0]; break; case PVARI: fit[i] = des->V[0]; break; case PNLX: fit[i] = sqrt(des->V[0]); break; case PT0: fit[i] = des->f1[0]; break; case PBAND: fit[i] = des->h; break; case PDEGR: fit[i] = deg(&lf->sp); break; case PLIK: fit[i] = des->llk; break; case PRDF: fit[i] = des->tr0 - des->tr2; break; default: LERR(("unknown what in predptdir")); } } void prepvector(lf,des,x,n,what,dir) /* interpolate a vector */ lfit *lf; design *des; double **x; int n, what, dir; { int i, j; double xx[MXDIM]; for (i=0; i<n; i++) { for (j=0; j<lf->fp.d; j++) xx[j] = x[j][i]; if (dir) predptdir(lf,des,xx,what,i); else predptall(lf,xx,what,ev(&lf->evs),i); if (lf_error) return; } } void prepfitp(lf,what) lfit *lf; int what; { int i; for (i=0; i<lf->fp.nv; i++) { predptall(lf,evpt(&lf->fp,i),what,EFITP,i); if (lf_error) return; } } void prepgrid(lf,des,x,mg,n,what,dir) /* interpolate a grid given margins */ lfit *lf; design *des; double **x; int *mg, dir, n, what; { int i, ii, j, d; double xv[MXDIM]; d = lf->fp.d; for (i=0; i<n; i++) { ii = i; for (j=0; j<d; j++) { xv[j] = x[j][ii%mg[j]]; ii /= mg[j]; } if (dir) predptdir(lf,des,xv,what,i); else predptall(lf,xv,what,ev(&lf->evs),i); if (lf_error) return; } } void preplot(lf,x,f,se,band,mg,where,what,dir) lfit *lf; double **x, *f, *se; int *mg, where, what, dir; char band; { int d, i, n; double *xx[MXDIM]; design ppdes; d = lf->fp.d; fit = f; sef = se; cb = band; if (cb!='n') sigmahat = sqrt(rv(&lf->fp)); if (dir) des_init(&ppdes,lf->lfd.n,npar(&lf->sp)); switch(where) { case 1: /* vector */ n = mg[0]; prepvector(lf,&ppdes,x,n,what,dir); break; case 2: /* grid */ n = 1; for (i=0; i<d; i++) n *= mg[i]; prepgrid(lf,&ppdes,x,mg,n,what,dir); break; case 3: /* data */ n = lf->lfd.n; if ((ev(&lf->evs)==EDATA) | (ev(&lf->evs)==ECROS)) { prepfitp(lf,what); dir = 0; } else { for (i=0; i<d; i++) xx[i] = dvari(&lf->lfd,i); prepvector(lf,&ppdes,xx,n,what,dir); } break; case 4: /* fit points */ n = lf->fp.nv; dir = 0; prepfitp(lf,what); break; default: LERR(("unknown where in preplot")); } if ((!dir) && ((what==PT0)|(what==PVARI))) for (i=0; i<n; i++) f[i] = f[i]*f[i]; } /* * Copyright 1996-2006 Catherine Loader. */ #include "lfev.h" int procv_nov(des,lf,v) design *des; lfit *lf; int v; { int lf_status; if (lf_debug>1) mut_printf(" procveraw: %d\n",v); des->xev = evpt(&lf->fp,v); if (acri(&lf->sp)==ANONE) lf_status = locfit(&lf->lfd,des,&lf->sp,0,1,0); else lf_status = alocfit(&lf->lfd,&lf->sp,&lf->dv,des,0); if (lf->fp.h != NULL) lf->fp.h[v] = des->h; return(lf_status); } int procv_var(des,lf,v) design *des; lfit *lf; int v; { int i, lf_status; if (lf_debug>1) mut_printf(" procvraw: %d\n",v); des->xev = evpt(&lf->fp,v); if (acri(&lf->sp)==ANONE) lf_status = locfit(&lf->lfd,des,&lf->sp,0,1,1); else lf_status = alocfit(&lf->lfd,&lf->sp,&lf->dv,des,1); if (lf->fp.h != NULL) lf->fp.h[v] = des->h; return(lf_status); } /* * Copyright 1996-2006 Catherine Loader. */ /* * startmodule(lf,des,mod,dir) -- the standard entry point. * des and lf are pointers to the design and fit structures. * mod - module name. Set to NULL if the module is already * initialized. * dir - for dynamic modules, the directory. * * initmodule(mdl,mod,dir,lf) * direct call for module initialization. * */ #include "lfev.h" #ifdef WINDOWS #define DIRSEP '\\' #define PATHSEP ';' #else #define DIRSEP '/' #define PATHSEP ':' #endif #ifdef ALLOW_MODULES #ifdef WINDOWS #include <windows.h> #define DLEXT "dll" #define DLOPEN(x) LoadLibrary(x) #define DLSYM GetProcAddress #else #include <dlfcn.h> #define DLEXT "so" #define DLOPEN(x) dlopen(x,RTLD_LAZY) #define DLSYM dlsym #endif #endif static double fpkap[6]; void fitpt_init(fp) fitpt *fp; { dc(fp) = 0; geth(fp) = GSTD; fp->nv = fp->nvm = 0; if (fp->kap==NULL) fp->kap = fpkap; } void lfit_init(lf) lfit *lf; { lfdata_init(&lf->lfd); evstruc_init(&lf->evs); smpar_init(&lf->sp,&lf->lfd); deriv_init(&lf->dv); fitpt_init(&lf->fp); lf->mdl.np = 0; } void fitdefault(lf) lfit *lf; { WARN(("fitdefault deprecated -- use lfit_init()")); lfit_init(lf); } void set_flim(lfd,evs) lfdata *lfd; evstruc *evs; { int i, j, d, n; double z, mx, mn, *bx; if (ev(evs)==ESPHR) return; d = lfd->d; n = lfd->n; bx = evs->fl; for (i=0; i<d; i++) if (bx[i]==bx[i+d]) { if (lfd->sty[i]==STANGL) { bx[i] = 0.0; bx[i+d] = 2*PI*lfd->sca[i]; } else { mx = mn = datum(lfd,i,0); for (j=1; j<n; j++) { mx = MAX(mx,datum(lfd,i,j)); mn = MIN(mn,datum(lfd,i,j)); } if (lfd->xl[i]<lfd->xl[i+d]) /* user set xlim; maybe use them. */ { z = mx-mn; if (mn-0.2*z < lfd->xl[i]) mn = lfd->xl[i]; if (mx+0.2*z > lfd->xl[i+d]) mx = lfd->xl[i+d]; } bx[i] = mn; bx[i+d] = mx; } } } double vvari(v,n) double *v; int n; { int i; double xb, s2; xb = s2 = 0.0; for (i=0; i<n; i++) xb += v[i]; xb /= n; for (i=0; i<n; i++) s2 += SQR(v[i]-xb); return(s2/(n-1)); } void set_scales(lfd) lfdata *lfd; { int i; for (i=0; i<lfd->d; i++) if (lfd->sca[i]<=0) /* set automatic scales */ { if (lfd->sty[i]==STANGL) lfd->sca[i] = 1.0; else lfd->sca[i] = sqrt(vvari(lfd->x[i],lfd->n)); } } void nstartlf(des,lf) design *des; lfit *lf; { int i, d, n; if (lf_debug>0) mut_printf("nstartlf\n"); n = lf->lfd.n; d = lf->lfd.d; npar(&lf->sp) = calcp(&lf->sp,d); des_init(des,n,npar(&lf->sp)); set_scales(&lf->lfd); set_flim(&lf->lfd,&lf->evs); compparcomp(des,&lf->lfd,&lf->sp,&lf->pc,lf->mdl.nopc); if (lf_error) return; makecfn(&lf->sp,des,&lf->dv,lf->lfd.d); lf->lfd.ord = 0; if ((d==1) && (lf->lfd.sty[0]!=STANGL)) { i = 1; while ((i<n) && (datum(&lf->lfd,0,i)>=datum(&lf->lfd,0,i-1))) i++; lf->lfd.ord = (i==n); } for (i=0; i<npar(&lf->sp); i++) des->fix[i] = 0; lf->fp.d = lf->lfd.d; lf->fp.hasd = (des->ncoef==(1+lf->fp.d)); lf->fp.nv = lf->evs.nce = 0; if (lf_debug>1) mut_printf("call eval structure %d\n",ev(&lf->evs)); switch(ev(&lf->evs)) { case EPHULL: triang_start(des,lf); break; case EDATA: dataf(des,lf); break; case ECROS: crossf(des,lf); break; case EGRID: gridf(des,lf); break; case ETREE: atree_start(des,lf); break; case EKDCE: kt(&lf->sp) = KCE; case EKDTR: kdtre_start(des,lf); break; case EPRES: preset(des,lf); break; case EXBAR: xbarf(des,lf); break; case ENONE: return; case ESPHR: sphere_start(des,lf); break; case ESPEC: lf->evs.espec(des,lf); break; default: LERR(("startlf: Invalid evaluation structure %d",ev(&lf->evs))); } /* renormalize for family=density */ if ((de_renorm) && (fam(&lf->sp)==TDEN)) dens_renorm(lf,des); } /* * getnextdir() gets the next dir from a string dirpath="dir1:dir2:dir3:..." * (;-separated on windows). * The directory is returned through dirnext, and the function returns * a pointer to the next string. * typical usage is recursive, dirpath = getnextdir(dirpath,dirnext). * with the above example, this sets dirnext="dir1" and dirpath="dir2:dir3:...". * if the input dirpath has no :, then it is copied to dirnext, and return is "". * if input dirpath is "", dirnext is set to "", and null pointer returned. */ char *getnextdir(dirpath,dirnext) char *dirpath, *dirnext; { char *z; if (strlen(dirpath)==0) { sprintf(dirnext,""); return(NULL); } z = strchr(dirpath,PATHSEP); if (z==NULL) { sprintf(dirnext,"%s%c",dirpath,DIRSEP); return(&dirpath[strlen(dirnext)]); } *z = '\0'; sprintf(dirnext,"%s%c",dirpath,DIRSEP); return(++z); } int initmodule(mdl, mod, dir, lf) module *mdl; lfit *lf; char *mod, *dir; { int n, d, p; #ifdef ALLOW_MODULES #ifdef WINDOWS HINSTANCE res; typedef void (CALLBACK* DLLFN)(); DLLFN init; #else void *res; void (*init)(); #endif char distname[500]; #endif n = lf->lfd.n; d = lf->lfd.d; p = npar(&lf->sp) = calcp(&lf->sp,d); mdl->isset = 1; PPROC(lf) = NULL; if (strcmp(mod,"std")==0) { initstd(lf); return(1); } if (strcmp(mod,"simple")==0) { initsimple(lf); return(1); } if (strcmp(mod,"allcf")==0) { initallcf(lf); return(1); } if (strcmp(mod,"hatm")==0) { inithatm(lf); return(1); } if (strcmp(mod,"kappa")==0) { initkappa(lf); return(1); } if (strcmp(mod,"lscv")==0) { initlscv(lf); return(1); } if (strcmp(mod,"gamf")==0) { initgam(lf); return(1); } if (strcmp(mod,"gamp")==0) { initgam(lf); return(1); } if (strcmp(mod,"rband")==0) { initrband(lf); return(1); } if (strcmp(mod,"scb")==0) { initscb(lf); return(1); } if (strcmp(mod,"vord")==0) { initvord(lf); return(1); } #ifdef ALLOW_MODULES while (dir != NULL) { dir = getnextdir(dir,distname); sprintf(&distname[strlen(distname)],"mod%s.%s",mod,DLEXT); res = DLOPEN(distname); if (res==NULL) { #ifdef WINDOWS mut_printf("LoadLibrary failed: %s, %d\n",distname,GetLastError()); #else mut_printf("dlopen failed: %s\n",dlerror()); #endif } else { #ifdef WINDOWS mut_printf("LoadLibrary success: %s\n",distname); #else mut_printf("dlopen success: %s\n",distname); #endif sprintf(distname,"init%s",mod); init = (void *)DLSYM(res,distname); if (init==NULL) { mut_printf("I can't find %s() function.\n",distname); mdl->isset = 0; return(0); } init(lf); return(1); } } #endif mdl->isset = 0; return(0); } /* * startmodule is the entry point to launch the fit. * if mod is provided, will first initialize the module. * if mod==NULL, assumes the module has been initialized separately. */ void startmodule(lf,des,mod,dir) lfit *lf; design *des; char *mod, *dir; { int z; if (mod != NULL) { z = initmodule(&lf->mdl,mod,dir,lf); if (!z) return; } lf->fp.nv = lf->evs.nce = 0; if (lf_error) return; if (PROCV(lf) != NULL) nstartlf(des,lf); if (lf_error) return; if (PPROC(lf) != NULL) PPROC(lf)(lf,des,lf->fp.kap); } /* for compatability, more or less. */ void startlf(des,lf,vfun,nopc) design *des; lfit *lf; int (*vfun)(), nopc; { int z; z = initmodule(&lf->mdl,"std",NULL,lf); if (!z) return; lf->mdl.procv = vfun; lf->mdl.nopc = nopc; nstartlf(des,lf); }