function [ quasi, seed ] = i4_sobol ( dim_num, seed ) %*****************************************************************************80 % %% I4_SOBOL generates a new quasirandom Sobol vector with each call. % % Discussion: % % The routine adapts the ideas of Antonov and Saleev. % % Thanks to Francis Dalaudier for pointing out that the range of allowed % values of DIM_NUM should start at 1, not 2! 17 February 2009. % % This function was modified to use PERSISTENT variables rather than % GLOBAL variables, 13 December 2009. % % Licensing: % % This code is distributed under the GNU LGPL license. % % Modified: % % 26 March 2012 % % Author: % % Original FORTRAN77 version by Bennett Fox. % MATLAB version by John Burkardt. % % Reference: % % Antonov, Saleev, % USSR Computational Mathematics and Mathematical Physics, % Volume 19, 1980, pages 252 - 256. % % Paul Bratley, Bennett Fox, % Algorithm 659: % Implementing Sobol's Quasirandom Sequence Generator, % ACM Transactions on Mathematical Software, % Volume 14, Number 1, pages 88-100, 1988. % % Bennett Fox, % Algorithm 647: % Implementation and Relative Efficiency of Quasirandom % Sequence Generators, % ACM Transactions on Mathematical Software, % Volume 12, Number 4, pages 362-376, 1986. % % Ilya Sobol, % USSR Computational Mathematics and Mathematical Physics, % Volume 16, pages 236-242, 1977. % % Ilya Sobol, Levitan, % The Production of Points Uniformly Distributed in a Multidimensional % Cube (in Russian), % Preprint IPM Akad. Nauk SSSR, % Number 40, Moscow 1976. % % Parameters: % % Input, integer DIM_NUM, the number of spatial dimensions. % DIM_NUM must satisfy 1 <= DIM_NUM <= 40. % % Input/output, integer SEED, the "seed" for the sequence. % This is essentially the index in the sequence of the quasirandom % value to be generated. On output, SEED has been set to the % appropriate next value, usually simply SEED+1. % If SEED is less than 0 on input, it is treated as though it were 0. % An input value of 0 requests the first (0-th) element of the sequence. % % Output, real QUASI(DIM_NUM), the next quasirandom vector. % persistent atmost; persistent dim_max; persistent dim_num_save; persistent initialized; persistent lastq; persistent log_max; persistent maxcol; persistent poly; persistent recipd; persistent seed_save; persistent v; if ( isempty ( initialized ) ) initialized = 0; dim_num_save = -1; end if ( ~initialized | dim_num ~= dim_num_save ) initialized = 1; dim_max = 40; dim_num_save = -1; log_max = 30; seed_save = -1; % % Initialize (part of) V. % v(1:dim_max,1:log_max) = zeros(dim_max,log_max); v(1:40,1) = [ ... 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]'; v(3:40,2) = [ ... 1, 3, 1, 3, 1, 3, 3, 1, ... 3, 1, 3, 1, 3, 1, 1, 3, 1, 3, ... 1, 3, 1, 3, 3, 1, 3, 1, 3, 1, ... 3, 1, 1, 3, 1, 3, 1, 3, 1, 3 ]'; v(4:40,3) = [ ... 7, 5, 1, 3, 3, 7, 5, ... 5, 7, 7, 1, 3, 3, 7, 5, 1, 1, ... 5, 3, 3, 1, 7, 5, 1, 3, 3, 7, ... 5, 1, 1, 5, 7, 7, 5, 1, 3, 3 ]'; v(6:40,4) = [ ... 1, 7, 9,13,11, ... 1, 3, 7, 9, 5,13,13,11, 3,15, ... 5, 3,15, 7, 9,13, 9, 1,11, 7, ... 5,15, 1,15,11, 5, 3, 1, 7, 9 ]'; v(8:40,5) = [ ... 9, 3,27, ... 15,29,21,23,19,11,25, 7,13,17, ... 1,25,29, 3,31,11, 5,23,27,19, ... 21, 5, 1,17,13, 7,15, 9,31, 9 ]'; v(14:40,6) = [ ... 37,33, 7, 5,11,39,63, ... 27,17,15,23,29, 3,21,13,31,25, ... 9,49,33,19,29,11,19,27,15,25 ]'; v(20:40,7) = [ ... 13, ... 33,115, 41, 79, 17, 29,119, 75, 73,105, ... 7, 59, 65, 21, 3,113, 61, 89, 45,107 ]'; v(38:40,8) = [ ... 7, 23, 39 ]'; % % Set POLY. % poly(1:40)= [ ... 1, 3, 7, 11, 13, 19, 25, 37, 59, 47, ... 61, 55, 41, 67, 97, 91, 109, 103, 115, 131, ... 193, 137, 145, 143, 241, 157, 185, 167, 229, 171, ... 213, 191, 253, 203, 211, 239, 247, 285, 369, 299 ]; atmost = 2^log_max - 1; % % Find the number of bits in ATMOST. % maxcol = i4_bit_hi1 ( atmost ); % % Initialize row 1 of V. % v(1,1:maxcol) = 1; end % % Things to do only if the dimension changed. % if ( dim_num ~= dim_num_save ) % % Check parameters. % if ( dim_num < 1 | dim_max < dim_num ) fprintf ( 1, '\n' ); fprintf ( 1, 'I4_SOBOL - Fatal error!\n' ); fprintf ( 1, ' The spatial dimension DIM_NUM should satisfy:\n' ); fprintf ( 1, ' 1 <= DIM_NUM <= %d\n', dim_max ); fprintf ( 1, ' But this input value is DIM_NUM = %d\n', dim_num ); return end dim_num_save = dim_num; % % Initialize the remaining rows of V. % for i = 2 : dim_num % % The bits of the integer POLY(I) gives the form of polynomial I. % % Find the degree of polynomial I from binary encoding. % j = poly(i); m = 0; while ( 1 ) j = floor ( j / 2 ); if ( j <= 0 ) break; end m = m + 1; end % % Expand this bit pattern to separate components of the logical array INCLUD. % j = poly(i); for k = m : -1 : 1 j2 = floor ( j / 2 ); includ(k) = ( j ~= 2 * j2 ); j = j2; end % % Calculate the remaining elements of row I as explained % in Bratley and Fox, section 2. % for j = m + 1 : maxcol newv = v(i,j-m); l = 1; for k = 1 : m l = 2 * l; if ( includ(k) ) newv = bitxor ( newv, l * v(i,j-k) ); end end v(i,j) = newv; end end % % Multiply columns of V by appropriate power of 2. % l = 1; for j = maxcol-1 : -1 : 1 l = 2 * l; v(1:dim_num,j) = v(1:dim_num,j) * l; end % % RECIPD is 1/(common denominator of the elements in V). % recipd = 1.0 / ( 2 * l ); lastq(1:dim_num) = 0; end seed = floor ( seed ); if ( seed < 0 ) seed = 0; end if ( seed == 0 ) l = 1; lastq(1:dim_num) = 0; elseif ( seed == seed_save + 1 ) % % Find the position of the right-hand zero in SEED. % l = i4_bit_lo0 ( seed ); elseif ( seed <= seed_save ) seed_save = 0; l = 1; lastq(1:dim_num) = 0; for seed_temp = seed_save : seed - 1 l = i4_bit_lo0 ( seed_temp ); for i = 1 : dim_num lastq(i) = bitxor ( lastq(i), v(i,l) ); end end l = i4_bit_lo0 ( seed ); elseif ( seed_save + 1 < seed ) for seed_temp = seed_save + 1 : seed - 1 l = i4_bit_lo0 ( seed_temp ); for i = 1 : dim_num lastq(i) = bitxor ( lastq(i), v(i,l) ); end end l = i4_bit_lo0 ( seed ); end % % Check that the user is not calling too many times! % if ( maxcol < l ) fprintf ( 1, '\n' ); fprintf ( 1, 'I4_SOBOL - Fatal error!\n' ); fprintf ( 1, ' Too many calls!\n' ); fprintf ( 1, ' MAXCOL = %d\n', maxcol ); fprintf ( 1, ' L = %d\n', l ); return end % % Calculate the new components of QUASI. % for i = 1 : dim_num quasi(i) = lastq(i) * recipd; lastq(i) = bitxor ( lastq(i), v(i,l) ); end seed_save = seed; seed = seed + 1; return end