/************************************************************************* * Rational least squares fitting, without weights and constraints. * * See BarycentricFitFloaterHormannWC() for more information. * * -- ALGLIB PROJECT -- * Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormann(ref double[] x, ref double[] y, int n, int m, ref int info, ref barycentricinterpolant b, ref barycentricfitreport rep) { double[] w = new double[0]; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; int i = 0; if (n < 1) { info = -1; return; } w = new double[n]; for (i = 0; i <= n - 1; i++) { w[i] = 1; } barycentricfitfloaterhormannwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 0, m, ref info, ref b, ref rep); }
/************************************************************************* Internal Floater-Hormann fitting subroutine for fixed D *************************************************************************/ private static void barycentricfitwcfixedd(double[] x, double[] y, double[] w, int n, double[] xc, double[] yc, int[] dc, int k, int m, int d, ref int info, ratint.barycentricinterpolant b, barycentricfitreport rep) { double[,] fmatrix = new double[0,0]; double[,] cmatrix = new double[0,0]; double[] y2 = new double[0]; double[] w2 = new double[0]; double[] sx = new double[0]; double[] sy = new double[0]; double[] sbf = new double[0]; double[] xoriginal = new double[0]; double[] yoriginal = new double[0]; double[] tmp = new double[0]; lsfitreport lrep = new lsfitreport(); double v0 = 0; double v1 = 0; double mx = 0; ratint.barycentricinterpolant b2 = new ratint.barycentricinterpolant(); int i = 0; int j = 0; int relcnt = 0; double xa = 0; double xb = 0; double sa = 0; double sb = 0; double decay = 0; int i_ = 0; x = (double[])x.Clone(); y = (double[])y.Clone(); w = (double[])w.Clone(); xc = (double[])xc.Clone(); yc = (double[])yc.Clone(); info = 0; if( ((n<1 || m<2) || k<0) || k>=m ) { info = -1; return; } for(i=0; i<=k-1; i++) { info = 0; if( dc[i]<0 ) { info = -1; } if( dc[i]>1 ) { info = -1; } if( info<0 ) { return; } } // // weight decay for correct handling of task which becomes // degenerate after constraints are applied // decay = 10000*math.machineepsilon; // // Scale X, Y, XC, YC // lsfitscalexy(ref x, ref y, ref w, n, ref xc, ref yc, dc, k, ref xa, ref xb, ref sa, ref sb, ref xoriginal, ref yoriginal); // // allocate space, initialize: // * FMatrix- values of basis functions at X[] // * CMatrix- values (derivatives) of basis functions at XC[] // y2 = new double[n+m]; w2 = new double[n+m]; fmatrix = new double[n+m, m]; if( k>0 ) { cmatrix = new double[k, m+1]; } y2 = new double[n+m]; w2 = new double[n+m]; // // Prepare design and constraints matrices: // * fill constraints matrix // * fill first N rows of design matrix with values // * fill next M rows of design matrix with regularizing term // * append M zeros to Y // * append M elements, mean(abs(W)) each, to W // sx = new double[m]; sy = new double[m]; sbf = new double[m]; for(j=0; j<=m-1; j++) { sx[j] = (double)(2*j)/(double)(m-1)-1; } for(i=0; i<=m-1; i++) { sy[i] = 1; } ratint.barycentricbuildfloaterhormann(sx, sy, m, d, b2); mx = 0; for(i=0; i<=n-1; i++) { barycentriccalcbasis(b2, x[i], ref sbf); for(i_=0; i_<=m-1;i_++) { fmatrix[i,i_] = sbf[i_]; } y2[i] = y[i]; w2[i] = w[i]; mx = mx+Math.Abs(w[i])/n; } for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { if( i==j ) { fmatrix[n+i,j] = decay; } else { fmatrix[n+i,j] = 0; } } y2[n+i] = 0; w2[n+i] = mx; } if( k>0 ) { for(j=0; j<=m-1; j++) { for(i=0; i<=m-1; i++) { sy[i] = 0; } sy[j] = 1; ratint.barycentricbuildfloaterhormann(sx, sy, m, d, b2); for(i=0; i<=k-1; i++) { alglib.ap.assert(dc[i]>=0 && dc[i]<=1, "BarycentricFit: internal error!"); ratint.barycentricdiff1(b2, xc[i], ref v0, ref v1); if( dc[i]==0 ) { cmatrix[i,j] = v0; } if( dc[i]==1 ) { cmatrix[i,j] = v1; } } } for(i=0; i<=k-1; i++) { cmatrix[i,m] = yc[i]; } } // // Solve constrained task // if( k>0 ) { // // solve using regularization // lsfitlinearwc(y2, w2, fmatrix, cmatrix, n+m, m, k, ref info, ref tmp, lrep); } else { // // no constraints, no regularization needed // lsfitlinearwc(y, w, fmatrix, cmatrix, n, m, k, ref info, ref tmp, lrep); } if( info<0 ) { return; } // // Generate interpolant and scale it // for(i_=0; i_<=m-1;i_++) { sy[i_] = tmp[i_]; } ratint.barycentricbuildfloaterhormann(sx, sy, m, d, b); ratint.barycentriclintransx(b, 2/(xb-xa), -((xa+xb)/(xb-xa))); ratint.barycentriclintransy(b, sb-sa, sa); // // Scale absolute errors obtained from LSFitLinearW. // Relative error should be calculated separately // (because of shifting/scaling of the task) // rep.taskrcond = lrep.taskrcond; rep.rmserror = lrep.rmserror*(sb-sa); rep.avgerror = lrep.avgerror*(sb-sa); rep.maxerror = lrep.maxerror*(sb-sa); rep.avgrelerror = 0; relcnt = 0; for(i=0; i<=n-1; i++) { if( (double)(yoriginal[i])!=(double)(0) ) { rep.avgrelerror = rep.avgrelerror+Math.Abs(ratint.barycentriccalc(b, xoriginal[i])-yoriginal[i])/Math.Abs(yoriginal[i]); relcnt = relcnt+1; } } if( relcnt!=0 ) { rep.avgrelerror = rep.avgrelerror/relcnt; } }
/************************************************************************* Rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9]. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0. M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormann(double[] x, double[] y, int n, int m, ref int info, ratint.barycentricinterpolant b, barycentricfitreport rep) { double[] w = new double[0]; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; int i = 0; info = 0; alglib.ap.assert(n>0, "BarycentricFitFloaterHormann: N<=0!"); alglib.ap.assert(m>0, "BarycentricFitFloaterHormann: M<=0!"); alglib.ap.assert(alglib.ap.len(x)>=n, "BarycentricFitFloaterHormann: Length(X)<N!"); alglib.ap.assert(alglib.ap.len(y)>=n, "BarycentricFitFloaterHormann: Length(Y)<N!"); alglib.ap.assert(apserv.isfinitevector(x, n), "BarycentricFitFloaterHormann: X contains infinite or NaN values!"); alglib.ap.assert(apserv.isfinitevector(y, n), "BarycentricFitFloaterHormann: Y contains infinite or NaN values!"); w = new double[n]; for(i=0; i<=n-1; i++) { w[i] = 1; } barycentricfitfloaterhormannwc(x, y, w, n, xc, yc, dc, 0, m, ref info, b, rep); }
/************************************************************************* Weghted rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9], with constraints and individual weights. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least WEIGHTED root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual weights and constraints. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. XC - points where function values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K<M. K=0 means no constraints (XC/YC/DC are not used in such cases) M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -1 means another errors in parameters passed (N<=0, for example) B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroutine doesn't calculate task's condition number for K<>0. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval boundaries. Note that consustency of the constraints on the function DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines which are more flexible). * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormannwc(double[] x, double[] y, double[] w, int n, double[] xc, double[] yc, int[] dc, int k, int m, ref int info, ratint.barycentricinterpolant b, barycentricfitreport rep) { int d = 0; int i = 0; double wrmscur = 0; double wrmsbest = 0; ratint.barycentricinterpolant locb = new ratint.barycentricinterpolant(); barycentricfitreport locrep = new barycentricfitreport(); int locinfo = 0; info = 0; alglib.ap.assert(n>0, "BarycentricFitFloaterHormannWC: N<=0!"); alglib.ap.assert(m>0, "BarycentricFitFloaterHormannWC: M<=0!"); alglib.ap.assert(k>=0, "BarycentricFitFloaterHormannWC: K<0!"); alglib.ap.assert(k<m, "BarycentricFitFloaterHormannWC: K>=M!"); alglib.ap.assert(alglib.ap.len(x)>=n, "BarycentricFitFloaterHormannWC: Length(X)<N!"); alglib.ap.assert(alglib.ap.len(y)>=n, "BarycentricFitFloaterHormannWC: Length(Y)<N!"); alglib.ap.assert(alglib.ap.len(w)>=n, "BarycentricFitFloaterHormannWC: Length(W)<N!"); alglib.ap.assert(alglib.ap.len(xc)>=k, "BarycentricFitFloaterHormannWC: Length(XC)<K!"); alglib.ap.assert(alglib.ap.len(yc)>=k, "BarycentricFitFloaterHormannWC: Length(YC)<K!"); alglib.ap.assert(alglib.ap.len(dc)>=k, "BarycentricFitFloaterHormannWC: Length(DC)<K!"); alglib.ap.assert(apserv.isfinitevector(x, n), "BarycentricFitFloaterHormannWC: X contains infinite or NaN values!"); alglib.ap.assert(apserv.isfinitevector(y, n), "BarycentricFitFloaterHormannWC: Y contains infinite or NaN values!"); alglib.ap.assert(apserv.isfinitevector(w, n), "BarycentricFitFloaterHormannWC: X contains infinite or NaN values!"); alglib.ap.assert(apserv.isfinitevector(xc, k), "BarycentricFitFloaterHormannWC: XC contains infinite or NaN values!"); alglib.ap.assert(apserv.isfinitevector(yc, k), "BarycentricFitFloaterHormannWC: YC contains infinite or NaN values!"); for(i=0; i<=k-1; i++) { alglib.ap.assert(dc[i]==0 || dc[i]==1, "BarycentricFitFloaterHormannWC: one of DC[] is not 0 or 1!"); } // // Find optimal D // // Info is -3 by default (degenerate constraints). // If LocInfo will always be equal to -3, Info will remain equal to -3. // If at least once LocInfo will be -4, Info will be -4. // wrmsbest = math.maxrealnumber; rep.dbest = -1; info = -3; for(d=0; d<=Math.Min(9, n-1); d++) { barycentricfitwcfixedd(x, y, w, n, xc, yc, dc, k, m, d, ref locinfo, locb, locrep); alglib.ap.assert((locinfo==-4 || locinfo==-3) || locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!"); if( locinfo>0 ) { // // Calculate weghted RMS // wrmscur = 0; for(i=0; i<=n-1; i++) { wrmscur = wrmscur+math.sqr(w[i]*(y[i]-ratint.barycentriccalc(locb, x[i]))); } wrmscur = Math.Sqrt(wrmscur/n); if( (double)(wrmscur)<(double)(wrmsbest) || rep.dbest<0 ) { ratint.barycentriccopy(locb, b); rep.dbest = d; info = 1; rep.rmserror = locrep.rmserror; rep.avgerror = locrep.avgerror; rep.avgrelerror = locrep.avgrelerror; rep.maxerror = locrep.maxerror; rep.taskrcond = locrep.taskrcond; wrmsbest = wrmscur; } } else { if( locinfo!=-3 && info<0 ) { info = locinfo; } } } }
public override alglib.apobject make_copy() { barycentricfitreport _result = new barycentricfitreport(); _result.taskrcond = taskrcond; _result.dbest = dbest; _result.rmserror = rmserror; _result.avgerror = avgerror; _result.avgrelerror = avgrelerror; _result.maxerror = maxerror; return _result; }
/************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ public static void _pexec_barycentricfitfloaterhormann(double[] x, double[] y, int n, int m, ref int info, ratint.barycentricinterpolant b, barycentricfitreport rep) { barycentricfitfloaterhormann(x,y,n,m,ref info,b,rep); }
/************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ public static void _pexec_barycentricfitfloaterhormannwc(double[] x, double[] y, double[] w, int n, double[] xc, double[] yc, int[] dc, int k, int m, ref int info, ratint.barycentricinterpolant b, barycentricfitreport rep) { barycentricfitfloaterhormannwc(x,y,w,n,xc,yc,dc,k,m,ref info,b,rep); }
/************************************************************************* Rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9]. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0. M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormann(double[] x, double[] y, int n, int m, out int info, out barycentricinterpolant b, out barycentricfitreport rep) { info = 0; b = new barycentricinterpolant(); rep = new barycentricfitreport(); lsfit.barycentricfitfloaterhormann(x, y, n, m, ref info, b.innerobj, rep.innerobj); return; }
/************************************************************************* Weghted rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9], with constraints and individual weights. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least WEIGHTED root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual weights and constraints. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. XC - points where function values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K<M. K=0 means no constraints (XC/YC/DC are not used in such cases) M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -1 means another errors in parameters passed (N<=0, for example) B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroutine doesn't calculate task's condition number for K<>0. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval boundaries. Note that consustency of the constraints on the function DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines which are more flexible). * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormannwc(double[] x, double[] y, double[] w, int n, double[] xc, double[] yc, int[] dc, int k, int m, out int info, out barycentricinterpolant b, out barycentricfitreport rep) { info = 0; b = new barycentricinterpolant(); rep = new barycentricfitreport(); lsfit.barycentricfitfloaterhormannwc(x, y, w, n, xc, yc, dc, k, m, ref info, b.innerobj, rep.innerobj); return; }
/************************************************************************* * Weghted rational least squares fitting using Floater-Hormann rational * functions with optimal D chosen from [0,9], with constraints and * individual weights. * * Equidistant grid with M node on [min(x),max(x)] is used to build basis * functions. Different values of D are tried, optimal D (least WEIGHTED root * mean square error) is chosen. Task is linear, so linear least squares * solver is used. Complexity of this computational scheme is O(N*M^2) * (mostly dominated by the least squares solver). * * SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual * weights and constraints. * * INPUT PARAMETERS: * X - points, array[0..N-1]. * Y - function values, array[0..N-1]. * W - weights, array[0..N-1] * Each summand in square sum of approximation deviations from * given values is multiplied by the square of corresponding * weight. Fill it by 1's if you don't want to solve weighted * task. * N - number of points, N>0. * XC - points where function values/derivatives are constrained, * array[0..K-1]. * YC - values of constraints, array[0..K-1] * DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] * SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS * K - number of constraints, 0<=K<M. * K=0 means no constraints (XC/YC/DC are not used in such cases) * M - number of basis functions ( = number_of_nodes), M>=2. * * OUTPUT PARAMETERS: * Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: * -4 means inconvergence of internal SVD * -3 means inconsistent constraints * -1 means another errors in parameters passed * (N<=0, for example) * B - barycentric interpolant. * Rep - report, same format as in LSFitLinearWC() subroutine. * Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error * NON-WEIGHTED ERRORS ARE CALCULATED * * IMPORTANT: * this subroitine doesn't calculate task's condition number for K<>0. * * SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: * * Setting constraints can lead to undesired results, like ill-conditioned * behavior, or inconsistency being detected. From the other side, it allows * us to improve quality of the fit. Here we summarize our experience with * constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis * functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more * chances that they will be consistent * the greater is M (given fixed constraints), the more chances that * constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval * boundaries. Note that consustency of the constraints on the function * DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines * which are more flexible). * another special case is ONE constraint on the function value (OR, but * not AND, derivative) anywhere in the interval * * Our final recommendation is to use constraints WHEN AND ONLY WHEN you * can't solve your task without them. Anything beyond special cases given * above is not guaranteed and may result in inconsistency. * * -- ALGLIB PROJECT -- * Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormannwc(ref double[] x, ref double[] y, ref double[] w, int n, ref double[] xc, ref double[] yc, ref int[] dc, int k, int m, ref int info, ref barycentricinterpolant b, ref barycentricfitreport rep) { int d = 0; int i = 0; double wrmscur = 0; double wrmsbest = 0; barycentricinterpolant locb = new barycentricinterpolant(); barycentricfitreport locrep = new barycentricfitreport(); int locinfo = 0; if (n < 1 | m < 2 | k < 0 | k >= m) { info = -1; return; } // // Find optimal D // // Info is -3 by default (degenerate constraints). // If LocInfo will always be equal to -3, Info will remain equal to -3. // If at least once LocInfo will be -4, Info will be -4. // wrmsbest = AP.Math.MaxRealNumber; rep.dbest = -1; info = -3; for (d = 0; d <= Math.Min(9, n - 1); d++) { barycentricfitwcfixedd(x, y, ref w, n, xc, yc, ref dc, k, m, d, ref locinfo, ref locb, ref locrep); System.Diagnostics.Debug.Assert(locinfo == -4 | locinfo == -3 | locinfo > 0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!"); if (locinfo > 0) { // // Calculate weghted RMS // wrmscur = 0; for (i = 0; i <= n - 1; i++) { wrmscur = wrmscur + AP.Math.Sqr(w[i] * (y[i] - barycentriccalc(ref locb, x[i]))); } wrmscur = Math.Sqrt(wrmscur / n); if ((double)(wrmscur) < (double)(wrmsbest) | rep.dbest < 0) { barycentriccopy(ref locb, ref b); rep.dbest = d; info = 1; rep.rmserror = locrep.rmserror; rep.avgerror = locrep.avgerror; rep.avgrelerror = locrep.avgrelerror; rep.maxerror = locrep.maxerror; rep.taskrcond = locrep.taskrcond; wrmsbest = wrmscur; } } else { if (locinfo != -3 & info < 0) { info = locinfo; } } } }
/************************************************************************* * Internal Floater-Hormann fitting subroutine for fixed D *************************************************************************/ private static void barycentricfitwcfixedd(double[] x, double[] y, ref double[] w, int n, double[] xc, double[] yc, ref int[] dc, int k, int m, int d, ref int info, ref barycentricinterpolant b, ref barycentricfitreport rep) { double[,] fmatrix = new double[0, 0]; double[,] cmatrix = new double[0, 0]; double[] y2 = new double[0]; double[] w2 = new double[0]; double[] sx = new double[0]; double[] sy = new double[0]; double[] sbf = new double[0]; double[] xoriginal = new double[0]; double[] yoriginal = new double[0]; double[] tmp = new double[0]; lsfit.lsfitreport lrep = new lsfit.lsfitreport(); double v0 = 0; double v1 = 0; double mx = 0; barycentricinterpolant b2 = new barycentricinterpolant(); int i = 0; int j = 0; int relcnt = 0; double xa = 0; double xb = 0; double sa = 0; double sb = 0; double decay = 0; int i_ = 0; x = (double[])x.Clone(); y = (double[])y.Clone(); xc = (double[])xc.Clone(); yc = (double[])yc.Clone(); if (n < 1 | m < 2 | k < 0 | k >= m) { info = -1; return; } for (i = 0; i <= k - 1; i++) { info = 0; if (dc[i] < 0) { info = -1; } if (dc[i] > 1) { info = -1; } if (info < 0) { return; } } // // weight decay for correct handling of task which becomes // degenerate after constraints are applied // decay = 10000 * AP.Math.MachineEpsilon; // // Scale X, Y, XC, YC // lsfit.lsfitscalexy(ref x, ref y, n, ref xc, ref yc, ref dc, k, ref xa, ref xb, ref sa, ref sb, ref xoriginal, ref yoriginal); // // allocate space, initialize: // * FMatrix- values of basis functions at X[] // * CMatrix- values (derivatives) of basis functions at XC[] // y2 = new double[n + m]; w2 = new double[n + m]; fmatrix = new double[n + m, m]; if (k > 0) { cmatrix = new double[k, m + 1]; } y2 = new double[n + m]; w2 = new double[n + m]; // // Prepare design and constraints matrices: // * fill constraints matrix // * fill first N rows of design matrix with values // * fill next M rows of design matrix with regularizing term // * append M zeros to Y // * append M elements, mean(abs(W)) each, to W // sx = new double[m]; sy = new double[m]; sbf = new double[m]; for (j = 0; j <= m - 1; j++) { sx[j] = (double)(2 * j) / ((double)(m - 1)) - 1; } for (i = 0; i <= m - 1; i++) { sy[i] = 1; } barycentricbuildfloaterhormann(ref sx, ref sy, m, d, ref b2); mx = 0; for (i = 0; i <= n - 1; i++) { barycentriccalcbasis(ref b2, x[i], ref sbf); for (i_ = 0; i_ <= m - 1; i_++) { fmatrix[i, i_] = sbf[i_]; } y2[i] = y[i]; w2[i] = w[i]; mx = mx + Math.Abs(w[i]) / n; } for (i = 0; i <= m - 1; i++) { for (j = 0; j <= m - 1; j++) { if (i == j) { fmatrix[n + i, j] = decay; } else { fmatrix[n + i, j] = 0; } } y2[n + i] = 0; w2[n + i] = mx; } if (k > 0) { for (j = 0; j <= m - 1; j++) { for (i = 0; i <= m - 1; i++) { sy[i] = 0; } sy[j] = 1; barycentricbuildfloaterhormann(ref sx, ref sy, m, d, ref b2); for (i = 0; i <= k - 1; i++) { System.Diagnostics.Debug.Assert(dc[i] >= 0 & dc[i] <= 1, "BarycentricFit: internal error!"); barycentricdiff1(ref b2, xc[i], ref v0, ref v1); if (dc[i] == 0) { cmatrix[i, j] = v0; } if (dc[i] == 1) { cmatrix[i, j] = v1; } } } for (i = 0; i <= k - 1; i++) { cmatrix[i, m] = yc[i]; } } // // Solve constrained task // if (k > 0) { // // solve using regularization // lsfit.lsfitlinearwc(y2, ref w2, ref fmatrix, cmatrix, n + m, m, k, ref info, ref tmp, ref lrep); } else { // // no constraints, no regularization needed // lsfit.lsfitlinearwc(y, ref w, ref fmatrix, cmatrix, n, m, k, ref info, ref tmp, ref lrep); } if (info < 0) { return; } // // Generate interpolant and scale it // for (i_ = 0; i_ <= m - 1; i_++) { sy[i_] = tmp[i_]; } barycentricbuildfloaterhormann(ref sx, ref sy, m, d, ref b); barycentriclintransx(ref b, 2 / (xb - xa), -((xa + xb) / (xb - xa))); barycentriclintransy(ref b, sb - sa, sa); // // Scale absolute errors obtained from LSFitLinearW. // Relative error should be calculated separately // (because of shifting/scaling of the task) // rep.taskrcond = lrep.taskrcond; rep.rmserror = lrep.rmserror * (sb - sa); rep.avgerror = lrep.avgerror * (sb - sa); rep.maxerror = lrep.maxerror * (sb - sa); rep.avgrelerror = 0; relcnt = 0; for (i = 0; i <= n - 1; i++) { if ((double)(yoriginal[i]) != (double)(0)) { rep.avgrelerror = rep.avgrelerror + Math.Abs(barycentriccalc(ref b, xoriginal[i]) - yoriginal[i]) / Math.Abs(yoriginal[i]); relcnt = relcnt + 1; } } if (relcnt != 0) { rep.avgrelerror = rep.avgrelerror / relcnt; } }
/************************************************************************* Weghted rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9], with constraints and individual weights. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least WEIGHTED root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual weights and constraints. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. XC - points where function values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K<M. K=0 means no constraints (XC/YC/DC are not used in such cases) M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -1 means another errors in parameters passed (N<=0, for example) B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval boundaries. Note that consustency of the constraints on the function DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines which are more flexible). * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormannwc(ref double[] x, ref double[] y, ref double[] w, int n, ref double[] xc, ref double[] yc, ref int[] dc, int k, int m, ref int info, ref barycentricinterpolant b, ref barycentricfitreport rep) { int d = 0; int i = 0; double wrmscur = 0; double wrmsbest = 0; barycentricinterpolant locb = new barycentricinterpolant(); barycentricfitreport locrep = new barycentricfitreport(); int locinfo = 0; if( n<1 | m<2 | k<0 | k>=m ) { info = -1; return; } // // Find optimal D // // Info is -3 by default (degenerate constraints). // If LocInfo will always be equal to -3, Info will remain equal to -3. // If at least once LocInfo will be -4, Info will be -4. // wrmsbest = AP.Math.MaxRealNumber; rep.dbest = -1; info = -3; for(d=0; d<=Math.Min(9, n-1); d++) { barycentricfitwcfixedd(x, y, ref w, n, xc, yc, ref dc, k, m, d, ref locinfo, ref locb, ref locrep); System.Diagnostics.Debug.Assert(locinfo==-4 | locinfo==-3 | locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!"); if( locinfo>0 ) { // // Calculate weghted RMS // wrmscur = 0; for(i=0; i<=n-1; i++) { wrmscur = wrmscur+AP.Math.Sqr(w[i]*(y[i]-barycentriccalc(ref locb, x[i]))); } wrmscur = Math.Sqrt(wrmscur/n); if( (double)(wrmscur)<(double)(wrmsbest) | rep.dbest<0 ) { barycentriccopy(ref locb, ref b); rep.dbest = d; info = 1; rep.rmserror = locrep.rmserror; rep.avgerror = locrep.avgerror; rep.avgrelerror = locrep.avgrelerror; rep.maxerror = locrep.maxerror; rep.taskrcond = locrep.taskrcond; wrmsbest = wrmscur; } } else { if( locinfo!=-3 & info<0 ) { info = locinfo; } } } }
/************************************************************************* Rational least squares fitting, without weights and constraints. See BarycentricFitFloaterHormannWC() for more information. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ public static void barycentricfitfloaterhormann(ref double[] x, ref double[] y, int n, int m, ref int info, ref barycentricinterpolant b, ref barycentricfitreport rep) { double[] w = new double[0]; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; int i = 0; if( n<1 ) { info = -1; return; } w = new double[n]; for(i=0; i<=n-1; i++) { w[i] = 1; } barycentricfitfloaterhormannwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 0, m, ref info, ref b, ref rep); }