/************************************************************************* * Least squares fitting by polynomial. * * This subroutine is "lightweight" alternative for more complex and feature- * rich PolynomialFitWC(). See PolynomialFitWC() for more information about * subroutine parameters (we don't duplicate it here because of length) * * -- ALGLIB PROJECT -- * Copyright 12.10.2009 by Bochkanov Sergey *************************************************************************/ public static void polynomialfit(ref double[] x, ref double[] y, int n, int m, ref int info, ref ratint.barycentricinterpolant p, ref polynomialfitreport rep) { int i = 0; double[] w = new double[0]; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; if (n > 0) { w = new double[n]; for (i = 0; i <= n - 1; i++) { w[i] = 1; } } polynomialfitwc(x, y, ref w, n, xc, yc, ref dc, 0, m, ref info, ref p, ref rep); }
private static void brcunset(ref ratint.barycentricinterpolant b) { double[] x = new double[0]; double[] y = new double[0]; double[] w = new double[0]; x = new double[1]; y = new double[1]; w = new double[1]; x[0] = 0; y[0] = 0; w[0] = 1; ratint.barycentricbuildxyw(ref x, ref y, ref w, 1, ref b); }
/************************************************************************* * Lagrange intepolant on Chebyshev grid (second kind). * This function has O(N) complexity. * * INPUT PARAMETERS: * A - left boundary of [A,B] * B - right boundary of [A,B] * Y - function values at the nodes, array[0..N-1], * Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) * N - number of points, N>=1 * for N=1 a constant model is constructed. * * OIYTPUT PARAMETERS * P - barycentric model which represents Lagrange interpolant * (see ratint unit info and BarycentricCalc() description for * more information). * * -- ALGLIB -- * Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ public static void polynomialbuildcheb2(double a, double b, ref double[] y, int n, ref ratint.barycentricinterpolant p) { int i = 0; double[] w = new double[0]; double[] x = new double[0]; double v = 0; System.Diagnostics.Debug.Assert(n > 0, "PolIntBuildCheb2: N<=0!"); // // Special case: N=1 // if (n == 1) { x = new double[1]; w = new double[1]; x[0] = 0.5 * (b + a); w[0] = 1; ratint.barycentricbuildxyw(ref x, ref y, ref w, 1, ref p); return; } // // general case // x = new double[n]; w = new double[n]; v = 1; for (i = 0; i <= n - 1; i++) { if (i == 0 | i == n - 1) { w[i] = v * 0.5; } else { w[i] = v; } x[i] = 0.5 * (b + a) + 0.5 * (b - a) * Math.Cos(Math.PI * i / (n - 1)); v = -v; } ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p); }
/************************************************************************* * Lagrange intepolant on Chebyshev grid (first kind). * This function has O(N) complexity. * * INPUT PARAMETERS: * A - left boundary of [A,B] * B - right boundary of [A,B] * Y - function values at the nodes, array[0..N-1], * Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) * N - number of points, N>=1 * for N=1 a constant model is constructed. * * OIYTPUT PARAMETERS * P - barycentric model which represents Lagrange interpolant * (see ratint unit info and BarycentricCalc() description for * more information). * * -- ALGLIB -- * Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ public static void polynomialbuildcheb1(double a, double b, ref double[] y, int n, ref ratint.barycentricinterpolant p) { int i = 0; double[] w = new double[0]; double[] x = new double[0]; double v = 0; double t = 0; System.Diagnostics.Debug.Assert(n > 0, "PolIntBuildCheb1: N<=0!"); // // Special case: N=1 // if (n == 1) { x = new double[1]; w = new double[1]; x[0] = 0.5 * (b + a); w[0] = 1; ratint.barycentricbuildxyw(ref x, ref y, ref w, 1, ref p); return; } // // general case // x = new double[n]; w = new double[n]; v = 1; for (i = 0; i <= n - 1; i++) { t = Math.Tan(0.5 * Math.PI * (2 * i + 1) / (2 * n)); w[i] = 2 * v * t / (1 + AP.Math.Sqr(t)); x[i] = 0.5 * (b + a) + 0.5 * (b - a) * (1 - AP.Math.Sqr(t)) / (1 + AP.Math.Sqr(t)); v = -v; } ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p); }
/************************************************************************* * Lagrange intepolant: generation of the model on equidistant grid. * This function has O(N) complexity. * * INPUT PARAMETERS: * A - left boundary of [A,B] * B - right boundary of [A,B] * Y - function values at the nodes, array[0..N-1] * N - number of points, N>=1 * for N=1 a constant model is constructed. * * OIYTPUT PARAMETERS * P - barycentric model which represents Lagrange interpolant * (see ratint unit info and BarycentricCalc() description for * more information). * * -- ALGLIB -- * Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ public static void polynomialbuildeqdist(double a, double b, ref double[] y, int n, ref ratint.barycentricinterpolant p) { int i = 0; double[] w = new double[0]; double[] x = new double[0]; double v = 0; System.Diagnostics.Debug.Assert(n > 0, "PolIntBuildEqDist: N<=0!"); // // Special case: N=1 // if (n == 1) { x = new double[1]; w = new double[1]; x[0] = 0.5 * (b + a); w[0] = 1; ratint.barycentricbuildxyw(ref x, ref y, ref w, 1, ref p); return; } // // general case // x = new double[n]; w = new double[n]; v = 1; for (i = 0; i <= n - 1; i++) { w[i] = v; x[i] = a + (b - a) * i / (n - 1); v = -(v * (n - 1 - i)); v = v / (i + 1); } ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p); }
public static bool testri(bool silent) { bool result = new bool(); bool waserrors = new bool(); bool bcerrors = new bool(); bool nperrors = new bool(); bool fiterrors = new bool(); double threshold = 0; double lipschitztol = 0; int maxn = 0; int passcount = 0; ratint.barycentricinterpolant b1 = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant b2 = new ratint.barycentricinterpolant(); double[] x = new double[0]; double[] x2 = new double[0]; double[] y = new double[0]; double[] y2 = new double[0]; double[] w = new double[0]; double[] w2 = new double[0]; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; double h = 0; double s1 = 0; double s2 = 0; bool bsame = new bool(); int n = 0; int m = 0; int n2 = 0; int i = 0; int j = 0; int k = 0; int d = 0; int pass = 0; double err = 0; double maxerr = 0; double t = 0; double a = 0; double b = 0; double s = 0; double v = 0; double v0 = 0; double v1 = 0; double v2 = 0; double v3 = 0; double d0 = 0; double d1 = 0; double d2 = 0; int info = 0; int info2 = 0; double xmin = 0; double xmax = 0; double refrms = 0; double refavg = 0; double refavgrel = 0; double refmax = 0; double[] ra = new double[0]; double[] ra2 = new double[0]; int ralen = 0; ratint.barycentricfitreport rep = new ratint.barycentricfitreport(); ratint.barycentricfitreport rep2 = new ratint.barycentricfitreport(); ratint.barycentricinterpolant b3 = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant b4 = new ratint.barycentricinterpolant(); int i_ = 0; nperrors = false; bcerrors = false; fiterrors = false; waserrors = false; // // PassCount number of repeated passes // Threshold error tolerance // LipschitzTol Lipschitz constant increase allowed // when calculating constant on a twice denser grid // passcount = 5; maxn = 15; threshold = 1000000*AP.Math.MachineEpsilon; lipschitztol = 1.3; // // Basic barycentric functions // for(n=1; n<=10; n++) { // // randomized tests // for(pass=1; pass<=passcount; pass++) { // // generate weights from polynomial interpolation // v0 = 1+0.4*AP.Math.RandomReal()-0.2; v1 = 2*AP.Math.RandomReal()-1; v2 = 2*AP.Math.RandomReal()-1; v3 = 2*AP.Math.RandomReal()-1; x = new double[n]; y = new double[n]; w = new double[n]; for(i=0; i<=n-1; i++) { if( n==1 ) { x[i] = 0; } else { x[i] = v0*Math.Cos(i*Math.PI/(n-1)); } y[i] = Math.Sin(v1*x[i])+Math.Cos(v2*x[i])+Math.Exp(v3*x[i]); } for(j=0; j<=n-1; j++) { w[j] = 1; for(k=0; k<=n-1; k++) { if( k!=j ) { w[j] = w[j]/(x[j]-x[k]); } } } ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref b1); // // unpack, then pack again and compare // brcunset(ref b2); ratint.barycentricunpack(ref b1, ref n2, ref x2, ref y2, ref w2); bcerrors = bcerrors | n2!=n; ratint.barycentricbuildxyw(ref x2, ref y2, ref w2, n2, ref b2); t = 2*AP.Math.RandomReal()-1; bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t)-ratint.barycentriccalc(ref b2, t)))>(double)(threshold); // // serialize, unserialize, compare // brcunset(ref b2); ratint.barycentricserialize(ref b1, ref ra, ref ralen); ra2 = new double[ralen]; for(i_=0; i_<=ralen-1;i_++) { ra2[i_] = ra[i_]; } ratint.barycentricunserialize(ref ra2, ref b2); t = 2*AP.Math.RandomReal()-1; bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t)-ratint.barycentriccalc(ref b2, t)))>(double)(threshold); // // copy, compare // brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); t = 2*AP.Math.RandomReal()-1; bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t)-ratint.barycentriccalc(ref b2, t)))>(double)(threshold); // // test interpolation properties // for(i=0; i<=n-1; i++) { // // test interpolation at nodes // bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, x[i])-y[i]))>(double)(threshold*Math.Abs(y[i])); // // compare with polynomial interpolation // t = 2*AP.Math.RandomReal()-1; poldiff2(ref x, y, n, t, ref v0, ref v1, ref v2); bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t)-v0))>(double)(threshold*Math.Max(Math.Abs(v0), 1)); // // test continuity between nodes // calculate Lipschitz constant on two grids - // dense and even more dense. If Lipschitz constant // on a denser grid is significantly increased, // continuity test is failed // t = 3.0; k = 100; s1 = 0; for(j=0; j<=k-1; j++) { v1 = x[i]+(t-x[i])*j/k; v2 = x[i]+(t-x[i])*(j+1)/k; s1 = Math.Max(s1, Math.Abs(ratint.barycentriccalc(ref b1, v2)-ratint.barycentriccalc(ref b1, v1))/Math.Abs(v2-v1)); } k = 2*k; s2 = 0; for(j=0; j<=k-1; j++) { v1 = x[i]+(t-x[i])*j/k; v2 = x[i]+(t-x[i])*(j+1)/k; s2 = Math.Max(s2, Math.Abs(ratint.barycentriccalc(ref b1, v2)-ratint.barycentriccalc(ref b1, v1))/Math.Abs(v2-v1)); } bcerrors = bcerrors | (double)(s2)>(double)(lipschitztol*s1) & (double)(s1)>(double)(threshold*k); } // // test differentiation properties // for(i=0; i<=n-1; i++) { t = 2*AP.Math.RandomReal()-1; poldiff2(ref x, y, n, t, ref v0, ref v1, ref v2); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff1(ref b1, t, ref d0, ref d1); bcerrors = bcerrors | (double)(Math.Abs(v0-d0))>(double)(threshold*Math.Max(Math.Abs(v0), 1)); bcerrors = bcerrors | (double)(Math.Abs(v1-d1))>(double)(threshold*Math.Max(Math.Abs(v1), 1)); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff2(ref b1, t, ref d0, ref d1, ref d2); bcerrors = bcerrors | (double)(Math.Abs(v0-d0))>(double)(threshold*Math.Max(Math.Abs(v0), 1)); bcerrors = bcerrors | (double)(Math.Abs(v1-d1))>(double)(threshold*Math.Max(Math.Abs(v1), 1)); bcerrors = bcerrors | (double)(Math.Abs(v2-d2))>(double)(Math.Sqrt(threshold)*Math.Max(Math.Abs(v2), 1)); } // // test linear translation // t = 2*AP.Math.RandomReal()-1; a = 2*AP.Math.RandomReal()-1; b = 2*AP.Math.RandomReal()-1; brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); ratint.barycentriclintransx(ref b2, a, b); bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, a*t+b)-ratint.barycentriccalc(ref b2, t)))>(double)(threshold); a = 0; b = 2*AP.Math.RandomReal()-1; brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); ratint.barycentriclintransx(ref b2, a, b); bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, a*t+b)-ratint.barycentriccalc(ref b2, t)))>(double)(threshold); a = 2*AP.Math.RandomReal()-1; b = 2*AP.Math.RandomReal()-1; brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); ratint.barycentriclintransy(ref b2, a, b); bcerrors = bcerrors | (double)(Math.Abs(a*ratint.barycentriccalc(ref b1, t)+b-ratint.barycentriccalc(ref b2, t)))>(double)(threshold); } } for(pass=0; pass<=3; pass++) { // // Crash-test: small numbers, large numbers // x = new double[4]; y = new double[4]; w = new double[4]; h = 1; if( pass%2==0 ) { h = 100*AP.Math.MinRealNumber; } if( pass%2==1 ) { h = 0.01*AP.Math.MaxRealNumber; } x[0] = 0*h; x[1] = 1*h; x[2] = 2*h; x[3] = 3*h; y[0] = 0*h; y[1] = 1*h; y[2] = 2*h; y[3] = 3*h; w[0] = -(1/(x[1]-x[0])); w[1] = +(1*(1/(x[1]-x[0])+1/(x[2]-x[1]))); w[2] = -(1*(1/(x[2]-x[1])+1/(x[3]-x[2]))); w[3] = +(1/(x[3]-x[2])); if( pass/2==0 ) { v0 = 0; } if( pass/2==1 ) { v0 = 0.6*h; } ratint.barycentricbuildxyw(ref x, ref y, ref w, 4, ref b1); t = ratint.barycentriccalc(ref b1, v0); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff1(ref b1, v0, ref d0, ref d1); bcerrors = bcerrors | (double)(Math.Abs(t-v0))>(double)(threshold*v0); bcerrors = bcerrors | (double)(Math.Abs(d0-v0))>(double)(threshold*v0); bcerrors = bcerrors | (double)(Math.Abs(d1-1))>(double)(1000*threshold); } // // crash test: large abscissas, small argument // // test for errors in D0 is not very strict // because renormalization used in Diff1() // destroys part of precision. // x = new double[4]; y = new double[4]; w = new double[4]; h = 0.01*AP.Math.MaxRealNumber; x[0] = 0*h; x[1] = 1*h; x[2] = 2*h; x[3] = 3*h; y[0] = 0*h; y[1] = 1*h; y[2] = 2*h; y[3] = 3*h; w[0] = -(1/(x[1]-x[0])); w[1] = +(1*(1/(x[1]-x[0])+1/(x[2]-x[1]))); w[2] = -(1*(1/(x[2]-x[1])+1/(x[3]-x[2]))); w[3] = +(1/(x[3]-x[2])); v0 = 100*AP.Math.MinRealNumber; ratint.barycentricbuildxyw(ref x, ref y, ref w, 4, ref b1); t = ratint.barycentriccalc(ref b1, v0); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff1(ref b1, v0, ref d0, ref d1); bcerrors = bcerrors | (double)(Math.Abs(t))>(double)(v0*(1+threshold)); bcerrors = bcerrors | (double)(Math.Abs(d0))>(double)(v0*(1+threshold)); bcerrors = bcerrors | (double)(Math.Abs(d1-1))>(double)(1000*threshold); // // crash test: test safe barycentric formula // x = new double[4]; y = new double[4]; w = new double[4]; h = 2*AP.Math.MinRealNumber; x[0] = 0*h; x[1] = 1*h; x[2] = 2*h; x[3] = 3*h; y[0] = 0*h; y[1] = 1*h; y[2] = 2*h; y[3] = 3*h; w[0] = -(1/(x[1]-x[0])); w[1] = +(1*(1/(x[1]-x[0])+1/(x[2]-x[1]))); w[2] = -(1*(1/(x[2]-x[1])+1/(x[3]-x[2]))); w[3] = +(1/(x[3]-x[2])); v0 = AP.Math.MinRealNumber; ratint.barycentricbuildxyw(ref x, ref y, ref w, 4, ref b1); t = ratint.barycentriccalc(ref b1, v0); bcerrors = bcerrors | (double)(Math.Abs(t-v0)/v0)>(double)(threshold); // // Testing "No Poles" interpolation // maxerr = 0; for(pass=1; pass<=passcount-1; pass++) { x = new double[1]; y = new double[1]; x[0] = 2*AP.Math.RandomReal()-1; y[0] = 2*AP.Math.RandomReal()-1; ratint.barycentricbuildfloaterhormann(ref x, ref y, 1, 1, ref b1); maxerr = Math.Max(maxerr, Math.Abs(ratint.barycentriccalc(ref b1, 2*AP.Math.RandomReal()-1)-y[0])); } for(n=2; n<=10; n++) { // // compare interpolant built by subroutine // with interpolant built by hands // x = new double[n]; y = new double[n]; w = new double[n]; w2 = new double[n]; // // D=1, non-equidistant nodes // for(pass=1; pass<=passcount; pass++) { // // Initialize X, Y, W // a = -1-1*AP.Math.RandomReal(); b = +1+1*AP.Math.RandomReal(); for(i=0; i<=n-1; i++) { x[i] = Math.Atan((b-a)*i/(n-1)+a); } for(i=0; i<=n-1; i++) { y[i] = 2*AP.Math.RandomReal()-1; } w[0] = -(1/(x[1]-x[0])); s = 1; for(i=1; i<=n-2; i++) { w[i] = s*(1/(x[i]-x[i-1])+1/(x[i+1]-x[i])); s = -s; } w[n-1] = s/(x[n-1]-x[n-2]); for(i=0; i<=n-1; i++) { k = AP.Math.RandomInteger(n); if( k!=i ) { t = x[i]; x[i] = x[k]; x[k] = t; t = y[i]; y[i] = y[k]; y[k] = t; t = w[i]; w[i] = w[k]; w[k] = t; } } // // Build and test // ratint.barycentricbuildfloaterhormann(ref x, ref y, n, 1, ref b1); ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref b2); for(i=1; i<=2*n; i++) { t = a+(b-a)*AP.Math.RandomReal(); maxerr = Math.Max(maxerr, Math.Abs(ratint.barycentriccalc(ref b1, t)-ratint.barycentriccalc(ref b2, t))); } } // // D = 0, 1, 2. Equidistant nodes. // for(d=0; d<=2; d++) { for(pass=1; pass<=passcount; pass++) { // // Skip incorrect (N,D) pairs // if( n<2*d ) { continue; } // // Initialize X, Y, W // a = -1-1*AP.Math.RandomReal(); b = +1+1*AP.Math.RandomReal(); for(i=0; i<=n-1; i++) { x[i] = (b-a)*i/(n-1)+a; } for(i=0; i<=n-1; i++) { y[i] = 2*AP.Math.RandomReal()-1; } s = 1; if( d==0 ) { for(i=0; i<=n-1; i++) { w[i] = s; s = -s; } } if( d==1 ) { w[0] = -s; for(i=1; i<=n-2; i++) { w[i] = 2*s; s = -s; } w[n-1] = s; } if( d==2 ) { w[0] = s; w[1] = -(3*s); for(i=2; i<=n-3; i++) { w[i] = 4*s; s = -s; } w[n-2] = 3*s; w[n-1] = -s; } // // Mix // for(i=0; i<=n-1; i++) { k = AP.Math.RandomInteger(n); if( k!=i ) { t = x[i]; x[i] = x[k]; x[k] = t; t = y[i]; y[i] = y[k]; y[k] = t; t = w[i]; w[i] = w[k]; w[k] = t; } } // // Build and test // ratint.barycentricbuildfloaterhormann(ref x, ref y, n, d, ref b1); ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref b2); for(i=1; i<=2*n; i++) { t = a+(b-a)*AP.Math.RandomReal(); maxerr = Math.Max(maxerr, Math.Abs(ratint.barycentriccalc(ref b1, t)-ratint.barycentriccalc(ref b2, t))); } } } } if( (double)(maxerr)>(double)(threshold) ) { nperrors = true; } // // Test rational fitting: // for(pass=1; pass<=passcount; pass++) { for(n=2; n<=maxn; n++) { // // N=M+K fitting (i.e. interpolation) // for(k=0; k<=n-1; k++) { x = new double[n-k]; y = new double[n-k]; w = new double[n-k]; if( k>0 ) { xc = new double[k]; yc = new double[k]; dc = new int[k]; } for(i=0; i<=n-k-1; i++) { x[i] = (double)(i)/((double)(n-1)); y[i] = 2*AP.Math.RandomReal()-1; w[i] = 1+AP.Math.RandomReal(); } for(i=0; i<=k-1; i++) { xc[i] = ((double)(n-k+i))/((double)(n-1)); yc[i] = 2*AP.Math.RandomReal()-1; dc[i] = 0; } ratint.barycentricfitfloaterhormannwc(ref x, ref y, ref w, n-k, ref xc, ref yc, ref dc, k, n, ref info, ref b1, ref rep); if( info<=0 ) { fiterrors = true; } else { for(i=0; i<=n-k-1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, x[i])-y[i]))>(double)(threshold); } for(i=0; i<=k-1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, xc[i])-yc[i]))>(double)(threshold); } } } // // Testing constraints on derivatives: // * several M's are tried // * several K's are tried - 1, 2. // * constraints at the ends of the interval // for(m=3; m<=5; m++) { for(k=1; k<=2; k++) { x = new double[n]; y = new double[n]; w = new double[n]; xc = new double[2]; yc = new double[2]; dc = new int[2]; for(i=0; i<=n-1; i++) { x[i] = 2*AP.Math.RandomReal()-1; y[i] = 2*AP.Math.RandomReal()-1; w[i] = 1+AP.Math.RandomReal(); } xc[0] = -1; yc[0] = 2*AP.Math.RandomReal()-1; dc[0] = 0; xc[1] = +1; yc[1] = 2*AP.Math.RandomReal()-1; dc[1] = 0; ratint.barycentricfitfloaterhormannwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, k, m, ref info, ref b1, ref rep); if( info<=0 ) { fiterrors = true; } else { for(i=0; i<=k-1; i++) { ratint.barycentricdiff1(ref b1, xc[i], ref v0, ref v1); fiterrors = fiterrors | (double)(Math.Abs(v0-yc[i]))>(double)(threshold); } } } } } } for(m=2; m<=8; m++) { for(pass=1; pass<=passcount; pass++) { // // General fitting // // interpolating function through M nodes should have // greater RMS error than fitting it through the same M nodes // n = 100; x2 = new double[n]; y2 = new double[n]; w2 = new double[n]; xmin = AP.Math.MaxRealNumber; xmax = -AP.Math.MaxRealNumber; for(i=0; i<=n-1; i++) { x2[i] = 2*Math.PI*AP.Math.RandomReal(); y2[i] = Math.Sin(x2[i]); w2[i] = 1; xmin = Math.Min(xmin, x2[i]); xmax = Math.Max(xmax, x2[i]); } x = new double[m]; y = new double[m]; for(i=0; i<=m-1; i++) { x[i] = xmin+(xmax-xmin)*i/(m-1); y[i] = Math.Sin(x[i]); } ratint.barycentricbuildfloaterhormann(ref x, ref y, m, 3, ref b1); ratint.barycentricfitfloaterhormannwc(ref x2, ref y2, ref w2, n, ref xc, ref yc, ref dc, 0, m, ref info, ref b2, ref rep); if( info<=0 ) { fiterrors = true; } else { // // calculate B1 (interpolant) RMS error, compare with B2 error // v1 = 0; v2 = 0; for(i=0; i<=n-1; i++) { v1 = v1+AP.Math.Sqr(ratint.barycentriccalc(ref b1, x2[i])-y2[i]); v2 = v2+AP.Math.Sqr(ratint.barycentriccalc(ref b2, x2[i])-y2[i]); } v1 = Math.Sqrt(v1/n); v2 = Math.Sqrt(v2/n); fiterrors = fiterrors | (double)(v2)>(double)(v1); fiterrors = fiterrors | (double)(Math.Abs(v2-rep.rmserror))>(double)(threshold); } // // compare weighted and non-weighted // n = 20; x = new double[n]; y = new double[n]; w = new double[n]; for(i=0; i<=n-1; i++) { x[i] = 2*AP.Math.RandomReal()-1; y[i] = 2*AP.Math.RandomReal()-1; w[i] = 1; } ratint.barycentricfitfloaterhormannwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 0, m, ref info, ref b1, ref rep); ratint.barycentricfitfloaterhormann(ref x, ref y, n, m, ref info2, ref b2, ref rep2); if( info<=0 | info2<=0 ) { fiterrors = true; } else { // // calculate B1 (interpolant), compare with B2 // compare RMS errors // t = 2*AP.Math.RandomReal()-1; v1 = ratint.barycentriccalc(ref b1, t); v2 = ratint.barycentriccalc(ref b2, t); fiterrors = fiterrors | (double)(v2)!=(double)(v1); fiterrors = fiterrors | (double)(rep.rmserror)!=(double)(rep2.rmserror); fiterrors = fiterrors | (double)(rep.avgerror)!=(double)(rep2.avgerror); fiterrors = fiterrors | (double)(rep.avgrelerror)!=(double)(rep2.avgrelerror); fiterrors = fiterrors | (double)(rep.maxerror)!=(double)(rep2.maxerror); } } } for(pass=1; pass<=passcount; pass++) { System.Diagnostics.Debug.Assert(passcount>=2, "PassCount should be 2 or greater!"); // // solve simple task (all X[] are the same, Y[] are specially // calculated to ensure simple form of all types of errors) // and check correctness of the errors calculated by subroutines // // First pass is done with zero Y[], other passes - with random Y[]. // It should test both ability to correctly calculate errors and // ability to not fail while working with zeros :) // n = 4; if( pass==1 ) { v1 = 0; v2 = 0; v = 0; } else { v1 = AP.Math.RandomReal(); v2 = AP.Math.RandomReal(); v = 1+AP.Math.RandomReal(); } x = new double[4]; y = new double[4]; w = new double[4]; x[0] = 0; y[0] = v-v2; w[0] = 1; x[1] = 0; y[1] = v-v1; w[1] = 1; x[2] = 0; y[2] = v+v1; w[2] = 1; x[3] = 0; y[3] = v+v2; w[3] = 1; refrms = Math.Sqrt((AP.Math.Sqr(v1)+AP.Math.Sqr(v2))/2); refavg = (Math.Abs(v1)+Math.Abs(v2))/2; if( pass==1 ) { refavgrel = 0; } else { refavgrel = 0.25*(Math.Abs(v2)/Math.Abs(v-v2)+Math.Abs(v1)/Math.Abs(v-v1)+Math.Abs(v1)/Math.Abs(v+v1)+Math.Abs(v2)/Math.Abs(v+v2)); } refmax = Math.Max(v1, v2); // // Test errors correctness // ratint.barycentricfitfloaterhormann(ref x, ref y, 4, 2, ref info, ref b1, ref rep); if( info<=0 ) { fiterrors = true; } else { s = ratint.barycentriccalc(ref b1, 0); fiterrors = fiterrors | (double)(Math.Abs(s-v))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.rmserror-refrms))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgerror-refavg))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgrelerror-refavgrel))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.maxerror-refmax))>(double)(threshold); } } // // report // waserrors = bcerrors | nperrors | fiterrors; if( !silent ) { System.Console.Write("TESTING RATIONAL INTERPOLATION"); System.Console.WriteLine(); System.Console.Write("BASIC BARYCENTRIC FUNCTIONS: "); if( bcerrors ) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } System.Console.Write("FLOATER-HORMANN: "); if( nperrors ) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } System.Console.Write("RATIONAL FITTING: "); if( fiterrors ) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } if( waserrors ) { System.Console.Write("TEST FAILED"); System.Console.WriteLine(); } else { System.Console.Write("TEST PASSED"); System.Console.WriteLine(); } System.Console.WriteLine(); System.Console.WriteLine(); } // // end // result = !waserrors; return result; }
/************************************************************************* * Lagrange intepolant: generation of the model on the general grid. * This function has O(N^2) complexity. * * INPUT PARAMETERS: * X - abscissas, array[0..N-1] * Y - function values, array[0..N-1] * N - number of points, N>=1 * * OIYTPUT PARAMETERS * P - barycentric model which represents Lagrange interpolant * (see ratint unit info and BarycentricCalc() description for * more information). * * -- ALGLIB -- * Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ public static void polynomialbuild(ref double[] x, ref double[] y, int n, ref ratint.barycentricinterpolant p) { int j = 0; int k = 0; double[] w = new double[0]; double b = 0; double a = 0; double v = 0; double mx = 0; int i_ = 0; System.Diagnostics.Debug.Assert(n > 0, "PolIntBuild: N<=0!"); // // calculate W[j] // multi-pass algorithm is used to avoid overflow // w = new double[n]; a = x[0]; b = x[0]; for (j = 0; j <= n - 1; j++) { w[j] = 1; a = Math.Min(a, x[j]); b = Math.Max(b, x[j]); } for (k = 0; k <= n - 1; k++) { // // W[K] is used instead of 0.0 because // cycle on J does not touch K-th element // and we MUST get maximum from ALL elements // mx = Math.Abs(w[k]); for (j = 0; j <= n - 1; j++) { if (j != k) { v = (b - a) / (x[j] - x[k]); w[j] = w[j] * v; mx = Math.Max(mx, Math.Abs(w[j])); } } if (k % 5 == 0) { // // every 5-th run we renormalize W[] // v = 1 / mx; for (i_ = 0; i_ <= n - 1; i_++) { w[i_] = v * w[i_]; } } } ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p); }
/************************************************************************* Unit test *************************************************************************/ public static bool testpolint(bool silent) { bool result = new bool(); bool waserrors = new bool(); bool interrors = new bool(); bool fiterrors = new bool(); double threshold = 0; double[] x = new double[0]; double[] y = new double[0]; double[] w = new double[0]; double[] x2 = new double[0]; double[] y2 = new double[0]; double[] w2 = new double[0]; double[] xfull = new double[0]; double[] yfull = new double[0]; double a = 0; double b = 0; double t = 0; int i = 0; int k = 0; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; int info = 0; int info2 = 0; double v = 0; double v0 = 0; double v1 = 0; double v2 = 0; double s = 0; double xmin = 0; double xmax = 0; double refrms = 0; double refavg = 0; double refavgrel = 0; double refmax = 0; ratint.barycentricinterpolant p = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant p1 = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant p2 = new ratint.barycentricinterpolant(); polint.polynomialfitreport rep = new polint.polynomialfitreport(); polint.polynomialfitreport rep2 = new polint.polynomialfitreport(); int n = 0; int m = 0; int maxn = 0; int pass = 0; int passcount = 0; waserrors = false; interrors = false; fiterrors = false; maxn = 5; passcount = 20; threshold = 1.0E8*AP.Math.MachineEpsilon; // // Test equidistant interpolation // for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { // // prepare task: // * equidistant points // * random Y // * T in [A,B] or near (within 10% of its width) // do { a = 2*AP.Math.RandomReal()-1; b = 2*AP.Math.RandomReal()-1; } while( (double)(Math.Abs(a-b))<=(double)(0.2) ); t = a+(1.2*AP.Math.RandomReal()-0.1)*(b-a); apserv.taskgenint1dequidist(a, b, n, ref x, ref y); // // test "fast" equidistant interpolation (no barycentric model) // interrors = interrors | (double)(Math.Abs(polint.polynomialcalceqdist(a, b, ref y, n, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); // // test "slow" equidistant interpolation (create barycentric model) // brcunset(ref p); polint.polynomialbuild(ref x, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); // // test "fast" interpolation (create "fast" barycentric model) // brcunset(ref p); polint.polynomialbuildeqdist(a, b, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); } } // // Test Chebyshev-1 interpolation // for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { // // prepare task: // * equidistant points // * random Y // * T in [A,B] or near (within 10% of its width) // do { a = 2*AP.Math.RandomReal()-1; b = 2*AP.Math.RandomReal()-1; } while( (double)(Math.Abs(a-b))<=(double)(0.2) ); t = a+(1.2*AP.Math.RandomReal()-0.1)*(b-a); apserv.taskgenint1dcheb1(a, b, n, ref x, ref y); // // test "fast" interpolation (no barycentric model) // interrors = interrors | (double)(Math.Abs(polint.polynomialcalccheb1(a, b, ref y, n, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); // // test "slow" interpolation (create barycentric model) // brcunset(ref p); polint.polynomialbuild(ref x, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); // // test "fast" interpolation (create "fast" barycentric model) // brcunset(ref p); polint.polynomialbuildcheb1(a, b, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); } } // // Test Chebyshev-2 interpolation // for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { // // prepare task: // * equidistant points // * random Y // * T in [A,B] or near (within 10% of its width) // do { a = 2*AP.Math.RandomReal()-1; b = 2*AP.Math.RandomReal()-1; } while( (double)(Math.Abs(a-b))<=(double)(0.2) ); t = a+(1.2*AP.Math.RandomReal()-0.1)*(b-a); apserv.taskgenint1dcheb2(a, b, n, ref x, ref y); // // test "fast" interpolation (no barycentric model) // interrors = interrors | (double)(Math.Abs(polint.polynomialcalccheb2(a, b, ref y, n, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); // // test "slow" interpolation (create barycentric model) // brcunset(ref p); polint.polynomialbuild(ref x, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); // // test "fast" interpolation (create "fast" barycentric model) // brcunset(ref p); polint.polynomialbuildcheb2(a, b, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t)-internalpolint(ref x, y, n, t)))>(double)(threshold); } } // // crash-test: ability to solve tasks which will overflow/underflow // weights with straightforward implementation // for(n=1; n<=20; n++) { a = -(0.1*AP.Math.MaxRealNumber); b = +(0.1*AP.Math.MaxRealNumber); apserv.taskgenint1dequidist(a, b, n, ref x, ref y); polint.polynomialbuild(ref x, ref y, n, ref p); for(i=0; i<=n-1; i++) { interrors = interrors | (double)(p.w[i])==(double)(0); } } // // Test rational fitting: // for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { // // N=M+K fitting (i.e. interpolation) // for(k=0; k<=n-1; k++) { apserv.taskgenint1d(-1, 1, n, ref xfull, ref yfull); x = new double[n-k]; y = new double[n-k]; w = new double[n-k]; if( k>0 ) { xc = new double[k]; yc = new double[k]; dc = new int[k]; } for(i=0; i<=n-k-1; i++) { x[i] = xfull[i]; y[i] = yfull[i]; w[i] = 1+AP.Math.RandomReal(); } for(i=0; i<=k-1; i++) { xc[i] = xfull[n-k+i]; yc[i] = yfull[n-k+i]; dc[i] = 0; } polint.polynomialfitwc(x, y, ref w, n-k, xc, yc, ref dc, k, n, ref info, ref p1, ref rep); if( info<=0 ) { fiterrors = true; } else { for(i=0; i<=n-k-1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref p1, x[i])-y[i]))>(double)(threshold); } for(i=0; i<=k-1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref p1, xc[i])-yc[i]))>(double)(threshold); } } } // // Testing constraints on derivatives. // Special tasks which will always have solution: // 1. P(0)=YC[0] // 2. P(0)=YC[0], P'(0)=YC[1] // if( n>1 ) { for(m=3; m<=5; m++) { for(k=1; k<=2; k++) { apserv.taskgenint1d(-1, 1, n, ref x, ref y); w = new double[n]; xc = new double[2]; yc = new double[2]; dc = new int[2]; for(i=0; i<=n-1; i++) { w[i] = 1+AP.Math.RandomReal(); } xc[0] = 0; yc[0] = 2*AP.Math.RandomReal()-1; dc[0] = 0; xc[1] = 0; yc[1] = 2*AP.Math.RandomReal()-1; dc[1] = 1; polint.polynomialfitwc(x, y, ref w, n, xc, yc, ref dc, k, m, ref info, ref p1, ref rep); if( info<=0 ) { fiterrors = true; } else { ratint.barycentricdiff1(ref p1, 0.0, ref v0, ref v1); fiterrors = fiterrors | (double)(Math.Abs(v0-yc[0]))>(double)(threshold); if( k==2 ) { fiterrors = fiterrors | (double)(Math.Abs(v1-yc[1]))>(double)(threshold); } } } } } } } for(m=2; m<=8; m++) { for(pass=1; pass<=passcount; pass++) { // // General fitting // // interpolating function through M nodes should have // greater RMS error than fitting it through the same M nodes // n = 100; x2 = new double[n]; y2 = new double[n]; w2 = new double[n]; xmin = 0; xmax = 2*Math.PI; for(i=0; i<=n-1; i++) { x2[i] = 2*Math.PI*AP.Math.RandomReal(); y2[i] = Math.Sin(x2[i]); w2[i] = 1; } x = new double[m]; y = new double[m]; for(i=0; i<=m-1; i++) { x[i] = xmin+(xmax-xmin)*i/(m-1); y[i] = Math.Sin(x[i]); } polint.polynomialbuild(ref x, ref y, m, ref p1); polint.polynomialfitwc(x2, y2, ref w2, n, xc, yc, ref dc, 0, m, ref info, ref p2, ref rep); if( info<=0 ) { fiterrors = true; } else { // // calculate P1 (interpolant) RMS error, compare with P2 error // v1 = 0; v2 = 0; for(i=0; i<=n-1; i++) { v1 = v1+AP.Math.Sqr(ratint.barycentriccalc(ref p1, x2[i])-y2[i]); v2 = v2+AP.Math.Sqr(ratint.barycentriccalc(ref p2, x2[i])-y2[i]); } v1 = Math.Sqrt(v1/n); v2 = Math.Sqrt(v2/n); fiterrors = fiterrors | (double)(v2)>(double)(v1); fiterrors = fiterrors | (double)(Math.Abs(v2-rep.rmserror))>(double)(threshold); } // // compare weighted and non-weighted // n = 20; x = new double[n]; y = new double[n]; w = new double[n]; for(i=0; i<=n-1; i++) { x[i] = 2*AP.Math.RandomReal()-1; y[i] = 2*AP.Math.RandomReal()-1; w[i] = 1; } polint.polynomialfitwc(x, y, ref w, n, xc, yc, ref dc, 0, m, ref info, ref p1, ref rep); polint.polynomialfit(ref x, ref y, n, m, ref info2, ref p2, ref rep2); if( info<=0 | info2<=0 ) { fiterrors = true; } else { // // calculate P1 (interpolant), compare with P2 error // compare RMS errors // t = 2*AP.Math.RandomReal()-1; v1 = ratint.barycentriccalc(ref p1, t); v2 = ratint.barycentriccalc(ref p2, t); fiterrors = fiterrors | (double)(v2)!=(double)(v1); fiterrors = fiterrors | (double)(rep.rmserror)!=(double)(rep2.rmserror); fiterrors = fiterrors | (double)(rep.avgerror)!=(double)(rep2.avgerror); fiterrors = fiterrors | (double)(rep.avgrelerror)!=(double)(rep2.avgrelerror); fiterrors = fiterrors | (double)(rep.maxerror)!=(double)(rep2.maxerror); } } } for(pass=1; pass<=passcount; pass++) { System.Diagnostics.Debug.Assert(passcount>=2, "PassCount should be 2 or greater!"); // // solve simple task (all X[] are the same, Y[] are specially // calculated to ensure simple form of all types of errors) // and check correctness of the errors calculated by subroutines // // First pass is done with zero Y[], other passes - with random Y[]. // It should test both ability to correctly calculate errors and // ability to not fail while working with zeros :) // n = 4; if( pass==1 ) { v1 = 0; v2 = 0; v = 0; } else { v1 = AP.Math.RandomReal(); v2 = AP.Math.RandomReal(); v = 1+AP.Math.RandomReal(); } x = new double[4]; y = new double[4]; w = new double[4]; x[0] = 0; y[0] = v-v2; w[0] = 1; x[1] = 0; y[1] = v-v1; w[1] = 1; x[2] = 0; y[2] = v+v1; w[2] = 1; x[3] = 0; y[3] = v+v2; w[3] = 1; refrms = Math.Sqrt((AP.Math.Sqr(v1)+AP.Math.Sqr(v2))/2); refavg = (Math.Abs(v1)+Math.Abs(v2))/2; if( pass==1 ) { refavgrel = 0; } else { refavgrel = 0.25*(Math.Abs(v2)/Math.Abs(v-v2)+Math.Abs(v1)/Math.Abs(v-v1)+Math.Abs(v1)/Math.Abs(v+v1)+Math.Abs(v2)/Math.Abs(v+v2)); } refmax = Math.Max(v1, v2); // // Test errors correctness // polint.polynomialfit(ref x, ref y, 4, 1, ref info, ref p, ref rep); if( info<=0 ) { fiterrors = true; } else { s = ratint.barycentriccalc(ref p, 0); fiterrors = fiterrors | (double)(Math.Abs(s-v))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.rmserror-refrms))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgerror-refavg))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgrelerror-refavgrel))>(double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.maxerror-refmax))>(double)(threshold); } } // // report // waserrors = interrors | fiterrors; if( !silent ) { System.Console.Write("TESTING POLYNOMIAL INTERPOLATION AND FITTING"); System.Console.WriteLine(); // // Normal tests // System.Console.Write("INTERPOLATION TEST: "); if( interrors ) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } System.Console.Write("FITTING TEST: "); if( fiterrors ) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } if( waserrors ) { System.Console.Write("TEST FAILED"); System.Console.WriteLine(); } else { System.Console.Write("TEST PASSED"); System.Console.WriteLine(); } System.Console.WriteLine(); System.Console.WriteLine(); } // // end // result = !waserrors; return result; }
/************************************************************************* * Unit test *************************************************************************/ public static bool testpolint(bool silent) { bool result = new bool(); bool waserrors = new bool(); bool interrors = new bool(); bool fiterrors = new bool(); double threshold = 0; double[] x = new double[0]; double[] y = new double[0]; double[] w = new double[0]; double[] x2 = new double[0]; double[] y2 = new double[0]; double[] w2 = new double[0]; double[] xfull = new double[0]; double[] yfull = new double[0]; double a = 0; double b = 0; double t = 0; int i = 0; int k = 0; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; int info = 0; int info2 = 0; double v = 0; double v0 = 0; double v1 = 0; double v2 = 0; double s = 0; double xmin = 0; double xmax = 0; double refrms = 0; double refavg = 0; double refavgrel = 0; double refmax = 0; ratint.barycentricinterpolant p = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant p1 = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant p2 = new ratint.barycentricinterpolant(); polint.polynomialfitreport rep = new polint.polynomialfitreport(); polint.polynomialfitreport rep2 = new polint.polynomialfitreport(); int n = 0; int m = 0; int maxn = 0; int pass = 0; int passcount = 0; waserrors = false; interrors = false; fiterrors = false; maxn = 5; passcount = 20; threshold = 1.0E8 * AP.Math.MachineEpsilon; // // Test equidistant interpolation // for (pass = 1; pass <= passcount; pass++) { for (n = 1; n <= maxn; n++) { // // prepare task: // * equidistant points // * random Y // * T in [A,B] or near (within 10% of its width) // do { a = 2 * AP.Math.RandomReal() - 1; b = 2 * AP.Math.RandomReal() - 1; }while((double)(Math.Abs(a - b)) <= (double)(0.2)); t = a + (1.2 * AP.Math.RandomReal() - 0.1) * (b - a); apserv.taskgenint1dequidist(a, b, n, ref x, ref y); // // test "fast" equidistant interpolation (no barycentric model) // interrors = interrors | (double)(Math.Abs(polint.polynomialcalceqdist(a, b, ref y, n, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); // // test "slow" equidistant interpolation (create barycentric model) // brcunset(ref p); polint.polynomialbuild(ref x, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); // // test "fast" interpolation (create "fast" barycentric model) // brcunset(ref p); polint.polynomialbuildeqdist(a, b, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); } } // // Test Chebyshev-1 interpolation // for (pass = 1; pass <= passcount; pass++) { for (n = 1; n <= maxn; n++) { // // prepare task: // * equidistant points // * random Y // * T in [A,B] or near (within 10% of its width) // do { a = 2 * AP.Math.RandomReal() - 1; b = 2 * AP.Math.RandomReal() - 1; }while((double)(Math.Abs(a - b)) <= (double)(0.2)); t = a + (1.2 * AP.Math.RandomReal() - 0.1) * (b - a); apserv.taskgenint1dcheb1(a, b, n, ref x, ref y); // // test "fast" interpolation (no barycentric model) // interrors = interrors | (double)(Math.Abs(polint.polynomialcalccheb1(a, b, ref y, n, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); // // test "slow" interpolation (create barycentric model) // brcunset(ref p); polint.polynomialbuild(ref x, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); // // test "fast" interpolation (create "fast" barycentric model) // brcunset(ref p); polint.polynomialbuildcheb1(a, b, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); } } // // Test Chebyshev-2 interpolation // for (pass = 1; pass <= passcount; pass++) { for (n = 1; n <= maxn; n++) { // // prepare task: // * equidistant points // * random Y // * T in [A,B] or near (within 10% of its width) // do { a = 2 * AP.Math.RandomReal() - 1; b = 2 * AP.Math.RandomReal() - 1; }while((double)(Math.Abs(a - b)) <= (double)(0.2)); t = a + (1.2 * AP.Math.RandomReal() - 0.1) * (b - a); apserv.taskgenint1dcheb2(a, b, n, ref x, ref y); // // test "fast" interpolation (no barycentric model) // interrors = interrors | (double)(Math.Abs(polint.polynomialcalccheb2(a, b, ref y, n, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); // // test "slow" interpolation (create barycentric model) // brcunset(ref p); polint.polynomialbuild(ref x, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); // // test "fast" interpolation (create "fast" barycentric model) // brcunset(ref p); polint.polynomialbuildcheb2(a, b, ref y, n, ref p); interrors = interrors | (double)(Math.Abs(ratint.barycentriccalc(ref p, t) - internalpolint(ref x, y, n, t))) > (double)(threshold); } } // // crash-test: ability to solve tasks which will overflow/underflow // weights with straightforward implementation // for (n = 1; n <= 20; n++) { a = -(0.1 * AP.Math.MaxRealNumber); b = +(0.1 * AP.Math.MaxRealNumber); apserv.taskgenint1dequidist(a, b, n, ref x, ref y); polint.polynomialbuild(ref x, ref y, n, ref p); for (i = 0; i <= n - 1; i++) { interrors = interrors | (double)(p.w[i]) == (double)(0); } } // // Test rational fitting: // for (pass = 1; pass <= passcount; pass++) { for (n = 1; n <= maxn; n++) { // // N=M+K fitting (i.e. interpolation) // for (k = 0; k <= n - 1; k++) { apserv.taskgenint1d(-1, 1, n, ref xfull, ref yfull); x = new double[n - k]; y = new double[n - k]; w = new double[n - k]; if (k > 0) { xc = new double[k]; yc = new double[k]; dc = new int[k]; } for (i = 0; i <= n - k - 1; i++) { x[i] = xfull[i]; y[i] = yfull[i]; w[i] = 1 + AP.Math.RandomReal(); } for (i = 0; i <= k - 1; i++) { xc[i] = xfull[n - k + i]; yc[i] = yfull[n - k + i]; dc[i] = 0; } polint.polynomialfitwc(x, y, ref w, n - k, xc, yc, ref dc, k, n, ref info, ref p1, ref rep); if (info <= 0) { fiterrors = true; } else { for (i = 0; i <= n - k - 1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref p1, x[i]) - y[i])) > (double)(threshold); } for (i = 0; i <= k - 1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref p1, xc[i]) - yc[i])) > (double)(threshold); } } } // // Testing constraints on derivatives. // Special tasks which will always have solution: // 1. P(0)=YC[0] // 2. P(0)=YC[0], P'(0)=YC[1] // if (n > 1) { for (m = 3; m <= 5; m++) { for (k = 1; k <= 2; k++) { apserv.taskgenint1d(-1, 1, n, ref x, ref y); w = new double[n]; xc = new double[2]; yc = new double[2]; dc = new int[2]; for (i = 0; i <= n - 1; i++) { w[i] = 1 + AP.Math.RandomReal(); } xc[0] = 0; yc[0] = 2 * AP.Math.RandomReal() - 1; dc[0] = 0; xc[1] = 0; yc[1] = 2 * AP.Math.RandomReal() - 1; dc[1] = 1; polint.polynomialfitwc(x, y, ref w, n, xc, yc, ref dc, k, m, ref info, ref p1, ref rep); if (info <= 0) { fiterrors = true; } else { ratint.barycentricdiff1(ref p1, 0.0, ref v0, ref v1); fiterrors = fiterrors | (double)(Math.Abs(v0 - yc[0])) > (double)(threshold); if (k == 2) { fiterrors = fiterrors | (double)(Math.Abs(v1 - yc[1])) > (double)(threshold); } } } } } } } for (m = 2; m <= 8; m++) { for (pass = 1; pass <= passcount; pass++) { // // General fitting // // interpolating function through M nodes should have // greater RMS error than fitting it through the same M nodes // n = 100; x2 = new double[n]; y2 = new double[n]; w2 = new double[n]; xmin = 0; xmax = 2 * Math.PI; for (i = 0; i <= n - 1; i++) { x2[i] = 2 * Math.PI * AP.Math.RandomReal(); y2[i] = Math.Sin(x2[i]); w2[i] = 1; } x = new double[m]; y = new double[m]; for (i = 0; i <= m - 1; i++) { x[i] = xmin + (xmax - xmin) * i / (m - 1); y[i] = Math.Sin(x[i]); } polint.polynomialbuild(ref x, ref y, m, ref p1); polint.polynomialfitwc(x2, y2, ref w2, n, xc, yc, ref dc, 0, m, ref info, ref p2, ref rep); if (info <= 0) { fiterrors = true; } else { // // calculate P1 (interpolant) RMS error, compare with P2 error // v1 = 0; v2 = 0; for (i = 0; i <= n - 1; i++) { v1 = v1 + AP.Math.Sqr(ratint.barycentriccalc(ref p1, x2[i]) - y2[i]); v2 = v2 + AP.Math.Sqr(ratint.barycentriccalc(ref p2, x2[i]) - y2[i]); } v1 = Math.Sqrt(v1 / n); v2 = Math.Sqrt(v2 / n); fiterrors = fiterrors | (double)(v2) > (double)(v1); fiterrors = fiterrors | (double)(Math.Abs(v2 - rep.rmserror)) > (double)(threshold); } // // compare weighted and non-weighted // n = 20; x = new double[n]; y = new double[n]; w = new double[n]; for (i = 0; i <= n - 1; i++) { x[i] = 2 * AP.Math.RandomReal() - 1; y[i] = 2 * AP.Math.RandomReal() - 1; w[i] = 1; } polint.polynomialfitwc(x, y, ref w, n, xc, yc, ref dc, 0, m, ref info, ref p1, ref rep); polint.polynomialfit(ref x, ref y, n, m, ref info2, ref p2, ref rep2); if (info <= 0 | info2 <= 0) { fiterrors = true; } else { // // calculate P1 (interpolant), compare with P2 error // compare RMS errors // t = 2 * AP.Math.RandomReal() - 1; v1 = ratint.barycentriccalc(ref p1, t); v2 = ratint.barycentriccalc(ref p2, t); fiterrors = fiterrors | (double)(v2) != (double)(v1); fiterrors = fiterrors | (double)(rep.rmserror) != (double)(rep2.rmserror); fiterrors = fiterrors | (double)(rep.avgerror) != (double)(rep2.avgerror); fiterrors = fiterrors | (double)(rep.avgrelerror) != (double)(rep2.avgrelerror); fiterrors = fiterrors | (double)(rep.maxerror) != (double)(rep2.maxerror); } } } for (pass = 1; pass <= passcount; pass++) { System.Diagnostics.Debug.Assert(passcount >= 2, "PassCount should be 2 or greater!"); // // solve simple task (all X[] are the same, Y[] are specially // calculated to ensure simple form of all types of errors) // and check correctness of the errors calculated by subroutines // // First pass is done with zero Y[], other passes - with random Y[]. // It should test both ability to correctly calculate errors and // ability to not fail while working with zeros :) // n = 4; if (pass == 1) { v1 = 0; v2 = 0; v = 0; } else { v1 = AP.Math.RandomReal(); v2 = AP.Math.RandomReal(); v = 1 + AP.Math.RandomReal(); } x = new double[4]; y = new double[4]; w = new double[4]; x[0] = 0; y[0] = v - v2; w[0] = 1; x[1] = 0; y[1] = v - v1; w[1] = 1; x[2] = 0; y[2] = v + v1; w[2] = 1; x[3] = 0; y[3] = v + v2; w[3] = 1; refrms = Math.Sqrt((AP.Math.Sqr(v1) + AP.Math.Sqr(v2)) / 2); refavg = (Math.Abs(v1) + Math.Abs(v2)) / 2; if (pass == 1) { refavgrel = 0; } else { refavgrel = 0.25 * (Math.Abs(v2) / Math.Abs(v - v2) + Math.Abs(v1) / Math.Abs(v - v1) + Math.Abs(v1) / Math.Abs(v + v1) + Math.Abs(v2) / Math.Abs(v + v2)); } refmax = Math.Max(v1, v2); // // Test errors correctness // polint.polynomialfit(ref x, ref y, 4, 1, ref info, ref p, ref rep); if (info <= 0) { fiterrors = true; } else { s = ratint.barycentriccalc(ref p, 0); fiterrors = fiterrors | (double)(Math.Abs(s - v)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.rmserror - refrms)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgerror - refavg)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgrelerror - refavgrel)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.maxerror - refmax)) > (double)(threshold); } } // // report // waserrors = interrors | fiterrors; if (!silent) { System.Console.Write("TESTING POLYNOMIAL INTERPOLATION AND FITTING"); System.Console.WriteLine(); // // Normal tests // System.Console.Write("INTERPOLATION TEST: "); if (interrors) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } System.Console.Write("FITTING TEST: "); if (fiterrors) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } if (waserrors) { System.Console.Write("TEST FAILED"); System.Console.WriteLine(); } else { System.Console.Write("TEST PASSED"); System.Console.WriteLine(); } System.Console.WriteLine(); System.Console.WriteLine(); } // // end // result = !waserrors; return(result); }
/************************************************************************* * Weighted fitting by Chebyshev polynomial in barycentric form, with * constraints on function values or first derivatives. * * Small regularizing term is used when solving constrained tasks (to improve * stability). * * Task is linear, so linear least squares solver is used. Complexity of this * computational scheme is O(N*M^2), mostly dominated by least squares solver * * SEE ALSO: * PolynomialFit() * * 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 polynomial 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 P(XC[i])=YC[i] * DC[i]=1 means that P'(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 (= polynomial_degree + 1), M>=1 * * OUTPUT PARAMETERS: * Info- same format as in LSFitLinearW() 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) * P - interpolant in barycentric form. * Rep - report, same format as in LSFitLinearW() subroutine. * Following fields are set: * 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 regression splines: * even simple constraints can be inconsistent, see Wikipedia article on * this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation * 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 one special cases, however, we can guarantee consistency. This * case is: M>1 and constraints on the function values (NOT DERIVATIVES) * * 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 10.12.2009 by Bochkanov Sergey *************************************************************************/ public static void polynomialfitwc(double[] x, double[] y, ref double[] w, int n, double[] xc, double[] yc, ref int[] dc, int k, int m, ref int info, ref ratint.barycentricinterpolant p, ref polynomialfitreport rep) { double xa = 0; double xb = 0; double sa = 0; double sb = 0; double[] xoriginal = new double[0]; double[] yoriginal = new double[0]; double[] y2 = new double[0]; double[] w2 = new double[0]; double[] tmp = new double[0]; double[] tmp2 = new double[0]; double[] tmpdiff = new double[0]; double[] bx = new double[0]; double[] by = new double[0]; double[] bw = new double[0]; double[,] fmatrix = new double[0, 0]; double[,] cmatrix = new double[0, 0]; int i = 0; int j = 0; double mx = 0; double decay = 0; double u = 0; double v = 0; double s = 0; int relcnt = 0; lsfit.lsfitreport lrep = new lsfit.lsfitreport(); int i_ = 0; x = (double[])x.Clone(); y = (double[])y.Clone(); xc = (double[])xc.Clone(); yc = (double[])yc.Clone(); if (m < 1 | n < 1 | 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/fill: // * FMatrix- values of basis functions at X[] // * CMatrix- values (derivatives) of basis functions at XC[] // * 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 // y2 = new double[n + m]; w2 = new double[n + m]; tmp = new double[m]; tmpdiff = new double[m]; fmatrix = new double[n + m, m]; if (k > 0) { cmatrix = new double[k, m + 1]; } // // Fill design matrix, Y2, W2: // * first N rows with basis functions for original points // * next M rows with decay terms // for (i = 0; i <= n - 1; i++) { // // prepare Ith row // use Tmp for calculations to avoid multidimensional arrays overhead // for (j = 0; j <= m - 1; j++) { if (j == 0) { tmp[j] = 1; } else { if (j == 1) { tmp[j] = x[i]; } else { tmp[j] = 2 * x[i] * tmp[j - 1] - tmp[j - 2]; } } } for (i_ = 0; i_ <= m - 1; i_++) { fmatrix[i, i_] = tmp[i_]; } } 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; } } } for (i_ = 0; i_ <= n - 1; i_++) { y2[i_] = y[i_]; } for (i_ = 0; i_ <= n - 1; i_++) { w2[i_] = w[i_]; } mx = 0; for (i = 0; i <= n - 1; i++) { mx = mx + Math.Abs(w[i]); } mx = mx / n; for (i = 0; i <= m - 1; i++) { y2[n + i] = 0; w2[n + i] = mx; } // // fill constraints matrix // for (i = 0; i <= k - 1; i++) { // // prepare Ith row // use Tmp for basis function values, // TmpDiff for basos function derivatives // for (j = 0; j <= m - 1; j++) { if (j == 0) { tmp[j] = 1; tmpdiff[j] = 0; } else { if (j == 1) { tmp[j] = xc[i]; tmpdiff[j] = 1; } else { tmp[j] = 2 * xc[i] * tmp[j - 1] - tmp[j - 2]; tmpdiff[j] = 2 * (tmp[j - 1] + xc[i] * tmpdiff[j - 1]) - tmpdiff[j - 2]; } } } if (dc[i] == 0) { for (i_ = 0; i_ <= m - 1; i_++) { cmatrix[i, i_] = tmp[i_]; } } if (dc[i] == 1) { for (i_ = 0; i_ <= m - 1; i_++) { cmatrix[i, i_] = tmpdiff[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, 0, ref info, ref tmp, ref lrep); } if (info < 0) { return; } // // Generate barycentric model and scale it // * BX, BY store barycentric model nodes // * FMatrix is reused (remember - it is at least MxM, what we need) // // Model intialization is done in O(M^2). In principle, it can be // done in O(M*log(M)), but before it we solved task with O(N*M^2) // complexity, so it is only a small amount of total time spent. // bx = new double[m]; by = new double[m]; bw = new double[m]; tmp2 = new double[m]; s = 1; for (i = 0; i <= m - 1; i++) { if (m != 1) { u = Math.Cos(Math.PI * i / (m - 1)); } else { u = 0; } v = 0; for (j = 0; j <= m - 1; j++) { if (j == 0) { tmp2[j] = 1; } else { if (j == 1) { tmp2[j] = u; } else { tmp2[j] = 2 * u * tmp2[j - 1] - tmp2[j - 2]; } } v = v + tmp[j] * tmp2[j]; } bx[i] = u; by[i] = v; bw[i] = s; if (i == 0 | i == m - 1) { bw[i] = 0.5 * bw[i]; } s = -s; } ratint.barycentricbuildxyw(ref bx, ref by, ref bw, m, ref p); ratint.barycentriclintransx(ref p, 2 / (xb - xa), -((xa + xb) / (xb - xa))); ratint.barycentriclintransy(ref p, 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(ref p, xoriginal[i]) - yoriginal[i]) / Math.Abs(yoriginal[i]); relcnt = relcnt + 1; } } if (relcnt != 0) { rep.avgrelerror = rep.avgrelerror / relcnt; } }
public static bool testri(bool silent) { bool result = new bool(); bool waserrors = new bool(); bool bcerrors = new bool(); bool nperrors = new bool(); bool fiterrors = new bool(); double threshold = 0; double lipschitztol = 0; int maxn = 0; int passcount = 0; ratint.barycentricinterpolant b1 = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant b2 = new ratint.barycentricinterpolant(); double[] x = new double[0]; double[] x2 = new double[0]; double[] y = new double[0]; double[] y2 = new double[0]; double[] w = new double[0]; double[] w2 = new double[0]; double[] xc = new double[0]; double[] yc = new double[0]; int[] dc = new int[0]; double h = 0; double s1 = 0; double s2 = 0; bool bsame = new bool(); int n = 0; int m = 0; int n2 = 0; int i = 0; int j = 0; int k = 0; int d = 0; int pass = 0; double err = 0; double maxerr = 0; double t = 0; double a = 0; double b = 0; double s = 0; double v = 0; double v0 = 0; double v1 = 0; double v2 = 0; double v3 = 0; double d0 = 0; double d1 = 0; double d2 = 0; int info = 0; int info2 = 0; double xmin = 0; double xmax = 0; double refrms = 0; double refavg = 0; double refavgrel = 0; double refmax = 0; double[] ra = new double[0]; double[] ra2 = new double[0]; int ralen = 0; ratint.barycentricfitreport rep = new ratint.barycentricfitreport(); ratint.barycentricfitreport rep2 = new ratint.barycentricfitreport(); ratint.barycentricinterpolant b3 = new ratint.barycentricinterpolant(); ratint.barycentricinterpolant b4 = new ratint.barycentricinterpolant(); int i_ = 0; nperrors = false; bcerrors = false; fiterrors = false; waserrors = false; // // PassCount number of repeated passes // Threshold error tolerance // LipschitzTol Lipschitz constant increase allowed // when calculating constant on a twice denser grid // passcount = 5; maxn = 15; threshold = 1000000 * AP.Math.MachineEpsilon; lipschitztol = 1.3; // // Basic barycentric functions // for (n = 1; n <= 10; n++) { // // randomized tests // for (pass = 1; pass <= passcount; pass++) { // // generate weights from polynomial interpolation // v0 = 1 + 0.4 * AP.Math.RandomReal() - 0.2; v1 = 2 * AP.Math.RandomReal() - 1; v2 = 2 * AP.Math.RandomReal() - 1; v3 = 2 * AP.Math.RandomReal() - 1; x = new double[n]; y = new double[n]; w = new double[n]; for (i = 0; i <= n - 1; i++) { if (n == 1) { x[i] = 0; } else { x[i] = v0 * Math.Cos(i * Math.PI / (n - 1)); } y[i] = Math.Sin(v1 * x[i]) + Math.Cos(v2 * x[i]) + Math.Exp(v3 * x[i]); } for (j = 0; j <= n - 1; j++) { w[j] = 1; for (k = 0; k <= n - 1; k++) { if (k != j) { w[j] = w[j] / (x[j] - x[k]); } } } ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref b1); // // unpack, then pack again and compare // brcunset(ref b2); ratint.barycentricunpack(ref b1, ref n2, ref x2, ref y2, ref w2); bcerrors = bcerrors | n2 != n; ratint.barycentricbuildxyw(ref x2, ref y2, ref w2, n2, ref b2); t = 2 * AP.Math.RandomReal() - 1; bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t) - ratint.barycentriccalc(ref b2, t))) > (double)(threshold); // // serialize, unserialize, compare // brcunset(ref b2); ratint.barycentricserialize(ref b1, ref ra, ref ralen); ra2 = new double[ralen]; for (i_ = 0; i_ <= ralen - 1; i_++) { ra2[i_] = ra[i_]; } ratint.barycentricunserialize(ref ra2, ref b2); t = 2 * AP.Math.RandomReal() - 1; bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t) - ratint.barycentriccalc(ref b2, t))) > (double)(threshold); // // copy, compare // brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); t = 2 * AP.Math.RandomReal() - 1; bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t) - ratint.barycentriccalc(ref b2, t))) > (double)(threshold); // // test interpolation properties // for (i = 0; i <= n - 1; i++) { // // test interpolation at nodes // bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, x[i]) - y[i])) > (double)(threshold * Math.Abs(y[i])); // // compare with polynomial interpolation // t = 2 * AP.Math.RandomReal() - 1; poldiff2(ref x, y, n, t, ref v0, ref v1, ref v2); bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, t) - v0)) > (double)(threshold * Math.Max(Math.Abs(v0), 1)); // // test continuity between nodes // calculate Lipschitz constant on two grids - // dense and even more dense. If Lipschitz constant // on a denser grid is significantly increased, // continuity test is failed // t = 3.0; k = 100; s1 = 0; for (j = 0; j <= k - 1; j++) { v1 = x[i] + (t - x[i]) * j / k; v2 = x[i] + (t - x[i]) * (j + 1) / k; s1 = Math.Max(s1, Math.Abs(ratint.barycentriccalc(ref b1, v2) - ratint.barycentriccalc(ref b1, v1)) / Math.Abs(v2 - v1)); } k = 2 * k; s2 = 0; for (j = 0; j <= k - 1; j++) { v1 = x[i] + (t - x[i]) * j / k; v2 = x[i] + (t - x[i]) * (j + 1) / k; s2 = Math.Max(s2, Math.Abs(ratint.barycentriccalc(ref b1, v2) - ratint.barycentriccalc(ref b1, v1)) / Math.Abs(v2 - v1)); } bcerrors = bcerrors | (double)(s2) > (double)(lipschitztol * s1) & (double)(s1) > (double)(threshold * k); } // // test differentiation properties // for (i = 0; i <= n - 1; i++) { t = 2 * AP.Math.RandomReal() - 1; poldiff2(ref x, y, n, t, ref v0, ref v1, ref v2); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff1(ref b1, t, ref d0, ref d1); bcerrors = bcerrors | (double)(Math.Abs(v0 - d0)) > (double)(threshold * Math.Max(Math.Abs(v0), 1)); bcerrors = bcerrors | (double)(Math.Abs(v1 - d1)) > (double)(threshold * Math.Max(Math.Abs(v1), 1)); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff2(ref b1, t, ref d0, ref d1, ref d2); bcerrors = bcerrors | (double)(Math.Abs(v0 - d0)) > (double)(threshold * Math.Max(Math.Abs(v0), 1)); bcerrors = bcerrors | (double)(Math.Abs(v1 - d1)) > (double)(threshold * Math.Max(Math.Abs(v1), 1)); bcerrors = bcerrors | (double)(Math.Abs(v2 - d2)) > (double)(Math.Sqrt(threshold) * Math.Max(Math.Abs(v2), 1)); } // // test linear translation // t = 2 * AP.Math.RandomReal() - 1; a = 2 * AP.Math.RandomReal() - 1; b = 2 * AP.Math.RandomReal() - 1; brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); ratint.barycentriclintransx(ref b2, a, b); bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, a * t + b) - ratint.barycentriccalc(ref b2, t))) > (double)(threshold); a = 0; b = 2 * AP.Math.RandomReal() - 1; brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); ratint.barycentriclintransx(ref b2, a, b); bcerrors = bcerrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, a * t + b) - ratint.barycentriccalc(ref b2, t))) > (double)(threshold); a = 2 * AP.Math.RandomReal() - 1; b = 2 * AP.Math.RandomReal() - 1; brcunset(ref b2); ratint.barycentriccopy(ref b1, ref b2); ratint.barycentriclintransy(ref b2, a, b); bcerrors = bcerrors | (double)(Math.Abs(a * ratint.barycentriccalc(ref b1, t) + b - ratint.barycentriccalc(ref b2, t))) > (double)(threshold); } } for (pass = 0; pass <= 3; pass++) { // // Crash-test: small numbers, large numbers // x = new double[4]; y = new double[4]; w = new double[4]; h = 1; if (pass % 2 == 0) { h = 100 * AP.Math.MinRealNumber; } if (pass % 2 == 1) { h = 0.01 * AP.Math.MaxRealNumber; } x[0] = 0 * h; x[1] = 1 * h; x[2] = 2 * h; x[3] = 3 * h; y[0] = 0 * h; y[1] = 1 * h; y[2] = 2 * h; y[3] = 3 * h; w[0] = -(1 / (x[1] - x[0])); w[1] = +(1 * (1 / (x[1] - x[0]) + 1 / (x[2] - x[1]))); w[2] = -(1 * (1 / (x[2] - x[1]) + 1 / (x[3] - x[2]))); w[3] = +(1 / (x[3] - x[2])); if (pass / 2 == 0) { v0 = 0; } if (pass / 2 == 1) { v0 = 0.6 * h; } ratint.barycentricbuildxyw(ref x, ref y, ref w, 4, ref b1); t = ratint.barycentriccalc(ref b1, v0); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff1(ref b1, v0, ref d0, ref d1); bcerrors = bcerrors | (double)(Math.Abs(t - v0)) > (double)(threshold * v0); bcerrors = bcerrors | (double)(Math.Abs(d0 - v0)) > (double)(threshold * v0); bcerrors = bcerrors | (double)(Math.Abs(d1 - 1)) > (double)(1000 * threshold); } // // crash test: large abscissas, small argument // // test for errors in D0 is not very strict // because renormalization used in Diff1() // destroys part of precision. // x = new double[4]; y = new double[4]; w = new double[4]; h = 0.01 * AP.Math.MaxRealNumber; x[0] = 0 * h; x[1] = 1 * h; x[2] = 2 * h; x[3] = 3 * h; y[0] = 0 * h; y[1] = 1 * h; y[2] = 2 * h; y[3] = 3 * h; w[0] = -(1 / (x[1] - x[0])); w[1] = +(1 * (1 / (x[1] - x[0]) + 1 / (x[2] - x[1]))); w[2] = -(1 * (1 / (x[2] - x[1]) + 1 / (x[3] - x[2]))); w[3] = +(1 / (x[3] - x[2])); v0 = 100 * AP.Math.MinRealNumber; ratint.barycentricbuildxyw(ref x, ref y, ref w, 4, ref b1); t = ratint.barycentriccalc(ref b1, v0); d0 = 0; d1 = 0; d2 = 0; ratint.barycentricdiff1(ref b1, v0, ref d0, ref d1); bcerrors = bcerrors | (double)(Math.Abs(t)) > (double)(v0 * (1 + threshold)); bcerrors = bcerrors | (double)(Math.Abs(d0)) > (double)(v0 * (1 + threshold)); bcerrors = bcerrors | (double)(Math.Abs(d1 - 1)) > (double)(1000 * threshold); // // crash test: test safe barycentric formula // x = new double[4]; y = new double[4]; w = new double[4]; h = 2 * AP.Math.MinRealNumber; x[0] = 0 * h; x[1] = 1 * h; x[2] = 2 * h; x[3] = 3 * h; y[0] = 0 * h; y[1] = 1 * h; y[2] = 2 * h; y[3] = 3 * h; w[0] = -(1 / (x[1] - x[0])); w[1] = +(1 * (1 / (x[1] - x[0]) + 1 / (x[2] - x[1]))); w[2] = -(1 * (1 / (x[2] - x[1]) + 1 / (x[3] - x[2]))); w[3] = +(1 / (x[3] - x[2])); v0 = AP.Math.MinRealNumber; ratint.barycentricbuildxyw(ref x, ref y, ref w, 4, ref b1); t = ratint.barycentriccalc(ref b1, v0); bcerrors = bcerrors | (double)(Math.Abs(t - v0) / v0) > (double)(threshold); // // Testing "No Poles" interpolation // maxerr = 0; for (pass = 1; pass <= passcount - 1; pass++) { x = new double[1]; y = new double[1]; x[0] = 2 * AP.Math.RandomReal() - 1; y[0] = 2 * AP.Math.RandomReal() - 1; ratint.barycentricbuildfloaterhormann(ref x, ref y, 1, 1, ref b1); maxerr = Math.Max(maxerr, Math.Abs(ratint.barycentriccalc(ref b1, 2 * AP.Math.RandomReal() - 1) - y[0])); } for (n = 2; n <= 10; n++) { // // compare interpolant built by subroutine // with interpolant built by hands // x = new double[n]; y = new double[n]; w = new double[n]; w2 = new double[n]; // // D=1, non-equidistant nodes // for (pass = 1; pass <= passcount; pass++) { // // Initialize X, Y, W // a = -1 - 1 * AP.Math.RandomReal(); b = +1 + 1 * AP.Math.RandomReal(); for (i = 0; i <= n - 1; i++) { x[i] = Math.Atan((b - a) * i / (n - 1) + a); } for (i = 0; i <= n - 1; i++) { y[i] = 2 * AP.Math.RandomReal() - 1; } w[0] = -(1 / (x[1] - x[0])); s = 1; for (i = 1; i <= n - 2; i++) { w[i] = s * (1 / (x[i] - x[i - 1]) + 1 / (x[i + 1] - x[i])); s = -s; } w[n - 1] = s / (x[n - 1] - x[n - 2]); for (i = 0; i <= n - 1; i++) { k = AP.Math.RandomInteger(n); if (k != i) { t = x[i]; x[i] = x[k]; x[k] = t; t = y[i]; y[i] = y[k]; y[k] = t; t = w[i]; w[i] = w[k]; w[k] = t; } } // // Build and test // ratint.barycentricbuildfloaterhormann(ref x, ref y, n, 1, ref b1); ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref b2); for (i = 1; i <= 2 * n; i++) { t = a + (b - a) * AP.Math.RandomReal(); maxerr = Math.Max(maxerr, Math.Abs(ratint.barycentriccalc(ref b1, t) - ratint.barycentriccalc(ref b2, t))); } } // // D = 0, 1, 2. Equidistant nodes. // for (d = 0; d <= 2; d++) { for (pass = 1; pass <= passcount; pass++) { // // Skip incorrect (N,D) pairs // if (n < 2 * d) { continue; } // // Initialize X, Y, W // a = -1 - 1 * AP.Math.RandomReal(); b = +1 + 1 * AP.Math.RandomReal(); for (i = 0; i <= n - 1; i++) { x[i] = (b - a) * i / (n - 1) + a; } for (i = 0; i <= n - 1; i++) { y[i] = 2 * AP.Math.RandomReal() - 1; } s = 1; if (d == 0) { for (i = 0; i <= n - 1; i++) { w[i] = s; s = -s; } } if (d == 1) { w[0] = -s; for (i = 1; i <= n - 2; i++) { w[i] = 2 * s; s = -s; } w[n - 1] = s; } if (d == 2) { w[0] = s; w[1] = -(3 * s); for (i = 2; i <= n - 3; i++) { w[i] = 4 * s; s = -s; } w[n - 2] = 3 * s; w[n - 1] = -s; } // // Mix // for (i = 0; i <= n - 1; i++) { k = AP.Math.RandomInteger(n); if (k != i) { t = x[i]; x[i] = x[k]; x[k] = t; t = y[i]; y[i] = y[k]; y[k] = t; t = w[i]; w[i] = w[k]; w[k] = t; } } // // Build and test // ratint.barycentricbuildfloaterhormann(ref x, ref y, n, d, ref b1); ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref b2); for (i = 1; i <= 2 * n; i++) { t = a + (b - a) * AP.Math.RandomReal(); maxerr = Math.Max(maxerr, Math.Abs(ratint.barycentriccalc(ref b1, t) - ratint.barycentriccalc(ref b2, t))); } } } } if ((double)(maxerr) > (double)(threshold)) { nperrors = true; } // // Test rational fitting: // for (pass = 1; pass <= passcount; pass++) { for (n = 2; n <= maxn; n++) { // // N=M+K fitting (i.e. interpolation) // for (k = 0; k <= n - 1; k++) { x = new double[n - k]; y = new double[n - k]; w = new double[n - k]; if (k > 0) { xc = new double[k]; yc = new double[k]; dc = new int[k]; } for (i = 0; i <= n - k - 1; i++) { x[i] = (double)(i) / ((double)(n - 1)); y[i] = 2 * AP.Math.RandomReal() - 1; w[i] = 1 + AP.Math.RandomReal(); } for (i = 0; i <= k - 1; i++) { xc[i] = ((double)(n - k + i)) / ((double)(n - 1)); yc[i] = 2 * AP.Math.RandomReal() - 1; dc[i] = 0; } ratint.barycentricfitfloaterhormannwc(ref x, ref y, ref w, n - k, ref xc, ref yc, ref dc, k, n, ref info, ref b1, ref rep); if (info <= 0) { fiterrors = true; } else { for (i = 0; i <= n - k - 1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, x[i]) - y[i])) > (double)(threshold); } for (i = 0; i <= k - 1; i++) { fiterrors = fiterrors | (double)(Math.Abs(ratint.barycentriccalc(ref b1, xc[i]) - yc[i])) > (double)(threshold); } } } // // Testing constraints on derivatives: // * several M's are tried // * several K's are tried - 1, 2. // * constraints at the ends of the interval // for (m = 3; m <= 5; m++) { for (k = 1; k <= 2; k++) { x = new double[n]; y = new double[n]; w = new double[n]; xc = new double[2]; yc = new double[2]; dc = new int[2]; for (i = 0; i <= n - 1; i++) { x[i] = 2 * AP.Math.RandomReal() - 1; y[i] = 2 * AP.Math.RandomReal() - 1; w[i] = 1 + AP.Math.RandomReal(); } xc[0] = -1; yc[0] = 2 * AP.Math.RandomReal() - 1; dc[0] = 0; xc[1] = +1; yc[1] = 2 * AP.Math.RandomReal() - 1; dc[1] = 0; ratint.barycentricfitfloaterhormannwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, k, m, ref info, ref b1, ref rep); if (info <= 0) { fiterrors = true; } else { for (i = 0; i <= k - 1; i++) { ratint.barycentricdiff1(ref b1, xc[i], ref v0, ref v1); fiterrors = fiterrors | (double)(Math.Abs(v0 - yc[i])) > (double)(threshold); } } } } } } for (m = 2; m <= 8; m++) { for (pass = 1; pass <= passcount; pass++) { // // General fitting // // interpolating function through M nodes should have // greater RMS error than fitting it through the same M nodes // n = 100; x2 = new double[n]; y2 = new double[n]; w2 = new double[n]; xmin = AP.Math.MaxRealNumber; xmax = -AP.Math.MaxRealNumber; for (i = 0; i <= n - 1; i++) { x2[i] = 2 * Math.PI * AP.Math.RandomReal(); y2[i] = Math.Sin(x2[i]); w2[i] = 1; xmin = Math.Min(xmin, x2[i]); xmax = Math.Max(xmax, x2[i]); } x = new double[m]; y = new double[m]; for (i = 0; i <= m - 1; i++) { x[i] = xmin + (xmax - xmin) * i / (m - 1); y[i] = Math.Sin(x[i]); } ratint.barycentricbuildfloaterhormann(ref x, ref y, m, 3, ref b1); ratint.barycentricfitfloaterhormannwc(ref x2, ref y2, ref w2, n, ref xc, ref yc, ref dc, 0, m, ref info, ref b2, ref rep); if (info <= 0) { fiterrors = true; } else { // // calculate B1 (interpolant) RMS error, compare with B2 error // v1 = 0; v2 = 0; for (i = 0; i <= n - 1; i++) { v1 = v1 + AP.Math.Sqr(ratint.barycentriccalc(ref b1, x2[i]) - y2[i]); v2 = v2 + AP.Math.Sqr(ratint.barycentriccalc(ref b2, x2[i]) - y2[i]); } v1 = Math.Sqrt(v1 / n); v2 = Math.Sqrt(v2 / n); fiterrors = fiterrors | (double)(v2) > (double)(v1); fiterrors = fiterrors | (double)(Math.Abs(v2 - rep.rmserror)) > (double)(threshold); } // // compare weighted and non-weighted // n = 20; x = new double[n]; y = new double[n]; w = new double[n]; for (i = 0; i <= n - 1; i++) { x[i] = 2 * AP.Math.RandomReal() - 1; y[i] = 2 * AP.Math.RandomReal() - 1; w[i] = 1; } ratint.barycentricfitfloaterhormannwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 0, m, ref info, ref b1, ref rep); ratint.barycentricfitfloaterhormann(ref x, ref y, n, m, ref info2, ref b2, ref rep2); if (info <= 0 | info2 <= 0) { fiterrors = true; } else { // // calculate B1 (interpolant), compare with B2 // compare RMS errors // t = 2 * AP.Math.RandomReal() - 1; v1 = ratint.barycentriccalc(ref b1, t); v2 = ratint.barycentriccalc(ref b2, t); fiterrors = fiterrors | (double)(v2) != (double)(v1); fiterrors = fiterrors | (double)(rep.rmserror) != (double)(rep2.rmserror); fiterrors = fiterrors | (double)(rep.avgerror) != (double)(rep2.avgerror); fiterrors = fiterrors | (double)(rep.avgrelerror) != (double)(rep2.avgrelerror); fiterrors = fiterrors | (double)(rep.maxerror) != (double)(rep2.maxerror); } } } for (pass = 1; pass <= passcount; pass++) { System.Diagnostics.Debug.Assert(passcount >= 2, "PassCount should be 2 or greater!"); // // solve simple task (all X[] are the same, Y[] are specially // calculated to ensure simple form of all types of errors) // and check correctness of the errors calculated by subroutines // // First pass is done with zero Y[], other passes - with random Y[]. // It should test both ability to correctly calculate errors and // ability to not fail while working with zeros :) // n = 4; if (pass == 1) { v1 = 0; v2 = 0; v = 0; } else { v1 = AP.Math.RandomReal(); v2 = AP.Math.RandomReal(); v = 1 + AP.Math.RandomReal(); } x = new double[4]; y = new double[4]; w = new double[4]; x[0] = 0; y[0] = v - v2; w[0] = 1; x[1] = 0; y[1] = v - v1; w[1] = 1; x[2] = 0; y[2] = v + v1; w[2] = 1; x[3] = 0; y[3] = v + v2; w[3] = 1; refrms = Math.Sqrt((AP.Math.Sqr(v1) + AP.Math.Sqr(v2)) / 2); refavg = (Math.Abs(v1) + Math.Abs(v2)) / 2; if (pass == 1) { refavgrel = 0; } else { refavgrel = 0.25 * (Math.Abs(v2) / Math.Abs(v - v2) + Math.Abs(v1) / Math.Abs(v - v1) + Math.Abs(v1) / Math.Abs(v + v1) + Math.Abs(v2) / Math.Abs(v + v2)); } refmax = Math.Max(v1, v2); // // Test errors correctness // ratint.barycentricfitfloaterhormann(ref x, ref y, 4, 2, ref info, ref b1, ref rep); if (info <= 0) { fiterrors = true; } else { s = ratint.barycentriccalc(ref b1, 0); fiterrors = fiterrors | (double)(Math.Abs(s - v)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.rmserror - refrms)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgerror - refavg)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.avgrelerror - refavgrel)) > (double)(threshold); fiterrors = fiterrors | (double)(Math.Abs(rep.maxerror - refmax)) > (double)(threshold); } } // // report // waserrors = bcerrors | nperrors | fiterrors; if (!silent) { System.Console.Write("TESTING RATIONAL INTERPOLATION"); System.Console.WriteLine(); System.Console.Write("BASIC BARYCENTRIC FUNCTIONS: "); if (bcerrors) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } System.Console.Write("FLOATER-HORMANN: "); if (nperrors) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } System.Console.Write("RATIONAL FITTING: "); if (fiterrors) { System.Console.Write("FAILED"); System.Console.WriteLine(); } else { System.Console.Write("OK"); System.Console.WriteLine(); } if (waserrors) { System.Console.Write("TEST FAILED"); System.Console.WriteLine(); } else { System.Console.Write("TEST PASSED"); System.Console.WriteLine(); } System.Console.WriteLine(); System.Console.WriteLine(); } // // end // result = !waserrors; return(result); }