Stochastic
Methods for procedurally generating number sequences based on various types of randomness, such as white noise (evenly distributed), rolling dice, flipping a coin and more. Also includes Markov Chain.
Include
const Rand = require('total-serialism').Stochastic;
Methods
- seed
- getSeed
- random / randomFloat
- drunk / drunkFloat
- coin
- dice
- urn
- twelveTone
- shuffle
- choose
- pick
- clave
- expand
- MarkovChain
- DeepMarkovChain
seed
Set the seed for the Random Number Genrators. A value of 0
sets to unpredictable seeding. The seed can only be set once for every import of the library. However, seed can be reset between function calls.
// set the random number generator seed
Rand.seed(19374);
getSeed
Get the seed from the Random Number Generator. Returns the value that was latest set with seed()
.
// get the random number generator seed
Rand.getSeed();
// => 19374
random randomFloat
Generate a list of random integers or floating points between a specified range (excluding high value).
Alias: randomF
arguments
- {Int+} -> number of values to output
- {Number} -> minimum range (optional, default=0)
- {Number} -> maximum range (optional, default=2)
// generate an array of random integers in range
Rand.random(5, 0, 12);
//=> [ 3, 3, 7, 1, 0 ]
// generate an array of random floats in range -1 to 1
Rand.randomFloat(3, -1, 1);
//=> [ 0.6291111850577886, 0.15153786227276944, 0.32814801081039646 ]
drunk drunkFloat
Generate a list of random values (int/float) but the next random value is within a limited step-range of the previous value generating a random “drunk” walk, also referred to as brownian motion. Inspired by the [drunk]
-object in MaxMSP
Alias: drunkF
arguments
- {Int} -> number of values to output
- {Number} -> step range for next random value
- {Number} -> minimum range (optional, default=null)
- {Number} -> maximum range (optional, default=null)
- {Number} -> starting point (optional, default=(lo+hi)/2)
- {Bool} -> fold between lo and hi range (optional, default=true)
Rand.drunkFloat(5);
//=> [ 0.493, 0.459, 0.846, 0.963, 0.400 ]
// 0.88 ┼╮╭╮
// 0.76 ┤╰╯│
// 0.63 ┤ │
// 0.51 ┤ ╰╮
// 0.39 ┤ │
// 0.26 ┤ ╰
Rand.drunk(10, 5, 0, 24);
//=> [ 13, 10, 14, 13, 14, 13, 15, 10, 8, 4 ]
// 22.00 ┼ ╭╮
// 17.80 ┼─╮╭─╮ ││
// 13.60 ┤ ││ ╰╮╭╯│
// 9.40 ┤ ││ ╰╯ │
// 5.20 ┤ ╰╯ │
// 1.00 ┤ ╰
Rand.drunk(10, 4, 0, 12, 6, false);
//=> [ 2, -2, 2, 1, -3, -1, -2, -1, 3, 6 ]
// 2.00 ┤╭╮
// -0.20 ┤│╰╮ ╭
// -2.40 ┼╯ ╰╮ │
// -4.60 ┤ │╭╮ ╭╯
// -6.80 ┼ ╰╯│╭╯
// -9.00 ┤ ╰╯
coin
Generate a list of random integer values 0 or 1 like a coin toss, heads/tails. Or
arguments
- {Int+} -> number of coin tosses to output as list
// generate an array of coin tosses
Rand.coin(10);
//=> [ 0, 1, 0, 1, 0, 1, 0, 0, 1, 0 ]
dice
Generate a list of dice rolls, resulting in random integer values from 1 to 6. Optionally use a second argument to set the amount of sides for the die.
arguments
- {Int+} -> number of dice rolls to output as list
- {Int+} -> set the sides of the die (optional, default=6)
// generate an array of dice rolls
Rand.dice(4);
//=> [ 4, 4, 2, 3 ]
// optionally set the amount of sides for the die
Rand.dice(4, 8);
//=> [ 8, 3, 7, 1 ]
urn
Generate a list of unique random integer values between a certain specified range (excluding high val). An ‘urn’ is filled with values and when one is picked it is removed from the urn. If the outputlist is longer then the range, the urn refills when empty. On refill it is made sure no repeating value can be picked. Inspired by the [urn]
-object in MaxMSP.
arguments
- {Int+} -> number of values to output
- {Number} -> maximum range (optional, default=12)
- {Number} -> minimum range (optional, defautl=0)
// generate an array with random values picked from an urn
// with default range 0 to 12 (exclusive)
Rand.urn(5);
//=> [ 3, 6, 2, 8, 7 ]
// set the range with a second argument to 0-7 (exclusive)
// when more values then range are requested the urn
// refills and reshuffles
Rand.urn(10, 7);
//=> [ 6, 4, 3, 2, 0, 5, 1, 4, 2, 1 ]
// A third argument sets a lower range replacing the default 0
Rand.urn(12, -3, 3);
//=> [ -3, 1, -1, 2, 0, -2, 2, -2, 0, -1, -3, 1 ]
twelveTone
Generate a list of 12 semitones then shuffle the list based on the random seed.
arguments
- {None}
// generate a twelve-tone series, influenced by the random seed
// basically the same as: Mod.shuffle(Gen.spread(12));
Rand.twelveTone();
//=> [ 11, 0, 8, 2, 4, 9, 1, 6, 3, 5, 7, 10 ]
shuffle
Shuffle an array, influenced by the random seed. Based on the Fisher-Yates shuffle algorithm by Ronald Fisher and Frank Yates in 1938. The algorithm has run time complexity of O(n)
Alias: scramble()
arguments
- {Array} -> Array to shuffle
// shuffle the items in an array, influenced by the random seed
Rand.shuffle([0, 5, 7, 12]);
//=> [ 7, 5, 0, 12 ]
choose
Choose random items from an array provided with uniform probability distribution. The default array is an array of 0 and 1.
arguments
- {Int+} -> length of array output
- {Array} -> items to choose from (optional, default=[0 1])
// Choose random items from an array provided, uniform distribution
Rand.choose(5, [0, 1, 2, 3, 5, 8, 13]);
//=> [ 3, 0, 13, 3, 2 ]
// Array can have any datatype
Rand.choose(5, ['c', 'e', 'g']);
//=> [ 'c', 'c', 'g', 'e', 'g' ]
pick
Pick random items from an array provided. An “urn” is filled with values and when one is picked it is removed from the urn. If the outputlist is longer then the range, the urn refills when empty. On refill it is made sure no repeating value can be picked.
arguments
- {Int+} -> length of array output
- {Array} -> items to choose from (optional, default=[0 1])
// Pick random items from an array similar to urn
// no repeating values untill urn is empty
Rand.pick(5, [0, 1, 2, 3, 5, 8, 13]);
//=> [ 2, 5, 8, 1, 3 ]
// Array can have any datatype
Rand.pick(5, ['c', 'e', ['g', 'd']]);
//=> [ 'e', [ 'g', 'd' ], 'c', [ 'g', 'd' ], 'e' ]
clave
Generate random clave patterns. The output is a binary list that represents a rhythm, where 1’s represent onsets and 0’s rests. First argument sets the list length output, second argument sets the maximum gap between onsets, third argument the minimum gap.
arguments
- {Int+} -> output length of rhythm (default=8)
- {Int+} -> maximum gap between onsets (default=3)
- {Int+} -> minimum gap between onsets (default=2)
Rand.clave();
//=> [ 1, 0, 1, 0, 0, 1, 0, 1 ]
//=> █ █ █ █
Rand.clave(8);
//=> [ 1, 0, 0, 1, 0, 1, 0, 1 ]
//=> █ █ █ █
Rand.clave(16, 4);
//=> [ 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1 ]
//=> █ █ █ █ █ █
Rand.clave(16, 3, 1);
//=> [ 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1 ]
//=> █ █ ██ █ █ █
expand
Expand an array based upon the pattern within an array. The pattern is derived from the rate in change between values by calculating the differences between every consecutive value. The newly generated values are selected randomly from the list of possible changes, but in such a way that every change occurs once in the sequence of total changes before reshuffling and selecting the next one (see the pick
method for explanation). The resulting output starts with the input array.
arguments
- {Array} -> Array to expand
- {Int+} -> length of array output (including original array)
Rand.seed(3141);
Rand.expand([0, 9, 7, 3, 5, 0, -1], 30);
//=> 9.00 ┤╭╮ ╭╮
// 6.80 ┤│╰╮ ││
// 4.60 ┤│ │╭╮ ││
// 2.40 ┤│ ╰╯│ │╰─╮ ╭─╮
// 0.20 ┼╯ ╰─╮╭╯ │ │ │╭
// -2.00 ┤ ╰╯ ╰╮ ╭─╮ │ ╰╯
// -4.20 ┼ │ │ │ ╭╮│
// -6.40 ┤ ╰╮ │ │ │╰╯
// -8.60 ┤ │╭╮│ ╰─╮ │
// -10.80 ┤ ╰╯╰╯ │╭╮│
// -13.00 ┤ ╰╯╰╯
Rand.seed(6181);
Rand.expand([0, 9, 7, 3, 5, 0, -1], 30);
//=> 9.00 ┤╭╮
// 6.80 ┤│╰╮
// 4.60 ┤│ │╭╮
// 2.40 ┤│ ╰╯│ ╭╮╭╮
// 0.20 ┼╯ ╰─╮╭╮ │╰╯╰╮ ╭──
// -2.00 ┤ ╰╯│ ╭╮│ ╰╮ │
// -4.20 ┼ ╰╮ │││ ╰╮ ╭╮ │
// -6.40 ┤ │ │╰╯ │╭╮ ││ │
// -8.60 ┤ ╰╮│ ╰╯╰╮│╰╮│
// -10.80 ┤ ╰╯ ││ ╰╯
// -13.00 ┤ ╰╯
MarkovChain
Build a Markov Chain from a set of datapoints and use it to generate new values or an array of values based on the probabilities of the transitions in the provided training dataset. A Markov Chain is a model that describes possible next events based on a current state (first order) and sometimes previous states (2nd, 3rd, … n-order). The Markov Chain is a broadly used method in algorithmic music to generate new material (melodies, rhythms, but even words) based on a set of provided material, but can also be used in linguistics to analyze word or sentence structures.
const Rand = require('total-serialism').Stochastic;
var melody = ['c', 'e', 'f', 'e', 'g', 'f', 'a', 'c'];
// make a MarkovChain instance and optionally train with array
let markov = new Rand.MarkovChain(melody);
// add more to the training
var melody2 = ['g', 'a', 'b', 'g', 'a', 'f', 'd', 'e'];
markov.train(melody2);
// view the transition table (stored as dictionary)
// can also be used to export the table to a file
console.log(markov.table);
// { c: [ 'e' ],
// e: [ 'f', 'g' ],
// f: [ 'e', 'a', 'd' ],
// g: [ 'f', 'a', 'a' ],
// a: [ 'c', 'b', 'f' ],
// b: [ 'g' ],
// d: [ 'e' ] }
// set the state of the model used as initial value
markov.state('c');
// set the seed for the global random number generator
markov.seed(31415);
// same as works with Rand.seed()
// go to the next state based on the models probabilities
markov.next();
// => 'e'
// generate an array of 10 values
markov.chain(10);
// => [ 'f', 'd', 'e', 'g', 'a', 'b', 'g', 'a', 'c', 'e' ]
// clear the model
markov.clear();
// read a model from a json/object structure
markov.read({ c: ['e'], e: ['f', 'g' ]});
DeepMarkovChain
This is an identical approach to the Markov Chain while also offering the possibility of training to create n-order chains. In theory, longer chains preserve the original structure of the model, but won’t generate as diverse outputs.
Alias: DeepMarkov()
const Rand = require('total-serialism').Stochastic;
var pattern = [1, 2, 3, 1, 2, 4, 1, 2, 5, 2, 3, 4];
// make a MarkovChain instance and optionally train with array
// an optional second argument sets the order of the markov (default=2)
let markov = new Rand.DeepMarkov(pattern, 2);
// view the transition table (stored as Map())
// Keys are stored as stringis derived via JSON.stringify()
console.log(markov.table);
// Map(7) {
// '[1,2]' => [ 3, 4, 5 ],
// '[2,3]' => [ 1, 4 ],
// '[3,1]' => [ 2 ],
// '[2,4]' => [ 1 ],
// '[4,1]' => [ 2 ],
// '[2,5]' => [ 2 ],
// '[5,2]' => [ 3 ]
// }
// set the state of the model used as initial value
markov.state([1, 2]);
// set the seed for the global random number generator
markov.seed(31415);
// same as works with Rand.seed()
// go to the next state based on the model probabilities
markov.next();
// => 5
// generate an array of 10 values
markov.chain(10);
// => [ 2, 3, 1, 2, 5, 2, 3, 4, 1, 2 ]
// clear the model
markov.clear();
// TO DO:
// read/write a model from a Map structure
let model = markov.table;
let otherMarkov = new DeepMarkov();
otherMarkov.read(model);
// for storage to file or transfer between DeepMarkov instances
// you can use the build in stringify and parse methods
// these methods utilize JSON.stringify() and .parse()
// with specific replacer and reviver methods
let modelString = markov.stringify();
let fromStringMarkov = new DeepMarkov();
fromStringMarkov.parse(modelString);