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 + "\"."); } }
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); }
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); }
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 + ""); }
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); }
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); }
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); }
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))); } }
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 + ""); }
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 + "\"."); }