Exemple #1
0
    public static int Main(string[] args)
    {
        double[] x    = new double[0];
        double[] y    = new double[0];
        double[] w    = new double[0];
        double[] xc   = new double[0];
        double[] yc   = new double[0];
        int[]    dc   = new int[0];
        int      n    = 0;
        int      i    = 0;
        int      info = 0;

        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double t = 0;

        spline1d.spline1dfitreport rep = new spline1d.spline1dfitreport();


        //
        // Fitting by constrained Hermite spline
        //
        System.Console.Write("FITTING BY CONSTRAINED HERMITE SPLINE");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x)      function being fitted");
        System.Console.WriteLine();
        System.Console.Write("[0, pi]          interval");
        System.Console.WriteLine();
        System.Console.Write("M=6              number of basis functions to use");
        System.Console.WriteLine();
        System.Console.Write("S(0)=0           first constraint");
        System.Console.WriteLine();
        System.Console.Write("S(pi)=0          second constraint");
        System.Console.WriteLine();
        System.Console.Write("N=100            number of points to fit");
        System.Console.WriteLine();

        //
        // Create and fit:
        // * X  contains points
        // * Y  contains values
        // * W  contains weights
        // * XC contains constraints locations
        // * YC contains constraints values
        // * DC contains derivative indexes (0 = constrained function value)
        //
        n = 100;
        x = new double[n];
        y = new double[n];
        w = new double[n];
        for (i = 0; i <= n - 1; i++)
        {
            x[i] = Math.PI * i / (n - 1);
            y[i] = Math.Sin(x[i]);
            w[i] = 1;
        }
        xc    = new double[2];
        yc    = new double[2];
        dc    = new int[2];
        xc[0] = 0;
        yc[0] = 0;
        dc[0] = 0;
        xc[0] = Math.PI;
        yc[0] = 0;
        dc[0] = 0;
        spline1d.spline1dfithermitewc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 2, 6, ref info, ref s, ref rep);

        //
        // Output results
        //
        if (info > 0)
        {
            System.Console.WriteLine();
            System.Console.Write("OK, we have finished");
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("     x   F(x)   S(x)  Error");
            System.Console.WriteLine();
            t = 0;
            while ((double)(t) < (double)(0.999999 * Math.PI))
            {
                System.Console.Write("{0,6:F3}", t);
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}", Math.Sin(t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}", spline1d.spline1dcalc(ref s, t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}", Math.Abs(spline1d.spline1dcalc(ref s, t) - Math.Sin(t)));
                System.Console.WriteLine();
                t = Math.Min(Math.PI, t + 0.25);
            }
            System.Console.Write("{0,6:F3}", t);
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", Math.Sin(t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", spline1d.spline1dcalc(ref s, t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", Math.Abs(spline1d.spline1dcalc(ref s, t) - Math.Sin(t)));
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("rms error is ");
            System.Console.Write("{0,6:F3}", rep.rmserror);
            System.Console.WriteLine();
            System.Console.Write("max error is ");
            System.Console.Write("{0,6:F3}", rep.maxerror);
            System.Console.WriteLine();
            System.Console.Write("S(0) = S(pi) = 0 (exactly)");
            System.Console.WriteLine();
            System.Console.WriteLine();
        }
        else
        {
            System.Console.WriteLine();
            System.Console.Write("Something wrong, Info=");
            System.Console.Write("{0,0:d}", info);
        }
        return(0);
    }
Exemple #2
0
 public spline1dinterpolant(spline1d.spline1dinterpolant obj)
 {
     _innerobj = obj;
 }
