public spline1dfitreport(lsfit.spline1dfitreport obj) { _innerobj = obj; }
private static void testsplinefitting(ref bool fiterrors) { double threshold = 0; double nonstrictthreshold = 0; int passcount = 0; int n = 0; int m = 0; int i = 0; int k = 0; int pass = 0; double[] x = new double[0]; double[] y = new double[0]; double[] w = new double[0]; double[] w2 = new double[0]; double[] xc = new double[0]; double[] yc = new double[0]; double[] d = new double[0]; int[] dc = new int[0]; double sa = 0; double sb = 0; int info = 0; int info1 = 0; int info2 = 0; spline1d.spline1dinterpolant c = new spline1d.spline1dinterpolant(); spline1d.spline1dinterpolant c2 = new spline1d.spline1dinterpolant(); lsfit.spline1dfitreport rep = new lsfit.spline1dfitreport(); lsfit.spline1dfitreport rep2 = new lsfit.spline1dfitreport(); double s = 0; double ds = 0; double d2s = 0; int stype = 0; double t = 0; double v = 0; double v1 = 0; double v2 = 0; double refrms = 0; double refavg = 0; double refavgrel = 0; double refmax = 0; double rho = 0; // // Valyes: // * pass count // * threshold - for tests which must be satisfied exactly // * nonstrictthreshold - for approximate tests // passcount = 20; threshold = 10000*math.machineepsilon; nonstrictthreshold = 1.0E-4; fiterrors = false; // // Test fitting by Cubic and Hermite splines (obsolete, but still supported) // for(pass=1; pass<=passcount; pass++) { // // Cubic splines // Ability to handle boundary constraints (1-4 constraints on F, dF/dx). // for(m=4; m<=8; m++) { for(k=1; k<=4; k++) { if( k>=m ) { continue; } n = 100; x = new double[n]; y = new double[n]; w = new double[n]; xc = new double[4]; yc = new double[4]; dc = new int[4]; sa = 1+math.randomreal(); sb = 2*math.randomreal()-1; for(i=0; i<=n-1; i++) { x[i] = sa*math.randomreal()+sb; y[i] = 2*math.randomreal()-1; w[i] = 1+math.randomreal(); } xc[0] = sb; yc[0] = 2*math.randomreal()-1; dc[0] = 0; xc[1] = sb; yc[1] = 2*math.randomreal()-1; dc[1] = 1; xc[2] = sa+sb; yc[2] = 2*math.randomreal()-1; dc[2] = 0; xc[3] = sa+sb; yc[3] = 2*math.randomreal()-1; dc[3] = 1; lsfit.spline1dfitcubicwc(x, y, w, n, xc, yc, dc, k, m, ref info, c, rep); if( info<=0 ) { fiterrors = true; } else { // // Check that constraints are satisfied // for(i=0; i<=k-1; i++) { spline1d.spline1ddiff(c, xc[i], ref s, ref ds, ref d2s); if( dc[i]==0 ) { fiterrors = fiterrors | (double)(Math.Abs(s-yc[i]))>(double)(threshold); } if( dc[i]==1 ) { fiterrors = fiterrors | (double)(Math.Abs(ds-yc[i]))>(double)(threshold); } if( dc[i]==2 ) { fiterrors = fiterrors | (double)(Math.Abs(d2s-yc[i]))>(double)(threshold); } } } } } // // Cubic splines // Ability to handle one internal constraint // for(m=4; m<=8; m++) { n = 100; x = new double[n]; y = new double[n]; w = new double[n]; xc = new double[1]; yc = new double[1]; dc = new int[1]; sa = 1+math.randomreal(); sb = 2*math.randomreal()-1; for(i=0; i<=n-1; i++) { x[i] = sa*math.randomreal()+sb; y[i] = 2*math.randomreal()-1; w[i] = 1+math.randomreal(); } xc[0] = sa*math.randomreal()+sb; yc[0] = 2*math.randomreal()-1; dc[0] = math.randominteger(2); lsfit.spline1dfitcubicwc(x, y, w, n, xc, yc, dc, 1, m, ref info, c, rep); if( info<=0 ) { fiterrors = true; } else { // // Check that constraints are satisfied // spline1d.spline1ddiff(c, xc[0], ref s, ref ds, ref d2s); if( dc[0]==0 ) { fiterrors = fiterrors | (double)(Math.Abs(s-yc[0]))>(double)(threshold); } if( dc[0]==1 ) { fiterrors = fiterrors | (double)(Math.Abs(ds-yc[0]))>(double)(threshold); } if( dc[0]==2 ) { fiterrors = fiterrors | (double)(Math.Abs(d2s-yc[0]))>(double)(threshold); } } } // // Hermite splines // Ability to handle boundary constraints (1-4 constraints on F, dF/dx). // for(m=4; m<=8; m++) { for(k=1; k<=4; k++) { if( k>=m ) { continue; } if( m%2!=0 ) { continue; } n = 100; x = new double[n]; y = new double[n]; w = new double[n]; xc = new double[4]; yc = new double[4]; dc = new int[4]; sa = 1+math.randomreal(); sb = 2*math.randomreal()-1; for(i=0; i<=n-1; i++) { x[i] = sa*math.randomreal()+sb; y[i] = 2*math.randomreal()-1; w[i] = 1+math.randomreal(); } xc[0] = sb; yc[0] = 2*math.randomreal()-1; dc[0] = 0; xc[1] = sb; yc[1] = 2*math.randomreal()-1; dc[1] = 1; xc[2] = sa+sb; yc[2] = 2*math.randomreal()-1; dc[2] = 0; xc[3] = sa+sb; yc[3] = 2*math.randomreal()-1; dc[3] = 1; lsfit.spline1dfithermitewc(x, y, w, n, xc, yc, dc, k, m, ref info, c, rep); if( info<=0 ) { fiterrors = true; } else { // // Check that constraints are satisfied // for(i=0; i<=k-1; i++) { spline1d.spline1ddiff(c, xc[i], ref s, ref ds, ref d2s); if( dc[i]==0 ) { fiterrors = fiterrors | (double)(Math.Abs(s-yc[i]))>(double)(threshold); } if( dc[i]==1 ) { fiterrors = fiterrors | (double)(Math.Abs(ds-yc[i]))>(double)(threshold); } if( dc[i]==2 ) { fiterrors = fiterrors | (double)(Math.Abs(d2s-yc[i]))>(double)(threshold); } } } } } // // Hermite splines // Ability to handle one internal constraint // for(m=4; m<=8; m++) { if( m%2!=0 ) { continue; } n = 100; x = new double[n]; y = new double[n]; w = new double[n]; xc = new double[1]; yc = new double[1]; dc = new int[1]; sa = 1+math.randomreal(); sb = 2*math.randomreal()-1; for(i=0; i<=n-1; i++) { x[i] = sa*math.randomreal()+sb; y[i] = 2*math.randomreal()-1; w[i] = 1+math.randomreal(); } xc[0] = sa*math.randomreal()+sb; yc[0] = 2*math.randomreal()-1; dc[0] = math.randominteger(2); lsfit.spline1dfithermitewc(x, y, w, n, xc, yc, dc, 1, m, ref info, c, rep); if( info<=0 ) { fiterrors = true; } else { // // Check that constraints are satisfied // spline1d.spline1ddiff(c, xc[0], ref s, ref ds, ref d2s); if( dc[0]==0 ) { fiterrors = fiterrors | (double)(Math.Abs(s-yc[0]))>(double)(threshold); } if( dc[0]==1 ) { fiterrors = fiterrors | (double)(Math.Abs(ds-yc[0]))>(double)(threshold); } if( dc[0]==2 ) { fiterrors = fiterrors | (double)(Math.Abs(d2s-yc[0]))>(double)(threshold); } } } } for(m=4; m<=8; m++) { for(stype=0; stype<=1; stype++) { for(pass=1; pass<=passcount; pass++) { if( stype==1 & m%2!=0 ) { continue; } // // cubic/Hermite spline fitting: // * generate "template spline" C2 // * generate 2*N points from C2, such that result of // ideal fit should be equal to C2 // * fit, store in C // * compare C and C2 // sa = 1+math.randomreal(); sb = 2*math.randomreal()-1; if( stype==0 ) { x = new double[m-2]; y = new double[m-2]; for(i=0; i<=m-2-1; i++) { x[i] = sa*i/(m-2-1)+sb; y[i] = 2*math.randomreal()-1; } spline1d.spline1dbuildcubic(x, y, m-2, 1, 2*math.randomreal()-1, 1, 2*math.randomreal()-1, c2); } if( stype==1 ) { x = new double[m/2]; y = new double[m/2]; d = new double[m/2]; for(i=0; i<=m/2-1; i++) { x[i] = sa*i/(m/2-1)+sb; y[i] = 2*math.randomreal()-1; d[i] = 2*math.randomreal()-1; } spline1d.spline1dbuildhermite(x, y, d, m/2, c2); } n = 50; x = new double[2*n]; y = new double[2*n]; w = new double[2*n]; for(i=0; i<=n-1; i++) { // // "if i=0" and "if i=1" are needed to // synchronize interval size for C2 and // spline being fitted (i.e. C). // t = math.randomreal(); x[i] = sa*math.randomreal()+sb; if( i==0 ) { x[i] = sb; } if( i==1 ) { x[i] = sa+sb; } v = spline1d.spline1dcalc(c2, x[i]); y[i] = v+t; w[i] = 1+math.randomreal(); x[n+i] = x[i]; y[n+i] = v-t; w[n+i] = w[i]; } if( stype==0 ) { lsfit.spline1dfitcubicwc(x, y, w, 2*n, xc, yc, dc, 0, m, ref info, c, rep); } if( stype==1 ) { lsfit.spline1dfithermitewc(x, y, w, 2*n, xc, yc, dc, 0, m, ref info, c, rep); } if( info<=0 ) { fiterrors = true; } else { for(i=0; i<=n-1; i++) { v = sa*math.randomreal()+sb; fiterrors = fiterrors | (double)(Math.Abs(spline1d.spline1dcalc(c, v)-spline1d.spline1dcalc(c2, v)))>(double)(threshold); } } } } } for(m=4; m<=8; m++) { for(pass=1; pass<=passcount; pass++) { // // prepare points/weights // sa = 1+math.randomreal(); sb = 2*math.randomreal()-1; n = 10+math.randominteger(10); x = new double[n]; y = new double[n]; w = new double[n]; for(i=0; i<=n-1; i++) { x[i] = sa*math.randomreal()+sb; y[i] = 2*math.randomreal()-1; w[i] = 1; } // // Fit cubic with unity weights, without weights, then compare // if( m>=4 ) { lsfit.spline1dfitcubicwc(x, y, w, n, xc, yc, dc, 0, m, ref info1, c, rep); lsfit.spline1dfitcubic(x, y, n, m, ref info2, c2, rep2); if( info1<=0 | info2<=0 ) { fiterrors = true; } else { for(i=0; i<=n-1; i++) { v = sa*math.randomreal()+sb; fiterrors = fiterrors | (double)(spline1d.spline1dcalc(c, v))!=(double)(spline1d.spline1dcalc(c2, v)); fiterrors = fiterrors | (double)(rep.taskrcond)!=(double)(rep2.taskrcond); 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); } } } // // Fit Hermite with unity weights, without weights, then compare // if( m>=4 & m%2==0 ) { lsfit.spline1dfithermitewc(x, y, w, n, xc, yc, dc, 0, m, ref info1, c, rep); lsfit.spline1dfithermite(x, y, n, m, ref info2, c2, rep2); if( info1<=0 | info2<=0 ) { fiterrors = true; } else { for(i=0; i<=n-1; i++) { v = sa*math.randomreal()+sb; fiterrors = fiterrors | (double)(spline1d.spline1dcalc(c, v))!=(double)(spline1d.spline1dcalc(c2, v)); fiterrors = fiterrors | (double)(rep.taskrcond)!=(double)(rep2.taskrcond); 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); } } } } } // // check basic properties of penalized splines which are // preserved independently of Rho parameter. // for(m=4; m<=10; m++) { for(k=-5; k<=5; k++) { rho = k; // // when we have two points (even with different weights), // resulting spline must be equal to the straight line // x = new double[2]; y = new double[2]; w = new double[2]; x[0] = -0.5-math.randomreal(); y[0] = 0.5+math.randomreal(); w[0] = 1+math.randomreal(); x[1] = 0.5+math.randomreal(); y[1] = 0.5+math.randomreal(); w[1] = 1+math.randomreal(); lsfit.spline1dfitpenalized(x, y, 2, m, rho, ref info, c, rep); if( info>0 ) { v = 2*math.randomreal()-1; v1 = (v-x[0])/(x[1]-x[0])*y[1]+(v-x[1])/(x[0]-x[1])*y[0]; fiterrors = fiterrors | (double)(Math.Abs(v1-spline1d.spline1dcalc(c, v)))>(double)(nonstrictthreshold); } else { fiterrors = true; } lsfit.spline1dfitpenalizedw(x, y, w, 2, m, rho, ref info, c, rep); if( info>0 ) { v = 2*math.randomreal()-1; v1 = (v-x[0])/(x[1]-x[0])*y[1]+(v-x[1])/(x[0]-x[1])*y[0]; fiterrors = fiterrors | (double)(Math.Abs(v1-spline1d.spline1dcalc(c, v)))>(double)(nonstrictthreshold); } else { fiterrors = true; } // // spline fitting is invariant with respect to // scaling of weights (of course, ANY fitting algorithm // must be invariant, but we want to test this property // just to be sure that it is correctly implemented) // for(n=2; n<=2*m; n++) { x = new double[n]; y = new double[n]; w = new double[n]; w2 = new double[n]; s = 1+Math.Exp(10*math.randomreal()); for(i=0; i<=n-1; i++) { x[i] = (double)i/(double)(n-1); y[i] = math.randomreal(); w[i] = 0.1+math.randomreal(); w2[i] = w[i]*s; } lsfit.spline1dfitpenalizedw(x, y, w, n, m, rho, ref info, c, rep); lsfit.spline1dfitpenalizedw(x, y, w2, n, m, rho, ref info2, c2, rep2); if( info>0 & info2>0 ) { v = math.randomreal(); v1 = spline1d.spline1dcalc(c, v); v2 = spline1d.spline1dcalc(c2, v); fiterrors = fiterrors | (double)(Math.Abs(v1-v2))>(double)(nonstrictthreshold); } else { fiterrors = true; } } } } // // Advanced proprties: // * penalized spline with M about 5*N and sufficiently small Rho // must pass through all points on equidistant grid // for(n=2; n<=10; n++) { m = 5*n; rho = -5; x = new double[n]; y = new double[n]; w = new double[n]; for(i=0; i<=n-1; i++) { x[i] = (double)i/(double)(n-1); y[i] = math.randomreal(); w[i] = 0.1+math.randomreal(); } lsfit.spline1dfitpenalized(x, y, n, m, rho, ref info, c, rep); if( info>0 ) { for(i=0; i<=n-1; i++) { fiterrors = fiterrors | (double)(Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])))>(double)(nonstrictthreshold); } } else { fiterrors = true; } lsfit.spline1dfitpenalizedw(x, y, w, n, m, rho, ref info, c, rep); if( info>0 ) { for(i=0; i<=n-1; i++) { fiterrors = fiterrors | (double)(Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])))>(double)(nonstrictthreshold); } } else { fiterrors = true; } } // // Check correctness of error reports // for(pass=1; pass<=passcount; pass++) { ap.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 = math.randomreal(); v2 = math.randomreal(); v = 1+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((math.sqr(v1)+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 penalized spline // lsfit.spline1dfitpenalizedw(x, y, w, 4, 4, 0.0, ref info, c, rep); if( info<=0 ) { fiterrors = true; } else { s = spline1d.spline1dcalc(c, 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); } // // Test cubic fitting // lsfit.spline1dfitcubic(x, y, 4, 4, ref info, c, rep); if( info<=0 ) { fiterrors = true; } else { s = spline1d.spline1dcalc(c, 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); } // // Test Hermite fitting // lsfit.spline1dfithermite(x, y, 4, 4, ref info, c, rep); if( info<=0 ) { fiterrors = true; } else { s = spline1d.spline1dcalc(c, 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); } } }
public spline1dfitreport() { _innerobj = new lsfit.spline1dfitreport(); }