Exemple #1
0
    public static void chain(ref typeMethods.r8vecNormalData data, ref int seed, int n, ref double[] xem, ref double[] vem, ref double diff)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    CHAIN tests the stochastic Chain Rule.
    //
    //  Discussion:
    //
    //    This function solves a stochastic differential equation for
    //
    //      V = sqrt(X)
    //
    //    where X satisfies the stochastic differential equation:
    //
    //      dX = ( alpha - X ) * dt + beta * sqrt(X) dW,
    //      X(0) = Xzero,
    //
    //    with
    //
    //      alpha = 2,
    //      beta = 1,
    //      Xzero = 1.
    //
    //    From the stochastic Chain Rule, the SDE for V is therefore:
    //
    //      dV = ( ( 4 * alpha - beta^2 ) / ( 8 * V ) - 1/2 V ) dt + 1/2 beta dW
    //      V(0) = sqrt ( Xzero ).
    //
    //    Xem is the Euler-Maruyama solution for X.
    //
    //    Vem is the Euler-Maruyama solution of the SDE for V from
    //    the stochastic Chain Rule.
    //
    //    Hence, we compare sqrt(Xem) and Vem.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original Matlab version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input, int &SEED, a seed for the random number generator.
    //
    //    Input, int N, the number of time steps.
    //
    //    Output, double XEM[N+1], the computed value of X.
    //
    //    Output, double VEM[N+1], the computed value of V.
    //
    //    Output, double &DIFF, the maximum value of |sqrt(XEM)-V|.
    //
    {
        int i;
        int j;
        //
        //  Set problem parameters.
        //
        const double alpha = 2.0;
        const double beta  = 1.0;
        //
        //  Stepping parameters.
        //  dt2 is the size of the Euler-Maruyama steps.
        //
        const double tmax = 1.0;
        double       dt   = tmax / n;

        //
        //  Define the increments dW.
        //
        double[] dw = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

        for (i = 0; i < n; i++)
        {
            dw[i] = Math.Sqrt(dt) * dw[i];
        }

        //
        //  Solve for X(t).
        //
        xem[0] = 1.0;
        for (j = 1; j <= n; j++)
        {
            xem[j] = xem[j - 1] + (alpha - xem[j - 1]) * dt
                     + beta * Math.Sqrt(xem[j - 1]) * dw[j - 1];
        }

        //
        //  Solve for V(t).
        //
        vem[0] = Math.Sqrt(xem[0]);
        for (j = 1; j <= n; j++)
        {
            vem[j] = vem[j - 1]
                     + ((4.0 * alpha - beta * beta) / (8.0 * vem[j - 1])
                        - 0.5 * vem[j - 1]) * dt
                     + 0.5 * beta * dw[j - 1];
        }

        //
        //  Compare sqrt(X) and V.
        //
        diff = 0.0;
        for (i = 0; i <= n; i++)
        {
            diff = Math.Max(diff, Math.Abs(Math.Sqrt(xem[i]) - vem[i]));
        }
    }
    public static double[] hypersphere01_sample(int m, int n, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    HYPERSPHERE01_SAMPLE uniformly samples the surface of the unit hypersphere.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    04 January 2014
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Russell Cheng,
    //    Random Variate Generation,
    //    in Handbook of Simulation,
    //    edited by Jerry Banks,
    //    Wiley, 1998, pages 168.
    //
    //    Reuven Rubinstein,
    //    Monte Carlo Optimization, Simulation, and Sensitivity
    //    of Queueing Networks,
    //    Krieger, 1992,
    //    ISBN: 0894647644,
    //    LC: QA298.R79.
    //
    //  Parameters:
    //
    //    Input, int M, the spatial dimension.
    //
    //    Input, int N, the number of points.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, double X[M*N], the points.
    //
    {
        int j;

        double[] x = typeMethods.r8mat_normal_01_new(m, n, ref data, ref seed);

        for (j = 0; j < n; j++)
        {
            //
            //  Compute the length of the vector.
            //
            double norm = 0.0;
            int    i;
            for (i = 0; i < m; i++)
            {
                norm += Math.Pow(x[i + j * m], 2);
            }

            norm = Math.Sqrt(norm);
            //
            //  Normalize the vector.
            //
            for (i = 0; i < m; i++)
            {
                x[i + j * m] /= norm;
            }
        }

        return(x);
    }
    public static void stab_meansquare(ref typeMethods.r8vecNormalData vdata, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    STAB_MEANSQUARE examines mean-square stability.
    //
    //  Discussion:
    //
    //    The function tests the mean-square stability
    //    of the Euler-Maruyama method applied to a stochastic differential
    //    equation (SDE).
    //
    //    The SDE is
    //
    //      dX = lambda*X dt + mu*X dW,
    //      X(0) = Xzero,
    //
    //    where
    //
    //      lambda is a constant,
    //      mu is a constant,
    //      Xzero = 1.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original Matlab version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input, int &SEED, a seed for the random number generator.
    //    In the reference, this value is set to 100.
    //
    {
        const string  command_filename = "stab_meansquare_commands.txt";
        List <string> command          = new();
        const string  data_filename0   = "stab_meansquare0_data.txt";
        List <string> data             = new();
        int           k;

        Console.WriteLine("");
        Console.WriteLine("STAB_MEANSQUARE:");
        Console.WriteLine("  Investigate mean square stability of Euler-Maruyama");
        Console.WriteLine("  solution with stepsize DT and MU.");
        Console.WriteLine("");
        Console.WriteLine("  SDE is mean square stable if");
        Console.WriteLine("    Real ( lambda + 1/2 |mu|^2 ) < 0.");
        Console.WriteLine("");
        Console.WriteLine("  EM with DT is mean square stable if");
        Console.WriteLine("    |1+dt^2| + dt * |mu|^2 - 1.0 < 0.");
        //
        //  Set problem parameters.
        //
        const double tmax  = 20.0;
        const int    m     = 50000;
        const double xzero = 1.0;
        //
        //  Problem parameters.
        //
        const double lambda = -3.0;
        double       mu     = Math.Sqrt(3.0);

        //
        //  Test the SDE.
        //
        Console.WriteLine("");
        Console.WriteLine("  Lambda = " + lambda + "");
        Console.WriteLine("  Mu =     " + mu + "");
        double test = lambda + 0.5 * mu * mu;

        Console.WriteLine("  SDE mean square stability test = " + test + "");
        //
        //  XMS is the mean square estimate of M paths.
        //
        string data_filename = data_filename0;

        for (k = 0; k < 3; k++)
        {
            double dt = Math.Pow(2.0, -k);
            int    n  = 20 * (int)Math.Pow(2, k);
            //
            //  Test the EM for this DT.
            //
            Console.WriteLine("");
            Console.WriteLine("  dt = " + dt + "");
            test = Math.Pow(1.0 + dt * lambda, 2) + dt * mu * mu - 1.0;
            Console.WriteLine("  EM mean square stability test = " + test + "");

            double[] xms   = new double[n + 1];
            double[] xtemp = new double[m];
            int      i;
            for (i = 0; i < m; i++)
            {
                xtemp[i] = xzero;
            }

            xms[0] = xzero;

            int j;
            for (j = 0; j <= n; j++)
            {
                double[] winc = typeMethods.r8vec_normal_01_new(m, ref vdata, ref seed);
                for (i = 0; i < m; i++)
                {
                    winc[i] = Math.Sqrt(dt) * winc[i];
                }

                for (i = 0; i < m; i++)
                {
                    xtemp[i] = xtemp[i]
                               + dt * lambda * xtemp[i]
                               + mu * xtemp[i] * winc[i];
                }

                xms[j] = 0.0;
                for (i = 0; i < m; i++)
                {
                    xms[j] += xtemp[i] * xtemp[i];
                }

                xms[j] /= m;
            }

            //
            //  Write this data to a file.
            //
            Files.filename_inc(ref data_filename);

            for (j = 0; j <= n; j++)
            {
                double t = tmax * j / n;
                data.Add("  " + t
                         + "  " + xms[j] + "");
            }

            File.WriteAllLines(data_filename, data);

            Console.WriteLine("");
            Console.WriteLine("  Data for DT = " + dt + " stored in \"" + data_filename + "\".");


            command.Add("# stab_meansquare_commands.txt");
            command.Add("# created by sde::stab_meansquare.");
            command.Add("#");
            command.Add("# Usage:");
            command.Add("#  gnuplot < stab_meansquare_commands.txt");
            command.Add("#");
            command.Add("set term png");
            command.Add("set output 'stab_meansquare.png'");
            command.Add("set xlabel 't'");
            command.Add("set ylabel 'E|X^2(t)|'");
            command.Add("set title 'Mean Square of EM Solution'");
            command.Add("set grid");
            command.Add("set logscale y 10");
            command.Add("set style data lines");

            data_filename = data_filename0;

            Files.filename_inc(ref data_filename);
            command.Add("plot '" + data_filename + "' using 1:2, \\");

            for (k = 1; k <= 1; k++)
            {
                Files.filename_inc(ref data_filename);
                command.Add("     '" + data_filename + "' using 1:2, \\");
            }

            Files.filename_inc(ref data_filename);
            command.Add("     '" + data_filename + "' using 1:2");

            command.Add("quit");

            File.WriteAllLines(command_filename, command);

            Console.WriteLine("  STAB_MEANSQUARE plot commands stored in \"" + command_filename + "\".");
        }
    }
Exemple #4
0
    public static double[] disk_sample(double[] center, double r, int n, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    DISK_SAMPLE uniformly samples the general disk in 2D.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    05 July 2018
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, double CENTER[2], coordinates of the center.
    //    This information is not actually needed to compute the area.
    //
    //    Input, double R, the radius of the disk.
    //
    //    Input, int N, the number of points.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, double X[2*N], the points.
    //
    {
        int j;

        double[] x = new double[2 * n];

        for (j = 0; j < n; j++)
        {
            double[] v = typeMethods.r8vec_normal_01_new(2, ref data, ref seed);
            //
            //  Compute the length of the vector.
            //
            double norm = Math.Sqrt(Math.Pow(v[0], 2) + Math.Pow(v[1], 2));
            //
            //  Normalize the vector.
            //
            int i;
            for (i = 0; i < 2; i++)
            {
                v[i] /= norm;
            }

            //
            //  Now compute a value to map the point ON the circle INTO the circle.
            //
            double r2 = UniformRNG.r8_uniform_01(ref seed);

            for (i = 0; i < 2; i++)
            {
                x[i + j * 2] = center[i] + r * Math.Sqrt(r2) * v[i];
            }
        }

        return(x);
    }
Exemple #5
0
    public static double[] bpath(ref typeMethods.r8vecNormalData data, ref int seed, int n)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    BPATH performs a Brownian path simulation.
    //
    //  Discussion:
    //
    //    This routine computes one simulation of discretized Brownian
    //    motion over the time interval [0,1] using N time steps.
    //    The user specifies a random number seed.  Different values of
    //    the seed will result in different realizations of the path.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original MATLAB version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input/output, int &SEED, a seed for the random number
    //    generator.
    //
    //    Input, int N, the number of steps.
    //
    //    Output, double BPATH[N+1], the Brownian path.
    //
    {
        int j;

        const double tmax = 1.0;
        double       dt   = tmax / n;

        //
        //  Define the increments dW.
        //
        double[] dw = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

        for (j = 0; j < n; j++)
        {
            dw[j] = Math.Sqrt(dt) * dw[j];
        }

        //
        //  W is the sum of the previous increments.
        //
        double[] w = new double[n + 1];

        w[0] = 0.0;
        for (j = 1; j < n; j++)
        {
            w[j] = w[j - 1] + dw[j];
        }

        return(w);
    }
    public static double[] mc(double s0, double e, double r, double sigma, double t1, int m,
                              ref typeMethods.r8vecNormalData data,
                              ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    MC uses Monte Carlo valuation on a European call.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    08 June 2016
    //
    //  Author:
    //
    //    Original MATLAB version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    Black-Scholes for Scientific Computing Students,
    //    Computing in Science and Engineering,
    //    November/December 2004, Volume 6, Number 6, pages 72-79.
    //
    //  Parameters:
    //
    //    Input, double S0, the asset price at time 0.
    //
    //    Input, double E, the exercise price.
    //
    //    Input, double R, the interest rate.
    //
    //    Input, double SIGMA, the volatility of the asset.
    //
    //    Input, double T1, the expiry date.
    //
    //    Input, int M, the number of simulations.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, double MC[2], the estimated range of the valuation.
    //
    {
        int i;

        double[] u = typeMethods.r8vec_normal_01_new(m, ref data, ref seed);

        double[] svals = new double[m];

        for (i = 0; i < m; i++)
        {
            svals[i] = s0 * Math.Exp((r - 0.5 * sigma * sigma) * t1
                                     + sigma * Math.Sqrt(t1) * u[i]);
        }

        double[] pvals = new double[m];

        for (i = 0; i < m; i++)
        {
            pvals[i] = Math.Exp(-r * t1) * Math.Max(svals[i] - e, 0.0);
        }

        double pmean = 0.0;

        for (i = 0; i < m; i++)
        {
            pmean += pvals[i];
        }

        pmean /= m;

        double std = 0.0;

        for (i = 0; i < m; i++)
        {
            std += Math.Pow(pvals[i] - pmean, 2);
        }

        std = Math.Sqrt(std / (m - 1));

        double width = 1.96 * std / Math.Sqrt(m);

        double[] conf = new double[2];

        conf[0] = pmean - width;
        conf[1] = pmean + width;

        return(conf);
    }
Exemple #7
0
    public static double[] uniform_on_sphere01_map(int dim_num, int n, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    UNIFORM_ON_SPHERE01_MAP maps uniform points onto the unit sphere.
    //
    //  Discussion:
    //
    //    The sphere has center 0 and radius 1.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    12 November 2010
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Russell Cheng,
    //    Random Variate Generation,
    //    in Handbook of Simulation,
    //    edited by Jerry Banks,
    //    Wiley, 1998, pages 168.
    //
    //    Reuven Rubinstein,
    //    Monte Carlo Optimization, Simulation, and Sensitivity
    //    of Queueing Networks,
    //    Krieger, 1992,
    //    ISBN: 0894647644,
    //    LC: QA298.R79.
    //
    //  Parameters:
    //
    //    Input, int DIM_NUM, the dimension of the space.
    //
    //    Input, int N, the number of points.
    //
    //    Input/output, int &SEED, a seed for the random number generator.
    //
    //    Output, double UNIFORM_ON_SPHERE01_MAP[DIM_NUM*N], the points.
    //
    {
        int j;

        double[] x = typeMethods.r8mat_normal_01_new(dim_num, n, ref data, ref seed);

        for (j = 0; j < n; j++)
        {
            //
            //  Compute the length of the vector.
            //
            double norm = 0.0;
            int    i;
            for (i = 0; i < dim_num; i++)
            {
                norm += x[i + j * dim_num] * x[i + j * dim_num];
            }

            norm = Math.Sqrt(norm);
            //
            //  Normalize the vector.
            //
            for (i = 0; i < dim_num; i++)
            {
                x[i + j * dim_num] /= norm;
            }
        }

        return(x);
    }
    public static void emweak(ref typeMethods.r8vecNormalData data, ref int seed, int method, int m, int p_max, ref double[] dtvals,
                              ref double[] xerr)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    EMWEAK tests the weak convergence of the Euler-Maruyama method.
    //
    //  Discussion:
    //
    //    The SDE is
    //
    //      dX = lambda * X dt + mu * X dW,
    //      X(0) = Xzero,
    //
    //    where
    //
    //      lambda = 2,
    //      mu = 1,
    //      Xzero = 1.
    //
    //    The discretized Brownian path over [0,1] has dt = 2^(-9).
    //
    //    The Euler-Maruyama method will use 5 different timesteps:
    //
    //      2^(p-10),  p = 1,2,3,4,5.
    //
    //    We examine weak convergence at T=1:
    //
    //      | E (X_L) - E (X(T)) |.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    25 September 2012
    //
    //  Author:
    //
    //    Original MATLAB version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546
    //
    //  Parameters:
    //
    //    Input, int &SEED, a seed for the random number generator.
    //
    //    Input, int METHOD.
    //    0, use the standard Euler-Maruyama method;
    //    1, use the weak Euler-Maruyama method.
    //
    //    Input, int M, the number of simulations to perform.
    //    A typical value is M = 1000.
    //
    //    Input, int P_MAX, the number of time step sizes to use.
    //    A typical value is 5.
    //
    //    Output, double DTVALS[P_MAX], the time steps used.
    //
    //    Output, double XERR[P_MAX], the averaged absolute error in the
    //    solution estimate at the final time.
    //
    {
        int i;
        int p;
        //
        //  Problem parameters;
        //
        const double lambda = 2.0;
        const double mu     = 0.1;
        const double xzero  = 1.0;

        //
        //  Stepping parameters.
        //
        for (p = 0; p < p_max; p++)
        {
            dtvals[p] = Math.Pow(2.0, p - 9);
        }

        //
        //  Take various Euler timesteps.
        //  For stepsize dt, we will need to take L Euler steps to reach time TMAX.
        //
        double[] xtemp = new double[m];
        double[] xem   = new double[p_max];

        for (p = 0; p < p_max; p++)
        {
            int    l  = (int)Math.Pow(2, 9 - p);
            double dt = dtvals[p];

            for (i = 0; i < m; i++)
            {
                xtemp[i] = xzero;
            }

            int j;
            for (j = 0; j < l; j++)
            {
                double[] winc = typeMethods.r8vec_normal_01_new(m, ref data, ref seed);
                switch (method)
                {
                case 0:
                {
                    for (i = 0; i < m; i++)
                    {
                        winc[i] = Math.Sqrt(dt) * winc[i];
                    }

                    break;
                }

                default:
                {
                    for (i = 0; i < m; i++)
                    {
                        winc[i] = Math.Sqrt(dt) * typeMethods.r8_sign(winc[i]);
                    }

                    break;
                }
                }

                for (i = 0; i < m; i++)
                {
                    xtemp[i] = xtemp[i] + dt * lambda * xtemp[i]
                               + mu * xtemp[i] * winc[i];
                }
            }

            //
            //  Average the M results for this stepsize.
            //
            xem[p] = typeMethods.r8vec_mean(m, xtemp);
        }

        //
        //  Compute the error in the estimates for each stepsize.
        //
        for (p = 0; p < p_max; p++)
        {
            xerr[p] = Math.Abs(xem[p] - Math.Exp(lambda));
        }

        //
        //  Least squares fit of error = c * dt^q.
        //
        double[] a   = new double[p_max * 2];
        double[] rhs = new double[p_max];

        for (i = 0; i < p_max; i++)
        {
            a[i + 0 * p_max] = 1.0;
            a[i + 1 * p_max] = Math.Log(dtvals[i]);
            rhs[i]           = Math.Log(xerr[i]);
        }

        double[] sol = QRSolve.qr_solve(p_max, 2, a, rhs);

        Console.WriteLine("");
        Console.WriteLine("EMWEAK:");
        switch (method)
        {
        case 0:
            Console.WriteLine("  Using standard Euler-Maruyama method.");
            break;

        default:
            Console.WriteLine("  Using weak Euler-Maruyama method.");
            break;
        }

        Console.WriteLine("  Least squares solution to Error = c * dt ^ q");
        Console.WriteLine("  (Expecting Q to be about 1.)");
        Console.WriteLine("  Computed Q = " + sol[1] + "");

        double resid = 0.0;

        for (i = 0; i < p_max; i++)
        {
            double e = a[i + 0 * p_max] * sol[0] + a[i + 1 * p_max] * sol[1] - rhs[i];
            resid += e * e;
        }

        resid = Math.Sqrt(resid);
        Console.WriteLine("  Residual is " + resid + "");
    }
Exemple #9
0
    public static double[] sample_paths2_cholesky(int n, int n2, double rhomin, double rhomax,
                                                  double rho0, Func <int, int, double[], double[], double, double[]> correlation2, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    SAMPLE_PATHS2_CHOLESKY: sample paths for stationary correlation functions.
    //
    //  Discussion:
    //
    //    This method uses the Cholesky factorization of the correlation matrix.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    12 November 2012
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int N, the number of points on each path.
    //
    //    Input, int N2, the number of paths.
    //
    //    Input, double RHOMIN, RHOMAX, the range of RHO.
    //
    //    Input, double RHO0, the correlation length.
    //
    //    Input, double *CORRELATION2 ( int m, int n, double s[], double t[],
    //    double rho0 ), the name of the function which evaluates the correlation.
    //
    //    Input/output, int &SEED, a seed for the random number
    //    generator.
    //
    //    Output, double X[N*N2], the sample paths.
    //
    {
        int flag = 0;

        //
        //  Choose N equally spaced sample points from RHOMIN to RHOMAX.
        //
        double[] s = typeMethods.r8vec_linspace_new(n, rhomin, rhomax);
        //
        //  Evaluate the correlation function.
        //
        double[] cor = correlation2(n, n, s, s, rho0);
        //
        //  Get the Cholesky factorization of COR:
        //
        //    COR = L * L'.
        //
        double[] l = typeMethods.r8mat_cholesky_factor(n, cor, ref flag);
        switch (flag)
        {
        //
        //  The matrix might not be nonnegative definite.
        //
        case 2:
            Console.WriteLine("");
            Console.WriteLine("SAMPLE_PATHS2_CHOLESKY - Fatal error!");
            Console.WriteLine("  The correlation matrix is not");
            Console.WriteLine("  symmetric nonnegative definite.");
            return(null);
        }

        //
        //  Compute a matrix of N by N2 normally distributed values.
        //
        double[] r = typeMethods.r8mat_normal_01_new(n, n2, ref data, ref seed);
        //
        //  Compute the sample path.
        //
        double[] x = typeMethods.r8mat_mm_new(n, n, n2, l, r);

        return(x);
    }
Exemple #10
0
    public static Correlation.CorrelationResult sample_paths_cholesky(FullertonLib.BesselData globaldata, FullertonLib.r8BESKData kdata, int n, int n2, double rhomax, double rho0,
                                                                      Func <FullertonLib.BesselData, FullertonLib.r8BESKData, int, double[], double, Correlation.CorrelationResult> correlation, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    SAMPLE_PATHS_CHOLESKY: sample paths for stationary correlation functions.
    //
    //  Discussion:
    //
    //    This method uses the Cholesky factorization of the correlation matrix.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    11 November 2012
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int N, the number of points on each path.
    //
    //    Input, int N2, the number of paths.
    //
    //    Input, double RHOMAX, the maximum value of RHO.
    //
    //    Input, double RHO0, the correlation length.
    //
    //    Input, double *CORRELATION ( int n, double rho_vec[], double rho0),
    //    the name of the function which evaluates the correlation.
    //
    //    Input/output, int &SEED, a seed for the random number
    //    generator.
    //
    //    Output, double X[N*N2], the sample paths.
    //
    {
        int flag = 0;
        int j;
        //
        //  Choose N equally spaced sample points from 0 to RHOMAX.
        //
        const double rhomin = 0.0;

        double[] rho_vec = typeMethods.r8vec_linspace_new(n, rhomin, rhomax);
        //
        //  Evaluate the correlation function.
        //
        Correlation.CorrelationResult tr = correlation(globaldata, kdata, n, rho_vec, rho0);
        double[] cor_vec = tr.result;
        globaldata = tr.data;
        //
        //  Construct the correlation matrix;
        //
        //  From the vector
        //    [ C(0), C(1), C(2), ... C(N-1) ]
        //  construct the vector
        //    [ C(N-1), ..., C(2), C(1), C(0), C(1), C(2), ...  C(N-1) ]
        //  Every row of the correlation matrix can be constructed by a subvector
        //  of this vector.
        //
        double[] cor = new double[n * n];

        for (j = 0; j < n; j++)
        {
            int i;
            for (i = 0; i < n; i++)
            {
                int k = typeMethods.i4_wrap(j - i, 0, n - 1);
                cor[i + j * n] = cor_vec[k];
            }
        }

        //
        //  Get the Cholesky factorization of COR:
        //
        //    COR = L * L'.
        //
        double[] l = typeMethods.r8mat_cholesky_factor(n, cor, ref flag);
        switch (flag)
        {
        //
        //  The matrix might not be nonnegative definite.
        //
        case 2:
            Console.WriteLine("");
            Console.WriteLine("SAMPLE_PATHS_CHOLESKY - Fatal error!");
            Console.WriteLine("  The correlation matrix is not");
            Console.WriteLine("  symmetric nonnegative definite.");
            return(null);
        }

        //
        //  Compute a matrix of N by N2 normally distributed values.
        //
        double[] r = typeMethods.r8mat_normal_01_new(n, n2, ref data, ref seed);
        //
        //  Compute the sample path.
        //
        double[] x = typeMethods.r8mat_mm_new(n, n, n2, l, r);

        Correlation.CorrelationResult res = new() { result = x, data = globaldata };

        return(res);
    }
    public static Correlation.CorrelationResult sample_paths_eigen(FullertonLib.BesselData globaldata, FullertonLib.r8BESJ0Data jdata, int n, int n2, double rhomax, double rho0,
                                                                   Func <FullertonLib.BesselData, FullertonLib.r8BESJ0Data, int, double[], double, Correlation.CorrelationResult> correlation, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    SAMPLE_PATHS_EIGEN: sample paths for stationary correlation functions.
    //
    //  Discussion:
    //
    //    This method uses the eigen-decomposition of the correlation matrix.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    12 November 2012
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int N, the number of points on each path.
    //
    //    Input, int N2, the number of paths.
    //
    //    Input, double RHOMAX, the maximum value of RHO.
    //
    //    Input, double RHO0, the correlation length.
    //
    //    Input, double *CORRELATION ( int n, double rho_vec[], double rho0),
    //    the name of the function which evaluates the correlation.
    //
    //    Input/output, int &SEED, a seed for the random number
    //    generator.
    //
    //    Output, double X[N*N2], the sample paths.
    //
    {
        int i;
        int j;
        int k;
        //
        //  Choose N equally spaced sample points from 0 to RHOMAX.
        //
        const double rhomin = 0.0;

        double[] rho_vec = typeMethods.r8vec_linspace_new(n, rhomin, rhomax);
        //
        //  Evaluate the correlation function.
        //
        Correlation.CorrelationResult tr = correlation(globaldata, jdata, n, rho_vec, rho0);
        double[] cor_vec = tr.result;
        globaldata = tr.data;
        jdata      = tr.j0data;
        //
        //  Construct the correlation matrix;
        //
        //  From the vector
        //    [ C(0), C(1), C(2), ... C(N-1) ]
        //  construct the vector
        //    [ C(N-1), ..., C(2), C(1), C(0), C(1), C(2), ...  C(N-1) ]
        //  Every row of the correlation matrix can be constructed by a subvector
        //  of this vector.
        //
        double[] cor = new double[n * n];

        for (j = 0; j < n; j++)
        {
            for (i = 0; i < n; i++)
            {
                k = typeMethods.i4_wrap(Math.Abs(i - j), 0, n - 1);
                cor[i + j * n] = cor_vec[k];
            }
        }

        //
        //  Get the eigendecomposition of COR:
        //
        //    COR = V * D * V'.
        //
        //  Because COR is symmetric, V is orthogonal.
        //
        double[] d = new double[n];
        double[] w = new double[n];
        double[] v = new double[n * n];

        TRED2.tred2(n, cor, ref d, ref w, ref v);

        TQL2.tql2(n, ref d, ref w, v);
        //
        //  We assume COR is non-negative definite, and hence that there
        //  are no negative eigenvalues.
        //
        double dmin = typeMethods.r8vec_min(n, d);

        if (dmin < -Math.Sqrt(typeMethods.r8_epsilon()))
        {
            Console.WriteLine("");
            Console.WriteLine("SAMPLE_PATHS_EIGEN - Warning!");
            Console.WriteLine("  Negative eigenvalues observed as low as " + dmin + "");
        }

        for (i = 0; i < n; i++)
        {
            d[i] = Math.Max(d[i], 0.0);
        }

        //
        //  Compute the eigenvalues of the factor C.
        //
        for (i = 0; i < n; i++)
        {
            d[i] = Math.Sqrt(d[i]);
        }

        //
        //  Compute C, such that C' * C = COR.
        //
        double[] c = new double[n * n];

        for (j = 0; j < n; j++)
        {
            for (i = 0; i < n; i++)
            {
                c[i + j * n] = 0.0;
                for (k = 0; k < n; k++)
                {
                    c[i + j * n] += d[k] * v[i + k * n] * v[j + k * n];
                }
            }
        }

        //
        //  Compute N by N2 independent random normal values.
        //
        double[] r = typeMethods.r8mat_normal_01_new(n, n2, ref data, ref seed);
        //
        //  Multiply to get the variables X which have correlation COR.
        //
        double[] x = typeMethods.r8mat_mm_new(n, n, n2, c, r);

        Correlation.CorrelationResult result = new() { result = x, data = globaldata };

        return(result);
    }
    public static double[] sample_paths2_eigen(int n, int n2, double rhomin, double rhomax,
                                               double rho0, Func <int, int, double[], double[], double, double[]> correlation2, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    SAMPLE_PATHS2_EIGEN: sample paths for stationary correlation functions.
    //
    //  Discussion:
    //
    //    This method uses the eigen-decomposition of the correlation matrix.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    12 November 2012
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int N, the number of points on each path.
    //
    //    Input, int N2, the number of paths.
    //
    //    Input, double RHOMIN, RHOMAX, the range of RHO.
    //
    //    Input, double RHO0, the correlation length.
    //
    //    Input, double *CORRELATION2 ( int m, int n, double s[], double t[],
    //    double rho0 ), the name of the function which evaluates the correlation.
    //
    //    Input/output, int &SEED, a seed for the random number
    //    generator.
    //
    //    Output, double X[N*N2], the sample paths.
    //
    {
        int i;
        int j;

        //
        //  Choose N equally spaced sample points from RHOMIN to RHOMAX.
        //
        double[] s = typeMethods.r8vec_linspace_new(n, rhomin, rhomax);
        //
        //  Evaluate the correlation function.
        //
        double[] cor = correlation2(n, n, s, s, rho0);
        //
        //  Get the eigendecomposition of COR:
        //
        //    COR = V * D * V'.
        //
        //  Because COR is symmetric, V is orthogonal.
        //
        double[] d = new double[n];
        double[] w = new double[n];
        double[] v = new double[n * n];

        TRED2.tred2(n, cor, ref d, ref w, ref v);

        TQL2.tql2(n, ref d, ref w, v);
        //
        //  We assume COR is non-negative definite, and hence that there
        //  are no negative eigenvalues.
        //
        double dmin = typeMethods.r8vec_min(n, d);

        if (dmin < -Math.Sqrt(typeMethods.r8_epsilon()))
        {
            Console.WriteLine("");
            Console.WriteLine("SAMPLE_PATHS2_EIGEN - Warning!");
            Console.WriteLine("  Negative eigenvalues observed as low as " + dmin + "");
        }

        for (i = 0; i < n; i++)
        {
            d[i] = Math.Max(d[i], 0.0);
        }

        //
        //  Compute the eigenvalues of the factor C.
        //
        for (i = 0; i < n; i++)
        {
            d[i] = Math.Sqrt(d[i]);
        }

        //
        //  Compute C, such that C' * C = COR.
        //
        double[] c = new double[n * n];

        for (j = 0; j < n; j++)
        {
            for (i = 0; i < n; i++)
            {
                c[i + j * n] = 0.0;
                int k;
                for (k = 0; k < n; k++)
                {
                    c[i + j * n] += d[k] * v[i + k * n] * v[j + k * n];
                }
            }
        }

        //
        //  Compute N by N2 independent random normal values.
        //
        double[] r = typeMethods.r8mat_normal_01_new(n, n2, ref data, ref seed);
        //
        //  Multiply to get the variables X which have correlation COR.
        //
        double[] x = typeMethods.r8mat_mm_new(n, n, n2, c, r);

        return(x);
    }
    public static void em(ref typeMethods.r8vecNormalData data, ref int seed, int n, ref double[] t, ref double[] xtrue, ref double[] t2,
                          ref double[] xem, ref double error)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    EM applies the Euler-Maruyama method to a linear SDE.
    //
    //  Discussion:
    //
    //    The SDE is
    //
    //      dX = lambda * X dt + mu * X dW,
    //      X(0) = Xzero,
    //
    //    where
    //
    //      lambda = 2,
    //      mu = 1,
    //      Xzero = 1.
    //
    //    The discretized Brownian path over [0,1] uses
    //    a stepsize dt = 2^(-8).
    //
    //    The Euler-Maruyama method uses a larger timestep Dt = R*dt,
    //    where R is an integer.  For an SDE of the form
    //
    //      dX = f(X(t)) dt + g(X(t)) dW(t)
    //
    //    it has the form
    //
    //      X(j) = X(j-1) + f(X(j-1)) * Dt + g(X(j-1)) * ( W(j*Dt) - W((j-1)*Dt) )
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original Matlab version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546
    //
    //  Parameters:
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Input, int N, the number of time steps.  A typical
    //    value is 2^8.  N should be a multiple of 4.
    //
    //    Output, double T[N+1], the time values for the exact solution.
    //
    //    Output, double XTRUE[N+1], the exact solution.
    //
    //    Output, double T2[N/4+1], the time values for the
    //    Euler-Maruyama solution.
    //
    //    Output, double XEM[N/4+1], the Euler-Maruyama solution.
    //
    //    Output, double &ERROR, the value of | XEM(T) - XTRUE(T) |.
    //
    {
        int j;
        //
        //  Set problem parameters.
        //
        const double lambda = 2.0;
        const double mu     = 1.0;
        const double xzero  = 1.0;
        //
        //  Set stepping parameters.
        //
        const double tmax = 1.0;
        double       dt   = tmax / n;

        //
        //  Define the increments dW.
        //
        double[] dw = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

        for (j = 0; j < n; j++)
        {
            dw[j] = Math.Sqrt(dt) * dw[j];
        }

        //
        //  Sum the Brownian increments.
        //
        double[] w = new double[n + 1];
        w[0] = 0.0;
        for (j = 1; j <= n; j++)
        {
            w[j] = w[j - 1] + dw[j - 1];
        }

        for (j = 0; j <= n; j++)
        {
            t[j] = j * tmax / n;
        }

        //
        //  Compute the discretized Brownian path.
        //
        for (j = 0; j <= n; j++)
        {
            xtrue[j] = xzero * Math.Exp((lambda - 0.5 * mu * mu) * (t[j] + mu * w[j]));
        }

        //
        //  Set:
        //  R, the multiplier for the EM step,
        //  Dt, the EM stepsize,
        //  L, the number of EM steps (we need N to be a multiple of R!)
        //
        const int r   = 4;
        double    dt2 = r * dt;
        int       l   = n / r;

        for (j = 0; j <= l; j++)
        {
            t2[j] = j * tmax / l;
        }

        //
        //  Compute XEM.
        //
        xem[0] = xzero;
        for (j = 1; j <= l; j++)
        {
            double dw2 = 0.0;
            int    i;
            for (i = r * (j - 1); i < r * j; i++)
            {
                dw2 += dw[i];
            }

            xem[j] = xem[j - 1] + dt2 * lambda * xem[j - 1] + mu * xem[j - 1] * dw2;
        }

        error = Math.Abs(xem[l] - xtrue[n]);
    }
    public static double[] ellipsoid_sample(int m, int n, double[] a, double[] v, double r,
                                            ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ELLIPSOID_SAMPLE samples points uniformly from an ellipsoid.
    //
    //  Discussion:
    //
    //    The points X in the ellipsoid are described by a M by M
    //    positive definite symmetric matrix A, a "center" V, and
    //    a "radius" R, such that
    //
    //      (X-V)' * A * (X-V) <= R * R
    //
    //    The algorithm computes the Cholesky factorization of A:
    //
    //      A = U' * U.
    //
    //    A set of uniformly random points Y is generated, satisfying:
    //
    //      Y' * Y <= R * R.
    //
    //    The appropriate points in the ellipsoid are found by solving
    //
    //      U * X = Y
    //      X = X + V
    //
    //    Thanks to Dr Karl-Heinz Keil for pointing out that the original
    //    coding was actually correct only if A was replaced by its inverse.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    14 August 2014
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Reuven Rubinstein,
    //    Monte Carlo Optimization, Simulation, and Sensitivity
    //    of Queueing Networks,
    //    Krieger, 1992,
    //    ISBN: 0894647644,
    //    LC: QA298.R79.
    //
    //  Parameters:
    //
    //    Input, int M, the dimension of the space.
    //
    //    Input, int N, the number of points.
    //
    //    Input, double A[M*M], the matrix that describes
    //    the ellipsoid.
    //
    //    Input, double V[M], the "center" of the ellipsoid.
    //
    //    Input, double R, the "radius" of the ellipsoid.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, double ELLIPSE_SAMPLE[M*N], the points.
    //
    {
        int i;
        int j;

        double[] u;
        //
        //  Get the Cholesky factor U.
        //
        try
        {
            u = typeMethods.r8po_fa(m, a);
        }
        catch (Exception)
        {
            Console.WriteLine("");
            Console.WriteLine("ELLIPSOID_SAMPLE - Fatal error!");
            Console.WriteLine("  R8PO_FA reports that the matrix A");
            Console.WriteLine("  is not positive definite symmetric.");
            return(null);
        }

        //
        //  Get the points Y that satisfy Y' * Y <= 1.
        //
        double[] x = Uniform.Sphere.uniform_in_sphere01_map(m, n, ref data, ref seed);
        //
        //  Get the points Y that satisfy Y' * Y <= R * R.
        //
        for (j = 0; j < n; j++)
        {
            for (i = 0; i < m; i++)
            {
                x[i + j * m] = r * x[i + j * m];
            }
        }

        //
        //  Solve U * X = Y.
        //
        for (j = 0; j < n; j++)
        {
            double[] t = typeMethods.r8po_sl(m, u, x, bIndex: +j * m);
            for (i = 0; i < m; i++)
            {
                x[i + j * m] = t[i];
            }
        }

        //
        //  X = X + V.
        //
        for (j = 0; j < n; j++)
        {
            for (i = 0; i < m; i++)
            {
                x[i + j * m] += v[i];
            }
        }

        return(x);
    }
Exemple #15
0
    public static double[] uniform_in_sphere01_map(int m, int n, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    UNIFORM_IN_SPHERE01_MAP maps uniform points into the unit sphere.
    //
    //  Discussion:
    //
    //    The sphere has center 0 and radius 1.
    //
    //    We first generate a point ON the sphere, and then distribute it
    //    IN the sphere.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    14 August 2014
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Russell Cheng,
    //    Random Variate Generation,
    //    in Handbook of Simulation,
    //    edited by Jerry Banks,
    //    Wiley, 1998, pages 168.
    //
    //    Reuven Rubinstein,
    //    Monte Carlo Optimization, Simulation, and Sensitivity
    //    of Queueing Networks,
    //    Krieger, 1992,
    //    ISBN: 0894647644,
    //    LC: QA298.R79.
    //
    //  Parameters:
    //
    //    Input, int M, the dimension of the space.
    //
    //    Input, int N, the number of points.
    //
    //    Input/output, int &SEED, a seed for the random number generator.
    //
    //    Output, double X[M*N], the points.
    //
    {
        int j;

        double exponent = 1.0 / m;

        double[] x = new double[m * n];

        for (j = 0; j < n; j++)
        {
            //
            //  Fill a vector with normally distributed values.
            //
            double[] v = typeMethods.r8vec_normal_01_new(m, ref data, ref seed);
            //
            //  Compute the length of the vector.
            //
            double norm = typeMethods.r8vec_norm(m, v);
            //
            //  Normalize the vector.
            //
            int i;
            for (i = 0; i < m; i++)
            {
                v[i] /= norm;
            }

            //
            //  Now compute a value to map the point ON the sphere INTO the sphere.
            //
            double r = UniformRNG.r8_uniform_01(ref seed);
            r = Math.Pow(r, exponent);

            for (i = 0; i < m; i++)
            {
                x[i + j * m] = r * v[i];
            }
        }

        return(x);
    }
    public static double[] uniform_in_ellipsoid_map(int dim_num, int n, double[] a, double r,
                                                    ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    UNIFORM_IN_ELLIPSOID_MAP maps uniform points into an ellipsoid.
    //
    //  Discussion:
    //
    //    The points X in the ellipsoid are described by a DIM_NUM by DIM_NUM positive
    //    definite symmetric matrix A, and a "radius" R, such that
    //
    //      X' * A * X <= R * R
    //
    //    The algorithm computes the Cholesky factorization of A:
    //
    //      A = U' * U.
    //
    //    A set of uniformly random points Y is generated, satisfying:
    //
    //      Y' * Y <= R * R.
    //
    //    The appropriate points in the ellipsoid are found by solving
    //
    //      U * X = Y
    //
    //    Thanks to Dr Karl-Heinz Keil for pointing out that the original
    //    coding was actually correct only if A was replaced by its inverse.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    23 May 2005
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Reuven Rubinstein,
    //    Monte Carlo Optimization, Simulation, and Sensitivity
    //    of Queueing Networks,
    //    Krieger, 1992,
    //    ISBN: 0894647644,
    //    LC: QA298.R79.
    //
    //  Parameters:
    //
    //    Input, int DIM_NUM, the dimension of the space.
    //
    //    Input, int N, the number of points.
    //
    //    Input, double A[DIM_NUM*DIM_NUM], the matrix that describes the ellipsoid.
    //
    //    Input, double R, the right hand side of the ellipsoid equation.
    //
    //    Input/output, int &SEED, a seed for the random number generator.
    //
    //    Output, double UNIFORM_IN_ELLIPSOID_MAP[DIM_NUM*N], the points.
    //
    {
        int i;
        int j;

        //
        //  Get the upper triangular Cholesky factor U of A.
        //
        double[] u = new double[dim_num * dim_num];

        for (j = 0; j < dim_num; j++)
        {
            for (i = 0; i < dim_num; i++)
            {
                u[i + j * dim_num] = a[i + j * dim_num];
            }
        }

        int info = typeMethods.r8po_fa(ref u, dim_num, dim_num);

        if (info != 0)
        {
            Console.WriteLine("");
            Console.WriteLine("UNIFORM_IN_ELLIPSOID_MAP - Fatal error!");
            Console.WriteLine("  R8PO_FA reports that the matrix A");
            Console.WriteLine("  is not positive definite symmetric.");
            return(null);
        }

        //
        //  Get the points Y that satisfy Y' * Y <= R * R.
        //
        double[] x = Sphere.uniform_in_sphere01_map(dim_num, n, ref data, ref seed);

        for (j = 0; j < n; j++)
        {
            for (i = 0; i < dim_num; i++)
            {
                x[i + j * dim_num] = r * x[i + j * dim_num];
            }
        }

        //
        //  Solve U * X = Y.
        //
        for (j = 0; j < n; j++)
        {
            typeMethods.r8po_sl(u, dim_num, dim_num, ref x, bIndex: +j * dim_num);
        }

        return(x);
    }
    public static void stochastic_integral_strat(int n, ref typeMethods.r8vecNormalData data, ref int seed, ref double estimate,
                                                 ref double exact, ref double error)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    STOCHASTIC_INTEGRAL_STRAT approximates the Stratonovich integral of W(t) dW.
    //
    //  Discussion:
    //
    //    This function estimates the Stratonovich integral of W(t) dW over
    //    the interval [0,1].
    //
    //    The estimates is made by taking N steps.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original Matlab version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input, int N, the number of steps to take.
    //
    //    Input, int &SEED, a seed for the random number generator.
    //
    //    Output, double &ESTIMATE, the estimate of the integral.
    //
    //    Output, double &EXACT, the exact value of the integral.
    //
    //    Output, double &ERROR, the error in the integral estimate.
    //
    {
        int j;
        //
        //  Set step parameters.
        //
        const double tmax = 1.0;
        double       dt   = tmax / n;

        //
        //  Define the increments dW.
        //
        double[] dw = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

        for (j = 0; j < n; j++)
        {
            dw[j] = Math.Sqrt(dt) * dw[j];
        }

        //
        //  Sum the increments to get the Brownian path.
        //
        double[] w = new double[n + 1];
        w[0] = 0.0;
        for (j = 1; j <= n; j++)
        {
            w[j] = w[j - 1] + dw[j - 1];
        }

        //
        //  Approximate the Stratonovich integral.
        //
        double[] u = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

        double[] v = new double[n];
        for (j = 0; j < n; j++)
        {
            v[j] = 0.5 * (w[j] + w[j + 1]) + 0.5 * Math.Sqrt(dt) * u[j];
        }

        estimate = typeMethods.r8vec_dot_product(n, v, dw);
        //
        //  Compare with the exact solution.
        //
        exact = 0.5 * w[n - 1] * w[n - 1];
        error = Math.Abs(estimate - exact);
    }
Exemple #18
0
    public static void bpath_average(ref typeMethods.r8vecNormalData data, ref int seed, int m, int n, ref double[] u, ref double[] umean,
                                     ref double error)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    BPATH_AVERAGE: displays the average of 1000 Brownian paths.
    //
    //  Discussion:
    //
    //    This routine computes M simulations of discretized Brownian
    //    motion W(t) over the time interval [0,1] using N time steps.
    //    The user specifies a random number seed.  Different values of
    //    the seed will result in a different set of realizations of the path.
    //
    //    Actually, we are interested in a function u(W(t)):
    //
    //      u(W(t)) = exp ( t + W(t)/2 )
    //
    //    The routine plots 5 of the simulations, as well as the average
    //    of all the simulations.
    //
    //    The plot of the average should be quite smooth.  Its expected
    //    value is exp ( 9 * t / 8 ), and we compute the 'error', that is,
    //    the difference between the averaged value and this expected
    //    value.  This 'error' should decrease as the number of simulation
    //    is increased.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original Matlab version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Input, int M, the number of simulations to compute
    //    and average.  A typical value is 1000.
    //
    //    Input, int N, the number of steps.  A typical value
    //    is 500.
    //
    //    Output, double U[M*(N+1)], the M paths.
    //
    //    Output, double UMEAN[N+1], the averaged path.
    //
    //    Output, double &ERROR, the maximum difference between the
    //    averaged path and the exact expected value.
    //
    {
        int i;
        int j;

        const double tmax = 1.0;
        double       dt   = tmax / n;

        double[] t = new double[n + 1];
        for (j = 0; j <= n; j++)
        {
            t[j] = j * tmax / n;
        }

        double[] w = new double[n + 1];

        for (i = 0; i < m; i++)
        {
            //
            //  Define the increments dW.
            //
            double[] dw = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

            for (j = 0; j < n; j++)
            {
                dw[j] = Math.Sqrt(dt) * dw[j];
            }

            //
            //  W is the sum of the previous increments.
            //
            w[0] = 0.0;
            for (j = 1; j <= n; j++)
            {
                w[j] = w[j - 1] + dw[j - 1];
            }

            for (j = 0; j <= n; j++)
            {
                u[i + j * m] = Math.Exp(t[j] + 0.5 * w[j]);
            }
        }

        //
        //  Average the M estimates of the path.
        //
        for (j = 0; j <= n; j++)
        {
            umean[j] = 0.0;
            for (i = 0; i < m; i++)
            {
                umean[j] += u[i + j * m];
            }

            umean[j] /= m;
        }

        error = 0.0;
        for (j = 0; j <= n; j++)
        {
            error = Math.Max(error, Math.Abs(umean[j] - Math.Exp(9.0 * t[j] / 8.0)));
        }
    }
Exemple #19
0
    public static void milstrong(ref typeMethods.r8vecNormalData data, ref int seed, int p_max, ref double[] dtvals, ref double[] xerr)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    MILSTRONG tests the strong convergence of the Milstein method.
    //
    //  Discussion:
    //
    //    This function solves the stochastic differential equation
    //
    //      dX = sigma * X * ( k - X ) dt + beta * X dW,
    //      X(0) = Xzero,
    //
    //    where
    //
    //       sigma = 2,
    //       k = 1,
    //       beta = 1,
    //       Xzero = 0.5.
    //
    //    The discretized Brownian path over [0,1] has dt = 2^(-11).
    //
    //    The Milstein method uses timesteps 128*dt, 64*dt, 32*dt, 16*dt
    //    (also dt for reference).
    //
    //    We examine strong convergence at T=1:
    //
    //      E | X_L - X(T) |.
    //
    //    The code is vectorized: all paths computed simultaneously.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original MATLAB version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Input, int P_MAX, the number of time step sizes to use.
    //    A typical value is 4.
    //
    //    Output, double DTVALS[P_MAX], the time steps used.
    //
    //    Output, double XERR[P_MAX], the averaged absolute error in the
    //    solution estimate at the final time.
    //
    {
        int i;
        int j;
        int p;
        //
        //  Set problem parameters.
        //
        const double sigma = 2.0;
        const double k     = 1.0;
        const double beta  = 0.25;
        const double xzero = 0.5;
        //
        //  Set stepping parameters.
        //
        const double tmax = 1.0;
        int          n    = (int)Math.Pow(2, 11);
        double       dt   = tmax / n;
        //
        //  Number of paths sampled.
        //
        const int m = 500;

        //
        //  Define the increments dW.
        //
        double[] dw = typeMethods.r8mat_normal_01_new(m, n, ref data, ref seed);
        for (j = 0; j < n; j++)
        {
            for (i = 0; i < m; i++)
            {
                dw[i + j * m] = Math.Sqrt(dt) * dw[i + j * m];
            }
        }

        //
        //  Estimate the reference solution at time T M times.
        //
        double[] xref = new double[m];

        for (i = 0; i < m; i++)
        {
            xref[i] = xzero;
        }

        for (j = 0; j < n; j++)
        {
            for (i = 0; i < m; i++)
            {
                xref[i] = xref[i]
                          + dt * sigma * xref[i] * (k - xref[i])
                          + beta * xref[i] * dw[i + j * m]
                          + 0.5 * beta * beta * xref[i] * (dw[i + j * m] * dw[i + j * m] - dt);
            }
        }

        //
        //  Now compute M Milstein approximations at each of 4 timesteps,
        //  and record the average errors.
        //
        for (p = 0; p < p_max; p++)
        {
            dtvals[p] = dt * 8.0 * Math.Pow(2.0, p + 1);
        }

        for (p = 0; p < p_max; p++)
        {
            xerr[p] = 0.0;
        }

        double[] xtemp = new double[m];
        for (p = 0; p < p_max; p++)
        {
            int    r   = 8 * (int)Math.Pow(2, p + 1);
            double dtp = dtvals[p];
            int    l   = n / r;
            for (i = 0; i < m; i++)
            {
                xtemp[i] = xzero;
            }

            for (j = 0; j < l; j++)
            {
                for (i = 0; i < m; i++)
                {
                    double winc = 0.0;
                    int    i2;
                    for (i2 = r * j; i2 < r * (j + 1); i2++)
                    {
                        winc += dw[i + i2 * m];
                    }

                    xtemp[i] = xtemp[i]
                               + dtp * sigma * xtemp[i] * (k - xtemp[i])
                               + beta * xtemp[i] * winc
                               + 0.5 * beta * beta * xtemp[i] * (winc * winc - dtp);
                }
            }

            xerr[p] = 0.0;
            for (i = 0; i < m; i++)
            {
                xerr[p] += Math.Abs(xtemp[i] - xref[i]);
            }

            xerr[p] /= m;
        }

        //
        //  Least squares fit of error = C * dt^q
        //
        double[] a   = new double[p_max * 2];
        double[] rhs = new double[p_max];
        for (p = 0; p < p_max; p++)
        {
            a[p + 0 * p_max] = 1.0;
            a[p + 1 * p_max] = Math.Log(dtvals[p]);
            rhs[p]           = Math.Log(xerr[p]);
        }

        double[] sol = QRSolve.qr_solve(p_max, 2, a, rhs);

        Console.WriteLine("");
        Console.WriteLine("MILSTEIN:");
        Console.WriteLine("  Least squares solution to Error = c * dt ^ q");
        Console.WriteLine("  Expecting Q to be about 1.");
        Console.WriteLine("  Computed Q = " + sol[1] + "");

        double resid = 0.0;

        for (i = 0; i < p_max; i++)
        {
            double e = a[i + 0 * p_max] * sol[0] + a[i + 1 * p_max] * sol[1] - rhs[i];
            resid += e * e;
        }

        resid = Math.Sqrt(resid);
        Console.WriteLine("  Residual is " + resid + "");
    }
    public static void emstrong(ref typeMethods.r8vecNormalData data, ref int seed, int m, int n, int p_max, ref double[] dtvals,
                                ref double[] xerr)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    EMSTRONG tests the strong convergence of the EM method.
    //
    //  Discussion:
    //
    //    The SDE is
    //
    //      dX = lambda * X dt + mu * X dW,
    //      X(0) = Xzero,
    //
    //    where
    //
    //      lambda = 2,
    //      mu = 1,
    //      Xzero = 1.
    //
    //    The discretized Brownian path over [0,1] has dt = 2^(-9).
    //
    //    The Euler-Maruyama method uses 5 different timesteps:
    //      16*dt, 8*dt, 4*dt, 2*dt, dt.
    //
    //    We are interested in examining strong convergence at T=1,
    //    that is
    //
    //      E | X_L - X(T) |.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original Matlab version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Input, int M, the number of simulations to perform.
    //    A typical value is M = 1000.
    //
    //    Input, int N, the number of time steps to take.
    //    A typical value is N = 512.
    //
    //    Input, int P_MAX, the number of time step sizes to use.
    //    A typical value is 5.
    //
    //    Output, double DTVALS[P_MAX], the time steps used.
    //
    //    Output, double XERR[P_MAX], the averaged absolute error in the
    //    solution estimate at the final time.
    //
    {
        int i;
        int p;
        int s;
        //
        //  Set problem parameters.
        //
        const double lambda = 2.0;
        const double mu     = 1.0;
        const double xzero  = 1.0;
        //
        //  Set stepping parameters.
        //
        const double tmax = 1.0;
        double       dt   = tmax / n;

        for (p = 0; p < p_max; p++)
        {
            dtvals[p] = dt * Math.Pow(2.0, p);
        }

        //
        //  Sample over discrete Brownian paths.
        //
        for (p = 0; p < p_max; p++)
        {
            xerr[p] = 0.0;
        }

        for (s = 0; s < m; s++)
        {
            //
            //  Define the increments dW.
            //
            double[] dw = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

            int j;
            for (j = 0; j < n; j++)
            {
                dw[j] = Math.Sqrt(dt) * dw[j];
            }

            //
            //  Sum the increments to get the Brownian path.
            //
            double[] w = new double[n + 1];
            w[0] = 0.0;
            for (j = 1; j <= n; j++)
            {
                w[j] = w[j - 1] + dw[j - 1];
            }

            //
            //  Determine the true solution.
            //
            double xtrue = xzero * Math.Exp(lambda - 0.5 * mu * mu + mu * w[n]);
            //
            //  Use the Euler-Maruyama method with 5 different time steps dt2 = r * dt
            //  to estimate the solution value at time TMAX.
            //
            for (p = 0; p < p_max; p++)
            {
                double dt2   = dtvals[p];
                int    r     = (int)Math.Pow(2, p);
                int    l     = n / r;
                double xtemp = xzero;
                for (j = 0; j < l; j++)
                {
                    double winc = 0.0;
                    int    k;
                    for (k = r * j; k < r * (j + 1); k++)
                    {
                        winc += dw[k];
                    }

                    xtemp = xtemp + dt2 * lambda * xtemp + mu * xtemp * winc;
                }

                xerr[p] += Math.Abs(xtemp - xtrue);
            }
        }

        for (p = 0; p < p_max; p++)
        {
            xerr[p] /= m;
        }

        //
        //  Least squares fit of error = c * dt^q.
        //
        double[] a   = new double[p_max * 2];
        double[] rhs = new double[p_max];

        for (i = 0; i < p_max; i++)
        {
            a[i + 0 * p_max] = 1.0;
            a[i + 1 * p_max] = Math.Log(dtvals[i]);
            rhs[i]           = Math.Log(xerr[i]);
        }

        double[] sol = QRSolve.qr_solve(p_max, 2, a, rhs);

        Console.WriteLine("");
        Console.WriteLine("EMSTRONG:");
        Console.WriteLine("  Least squares solution to Error = c * dt ^ q");
        Console.WriteLine("  (Expecting Q to be about 1/2.)");
        Console.WriteLine("  Computed Q = " + sol[1] + "");

        double resid = 0.0;

        for (i = 0; i < p_max; i++)
        {
            double e = a[i + 0 * p_max] * sol[0] + a[i + 1 * p_max] * sol[1] - rhs[i];
            resid += e * e;
        }

        resid = Math.Sqrt(resid);
        Console.WriteLine("  Residual is " + resid + "");
    }
Exemple #21
0
    public static double[] ellipse_sample(int n, double[] a, double r, ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ELLIPSE_SAMPLE samples points in an ellipse.
    //
    //  Discussion:
    //
    //    The points X in the ellipsoid are described by a 2 by 2 positive
    //    definite symmetric matrix A, and a "radius" R, such that
    //      X' * A * X <= R * R
    //    The algorithm computes the Cholesky factorization of A:
    //      A = U' * U.
    //    A set of uniformly random points Y is generated, satisfying:
    //      Y' * Y <= R * R.
    //    The appropriate points in the ellipsoid are found by solving
    //      U * X = Y
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    23 May 2005
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Reuven Rubinstein,
    //    Monte Carlo Optimization, Simulation, and Sensitivity
    //    of Queueing Networks,
    //    Krieger, 1992,
    //    ISBN: 0894647644,
    //    LC: QA298.R79.
    //
    //  Parameters:
    //
    //    Input, int N, the number of points.
    //
    //    Input, double A[2*2], the matrix that describes the ellipse.
    //
    //    Input, double R, the right hand side of the ellipse equation.
    //
    //    Input/output, int *SEED, a seed for the random number generator.
    //
    //    Output, double ELLIPSE_SAMPLE[2*N], the points.
    //
    {
        int       i;
        int       j;
        const int m = 2;

        //
        //  Get the upper triangular Cholesky factor U of A.
        //
        double[] u = new double[m * m];

        for (j = 0; j < m; j++)
        {
            for (i = 0; i < m; i++)
            {
                u[i + j * m] = a[i + j * m];
            }
        }

        int info = typeMethods.r8po_fa(ref u, m, m);

        if (info != 0)
        {
            Console.WriteLine("");
            Console.WriteLine("ELLIPSE_SAMPLE - Fatal error!");
            Console.WriteLine("  R8PO_FA reports that the matrix A");
            Console.WriteLine("  is not positive definite symmetric.");
            return(null);
        }

        //
        //  Get the points Y that satisfy Y' * Y <= R * R.
        //
        double[] x = Uniform.Sphere.uniform_in_sphere01_map(m, n, ref data, ref seed);

        for (j = 0; j < n; j++)
        {
            for (i = 0; i < m; i++)
            {
                x[i + j * m] = r * x[i + j * m];
            }
        }

        //
        //  Solve U * X = Y.
        //
        for (j = 0; j < n; j++)
        {
            typeMethods.r8po_sl(u, m, m, ref x, bIndex: +j * m);
        }

        return(x);
    }
    public static double[] asset_path(double s0, double mu, double sigma, double t1, int n,
                                      ref typeMethods.r8vecNormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ASSET_PATH simulates the behavior of an asset price over time.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    08 June 2016
    //
    //  Author:
    //
    //    Original MATLAB version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    Black-Scholes for Scientific Computing Students,
    //    Computing in Science and Engineering,
    //    November/December 2004, Volume 6, Number 6, pages 72-79.
    //
    //  Parameters:
    //
    //    Input, double S0, the asset price at time 0.
    //
    //    Input, double MU, the expected growth rate.
    //
    //    Input, double SIGMA, the volatility of the asset.
    //
    //    Input, double T1, the expiry date.
    //
    //    Input, integer N, the number of steps to take between 0 and T1.
    //
    //    Input/output, int &SEED, a seed for the random number generator.
    //
    //    Output, double ASSET_PATH[N+1], the option values from time 0 to T1
    //    in equal steps.
    //
    {
        int i;

        double dt = t1 / n;

        double[] r = typeMethods.r8vec_normal_01_new(n, ref data, ref seed);

        double[] s = new double[n + 1];

        s[0] = s0;
        double p = s0;

        for (i = 1; i <= n; i++)
        {
            p   *= Math.Exp((mu - sigma * sigma) * dt + sigma * Math.Sqrt(dt) * r[i - 1]);
            s[i] = p;
        }

        return(s);
    }
    public static void stab_asymptotic(ref typeMethods.r8vecNormalData vdata, ref typeMethods.r8NormalData data, ref int seed, int n, int p_max)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    STAB_ASYMPTOTIC examines asymptotic stability.
    //
    //  Discussion:
    //
    //    The function tests the asymptotic stability
    //    of the Euler-Maruyama method applied to a stochastic differential
    //    equation (SDE).
    //
    //    The SDE is
    //
    //      dX = lambda*X dt + mu*X dW,
    //      X(0) = Xzero,
    //
    //    where
    //
    //      lambda is a constant,
    //      mu is a constant,
    //      Xzero = 1.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    28 September 2012
    //
    //  Author:
    //
    //    Original Matlab version by Desmond Higham.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Desmond Higham,
    //    An Algorithmic Introduction to Numerical Simulation of
    //    Stochastic Differential Equations,
    //    SIAM Review,
    //    Volume 43, Number 3, September 2001, pages 525-546.
    //
    //  Parameters:
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Input, int N, the number of time steps for the
    //    first solution.
    //
    //    Input, int P_MAX, the number of time step sizes.
    //
    {
        const string  command_filename = "stab_asymptotic_commands.txt";
        List <string> command          = new();
        const string  data_filename0   = "stab_asymptotic0_data.txt";
        List <string> out_data         = new();
        int           p;

        Console.WriteLine("");
        Console.WriteLine("STAB_ASYMPTOTIC:");
        Console.WriteLine("  Investigate asymptotic stability of Euler-Maruyama");
        Console.WriteLine("  solution with stepsize DT and MU.");
        Console.WriteLine("");
        Console.WriteLine("  SDE is asymptotically stable if");
        Console.WriteLine("    Real ( lambda - 1/2 mu^2 ) < 0.");
        Console.WriteLine("");
        Console.WriteLine("  EM with DT is asymptotically stable if");
        Console.WriteLine("    E log ( | 1 + lambda dt - sqrt(dt) mu n(0,1) | ) < 0.");
        Console.WriteLine("  where n(0,1) is a normal random value.");
        //
        //  Problem parameters.
        //
        const double lambda = 0.5;
        double       mu     = Math.Sqrt(6.0);
        const double xzero  = 1.0;

        //
        //  Test the SDE.
        //
        Console.WriteLine("");
        Console.WriteLine("  Lambda = " + lambda + "");
        Console.WriteLine("  Mu =     " + mu + "");
        double test = lambda - 0.5 * mu * mu;

        Console.WriteLine("  SDE asymptotic stability test = " + test + "");
        //
        //  Step parameters.
        //
        const double tmax = 500.0;
        //
        //  For each stepsize, compute the Euler-Maruyama solution.
        //
        string data_filename = data_filename0;

        double[] dtvals = new double[p_max];

        for (p = 0; p < p_max; p++)
        {
            int    nval = n * (int)Math.Pow(2, p);
            double dt   = tmax / nval;
            dtvals[p] = dt;
            //
            //  Test the EM for this DT.
            //
            Console.WriteLine("");
            Console.WriteLine("  dt = " + dt + "");
            double[] u = typeMethods.r8vec_normal_01_new(1000, ref vdata, ref seed);
            int      i;
            for (i = 0; i < 1000; i++)
            {
                u[i] = Math.Log(Math.Abs(1.0 + lambda * dt - Math.Sqrt(dt) * mu * u[i]));
            }

            test = typeMethods.r8vec_mean(1000, u);
            Console.WriteLine("  EM asymptotic test = " + test + "");

            double   xtemp  = xzero;
            double[] xemabs = new double[nval + 1];
            xemabs[0] = xtemp;

            int j;
            for (j = 1; j <= nval; j++)
            {
                double winc = Math.Sqrt(dt) * typeMethods.r8_normal_01(ref data, ref seed);
                xtemp     = xtemp + dt * lambda * xtemp + mu * xtemp * winc;
                xemabs[j] = Math.Abs(xtemp);
            }

            //
            //  Write this data to a file.
            //
            Files.filename_inc(ref data_filename);

            //
            //  We have to impose a tiny lower bound on the values because we
            //  will end up plotting their logs.
            //
            double xmin = Math.Exp(-200.0);
            for (i = 0; i <= nval; i++)
            {
                double t = tmax * i / nval;
                out_data.Add("  " + t
                             + "  " + Math.Max(xemabs[i], xmin) + "");
            }

            File.WriteAllLines(data_filename, out_data);

            Console.WriteLine("");
            Console.WriteLine("  Data for DT = " + dt + " stored in \"" + data_filename + "\"");
        }

        command.Add("# stab_asymptotic_commands.txt");
        command.Add("# created by sde::stab_asymptotic.");
        command.Add("#");
        command.Add("# Usage:");
        command.Add("#  gnuplot < stab_asymptotic_commands.txt");
        command.Add("#");
        command.Add("set term png");
        command.Add("set output 'stab_asymptotic.png'");
        command.Add("set xlabel 't'");
        command.Add("set ylabel '|X(t)|'");
        command.Add("set title 'Absolute value of EM Solution'");
        command.Add("set grid");
        command.Add("set logscale y 10");
        command.Add("set style data lines");

        data_filename = data_filename0;

        Files.filename_inc(ref data_filename);
        command.Add("plot '" + data_filename + "' using 1:2, \\");

        for (p = 1; p < p_max - 1; p++)
        {
            Files.filename_inc(ref data_filename);
            command.Add("     '" + data_filename + "' using 1:2, \\");
        }

        Files.filename_inc(ref data_filename);
        command.Add("     '" + data_filename + "' using 1:2");

        command.Add("quit");

        File.WriteAllLines(command_filename, command);

        Console.WriteLine("  STAB_ASYMPTOTIC plot stored in \"" + command_filename + "\".");
    }