Exemple #3
0
    public static int Main(string[] args)
    {
        double[] x = new double[0];
        double[] y = new double[0];
        double[] d = new double[0];
        int      n = 0;
        int      i = 0;
        double   t = 0;

        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double err    = 0;
        double maxerr = 0;


        //
        // Interpolation by natural Cubic spline.
        //
        System.Console.Write("INTERPOLATION BY HERMITE SPLINE");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x), [0, pi], 3 nodes");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("     x   F(x)   S(x)  Error");
        System.Console.WriteLine();

        //
        // Create spline
        //
        n = 3;
        x = new double[n];
        y = new double[n];
        d = new double[n];
        for (i = 0; i <= n - 1; i++)
        {
            x[i] = Math.PI * i / (n - 1);
            y[i] = Math.Sin(x[i]);
            d[i] = Math.Cos(x[i]);
        }
        spline1d.spline1dbuildhermite(x, y, d, n, ref s);

        //
        // Output results
        //
        t      = 0;
        maxerr = 0;
        while ((double)(t) < (double)(0.999999 * Math.PI))
        {
            err    = Math.Abs(spline1d.spline1dcalc(ref s, t) - Math.Sin(t));
            maxerr = Math.Max(err, maxerr);
            System.Console.Write("{0,6:F3}", t);
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", Math.Sin(t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", spline1d.spline1dcalc(ref s, t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", err);
            System.Console.WriteLine();
            t = Math.Min(Math.PI, t + 0.25);
        }
        err    = Math.Abs(spline1d.spline1dcalc(ref s, Math.PI) - Math.Sin(Math.PI));
        maxerr = Math.Max(err, maxerr);
        System.Console.Write("{0,6:F3}", Math.PI);
        System.Console.Write(" ");
        System.Console.Write("{0,6:F3}", Math.Sin(Math.PI));
        System.Console.Write(" ");
        System.Console.Write("{0,6:F3}", spline1d.spline1dcalc(ref s, Math.PI));
        System.Console.Write(" ");
        System.Console.Write("{0,6:F3}", err);
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("max|error| = ");
        System.Console.Write("{0,0:F3}", maxerr);
        System.Console.WriteLine();
        System.Console.Write("Try other demos (spline1d_linear, spline1d_cubic) and compare errors...");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.WriteLine();
        return(0);
    }
        public static bool testspline1d(bool silent)
        {
            bool result = new bool();
            bool waserrors = new bool();
            bool crserrors = new bool();
            bool cserrors = new bool();
            bool hserrors = new bool();
            bool aserrors = new bool();
            bool lserrors = new bool();
            bool dserrors = new bool();
            bool uperrors = new bool();
            bool cperrors = new bool();
            bool lterrors = new bool();
            bool ierrors = new bool();
            bool fiterrors = new bool();
            double nonstrictthreshold = 0;
            double threshold = 0;
            int passcount = 0;
            double lstep = 0;
            double h = 0;
            int maxn = 0;
            int bltype = 0;
            int brtype = 0;
            bool periodiccond = new bool();
            int n = 0;
            int m = 0;
            int i = 0;
            int k = 0;
            int pass = 0;
            int stype = 0;
            double[] x = new double[0];
            double[] y = new double[0];
            double[] yp = new double[0];
            double[] w = new double[0];
            double[] w2 = new double[0];
            double[] y2 = new double[0];
            double[] d = new double[0];
            double[] xc = new double[0];
            double[] yc = new double[0];
            int n2 = 0;
            double[] tmp0 = new double[0];
            double[] tmp1 = new double[0];
            double[] tmp2 = new double[0];
            double[] tmpx = new double[0];
            int[] dc = new int[0];
            spline1d.spline1dinterpolant c = new spline1d.spline1dinterpolant();
            spline1d.spline1dinterpolant c2 = new spline1d.spline1dinterpolant();
            int info = 0;
            int info1 = 0;
            int info2 = 0;
            double a = 0;
            double b = 0;
            double bl = 0;
            double br = 0;
            double t = 0;
            double sa = 0;
            double sb = 0;
            double v = 0;
            double v1 = 0;
            double v2 = 0;
            double l10 = 0;
            double l11 = 0;
            double l12 = 0;
            double l20 = 0;
            double l21 = 0;
            double l22 = 0;
            double p0 = 0;
            double p1 = 0;
            double p2 = 0;
            double s = 0;
            double ds = 0;
            double d2s = 0;
            double s2 = 0;
            double ds2 = 0;
            double d2s2 = 0;
            double vl = 0;
            double vm = 0;
            double vr = 0;
            double err = 0;
            double tension = 0;
            double intab = 0;
            spline1d.spline1dfitreport rep = new spline1d.spline1dfitreport();
            spline1d.spline1dfitreport rep2 = new spline1d.spline1dfitreport();
            double refrms = 0;
            double refavg = 0;
            double refavgrel = 0;
            double refmax = 0;
            int i_ = 0;

            waserrors = false;
            passcount = 20;
            lstep = 0.005;
            h = 0.00001;
            maxn = 10;
            threshold = 10000*math.machineepsilon;
            nonstrictthreshold = 0.00001;
            lserrors = false;
            cserrors = false;
            crserrors = false;
            hserrors = false;
            aserrors = false;
            dserrors = false;
            cperrors = false;
            uperrors = false;
            lterrors = false;
            ierrors = false;
            fiterrors = false;
            
            //
            // General test: linear, cubic, Hermite, Akima
            //
            for(n=2; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                yp = new double[n-1+1];
                d = new double[n-1+1];
                for(pass=1; pass<=passcount; pass++)
                {
                    
                    //
                    // Prepare task:
                    // * X contains abscissas from [A,B]
                    // * Y contains function values
                    // * YP contains periodic function values
                    //
                    a = -1-math.randomreal();
                    b = 1+math.randomreal();
                    bl = 2*math.randomreal()-1;
                    br = 2*math.randomreal()-1;
                    for(i=0; i<=n-1; i++)
                    {
                        x[i] = 0.5*(b+a)+0.5*(b-a)*Math.Cos(Math.PI*(2*i+1)/(2*n));
                        if( i==0 )
                        {
                            x[i] = a;
                        }
                        if( i==n-1 )
                        {
                            x[i] = b;
                        }
                        y[i] = Math.Cos(1.3*Math.PI*x[i]+0.4);
                        yp[i] = y[i];
                        d[i] = -(1.3*Math.PI*Math.Sin(1.3*Math.PI*x[i]+0.4));
                    }
                    yp[n-1] = yp[0];
                    for(i=0; i<=n-1; i++)
                    {
                        k = 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 = yp[i];
                            yp[i] = yp[k];
                            yp[k] = t;
                            t = d[i];
                            d[i] = d[k];
                            d[k] = t;
                        }
                    }
                    
                    //
                    // Build linear spline
                    // Test for general interpolation scheme properties:
                    // * values at nodes
                    // * continuous function
                    // Test for specific properties is implemented below.
                    //
                    spline1d.spline1dbuildlinear(x, y, n, c);
                    err = 0;
                    for(i=0; i<=n-1; i++)
                    {
                        err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                    }
                    lserrors = lserrors | (double)(err)>(double)(threshold);
                    lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                    lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                    lserrors = lserrors | (double)(l20/l10)>(double)(1.2);
                    
                    //
                    // Build cubic spline.
                    // Test for interpolation scheme properties:
                    // * values at nodes
                    // * boundary conditions
                    // * continuous function
                    // * continuous first derivative
                    // * continuous second derivative
                    // * periodicity properties
                    // * Spline1DGridDiff(), Spline1DGridDiff2() and Spline1DDiff()
                    //   calls must return same results
                    //
                    for(bltype=-1; bltype<=2; bltype++)
                    {
                        for(brtype=-1; brtype<=2; brtype++)
                        {
                            
                            //
                            // skip meaningless combination of boundary conditions
                            // (one condition is periodic, another is not)
                            //
                            periodiccond = bltype==-1 | brtype==-1;
                            if( periodiccond & bltype!=brtype )
                            {
                                continue;
                            }
                            
                            //
                            // build
                            //
                            if( periodiccond )
                            {
                                spline1d.spline1dbuildcubic(x, yp, n, bltype, bl, brtype, br, c);
                            }
                            else
                            {
                                spline1d.spline1dbuildcubic(x, y, n, bltype, bl, brtype, br, c);
                            }
                            
                            //
                            // interpolation properties
                            //
                            err = 0;
                            if( periodiccond )
                            {
                                
                                //
                                // * check values at nodes; spline is periodic so
                                //   we add random number of periods to nodes
                                // * we also test for periodicity of derivatives
                                //
                                for(i=0; i<=n-1; i++)
                                {
                                    v = x[i];
                                    vm = v+(b-a)*(math.randominteger(5)-2);
                                    t = yp[i]-spline1d.spline1dcalc(c, vm);
                                    err = Math.Max(err, Math.Abs(t));
                                    spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                                    spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                                    err = Math.Max(err, Math.Abs(s-s2));
                                    err = Math.Max(err, Math.Abs(ds-ds2));
                                    err = Math.Max(err, Math.Abs(d2s-d2s2));
                                }
                                
                                //
                                // periodicity between nodes
                                //
                                v = a+(b-a)*math.randomreal();
                                vm = v+(b-a)*(math.randominteger(5)-2);
                                err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, v)-spline1d.spline1dcalc(c, vm)));
                                spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                                err = Math.Max(err, Math.Abs(s-s2));
                                err = Math.Max(err, Math.Abs(ds-ds2));
                                err = Math.Max(err, Math.Abs(d2s-d2s2));
                            }
                            else
                            {
                                
                                //
                                // * check values at nodes
                                //
                                for(i=0; i<=n-1; i++)
                                {
                                    err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                                }
                            }
                            cserrors = cserrors | (double)(err)>(double)(threshold);
                            
                            //
                            // check boundary conditions
                            //
                            err = 0;
                            if( bltype==0 )
                            {
                                spline1d.spline1ddiff(c, a-h, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, a+h, ref s2, ref ds2, ref d2s2);
                                t = (d2s2-d2s)/(2*h);
                                err = Math.Max(err, Math.Abs(t));
                            }
                            if( bltype==1 )
                            {
                                t = (spline1d.spline1dcalc(c, a+h)-spline1d.spline1dcalc(c, a-h))/(2*h);
                                err = Math.Max(err, Math.Abs(bl-t));
                            }
                            if( bltype==2 )
                            {
                                t = (spline1d.spline1dcalc(c, a+h)-2*spline1d.spline1dcalc(c, a)+spline1d.spline1dcalc(c, a-h))/math.sqr(h);
                                err = Math.Max(err, Math.Abs(bl-t));
                            }
                            if( brtype==0 )
                            {
                                spline1d.spline1ddiff(c, b-h, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, b+h, ref s2, ref ds2, ref d2s2);
                                t = (d2s2-d2s)/(2*h);
                                err = Math.Max(err, Math.Abs(t));
                            }
                            if( brtype==1 )
                            {
                                t = (spline1d.spline1dcalc(c, b+h)-spline1d.spline1dcalc(c, b-h))/(2*h);
                                err = Math.Max(err, Math.Abs(br-t));
                            }
                            if( brtype==2 )
                            {
                                t = (spline1d.spline1dcalc(c, b+h)-2*spline1d.spline1dcalc(c, b)+spline1d.spline1dcalc(c, b-h))/math.sqr(h);
                                err = Math.Max(err, Math.Abs(br-t));
                            }
                            if( bltype==-1 | brtype==-1 )
                            {
                                spline1d.spline1ddiff(c, a+100*math.machineepsilon, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, b-100*math.machineepsilon, ref s2, ref ds2, ref d2s2);
                                err = Math.Max(err, Math.Abs(s-s2));
                                err = Math.Max(err, Math.Abs(ds-ds2));
                                err = Math.Max(err, Math.Abs(d2s-d2s2));
                            }
                            cserrors = cserrors | (double)(err)>(double)(1.0E-3);
                            
                            //
                            // Check Lipschitz continuity
                            //
                            lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                            lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                            if( (double)(l10)>(double)(1.0E-6) )
                            {
                                cserrors = cserrors | (double)(l20/l10)>(double)(1.2);
                            }
                            if( (double)(l11)>(double)(1.0E-6) )
                            {
                                cserrors = cserrors | (double)(l21/l11)>(double)(1.2);
                            }
                            if( (double)(l12)>(double)(1.0E-6) )
                            {
                                cserrors = cserrors | (double)(l22/l12)>(double)(1.2);
                            }
                            
                            //
                            // compare spline1dgriddiff() and spline1ddiff() results
                            //
                            err = 0;
                            if( periodiccond )
                            {
                                spline1d.spline1dgriddiffcubic(x, yp, n, bltype, bl, brtype, br, ref tmp1);
                            }
                            else
                            {
                                spline1d.spline1dgriddiffcubic(x, y, n, bltype, bl, brtype, br, ref tmp1);
                            }
                            ap.assert(ap.len(tmp1)>=n);
                            for(i=0; i<=n-1; i++)
                            {
                                spline1d.spline1ddiff(c, x[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                            }
                            if( periodiccond )
                            {
                                spline1d.spline1dgriddiff2cubic(x, yp, n, bltype, bl, brtype, br, ref tmp1, ref tmp2);
                            }
                            else
                            {
                                spline1d.spline1dgriddiff2cubic(x, y, n, bltype, bl, brtype, br, ref tmp1, ref tmp2);
                            }
                            for(i=0; i<=n-1; i++)
                            {
                                spline1d.spline1ddiff(c, x[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                                err = Math.Max(err, Math.Abs(d2s-tmp2[i]));
                            }
                            cserrors = cserrors | (double)(err)>(double)(threshold);
                            
                            //
                            // compare spline1dconv()/convdiff()/convdiff2() and spline1ddiff() results
                            //
                            n2 = 2*n+math.randominteger(n);
                            tmpx = new double[n2];
                            for(i=0; i<=n2-1; i++)
                            {
                                tmpx[i] = 0.5*(a+b)+(a-b)*(2*math.randomreal()-1);
                            }
                            err = 0;
                            if( periodiccond )
                            {
                                spline1d.spline1dconvcubic(x, yp, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0);
                            }
                            else
                            {
                                spline1d.spline1dconvcubic(x, y, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0);
                            }
                            for(i=0; i<=n2-1; i++)
                            {
                                spline1d.spline1ddiff(c, tmpx[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(s-tmp0[i]));
                            }
                            if( periodiccond )
                            {
                                spline1d.spline1dconvdiffcubic(x, yp, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1);
                            }
                            else
                            {
                                spline1d.spline1dconvdiffcubic(x, y, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1);
                            }
                            for(i=0; i<=n2-1; i++)
                            {
                                spline1d.spline1ddiff(c, tmpx[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(s-tmp0[i]));
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                            }
                            if( periodiccond )
                            {
                                spline1d.spline1dconvdiff2cubic(x, yp, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1, ref tmp2);
                            }
                            else
                            {
                                spline1d.spline1dconvdiff2cubic(x, y, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1, ref tmp2);
                            }
                            for(i=0; i<=n2-1; i++)
                            {
                                spline1d.spline1ddiff(c, tmpx[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(s-tmp0[i]));
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                                err = Math.Max(err, Math.Abs(d2s-tmp2[i]));
                            }
                            cserrors = cserrors | (double)(err)>(double)(threshold);
                        }
                    }
                    
                    //
                    // Build Catmull-Rom spline.
                    // Test for interpolation scheme properties:
                    // * values at nodes
                    // * boundary conditions
                    // * continuous function
                    // * continuous first derivative
                    // * periodicity properties
                    //
                    for(bltype=-1; bltype<=0; bltype++)
                    {
                        periodiccond = bltype==-1;
                        
                        //
                        // select random tension value, then build
                        //
                        if( (double)(math.randomreal())>(double)(0.5) )
                        {
                            if( (double)(math.randomreal())>(double)(0.5) )
                            {
                                tension = 0;
                            }
                            else
                            {
                                tension = 1;
                            }
                        }
                        else
                        {
                            tension = math.randomreal();
                        }
                        if( periodiccond )
                        {
                            spline1d.spline1dbuildcatmullrom(x, yp, n, bltype, tension, c);
                        }
                        else
                        {
                            spline1d.spline1dbuildcatmullrom(x, y, n, bltype, tension, c);
                        }
                        
                        //
                        // interpolation properties
                        //
                        err = 0;
                        if( periodiccond )
                        {
                            
                            //
                            // * check values at nodes; spline is periodic so
                            //   we add random number of periods to nodes
                            // * we also test for periodicity of first derivative
                            //
                            for(i=0; i<=n-1; i++)
                            {
                                v = x[i];
                                vm = v+(b-a)*(math.randominteger(5)-2);
                                t = yp[i]-spline1d.spline1dcalc(c, vm);
                                err = Math.Max(err, Math.Abs(t));
                                spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                                err = Math.Max(err, Math.Abs(s-s2));
                                err = Math.Max(err, Math.Abs(ds-ds2));
                            }
                            
                            //
                            // periodicity between nodes
                            //
                            v = a+(b-a)*math.randomreal();
                            vm = v+(b-a)*(math.randominteger(5)-2);
                            err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, v)-spline1d.spline1dcalc(c, vm)));
                            spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                            err = Math.Max(err, Math.Abs(s-s2));
                            err = Math.Max(err, Math.Abs(ds-ds2));
                        }
                        else
                        {
                            
                            //
                            // * check values at nodes
                            //
                            for(i=0; i<=n-1; i++)
                            {
                                err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                            }
                        }
                        crserrors = crserrors | (double)(err)>(double)(threshold);
                        
                        //
                        // check boundary conditions
                        //
                        err = 0;
                        if( bltype==0 )
                        {
                            spline1d.spline1ddiff(c, a-h, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, a+h, ref s2, ref ds2, ref d2s2);
                            t = (d2s2-d2s)/(2*h);
                            err = Math.Max(err, Math.Abs(t));
                            spline1d.spline1ddiff(c, b-h, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, b+h, ref s2, ref ds2, ref d2s2);
                            t = (d2s2-d2s)/(2*h);
                            err = Math.Max(err, Math.Abs(t));
                        }
                        if( bltype==-1 )
                        {
                            spline1d.spline1ddiff(c, a+100*math.machineepsilon, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, b-100*math.machineepsilon, ref s2, ref ds2, ref d2s2);
                            err = Math.Max(err, Math.Abs(s-s2));
                            err = Math.Max(err, Math.Abs(ds-ds2));
                        }
                        crserrors = crserrors | (double)(err)>(double)(1.0E-3);
                        
                        //
                        // Check Lipschitz continuity
                        //
                        lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                        lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                        if( (double)(l10)>(double)(1.0E-6) )
                        {
                            crserrors = crserrors | (double)(l20/l10)>(double)(1.2);
                        }
                        if( (double)(l11)>(double)(1.0E-6) )
                        {
                            crserrors = crserrors | (double)(l21/l11)>(double)(1.2);
                        }
                    }
                    
                    //
                    // Build Hermite spline.
                    // Test for interpolation scheme properties:
                    // * values and derivatives at nodes
                    // * continuous function
                    // * continuous first derivative
                    //
                    spline1d.spline1dbuildhermite(x, y, d, n, c);
                    err = 0;
                    for(i=0; i<=n-1; i++)
                    {
                        err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                    }
                    hserrors = hserrors | (double)(err)>(double)(threshold);
                    err = 0;
                    for(i=0; i<=n-1; i++)
                    {
                        t = (spline1d.spline1dcalc(c, x[i]+h)-spline1d.spline1dcalc(c, x[i]-h))/(2*h);
                        err = Math.Max(err, Math.Abs(d[i]-t));
                    }
                    hserrors = hserrors | (double)(err)>(double)(1.0E-3);
                    lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                    lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                    hserrors = hserrors | (double)(l20/l10)>(double)(1.2);
                    hserrors = hserrors | (double)(l21/l11)>(double)(1.2);
                    
                    //
                    // Build Akima spline
                    // Test for general interpolation scheme properties:
                    // * values at nodes
                    // * continuous function
                    // * continuous first derivative
                    // Test for specific properties is implemented below.
                    //
                    if( n>=5 )
                    {
                        spline1d.spline1dbuildakima(x, y, n, c);
                        err = 0;
                        for(i=0; i<=n-1; i++)
                        {
                            err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                        }
                        aserrors = aserrors | (double)(err)>(double)(threshold);
                        lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                        lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                        hserrors = hserrors | (double)(l20/l10)>(double)(1.2);
                        hserrors = hserrors | (double)(l21/l11)>(double)(1.2);
                    }
                }
            }
            
            //
            // Special linear spline test:
            // test for linearity between x[i] and x[i+1]
            //
            for(n=2; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                
                //
                // Prepare task
                //
                a = -1;
                b = 1;
                for(i=0; i<=n-1; i++)
                {
                    x[i] = a+(b-a)*i/(n-1);
                    y[i] = 2*math.randomreal()-1;
                }
                spline1d.spline1dbuildlinear(x, y, n, c);
                
                //
                // Test
                //
                err = 0;
                for(k=0; k<=n-2; k++)
                {
                    a = x[k];
                    b = x[k+1];
                    for(pass=1; pass<=passcount; pass++)
                    {
                        t = a+(b-a)*math.randomreal();
                        v = y[k]+(t-a)/(b-a)*(y[k+1]-y[k]);
                        err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-v));
                    }
                }
                lserrors = lserrors | (double)(err)>(double)(threshold);
            }
            
            //
            // Special Akima test: test outlier sensitivity
            // Spline value at (x[i], x[i+1]) should depend from
            // f[i-2], f[i-1], f[i], f[i+1], f[i+2], f[i+3] only.
            //
            for(n=5; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                y2 = new double[n-1+1];
                
                //
                // Prepare unperturbed Akima spline
                //
                a = -1;
                b = 1;
                for(i=0; i<=n-1; i++)
                {
                    x[i] = a+(b-a)*i/(n-1);
                    y[i] = Math.Cos(1.3*Math.PI*x[i]+0.4);
                }
                spline1d.spline1dbuildakima(x, y, n, c);
                
                //
                // Process perturbed tasks
                //
                err = 0;
                for(k=0; k<=n-1; k++)
                {
                    for(i_=0; i_<=n-1;i_++)
                    {
                        y2[i_] = y[i_];
                    }
                    y2[k] = 5;
                    spline1d.spline1dbuildakima(x, y2, n, c2);
                    
                    //
                    // Test left part independence
                    //
                    if( k-3>=1 )
                    {
                        a = -1;
                        b = x[k-3];
                        for(pass=1; pass<=passcount; pass++)
                        {
                            t = a+(b-a)*math.randomreal();
                            err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, t)));
                        }
                    }
                    
                    //
                    // Test right part independence
                    //
                    if( k+3<=n-2 )
                    {
                        a = x[k+3];
                        b = 1;
                        for(pass=1; pass<=passcount; pass++)
                        {
                            t = a+(b-a)*math.randomreal();
                            err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, t)));
                        }
                    }
                }
                aserrors = aserrors | (double)(err)>(double)(threshold);
            }
            
            //
            // Differentiation, copy/unpack test
            //
            for(n=2; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                
                //
                // Prepare cubic spline
                //
                a = -1-math.randomreal();
                b = 1+math.randomreal();
                for(i=0; i<=n-1; i++)
                {
                    x[i] = a+(b-a)*i/(n-1);
                    y[i] = Math.Cos(1.3*Math.PI*x[i]+0.4);
                }
                spline1d.spline1dbuildcubic(x, y, n, 2, 0.0, 2, 0.0, c);
                
                //
                // Test diff
                //
                err = 0;
                for(pass=1; pass<=passcount; pass++)
                {
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1ddiff(c, t, ref s, ref ds, ref d2s);
                    vl = spline1d.spline1dcalc(c, t-h);
                    vm = spline1d.spline1dcalc(c, t);
                    vr = spline1d.spline1dcalc(c, t+h);
                    err = Math.Max(err, Math.Abs(s-vm));
                    err = Math.Max(err, Math.Abs(ds-(vr-vl)/(2*h)));
                    err = Math.Max(err, Math.Abs(d2s-(vr-2*vm+vl)/math.sqr(h)));
                }
                dserrors = dserrors | (double)(err)>(double)(0.001);
                
                //
                // Test copy
                //
                unsetspline1d(c2);
                spline1d.spline1dcopy(c, c2);
                err = 0;
                for(pass=1; pass<=passcount; pass++)
                {
                    t = a+(b-a)*math.randomreal();
                    err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, t)));
                }
                cperrors = cperrors | (double)(err)>(double)(threshold);
                
                //
                // Test unpack
                //
                uperrors = uperrors | !testunpack(c, x);
                
                //
                // Test lin.trans.
                //
                err = 0;
                for(pass=1; pass<=passcount; pass++)
                {
                    
                    //
                    // LinTransX, general A
                    //
                    sa = 4*math.randomreal()-2;
                    sb = 2*math.randomreal()-1;
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1dcopy(c, c2);
                    spline1d.spline1dlintransx(c2, sa, sb);
                    err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, (t-sb)/sa)));
                    
                    //
                    // LinTransX, special case: A=0
                    //
                    sb = 2*math.randomreal()-1;
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1dcopy(c, c2);
                    spline1d.spline1dlintransx(c2, 0, sb);
                    err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, sb)-spline1d.spline1dcalc(c2, t)));
                    
                    //
                    // LinTransY
                    //
                    sa = 2*math.randomreal()-1;
                    sb = 2*math.randomreal()-1;
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1dcopy(c, c2);
                    spline1d.spline1dlintransy(c2, sa, sb);
                    err = Math.Max(err, Math.Abs(sa*spline1d.spline1dcalc(c, t)+sb-spline1d.spline1dcalc(c2, t)));
                }
                lterrors = lterrors | (double)(err)>(double)(threshold);
            }
            
            //
            // Testing integration.
            // Three tests are performed:
            //
            // * approximate test (well behaved smooth function, many points,
            //   integration inside [a,b]), non-periodic spline
            //
            // * exact test (integration of parabola, outside of [a,b], non-periodic spline
            //
            // * approximate test for periodic splines. F(x)=cos(2*pi*x)+1.
            //   Period length is equals to 1.0, so all operations with
            //   multiples of period are done exactly. For each value of PERIOD
            //   we calculate and test integral at four points:
            //   -   0 < t0 < PERIOD
            //   -   t1 = PERIOD-eps
            //   -   t2 = PERIOD
            //   -   t3 = PERIOD+eps
            //
            err = 0;
            for(n=20; n<=35; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                for(pass=1; pass<=passcount; pass++)
                {
                    
                    //
                    // Prepare cubic spline
                    //
                    a = -1-0.2*math.randomreal();
                    b = 1+0.2*math.randomreal();
                    for(i=0; i<=n-1; i++)
                    {
                        x[i] = a+(b-a)*i/(n-1);
                        y[i] = Math.Sin(Math.PI*x[i]+0.4)+Math.Exp(x[i]);
                    }
                    bl = Math.PI*Math.Cos(Math.PI*a+0.4)+Math.Exp(a);
                    br = Math.PI*Math.Cos(Math.PI*b+0.4)+Math.Exp(b);
                    spline1d.spline1dbuildcubic(x, y, n, 1, bl, 1, br, c);
                    
                    //
                    // Test
                    //
                    t = a+(b-a)*math.randomreal();
                    v = -(Math.Cos(Math.PI*a+0.4)/Math.PI)+Math.Exp(a);
                    v = -(Math.Cos(Math.PI*t+0.4)/Math.PI)+Math.Exp(t)-v;
                    v = v-spline1d.spline1dintegrate(c, t);
                    err = Math.Max(err, Math.Abs(v));
                }
            }
            ierrors = ierrors | (double)(err)>(double)(0.001);
            p0 = 2*math.randomreal()-1;
            p1 = 2*math.randomreal()-1;
            p2 = 2*math.randomreal()-1;
            a = -math.randomreal()-0.5;
            b = math.randomreal()+0.5;
            n = 2;
            x = new double[n];
            y = new double[n];
            d = new double[n];
            x[0] = a;
            y[0] = p0+p1*a+p2*math.sqr(a);
            d[0] = p1+2*p2*a;
            x[1] = b;
            y[1] = p0+p1*b+p2*math.sqr(b);
            d[1] = p1+2*p2*b;
            spline1d.spline1dbuildhermite(x, y, d, n, c);
            bl = Math.Min(a, b)-Math.Abs(b-a);
            br = Math.Min(a, b)+Math.Abs(b-a);
            err = 0;
            for(pass=1; pass<=100; pass++)
            {
                t = bl+(br-bl)*math.randomreal();
                v = p0*t+p1*math.sqr(t)/2+p2*math.sqr(t)*t/3-(p0*a+p1*math.sqr(a)/2+p2*math.sqr(a)*a/3);
                v = v-spline1d.spline1dintegrate(c, t);
                err = Math.Max(err, Math.Abs(v));
            }
            ierrors = ierrors | (double)(err)>(double)(threshold);
            n = 100;
            x = new double[n];
            y = new double[n];
            for(i=0; i<=n-1; i++)
            {
                x[i] = (double)i/(double)(n-1);
                y[i] = Math.Cos(2*Math.PI*x[i])+1;
            }
            y[0] = 2;
            y[n-1] = 2;
            spline1d.spline1dbuildcubic(x, y, n, -1, 0.0, -1, 0.0, c);
            intab = spline1d.spline1dintegrate(c, 1.0);
            v = math.randomreal();
            vr = spline1d.spline1dintegrate(c, v);
            ierrors = ierrors | (double)(Math.Abs(intab-1))>(double)(0.001);
            for(i=-10; i<=10; i++)
            {
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i+v)-(i*intab+vr)))>(double)(0.001);
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i-1000*math.machineepsilon)-i*intab))>(double)(0.001);
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i)-i*intab))>(double)(0.001);
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i+1000*math.machineepsilon)-i*intab))>(double)(0.001);
            }
            
            //
            // Test fitting.
            //
            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;
                        spline1d.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);
                    spline1d.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;
                        spline1d.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);
                    spline1d.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 )
                        {
                            spline1d.spline1dfitcubicwc(x, y, w, 2*n, xc, yc, dc, 0, m, ref info, c, rep);
                        }
                        if( stype==1 )
                        {
                            spline1d.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 )
                    {
                        spline1d.spline1dfitcubicwc(x, y, w, n, xc, yc, dc, 0, m, ref info1, c, rep);
                        spline1d.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 )
                    {
                        spline1d.spline1dfithermitewc(x, y, w, n, xc, yc, dc, 0, m, ref info1, c, rep);
                        spline1d.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);
                            }
                        }
                    }
                }
            }
            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 cubic fitting
                //
                spline1d.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 cubic fitting
                //
                spline1d.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);
                }
            }
            
            //
            // report
            //
            waserrors = (((((((((lserrors | cserrors) | crserrors) | hserrors) | aserrors) | dserrors) | cperrors) | uperrors) | lterrors) | ierrors) | fiterrors;
            if( !silent )
            {
                System.Console.Write("TESTING SPLINE INTERPOLATION");
                System.Console.WriteLine();
                
                //
                // Normal tests
                //
                System.Console.Write("LINEAR SPLINE TEST:                      ");
                if( lserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("CUBIC SPLINE TEST:                       ");
                if( cserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("CATMULL-ROM SPLINE TEST:                 ");
                if( crserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("HERMITE SPLINE TEST:                     ");
                if( hserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("AKIMA SPLINE TEST:                       ");
                if( aserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("DIFFERENTIATION TEST:                    ");
                if( dserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("COPY/SERIALIZATION TEST:                 ");
                if( cperrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("UNPACK TEST:                             ");
                if( uperrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("LIN.TRANS. TEST:                         ");
                if( lterrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("INTEGRATION TEST:                        ");
                if( ierrors )
                {
                    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;
        }
Exemple #5
0
        //
        // Public declarations
        //

        public spline1dinterpolant()
        {
            _innerobj = new spline1d.spline1dinterpolant();
        }
        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 static int Main(string[] args)
    {
        double[] x    = new double[0];
        double[] y    = new double[0];
        int      n    = 0;
        int      i    = 0;
        int      info = 0;

        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double t = 0;

        spline1d.spline1dfitreport rep = new spline1d.spline1dfitreport();


        //
        // Fitting by unconstrained natural cubic spline
        //
        System.Console.Write("FITTING BY UNCONSTRAINED NATURAL CUBIC SPLINE");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x)      function being fitted");
        System.Console.WriteLine();
        System.Console.Write("[0, pi]          interval");
        System.Console.WriteLine();
        System.Console.Write("M=4              number of basis functions to use");
        System.Console.WriteLine();
        System.Console.Write("N=100            number of points to fit");
        System.Console.WriteLine();

        //
        // Create and fit
        //
        n = 100;
        x = new double[n];
        y = new double[n];
        for (i = 0; i <= n - 1; i++)
        {
            x[i] = Math.PI * i / (n - 1);
            y[i] = Math.Sin(x[i]);
        }
        spline1d.spline1dfitcubic(ref x, ref y, n, 4, ref info, ref s, ref rep);

        //
        // Output results
        //
        if (info > 0)
        {
            System.Console.WriteLine();
            System.Console.Write("OK, we have finished");
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("     x   F(x)   S(x)  Error");
            System.Console.WriteLine();
            t = 0;
            while ((double)(t) < (double)(0.999999 * Math.PI))
            {
                System.Console.Write("{0,6:F3}", t);
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}", Math.Sin(t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}", spline1d.spline1dcalc(ref s, t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}", Math.Abs(spline1d.spline1dcalc(ref s, t) - Math.Sin(t)));
                System.Console.WriteLine();
                t = Math.Min(Math.PI, t + 0.25);
            }
            System.Console.Write("{0,6:F3}", t);
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", Math.Sin(t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", spline1d.spline1dcalc(ref s, t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}", Math.Abs(spline1d.spline1dcalc(ref s, t) - Math.Sin(t)));
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("rms error is ");
            System.Console.Write("{0,6:F3}", rep.rmserror);
            System.Console.WriteLine();
            System.Console.Write("max error is ");
            System.Console.Write("{0,6:F3}", rep.maxerror);
            System.Console.WriteLine();
        }
        else
        {
            System.Console.WriteLine();
            System.Console.Write("Something wrong, Info=");
            System.Console.Write("{0,0:d}", info);
        }
        return(0);
    }
Exemple #8
0
        /*************************************************************************
        Weighted fitting by penalized cubic spline.

        Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
        basis functions. Basis functions are cubic splines with  natural  boundary
        conditions. Problem is regularized by  adding non-linearity penalty to the
        usual least squares penalty function:

            S(x) = arg min { LS + P }, where
            LS   = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty
            P    = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty
            rho  - tunable constant given by user
            C    - automatically determined scale parameter,
                   makes penalty invariant with respect to scaling of X, Y, W.

        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
                    problem.
            N   -   number of points (optional):
                    * N>0
                    * if given, only first N elements of X/Y/W are processed
                    * if not given, automatically determined from X/Y/W sizes
            M   -   number of basis functions ( = number_of_nodes), M>=4.
            Rho -   regularization  constant  passed   by   user.   It   penalizes
                    nonlinearity in the regression spline. It  is  logarithmically
                    scaled,  i.e.  actual  value  of  regularization  constant  is
                    calculated as 10^Rho. It is automatically scaled so that:
                    * Rho=2.0 corresponds to moderate amount of nonlinearity
                    * generally, it should be somewhere in the [-8.0,+8.0]
                    If you do not want to penalize nonlineary,
                    pass small Rho. Values as low as -15 should work.

        OUTPUT PARAMETERS:
            Info-   same format as in LSFitLinearWC() subroutine.
                    * Info>0    task is solved
                    * Info<=0   an error occured:
                                -4 means inconvergence of internal SVD or
                                   Cholesky decomposition; problem may be
                                   too ill-conditioned (very rare)
            S   -   spline interpolant.
            Rep -   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.

        NOTE 1: additional nodes are added to the spline outside  of  the  fitting
        interval to force linearity when x<min(x,xc) or x>max(x,xc).  It  is  done
        for consistency - we penalize non-linearity  at [min(x,xc),max(x,xc)],  so
        it is natural to force linearity outside of this interval.

        NOTE 2: function automatically sorts points,  so  caller may pass unsorted
        array.

          -- ALGLIB PROJECT --
             Copyright 19.10.2010 by Bochkanov Sergey
        *************************************************************************/
        public static void spline1dfitpenalizedw(double[] x,
            double[] y,
            double[] w,
            int n,
            int m,
            double rho,
            ref int info,
            spline1d.spline1dinterpolant s,
            spline1dfitreport rep)
        {
            int i = 0;
            int j = 0;
            int b = 0;
            double v = 0;
            double relcnt = 0;
            double xa = 0;
            double xb = 0;
            double sa = 0;
            double sb = 0;
            double[] xoriginal = new double[0];
            double[] yoriginal = new double[0];
            double pdecay = 0;
            double tdecay = 0;
            double[,] fmatrix = new double[0,0];
            double[] fcolumn = new double[0];
            double[] y2 = new double[0];
            double[] w2 = new double[0];
            double[] xc = new double[0];
            double[] yc = new double[0];
            int[] dc = new int[0];
            double fdmax = 0;
            double admax = 0;
            double[,] amatrix = new double[0,0];
            double[,] d2matrix = new double[0,0];
            double fa = 0;
            double ga = 0;
            double fb = 0;
            double gb = 0;
            double lambdav = 0;
            double[] bx = new double[0];
            double[] by = new double[0];
            double[] bd1 = new double[0];
            double[] bd2 = new double[0];
            double[] tx = new double[0];
            double[] ty = new double[0];
            double[] td = new double[0];
            spline1d.spline1dinterpolant bs = new spline1d.spline1dinterpolant();
            double[,] nmatrix = new double[0,0];
            double[] rightpart = new double[0];
            fbls.fblslincgstate cgstate = new fbls.fblslincgstate();
            double[] c = new double[0];
            double[] tmp0 = new double[0];
            int i_ = 0;
            int i1_ = 0;

            x = (double[])x.Clone();
            y = (double[])y.Clone();
            w = (double[])w.Clone();
            info = 0;

            alglib.ap.assert(n>=1, "Spline1DFitPenalizedW: N<1!");
            alglib.ap.assert(m>=4, "Spline1DFitPenalizedW: M<4!");
            alglib.ap.assert(alglib.ap.len(x)>=n, "Spline1DFitPenalizedW: Length(X)<N!");
            alglib.ap.assert(alglib.ap.len(y)>=n, "Spline1DFitPenalizedW: Length(Y)<N!");
            alglib.ap.assert(alglib.ap.len(w)>=n, "Spline1DFitPenalizedW: Length(W)<N!");
            alglib.ap.assert(apserv.isfinitevector(x, n), "Spline1DFitPenalizedW: X contains infinite or NAN values!");
            alglib.ap.assert(apserv.isfinitevector(y, n), "Spline1DFitPenalizedW: Y contains infinite or NAN values!");
            alglib.ap.assert(apserv.isfinitevector(w, n), "Spline1DFitPenalizedW: Y contains infinite or NAN values!");
            alglib.ap.assert(math.isfinite(rho), "Spline1DFitPenalizedW: Rho is infinite!");
            
            //
            // Prepare LambdaV
            //
            v = -(Math.Log(math.machineepsilon)/Math.Log(10));
            if( (double)(rho)<(double)(-v) )
            {
                rho = -v;
            }
            if( (double)(rho)>(double)(v) )
            {
                rho = v;
            }
            lambdav = Math.Pow(10, rho);
            
            //
            // Sort X, Y, W
            //
            spline1d.heapsortdpoints(ref x, ref y, ref w, n);
            
            //
            // Scale X, Y, XC, YC
            //
            lsfitscalexy(ref x, ref y, ref w, n, ref xc, ref yc, dc, 0, ref xa, ref xb, ref sa, ref sb, ref xoriginal, ref yoriginal);
            
            //
            // Allocate space
            //
            fmatrix = new double[n, m];
            amatrix = new double[m, m];
            d2matrix = new double[m, m];
            bx = new double[m];
            by = new double[m];
            fcolumn = new double[n];
            nmatrix = new double[m, m];
            rightpart = new double[m];
            tmp0 = new double[Math.Max(m, n)];
            c = new double[m];
            
            //
            // Fill:
            // * FMatrix by values of basis functions
            // * TmpAMatrix by second derivatives of I-th function at J-th point
            // * CMatrix by constraints
            //
            fdmax = 0;
            for(b=0; b<=m-1; b++)
            {
                
                //
                // Prepare I-th basis function
                //
                for(j=0; j<=m-1; j++)
                {
                    bx[j] = (double)(2*j)/(double)(m-1)-1;
                    by[j] = 0;
                }
                by[b] = 1;
                spline1d.spline1dgriddiff2cubic(bx, by, m, 2, 0.0, 2, 0.0, ref bd1, ref bd2);
                spline1d.spline1dbuildcubic(bx, by, m, 2, 0.0, 2, 0.0, bs);
                
                //
                // Calculate B-th column of FMatrix
                // Update FDMax (maximum column norm)
                //
                spline1d.spline1dconvcubic(bx, by, m, 2, 0.0, 2, 0.0, x, n, ref fcolumn);
                for(i_=0; i_<=n-1;i_++)
                {
                    fmatrix[i_,b] = fcolumn[i_];
                }
                v = 0;
                for(i=0; i<=n-1; i++)
                {
                    v = v+math.sqr(w[i]*fcolumn[i]);
                }
                fdmax = Math.Max(fdmax, v);
                
                //
                // Fill temporary with second derivatives of basis function
                //
                for(i_=0; i_<=m-1;i_++)
                {
                    d2matrix[b,i_] = bd2[i_];
                }
            }
            
            //
            // * calculate penalty matrix A
            // * calculate max of diagonal elements of A
            // * calculate PDecay - coefficient before penalty matrix
            //
            for(i=0; i<=m-1; i++)
            {
                for(j=i; j<=m-1; j++)
                {
                    
                    //
                    // calculate integral(B_i''*B_j'') where B_i and B_j are
                    // i-th and j-th basis splines.
                    // B_i and B_j are piecewise linear functions.
                    //
                    v = 0;
                    for(b=0; b<=m-2; b++)
                    {
                        fa = d2matrix[i,b];
                        fb = d2matrix[i,b+1];
                        ga = d2matrix[j,b];
                        gb = d2matrix[j,b+1];
                        v = v+(bx[b+1]-bx[b])*(fa*ga+(fa*(gb-ga)+ga*(fb-fa))/2+(fb-fa)*(gb-ga)/3);
                    }
                    amatrix[i,j] = v;
                    amatrix[j,i] = v;
                }
            }
            admax = 0;
            for(i=0; i<=m-1; i++)
            {
                admax = Math.Max(admax, Math.Abs(amatrix[i,i]));
            }
            pdecay = lambdav*fdmax/admax;
            
            //
            // Calculate TDecay for Tikhonov regularization
            //
            tdecay = fdmax*(1+pdecay)*10*math.machineepsilon;
            
            //
            // Prepare system
            //
            // NOTE: FMatrix is spoiled during this process
            //
            for(i=0; i<=n-1; i++)
            {
                v = w[i];
                for(i_=0; i_<=m-1;i_++)
                {
                    fmatrix[i,i_] = v*fmatrix[i,i_];
                }
            }
            ablas.rmatrixgemm(m, m, n, 1.0, fmatrix, 0, 0, 1, fmatrix, 0, 0, 0, 0.0, nmatrix, 0, 0);
            for(i=0; i<=m-1; i++)
            {
                for(j=0; j<=m-1; j++)
                {
                    nmatrix[i,j] = nmatrix[i,j]+pdecay*amatrix[i,j];
                }
            }
            for(i=0; i<=m-1; i++)
            {
                nmatrix[i,i] = nmatrix[i,i]+tdecay;
            }
            for(i=0; i<=m-1; i++)
            {
                rightpart[i] = 0;
            }
            for(i=0; i<=n-1; i++)
            {
                v = y[i]*w[i];
                for(i_=0; i_<=m-1;i_++)
                {
                    rightpart[i_] = rightpart[i_] + v*fmatrix[i,i_];
                }
            }
            
            //
            // Solve system
            //
            if( !trfac.spdmatrixcholesky(ref nmatrix, m, true) )
            {
                info = -4;
                return;
            }
            fbls.fblscholeskysolve(nmatrix, 1.0, m, true, ref rightpart, ref tmp0);
            for(i_=0; i_<=m-1;i_++)
            {
                c[i_] = rightpart[i_];
            }
            
            //
            // add nodes to force linearity outside of the fitting interval
            //
            spline1d.spline1dgriddiffcubic(bx, c, m, 2, 0.0, 2, 0.0, ref bd1);
            tx = new double[m+2];
            ty = new double[m+2];
            td = new double[m+2];
            i1_ = (0) - (1);
            for(i_=1; i_<=m;i_++)
            {
                tx[i_] = bx[i_+i1_];
            }
            i1_ = (0) - (1);
            for(i_=1; i_<=m;i_++)
            {
                ty[i_] = rightpart[i_+i1_];
            }
            i1_ = (0) - (1);
            for(i_=1; i_<=m;i_++)
            {
                td[i_] = bd1[i_+i1_];
            }
            tx[0] = tx[1]-(tx[2]-tx[1]);
            ty[0] = ty[1]-td[1]*(tx[2]-tx[1]);
            td[0] = td[1];
            tx[m+1] = tx[m]+(tx[m]-tx[m-1]);
            ty[m+1] = ty[m]+td[m]*(tx[m]-tx[m-1]);
            td[m+1] = td[m];
            spline1d.spline1dbuildhermite(tx, ty, td, m+2, s);
            spline1d.spline1dlintransx(s, 2/(xb-xa), -((xa+xb)/(xb-xa)));
            spline1d.spline1dlintransy(s, sb-sa, sa);
            info = 1;
            
            //
            // Fill report
            //
            rep.rmserror = 0;
            rep.avgerror = 0;
            rep.avgrelerror = 0;
            rep.maxerror = 0;
            relcnt = 0;
            spline1d.spline1dconvcubic(bx, rightpart, m, 2, 0.0, 2, 0.0, x, n, ref fcolumn);
            for(i=0; i<=n-1; i++)
            {
                v = (sb-sa)*fcolumn[i]+sa;
                rep.rmserror = rep.rmserror+math.sqr(v-yoriginal[i]);
                rep.avgerror = rep.avgerror+Math.Abs(v-yoriginal[i]);
                if( (double)(yoriginal[i])!=(double)(0) )
                {
                    rep.avgrelerror = rep.avgrelerror+Math.Abs(v-yoriginal[i])/Math.Abs(yoriginal[i]);
                    relcnt = relcnt+1;
                }
                rep.maxerror = Math.Max(rep.maxerror, Math.Abs(v-yoriginal[i]));
            }
            rep.rmserror = Math.Sqrt(rep.rmserror/n);
            rep.avgerror = rep.avgerror/n;
            if( (double)(relcnt)!=(double)(0) )
            {
                rep.avgrelerror = rep.avgrelerror/relcnt;
            }
        }
Exemple #9
0
        /*************************************************************************
        Internal spline fitting subroutine

          -- ALGLIB PROJECT --
             Copyright 08.09.2009 by Bochkanov Sergey
        *************************************************************************/
        private static void spline1dfitinternal(int st,
            double[] x,
            double[] y,
            double[] w,
            int n,
            double[] xc,
            double[] yc,
            int[] dc,
            int k,
            int m,
            ref int info,
            spline1d.spline1dinterpolant s,
            spline1dfitreport rep)
        {
            double[,] fmatrix = new double[0,0];
            double[,] cmatrix = new double[0,0];
            double[] y2 = new double[0];
            double[] w2 = new double[0];
            double[] sx = new double[0];
            double[] sy = new double[0];
            double[] sd = new double[0];
            double[] tmp = new double[0];
            double[] xoriginal = new double[0];
            double[] yoriginal = new double[0];
            lsfitreport lrep = new lsfitreport();
            double v0 = 0;
            double v1 = 0;
            double v2 = 0;
            double mx = 0;
            spline1d.spline1dinterpolant s2 = new spline1d.spline1dinterpolant();
            int i = 0;
            int j = 0;
            int relcnt = 0;
            double xa = 0;
            double xb = 0;
            double sa = 0;
            double sb = 0;
            double bl = 0;
            double br = 0;
            double decay = 0;
            int i_ = 0;

            x = (double[])x.Clone();
            y = (double[])y.Clone();
            w = (double[])w.Clone();
            xc = (double[])xc.Clone();
            yc = (double[])yc.Clone();
            info = 0;

            alglib.ap.assert(st==0 || st==1, "Spline1DFit: internal error!");
            if( st==0 && m<4 )
            {
                info = -1;
                return;
            }
            if( st==1 && m<4 )
            {
                info = -1;
                return;
            }
            if( (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;
                }
            }
            if( st==1 && m%2!=0 )
            {
                
                //
                // Hermite fitter must have even number of basis functions
                //
                info = -2;
                return;
            }
            
            //
            // weight decay for correct handling of task which becomes
            // degenerate after constraints are applied
            //
            decay = 10000*math.machineepsilon;
            
            //
            // Scale X, Y, XC, YC
            //
            lsfitscalexy(ref x, ref y, ref w, n, ref xc, ref yc, dc, k, ref xa, ref xb, ref sa, ref sb, ref xoriginal, ref yoriginal);
            
            //
            // allocate space, initialize:
            // * SX     -   grid for basis functions
            // * SY     -   values of basis functions at grid points
            // * FMatrix-   values of basis functions at X[]
            // * CMatrix-   values (derivatives) of basis functions at XC[]
            //
            y2 = new double[n+m];
            w2 = new double[n+m];
            fmatrix = new double[n+m, m];
            if( k>0 )
            {
                cmatrix = new double[k, m+1];
            }
            if( st==0 )
            {
                
                //
                // allocate space for cubic spline
                //
                sx = new double[m-2];
                sy = new double[m-2];
                for(j=0; j<=m-2-1; j++)
                {
                    sx[j] = (double)(2*j)/(double)(m-2-1)-1;
                }
            }
            if( st==1 )
            {
                
                //
                // allocate space for Hermite spline
                //
                sx = new double[m/2];
                sy = new double[m/2];
                sd = new double[m/2];
                for(j=0; j<=m/2-1; j++)
                {
                    sx[j] = (double)(2*j)/(double)(m/2-1)-1;
                }
            }
            
            //
            // Prepare design and constraints matrices:
            // * fill constraints matrix
            // * fill first N rows of design matrix with values
            // * fill next M rows of design matrix with regularizing term
            // * append M zeros to Y
            // * append M elements, mean(abs(W)) each, to W
            //
            for(j=0; j<=m-1; j++)
            {
                
                //
                // prepare Jth basis function
                //
                if( st==0 )
                {
                    
                    //
                    // cubic spline basis
                    //
                    for(i=0; i<=m-2-1; i++)
                    {
                        sy[i] = 0;
                    }
                    bl = 0;
                    br = 0;
                    if( j<m-2 )
                    {
                        sy[j] = 1;
                    }
                    if( j==m-2 )
                    {
                        bl = 1;
                    }
                    if( j==m-1 )
                    {
                        br = 1;
                    }
                    spline1d.spline1dbuildcubic(sx, sy, m-2, 1, bl, 1, br, s2);
                }
                if( st==1 )
                {
                    
                    //
                    // Hermite basis
                    //
                    for(i=0; i<=m/2-1; i++)
                    {
                        sy[i] = 0;
                        sd[i] = 0;
                    }
                    if( j%2==0 )
                    {
                        sy[j/2] = 1;
                    }
                    else
                    {
                        sd[j/2] = 1;
                    }
                    spline1d.spline1dbuildhermite(sx, sy, sd, m/2, s2);
                }
                
                //
                // values at X[], XC[]
                //
                for(i=0; i<=n-1; i++)
                {
                    fmatrix[i,j] = spline1d.spline1dcalc(s2, x[i]);
                }
                for(i=0; i<=k-1; i++)
                {
                    alglib.ap.assert(dc[i]>=0 && dc[i]<=2, "Spline1DFit: internal error!");
                    spline1d.spline1ddiff(s2, xc[i], ref v0, ref v1, ref v2);
                    if( dc[i]==0 )
                    {
                        cmatrix[i,j] = v0;
                    }
                    if( dc[i]==1 )
                    {
                        cmatrix[i,j] = v1;
                    }
                    if( dc[i]==2 )
                    {
                        cmatrix[i,j] = v2;
                    }
                }
            }
            for(i=0; i<=k-1; i++)
            {
                cmatrix[i,m] = yc[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;
                    }
                }
            }
            y2 = new double[n+m];
            w2 = new double[n+m];
            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;
            }
            
            //
            // Solve constrained task
            //
            if( k>0 )
            {
                
                //
                // solve using regularization
                //
                lsfitlinearwc(y2, w2, fmatrix, cmatrix, n+m, m, k, ref info, ref tmp, lrep);
            }
            else
            {
                
                //
                // no constraints, no regularization needed
                //
                lsfitlinearwc(y, w, fmatrix, cmatrix, n, m, k, ref info, ref tmp, lrep);
            }
            if( info<0 )
            {
                return;
            }
            
            //
            // Generate spline and scale it
            //
            if( st==0 )
            {
                
                //
                // cubic spline basis
                //
                for(i_=0; i_<=m-2-1;i_++)
                {
                    sy[i_] = tmp[i_];
                }
                spline1d.spline1dbuildcubic(sx, sy, m-2, 1, tmp[m-2], 1, tmp[m-1], s);
            }
            if( st==1 )
            {
                
                //
                // Hermite basis
                //
                for(i=0; i<=m/2-1; i++)
                {
                    sy[i] = tmp[2*i];
                    sd[i] = tmp[2*i+1];
                }
                spline1d.spline1dbuildhermite(sx, sy, sd, m/2, s);
            }
            spline1d.spline1dlintransx(s, 2/(xb-xa), -((xa+xb)/(xb-xa)));
            spline1d.spline1dlintransy(s, 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(spline1d.spline1dcalc(s, xoriginal[i])-yoriginal[i])/Math.Abs(yoriginal[i]);
                    relcnt = relcnt+1;
                }
            }
            if( relcnt!=0 )
            {
                rep.avgrelerror = rep.avgrelerror/relcnt;
            }
        }
    public static int Main(string[] args)
    {
        double[] x = new double[0];
        double[] y = new double[0];
        double[] d = new double[0];
        int n = 0;
        int i = 0;
        double t = 0;
        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double err = 0;
        double maxerr = 0;

        
        //
        // Interpolation by natural Cubic spline.
        //
        System.Console.Write("INTERPOLATION BY HERMITE SPLINE");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x), [0, pi], 3 nodes");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("     x   F(x)   S(x)  Error");
        System.Console.WriteLine();
        
        //
        // Create spline
        //
        n = 3;
        x = new double[n];
        y = new double[n];
        d = new double[n];
        for(i=0; i<=n-1; i++)
        {
            x[i] = Math.PI*i/(n-1);
            y[i] = Math.Sin(x[i]);
            d[i] = Math.Cos(x[i]);
        }
        spline1d.spline1dbuildhermite(x, y, d, n, ref s);
        
        //
        // Output results
        //
        t = 0;
        maxerr = 0;
        while( (double)(t)<(double)(0.999999*Math.PI) )
        {
            err = Math.Abs(spline1d.spline1dcalc(ref s, t)-Math.Sin(t));
            maxerr = Math.Max(err, maxerr);
            System.Console.Write("{0,6:F3}",t);
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",Math.Sin(t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",spline1d.spline1dcalc(ref s, t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",err);
            System.Console.WriteLine();
            t = Math.Min(Math.PI, t+0.25);
        }
        err = Math.Abs(spline1d.spline1dcalc(ref s, Math.PI)-Math.Sin(Math.PI));
        maxerr = Math.Max(err, maxerr);
        System.Console.Write("{0,6:F3}",Math.PI);
        System.Console.Write(" ");
        System.Console.Write("{0,6:F3}",Math.Sin(Math.PI));
        System.Console.Write(" ");
        System.Console.Write("{0,6:F3}",spline1d.spline1dcalc(ref s, Math.PI));
        System.Console.Write(" ");
        System.Console.Write("{0,6:F3}",err);
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("max|error| = ");
        System.Console.Write("{0,0:F3}",maxerr);
        System.Console.WriteLine();
        System.Console.Write("Try other demos (spline1d_linear, spline1d_cubic) and compare errors...");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.WriteLine();
        return 0;
    }
 public pspline3interpolant()
 {
     p = new double[0];
     x = new spline1d.spline1dinterpolant();
     y = new spline1d.spline1dinterpolant();
     z = new spline1d.spline1dinterpolant();
 }
    public static int Main(string[] args)
    {
        double[] x = new double[0];
        double[] y = new double[0];
        int n = 0;
        int i = 0;
        double t = 0;
        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double v = 0;
        double dv = 0;
        double d2v = 0;
        double err = 0;
        double maxerr = 0;

        
        //
        // Demonstration of Spline1DCalc(), Spline1DDiff(), Spline1DIntegrate()
        //
        System.Console.Write("DEMONSTRATION OF Spline1DCalc(), Spline1DDiff(), Spline1DIntegrate()");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x), [0, pi]");
        System.Console.WriteLine();
        System.Console.Write("Natural cubic spline with 3 nodes is used");
        System.Console.WriteLine();
        System.Console.WriteLine();
        
        //
        // Create spline
        //
        n = 3;
        x = new double[n];
        y = new double[n];
        for(i=0; i<=n-1; i++)
        {
            x[i] = Math.PI*i/(n-1);
            y[i] = Math.Sin(x[i]);
        }
        spline1d.spline1dbuildcubic(x, y, n, 2, 0.0, 2, 0.0, ref s);
        
        //
        // Output results
        //
        spline1d.spline1ddiff(ref s, 0, ref v, ref dv, ref d2v);
        System.Console.Write("                 S(x)    F(x) ");
        System.Console.WriteLine();
        System.Console.Write("function       ");
        System.Console.Write("{0,6:F3}",spline1d.spline1dcalc(ref s, 0));
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}",0);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.Write("d/dx(0)        ");
        System.Console.Write("{0,6:F3}",dv);
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}",1);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.Write("d2/dx2(0)      ");
        System.Console.Write("{0,6:F3}",d2v);
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}",0);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.Write("integral(0,pi) ");
        System.Console.Write("{0,6:F3}",spline1d.spline1dintegrate(ref s, Math.PI));
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}",2);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.WriteLine();
        return 0;
    }
        public static bool testpsplineinterpolation(bool silent)
        {
            bool   result             = new bool();
            bool   waserrors          = new bool();
            bool   p2errors           = new bool();
            bool   p3errors           = new bool();
            double nonstrictthreshold = 0;
            double threshold          = 0;
            int    passcount          = 0;
            double lstep       = 0;
            double h           = 0;
            int    maxn        = 0;
            int    periodicity = 0;
            int    skind       = 0;
            int    pkind       = 0;
            bool   periodic    = new bool();
            double a           = 0;
            double b           = 0;
            int    n           = 0;
            int    tmpn        = 0;
            int    i           = 0;
            int    k           = 0;
            double vx          = 0;
            double vy          = 0;
            double vz          = 0;
            double vx2         = 0;
            double vy2         = 0;
            double vz2         = 0;
            double vdx         = 0;
            double vdy         = 0;
            double vdz         = 0;
            double vdx2        = 0;
            double vdy2        = 0;
            double vdz2        = 0;
            double vd2x        = 0;
            double vd2y        = 0;
            double vd2z        = 0;
            double vd2x2       = 0;
            double vd2y2       = 0;
            double vd2z2       = 0;
            double v0          = 0;
            double v1          = 0;

            double[] x  = new double[0];
            double[] y  = new double[0];
            double[] z  = new double[0];
            double[] t  = new double[0];
            double[] t2 = new double[0];
            double[] t3 = new double[0];
            double[,] xy  = new double[0, 0];
            double[,] xyz = new double[0, 0];
            pspline.pspline2interpolant  p2 = new pspline.pspline2interpolant();
            pspline.pspline3interpolant  p3 = new pspline.pspline3interpolant();
            spline1d.spline1dinterpolant s  = new spline1d.spline1dinterpolant();
            int i_ = 0;

            waserrors          = false;
            passcount          = 20;
            lstep              = 0.005;
            h                  = 0.00001;
            maxn               = 10;
            threshold          = 10000 * AP.Math.MachineEpsilon;
            nonstrictthreshold = 0.00001;
            p2errors           = false;
            p3errors           = false;

            //
            // Test basic properties of 2- and 3-dimensional splines:
            // * PSpline2ParameterValues() properties
            // * values at nodes
            // * for periodic splines - periodicity properties
            //
            // Variables used:
            // * N              points count
            // * SKind          spline
            // * PKind          parameterization
            // * Periodicity    whether we have periodic spline or not
            //
            for (n = 2; n <= maxn; n++)
            {
                for (skind = 0; skind <= 2; skind++)
                {
                    for (pkind = 0; pkind <= 2; pkind++)
                    {
                        for (periodicity = 0; periodicity <= 1; periodicity++)
                        {
                            periodic = periodicity == 1;

                            //
                            // skip unsupported combinations of parameters
                            //
                            if (periodic & n < 3)
                            {
                                continue;
                            }
                            if (periodic & skind == 0)
                            {
                                continue;
                            }
                            if (n < 5 & skind == 0)
                            {
                                continue;
                            }

                            //
                            // init
                            //
                            xy  = new double[n, 2];
                            xyz = new double[n, 3];
                            apserv.taskgenint1dequidist(-1, +1, n, ref t2, ref x);
                            for (i_ = 0; i_ <= n - 1; i_++)
                            {
                                xy[i_, 0] = x[i_];
                            }
                            for (i_ = 0; i_ <= n - 1; i_++)
                            {
                                xyz[i_, 0] = x[i_];
                            }
                            apserv.taskgenint1dequidist(-1, +1, n, ref t2, ref y);
                            for (i_ = 0; i_ <= n - 1; i_++)
                            {
                                xy[i_, 1] = y[i_];
                            }
                            for (i_ = 0; i_ <= n - 1; i_++)
                            {
                                xyz[i_, 1] = y[i_];
                            }
                            apserv.taskgenint1dequidist(-1, +1, n, ref t2, ref z);
                            for (i_ = 0; i_ <= n - 1; i_++)
                            {
                                xyz[i_, 2] = z[i_];
                            }
                            unsetp2(ref p2);
                            unsetp3(ref p3);
                            if (periodic)
                            {
                                pspline.pspline2buildperiodic(xy, n, skind, pkind, ref p2);
                                pspline.pspline3buildperiodic(xyz, n, skind, pkind, ref p3);
                            }
                            else
                            {
                                pspline.pspline2build(xy, n, skind, pkind, ref p2);
                                pspline.pspline3build(xyz, n, skind, pkind, ref p3);
                            }

                            //
                            // PSpline2ParameterValues() properties
                            //
                            pspline.pspline2parametervalues(ref p2, ref tmpn, ref t2);
                            if (tmpn != n)
                            {
                                p2errors = true;
                                continue;
                            }
                            pspline.pspline3parametervalues(ref p3, ref tmpn, ref t3);
                            if (tmpn != n)
                            {
                                p3errors = true;
                                continue;
                            }
                            p2errors = p2errors | (double)(t2[0]) != (double)(0);
                            p3errors = p3errors | (double)(t3[0]) != (double)(0);
                            for (i = 1; i <= n - 1; i++)
                            {
                                p2errors = p2errors | (double)(t2[i]) <= (double)(t2[i - 1]);
                                p3errors = p3errors | (double)(t3[i]) <= (double)(t3[i - 1]);
                            }
                            if (periodic)
                            {
                                p2errors = p2errors | (double)(t2[n - 1]) >= (double)(1);
                                p3errors = p3errors | (double)(t3[n - 1]) >= (double)(1);
                            }
                            else
                            {
                                p2errors = p2errors | (double)(t2[n - 1]) != (double)(1);
                                p3errors = p3errors | (double)(t3[n - 1]) != (double)(1);
                            }

                            //
                            // Now we have parameter values stored at T,
                            // and want to test whether the actully correspond to
                            // points
                            //
                            for (i = 0; i <= n - 1; i++)
                            {
                                //
                                // 2-dimensional test
                                //
                                pspline.pspline2calc(ref p2, t2[i], ref vx, ref vy);
                                p2errors = p2errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);

                                //
                                // 3-dimensional test
                                //
                                pspline.pspline3calc(ref p3, t3[i], ref vx, ref vy, ref vz);
                                p3errors = p3errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz - z[i])) > (double)(threshold);
                            }

                            //
                            // Test periodicity (if needed)
                            //
                            if (periodic)
                            {
                                //
                                // periodicity at nodes
                                //
                                for (i = 0; i <= n - 1; i++)
                                {
                                    //
                                    // 2-dimensional test
                                    //
                                    pspline.pspline2calc(ref p2, t2[i] + AP.Math.RandomInteger(10) - 5, ref vx, ref vy);
                                    p2errors = p2errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                    p2errors = p2errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);
                                    pspline.pspline2diff(ref p2, t2[i] + AP.Math.RandomInteger(10) - 5, ref vx, ref vdx, ref vy, ref vdy);
                                    p2errors = p2errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                    p2errors = p2errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);
                                    pspline.pspline2diff2(ref p2, t2[i] + AP.Math.RandomInteger(10) - 5, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y);
                                    p2errors = p2errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                    p2errors = p2errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);

                                    //
                                    // 3-dimensional test
                                    //
                                    pspline.pspline3calc(ref p3, t3[i] + AP.Math.RandomInteger(10) - 5, ref vx, ref vy, ref vz);
                                    p3errors = p3errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vz - z[i])) > (double)(threshold);
                                    pspline.pspline3diff(ref p3, t3[i] + AP.Math.RandomInteger(10) - 5, ref vx, ref vdx, ref vy, ref vdy, ref vz, ref vdz);
                                    p3errors = p3errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vz - z[i])) > (double)(threshold);
                                    pspline.pspline3diff2(ref p3, t3[i] + AP.Math.RandomInteger(10) - 5, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y, ref vz, ref vdz, ref vd2z);
                                    p3errors = p3errors | (double)(Math.Abs(vx - x[i])) > (double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vy - y[i])) > (double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vz - z[i])) > (double)(threshold);
                                }

                                //
                                // periodicity between nodes
                                //
                                v0 = AP.Math.RandomReal();
                                pspline.pspline2calc(ref p2, v0, ref vx, ref vy);
                                pspline.pspline2calc(ref p2, v0 + AP.Math.RandomInteger(10) - 5, ref vx2, ref vy2);
                                p2errors = p2errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                pspline.pspline3calc(ref p3, v0, ref vx, ref vy, ref vz);
                                pspline.pspline3calc(ref p3, v0 + AP.Math.RandomInteger(10) - 5, ref vx2, ref vy2, ref vz2);
                                p3errors = p3errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz - vz2)) > (double)(threshold);

                                //
                                // near-boundary test for continuity of function values and derivatives:
                                // 2-dimensional curve
                                //
                                System.Diagnostics.Debug.Assert(skind == 1 | skind == 2, "TEST: unexpected spline type!");
                                v0 = 100 * AP.Math.MachineEpsilon;
                                v1 = 1 - v0;
                                pspline.pspline2calc(ref p2, v0, ref vx, ref vy);
                                pspline.pspline2calc(ref p2, v1, ref vx2, ref vy2);
                                p2errors = p2errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                pspline.pspline2diff(ref p2, v0, ref vx, ref vdx, ref vy, ref vdy);
                                pspline.pspline2diff(ref p2, v1, ref vx2, ref vdx2, ref vy2, ref vdy2);
                                p2errors = p2errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vdx - vdx2)) > (double)(nonstrictthreshold);
                                p2errors = p2errors | (double)(Math.Abs(vdy - vdy2)) > (double)(nonstrictthreshold);
                                pspline.pspline2diff2(ref p2, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y);
                                pspline.pspline2diff2(ref p2, v1, ref vx2, ref vdx2, ref vd2x2, ref vy2, ref vdy2, ref vd2y2);
                                p2errors = p2errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vdx - vdx2)) > (double)(nonstrictthreshold);
                                p2errors = p2errors | (double)(Math.Abs(vdy - vdy2)) > (double)(nonstrictthreshold);
                                if (skind == 2)
                                {
                                    //
                                    // second derivative test only for cubic splines
                                    //
                                    p2errors = p2errors | (double)(Math.Abs(vd2x - vd2x2)) > (double)(nonstrictthreshold);
                                    p2errors = p2errors | (double)(Math.Abs(vd2y - vd2y2)) > (double)(nonstrictthreshold);
                                }

                                //
                                // near-boundary test for continuity of function values and derivatives:
                                // 3-dimensional curve
                                //
                                System.Diagnostics.Debug.Assert(skind == 1 | skind == 2, "TEST: unexpected spline type!");
                                v0 = 100 * AP.Math.MachineEpsilon;
                                v1 = 1 - v0;
                                pspline.pspline3calc(ref p3, v0, ref vx, ref vy, ref vz);
                                pspline.pspline3calc(ref p3, v1, ref vx2, ref vy2, ref vz2);
                                p3errors = p3errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz - vz2)) > (double)(threshold);
                                pspline.pspline3diff(ref p3, v0, ref vx, ref vdx, ref vy, ref vdy, ref vz, ref vdz);
                                pspline.pspline3diff(ref p3, v1, ref vx2, ref vdx2, ref vy2, ref vdy2, ref vz2, ref vdz2);
                                p3errors = p3errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz - vz2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vdx - vdx2)) > (double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdy - vdy2)) > (double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdz - vdz2)) > (double)(nonstrictthreshold);
                                pspline.pspline3diff2(ref p3, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y, ref vz, ref vdz, ref vd2z);
                                pspline.pspline3diff2(ref p3, v1, ref vx2, ref vdx2, ref vd2x2, ref vy2, ref vdy2, ref vd2y2, ref vz2, ref vdz2, ref vd2z2);
                                p3errors = p3errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz - vz2)) > (double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vdx - vdx2)) > (double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdy - vdy2)) > (double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdz - vdz2)) > (double)(nonstrictthreshold);
                                if (skind == 2)
                                {
                                    //
                                    // second derivative test only for cubic splines
                                    //
                                    p3errors = p3errors | (double)(Math.Abs(vd2x - vd2x2)) > (double)(nonstrictthreshold);
                                    p3errors = p3errors | (double)(Math.Abs(vd2y - vd2y2)) > (double)(nonstrictthreshold);
                                    p3errors = p3errors | (double)(Math.Abs(vd2z - vd2z2)) > (double)(nonstrictthreshold);
                                }
                            }
                        }
                    }
                }
            }

            //
            // Test differentiation, tangents, calculation between nodes.
            //
            // Because differentiation is done in parameterization/spline/periodicity
            // oblivious manner, we don't have to test all possible combinations
            // of spline types and parameterizations.
            //
            // Actually we test special combination with properties which allow us
            // to easily solve this problem:
            // * 2 (3) variables
            // * first variable is sampled from equidistant grid on [0,1]
            // * other variables are random
            // * uniform parameterization is used
            // * periodicity - none
            // * spline type - any (we use cubic splines)
            // Same problem allows us to test calculation BETWEEN nodes.
            //
            for (n = 2; n <= maxn; n++)
            {
                //
                // init
                //
                xy  = new double[n, 2];
                xyz = new double[n, 3];
                apserv.taskgenint1dequidist(0, +1, n, ref t, ref x);
                for (i_ = 0; i_ <= n - 1; i_++)
                {
                    xy[i_, 0] = x[i_];
                }
                for (i_ = 0; i_ <= n - 1; i_++)
                {
                    xyz[i_, 0] = x[i_];
                }
                apserv.taskgenint1dequidist(0, +1, n, ref t, ref y);
                for (i_ = 0; i_ <= n - 1; i_++)
                {
                    xy[i_, 1] = y[i_];
                }
                for (i_ = 0; i_ <= n - 1; i_++)
                {
                    xyz[i_, 1] = y[i_];
                }
                apserv.taskgenint1dequidist(0, +1, n, ref t, ref z);
                for (i_ = 0; i_ <= n - 1; i_++)
                {
                    xyz[i_, 2] = z[i_];
                }
                unsetp2(ref p2);
                unsetp3(ref p3);
                pspline.pspline2build(xy, n, 2, 0, ref p2);
                pspline.pspline3build(xyz, n, 2, 0, ref p3);

                //
                // Test 2D/3D spline:
                // * build non-parametric cubic spline from T and X/Y
                // * calculate its value and derivatives at V0
                // * compare with Spline2Calc/Spline2Diff/Spline2Diff2
                // Because of task properties both variants should
                // return same answer.
                //
                v0 = AP.Math.RandomReal();
                spline1d.spline1dbuildcubic(t, x, n, 0, 0.0, 0, 0.0, ref s);
                spline1d.spline1ddiff(ref s, v0, ref vx2, ref vdx2, ref vd2x2);
                spline1d.spline1dbuildcubic(t, y, n, 0, 0.0, 0, 0.0, ref s);
                spline1d.spline1ddiff(ref s, v0, ref vy2, ref vdy2, ref vd2y2);
                spline1d.spline1dbuildcubic(t, z, n, 0, 0.0, 0, 0.0, ref s);
                spline1d.spline1ddiff(ref s, v0, ref vz2, ref vdz2, ref vd2z2);

                //
                // 2D test
                //
                pspline.pspline2calc(ref p2, v0, ref vx, ref vy);
                p2errors = p2errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                pspline.pspline2diff(ref p2, v0, ref vx, ref vdx, ref vy, ref vdy);
                p2errors = p2errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdx - vdx2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdy - vdy2)) > (double)(threshold);
                pspline.pspline2diff2(ref p2, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y);
                p2errors = p2errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdx - vdx2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdy - vdy2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vd2x - vd2x2)) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vd2y - vd2y2)) > (double)(threshold);

                //
                // 3D test
                //
                pspline.pspline3calc(ref p3, v0, ref vx, ref vy, ref vz);
                p3errors = p3errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz - vz2)) > (double)(threshold);
                pspline.pspline3diff(ref p3, v0, ref vx, ref vdx, ref vy, ref vdy, ref vz, ref vdz);
                p3errors = p3errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz - vz2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdx - vdx2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdy - vdy2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdz - vdz2)) > (double)(threshold);
                pspline.pspline3diff2(ref p3, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y, ref vz, ref vdz, ref vd2z);
                p3errors = p3errors | (double)(Math.Abs(vx - vx2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy - vy2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz - vz2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdx - vdx2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdy - vdy2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdz - vdz2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vd2x - vd2x2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vd2y - vd2y2)) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vd2z - vd2z2)) > (double)(threshold);

                //
                // Test tangents for 2D/3D
                //
                pspline.pspline2tangent(ref p2, v0, ref vx, ref vy);
                p2errors = p2errors | (double)(Math.Abs(vx - vdx2 / apserv.safepythag2(vdx2, vdy2))) > (double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy - vdy2 / apserv.safepythag2(vdx2, vdy2))) > (double)(threshold);
                pspline.pspline3tangent(ref p3, v0, ref vx, ref vy, ref vz);
                p3errors = p3errors | (double)(Math.Abs(vx - vdx2 / apserv.safepythag3(vdx2, vdy2, vdz2))) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy - vdy2 / apserv.safepythag3(vdx2, vdy2, vdz2))) > (double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz - vdz2 / apserv.safepythag3(vdx2, vdy2, vdz2))) > (double)(threshold);
            }

            //
            // Arc length test.
            //
            // Simple problem with easy solution (points on a straight line with
            // uniform parameterization).
            //
            for (n = 2; n <= maxn; n++)
            {
                xy  = new double[n, 2];
                xyz = new double[n, 3];
                for (i = 0; i <= n - 1; i++)
                {
                    xy[i, 0]  = i;
                    xy[i, 1]  = i;
                    xyz[i, 0] = i;
                    xyz[i, 1] = i;
                    xyz[i, 2] = i;
                }
                pspline.pspline2build(xy, n, 1, 0, ref p2);
                pspline.pspline3build(xyz, n, 1, 0, ref p3);
                a        = AP.Math.RandomReal();
                b        = AP.Math.RandomReal();
                p2errors = p2errors | (double)(Math.Abs(pspline.pspline2arclength(ref p2, a, b) - (b - a) * Math.Sqrt(2) * (n - 1))) > (double)(nonstrictthreshold);
                p3errors = p3errors | (double)(Math.Abs(pspline.pspline3arclength(ref p3, a, b) - (b - a) * Math.Sqrt(3) * (n - 1))) > (double)(nonstrictthreshold);
            }

            //
            // report
            //
            waserrors = p2errors | p3errors;
            if (!silent)
            {
                System.Console.Write("TESTING SPLINE INTERPOLATION");
                System.Console.WriteLine();

                //
                // Normal tests
                //
                System.Console.Write("2D TEST:                                 ");
                if (p2errors)
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("3D TEST:                                 ");
                if (p3errors)
                {
                    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);
        }
    public static int Main(string[] args)
    {
        double[] x = new double[0];
        double[] y = new double[0];
        double[] w = new double[0];
        double[] xc = new double[0];
        double[] yc = new double[0];
        int[] dc = new int[0];
        int n = 0;
        int i = 0;
        int info = 0;
        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double t = 0;
        spline1d.spline1dfitreport rep = new spline1d.spline1dfitreport();

        
        //
        // Fitting by constrained Hermite spline
        //
        System.Console.Write("FITTING BY CONSTRAINED HERMITE SPLINE");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x)      function being fitted");
        System.Console.WriteLine();
        System.Console.Write("[0, pi]          interval");
        System.Console.WriteLine();
        System.Console.Write("M=6              number of basis functions to use");
        System.Console.WriteLine();
        System.Console.Write("S(0)=0           first constraint");
        System.Console.WriteLine();
        System.Console.Write("S(pi)=0          second constraint");
        System.Console.WriteLine();
        System.Console.Write("N=100            number of points to fit");
        System.Console.WriteLine();
        
        //
        // Create and fit:
        // * X  contains points
        // * Y  contains values
        // * W  contains weights
        // * XC contains constraints locations
        // * YC contains constraints values
        // * DC contains derivative indexes (0 = constrained function value)
        //
        n = 100;
        x = new double[n];
        y = new double[n];
        w = new double[n];
        for(i=0; i<=n-1; i++)
        {
            x[i] = Math.PI*i/(n-1);
            y[i] = Math.Sin(x[i]);
            w[i] = 1;
        }
        xc = new double[2];
        yc = new double[2];
        dc = new int[2];
        xc[0] = 0;
        yc[0] = 0;
        dc[0] = 0;
        xc[0] = Math.PI;
        yc[0] = 0;
        dc[0] = 0;
        spline1d.spline1dfithermitewc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 2, 6, ref info, ref s, ref rep);
        
        //
        // Output results
        //
        if( info>0 )
        {
            System.Console.WriteLine();
            System.Console.Write("OK, we have finished");
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("     x   F(x)   S(x)  Error");
            System.Console.WriteLine();
            t = 0;
            while( (double)(t)<(double)(0.999999*Math.PI) )
            {
                System.Console.Write("{0,6:F3}",t);
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}",Math.Sin(t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}",spline1d.spline1dcalc(ref s, t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}",Math.Abs(spline1d.spline1dcalc(ref s, t)-Math.Sin(t)));
                System.Console.WriteLine();
                t = Math.Min(Math.PI, t+0.25);
            }
            System.Console.Write("{0,6:F3}",t);
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",Math.Sin(t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",spline1d.spline1dcalc(ref s, t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",Math.Abs(spline1d.spline1dcalc(ref s, t)-Math.Sin(t)));
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("rms error is ");
            System.Console.Write("{0,6:F3}",rep.rmserror);
            System.Console.WriteLine();
            System.Console.Write("max error is ");
            System.Console.Write("{0,6:F3}",rep.maxerror);
            System.Console.WriteLine();
            System.Console.Write("S(0) = S(pi) = 0 (exactly)");
            System.Console.WriteLine();
            System.Console.WriteLine();
        }
        else
        {
            System.Console.WriteLine();
            System.Console.Write("Something wrong, Info=");
            System.Console.Write("{0,0:d}",info);
        }
        return 0;
    }
