/* INTERP_EXTRAP_WTS.C interpolates/extrapolates a function whose values are known on a hypergrid. Interpolation is either multidimensional linear interpolation or the the simplicial interpolation algorithm given in Algorithm 6.5 (p. 243) of Judd, 1998, Numerical methods in Economics (MIT Press). Procedure also computes the gradient vector and extrapolates extrapolates when the point is outside of the hypergrid in one or more dimensions. Extrapolation is a fraction of a linear extrapolation based on the gradient of the function near the boundary of the hypergrid hypercube. This function differs from interp_extrap.c by returning a vector p that represents the interpolation/extrapolation, see below John Rust, University of Maryland, June 2005 Inputs: s: point (dx1 vector) the function is to be interpolated or extrapolated at vf: function to be interpolated, an (nx1) vector storing the function at n grid points on a rectangular hyergrid, where n=n1*n2*...*nd, where nj is the number of grids in dimension j, j=1,...,d grid: gridpoints at which vf is given grid=(x(1,1),...,x(1,n1),....,x(d,1),....,x(d,nd)) gridnum: dx1 vector with number of grid points used in each dimension gridnum=(n1,n2,...,nd) intmeth: interpolation method, 1 for simplicial interpolation 0 for multilinear interpolation Output: V(s): interpolated/extrapolated value of function at point s grad: gradient of the interpolated function at point s. p: a vector of dimension n x 1, same size as vf, that "represents" the interpolation operation, i.e. v(s)=p'vf. Note that when extrapolation occurs (i.e. one or more components of s are outside the min or max grid values), then v( s) is not necessarily equal to p'vf. We assume the elements of grid and vf are stored in column order, i.e. k=1; do i1=1,...,n1 do i2=1,...,n2 ... do id=1,...,nd k=k+1; vf[k]=v(x(i1,1),x(i2,2),...,x(id,d)), where the grid points in each dimension satisfy: x(j,1) < x(j,2) < .... < x(j,nj) Parameter: extfrac (extfrac is a parameter that controls the extrapolation of the function when the point s is outside the grid. If extfrac=0 we are using a flat extrapolation, i.e. assuming the function value equals the interpolated i value of the function on the nearest boundary face of the grid hypercube that is closest to s. If extrac=1, then a linear extrapolation is used, i.e. starting at the interpolated value of the function at the nearest grid hypercube cast to s, we project linearly using the gradient of the interpolated function at the nearest point to s in the hypercube. If extfrac is between 0 and 1 then a convex combination of the above two extrapolation strategies is used. Required procedures: binsucc.c computes binary successor operation power.c computes binary exponential function, 2^d vertwt.c computes the probability weights (convex combination) for the vertices of the grid hypercube so that the weighted average of the vertices equals the point s to be interpolated kseq.c locates the sequence number in a multidimensional index Note: this routine is for 2 and higher dimensional problems only. Use vint1d.c for 1-dimensional problems. In 1-dimensional problems there is no difference between linear and simplicial interpolation. */ double interp_extrap_wts(double *s,double *grad,double *p,double *vf,double *grid, int *gridnum,int d,int intmeth) { int i,j,ci,li,dd,n,k,lb,ub,lbs,twod,*indx,*gindx,*arg,*argl,*lbound,*ubound,*extrap; double adj,ivf,cvf,lvf,extfrac,*vsav,*wts,*swts,*ts,*runv,*grsav; extfrac=1.0; adj=0.0; ts=(double *) malloc(d*sizeof(double)); runv=(double *) malloc(d*sizeof(double)); wts=(double *) malloc(d*sizeof(double)); lbound=(int *) malloc(d*sizeof(int)); ubound=(int *) malloc(d*sizeof(int)); arg=(int *) malloc(d*sizeof(int)); extrap=(int *) malloc(d*sizeof(int)); n=1; for (i=0; i 0) of the maximum grid point for the coordinate in question. */ for (i=0; i 0) { lb=1; for (j=0; j<=i-1; j++) { lb=lb+gridnum[j]; } } else { lb=1; } lb--; ub--; lbs=lb; if (s[i] > grid[ub]) { extrap[i]=i+1; ts[i]=grid[ub]; } else if (s[i] < grid[lb]) { extrap[i]=-i-1; ts[i]=grid[lb]; } else { ts[i]=s[i]; } for (j=lb; j<=ub; j++) { if (grid[j] >= s[i]) { ub=j; } } if (ub == lb) { ub=lb+1; } else { lb=ub-1; } lbound[i]=lb-lbs; ubound[i]=ub-lbs; wts[i]=(ts[i]-grid[lb])/(grid[ub]-grid[lb]); runv[i]=grid[ub]-grid[lb]; } /* The following branch uses either simplicial interpolation or multidimensional linear interpolation depending on the value of the intmeth argument */ if (intmeth == 1) { /* Under simplicial interpolation, we start at the "top" of the hypercube (i.e. the largest gridpoint in the vector sense) and then move down the vertices of the hypercube for d more times according to the sorted weight vector, wts, above, and recursively taking convex combinations so that the final interpolated value is a convex combination of d+1 of the hypercube vectices. The gradient, however, will be discontinuous and constant within sub-simplices of the grid hypercube. */ swts=(double *) malloc(d*sizeof(double)); indx=(int *) malloc(d*sizeof(int)); argl=(int *) malloc(d*sizeof(int)); for (k=0; k0; dd--) { if (dd == d) { for(i=0; i=0; j--) { grad[j]=grsav[gindx[d-1-j]]; } ivf=vsav[0]; free(vsav); free(grsav); free(indx); free(gindx); } /* The final step is to determine if any extrapolation is necessary, and if so, extrapolate and then return the interpolated/extrapolated function value and the gradient vector */ k=0; for (j=0; j 0) { adj=0; for (i=0; i 0) { adj=adj+grad[extrap[i]-1]*(s[extrap[i]-1]-ts[extrap[i]-1]); } } ivf=ivf+extfrac*adj; } free(ts); free(runv); free(wts); free(lbound); free(ubound); free(arg); free(extrap); return ivf; }