Example #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);
    }
    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);
    }
    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;
    }
Example #4
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;
        }
    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;
    }
 public spline1dfitreport(spline1d.spline1dfitreport obj)
 {
     _innerobj = obj;
 }
 public spline1dfitreport()
 {
     _innerobj = new spline1d.spline1dfitreport();
 }