Exemple #15
0
    public static int Main(string[] args)
    {
        double[] x = new double[0];
        double[] y = new double[0];
        int      n = 0;
        int      i = 0;
        double   t = 0;

        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double v      = 0;
        double dv     = 0;
        double d2v    = 0;
        double err    = 0;
        double maxerr = 0;


        //
        // Demonstration of Spline1DCalc(), Spline1DDiff(), Spline1DIntegrate()
        //
        System.Console.Write("DEMONSTRATION OF Spline1DCalc(), Spline1DDiff(), Spline1DIntegrate()");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x), [0, pi]");
        System.Console.WriteLine();
        System.Console.Write("Natural cubic spline with 3 nodes is used");
        System.Console.WriteLine();
        System.Console.WriteLine();

        //
        // Create spline
        //
        n = 3;
        x = new double[n];
        y = new double[n];
        for (i = 0; i <= n - 1; i++)
        {
            x[i] = Math.PI * i / (n - 1);
            y[i] = Math.Sin(x[i]);
        }
        spline1d.spline1dbuildcubic(x, y, n, 2, 0.0, 2, 0.0, ref s);

        //
        // Output results
        //
        spline1d.spline1ddiff(ref s, 0, ref v, ref dv, ref d2v);
        System.Console.Write("                 S(x)    F(x) ");
        System.Console.WriteLine();
        System.Console.Write("function       ");
        System.Console.Write("{0,6:F3}", spline1d.spline1dcalc(ref s, 0));
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}", 0);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.Write("d/dx(0)        ");
        System.Console.Write("{0,6:F3}", dv);
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}", 1);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.Write("d2/dx2(0)      ");
        System.Console.Write("{0,6:F3}", d2v);
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}", 0);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.Write("integral(0,pi) ");
        System.Console.Write("{0,6:F3}", spline1d.spline1dintegrate(ref s, Math.PI));
        System.Console.Write("  ");
        System.Console.Write("{0,6:F3}", 2);
        System.Console.Write(" ");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.WriteLine();
        return(0);
    }
