function [seed,whichGen] = ClockRandSeed(seed,whichGen)
% [seed,whichGen] = ClockRandSeed([seed],[whichGen])
% ClockRandSeed seeds the random number from the time-of-day clock or another
% "random enough" random source, e.g., high resolution time, or a true
% random number source. If 'seed' is passed this is used instead of a
% random source or clock time.
%
% 'whichGen' optionally allows selection of the random number generator.
% If omitted, the recommended Mersenne-Twister will be used on both
% Matlab and Octave.
%
% If supported, the rng() function will be used, with rng('shuffle') if
% 'seed' is omitted. Otherwise the old rand()/randn() setup method is
% used, with 'reset' on Octave for truly random init from /dev/urandom
% or high resolution clock time. On Matlab the old seed = fix(1e6*sum(clock))
% will be used.
%
% NOTE: There is a page in the 2017 Matlab docs describing the issues around
% random number generator selection and seeding. Type "help rand" and then
% follow to the note on "Replace Discouraged Syntaxes of rand and randn" that
% is at the end of the Description section.
%
% For reseeding on old Matlab versions, note the following:
%
% The multiplier 1e6 in fix(1e6*sum(clock)) is bigger than the 100
% suggested by Mathworks (see help RAND). They suggest 100*sum(clock), but
% this would only change the seed once every 1/100 sec, which might
% correspond to many iterations of a loop. With the bigger multiplier it's
% pretty sure (depending only on clock grain) that two successive calls
% will generate different seeds.
%
% Also unlike the Mathworks suggestion (see help RAND), we call FIX. This
% has no effect on RAND and RANDN, but makes it easier to correctly print
% the seed to a file. When a random seed generates an interesting result
% one would like to be able to recreate the conditions that generated the
% run. If the seed 1e6*sum(clock) is printed to a file, '%.0f' will often
% round it differently than RAND would.
%
% See also: rng, rand, randn.
% 10/15/93 dhb Made this a function.
% 4/11/94 dhb Added randn seeding.
% 8/9/97 dgp Update for more reliable seed.
% dgp Gutted it to make version-dependence explicit.
% 8/9/97 dhb Ungutted it to hide version-dependence.
% 8/13/97 dhb Optional return of which generator used and passing of seed/generator.
% 7/24/04 awi Cosmetic.
% 1/29/05 dgp Cosmetic.
% 06/15/17 dhb Added warning and help text that this is obsolete.
% 9-Aug-17 mk Undid dhb's warning, as it promotes writing non-portable code
% that only works on specific versions of Matlab, and thereby
% creates vendor lock-in. Instead rewrote the function to call
% equivalent methods to rng('shuffle') in current Octave and older
% versions of Matlab, and rng('shuffle') in current Matlab and
% future Octave. That was the whole point of having ClockRandSeed()
% in the first place: Something that doesn't break each time that
% Mathworks incompetent or careless software engineering breaks
% backward compatibility. At least i don't want this to degrade to
% Mathworks or Apples standards if possible.
% 6-May-20 mk Take into account that recent rng() implementations can
% return 'seed' as a struct consisting of seed and generator
% type. Reported and suggested fix by Xiangrui Li, thanks!
if nargin < 2 || isempty(whichGen)
% Recommended generator on Matlab and Octave is 'twister' for Mersenne-Twister.
% This is also the default startup generator of Octave and modern Matlab:
whichGen = 'twister';
end
if nargin < 1 || isempty(seed)
% No seed specified. Let Matlab/Octave do the job:
if exist('rng')
% Reinit from system time or other appropriate source:
rng('shuffle', whichGen);
% Retrieve new seed after reinit:
seed = rng;
if isstruct(seed)
whichGen = seed.Type;
seed = seed.Seed;
end
else
if IsOctave
% Octave 'reset' will reinit from system time, or from the
% truly random random number generator /dev/urandom if it
% exists, e.g. on Linux:
rand(whichGen, 'reset');
% Retrieve new seed after init:
seed = rand(whichGen);
% Apply it to the other randn() generator, so both operate
% off the same 'seed':
randn(whichGen, seed);
else
% Matlab: Manually reinit with clock time:
seed = fix(1e6*sum(clock));
rand(whichGen, seed);
randn(whichGen, seed);
end
end
% Got our reinit and whichGen and seed contain the new selected
% generator type and seed, so we are done:
return;
end
% If we get to this point, then user wants total control:
if exist('rng')
rng(seed, whichGen);
else
rand(whichGen,seed);
randn(whichGen,seed);
end
return;