516 lines
12 KiB
Racket
516 lines
12 KiB
Racket
#lang scribble/manual
|
|
@(require (for-label racket))
|
|
|
|
@title{Randomness}
|
|
@section{categories}
|
|
Random
|
|
Randomness in SC@section{related}
|
|
Reference/randomSeed
|
|
|
|
As in any computer program, there are no "truly random" number generators in SC.
|
|
They are pseudo-random, meaning they use very complex, but deterministic
|
|
algorithms to generate sequences of numbers that are long enough and complicated enough
|
|
to seem "random" for human beings. (i.e. the patterns are too complex for us to detect.)
|
|
|
|
If you start a random number generator algorithm with the same "seed" number
|
|
several times, you get the same sequence of random numbers.
|
|
(See example below, randomSeed)
|
|
|
|
@section{section}
|
|
Create single random numbers
|
|
|
|
@section{subsection}
|
|
Between zero and <number>
|
|
|
|
@racketblock[
|
|
5.rand // evenly distributed.
|
|
|
|
1.0.linrand // probability decreases linearly from 0 to <number>.
|
|
::
|
|
|
|
]
|
|
@section{subsection}
|
|
Between -<number> and <number>
|
|
|
|
@racketblock[
|
|
5.0.rand2 // evenly distributed.
|
|
|
|
10.bilinrand // probability is highest around 0,
|
|
// decreases linearly toward +-<number>.
|
|
|
|
1.0.sum3rand // quasi-gaussian, bell-shaped distribution.
|
|
::
|
|
|
|
]
|
|
@section{subsection}
|
|
Within a given range
|
|
|
|
@racketblock[
|
|
rrand(24, 48) // linear distribution in the given range.
|
|
|
|
exprand(0.01, 1) // exponential distribution;
|
|
// both numbers must have the same sign.
|
|
// (Note that the distribution of numbers is not exactly an exponential distribution,
|
|
// since that would be unbounded: we might call it a logarithmic uniform distribution.)
|
|
::
|
|
|
|
]
|
|
@section{subsection}
|
|
Test them multiple times with a do loop
|
|
|
|
@racketblock[
|
|
20.do({ 5.rand.postln; }); // evenly distributed
|
|
|
|
20.do({ 1.0.linrand.postln; }); // probability decreases linearly from 0 to 1.0
|
|
|
|
20.do({ 5.0.rand2.postln; }); // even
|
|
|
|
20.do({ 10.bilinrand.postln; }); // probability is highest around 0,
|
|
// decreases linearly toward +-<number>.
|
|
|
|
20.do({ 1.0.sum3rand.postln; }); // quasi-gaussian, bell-shaped.
|
|
::
|
|
|
|
]
|
|
@section{subsection}
|
|
Collect the results in an array
|
|
|
|
@racketblock[
|
|
Array.fill(10, { 1000.linrand }).postln;
|
|
|
|
// or more compact:
|
|
|
|
{ 1.0.sum3rand }.dup(100)
|
|
|
|
// or:
|
|
|
|
({ 1.0.sum3rand } ! 100)
|
|
::
|
|
|
|
]
|
|
@section{subsection}
|
|
Seeding
|
|
You can seed a random generator in order to repeat
|
|
the same sequence of random numbers:
|
|
|
|
@racketblock[
|
|
(
|
|
5.do({
|
|
thisThread.randSeed = 4;
|
|
Array.fill(10, { 1000.linrand}).postln;
|
|
});
|
|
)
|
|
|
|
// Just to check, no seeding:
|
|
|
|
(
|
|
5.do({ Array.fill(10, { 1000.linrand }).postln; });
|
|
)
|
|
::
|
|
See also link::Reference/randomSeed::.
|
|
|
|
|
|
]
|
|
@section{subsection}
|
|
Histograms
|
|
Demonstrate the various statistical distributions visually, with histograms:
|
|
|
|
|
|
@racketblock[
|
|
Array.fill(500, { 1.0.rand }).plot("Sequence of 500x 1.0.rand");
|
|
|
|
Array.fill(500, { 1.0.linrand }).plot("Sequence of 500x 1.0.linrand");
|
|
|
|
Array.fill(500, { 1.0.sum3rand }).plot("Sequence of 500x 1.0.sum3rand");
|
|
::
|
|
|
|
Use a histogram to display how often each (integer)
|
|
occurs in a collection of random numbers, :
|
|
]
|
|
|
|
@racketblock[
|
|
(
|
|
var randomNumbers, histogram, maxValue = 500, numVals = 10000, numBins = 500;
|
|
|
|
randomNumbers = Array.fill(numVals, { maxValue.rand; });
|
|
histogram = randomNumbers.histo(numBins, 0, maxValue);
|
|
histogram.plot("histogram for rand 0 - " ++ maxValue);
|
|
)
|
|
::
|
|
|
|
A histogram for linrand:
|
|
]
|
|
|
|
@racketblock[
|
|
(
|
|
var randomNumbers, histogram, maxValue = 500.0, numVals = 10000, numBins = 500;
|
|
|
|
randomNumbers = Array.fill(numVals, { maxValue.linrand; });
|
|
histogram = randomNumbers.histo(numBins, 0, maxValue);
|
|
histogram.plot("histogram for linrand 0 - " ++ maxValue);
|
|
)
|
|
::
|
|
A histogram for bilinrand:
|
|
]
|
|
|
|
@racketblock[
|
|
(
|
|
var randomNumbers, histogram, minValue = -250, maxValue = 250, numVals = 10000, numBins = 500;
|
|
|
|
randomNumbers = Array.fill(numVals, { maxValue.bilinrand; });
|
|
histogram = randomNumbers.histo(numBins, minValue, maxValue);
|
|
histogram.plot("histogram for bilinrand" + minValue + "to" + maxValue);
|
|
)
|
|
::
|
|
|
|
A histogram for exprand:
|
|
]
|
|
|
|
@racketblock[
|
|
(
|
|
var randomNumbers, histogram, minValue = 5.0, maxValue = 500, numVals = 10000, numBins = 500;
|
|
|
|
randomNumbers = Array.fill(numVals, { exprand(minValue, maxValue); });
|
|
histogram = randomNumbers.histo(numBins, minValue, maxValue);
|
|
histogram.plot("histogram for exprand: " ++ minValue ++ " to " ++ maxValue);
|
|
)
|
|
::
|
|
|
|
And for sum3rand (cheap quasi-gaussian):
|
|
]
|
|
|
|
@racketblock[
|
|
(
|
|
var randomNumbers, histogram, minValue = -250, maxValue = 250, numVals = 10000, numBins = 500;
|
|
|
|
randomNumbers = Array.fill(numVals, { maxValue.sum3rand; });
|
|
histogram = randomNumbers.histo(numBins, minValue, maxValue);
|
|
histogram.plot("histogram for sum3rand " ++ minValue ++ " to " ++ maxValue);
|
|
)
|
|
::
|
|
|
|
|
|
]
|
|
@section{subsection}
|
|
on Collections
|
|
All of the single-number methods also work for (Sequenceable)Collections,
|
|
simply by applying the given random message to each element of the collection:
|
|
|
|
@racketblock[
|
|
[ 1.0, 10, 100.0, \aSymbol ].rand.postln; // note: Symbols are left as they are.
|
|
List[ 10, -3.0, \aSymbol ].sum3rand.postln;
|
|
::
|
|
|
|
]
|
|
@section{subsection}
|
|
Arbitrary random distributions
|
|
|
|
An integral table can be used to create an arbitrary random distribution quite efficiently. The table
|
|
building is expensive though. The more points there are in the random table, the more accurate the
|
|
distribution.
|
|
|
|
@racketblock[
|
|
(
|
|
var randomNumbers, histogram, distribution, randomTable, randTableSize=200;
|
|
var minValue = -250, maxValue = 250, numVals = 10000, numBins = 500;
|
|
|
|
// create some random distribution with values between 0 and 1
|
|
distribution = Array.fill(randTableSize,
|
|
{ arg i; (i/ randTableSize * 35).sin.max(0) * (i / randTableSize) }
|
|
);
|
|
|
|
// render a randomTable
|
|
randomTable = distribution.asRandomTable;
|
|
|
|
// get random numbers, scale them
|
|
|
|
randomNumbers = Array.fill(numVals, { randomTable.tableRand * (maxValue - minValue) + minValue; });
|
|
histogram = randomNumbers.histo(numBins, minValue, maxValue);
|
|
|
|
|
|
histogram.plot("this is the histogram we got");
|
|
distribution.plot("this was the histogram we wanted");
|
|
)
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Random decisions
|
|
|
|
|
|
@racketblock[ coin :: simulates a coin toss and results in true or false.
|
|
1.0 is always true, 0.0 is always false, 0.5 is 50:50 chance.
|
|
]
|
|
|
|
@racketblock[
|
|
20.do({ 0.5.coin.postln });
|
|
::
|
|
biased random decision can be simulated bygenerating a single value
|
|
and check against a threshhold:
|
|
]
|
|
|
|
@racketblock[
|
|
20.do({ (1.0.linrand > 0.5).postln });
|
|
20.do({ (exprand(0.05, 1.0) > 0.5).postln });
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Generating Collections of random numbers
|
|
|
|
@racketblock[
|
|
// size, minVal, maxVal
|
|
Array.rand(7, 0.0, 1.0).postln;
|
|
|
|
// is short for:
|
|
|
|
Array.fill(7, { rrand(0.0, 1.0) }).postln;
|
|
::
|
|
]
|
|
|
|
@racketblock[
|
|
// size, minVal, maxVal
|
|
List.linrand(7, 10.0, 15.0).postln;
|
|
|
|
// is short for:
|
|
|
|
List.fill(7, { 10 + 5.0.linrand }).postln;
|
|
::
|
|
|
|
]
|
|
|
|
@racketblock[
|
|
Signal.exprand(10, 0.1, 1);
|
|
|
|
Signal.rand2(10, 1.0);
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Random choice from Collections
|
|
|
|
|
|
@racketblock[choose:: : equal chance for each element.
|
|
]
|
|
|
|
@racketblock[
|
|
10.do({ [ 1, 2, 3 ].choose.postln });
|
|
::
|
|
|
|
Weighted choice:
|
|
|
|
]
|
|
|
|
@racketblock[wchoose(weights):: : An array of weights sets the chance for each element.
|
|
]
|
|
|
|
@racketblock[
|
|
10.do({ [ 1, 2, 3 ].wchoose([0.1, 0.2, 0.7]).postln });
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Randomize the order of a Collection
|
|
|
|
|
|
@racketblock[
|
|
List[ 1, 2, 3, 4, 5 ].scramble.postln;
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Generate random numbers without duplicates
|
|
|
|
@racketblock[
|
|
f = { |n=8, min=0, max=7| (min..max).scramble.keep(n) };
|
|
f.value(8, 0, 7)
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Randomly group a Collection
|
|
|
|
@racketblock[
|
|
curdle(probability)
|
|
::
|
|
The probability argument sets the chance that two adjacent elements will be separated.
|
|
]
|
|
|
|
@racketblock[
|
|
[ 1, 2, 3, 4, 5, 6, 7, 8 ].curdle(0.2).postln; // big groups
|
|
|
|
[ 1, 2, 3, 4, 5, 6, 7, 8 ].curdle(0.75).postln; // small groups
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Random signal generators, i.e. UGens
|
|
@section{list}
|
|
|
|
## link::Classes/PinkNoise::
|
|
## link::Classes/WhiteNoise::
|
|
## link::Classes/GrayNoise::
|
|
## link::Classes/BrownNoise::
|
|
## link::Classes/ClipNoise::
|
|
## link::Classes/LFNoise0::
|
|
## link::Classes/LFNoise1::
|
|
## link::Classes/LFNoise2::
|
|
## link::Classes/LFClipNoise::
|
|
## link::Classes/LFDNoise0::
|
|
## link::Classes/LFDNoise1::
|
|
## link::Classes/LFDNoise3::
|
|
## link::Classes/LFDClipNoise::
|
|
## link::Classes/Dust::
|
|
## link::Classes/Dust2::
|
|
## link::Classes/Crackle::
|
|
## link::Classes/TWChoose::
|
|
::
|
|
|
|
Also see UGens>Generators>Stochastic in the link::Browse#UGens>Generators>Stochastic:: page.
|
|
|
|
@section{subsection}
|
|
Random operators on signals
|
|
|
|
Unary or binary random method produce a random value for each frame (not implemented in some cases). This can be used to implement tendency masks.
|
|
|
|
|
|
@racketblock[
|
|
{ rrand(SinOsc.ar(0.1), SinOsc.ar(0.42)) * 0.1 }.play
|
|
{ exprand(SinOsc.ar(0.1)) * 0.1 }.play
|
|
{ linrand(SinOsc.ar(0.1)) * 0.1 }.play
|
|
{ bilinrand(SinOsc.ar(0.1)) * 0.1 }.play
|
|
{ sum3rand(SinOsc.ar(0.1)) * 0.1 }.play
|
|
{ coin(SinOsc.ar(0.1)) * 0.1 }.play
|
|
::
|
|
|
|
|
|
|
|
]
|
|
@section{subsection}
|
|
UGens that generate random numbers once, or on trigger:
|
|
|
|
@section{definitionlist}
|
|
|
|
## link::Classes/Rand:: || uniform distribution of float between (lo, hi), as for numbers.
|
|
## link::Classes/IRand:: || uniform distribution of integer numbers.
|
|
## link::Classes/TRand:: || uniform distribution of float numbers, triggered
|
|
## link::Classes/TIRand:: || uniform distribution of integer numbers, triggered
|
|
## link::Classes/LinRand:: || skewed distribution of float numbers, triggered
|
|
## link::Classes/NRand:: || sum of n uniform distributions, approximates gaussian distr. with higher n.
|
|
## link::Classes/ExpRand:: || exponential distribution
|
|
## link::Classes/TExpRand:: || exponential distribution, triggered
|
|
## link::Classes/CoinGate:: || statistical gate for a trigger
|
|
## link::Classes/TWindex:: || triggered weighted choice between a list.
|
|
::
|
|
|
|
@section{subsection}
|
|
Seeding
|
|
Like using randSeed to set the random generatorsfor each thread in sclang,
|
|
you can choose which of several random generators on the server to use,
|
|
and you can reset (seed) these random generators:
|
|
@section{list}
|
|
|
|
## link::Classes/RandID::
|
|
## link::Classes/RandSeed::
|
|
::
|
|
|
|
@section{subsection}
|
|
UGens that generate random numbers on demand
|
|
("Demand UGens")
|
|
@section{list}
|
|
|
|
## link::Classes/Dwhite::
|
|
## link::Classes/Dbrown::
|
|
## link::Classes/Diwhite::
|
|
## link::Classes/Dibrown::
|
|
## link::Classes/Drand::
|
|
## link::Classes/Dxrand::
|
|
::
|
|
|
|
see random patterns with analogous names
|
|
|
|
@section{section}
|
|
Random Patterns
|
|
@section{definitionlist}
|
|
|
|
## link::Classes/Prand:: || choose randomly one from a list ( list, numRepeats)
|
|
## link::Classes/Pxrand:: || choose one element from a list, no repeat of previous choice
|
|
## link::Classes/Pwhite:: || within range [<hi>, <lo>], choose a random value.
|
|
## link::Classes/Pbrown:: || within range [<hi>, <lo>], do a random walk with a maximum <step> to the next value.
|
|
## link::Classes/Pgbrown:: || geometric brownian motion
|
|
|
|
## link::Classes/Plprand::
|
|
## link::Classes/Phprand::
|
|
## link::Classes/Pmeanrand::
|
|
## link::Classes/Pbeta::
|
|
## link::Classes/Pcauchy::
|
|
## link::Classes/Pgauss::
|
|
## link::Classes/Ppoisson::
|
|
## link::Classes/Pexprand::
|
|
|
|
## link::Classes/Pwrand:: || choose from a list, probabilities by weights
|
|
|
|
@racketblock[
|
|
Pwrand([ 1, 2, 3 ], [0.1, 0.3, 0.6], 20);
|
|
::
|
|
|
|
## link::Classes/Pshuf:: || scramble the list, then repeat that order <repeats> times.
|
|
|
|
## link::Classes/Pwalk:: || ]
|
|
|
|
@racketblock[Pwalk( (0 .. 10), Prand([ -2,-1, 1, 2], inf));:: random walk.
|
|
|
|
## link::Classes/Pfsm:: || random finite state machine pattern, see its help file. see also MarkovSet in MathLib quark
|
|
|
|
## link::Classes/Pseed:: || sets the random seed for that stream.
|
|
::
|
|
|
|
some basic examples
|
|
]
|
|
|
|
@racketblock[
|
|
(
|
|
Pbind(\note, Prand([ 0, 2, 4 ], inf),
|
|
\dur, 0.2
|
|
).play;
|
|
)
|
|
|
|
(
|
|
Pbind(
|
|
\note, Pxrand([ 0, 2, 4 ], inf),
|
|
\dur, 0.2
|
|
).play;
|
|
)
|
|
|
|
(
|
|
Pbind(
|
|
\note, Pwrand([ 0, 2, 4 ], [0.1, 0.3, 0.6], inf),
|
|
\dur, 0.2
|
|
).play;
|
|
)
|
|
|
|
(
|
|
Pbind(
|
|
\midinote, Pwhite(48, 72, inf),
|
|
\dur, 0.2
|
|
).play;
|
|
)
|
|
|
|
(
|
|
Pbind(
|
|
\midinote, Pbrown(48, 72, 5, inf),
|
|
\dur, 0.2
|
|
).play;
|
|
)
|
|
|
|
(
|
|
Pbind(
|
|
\midinote, Pgbrown(48, 72, 0.5, inf).round,
|
|
\dur, 0.2
|
|
).play;
|
|
)
|
|
::
|
|
|
|
]
|
|
|
|
|