function feynman_kac_2d ( ) %*****************************************************************************80 % %% MAIN is the main program for FEYNMAN_KAC_2D. % % Discussion: % % This program is derived from section 2.5, exercise 2.2 of Petersen and Arbenz. % % The problem is to determine the solution U(X,Y) of the following % partial differential equation: % % (1/2) Laplacian U - V(X,Y) * U = 0, % % inside the elliptic domain D: % % D = { (X,Y) | (X/A)^2+(Y/B)^2 <= 1 } % % with the boundary condition U(boundary(D)) = 1. % % The V(X,Y) is the potential function: % % V = 2 * ( (X/A^2)^2 + (Y/B^2)^2 ) + 1/A^2 + 1/B^2. % % The analytic solution of this problem is already known: % % U(X,Y) = exp ( (X/A)^2 + (Y/B)^2 - 1 ). % % Our method is via the Feynman-Kac Formula. % % The idea is to start from any (x,y) in D, and % compute (x+Wx(t),y+Wy(t)) where 3-D Brownian motion % (Wx,Wy) is updated each step by sqrt(h)*(z1,z2), % each z1,z2 are independent approximately Gaussian % random variables with zero mean and variance 1. % % Each (x1(t),x2(t)) is advanced until (x1,x2) exits the domain D. % % Upon its first exit from D, the sample path (x1,x2) is stopped and a % new sample path at (x,y) is started until N such paths are completed. % % The Feynman-Kac formula gives the solution here as % % U(X,Y) = (1/N) sum(1 <= I <= N) Y(tau_i), % % where % % Y(tau) = exp( -int(s=0..tau) v(x1(s),x2(s)) ds), % % and tau = first exit time for path (x1,x2). % % The integration procedure is a second order weak accurate method: % % X(t+h) = [ x1(t) + sqrt ( h ) * z1 ] % [ x2(t) + sqrt ( h ) * z2 ] % % Here Z1, Z2 are approximately normal univariate Gaussians. % % An Euler predictor approximates Y at the end of the step % % Y_e = (1 - h*v(X(t)) * Y(t), % % A trapezoidal rule completes the step: % % Y(t+h) = Y(t) - (h/2)*[v(X(t+h))*Y_e + v(X(t))*Y(t)]. % % Grateful thanks to Arno Petri, who pointed out, on 30 July 2012, that % this program could be substantially speeded up by % * calling the system random number generator "rand()" instead of % r8_uniform_01() % * suppressing the "return/end" statements (which apparently result in % a massive amount of worthless overhead.) % % Licensing: % % This code is distributed under the GNU LGPL license. % % Modified: % % 31 July 2012 % % Author: % % Original C version by Wesley Petersen. % MATLAB version by John Burkardt. % % Reference: % % Peter Arbenz, Wesley Petersen, % Introduction to Parallel Computing: % A Practical Guide with Examples in C, % Oxford, 2004, % ISBN: 0-19-851577-4, % LC: QA76.59.P47. % % Local parameters: % % Local, int GENERATOR, chooses the random number generator. % 0, use Matlab's rand(); % nonzero, use r8_uniform_01(). % tic GENERATOR = 0; if ( GENERATOR == 0 ) rand ( 'state', 0 ) else seed = 123456789; end a = 2.0; b = 1.0; dim = 2; h = 0.001; n = 100; timestamp ( ) fprintf ( 1, '\n' ); fprintf ( 1, 'FEYNMAN_KAC_2D:\n' ); fprintf ( 1, ' MATLAB version.\n' ); fprintf ( 1, '\n' ); fprintf ( 1, ' Program parameters:\n' ); fprintf ( 1, '\n' ); fprintf ( 1, ' The calculation takes place inside a 2D ellipse.\n' ); fprintf ( 1, ' A rectangular grid of points will be defined.\n' ); fprintf ( 1, ' The solution will be estimated for those grid points\n' ); fprintf ( 1, ' that lie inside the ellipse.\n' ); fprintf ( 1, '\n' ); fprintf ( 1, ... ' Each solution will be estimated by computing %d trajectories\n', n ); fprintf ( 1, ' from the point to the boundary.\n' ); fprintf ( 1, '\n' ); fprintf ( 1, ' (X/A)^2 + (Y/B)^2 = 1\n' ); fprintf ( 1, '\n' ); fprintf ( 1, ' The ellipse parameters A, B are set to:\n' ); fprintf ( 1, '\n' ); fprintf ( 1, ' A = %f\n', a ); fprintf ( 1, ' B = %f\n', b ); fprintf ( 1, ' Stepsize H = %f\n', h ); % % RTH is the scaled stepsize. % rth = sqrt ( dim * h ); % % Choose the spacing so we have about 10 points in the shorter direction. % if ( a < b ) ni = 6; nj = 1 + ceil ( b / a ) * ( ni - 1 ); else nj = 6; ni = 1 + ceil ( a / b ) * ( nj - 1 ); end fprintf ( 1, '\n' ); fprintf ( 1, ' X coordinate marked by %d points\n', ni ); fprintf ( 1, ' Y coordinate marked by %d points\n', nj ); % % Loop over the grid points. % err = 0.0; n_inside = 0; fprintf ( 1, '\n' ); fprintf ( 1, ... ' X Y W W Error Average\n' ); fprintf ( 1, ... ' approx exact Steps\n' ); fprintf ( 1, '\n' ); for i = 1 : ni x = ( ( ni - i ) * ( - a ) ... + ( i - 1 ) * a ) ... / ( ni - 1 ); for j = 1 : nj y = ( ( nj - j ) * ( - b ) ... + ( j - 1 ) * b ) ... / ( nj - 1 ); chk = ( x / a )^2 + ( y / b )^2; if ( 1.0D+00 < chk ) w_exact = 1.0; wt = 1.0; steps_ave = 0; fprintf ( 1, ' %12f %12f %12f %12f %12f %8d\n', ... x, y, wt, w_exact, abs ( w_exact - wt ), steps_ave ); continue; end n_inside = n_inside + 1; % % Compute the exact solution at this point (x,y). % w_exact = exp ( ( x / a )^2 + ( y / b )^2 - 1.0 ); % % Now try to estimate the solution at this point. % wt = 0.0; steps = 0; for k = 1 : n x1 = x; x2 = y; % % W = exp(-int(s=0..t) v(X)ds) % w = 1.0; % % CHK is < 1.0 while the point is inside the ellipsoid. % chk = 0.0; while ( chk < 1.0 ) % % Determine DX, DY. % if ( GENERATOR == 0 ) ut = rand ( ); else [ ut, seed ] = r8_uniform_01 ( seed ); end if ( ut < 1.0 / 2.0 ) if ( GENERATOR == 0 ) us = rand ( ); else [ us, seed ] = r8_uniform_01 ( seed ); end if ( us < 0.5 ) dx = - rth; else dx = + rth; end else dx = 0.0; end if ( GENERATOR == 0 ) ut = rand ( ); else [ ut, seed ] = r8_uniform_01 ( seed ); end if ( ut < 1.0 / 2.0 ) if ( GENERATOR == 0 ) us = rand ( ); else [ us, seed ] = r8_uniform_01 ( seed ); end if ( us < 0.5 ) dy = - rth; else dy = + rth; end else dy = 0.0; end vs = potential ( a, b, x1, x2 ); % % Move to the new point. % x1 = x1 + dx; x2 = x2 + dy; steps = steps + 1; vh = potential ( a, b, x1, x2 ); we = ( 1.0 - h * vs ) * w; w = w - 0.5 * h * ( vh * we + vs * w ); chk = ( x1 / a )^2 + ( x2 / b )^2; end wt = wt + w; end % % WT is the average of the sum of the different trials. % wt = wt / n; steps_ave = floor ( steps / n ); % % Add error in WT to the running L2 error in the solution. % err = err + ( w_exact - wt )^2; fprintf ( 1, ' %12f %12f %12f %12f %12f %8d\n', ... x, y, wt, w_exact, abs ( w_exact - wt ), steps_ave ); end end % % Compute the RMS error for all the points. % err = sqrt ( err / n_inside ); fprintf ( 1, '\n' ); fprintf ( 1, ' RMS absolute error in solution = %f\n', err ); % % Terminate. % fprintf ( 1, '\n' ); fprintf ( 1, 'FEYNMAN_KAC_2D:\n' ); fprintf ( 1, ' Normal end of execution.\n' ); fprintf ( 1, '\n' ); toc timestamp ( ); return end function v = potential ( a, b, x, y ) %*****************************************************************************80 % %% POTENTIAL evaluates the potential function V(X,Y). % % Licensing: % % This code is distributed under the GNU LGPL license. % % Modified: % % 08 August 2010 % % Author: % % John Burkardt % % Parameters: % % Input, real A, B, the parameters that define the ellipse. % % Input, real X, Y, the coordinates of the point. % % Output, real V, the value of the potential function. % v = 2.0 * ( ( x / a^2 )^2 + ( y / b^2 )^2 ) + 1.0 / a^2 + 1.0 / b^2; return end function [ r, seed ] = r8_uniform_01 ( seed ) %*****************************************************************************80 % %% R8_UNIFORM_01 returns a unit pseudorandom R8. % % Discussion: % % This routine implements the recursion % % seed = 16807 * seed mod ( 2^31 - 1 ) % r8_uniform_01 = seed / ( 2^31 - 1 ) % % The integer arithmetic never requires more than 32 bits, % including a sign bit. % % If the initial seed is 12345, then the first three computations are % % Input Output R8_UNIFORM_01 % SEED SEED % % 12345 207482415 0.096616 % 207482415 1790989824 0.833995 % 1790989824 2035175616 0.947702 % % Licensing: % % This code is distributed under the GNU LGPL license. % % Modified: % % 21 September 2006 % % Author: % % John Burkardt % % Reference: % % Paul Bratley, Bennett Fox, Linus Schrage, % A Guide to Simulation, % Second Edition, % Springer, 1987, % ISBN: 0387964673, % LC: QA76.9.C65.B73. % % Bennett Fox, % Algorithm 647: % Implementation and Relative Efficiency of Quasirandom % Sequence Generators, % ACM Transactions on Mathematical Software, % Volume 12, Number 4, December 1986, pages 362-376. % % Pierre L'Ecuyer, % Random Number Generation, % in Handbook of Simulation, % edited by Jerry Banks, % Wiley, 1998, % ISBN: 0471134031, % LC: T57.62.H37. % % Peter Lewis, Allen Goodman, James Miller, % A Pseudo-Random Number Generator for the System/360, % IBM Systems Journal, % Volume 8, Number 2, 1969, pages 136-143. % % Parameters: % % Input, integer SEED, the integer "seed" used to generate % the output random number. SEED should not be 0. % % Output, real R, a random value between 0 and 1. % % Output, integer SEED, the updated seed. This would % normally be used as the input seed on the next call. % i4_huge = 2147483647; if ( seed == 0 ) fprintf ( 1, '\n' ); fprintf ( 1, 'R8_UNIFORM_01 - Fatal error!\n' ); fprintf ( 1, ' Input SEED = 0!\n' ); error ( 'R8_UNIFORM_01 - Fatal error!' ); end seed = floor ( seed ); seed = mod ( seed, i4_huge ); if ( seed < 0 ) seed = seed + i4_huge; end k = floor ( seed / 127773 ); seed = 16807 * ( seed - k * 127773 ) - k * 2836; if ( seed < 0 ) seed = seed + i4_huge; end r = seed * 4.656612875E-10; return end function timestamp ( ) %*****************************************************************************80 % %% TIMESTAMP prints the current YMDHMS date as a timestamp. % % Licensing: % % This code is distributed under the GNU LGPL license. % % Modified: % % 14 February 2003 % % Author: % % John Burkardt % t = now; c = datevec ( t ); s = datestr ( c, 0 ); fprintf ( 1, '%s\n', s ); return end