Esempio n. 1
0
    public static double[] brownian(int dim_num, int n, ref typeMethods.r8NormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    BROWNIAN creates Brownian motion points.
    //
    //  Discussion:
    //
    //    A starting point is generated at the origin.  The next point
    //    is generated at a uniformly random angle and a (0,1) normally
    //    distributed distance from the previous point.
    //
    //    It is up to the user to rescale the data, if desired.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    19 August 2004
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int DIM_NUM, the dimension of the space.
    //
    //    Input, int N, the number of points.
    //
    //    Input, int &SEED, a seed for the random number generator.
    //
    //    Output, double BROWNIAN[DIM_NUM*N], the Brownian motion points.
    //
    {
        int i;

        double[] direction = new double[dim_num];
        double[] x         = new double[dim_num * n];
        //
        //  Initial point.
        //
        int j = 0;

        for (i = 0; i < dim_num; i++)
        {
            x[i + j * dim_num] = 0.0;
        }
        //
        //  Generate angles and steps.
        //
        for (j = 1; j < n; j++)
        {
            double r = typeMethods.r8_normal_01(ref data, ref seed);
            r = Math.Abs(r);

            direction_uniform_nd(dim_num, ref seed, ref direction);

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

        return(x);
    }
Esempio n. 2
0
    public static double[] dirichlet_sample(int n, double[] a, ref typeMethods.r8NormalData data, ref int seed)
    //****************************************************************************80
    //
    //  Purpose:
    //
    //    DIRICHLET_SAMPLE samples the Dirichlet PDF.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    05 June 2013
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Jerry Banks, editor,
    //    Handbook of Simulation,
    //    Engineering and Management Press Books, 1998, page 169.
    //
    //  Parameters:
    //
    //    Input, int N, the number of components.
    //
    //    Input, double A[N], the probabilities for each component.
    //    Each A(I) should be nonnegative, and at least one should be
    //    positive.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, double DIRICHLET_SAMPLE[N], a sample of the PDF.  The entries
    //    of X should sum to 1.
    //
    {
        dirichlet_check(n, a);

        double[] x = new double[n];

        for (int i = 0; i < n; i++)
        {
            x[i] = gamma_sample(a[i], 1.0, ref data, ref seed);
        }

        //
        //  Normalize the result.
        //
        double x_sum = typeMethods.r8vec_sum(n, x);

        for (int i = 0; i < n; i++)
        {
            x[i] /= x_sum;
        }

        return(x);
    }
Esempio n. 3
0
    public static double[] f_alpha(int n, double q_d, double alpha, ref typeMethods.r8NormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    F_ALPHA generates a 1/F^ALPHA noise sequence.
    //
    //  Discussion:
    //
    //    Thanks to Miro Stoyanov for pointing out that the second half of
    //    the data returned by the inverse Fourier transform should be
    //    discarded, 24 August 2010.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    24 August 2010
    //
    //  Author:
    //
    //    Original C version by Todd Walter.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Jeremy Kasdin,
    //    Discrete Simulation of Colored Noise and Stochastic Processes
    //    and 1/f^a Power Law Noise Generation,
    //    Proceedings of the IEEE,
    //    Volume 83, Number 5, 1995, pages 802-827.
    //
    //  Parameters:
    //
    //    Input, int N, the number of samples of the noise to generate.
    //
    //    Input, double Q_D, the variance of the noise.
    //
    //    Input, double ALPHA, the exponent for the noise.
    //
    //    Input/output, int *SEED, a seed for the random number generator.
    //
    //    Output, double F_ALPHA[N], a sequence sampled with the given
    //    power law.
    //
    {
        double h_azero = 0;
        int    i;
        double w_azero = 0;

        //
        //  Set the deviation of the noise.
        //
        q_d = Math.Sqrt(q_d);
        //
        //  Generate the coefficients Hk.
        //
        double[] hfa = new double[2 * n];
        hfa[0] = 1.0;
        for (i = 1; i < n; i++)
        {
            hfa[i] = hfa[i - 1]
                     * (0.5 * alpha + (i - 1)) / i;
        }

        for (i = n; i < 2 * n; i++)
        {
            hfa[i] = 0.0;
        }

        //
        //  Fill Wk with white noise.
        //
        double[] wfa = new double[2 * n];

        for (i = 0; i < n; i++)
        {
            wfa[i] = q_d * typeMethods.r8_normal_01(ref data, ref seed);
        }

        for (i = n; i < 2 * n; i++)
        {
            wfa[i] = 0.0;
        }

        //
        //  Perform the discrete Fourier transforms of Hk and Wk.
        //
        double[] h_a = new double[n];
        double[] h_b = new double[n];

        Slow.r8vec_sftf(2 * n, hfa, ref h_azero, ref h_a, ref h_b);

        double[] w_a = new double[n];
        double[] w_b = new double[n];

        Slow.r8vec_sftf(2 * n, wfa, ref w_azero, ref w_a, ref w_b);
        //
        //  Multiply the two complex vectors.
        //
        w_azero *= h_azero;

        for (i = 0; i < n; i++)
        {
            double wr = w_a[i];
            double wi = w_b[i];
            w_a[i] = wr * h_a[i] - wi * h_b[i];
            w_b[i] = wi * h_a[i] + wr * h_b[i];
        }

        //
        //  This scaling is introduced only to match the behavior
        //  of the Numerical Recipes code...
        //
        w_azero = w_azero * 2 * n;
        for (i = 0; i < n - 1; i++)
        {
            w_a[i] *= n;
            w_b[i] *= n;
        }

        i      = n - 1;
        w_a[i] = w_a[i] * 2 * n;
        w_b[i] = w_b[i] * 2 * n;
        //
        //  Take the inverse Fourier transform of the result.
        //
        double[] x2 = Slow.r8vec_sftb(2 * n, w_azero, w_a, w_b);
        //
        //  Only return the first N inverse Fourier transform values.
        //
        double[] x = new double[n];
        for (i = 0; i < n; i++)
        {
            x[i] = x2[i];
        }

        return(x);
    }
Esempio n. 4
0
    public static double[] dirichlet_mix_sample(int comp_max, int comp_num, int elem_num,
                                                double[] a, double[] comp_weight, ref typeMethods.r8NormalData data, ref int seed, ref int comp)
    //****************************************************************************80
    //
    //  Purpose:
    //
    //    DIRICHLET_MIX_SAMPLE samples a Dirichlet mixture PDF.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    05 June 2013
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int COMP_MAX, the leading dimension of A, which
    //    must be at least COMP_NUM.
    //
    //    Input, int COMP_NUM, the number of components in the
    //    Dirichlet mixture density, that is, the number of distinct Dirichlet PDF's
    //    that are mixed together.
    //
    //    Input, int ELEM_NUM, the number of elements of an
    //    observation.
    //
    //    Input, double A[COMP_MAX*ELEM_NUM], the probabilities for
    //    element ELEM_NUM in component COMP_NUM.
    //    Each A(I,J) should be greater than or equal to 0.0.
    //
    //    Input, double COMP_WEIGHT[COMP_NUM], the mixture weights of
    //    the densities.
    //    These do not need to be normalized.  The weight of a given component is
    //    the relative probability that that component will be used to generate
    //    the sample.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, int &COMP, the index of the component of the
    //    Dirichlet mixture that was chosen to generate the sample.
    //
    //    Output, double DIRICHLET_MIX_SAMPLE[ELEM_NUM], a sample of the PDF.
    //
    {
        //
        //  Check.
        //
        for (int comp_i = 0; comp_i < comp_num; comp_i++)
        {
            for (int elem_i = 0; elem_i < elem_num; elem_i++)
            {
                switch (a[comp_i + elem_i * comp_max])
                {
                case < 0.0:
                    Console.WriteLine("");
                    Console.WriteLine("DIRICHLET_MIX_SAMPLE - Fatal error!");
                    Console.WriteLine("  A(COMP,ELEM) < 0.'");
                    Console.WriteLine("  COMP = " + comp_i + "");
                    Console.WriteLine("  ELEM = " + elem_i + "");
                    Console.WriteLine("  A(COMP,ELEM) = " + a[comp_i + elem_i * comp_max] + "");
                    break;
                }
            }
        }

        //
        //  Choose a particular density MIX.
        //
        double comp_weight_sum = typeMethods.r8vec_sum(comp_num, comp_weight);

        double r = UniformRNG.r8_uniform_ab(0.0, comp_weight_sum, ref seed);

        comp = 0;
        double sum2 = 0.0;

        while (comp < comp_num)
        {
            sum2 += comp_weight[comp];

            if (r <= sum2)
            {
                break;
            }

            comp += 1;
        }

        //
        //  Sample density COMP.
        //
        double[] x = new double[elem_num];

        for (int elem_i = 0; elem_i < elem_num; elem_i++)
        {
            x[elem_i] = gamma_sample(a[comp + elem_i * comp_max], 1.0, ref data, ref seed);
        }

        //
        //  Normalize the result.
        //
        double x_sum = typeMethods.r8vec_sum(elem_num, x);

        for (int elem_i = 0; elem_i < elem_num; elem_i++)
        {
            x[elem_i] /= x_sum;
        }

        return(x);
    }
Esempio n. 5
0
    public static double gamma_sample(double a, double b, ref typeMethods.r8NormalData data, ref int seed)
    //****************************************************************************80
    //
    //  Purpose:
    //
    //    GAMMA_SAMPLE samples the Gamma PDF.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    05 June 2013
    //
    //  Author:
    //
    //    Original FORTRAN77 version by Joachim Ahrens, Ulrich Dieter.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    Joachim Ahrens, Ulrich Dieter,
    //    Computer Methods for Sampling from Gamma, Beta, Poisson and
    //    Binomial Distributions,
    //    Computing,
    //    Volume 12, Number 3, September 1974, pages 223-246.
    //
    //    Joachim Ahrens, Ulrich Dieter,
    //    Generating Gamma Variates by a Modified Rejection Technique,
    //    Communications of the ACM,
    //    Volume 25, Number 1, January 1982, pages 47-54.
    //
    //  Parameters:
    //
    //    Input, double A, B, the parameters of the PDF.
    //    0.0 < A,
    //    0.0 < B.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, double GAMMA_SAMPLE, a sample of the PDF.
    //
    {
        const double a1 = 0.3333333;
        const double a2 = -0.2500030;
        const double a3 = 0.2000062;
        const double a4 = -0.1662921;
        const double a5 = 0.1423657;
        const double a6 = -0.1367177;
        const double a7 = 0.1233795;
        const double e1 = 1.0;
        const double e2 = 0.4999897;
        const double e3 = 0.1668290;
        const double e4 = 0.0407753;
        const double e5 = 0.0102930;
        const double q1 = 0.04166669;
        const double q2 = 0.02083148;
        const double q3 = 0.00801191;
        const double q4 = 0.00144121;
        const double q5 = -0.00007388;
        const double q6 = 0.00024511;
        const double q7 = 0.00024240;

        double e;
        double x;

        switch (a)
        {
        //
        //  Allow A = 0.
        //
        case 0.0:
            x = 0.0;
            return(x);

        //
        //  A < 1.
        //
        case < 1.0:
        {
            for (;;)
            {
                double p = UniformRNG.r8_uniform_01(ref seed);
                p = (1.0 + 0.3678794 * a) * p;

                e = exponential_01_sample(ref seed);

                switch (p)
                {
                case >= 1.0:
                {
                    x = -Math.Log((1.0 + 0.3678794 * a - p) / a);

                    if ((1.0 - a) * Math.Log(x) <= e)
                    {
                        x /= b;
                        return(x);
                    }

                    break;
                }

                default:
                {
                    x = Math.Exp(Math.Log(p) / a);

                    if (x <= e)
                    {
                        x /= b;
                        return(x);
                    }

                    break;
                }
                }
            }
        }

        //
        default:
        {
            double s2 = a - 0.5;
            double s  = Math.Sqrt(a - 0.5);
            double d  = Math.Sqrt(32.0) - 12.0 * Math.Sqrt(a - 0.5);

            double t = typeMethods.r8_normal_01(ref data, ref seed);
            x = Math.Pow(Math.Sqrt(a - 0.5) + 0.5 * t, 2);

            switch (t)
            {
            case >= 0.0:
                x /= b;
                return(x);
            }

            double u = UniformRNG.r8_uniform_01(ref seed);

            if (d * u <= t * t * t)
            {
                x /= b;
                return(x);
            }

            double r  = 1.0 / a;
            double q0 = ((((((
                                 q7 * r
                                 + q6) * r
                             + q5) * r
                            + q4) * r
                           + q3) * r
                          + q2) * r
                         + q1) * r;

            double bcoef;
            double c;
            double si;
            switch (a)
            {
            case <= 3.686:
                bcoef = 0.463 + s - 0.178 * s2;
                si    = 1.235;
                c     = 0.195 / s - 0.079 + 0.016 * s;
                break;

            case <= 13.022:
                bcoef = 1.654 + 0.0076 * s2;
                si    = 1.68 / s + 0.275;
                c     = 0.062 / s + 0.024;
                break;

            default:
                bcoef = 1.77;
                si    = 0.75;
                c     = 0.1515 / s;
                break;
            }

            double q;
            double v;
            switch (Math.Sqrt(a - 0.5) + 0.5 * t)
            {
            case > 0.0:
            {
                v = 0.5 * t / s;

                q = Math.Abs(v) switch
                {
                    > 0.25 => q0 - s * t + 0.25 * t * t + 2.0 * s2 * Math.Log(1.0 + v),
                    _ => q0 + 0.5 * t * t *
                    ((((((a7 * v + a6) * v + a5) * v + a4) * v + a3) * v + a2) * v + a1) * v
                };

                if (Math.Log(1.0 - u) <= q)
                {
                    x /= b;
                    return(x);
                }

                break;
            }
            }

            for (;;)
            {
                e = exponential_01_sample(ref seed);

                u = UniformRNG.r8_uniform_01(ref seed);
                t = u switch
                {
Esempio n. 6
0
    public static double[] orth_random(int n, ref typeMethods.r8NormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ORTH_RANDOM returns the ORTH_RANDOM matrix.
    //
    //  Discussion:
    //
    //    The matrix is a random orthogonal matrix.
    //
    //  Properties:
    //
    //    The inverse of A is equal to A'.
    //    A is orthogonal: A * A' = A' * A = I.
    //    Because A is orthogonal, it is normal: A' * A = A * A'.
    //    Columns and rows of A have unit Euclidean norm.
    //    Distinct pairs of columns of A are orthogonal.
    //    Distinct pairs of rows of A are orthogonal.
    //    The L2 vector norm of A*x = the L2 vector norm of x for any vector x.
    //    The L2 matrix norm of A*B = the L2 matrix norm of B for any matrix B.
    //    det ( A ) = +1 or -1.
    //    A is unimodular.
    //    All the eigenvalues of A have modulus 1.
    //    All singular values of A are 1.
    //    All entries of A are between -1 and 1.
    //
    //  Discussion:
    //
    //    Thanks to Eugene Petrov, B I Stepanov Institute of Physics,
    //    National Academy of Sciences of Belarus, for convincingly
    //    pointing out the severe deficiencies of an earlier version of
    //    this routine.
    //
    //    Essentially, the computation involves saving the Q factor of the
    //    QR factorization of a matrix whose entries are normally distributed.
    //    However, it is only necessary to generate this matrix a column at
    //    a time, since it can be shown that when it comes time to annihilate
    //    the subdiagonal elements of column K, these (transformed) elements of
    //    column K are still normally distributed random values.  Hence, there
    //    is no need to generate them at the beginning of the process and
    //    transform them K-1 times.
    //
    //    For computational efficiency, the individual Householder transformations
    //    could be saved, as recommended in the reference, instead of being
    //    accumulated into an explicit matrix format.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    11 July 2008
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    Pete Stewart,
    //    Efficient Generation of Random Orthogonal Matrices With an Application
    //    to Condition Estimators,
    //    SIAM Journal on Numerical Analysis,
    //    Volume 17, Number 3, June 1980, pages 403-409.
    //
    //  Parameters:
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input/output, int &SEED, a seed for the random number
    //    generator.
    //
    //    Output, double ORTH_RANDOM[N*N] the matrix.
    //
    {
        int i;
        int j;

        //
        //  Start with A = the identity matrix.
        //
        double[] a = typeMethods.r8mat_zero_new(n, n);

        for (i = 0; i < n; i++)
        {
            a[i + i * n] = 1.0;
        }

        //
        //  Now behave as though we were computing the QR factorization of
        //  some other random matrix.  Generate the N elements of the first column,
        //  compute the Householder matrix H1 that annihilates the subdiagonal elements,
        //  and set A := A * H1' = A * H.
        //
        //  On the second step, generate the lower N-1 elements of the second column,
        //  compute the Householder matrix H2 that annihilates them,
        //  and set A := A * H2' = A * H2 = H1 * H2.
        //
        //  On the N-1 step, generate the lower 2 elements of column N-1,
        //  compute the Householder matrix HN-1 that annihilates them, and
        //  and set A := A * H(N-1)' = A * H(N-1) = H1 * H2 * ... * H(N-1).
        //  This is our random orthogonal matrix.
        //
        double[] x = new double[n];

        for (j = 0; j < n - 1; j++)
        {
            //
            //  Set the vector that represents the J-th column to be annihilated.
            //
            for (i = 0; i < j; i++)
            {
                x[i] = 0.0;
            }

            for (i = j; i < n; i++)
            {
                x[i] = typeMethods.r8_normal_01(ref data, ref seed);
            }

            //
            //  Compute the vector V that defines a Householder transformation matrix
            //  H(V) that annihilates the subdiagonal elements of X.
            //
            //  The COLUMN argument here is 1-based.
            //
            double[] v = typeMethods.r8vec_house_column(n, x, j + 1);
            //
            //  Postmultiply the matrix A by H'(V) = H(V).
            //
            typeMethods.r8mat_house_axh(n, ref a, v);
        }

        return(a);
    }
    public static double[] pds_random(int n, ref typeMethods.r8NormalData data, ref int seed)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    PDS_RANDOM returns the PDS_RANDOM matrix.
    //
    //  Discussion:
    //
    //    The matrix is a "random" positive definite symmetric matrix.
    //
    //    The matrix returned will have eigenvalues in the range [0,1].
    //
    //  Properties:
    //
    //    A is symmetric: A' = A.
    //
    //    A is positive definite: 0 < x'*A*x for nonzero x.
    //
    //    The eigenvalues of A will be real.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    15 June 2011
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input/output, int &SEED, a seed for the random
    //    number generator.
    //
    //    Output, double PDS_RANDOM[N*N], the matrix.
    //
    {
        int j;

        double[] a = new double[n * n];
        //
        //  Get a random set of eigenvalues.
        //
        double[] lambda = UniformRNG.r8vec_uniform_01_new(n, ref seed);
        //
        //  Get a random orthogonal matrix Q.
        //
        double[] q = Orthogonal.orth_random(n, ref data, ref seed);
        //
        //  Set A = Q * Lambda * Q'.
        //
        for (j = 0; j < n; j++)
        {
            int i;
            for (i = 0; i < n; i++)
            {
                a[i + j * n] = 0.0;
                int k;
                for (k = 0; k < n; k++)
                {
                    a[i + j * n] += q[i + k * n] * lambda[k] * q[j + k * n];
                }
            }
        }
        return(a);
    }
Esempio n. 8
0
    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 + "\".");
    }