Exemple #16
0
 public override void init()
 {
     p = new double[0];
     x = new spline1d.spline1dinterpolant();
     y = new spline1d.spline1dinterpolant();
     z = new spline1d.spline1dinterpolant();
 }
        public static bool testspline1d(bool silent)
        {
            bool result = new bool();
            bool waserrors = new bool();
            bool crserrors = new bool();
            bool cserrors = new bool();
            bool hserrors = new bool();
            bool aserrors = new bool();
            bool lserrors = new bool();
            bool dserrors = new bool();
            bool uperrors = new bool();
            bool cperrors = new bool();
            bool lterrors = new bool();
            bool ierrors = new bool();
            double nonstrictthreshold = 0;
            double threshold = 0;
            int passcount = 0;
            double lstep = 0;
            double h = 0;
            int maxn = 0;
            int bltype = 0;
            int brtype = 0;
            bool periodiccond = new bool();
            int n = 0;
            int i = 0;
            int k = 0;
            int pass = 0;
            double[] x = new double[0];
            double[] y = new double[0];
            double[] yp = new double[0];
            double[] w = new double[0];
            double[] w2 = new double[0];
            double[] y2 = new double[0];
            double[] d = new double[0];
            double[] xc = new double[0];
            double[] yc = new double[0];
            int n2 = 0;
            double[] tmp0 = new double[0];
            double[] tmp1 = new double[0];
            double[] tmp2 = new double[0];
            double[] tmpx = new double[0];
            int[] dc = new int[0];
            spline1d.spline1dinterpolant c = new spline1d.spline1dinterpolant();
            spline1d.spline1dinterpolant c2 = new spline1d.spline1dinterpolant();
            double a = 0;
            double b = 0;
            double bl = 0;
            double br = 0;
            double t = 0;
            double sa = 0;
            double sb = 0;
            double v = 0;
            double l10 = 0;
            double l11 = 0;
            double l12 = 0;
            double l20 = 0;
            double l21 = 0;
            double l22 = 0;
            double p0 = 0;
            double p1 = 0;
            double p2 = 0;
            double s = 0;
            double ds = 0;
            double d2s = 0;
            double s2 = 0;
            double ds2 = 0;
            double d2s2 = 0;
            double vl = 0;
            double vm = 0;
            double vr = 0;
            double err = 0;
            double tension = 0;
            double intab = 0;
            int i_ = 0;

            waserrors = false;
            passcount = 20;
            lstep = 0.005;
            h = 0.00001;
            maxn = 10;
            threshold = 10000*math.machineepsilon;
            nonstrictthreshold = 0.00001;
            lserrors = false;
            cserrors = false;
            crserrors = false;
            hserrors = false;
            aserrors = false;
            dserrors = false;
            cperrors = false;
            uperrors = false;
            lterrors = false;
            ierrors = false;
            
            //
            // General test: linear, cubic, Hermite, Akima
            //
            for(n=2; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                yp = new double[n-1+1];
                d = new double[n-1+1];
                for(pass=1; pass<=passcount; pass++)
                {
                    
                    //
                    // Prepare task:
                    // * X contains abscissas from [A,B]
                    // * Y contains function values
                    // * YP contains periodic function values
                    //
                    a = -1-math.randomreal();
                    b = 1+math.randomreal();
                    bl = 2*math.randomreal()-1;
                    br = 2*math.randomreal()-1;
                    for(i=0; i<=n-1; i++)
                    {
                        x[i] = 0.5*(b+a)+0.5*(b-a)*Math.Cos(Math.PI*(2*i+1)/(2*n));
                        if( i==0 )
                        {
                            x[i] = a;
                        }
                        if( i==n-1 )
                        {
                            x[i] = b;
                        }
                        y[i] = Math.Cos(1.3*Math.PI*x[i]+0.4);
                        yp[i] = y[i];
                        d[i] = -(1.3*Math.PI*Math.Sin(1.3*Math.PI*x[i]+0.4));
                    }
                    yp[n-1] = yp[0];
                    for(i=0; i<=n-1; i++)
                    {
                        k = 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 = yp[i];
                            yp[i] = yp[k];
                            yp[k] = t;
                            t = d[i];
                            d[i] = d[k];
                            d[k] = t;
                        }
                    }
                    
                    //
                    // Build linear spline
                    // Test for general interpolation scheme properties:
                    // * values at nodes
                    // * continuous function
                    // Test for specific properties is implemented below.
                    //
                    spline1d.spline1dbuildlinear(x, y, n, c);
                    err = 0;
                    for(i=0; i<=n-1; i++)
                    {
                        err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                    }
                    lserrors = lserrors | (double)(err)>(double)(threshold);
                    lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                    lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                    lserrors = lserrors | (double)(l20/l10)>(double)(1.2);
                    
                    //
                    // Build cubic spline.
                    // Test for interpolation scheme properties:
                    // * values at nodes
                    // * boundary conditions
                    // * continuous function
                    // * continuous first derivative
                    // * continuous second derivative
                    // * periodicity properties
                    // * Spline1DGridDiff(), Spline1DGridDiff2() and Spline1DDiff()
                    //   calls must return same results
                    //
                    for(bltype=-1; bltype<=2; bltype++)
                    {
                        for(brtype=-1; brtype<=2; brtype++)
                        {
                            
                            //
                            // skip meaningless combination of boundary conditions
                            // (one condition is periodic, another is not)
                            //
                            periodiccond = bltype==-1 | brtype==-1;
                            if( periodiccond & bltype!=brtype )
                            {
                                continue;
                            }
                            
                            //
                            // build
                            //
                            if( periodiccond )
                            {
                                spline1d.spline1dbuildcubic(x, yp, n, bltype, bl, brtype, br, c);
                            }
                            else
                            {
                                spline1d.spline1dbuildcubic(x, y, n, bltype, bl, brtype, br, c);
                            }
                            
                            //
                            // interpolation properties
                            //
                            err = 0;
                            if( periodiccond )
                            {
                                
                                //
                                // * check values at nodes; spline is periodic so
                                //   we add random number of periods to nodes
                                // * we also test for periodicity of derivatives
                                //
                                for(i=0; i<=n-1; i++)
                                {
                                    v = x[i];
                                    vm = v+(b-a)*(math.randominteger(5)-2);
                                    t = yp[i]-spline1d.spline1dcalc(c, vm);
                                    err = Math.Max(err, Math.Abs(t));
                                    spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                                    spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                                    err = Math.Max(err, Math.Abs(s-s2));
                                    err = Math.Max(err, Math.Abs(ds-ds2));
                                    err = Math.Max(err, Math.Abs(d2s-d2s2));
                                }
                                
                                //
                                // periodicity between nodes
                                //
                                v = a+(b-a)*math.randomreal();
                                vm = v+(b-a)*(math.randominteger(5)-2);
                                err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, v)-spline1d.spline1dcalc(c, vm)));
                                spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                                err = Math.Max(err, Math.Abs(s-s2));
                                err = Math.Max(err, Math.Abs(ds-ds2));
                                err = Math.Max(err, Math.Abs(d2s-d2s2));
                            }
                            else
                            {
                                
                                //
                                // * check values at nodes
                                //
                                for(i=0; i<=n-1; i++)
                                {
                                    err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                                }
                            }
                            cserrors = cserrors | (double)(err)>(double)(threshold);
                            
                            //
                            // check boundary conditions
                            //
                            err = 0;
                            if( bltype==0 )
                            {
                                spline1d.spline1ddiff(c, a-h, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, a+h, ref s2, ref ds2, ref d2s2);
                                t = (d2s2-d2s)/(2*h);
                                err = Math.Max(err, Math.Abs(t));
                            }
                            if( bltype==1 )
                            {
                                t = (spline1d.spline1dcalc(c, a+h)-spline1d.spline1dcalc(c, a-h))/(2*h);
                                err = Math.Max(err, Math.Abs(bl-t));
                            }
                            if( bltype==2 )
                            {
                                t = (spline1d.spline1dcalc(c, a+h)-2*spline1d.spline1dcalc(c, a)+spline1d.spline1dcalc(c, a-h))/math.sqr(h);
                                err = Math.Max(err, Math.Abs(bl-t));
                            }
                            if( brtype==0 )
                            {
                                spline1d.spline1ddiff(c, b-h, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, b+h, ref s2, ref ds2, ref d2s2);
                                t = (d2s2-d2s)/(2*h);
                                err = Math.Max(err, Math.Abs(t));
                            }
                            if( brtype==1 )
                            {
                                t = (spline1d.spline1dcalc(c, b+h)-spline1d.spline1dcalc(c, b-h))/(2*h);
                                err = Math.Max(err, Math.Abs(br-t));
                            }
                            if( brtype==2 )
                            {
                                t = (spline1d.spline1dcalc(c, b+h)-2*spline1d.spline1dcalc(c, b)+spline1d.spline1dcalc(c, b-h))/math.sqr(h);
                                err = Math.Max(err, Math.Abs(br-t));
                            }
                            if( bltype==-1 | brtype==-1 )
                            {
                                spline1d.spline1ddiff(c, a+100*math.machineepsilon, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, b-100*math.machineepsilon, ref s2, ref ds2, ref d2s2);
                                err = Math.Max(err, Math.Abs(s-s2));
                                err = Math.Max(err, Math.Abs(ds-ds2));
                                err = Math.Max(err, Math.Abs(d2s-d2s2));
                            }
                            cserrors = cserrors | (double)(err)>(double)(1.0E-3);
                            
                            //
                            // Check Lipschitz continuity
                            //
                            lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                            lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                            if( (double)(l10)>(double)(1.0E-6) )
                            {
                                cserrors = cserrors | (double)(l20/l10)>(double)(1.2);
                            }
                            if( (double)(l11)>(double)(1.0E-6) )
                            {
                                cserrors = cserrors | (double)(l21/l11)>(double)(1.2);
                            }
                            if( (double)(l12)>(double)(1.0E-6) )
                            {
                                cserrors = cserrors | (double)(l22/l12)>(double)(1.2);
                            }
                            
                            //
                            // compare spline1dgriddiff() and spline1ddiff() results
                            //
                            err = 0;
                            if( periodiccond )
                            {
                                spline1d.spline1dgriddiffcubic(x, yp, n, bltype, bl, brtype, br, ref tmp1);
                            }
                            else
                            {
                                spline1d.spline1dgriddiffcubic(x, y, n, bltype, bl, brtype, br, ref tmp1);
                            }
                            ap.assert(ap.len(tmp1)>=n);
                            for(i=0; i<=n-1; i++)
                            {
                                spline1d.spline1ddiff(c, x[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                            }
                            if( periodiccond )
                            {
                                spline1d.spline1dgriddiff2cubic(x, yp, n, bltype, bl, brtype, br, ref tmp1, ref tmp2);
                            }
                            else
                            {
                                spline1d.spline1dgriddiff2cubic(x, y, n, bltype, bl, brtype, br, ref tmp1, ref tmp2);
                            }
                            for(i=0; i<=n-1; i++)
                            {
                                spline1d.spline1ddiff(c, x[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                                err = Math.Max(err, Math.Abs(d2s-tmp2[i]));
                            }
                            cserrors = cserrors | (double)(err)>(double)(threshold);
                            
                            //
                            // compare spline1dconv()/convdiff()/convdiff2() and spline1ddiff() results
                            //
                            n2 = 2+math.randominteger(2*n);
                            tmpx = new double[n2];
                            for(i=0; i<=n2-1; i++)
                            {
                                tmpx[i] = 0.5*(a+b)+(a-b)*(2*math.randomreal()-1);
                            }
                            err = 0;
                            if( periodiccond )
                            {
                                spline1d.spline1dconvcubic(x, yp, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0);
                            }
                            else
                            {
                                spline1d.spline1dconvcubic(x, y, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0);
                            }
                            for(i=0; i<=n2-1; i++)
                            {
                                spline1d.spline1ddiff(c, tmpx[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(s-tmp0[i]));
                            }
                            if( periodiccond )
                            {
                                spline1d.spline1dconvdiffcubic(x, yp, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1);
                            }
                            else
                            {
                                spline1d.spline1dconvdiffcubic(x, y, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1);
                            }
                            for(i=0; i<=n2-1; i++)
                            {
                                spline1d.spline1ddiff(c, tmpx[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(s-tmp0[i]));
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                            }
                            if( periodiccond )
                            {
                                spline1d.spline1dconvdiff2cubic(x, yp, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1, ref tmp2);
                            }
                            else
                            {
                                spline1d.spline1dconvdiff2cubic(x, y, n, bltype, bl, brtype, br, tmpx, n2, ref tmp0, ref tmp1, ref tmp2);
                            }
                            for(i=0; i<=n2-1; i++)
                            {
                                spline1d.spline1ddiff(c, tmpx[i], ref s, ref ds, ref d2s);
                                err = Math.Max(err, Math.Abs(s-tmp0[i]));
                                err = Math.Max(err, Math.Abs(ds-tmp1[i]));
                                err = Math.Max(err, Math.Abs(d2s-tmp2[i]));
                            }
                            cserrors = cserrors | (double)(err)>(double)(threshold);
                        }
                    }
                    
                    //
                    // Build Catmull-Rom spline.
                    // Test for interpolation scheme properties:
                    // * values at nodes
                    // * boundary conditions
                    // * continuous function
                    // * continuous first derivative
                    // * periodicity properties
                    //
                    for(bltype=-1; bltype<=0; bltype++)
                    {
                        periodiccond = bltype==-1;
                        
                        //
                        // select random tension value, then build
                        //
                        if( (double)(math.randomreal())>(double)(0.5) )
                        {
                            if( (double)(math.randomreal())>(double)(0.5) )
                            {
                                tension = 0;
                            }
                            else
                            {
                                tension = 1;
                            }
                        }
                        else
                        {
                            tension = math.randomreal();
                        }
                        if( periodiccond )
                        {
                            spline1d.spline1dbuildcatmullrom(x, yp, n, bltype, tension, c);
                        }
                        else
                        {
                            spline1d.spline1dbuildcatmullrom(x, y, n, bltype, tension, c);
                        }
                        
                        //
                        // interpolation properties
                        //
                        err = 0;
                        if( periodiccond )
                        {
                            
                            //
                            // * check values at nodes; spline is periodic so
                            //   we add random number of periods to nodes
                            // * we also test for periodicity of first derivative
                            //
                            for(i=0; i<=n-1; i++)
                            {
                                v = x[i];
                                vm = v+(b-a)*(math.randominteger(5)-2);
                                t = yp[i]-spline1d.spline1dcalc(c, vm);
                                err = Math.Max(err, Math.Abs(t));
                                spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                                spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                                err = Math.Max(err, Math.Abs(s-s2));
                                err = Math.Max(err, Math.Abs(ds-ds2));
                            }
                            
                            //
                            // periodicity between nodes
                            //
                            v = a+(b-a)*math.randomreal();
                            vm = v+(b-a)*(math.randominteger(5)-2);
                            err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, v)-spline1d.spline1dcalc(c, vm)));
                            spline1d.spline1ddiff(c, v, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, vm, ref s2, ref ds2, ref d2s2);
                            err = Math.Max(err, Math.Abs(s-s2));
                            err = Math.Max(err, Math.Abs(ds-ds2));
                        }
                        else
                        {
                            
                            //
                            // * check values at nodes
                            //
                            for(i=0; i<=n-1; i++)
                            {
                                err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                            }
                        }
                        crserrors = crserrors | (double)(err)>(double)(threshold);
                        
                        //
                        // check boundary conditions
                        //
                        err = 0;
                        if( bltype==0 )
                        {
                            spline1d.spline1ddiff(c, a-h, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, a+h, ref s2, ref ds2, ref d2s2);
                            t = (d2s2-d2s)/(2*h);
                            err = Math.Max(err, Math.Abs(t));
                            spline1d.spline1ddiff(c, b-h, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, b+h, ref s2, ref ds2, ref d2s2);
                            t = (d2s2-d2s)/(2*h);
                            err = Math.Max(err, Math.Abs(t));
                        }
                        if( bltype==-1 )
                        {
                            spline1d.spline1ddiff(c, a+100*math.machineepsilon, ref s, ref ds, ref d2s);
                            spline1d.spline1ddiff(c, b-100*math.machineepsilon, ref s2, ref ds2, ref d2s2);
                            err = Math.Max(err, Math.Abs(s-s2));
                            err = Math.Max(err, Math.Abs(ds-ds2));
                        }
                        crserrors = crserrors | (double)(err)>(double)(1.0E-3);
                        
                        //
                        // Check Lipschitz continuity
                        //
                        lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                        lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                        if( (double)(l10)>(double)(1.0E-6) )
                        {
                            crserrors = crserrors | (double)(l20/l10)>(double)(1.2);
                        }
                        if( (double)(l11)>(double)(1.0E-6) )
                        {
                            crserrors = crserrors | (double)(l21/l11)>(double)(1.2);
                        }
                    }
                    
                    //
                    // Build Hermite spline.
                    // Test for interpolation scheme properties:
                    // * values and derivatives at nodes
                    // * continuous function
                    // * continuous first derivative
                    //
                    spline1d.spline1dbuildhermite(x, y, d, n, c);
                    err = 0;
                    for(i=0; i<=n-1; i++)
                    {
                        err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                    }
                    hserrors = hserrors | (double)(err)>(double)(threshold);
                    err = 0;
                    for(i=0; i<=n-1; i++)
                    {
                        t = (spline1d.spline1dcalc(c, x[i]+h)-spline1d.spline1dcalc(c, x[i]-h))/(2*h);
                        err = Math.Max(err, Math.Abs(d[i]-t));
                    }
                    hserrors = hserrors | (double)(err)>(double)(1.0E-3);
                    lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                    lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                    hserrors = hserrors | (double)(l20/l10)>(double)(1.2);
                    hserrors = hserrors | (double)(l21/l11)>(double)(1.2);
                    
                    //
                    // Build Akima spline
                    // Test for general interpolation scheme properties:
                    // * values at nodes
                    // * continuous function
                    // * continuous first derivative
                    // Test for specific properties is implemented below.
                    //
                    if( n>=5 )
                    {
                        spline1d.spline1dbuildakima(x, y, n, c);
                        err = 0;
                        for(i=0; i<=n-1; i++)
                        {
                            err = Math.Max(err, Math.Abs(y[i]-spline1d.spline1dcalc(c, x[i])));
                        }
                        aserrors = aserrors | (double)(err)>(double)(threshold);
                        lconst(a, b, c, lstep, ref l10, ref l11, ref l12);
                        lconst(a, b, c, lstep/3, ref l20, ref l21, ref l22);
                        hserrors = hserrors | (double)(l20/l10)>(double)(1.2);
                        hserrors = hserrors | (double)(l21/l11)>(double)(1.2);
                    }
                }
            }
            
            //
            // Special linear spline test:
            // test for linearity between x[i] and x[i+1]
            //
            for(n=2; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                
                //
                // Prepare task
                //
                a = -1;
                b = 1;
                for(i=0; i<=n-1; i++)
                {
                    x[i] = a+(b-a)*i/(n-1);
                    y[i] = 2*math.randomreal()-1;
                }
                spline1d.spline1dbuildlinear(x, y, n, c);
                
                //
                // Test
                //
                err = 0;
                for(k=0; k<=n-2; k++)
                {
                    a = x[k];
                    b = x[k+1];
                    for(pass=1; pass<=passcount; pass++)
                    {
                        t = a+(b-a)*math.randomreal();
                        v = y[k]+(t-a)/(b-a)*(y[k+1]-y[k]);
                        err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-v));
                    }
                }
                lserrors = lserrors | (double)(err)>(double)(threshold);
            }
            
            //
            // Special Akima test: test outlier sensitivity
            // Spline value at (x[i], x[i+1]) should depend from
            // f[i-2], f[i-1], f[i], f[i+1], f[i+2], f[i+3] only.
            //
            for(n=5; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                y2 = new double[n-1+1];
                
                //
                // Prepare unperturbed Akima spline
                //
                a = -1;
                b = 1;
                for(i=0; i<=n-1; i++)
                {
                    x[i] = a+(b-a)*i/(n-1);
                    y[i] = Math.Cos(1.3*Math.PI*x[i]+0.4);
                }
                spline1d.spline1dbuildakima(x, y, n, c);
                
                //
                // Process perturbed tasks
                //
                err = 0;
                for(k=0; k<=n-1; k++)
                {
                    for(i_=0; i_<=n-1;i_++)
                    {
                        y2[i_] = y[i_];
                    }
                    y2[k] = 5;
                    spline1d.spline1dbuildakima(x, y2, n, c2);
                    
                    //
                    // Test left part independence
                    //
                    if( k-3>=1 )
                    {
                        a = -1;
                        b = x[k-3];
                        for(pass=1; pass<=passcount; pass++)
                        {
                            t = a+(b-a)*math.randomreal();
                            err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, t)));
                        }
                    }
                    
                    //
                    // Test right part independence
                    //
                    if( k+3<=n-2 )
                    {
                        a = x[k+3];
                        b = 1;
                        for(pass=1; pass<=passcount; pass++)
                        {
                            t = a+(b-a)*math.randomreal();
                            err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, t)));
                        }
                    }
                }
                aserrors = aserrors | (double)(err)>(double)(threshold);
            }
            
            //
            // Differentiation, copy/unpack test
            //
            for(n=2; n<=maxn; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                
                //
                // Prepare cubic spline
                //
                a = -1-math.randomreal();
                b = 1+math.randomreal();
                for(i=0; i<=n-1; i++)
                {
                    x[i] = a+(b-a)*i/(n-1);
                    y[i] = Math.Cos(1.3*Math.PI*x[i]+0.4);
                }
                spline1d.spline1dbuildcubic(x, y, n, 2, 0.0, 2, 0.0, c);
                
                //
                // Test diff
                //
                err = 0;
                for(pass=1; pass<=passcount; pass++)
                {
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1ddiff(c, t, ref s, ref ds, ref d2s);
                    vl = spline1d.spline1dcalc(c, t-h);
                    vm = spline1d.spline1dcalc(c, t);
                    vr = spline1d.spline1dcalc(c, t+h);
                    err = Math.Max(err, Math.Abs(s-vm));
                    err = Math.Max(err, Math.Abs(ds-(vr-vl)/(2*h)));
                    err = Math.Max(err, Math.Abs(d2s-(vr-2*vm+vl)/math.sqr(h)));
                }
                dserrors = dserrors | (double)(err)>(double)(0.001);
                
                //
                // Test copy
                //
                unsetspline1d(c2);
                spline1d.spline1dcopy(c, c2);
                err = 0;
                for(pass=1; pass<=passcount; pass++)
                {
                    t = a+(b-a)*math.randomreal();
                    err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, t)));
                }
                cperrors = cperrors | (double)(err)>(double)(threshold);
                
                //
                // Test unpack
                //
                uperrors = uperrors | !testunpack(c, x);
                
                //
                // Test lin.trans.
                //
                err = 0;
                for(pass=1; pass<=passcount; pass++)
                {
                    
                    //
                    // LinTransX, general A
                    //
                    sa = 4*math.randomreal()-2;
                    sb = 2*math.randomreal()-1;
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1dcopy(c, c2);
                    spline1d.spline1dlintransx(c2, sa, sb);
                    err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, t)-spline1d.spline1dcalc(c2, (t-sb)/sa)));
                    
                    //
                    // LinTransX, special case: A=0
                    //
                    sb = 2*math.randomreal()-1;
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1dcopy(c, c2);
                    spline1d.spline1dlintransx(c2, 0, sb);
                    err = Math.Max(err, Math.Abs(spline1d.spline1dcalc(c, sb)-spline1d.spline1dcalc(c2, t)));
                    
                    //
                    // LinTransY
                    //
                    sa = 2*math.randomreal()-1;
                    sb = 2*math.randomreal()-1;
                    t = a+(b-a)*math.randomreal();
                    spline1d.spline1dcopy(c, c2);
                    spline1d.spline1dlintransy(c2, sa, sb);
                    err = Math.Max(err, Math.Abs(sa*spline1d.spline1dcalc(c, t)+sb-spline1d.spline1dcalc(c2, t)));
                }
                lterrors = lterrors | (double)(err)>(double)(threshold);
            }
            
            //
            // Testing integration.
            // Three tests are performed:
            //
            // * approximate test (well behaved smooth function, many points,
            //   integration inside [a,b]), non-periodic spline
            //
            // * exact test (integration of parabola, outside of [a,b], non-periodic spline
            //
            // * approximate test for periodic splines. F(x)=cos(2*pi*x)+1.
            //   Period length is equals to 1.0, so all operations with
            //   multiples of period are done exactly. For each value of PERIOD
            //   we calculate and test integral at four points:
            //   -   0 < t0 < PERIOD
            //   -   t1 = PERIOD-eps
            //   -   t2 = PERIOD
            //   -   t3 = PERIOD+eps
            //
            err = 0;
            for(n=20; n<=35; n++)
            {
                x = new double[n-1+1];
                y = new double[n-1+1];
                for(pass=1; pass<=passcount; pass++)
                {
                    
                    //
                    // Prepare cubic spline
                    //
                    a = -1-0.2*math.randomreal();
                    b = 1+0.2*math.randomreal();
                    for(i=0; i<=n-1; i++)
                    {
                        x[i] = a+(b-a)*i/(n-1);
                        y[i] = Math.Sin(Math.PI*x[i]+0.4)+Math.Exp(x[i]);
                    }
                    bl = Math.PI*Math.Cos(Math.PI*a+0.4)+Math.Exp(a);
                    br = Math.PI*Math.Cos(Math.PI*b+0.4)+Math.Exp(b);
                    spline1d.spline1dbuildcubic(x, y, n, 1, bl, 1, br, c);
                    
                    //
                    // Test
                    //
                    t = a+(b-a)*math.randomreal();
                    v = -(Math.Cos(Math.PI*a+0.4)/Math.PI)+Math.Exp(a);
                    v = -(Math.Cos(Math.PI*t+0.4)/Math.PI)+Math.Exp(t)-v;
                    v = v-spline1d.spline1dintegrate(c, t);
                    err = Math.Max(err, Math.Abs(v));
                }
            }
            ierrors = ierrors | (double)(err)>(double)(0.001);
            p0 = 2*math.randomreal()-1;
            p1 = 2*math.randomreal()-1;
            p2 = 2*math.randomreal()-1;
            a = -math.randomreal()-0.5;
            b = math.randomreal()+0.5;
            n = 2;
            x = new double[n];
            y = new double[n];
            d = new double[n];
            x[0] = a;
            y[0] = p0+p1*a+p2*math.sqr(a);
            d[0] = p1+2*p2*a;
            x[1] = b;
            y[1] = p0+p1*b+p2*math.sqr(b);
            d[1] = p1+2*p2*b;
            spline1d.spline1dbuildhermite(x, y, d, n, c);
            bl = Math.Min(a, b)-Math.Abs(b-a);
            br = Math.Min(a, b)+Math.Abs(b-a);
            err = 0;
            for(pass=1; pass<=100; pass++)
            {
                t = bl+(br-bl)*math.randomreal();
                v = p0*t+p1*math.sqr(t)/2+p2*math.sqr(t)*t/3-(p0*a+p1*math.sqr(a)/2+p2*math.sqr(a)*a/3);
                v = v-spline1d.spline1dintegrate(c, t);
                err = Math.Max(err, Math.Abs(v));
            }
            ierrors = ierrors | (double)(err)>(double)(threshold);
            n = 100;
            x = new double[n];
            y = new double[n];
            for(i=0; i<=n-1; i++)
            {
                x[i] = (double)i/(double)(n-1);
                y[i] = Math.Cos(2*Math.PI*x[i])+1;
            }
            y[0] = 2;
            y[n-1] = 2;
            spline1d.spline1dbuildcubic(x, y, n, -1, 0.0, -1, 0.0, c);
            intab = spline1d.spline1dintegrate(c, 1.0);
            v = math.randomreal();
            vr = spline1d.spline1dintegrate(c, v);
            ierrors = ierrors | (double)(Math.Abs(intab-1))>(double)(0.001);
            for(i=-10; i<=10; i++)
            {
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i+v)-(i*intab+vr)))>(double)(0.001);
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i-1000*math.machineepsilon)-i*intab))>(double)(0.001);
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i)-i*intab))>(double)(0.001);
                ierrors = ierrors | (double)(Math.Abs(spline1d.spline1dintegrate(c, i+1000*math.machineepsilon)-i*intab))>(double)(0.001);
            }
            
            //
            // report
            //
            waserrors = ((((((((lserrors | cserrors) | crserrors) | hserrors) | aserrors) | dserrors) | cperrors) | uperrors) | lterrors) | ierrors;
            if( !silent )
            {
                System.Console.Write("TESTING SPLINE INTERPOLATION");
                System.Console.WriteLine();
                
                //
                // Normal tests
                //
                System.Console.Write("LINEAR SPLINE TEST:                      ");
                if( lserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("CUBIC SPLINE TEST:                       ");
                if( cserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("CATMULL-ROM SPLINE TEST:                 ");
                if( crserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("HERMITE SPLINE TEST:                     ");
                if( hserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("AKIMA SPLINE TEST:                       ");
                if( aserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("DIFFERENTIATION TEST:                    ");
                if( dserrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("COPY/SERIALIZATION TEST:                 ");
                if( cperrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("UNPACK TEST:                             ");
                if( uperrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("LIN.TRANS. TEST:                         ");
                if( lterrors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("INTEGRATION TEST:                        ");
                if( ierrors )
                {
                    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;
        }
Exemple #18
0
        /*************************************************************************
        Bicubic spline resampling

        Input parameters:
            A           -   function values at the old grid,
                            array[0..OldHeight-1, 0..OldWidth-1]
            OldHeight   -   old grid height, OldHeight>1
            OldWidth    -   old grid width, OldWidth>1
            NewHeight   -   new grid height, NewHeight>1
            NewWidth    -   new grid width, NewWidth>1
            
        Output parameters:
            B           -   function values at the new grid,
                            array[0..NewHeight-1, 0..NewWidth-1]

          -- ALGLIB routine --
             15 May, 2007
             Copyright by Bochkanov Sergey
        *************************************************************************/
        public static void spline2dresamplebicubic(double[,] a,
            int oldheight,
            int oldwidth,
            ref double[,] b,
            int newheight,
            int newwidth)
        {
            double[,] buf = new double[0,0];
            double[] x = new double[0];
            double[] y = new double[0];
            spline1d.spline1dinterpolant c = new spline1d.spline1dinterpolant();
            int mw = 0;
            int mh = 0;
            int i = 0;
            int j = 0;

            b = new double[0,0];

            alglib.ap.assert(oldwidth>1 && oldheight>1, "Spline2DResampleBicubic: width/height less than 1");
            alglib.ap.assert(newwidth>1 && newheight>1, "Spline2DResampleBicubic: width/height less than 1");
            
            //
            // Prepare
            //
            mw = Math.Max(oldwidth, newwidth);
            mh = Math.Max(oldheight, newheight);
            b = new double[newheight, newwidth];
            buf = new double[oldheight, newwidth];
            x = new double[Math.Max(mw, mh)];
            y = new double[Math.Max(mw, mh)];
            
            //
            // Horizontal interpolation
            //
            for(i=0; i<=oldheight-1; i++)
            {
                
                //
                // Fill X, Y
                //
                for(j=0; j<=oldwidth-1; j++)
                {
                    x[j] = (double)j/(double)(oldwidth-1);
                    y[j] = a[i,j];
                }
                
                //
                // Interpolate and place result into temporary matrix
                //
                spline1d.spline1dbuildcubic(x, y, oldwidth, 0, 0.0, 0, 0.0, c);
                for(j=0; j<=newwidth-1; j++)
                {
                    buf[i,j] = spline1d.spline1dcalc(c, (double)j/(double)(newwidth-1));
                }
            }
            
            //
            // Vertical interpolation
            //
            for(j=0; j<=newwidth-1; j++)
            {
                
                //
                // Fill X, Y
                //
                for(i=0; i<=oldheight-1; i++)
                {
                    x[i] = (double)i/(double)(oldheight-1);
                    y[i] = buf[i,j];
                }
                
                //
                // Interpolate and place result into B
                //
                spline1d.spline1dbuildcubic(x, y, oldheight, 0, 0.0, 0, 0.0, c);
                for(i=0; i<=newheight-1; i++)
                {
                    b[i,j] = spline1d.spline1dcalc(c, (double)i/(double)(newheight-1));
                }
            }
        }
        public static bool testpspline(bool silent)
        {
            bool result = new bool();
            bool waserrors = new bool();
            bool p2errors = new bool();
            bool p3errors = new bool();
            double nonstrictthreshold = 0;
            double threshold = 0;
            int passcount = 0;
            double lstep = 0;
            double h = 0;
            int maxn = 0;
            int periodicity = 0;
            int skind = 0;
            int pkind = 0;
            bool periodic = new bool();
            double a = 0;
            double b = 0;
            int n = 0;
            int tmpn = 0;
            int i = 0;
            double vx = 0;
            double vy = 0;
            double vz = 0;
            double vx2 = 0;
            double vy2 = 0;
            double vz2 = 0;
            double vdx = 0;
            double vdy = 0;
            double vdz = 0;
            double vdx2 = 0;
            double vdy2 = 0;
            double vdz2 = 0;
            double vd2x = 0;
            double vd2y = 0;
            double vd2z = 0;
            double vd2x2 = 0;
            double vd2y2 = 0;
            double vd2z2 = 0;
            double v0 = 0;
            double v1 = 0;
            double[] x = new double[0];
            double[] y = new double[0];
            double[] z = new double[0];
            double[] t = new double[0];
            double[] t2 = new double[0];
            double[] t3 = new double[0];
            double[,] xy = new double[0,0];
            double[,] xyz = new double[0,0];
            pspline.pspline2interpolant p2 = new pspline.pspline2interpolant();
            pspline.pspline3interpolant p3 = new pspline.pspline3interpolant();
            spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
            int i_ = 0;

            waserrors = false;
            passcount = 20;
            lstep = 0.005;
            h = 0.00001;
            maxn = 10;
            threshold = 10000*math.machineepsilon;
            nonstrictthreshold = 0.00001;
            p2errors = false;
            p3errors = false;
            
            //
            // Test basic properties of 2- and 3-dimensional splines:
            // * PSpline2ParameterValues() properties
            // * values at nodes
            // * for periodic splines - periodicity properties
            //
            // Variables used:
            // * N              points count
            // * SKind          spline
            // * PKind          parameterization
            // * Periodicity    whether we have periodic spline or not
            //
            for(n=2; n<=maxn; n++)
            {
                for(skind=0; skind<=2; skind++)
                {
                    for(pkind=0; pkind<=2; pkind++)
                    {
                        for(periodicity=0; periodicity<=1; periodicity++)
                        {
                            periodic = periodicity==1;
                            
                            //
                            // skip unsupported combinations of parameters
                            //
                            if( periodic & n<3 )
                            {
                                continue;
                            }
                            if( periodic & skind==0 )
                            {
                                continue;
                            }
                            if( n<5 & skind==0 )
                            {
                                continue;
                            }
                            
                            //
                            // init
                            //
                            xy = new double[n, 2];
                            xyz = new double[n, 3];
                            apserv.taskgenint1dequidist(-1, 1, n, ref t2, ref x);
                            for(i_=0; i_<=n-1;i_++)
                            {
                                xy[i_,0] = x[i_];
                            }
                            for(i_=0; i_<=n-1;i_++)
                            {
                                xyz[i_,0] = x[i_];
                            }
                            apserv.taskgenint1dequidist(-1, 1, n, ref t2, ref y);
                            for(i_=0; i_<=n-1;i_++)
                            {
                                xy[i_,1] = y[i_];
                            }
                            for(i_=0; i_<=n-1;i_++)
                            {
                                xyz[i_,1] = y[i_];
                            }
                            apserv.taskgenint1dequidist(-1, 1, n, ref t2, ref z);
                            for(i_=0; i_<=n-1;i_++)
                            {
                                xyz[i_,2] = z[i_];
                            }
                            unsetp2(p2);
                            unsetp3(p3);
                            if( periodic )
                            {
                                pspline.pspline2buildperiodic(xy, n, skind, pkind, p2);
                                pspline.pspline3buildperiodic(xyz, n, skind, pkind, p3);
                            }
                            else
                            {
                                pspline.pspline2build(xy, n, skind, pkind, p2);
                                pspline.pspline3build(xyz, n, skind, pkind, p3);
                            }
                            
                            //
                            // PSpline2ParameterValues() properties
                            //
                            pspline.pspline2parametervalues(p2, ref tmpn, ref t2);
                            if( tmpn!=n )
                            {
                                p2errors = true;
                                continue;
                            }
                            pspline.pspline3parametervalues(p3, ref tmpn, ref t3);
                            if( tmpn!=n )
                            {
                                p3errors = true;
                                continue;
                            }
                            p2errors = p2errors | (double)(t2[0])!=(double)(0);
                            p3errors = p3errors | (double)(t3[0])!=(double)(0);
                            for(i=1; i<=n-1; i++)
                            {
                                p2errors = p2errors | (double)(t2[i])<=(double)(t2[i-1]);
                                p3errors = p3errors | (double)(t3[i])<=(double)(t3[i-1]);
                            }
                            if( periodic )
                            {
                                p2errors = p2errors | (double)(t2[n-1])>=(double)(1);
                                p3errors = p3errors | (double)(t3[n-1])>=(double)(1);
                            }
                            else
                            {
                                p2errors = p2errors | (double)(t2[n-1])!=(double)(1);
                                p3errors = p3errors | (double)(t3[n-1])!=(double)(1);
                            }
                            
                            //
                            // Now we have parameter values stored at T,
                            // and want to test whether the actully correspond to
                            // points
                            //
                            for(i=0; i<=n-1; i++)
                            {
                                
                                //
                                // 2-dimensional test
                                //
                                pspline.pspline2calc(p2, t2[i], ref vx, ref vy);
                                p2errors = p2errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                
                                //
                                // 3-dimensional test
                                //
                                pspline.pspline3calc(p3, t3[i], ref vx, ref vy, ref vz);
                                p3errors = p3errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz-z[i]))>(double)(threshold);
                            }
                            
                            //
                            // Test periodicity (if needed)
                            //
                            if( periodic )
                            {
                                
                                //
                                // periodicity at nodes
                                //
                                for(i=0; i<=n-1; i++)
                                {
                                    
                                    //
                                    // 2-dimensional test
                                    //
                                    pspline.pspline2calc(p2, t2[i]+math.randominteger(10)-5, ref vx, ref vy);
                                    p2errors = p2errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                    p2errors = p2errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                    pspline.pspline2diff(p2, t2[i]+math.randominteger(10)-5, ref vx, ref vdx, ref vy, ref vdy);
                                    p2errors = p2errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                    p2errors = p2errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                    pspline.pspline2diff2(p2, t2[i]+math.randominteger(10)-5, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y);
                                    p2errors = p2errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                    p2errors = p2errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                    
                                    //
                                    // 3-dimensional test
                                    //
                                    pspline.pspline3calc(p3, t3[i]+math.randominteger(10)-5, ref vx, ref vy, ref vz);
                                    p3errors = p3errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vz-z[i]))>(double)(threshold);
                                    pspline.pspline3diff(p3, t3[i]+math.randominteger(10)-5, ref vx, ref vdx, ref vy, ref vdy, ref vz, ref vdz);
                                    p3errors = p3errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vz-z[i]))>(double)(threshold);
                                    pspline.pspline3diff2(p3, t3[i]+math.randominteger(10)-5, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y, ref vz, ref vdz, ref vd2z);
                                    p3errors = p3errors | (double)(Math.Abs(vx-x[i]))>(double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vy-y[i]))>(double)(threshold);
                                    p3errors = p3errors | (double)(Math.Abs(vz-z[i]))>(double)(threshold);
                                }
                                
                                //
                                // periodicity between nodes
                                //
                                v0 = math.randomreal();
                                pspline.pspline2calc(p2, v0, ref vx, ref vy);
                                pspline.pspline2calc(p2, v0+math.randominteger(10)-5, ref vx2, ref vy2);
                                p2errors = p2errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                pspline.pspline3calc(p3, v0, ref vx, ref vy, ref vz);
                                pspline.pspline3calc(p3, v0+math.randominteger(10)-5, ref vx2, ref vy2, ref vz2);
                                p3errors = p3errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz-vz2))>(double)(threshold);
                                
                                //
                                // near-boundary test for continuity of function values and derivatives:
                                // 2-dimensional curve
                                //
                                ap.assert(skind==1 | skind==2, "TEST: unexpected spline type!");
                                v0 = 100*math.machineepsilon;
                                v1 = 1-v0;
                                pspline.pspline2calc(p2, v0, ref vx, ref vy);
                                pspline.pspline2calc(p2, v1, ref vx2, ref vy2);
                                p2errors = p2errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                pspline.pspline2diff(p2, v0, ref vx, ref vdx, ref vy, ref vdy);
                                pspline.pspline2diff(p2, v1, ref vx2, ref vdx2, ref vy2, ref vdy2);
                                p2errors = p2errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vdx-vdx2))>(double)(nonstrictthreshold);
                                p2errors = p2errors | (double)(Math.Abs(vdy-vdy2))>(double)(nonstrictthreshold);
                                pspline.pspline2diff2(p2, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y);
                                pspline.pspline2diff2(p2, v1, ref vx2, ref vdx2, ref vd2x2, ref vy2, ref vdy2, ref vd2y2);
                                p2errors = p2errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                p2errors = p2errors | (double)(Math.Abs(vdx-vdx2))>(double)(nonstrictthreshold);
                                p2errors = p2errors | (double)(Math.Abs(vdy-vdy2))>(double)(nonstrictthreshold);
                                if( skind==2 )
                                {
                                    
                                    //
                                    // second derivative test only for cubic splines
                                    //
                                    p2errors = p2errors | (double)(Math.Abs(vd2x-vd2x2))>(double)(nonstrictthreshold);
                                    p2errors = p2errors | (double)(Math.Abs(vd2y-vd2y2))>(double)(nonstrictthreshold);
                                }
                                
                                //
                                // near-boundary test for continuity of function values and derivatives:
                                // 3-dimensional curve
                                //
                                ap.assert(skind==1 | skind==2, "TEST: unexpected spline type!");
                                v0 = 100*math.machineepsilon;
                                v1 = 1-v0;
                                pspline.pspline3calc(p3, v0, ref vx, ref vy, ref vz);
                                pspline.pspline3calc(p3, v1, ref vx2, ref vy2, ref vz2);
                                p3errors = p3errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz-vz2))>(double)(threshold);
                                pspline.pspline3diff(p3, v0, ref vx, ref vdx, ref vy, ref vdy, ref vz, ref vdz);
                                pspline.pspline3diff(p3, v1, ref vx2, ref vdx2, ref vy2, ref vdy2, ref vz2, ref vdz2);
                                p3errors = p3errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz-vz2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vdx-vdx2))>(double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdy-vdy2))>(double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdz-vdz2))>(double)(nonstrictthreshold);
                                pspline.pspline3diff2(p3, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y, ref vz, ref vdz, ref vd2z);
                                pspline.pspline3diff2(p3, v1, ref vx2, ref vdx2, ref vd2x2, ref vy2, ref vdy2, ref vd2y2, ref vz2, ref vdz2, ref vd2z2);
                                p3errors = p3errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vz-vz2))>(double)(threshold);
                                p3errors = p3errors | (double)(Math.Abs(vdx-vdx2))>(double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdy-vdy2))>(double)(nonstrictthreshold);
                                p3errors = p3errors | (double)(Math.Abs(vdz-vdz2))>(double)(nonstrictthreshold);
                                if( skind==2 )
                                {
                                    
                                    //
                                    // second derivative test only for cubic splines
                                    //
                                    p3errors = p3errors | (double)(Math.Abs(vd2x-vd2x2))>(double)(nonstrictthreshold);
                                    p3errors = p3errors | (double)(Math.Abs(vd2y-vd2y2))>(double)(nonstrictthreshold);
                                    p3errors = p3errors | (double)(Math.Abs(vd2z-vd2z2))>(double)(nonstrictthreshold);
                                }
                            }
                        }
                    }
                }
            }
            
            //
            // Test differentiation, tangents, calculation between nodes.
            //
            // Because differentiation is done in parameterization/spline/periodicity
            // oblivious manner, we don't have to test all possible combinations
            // of spline types and parameterizations.
            //
            // Actually we test special combination with properties which allow us
            // to easily solve this problem:
            // * 2 (3) variables
            // * first variable is sampled from equidistant grid on [0,1]
            // * other variables are random
            // * uniform parameterization is used
            // * periodicity - none
            // * spline type - any (we use cubic splines)
            // Same problem allows us to test calculation BETWEEN nodes.
            //
            for(n=2; n<=maxn; n++)
            {
                
                //
                // init
                //
                xy = new double[n, 2];
                xyz = new double[n, 3];
                apserv.taskgenint1dequidist(0, 1, n, ref t, ref x);
                for(i_=0; i_<=n-1;i_++)
                {
                    xy[i_,0] = x[i_];
                }
                for(i_=0; i_<=n-1;i_++)
                {
                    xyz[i_,0] = x[i_];
                }
                apserv.taskgenint1dequidist(0, 1, n, ref t, ref y);
                for(i_=0; i_<=n-1;i_++)
                {
                    xy[i_,1] = y[i_];
                }
                for(i_=0; i_<=n-1;i_++)
                {
                    xyz[i_,1] = y[i_];
                }
                apserv.taskgenint1dequidist(0, 1, n, ref t, ref z);
                for(i_=0; i_<=n-1;i_++)
                {
                    xyz[i_,2] = z[i_];
                }
                unsetp2(p2);
                unsetp3(p3);
                pspline.pspline2build(xy, n, 2, 0, p2);
                pspline.pspline3build(xyz, n, 2, 0, p3);
                
                //
                // Test 2D/3D spline:
                // * build non-parametric cubic spline from T and X/Y
                // * calculate its value and derivatives at V0
                // * compare with Spline2Calc/Spline2Diff/Spline2Diff2
                // Because of task properties both variants should
                // return same answer.
                //
                v0 = math.randomreal();
                spline1d.spline1dbuildcubic(t, x, n, 0, 0.0, 0, 0.0, s);
                spline1d.spline1ddiff(s, v0, ref vx2, ref vdx2, ref vd2x2);
                spline1d.spline1dbuildcubic(t, y, n, 0, 0.0, 0, 0.0, s);
                spline1d.spline1ddiff(s, v0, ref vy2, ref vdy2, ref vd2y2);
                spline1d.spline1dbuildcubic(t, z, n, 0, 0.0, 0, 0.0, s);
                spline1d.spline1ddiff(s, v0, ref vz2, ref vdz2, ref vd2z2);
                
                //
                // 2D test
                //
                pspline.pspline2calc(p2, v0, ref vx, ref vy);
                p2errors = p2errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                pspline.pspline2diff(p2, v0, ref vx, ref vdx, ref vy, ref vdy);
                p2errors = p2errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdx-vdx2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdy-vdy2))>(double)(threshold);
                pspline.pspline2diff2(p2, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y);
                p2errors = p2errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdx-vdx2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vdy-vdy2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vd2x-vd2x2))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vd2y-vd2y2))>(double)(threshold);
                
                //
                // 3D test
                //
                pspline.pspline3calc(p3, v0, ref vx, ref vy, ref vz);
                p3errors = p3errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz-vz2))>(double)(threshold);
                pspline.pspline3diff(p3, v0, ref vx, ref vdx, ref vy, ref vdy, ref vz, ref vdz);
                p3errors = p3errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz-vz2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdx-vdx2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdy-vdy2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdz-vdz2))>(double)(threshold);
                pspline.pspline3diff2(p3, v0, ref vx, ref vdx, ref vd2x, ref vy, ref vdy, ref vd2y, ref vz, ref vdz, ref vd2z);
                p3errors = p3errors | (double)(Math.Abs(vx-vx2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy-vy2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz-vz2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdx-vdx2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdy-vdy2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vdz-vdz2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vd2x-vd2x2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vd2y-vd2y2))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vd2z-vd2z2))>(double)(threshold);
                
                //
                // Test tangents for 2D/3D
                //
                pspline.pspline2tangent(p2, v0, ref vx, ref vy);
                p2errors = p2errors | (double)(Math.Abs(vx-vdx2/apserv.safepythag2(vdx2, vdy2)))>(double)(threshold);
                p2errors = p2errors | (double)(Math.Abs(vy-vdy2/apserv.safepythag2(vdx2, vdy2)))>(double)(threshold);
                pspline.pspline3tangent(p3, v0, ref vx, ref vy, ref vz);
                p3errors = p3errors | (double)(Math.Abs(vx-vdx2/apserv.safepythag3(vdx2, vdy2, vdz2)))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vy-vdy2/apserv.safepythag3(vdx2, vdy2, vdz2)))>(double)(threshold);
                p3errors = p3errors | (double)(Math.Abs(vz-vdz2/apserv.safepythag3(vdx2, vdy2, vdz2)))>(double)(threshold);
            }
            
            //
            // Arc length test.
            //
            // Simple problem with easy solution (points on a straight line with
            // uniform parameterization).
            //
            for(n=2; n<=maxn; n++)
            {
                xy = new double[n, 2];
                xyz = new double[n, 3];
                for(i=0; i<=n-1; i++)
                {
                    xy[i,0] = i;
                    xy[i,1] = i;
                    xyz[i,0] = i;
                    xyz[i,1] = i;
                    xyz[i,2] = i;
                }
                pspline.pspline2build(xy, n, 1, 0, p2);
                pspline.pspline3build(xyz, n, 1, 0, p3);
                a = math.randomreal();
                b = math.randomreal();
                p2errors = p2errors | (double)(Math.Abs(pspline.pspline2arclength(p2, a, b)-(b-a)*Math.Sqrt(2)*(n-1)))>(double)(nonstrictthreshold);
                p3errors = p3errors | (double)(Math.Abs(pspline.pspline3arclength(p3, a, b)-(b-a)*Math.Sqrt(3)*(n-1)))>(double)(nonstrictthreshold);
            }
            
            //
            // report
            //
            waserrors = p2errors | p3errors;
            if( !silent )
            {
                System.Console.Write("TESTING SPLINE INTERPOLATION");
                System.Console.WriteLine();
                
                //
                // Normal tests
                //
                System.Console.Write("2D TEST:                                 ");
                if( p2errors )
                {
                    System.Console.Write("FAILED");
                    System.Console.WriteLine();
                }
                else
                {
                    System.Console.Write("OK");
                    System.Console.WriteLine();
                }
                System.Console.Write("3D TEST:                                 ");
                if( p3errors )
                {
                    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;
        }
Exemple #20
0
        /*************************************************************************
        Internal subroutine.
        Calculation of the first derivatives and the cross-derivative.
        *************************************************************************/
        private static void bicubiccalcderivatives(double[,] a,
            double[] x,
            double[] y,
            int m,
            int n,
            ref double[,] dx,
            ref double[,] dy,
            ref double[,] dxy)
        {
            int i = 0;
            int j = 0;
            double[] xt = new double[0];
            double[] ft = new double[0];
            double s = 0;
            double ds = 0;
            double d2s = 0;
            spline1d.spline1dinterpolant c = new spline1d.spline1dinterpolant();

            dx = new double[0,0];
            dy = new double[0,0];
            dxy = new double[0,0];

            dx = new double[m, n];
            dy = new double[m, n];
            dxy = new double[m, n];
            
            //
            // dF/dX
            //
            xt = new double[n];
            ft = new double[n];
            for(i=0; i<=m-1; i++)
            {
                for(j=0; j<=n-1; j++)
                {
                    xt[j] = x[j];
                    ft[j] = a[i,j];
                }
                spline1d.spline1dbuildcubic(xt, ft, n, 0, 0.0, 0, 0.0, c);
                for(j=0; j<=n-1; j++)
                {
                    spline1d.spline1ddiff(c, x[j], ref s, ref ds, ref d2s);
                    dx[i,j] = ds;
                }
            }
            
            //
            // dF/dY
            //
            xt = new double[m];
            ft = new double[m];
            for(j=0; j<=n-1; j++)
            {
                for(i=0; i<=m-1; i++)
                {
                    xt[i] = y[i];
                    ft[i] = a[i,j];
                }
                spline1d.spline1dbuildcubic(xt, ft, m, 0, 0.0, 0, 0.0, c);
                for(i=0; i<=m-1; i++)
                {
                    spline1d.spline1ddiff(c, y[i], ref s, ref ds, ref d2s);
                    dy[i,j] = ds;
                }
            }
            
            //
            // d2F/dXdY
            //
            xt = new double[n];
            ft = new double[n];
            for(i=0; i<=m-1; i++)
            {
                for(j=0; j<=n-1; j++)
                {
                    xt[j] = x[j];
                    ft[j] = dy[i,j];
                }
                spline1d.spline1dbuildcubic(xt, ft, n, 0, 0.0, 0, 0.0, c);
                for(j=0; j<=n-1; j++)
                {
                    spline1d.spline1ddiff(c, x[j], ref s, ref ds, ref d2s);
                    dxy[i,j] = ds;
                }
            }
        }
        /*************************************************************************
        *  Bicubic spline resampling
        *
        *  Input parameters:
        *   A           -   function values at the old grid,
        *                   array[0..OldHeight-1, 0..OldWidth-1]
        *   OldHeight   -   old grid height, OldHeight>1
        *   OldWidth    -   old grid width, OldWidth>1
        *   NewHeight   -   new grid height, NewHeight>1
        *   NewWidth    -   new grid width, NewWidth>1
        *
        *  Output parameters:
        *   B           -   function values at the new grid,
        *                   array[0..NewHeight-1, 0..NewWidth-1]
        *
        *  -- ALGLIB routine --
        *    15 May, 2007
        *    Copyright by Bochkanov Sergey
        *************************************************************************/
        public static void spline2dresamplebicubic(ref double[,] a,
                                                   int oldheight,
                                                   int oldwidth,
                                                   ref double[,] b,
                                                   int newheight,
                                                   int newwidth)
        {
            double[,] buf = new double[0, 0];
            double[] x = new double[0];
            double[] y = new double[0];
            spline1d.spline1dinterpolant c = new spline1d.spline1dinterpolant();
            int i  = 0;
            int j  = 0;
            int mw = 0;
            int mh = 0;

            System.Diagnostics.Debug.Assert(oldwidth > 1 & oldheight > 1, "Spline2DResampleBicubic: width/height less than 1");
            System.Diagnostics.Debug.Assert(newwidth > 1 & newheight > 1, "Spline2DResampleBicubic: width/height less than 1");

            //
            // Prepare
            //
            mw  = Math.Max(oldwidth, newwidth);
            mh  = Math.Max(oldheight, newheight);
            b   = new double[newheight - 1 + 1, newwidth - 1 + 1];
            buf = new double[oldheight - 1 + 1, newwidth - 1 + 1];
            x   = new double[Math.Max(mw, mh) - 1 + 1];
            y   = new double[Math.Max(mw, mh) - 1 + 1];

            //
            // Horizontal interpolation
            //
            for (i = 0; i <= oldheight - 1; i++)
            {
                //
                // Fill X, Y
                //
                for (j = 0; j <= oldwidth - 1; j++)
                {
                    x[j] = (double)(j) / ((double)(oldwidth - 1));
                    y[j] = a[i, j];
                }

                //
                // Interpolate and place result into temporary matrix
                //
                spline1d.spline1dbuildcubic(x, y, oldwidth, 0, 0.0, 0, 0.0, ref c);
                for (j = 0; j <= newwidth - 1; j++)
                {
                    buf[i, j] = spline1d.spline1dcalc(ref c, (double)(j) / ((double)(newwidth - 1)));
                }
            }

            //
            // Vertical interpolation
            //
            for (j = 0; j <= newwidth - 1; j++)
            {
                //
                // Fill X, Y
                //
                for (i = 0; i <= oldheight - 1; i++)
                {
                    x[i] = (double)(i) / ((double)(oldheight - 1));
                    y[i] = buf[i, j];
                }

                //
                // Interpolate and place result into B
                //
                spline1d.spline1dbuildcubic(x, y, oldheight, 0, 0.0, 0, 0.0, ref c);
                for (i = 0; i <= newheight - 1; i++)
                {
                    b[i, j] = spline1d.spline1dcalc(ref c, (double)(i) / ((double)(newheight - 1)));
                }
            }
        }
    public static int Main(string[] args)
    {
        double[] x = new double[0];
        double[] y = new double[0];
        int n = 0;
        int i = 0;
        int info = 0;
        spline1d.spline1dinterpolant s = new spline1d.spline1dinterpolant();
        double t = 0;
        spline1d.spline1dfitreport rep = new spline1d.spline1dfitreport();

        
        //
        // Fitting by unconstrained natural cubic spline
        //
        System.Console.Write("FITTING BY UNCONSTRAINED NATURAL CUBIC SPLINE");
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.Write("F(x)=sin(x)      function being fitted");
        System.Console.WriteLine();
        System.Console.Write("[0, pi]          interval");
        System.Console.WriteLine();
        System.Console.Write("M=4              number of basis functions to use");
        System.Console.WriteLine();
        System.Console.Write("N=100            number of points to fit");
        System.Console.WriteLine();
        
        //
        // Create and fit
        //
        n = 100;
        x = new double[n];
        y = new double[n];
        for(i=0; i<=n-1; i++)
        {
            x[i] = Math.PI*i/(n-1);
            y[i] = Math.Sin(x[i]);
        }
        spline1d.spline1dfitcubic(ref x, ref y, n, 4, ref info, ref s, ref rep);
        
        //
        // Output results
        //
        if( info>0 )
        {
            System.Console.WriteLine();
            System.Console.Write("OK, we have finished");
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("     x   F(x)   S(x)  Error");
            System.Console.WriteLine();
            t = 0;
            while( (double)(t)<(double)(0.999999*Math.PI) )
            {
                System.Console.Write("{0,6:F3}",t);
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}",Math.Sin(t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}",spline1d.spline1dcalc(ref s, t));
                System.Console.Write(" ");
                System.Console.Write("{0,6:F3}",Math.Abs(spline1d.spline1dcalc(ref s, t)-Math.Sin(t)));
                System.Console.WriteLine();
                t = Math.Min(Math.PI, t+0.25);
            }
            System.Console.Write("{0,6:F3}",t);
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",Math.Sin(t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",spline1d.spline1dcalc(ref s, t));
            System.Console.Write(" ");
            System.Console.Write("{0,6:F3}",Math.Abs(spline1d.spline1dcalc(ref s, t)-Math.Sin(t)));
            System.Console.WriteLine();
            System.Console.WriteLine();
            System.Console.Write("rms error is ");
            System.Console.Write("{0,6:F3}",rep.rmserror);
            System.Console.WriteLine();
            System.Console.Write("max error is ");
            System.Console.Write("{0,6:F3}",rep.maxerror);
            System.Console.WriteLine();
        }
        else
        {
            System.Console.WriteLine();
            System.Console.Write("Something wrong, Info=");
            System.Console.Write("{0,0:d}",info);
        }
        return 0;
    }