%% Multiple Streams
%% Using Multiple Independent Streams
% MATLAB® software includes generator algorithms that enable you to create multiple independent random number streams. For example, the four generator types that support multiple independent streams are the Combined Multiple Recursive ('mrg32k3a'), the Multiplicative Lagged Fibonacci ('mlfg6331_64'), the Philox 4x32 ('philox4x32_10'), and the Threefry 4x64 ('threefry4x64_20') generators. You can create multiple independent streams that are guaranteed to not overlap, and for which tests that demonstrate (pseudo)independence of the values between streams have been carried out. For more information about generator algorithms that support multiple streams, see the table of generator algorithms in Choosing a Random Number Generator.
% The RandStream.create function enables you to create streams that have the same generator algorithm and seed value, but are statistically independent.

[s1,s2,s3] = RandStream.create('mlfg6331_64','NumStreams',3)

% As evidence of independence, you can see that these streams are largely uncorrelated.

r1 = rand(s1,100000,1);
r2 = rand(s2,100000,1); 
r3 = rand(s3,100000,1);
corrcoef([r1,r2,r3])

% Depending on the application, creating only some of the streams in a set of independent streams can be useful if you need to simulate some events. Specify the StreamIndices parameter to create only some of the streams from a set of multiple streams. The StreamIndex property returns the index of each stream you create.

numLabs = 256;
labIndex = 4;
s4 = RandStream.create('mlfg6331_64','NumStreams',numLabs,'StreamIndices',labIndex)

% Multiple streams, since they are statistically independent, can be used to verify the precision of a simulation. For example, a set of independent streams can be used to repeat a Monte Carlo simulation several times in different MATLAB sessions or on different processors and determine the variance in the results. This makes multiple streams useful in large-scale parallel simulations.
%
%% Using Seeds to Get Different Results
% For generator types that do not explicitly support independent streams, different seeds provide a method to create multiple streams. By using different seeds, you can create streams that return different values and act separately from one another. However, using a generator specifically designed for multiple independent streams is a better option, as the statistical properties across streams have been carefully verified.
% Create two streams with different seeds by using the Mersenne twister generator.

s1 = RandStream('mt19937ar','Seed',1)
s2 = RandStream('mt19937ar','Seed',2)

% Use the first stream in one MATLAB session to generate random numbers.

r1 = rand(s1,100000,1);

% Use the second stream in another MATLAB session to generate random numbers.

r2 = rand(s2,100000,1);

% With different seeds, streams typically return values that are uncorrelated.

corrcoef([r1,r2])

% The two streams with different seeds may appear uncorrelated since the state space of the Mersenne Twister is so much larger ($2^{19937}$ elements) than the number of possible seeds ($2^{32}$). The chances of overlap in different simulation runs are pretty remote unless you use a large number of different seeds. Using widely spaced seeds does not increase the level of randomness. In fact, taking this strategy to the extreme and reseeding a generator before each call can result in the sequence of values that are not statistically independent and identically distributed.
% Seeding a stream is most useful if you use it as an initialization step, perhaps at MATLAB startup, or before running a simulation.
%
%% Using Substreams to Get Different Results
% Another method to get different results from a stream is to use substreams. Unlike seeds, where the locations along the sequence of random numbers are not exactly known, the spacing between substreams is known, so any chance of overlap can be eliminated. Like independent parallel streams, research has been done to demonstrate statistical independence across substreams. In short, substreams are a more controlled way to do many of the same things that seeds have traditionally been used for, and a more lightweight solution than parallel streams.
% Substreams provide a quick and easy way to ensure that you get different results from the same code at different times. For example, generate several random numbers in a loop.

defaultStream = RandStream('mlfg6331_64');
RandStream.setGlobalStream(defaultStream)
for i = 1:5
    defaultStream.Substream = i;
    z = rand(1,i)
end

% In another loop, you can generate random values that are independent from the first set of 5 iterations.

for i = 6:10
    defaultStream.Substream = i;
    z = rand(1,11-i)
end

% Each of these substreams can reproduce its loop iteration. For example, you can return to the 6th substream in the loop.

defaultStream.Substream = 6;
z = rand(1,5)

%
%
% Copyright 2020 The MathWorks, Inc.