/************************************************************************* * Initialization of internal structures. * * It assumes correctness of all parameters. * * -- ALGLIB -- * Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ private static void idwinit1(int n, int nx, int d, int nq, int nw, ref idwinterpolant z) { z.debugsolverfailures = 0; z.debugworstrcond = 1.0; z.debugbestrcond = 0; z.n = n; z.nx = nx; z.d = 0; if (d == 1) { z.d = 1; } if (d == 2) { z.d = 2; } if (d == -1) { z.d = 1; } z.nw = nw; if (d == -1) { z.q = new double[n, nx + 1 + nx]; } if (d == 0) { z.q = new double[n, nx + 1]; } if (d == 1) { z.q = new double[n, nx + 1 + nx]; } if (d == 2) { z.q = new double[n, nx + 1 + nx + (int)Math.Round(nx * (nx + 1) * 0.5)]; } z.tbuf = new int[nw]; z.rbuf = new double[nw]; z.xybuf = new double[nw, nx + 1]; z.xbuf = new double[nx]; }
/************************************************************************* * IDW interpolant using modified Shepard method for non-uniform datasets. * * This type of model uses constant nodal functions and interpolates using * all nodes which are closer than user-specified radius R. It may be used * when points distribution is non-uniform at the small scale, but it is at * the distances as large as R. * * INPUT PARAMETERS: * XY - X and Y values, array[0..N-1,0..NX]. * First NX columns contain X-values, last column contain * Y-values. * N - number of nodes, N>0. * NX - space dimension, NX>=1. * R - radius, R>0 * * OUTPUT PARAMETERS: * Z - IDW interpolant. * * NOTES: * if there is less than IDWKMin points within R-ball, algorithm selects * IDWKMin closest ones, so that continuity properties of interpolant are * preserved even far from points. * * -- ALGLIB PROJECT -- * Copyright 11.04.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildmodifiedshepardr(ref double[,] xy, int n, int nx, double r, ref idwinterpolant z) { int i = 0; int[] tags = new int[0]; int i_ = 0; // // assertions // System.Diagnostics.Debug.Assert(n > 0, "IDWBuildModifiedShepardR: N<=0!"); System.Diagnostics.Debug.Assert(nx >= 1, "IDWBuildModifiedShepardR: NX<1!"); System.Diagnostics.Debug.Assert((double)(r) > (double)(0), "IDWBuildModifiedShepardR: R<=0!"); // // primary initialization of Z // idwinit1(n, nx, 0, 0, n, ref z); z.modeltype = 1; z.r = r; // // Create KD-tree // tags = new int[n]; for (i = 0; i <= n - 1; i++) { tags[i] = i; } nearestneighbor.kdtreebuildtagged(ref xy, ref tags, n, nx, 1, 2, ref z.tree); // // build nodal functions // for (i = 0; i <= n - 1; i++) { for (i_ = 0; i_ <= nx; i_++) { z.q[i, i_] = xy[i, i_]; } } }
/************************************************************************* * Internal subroutine: K-th nodal function calculation * * -- ALGLIB -- * Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ private static double idwcalcq(ref idwinterpolant z, ref double[] x, int k) { double result = 0; int nx = 0; int i = 0; int j = 0; int offs = 0; nx = z.nx; // // constant member // result = z.q[k, nx]; // // linear members // if (z.d >= 1) { for (i = 0; i <= nx - 1; i++) { result = result + z.q[k, nx + 1 + i] * (x[i] - z.q[k, i]); } } // // quadratic members // if (z.d >= 2) { offs = nx + 1 + nx; for (i = 0; i <= nx - 1; i++) { for (j = i; j <= nx - 1; j++) { result = result + z.q[k, offs] * (x[i] - z.q[k, i]) * (x[j] - z.q[k, j]); offs = offs + 1; } } } return(result); }
/************************************************************************* Initialization of internal structures. It assumes correctness of all parameters. -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ private static void idwinit1(int n, int nx, int d, int nq, int nw, idwinterpolant z) { z.debugsolverfailures = 0; z.debugworstrcond = 1.0; z.debugbestrcond = 0; z.n = n; z.nx = nx; z.d = 0; if( d==1 ) { z.d = 1; } if( d==2 ) { z.d = 2; } if( d==-1 ) { z.d = 1; } z.nw = nw; if( d==-1 ) { z.q = new double[n, nx+1+nx]; } if( d==0 ) { z.q = new double[n, nx+1]; } if( d==1 ) { z.q = new double[n, nx+1+nx]; } if( d==2 ) { z.q = new double[n, nx+1+nx+(int)Math.Round(nx*(nx+1)*0.5)]; } z.tbuf = new int[nw]; z.rbuf = new double[nw]; z.xybuf = new double[nw, nx+1]; z.xbuf = new double[nx]; }
/************************************************************************* Internal subroutine: K-th nodal function calculation -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ private static double idwcalcq(idwinterpolant z, double[] x, int k) { double result = 0; int nx = 0; int i = 0; int j = 0; int offs = 0; nx = z.nx; // // constant member // result = z.q[k,nx]; // // linear members // if( z.d>=1 ) { for(i=0; i<=nx-1; i++) { result = result+z.q[k,nx+1+i]*(x[i]-z.q[k,i]); } } // // quadratic members // if( z.d>=2 ) { offs = nx+1+nx; for(i=0; i<=nx-1; i++) { for(j=i; j<=nx-1; j++) { result = result+z.q[k,offs]*(x[i]-z.q[k,i])*(x[j]-z.q[k,j]); offs = offs+1; } } } return result; }
/************************************************************************* IDW model for noisy data. This subroutine may be used to handle noisy data, i.e. data with noise in OUTPUT values. It differs from IDWBuildModifiedShepard() in the following aspects: * nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, i.e. we have fitting instead of interpolation. * weights which are used during least squares fitting stage are all equal to 1.0 (independently of distance) * "fast"-linear or constant nodal functions are not supported (either not robust enough or too rigid) This problem require far more complex tuning than interpolation problems. Below you can find some recommendations regarding this problem: * focus on tuning NQ; it controls noise reduction. As for NW, you can just make it equal to 2*NQ. * you can use cross-validation to determine optimal NQ. * optimal NQ is a result of complex tradeoff between noise level (more noise = larger NQ required) and underlying function complexity (given fixed N, larger NQ means smoothing of compex features in the data). For example, NQ=N will reduce noise to the minimum level possible, but you will end up with just constant/linear/quadratic (depending on D) least squares model for the whole dataset. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function degree, either: * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models (or for very noisy problems). * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). NQ - number of points used to calculate nodal functions. NQ should be significantly larger than 1.5 times the number of coefficients in a nodal function to overcome effects of noise: * larger than 1.5*(1+NX) for linear model, * larger than 3/4*(NX+2)*(NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ or larger OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, linear models are not recommended to use unless you are pretty sure that it is what you want * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildnoisy(double[,] xy, int n, int nx, int d, int nq, int nw, idwinterpolant z) { int i = 0; int j = 0; int k = 0; int j2 = 0; int j3 = 0; double v = 0; int nc = 0; int offs = 0; double taskrcond = 0; double[] x = new double[0]; double[] qrbuf = new double[0]; double[,] qxybuf = new double[0,0]; double[] y = new double[0]; double[] w = new double[0]; double[,] fmatrix = new double[0,0]; double[] qsol = new double[0]; int[] tags = new int[0]; double[] temp = new double[0]; int info = 0; int i_ = 0; // // these initializers are not really necessary, // but without them compiler complains about uninitialized locals // nc = 0; // // assertions // alglib.ap.assert(n>0, "IDWBuildNoisy: N<=0!"); alglib.ap.assert(nx>=1, "IDWBuildNoisy: NX<1!"); alglib.ap.assert(d>=1 && d<=2, "IDWBuildNoisy: D<>1 and D<>2!"); // // Correct parameters if needed // if( d==1 ) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor*(1+nx))+1); } if( d==2 ) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor*(nx+2)*(nx+1)/2)+1); } nw = Math.Max(nw, (int)Math.Round(Math.Pow(2, nx))+1); nq = Math.Min(nq, n); nw = Math.Min(nw, n); // // primary initialization of Z // idwinit1(n, nx, d, nq, nw, z); z.modeltype = 0; // // Create KD-tree // tags = new int[n]; for(i=0; i<=n-1; i++) { tags[i] = i; } nearestneighbor.kdtreebuildtagged(xy, tags, n, nx, 1, 2, z.tree); // // build nodal functions // (special algorithm for noisy data is used) // temp = new double[nq+1]; x = new double[nx]; qrbuf = new double[nq]; qxybuf = new double[nq, nx+1]; if( d==1 ) { y = new double[nq]; w = new double[nq]; qsol = new double[1+nx]; // // 1 for constant member, // NX for linear members, // 1 for temporary storage // fmatrix = new double[nq, 1+nx+1]; } if( d==2 ) { y = new double[nq]; w = new double[nq]; qsol = new double[1+nx+(int)Math.Round(nx*(nx+1)*0.5)]; // // 1 for constant member, // NX for linear members, // Round(NX*(NX+1)*0.5) for quadratic model, // 1 for temporary storage // fmatrix = new double[nq, 1+nx+(int)Math.Round(nx*(nx+1)*0.5)+1]; } for(i=0; i<=n-1; i++) { // // Initialize center. // for(i_=0; i_<=nx-1;i_++) { z.q[i,i_] = xy[i,i_]; } // // Calculate linear/quadratic members // using least squares fit // NOTE 1: all weight are equal to 1.0 // NOTE 2: self-match is USED for this query // for(i_=0; i_<=nx-1;i_++) { x[i_] = xy[i,i_]; } k = nearestneighbor.kdtreequeryknn(z.tree, x, nq, true); nearestneighbor.kdtreequeryresultsxy(z.tree, ref qxybuf); nearestneighbor.kdtreequeryresultsdistances(z.tree, ref qrbuf); if( d==1 ) { // // Linear nodal function calculated using // least squares fitting to its neighbors // for(j=0; j<=k-1; j++) { fmatrix[j,0] = 1.0; for(j2=0; j2<=nx-1; j2++) { fmatrix[j,1+j2] = qxybuf[j,j2]-xy[i,j2]; } y[j] = qxybuf[j,nx]; w[j] = 1; } nc = 1+nx; } if( d==2 ) { // // Quadratic nodal function calculated using // least squares fitting to its neighbors // for(j=0; j<=k-1; j++) { fmatrix[j,0] = 1; offs = 1; for(j2=0; j2<=nx-1; j2++) { fmatrix[j,offs] = qxybuf[j,j2]-xy[i,j2]; offs = offs+1; } for(j2=0; j2<=nx-1; j2++) { for(j3=j2; j3<=nx-1; j3++) { fmatrix[j,offs] = (qxybuf[j,j2]-xy[i,j2])*(qxybuf[j,j3]-xy[i,j3]); offs = offs+1; } } y[j] = qxybuf[j,nx]; w[j] = 1; } nc = 1+nx+(int)Math.Round(nx*(nx+1)*0.5); } idwinternalsolver(ref y, ref w, ref fmatrix, ref temp, k, nc, ref info, ref qsol, ref taskrcond); // // Least squares models: copy results // if( info>0 ) { // // LLS task is solved, copy results // z.debugworstrcond = Math.Min(z.debugworstrcond, taskrcond); z.debugbestrcond = Math.Max(z.debugbestrcond, taskrcond); for(j=0; j<=nc-1; j++) { z.q[i,nx+j] = qsol[j]; } } else { // // Solver failure, very strange, but we will use // zero values to handle it. // z.debugsolverfailures = z.debugsolverfailures+1; v = 0; for(j=0; j<=k-1; j++) { v = v+qxybuf[j,nx]; } z.q[i,nx] = v/k; for(j=0; j<=nc-2; j++) { z.q[i,nx+1+j] = 0; } } } }
/************************************************************************* IDW interpolant using modified Shepard method for non-uniform datasets. This type of model uses constant nodal functions and interpolates using all nodes which are closer than user-specified radius R. It may be used when points distribution is non-uniform at the small scale, but it is at the distances as large as R. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. R - radius, R>0 OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * if there is less than IDWKMin points within R-ball, algorithm selects IDWKMin closest ones, so that continuity properties of interpolant are preserved even far from points. -- ALGLIB PROJECT -- Copyright 11.04.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildmodifiedshepardr(double[,] xy, int n, int nx, double r, idwinterpolant z) { int i = 0; int[] tags = new int[0]; int i_ = 0; // // assertions // alglib.ap.assert(n>0, "IDWBuildModifiedShepardR: N<=0!"); alglib.ap.assert(nx>=1, "IDWBuildModifiedShepardR: NX<1!"); alglib.ap.assert((double)(r)>(double)(0), "IDWBuildModifiedShepardR: R<=0!"); // // primary initialization of Z // idwinit1(n, nx, 0, 0, n, z); z.modeltype = 1; z.r = r; // // Create KD-tree // tags = new int[n]; for(i=0; i<=n-1; i++) { tags[i] = i; } nearestneighbor.kdtreebuildtagged(xy, tags, n, nx, 1, 2, z.tree); // // build nodal functions // for(i=0; i<=n-1; i++) { for(i_=0; i_<=nx;i_++) { z.q[i,i_] = xy[i,i_]; } } }
/************************************************************************* IDW interpolation INPUT PARAMETERS: Z - IDW interpolant built with one of model building subroutines. X - array[0..NX-1], interpolation point Result: IDW interpolant Z(X) -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static double idwcalc(idwinterpolant z, double[] x) { double result = idwint.idwcalc(z.innerobj, x); return result; }
/************************************************************************* IDW interpolant using modified Shepard method for uniform point distributions. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function type, either: * 0 constant model. Just for demonstration only, worst model ever. * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). * -1 "fast" linear model, use with caution!!! It is significantly faster than linear/quadratic and better than constant model. But it is less robust (especially in the presence of noise). NQ - number of points used to calculate nodal functions (ignored for constant models). NQ should be LARGER than: * max(1.5*(1+NX),2^NX+1) for linear model, * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, worst - with constant models * when N is large, NQ and NW must be significantly smaller than N both to obtain optimal performance and to obtain optimal accuracy. In 2 or 3-dimensional tasks NQ=15 and NW=25 are good values to start with. * NQ and NW may be greater than N. In such cases they will be automatically decreased. * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. * this subroutine assumes that point distribution is uniform at the small scales. If it isn't - for example, points are concentrated along "lines", but "lines" distribution is uniform at the larger scale - then you should use IDWBuildModifiedShepardR() -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildmodifiedshepard(double[,] xy, int n, int nx, int d, int nq, int nw, idwinterpolant z) { int i = 0; int j = 0; int k = 0; int j2 = 0; int j3 = 0; double v = 0; double r = 0; double s = 0; double d0 = 0; double di = 0; double v1 = 0; double v2 = 0; int nc = 0; int offs = 0; double[] x = new double[0]; double[] qrbuf = new double[0]; double[,] qxybuf = new double[0,0]; double[] y = new double[0]; double[,] fmatrix = new double[0,0]; double[] w = new double[0]; double[] qsol = new double[0]; double[] temp = new double[0]; int[] tags = new int[0]; int info = 0; double taskrcond = 0; int i_ = 0; // // these initializers are not really necessary, // but without them compiler complains about uninitialized locals // nc = 0; // // assertions // alglib.ap.assert(n>0, "IDWBuildModifiedShepard: N<=0!"); alglib.ap.assert(nx>=1, "IDWBuildModifiedShepard: NX<1!"); alglib.ap.assert(d>=-1 && d<=2, "IDWBuildModifiedShepard: D<>-1 and D<>0 and D<>1 and D<>2!"); // // Correct parameters if needed // if( d==1 ) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor*(1+nx))+1); nq = Math.Max(nq, (int)Math.Round(Math.Pow(2, nx))+1); } if( d==2 ) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor*(nx+2)*(nx+1)/2)+1); nq = Math.Max(nq, (int)Math.Round(Math.Pow(2, nx))+1); } nw = Math.Max(nw, (int)Math.Round(Math.Pow(2, nx))+1); nq = Math.Min(nq, n); nw = Math.Min(nw, n); // // primary initialization of Z // idwinit1(n, nx, d, nq, nw, z); z.modeltype = 0; // // Create KD-tree // tags = new int[n]; for(i=0; i<=n-1; i++) { tags[i] = i; } nearestneighbor.kdtreebuildtagged(xy, tags, n, nx, 1, 2, z.tree); // // build nodal functions // temp = new double[nq+1]; x = new double[nx]; qrbuf = new double[nq]; qxybuf = new double[nq, nx+1]; if( d==-1 ) { w = new double[nq]; } if( d==1 ) { y = new double[nq]; w = new double[nq]; qsol = new double[nx]; // // NX for linear members, // 1 for temporary storage // fmatrix = new double[nq, nx+1]; } if( d==2 ) { y = new double[nq]; w = new double[nq]; qsol = new double[nx+(int)Math.Round(nx*(nx+1)*0.5)]; // // NX for linear members, // Round(NX*(NX+1)*0.5) for quadratic model, // 1 for temporary storage // fmatrix = new double[nq, nx+(int)Math.Round(nx*(nx+1)*0.5)+1]; } for(i=0; i<=n-1; i++) { // // Initialize center and function value. // If D=0 it is all what we need // for(i_=0; i_<=nx;i_++) { z.q[i,i_] = xy[i,i_]; } if( d==0 ) { continue; } // // calculate weights for linear/quadratic members calculation. // // NOTE 1: weights are calculated using NORMALIZED modified // Shepard's formula. Original formula is w(i) = sqr((R-di)/(R*di)), // where di is i-th distance, R is max(di). Modified formula have // following form: // w_mod(i) = 1, if di=d0 // w_mod(i) = w(i)/w(0), if di<>d0 // // NOTE 2: self-match is NOT used for this query // // NOTE 3: last point almost always gain zero weight, but it MUST // be used for fitting because sometimes it will gain NON-ZERO // weight - for example, when all distances are equal. // for(i_=0; i_<=nx-1;i_++) { x[i_] = xy[i,i_]; } k = nearestneighbor.kdtreequeryknn(z.tree, x, nq, false); nearestneighbor.kdtreequeryresultsxy(z.tree, ref qxybuf); nearestneighbor.kdtreequeryresultsdistances(z.tree, ref qrbuf); r = qrbuf[k-1]; d0 = qrbuf[0]; for(j=0; j<=k-1; j++) { di = qrbuf[j]; if( (double)(di)==(double)(d0) ) { // // distance is equal to shortest, set it 1.0 // without explicitly calculating (which would give // us same result, but 'll expose us to the risk of // division by zero). // w[j] = 1; } else { // // use normalized formula // v1 = (r-di)/(r-d0); v2 = d0/di; w[j] = math.sqr(v1*v2); } } // // calculate linear/quadratic members // if( d==-1 ) { // // "Fast" linear nodal function calculated using // inverse distance weighting // for(j=0; j<=nx-1; j++) { x[j] = 0; } s = 0; for(j=0; j<=k-1; j++) { // // calculate J-th inverse distance weighted gradient: // grad_k = (y_j-y_k)*(x_j-x_k)/sqr(norm(x_j-x_k)) // grad = sum(wk*grad_k)/sum(w_k) // v = 0; for(j2=0; j2<=nx-1; j2++) { v = v+math.sqr(qxybuf[j,j2]-xy[i,j2]); } // // Although x_j<>x_k, sqr(norm(x_j-x_k)) may be zero due to // underflow. If it is, we assume than J-th gradient is zero // (i.e. don't add anything) // if( (double)(v)!=(double)(0) ) { for(j2=0; j2<=nx-1; j2++) { x[j2] = x[j2]+w[j]*(qxybuf[j,nx]-xy[i,nx])*(qxybuf[j,j2]-xy[i,j2])/v; } } s = s+w[j]; } for(j=0; j<=nx-1; j++) { z.q[i,nx+1+j] = x[j]/s; } } else { // // Least squares models: build // if( d==1 ) { // // Linear nodal function calculated using // least squares fitting to its neighbors // for(j=0; j<=k-1; j++) { for(j2=0; j2<=nx-1; j2++) { fmatrix[j,j2] = qxybuf[j,j2]-xy[i,j2]; } y[j] = qxybuf[j,nx]-xy[i,nx]; } nc = nx; } if( d==2 ) { // // Quadratic nodal function calculated using // least squares fitting to its neighbors // for(j=0; j<=k-1; j++) { offs = 0; for(j2=0; j2<=nx-1; j2++) { fmatrix[j,offs] = qxybuf[j,j2]-xy[i,j2]; offs = offs+1; } for(j2=0; j2<=nx-1; j2++) { for(j3=j2; j3<=nx-1; j3++) { fmatrix[j,offs] = (qxybuf[j,j2]-xy[i,j2])*(qxybuf[j,j3]-xy[i,j3]); offs = offs+1; } } y[j] = qxybuf[j,nx]-xy[i,nx]; } nc = nx+(int)Math.Round(nx*(nx+1)*0.5); } idwinternalsolver(ref y, ref w, ref fmatrix, ref temp, k, nc, ref info, ref qsol, ref taskrcond); // // Least squares models: copy results // if( info>0 ) { // // LLS task is solved, copy results // z.debugworstrcond = Math.Min(z.debugworstrcond, taskrcond); z.debugbestrcond = Math.Max(z.debugbestrcond, taskrcond); for(j=0; j<=nc-1; j++) { z.q[i,nx+1+j] = qsol[j]; } } else { // // Solver failure, very strange, but we will use // zero values to handle it. // z.debugsolverfailures = z.debugsolverfailures+1; for(j=0; j<=nc-1; j++) { z.q[i,nx+1+j] = 0; } } } } }
/************************************************************************* IDW interpolation INPUT PARAMETERS: Z - IDW interpolant built with one of model building subroutines. X - array[0..NX-1], interpolation point Result: IDW interpolant Z(X) -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static double idwcalc(idwinterpolant z, double[] x) { double result = 0; int i = 0; int k = 0; double r = 0; double s = 0; double w = 0; double v1 = 0; double v2 = 0; double d0 = 0; double di = 0; // // these initializers are not really necessary, // but without them compiler complains about uninitialized locals // k = 0; // // Query // if( z.modeltype==0 ) { // // NQ/NW-based model // k = nearestneighbor.kdtreequeryknn(z.tree, x, z.nw, true); nearestneighbor.kdtreequeryresultsdistances(z.tree, ref z.rbuf); nearestneighbor.kdtreequeryresultstags(z.tree, ref z.tbuf); } if( z.modeltype==1 ) { // // R-based model // k = nearestneighbor.kdtreequeryrnn(z.tree, x, z.r, true); nearestneighbor.kdtreequeryresultsdistances(z.tree, ref z.rbuf); nearestneighbor.kdtreequeryresultstags(z.tree, ref z.tbuf); if( k<idwkmin ) { // // we need at least IDWKMin points // k = nearestneighbor.kdtreequeryknn(z.tree, x, idwkmin, true); nearestneighbor.kdtreequeryresultsdistances(z.tree, ref z.rbuf); nearestneighbor.kdtreequeryresultstags(z.tree, ref z.tbuf); } } // // initialize weights for linear/quadratic members calculation. // // NOTE 1: weights are calculated using NORMALIZED modified // Shepard's formula. Original formula gives w(i) = sqr((R-di)/(R*di)), // where di is i-th distance, R is max(di). Modified formula have // following form: // w_mod(i) = 1, if di=d0 // w_mod(i) = w(i)/w(0), if di<>d0 // // NOTE 2: self-match is USED for this query // // NOTE 3: last point almost always gain zero weight, but it MUST // be used for fitting because sometimes it will gain NON-ZERO // weight - for example, when all distances are equal. // r = z.rbuf[k-1]; d0 = z.rbuf[0]; result = 0; s = 0; for(i=0; i<=k-1; i++) { di = z.rbuf[i]; if( (double)(di)==(double)(d0) ) { // // distance is equal to shortest, set it 1.0 // without explicitly calculating (which would give // us same result, but 'll expose us to the risk of // division by zero). // w = 1; } else { // // use normalized formula // v1 = (r-di)/(r-d0); v2 = d0/di; w = math.sqr(v1*v2); } result = result+w*idwcalcq(z, x, z.tbuf[i]); s = s+w; } result = result/s; return result; }
public override alglib.apobject make_copy() { idwinterpolant _result = new idwinterpolant(); _result.n = n; _result.nx = nx; _result.d = d; _result.r = r; _result.nw = nw; _result.tree = (nearestneighbor.kdtree)tree.make_copy(); _result.modeltype = modeltype; _result.q = (double[,])q.Clone(); _result.xbuf = (double[])xbuf.Clone(); _result.tbuf = (int[])tbuf.Clone(); _result.rbuf = (double[])rbuf.Clone(); _result.xybuf = (double[,])xybuf.Clone(); _result.debugsolverfailures = debugsolverfailures; _result.debugworstrcond = debugworstrcond; _result.debugbestrcond = debugbestrcond; return _result; }
/************************************************************************* IDW model for noisy data. This subroutine may be used to handle noisy data, i.e. data with noise in OUTPUT values. It differs from IDWBuildModifiedShepard() in the following aspects: * nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, i.e. we have fitting instead of interpolation. * weights which are used during least squares fitting stage are all equal to 1.0 (independently of distance) * "fast"-linear or constant nodal functions are not supported (either not robust enough or too rigid) This problem require far more complex tuning than interpolation problems. Below you can find some recommendations regarding this problem: * focus on tuning NQ; it controls noise reduction. As for NW, you can just make it equal to 2*NQ. * you can use cross-validation to determine optimal NQ. * optimal NQ is a result of complex tradeoff between noise level (more noise = larger NQ required) and underlying function complexity (given fixed N, larger NQ means smoothing of compex features in the data). For example, NQ=N will reduce noise to the minimum level possible, but you will end up with just constant/linear/quadratic (depending on D) least squares model for the whole dataset. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function degree, either: * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models (or for very noisy problems). * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). NQ - number of points used to calculate nodal functions. NQ should be significantly larger than 1.5 times the number of coefficients in a nodal function to overcome effects of noise: * larger than 1.5*(1+NX) for linear model, * larger than 3/4*(NX+2)*(NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ or larger OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, linear models are not recommended to use unless you are pretty sure that it is what you want * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildnoisy(double[,] xy, int n, int nx, int d, int nq, int nw, out idwinterpolant z) { z = new idwinterpolant(); idwint.idwbuildnoisy(xy, n, nx, d, nq, nw, z.innerobj); return; }
/************************************************************************* IDW interpolant using modified Shepard method for non-uniform datasets. This type of model uses constant nodal functions and interpolates using all nodes which are closer than user-specified radius R. It may be used when points distribution is non-uniform at the small scale, but it is at the distances as large as R. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. R - radius, R>0 OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * if there is less than IDWKMin points within R-ball, algorithm selects IDWKMin closest ones, so that continuity properties of interpolant are preserved even far from points. -- ALGLIB PROJECT -- Copyright 11.04.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildmodifiedshepardr(double[,] xy, int n, int nx, double r, out idwinterpolant z) { z = new idwinterpolant(); idwint.idwbuildmodifiedshepardr(xy, n, nx, r, z.innerobj); return; }
/************************************************************************* * IDW interpolation * * INPUT PARAMETERS: * Z - IDW interpolant built with one of model building * subroutines. * X - array[0..NX-1], interpolation point * * Result: * IDW interpolant Z(X) * * -- ALGLIB -- * Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static double idwcalc(ref idwinterpolant z, ref double[] x) { double result = 0; int nx = 0; int i = 0; int k = 0; double r = 0; double s = 0; double w = 0; double v1 = 0; double v2 = 0; double d0 = 0; double di = 0; double v = 0; if (z.modeltype == 0) { // // NQ/NW-based model // nx = z.nx; nearestneighbor.kdtreequeryknn(ref z.tree, ref x, z.nw, true); nearestneighbor.kdtreequeryresultsdistances(ref z.tree, ref z.rbuf, ref k); nearestneighbor.kdtreequeryresultstags(ref z.tree, ref z.tbuf, ref k); } if (z.modeltype == 1) { // // R-based model // nx = z.nx; nearestneighbor.kdtreequeryrnn(ref z.tree, ref x, z.r, true); nearestneighbor.kdtreequeryresultsdistances(ref z.tree, ref z.rbuf, ref k); nearestneighbor.kdtreequeryresultstags(ref z.tree, ref z.tbuf, ref k); if (k < idwkmin) { // // we need at least IDWKMin points // nearestneighbor.kdtreequeryknn(ref z.tree, ref x, idwkmin, true); nearestneighbor.kdtreequeryresultsdistances(ref z.tree, ref z.rbuf, ref k); nearestneighbor.kdtreequeryresultstags(ref z.tree, ref z.tbuf, ref k); } } // // initialize weights for linear/quadratic members calculation. // // NOTE 1: weights are calculated using NORMALIZED modified // Shepard's formula. Original formula gives w(i) = sqr((R-di)/(R*di)), // where di is i-th distance, R is max(di). Modified formula have // following form: // w_mod(i) = 1, if di=d0 // w_mod(i) = w(i)/w(0), if di<>d0 // // NOTE 2: self-match is USED for this query // // NOTE 3: last point almost always gain zero weight, but it MUST // be used for fitting because sometimes it will gain NON-ZERO // weight - for example, when all distances are equal. // r = z.rbuf[k - 1]; d0 = z.rbuf[0]; result = 0; s = 0; for (i = 0; i <= k - 1; i++) { di = z.rbuf[i]; if ((double)(di) == (double)(d0)) { // // distance is equal to shortest, set it 1.0 // without explicitly calculating (which would give // us same result, but 'll expose us to the risk of // division by zero). // w = 1; } else { // // use normalized formula // v1 = (r - di) / (r - d0); v2 = d0 / di; w = AP.Math.Sqr(v1 * v2); } result = result + w * idwcalcq(ref z, ref x, z.tbuf[i]); s = s + w; } result = result / s; return(result); }
/************************************************************************* * IDW model for noisy data. * * This subroutine may be used to handle noisy data, i.e. data with noise in * OUTPUT values. It differs from IDWBuildModifiedShepard() in the following * aspects: * nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, * i.e. we have fitting instead of interpolation. * weights which are used during least squares fitting stage are all equal * to 1.0 (independently of distance) * "fast"-linear or constant nodal functions are not supported (either not * robust enough or too rigid) * * This problem require far more complex tuning than interpolation problems. * Below you can find some recommendations regarding this problem: * focus on tuning NQ; it controls noise reduction. As for NW, you can just * make it equal to 2*NQ. * you can use cross-validation to determine optimal NQ. * optimal NQ is a result of complex tradeoff between noise level (more * noise = larger NQ required) and underlying function complexity (given * fixed N, larger NQ means smoothing of compex features in the data). For * example, NQ=N will reduce noise to the minimum level possible, but you * will end up with just constant/linear/quadratic (depending on D) least * squares model for the whole dataset. * * INPUT PARAMETERS: * XY - X and Y values, array[0..N-1,0..NX]. * First NX columns contain X-values, last column contain * Y-values. * N - number of nodes, N>0. * NX - space dimension, NX>=1. * D - nodal function degree, either: * 1 linear model, least squares fitting. Simpe model for * datasets too small for quadratic models (or for very * noisy problems). * 2 quadratic model, least squares fitting. Best model * available (if your dataset is large enough). * NQ - number of points used to calculate nodal functions. NQ should * be significantly larger than 1.5 times the number of * coefficients in a nodal function to overcome effects of noise: * larger than 1.5*(1+NX) for linear model, * larger than 3/4*(NX+2)*(NX+1) for quadratic model. * Values less than this threshold will be silently increased. * NW - number of points used to calculate weights and to interpolate. * Required: >=2^NX+1, values less than this threshold will be * silently increased. * Recommended value: about 2*NQ or larger * * OUTPUT PARAMETERS: * Z - IDW interpolant. * * NOTES: * best results are obtained with quadratic models, linear models are not * recommended to use unless you are pretty sure that it is what you want * this subroutine is always succeeds (as long as correct parameters are * passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by * Robert J. Renka for more information on this algorithm. * * * -- ALGLIB PROJECT -- * Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildnoisy(ref double[,] xy, int n, int nx, int d, int nq, int nw, ref idwinterpolant z) { int i = 0; int j = 0; int k = 0; int j2 = 0; int j3 = 0; double v = 0; int nc = 0; int offs = 0; double taskrcond = 0; double[] x = new double[0]; double[] qrbuf = new double[0]; double[,] qxybuf = new double[0, 0]; double[] y = new double[0]; double[] w = new double[0]; double[,] fmatrix = new double[0, 0]; double[] qsol = new double[0]; int[] tags = new int[0]; double[] temp = new double[0]; int info = 0; int i_ = 0; // // assertions // System.Diagnostics.Debug.Assert(n > 0, "IDWBuildNoisy: N<=0!"); System.Diagnostics.Debug.Assert(nx >= 1, "IDWBuildNoisy: NX<1!"); System.Diagnostics.Debug.Assert(d >= 1 & d <= 2, "IDWBuildNoisy: D<>1 and D<>2!"); // // Correct parameters if needed // if (d == 1) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor * (1 + nx)) + 1); } if (d == 2) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor * (nx + 2) * (nx + 1) / 2) + 1); } nw = Math.Max(nw, (int)Math.Round(Math.Pow(2, nx)) + 1); nq = Math.Min(nq, n); nw = Math.Min(nw, n); // // primary initialization of Z // idwinit1(n, nx, d, nq, nw, ref z); z.modeltype = 0; // // Create KD-tree // tags = new int[n]; for (i = 0; i <= n - 1; i++) { tags[i] = i; } nearestneighbor.kdtreebuildtagged(ref xy, ref tags, n, nx, 1, 2, ref z.tree); // // build nodal functions // (special algorithm for noisy data is used) // temp = new double[nq + 1]; x = new double[nx]; qrbuf = new double[nq]; qxybuf = new double[nq, nx + 1]; if (d == 1) { y = new double[nq]; w = new double[nq]; qsol = new double[1 + nx]; // // 1 for constant member, // NX for linear members, // 1 for temporary storage // fmatrix = new double[nq, 1 + nx + 1]; } if (d == 2) { y = new double[nq]; w = new double[nq]; qsol = new double[1 + nx + (int)Math.Round(nx * (nx + 1) * 0.5)]; // // 1 for constant member, // NX for linear members, // Round(NX*(NX+1)*0.5) for quadratic model, // 1 for temporary storage // fmatrix = new double[nq, 1 + nx + (int)Math.Round(nx * (nx + 1) * 0.5) + 1]; } for (i = 0; i <= n - 1; i++) { // // Initialize center. // for (i_ = 0; i_ <= nx - 1; i_++) { z.q[i, i_] = xy[i, i_]; } // // Calculate linear/quadratic members // using least squares fit // NOTE 1: all weight are equal to 1.0 // NOTE 2: self-match is USED for this query // for (i_ = 0; i_ <= nx - 1; i_++) { x[i_] = xy[i, i_]; } nearestneighbor.kdtreequeryknn(ref z.tree, ref x, nq, true); nearestneighbor.kdtreequeryresultsxy(ref z.tree, ref qxybuf, ref k); nearestneighbor.kdtreequeryresultsdistances(ref z.tree, ref qrbuf, ref k); if (d == 1) { // // Linear nodal function calculated using // least squares fitting to its neighbors // for (j = 0; j <= k - 1; j++) { fmatrix[j, 0] = 1.0; for (j2 = 0; j2 <= nx - 1; j2++) { fmatrix[j, 1 + j2] = qxybuf[j, j2] - xy[i, j2]; } y[j] = qxybuf[j, nx]; w[j] = 1; } nc = 1 + nx; } if (d == 2) { // // Quadratic nodal function calculated using // least squares fitting to its neighbors // for (j = 0; j <= k - 1; j++) { fmatrix[j, 0] = 1; offs = 1; for (j2 = 0; j2 <= nx - 1; j2++) { fmatrix[j, offs] = qxybuf[j, j2] - xy[i, j2]; offs = offs + 1; } for (j2 = 0; j2 <= nx - 1; j2++) { for (j3 = j2; j3 <= nx - 1; j3++) { fmatrix[j, offs] = (qxybuf[j, j2] - xy[i, j2]) * (qxybuf[j, j3] - xy[i, j3]); offs = offs + 1; } } y[j] = qxybuf[j, nx]; w[j] = 1; } nc = 1 + nx + (int)Math.Round(nx * (nx + 1) * 0.5); } idwinternalsolver(ref y, ref w, ref fmatrix, ref temp, k, nc, ref info, ref qsol, ref taskrcond); // // Least squares models: copy results // if (info > 0) { // // LLS task is solved, copy results // z.debugworstrcond = Math.Min(z.debugworstrcond, taskrcond); z.debugbestrcond = Math.Max(z.debugbestrcond, taskrcond); for (j = 0; j <= nc - 1; j++) { z.q[i, nx + j] = qsol[j]; } } else { // // Solver failure, very strange, but we will use // zero values to handle it. // z.debugsolverfailures = z.debugsolverfailures + 1; v = 0; for (j = 0; j <= k - 1; j++) { v = v + qxybuf[j, nx]; } z.q[i, nx] = v / k; for (j = 0; j <= nc - 2; j++) { z.q[i, nx + 1 + j] = 0; } } } }
/************************************************************************* * IDW interpolant using modified Shepard method for uniform point * distributions. * * INPUT PARAMETERS: * XY - X and Y values, array[0..N-1,0..NX]. * First NX columns contain X-values, last column contain * Y-values. * N - number of nodes, N>0. * NX - space dimension, NX>=1. * D - nodal function type, either: * 0 constant model. Just for demonstration only, worst * model ever. * 1 linear model, least squares fitting. Simpe model for * datasets too small for quadratic models * 2 quadratic model, least squares fitting. Best model * available (if your dataset is large enough). * -1 "fast" linear model, use with caution!!! It is * significantly faster than linear/quadratic and better * than constant model. But it is less robust (especially * in the presence of noise). * NQ - number of points used to calculate nodal functions (ignored * for constant models). NQ should be LARGER than: * max(1.5*(1+NX),2^NX+1) for linear model, * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. * Values less than this threshold will be silently increased. * NW - number of points used to calculate weights and to interpolate. * Required: >=2^NX+1, values less than this threshold will be * silently increased. * Recommended value: about 2*NQ * * OUTPUT PARAMETERS: * Z - IDW interpolant. * * NOTES: * best results are obtained with quadratic models, worst - with constant * models * when N is large, NQ and NW must be significantly smaller than N both * to obtain optimal performance and to obtain optimal accuracy. In 2 or * 3-dimensional tasks NQ=15 and NW=25 are good values to start with. * NQ and NW may be greater than N. In such cases they will be * automatically decreased. * this subroutine is always succeeds (as long as correct parameters are * passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by * Robert J. Renka for more information on this algorithm. * this subroutine assumes that point distribution is uniform at the small * scales. If it isn't - for example, points are concentrated along * "lines", but "lines" distribution is uniform at the larger scale - then * you should use IDWBuildModifiedShepardR() * * * -- ALGLIB PROJECT -- * Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ public static void idwbuildmodifiedshepard(ref double[,] xy, int n, int nx, int d, int nq, int nw, ref idwinterpolant z) { int i = 0; int j = 0; int k = 0; int j2 = 0; int j3 = 0; double v = 0; double r = 0; double s = 0; double d0 = 0; double di = 0; double v1 = 0; double v2 = 0; int nc = 0; int offs = 0; double[] x = new double[0]; double[] qrbuf = new double[0]; double[,] qxybuf = new double[0, 0]; double[] y = new double[0]; double[,] fmatrix = new double[0, 0]; double[] w = new double[0]; double[] qsol = new double[0]; double[] temp = new double[0]; int[] tags = new int[0]; int info = 0; double taskrcond = 0; int i_ = 0; // // assertions // System.Diagnostics.Debug.Assert(n > 0, "IDWBuildModifiedShepard: N<=0!"); System.Diagnostics.Debug.Assert(nx >= 1, "IDWBuildModifiedShepard: NX<1!"); System.Diagnostics.Debug.Assert(d >= -1 & d <= 2, "IDWBuildModifiedShepard: D<>-1 and D<>0 and D<>1 and D<>2!"); // // Correct parameters if needed // if (d == 1) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor * (1 + nx)) + 1); nq = Math.Max(nq, (int)Math.Round(Math.Pow(2, nx)) + 1); } if (d == 2) { nq = Math.Max(nq, (int)Math.Ceiling(idwqfactor * (nx + 2) * (nx + 1) / 2) + 1); nq = Math.Max(nq, (int)Math.Round(Math.Pow(2, nx)) + 1); } nw = Math.Max(nw, (int)Math.Round(Math.Pow(2, nx)) + 1); nq = Math.Min(nq, n); nw = Math.Min(nw, n); // // primary initialization of Z // idwinit1(n, nx, d, nq, nw, ref z); z.modeltype = 0; // // Create KD-tree // tags = new int[n]; for (i = 0; i <= n - 1; i++) { tags[i] = i; } nearestneighbor.kdtreebuildtagged(ref xy, ref tags, n, nx, 1, 2, ref z.tree); // // build nodal functions // temp = new double[nq + 1]; x = new double[nx]; qrbuf = new double[nq]; qxybuf = new double[nq, nx + 1]; if (d == -1) { w = new double[nq]; } if (d == 1) { y = new double[nq]; w = new double[nq]; qsol = new double[nx]; // // NX for linear members, // 1 for temporary storage // fmatrix = new double[nq, nx + 1]; } if (d == 2) { y = new double[nq]; w = new double[nq]; qsol = new double[nx + (int)Math.Round(nx * (nx + 1) * 0.5)]; // // NX for linear members, // Round(NX*(NX+1)*0.5) for quadratic model, // 1 for temporary storage // fmatrix = new double[nq, nx + (int)Math.Round(nx * (nx + 1) * 0.5) + 1]; } for (i = 0; i <= n - 1; i++) { // // Initialize center and function value. // If D=0 it is all what we need // for (i_ = 0; i_ <= nx; i_++) { z.q[i, i_] = xy[i, i_]; } if (d == 0) { continue; } // // calculate weights for linear/quadratic members calculation. // // NOTE 1: weights are calculated using NORMALIZED modified // Shepard's formula. Original formula is w(i) = sqr((R-di)/(R*di)), // where di is i-th distance, R is max(di). Modified formula have // following form: // w_mod(i) = 1, if di=d0 // w_mod(i) = w(i)/w(0), if di<>d0 // // NOTE 2: self-match is NOT used for this query // // NOTE 3: last point almost always gain zero weight, but it MUST // be used for fitting because sometimes it will gain NON-ZERO // weight - for example, when all distances are equal. // for (i_ = 0; i_ <= nx - 1; i_++) { x[i_] = xy[i, i_]; } nearestneighbor.kdtreequeryknn(ref z.tree, ref x, nq, false); nearestneighbor.kdtreequeryresultsxy(ref z.tree, ref qxybuf, ref k); nearestneighbor.kdtreequeryresultsdistances(ref z.tree, ref qrbuf, ref k); r = qrbuf[k - 1]; d0 = qrbuf[0]; for (j = 0; j <= k - 1; j++) { di = qrbuf[j]; if ((double)(di) == (double)(d0)) { // // distance is equal to shortest, set it 1.0 // without explicitly calculating (which would give // us same result, but 'll expose us to the risk of // division by zero). // w[j] = 1; } else { // // use normalized formula // v1 = (r - di) / (r - d0); v2 = d0 / di; w[j] = AP.Math.Sqr(v1 * v2); } } // // calculate linear/quadratic members // if (d == -1) { // // "Fast" linear nodal function calculated using // inverse distance weighting // for (j = 0; j <= nx - 1; j++) { x[j] = 0; } s = 0; for (j = 0; j <= k - 1; j++) { // // calculate J-th inverse distance weighted gradient: // grad_k = (y_j-y_k)*(x_j-x_k)/sqr(norm(x_j-x_k)) // grad = sum(wk*grad_k)/sum(w_k) // v = 0; for (j2 = 0; j2 <= nx - 1; j2++) { v = v + AP.Math.Sqr(qxybuf[j, j2] - xy[i, j2]); } // // Although x_j<>x_k, sqr(norm(x_j-x_k)) may be zero due to // underflow. If it is, we assume than J-th gradient is zero // (i.e. don't add anything) // if ((double)(v) != (double)(0)) { for (j2 = 0; j2 <= nx - 1; j2++) { x[j2] = x[j2] + w[j] * (qxybuf[j, nx] - xy[i, nx]) * (qxybuf[j, j2] - xy[i, j2]) / v; } } s = s + w[j]; } for (j = 0; j <= nx - 1; j++) { z.q[i, nx + 1 + j] = x[j] / s; } } else { // // Least squares models: build // if (d == 1) { // // Linear nodal function calculated using // least squares fitting to its neighbors // for (j = 0; j <= k - 1; j++) { for (j2 = 0; j2 <= nx - 1; j2++) { fmatrix[j, j2] = qxybuf[j, j2] - xy[i, j2]; } y[j] = qxybuf[j, nx] - xy[i, nx]; } nc = nx; } if (d == 2) { // // Quadratic nodal function calculated using // least squares fitting to its neighbors // for (j = 0; j <= k - 1; j++) { offs = 0; for (j2 = 0; j2 <= nx - 1; j2++) { fmatrix[j, offs] = qxybuf[j, j2] - xy[i, j2]; offs = offs + 1; } for (j2 = 0; j2 <= nx - 1; j2++) { for (j3 = j2; j3 <= nx - 1; j3++) { fmatrix[j, offs] = (qxybuf[j, j2] - xy[i, j2]) * (qxybuf[j, j3] - xy[i, j3]); offs = offs + 1; } } y[j] = qxybuf[j, nx] - xy[i, nx]; } nc = nx + (int)Math.Round(nx * (nx + 1) * 0.5); } idwinternalsolver(ref y, ref w, ref fmatrix, ref temp, k, nc, ref info, ref qsol, ref taskrcond); // // Least squares models: copy results // if (info > 0) { // // LLS task is solved, copy results // z.debugworstrcond = Math.Min(z.debugworstrcond, taskrcond); z.debugbestrcond = Math.Max(z.debugbestrcond, taskrcond); for (j = 0; j <= nc - 1; j++) { z.q[i, nx + 1 + j] = qsol[j]; } } else { // // Solver failure, very strange, but we will use // zero values to handle it. // z.debugsolverfailures = z.debugsolverfailures + 1; for (j = 0; j <= nc - 1; j++) { z.q[i, nx + 1 + j] = 0; } } } } }