File: ProbabilityDistributions.sc

package info (click to toggle)
supercollider-sc3-plugins 3.7.1~repack-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 14,332 kB
  • ctags: 11,704
  • sloc: cpp: 140,180; lisp: 14,746; ansic: 2,133; xml: 86; makefile: 82; haskell: 21; sh: 8
file content (221 lines) | stat: -rw-r--r-- 5,189 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
	Probability RNGs by Lance Putnam (lance@uwalumni.com)

	These classes were ported from BASIC from the book
	Automated Music Composition by Phil Winsor.

	The number receiving the PDF message is by default the mean of the
	distribution and is referred to as 'this'.
*/

+SimpleNumber {

	/* Eularian Beta Distribution
		Smaller prob values produce higher probabilities near respective
		boundaries.  The mean is 'this'/('this'+'val2'). Be careful when
		using prob values > 5 as this can use a lot of CPU.

		Special cases:
		prob1<1, prob2<1
			The probabilities are greatest near 'this' and 'val2'.
		prob1=prob2=1
			This is a uniform distribution.
		prob1>1, prob2>1
			This a bounded Gaussian-type distribution.  The mean is the
			midpoint of the range if prob1=prob2.  If prob1 != prob2,
			the mean will be skewed to the lower probabilities respective
			bound.
		prob1=1, prob2=2
			This is a linear distribution.

		val2: values will be in the range ['this', 'val2']
		prob1: determines the probability of values near 'this'
		prob2: determines the probability of values near 'val2'
	*/
	betarand { arg val2=1, prob1=1, prob2=1;
		var invProb1, invProb2, temp, sum;

		invProb1 = 1/prob1;
		invProb2 = 1/prob2;
		sum = 2;

		while({
			sum > 1;
		},{
			temp = 1.0.rand ** invProb1;
			sum = temp + (1.0.rand ** invProb2);
		});

		^( ((temp/sum) * (val2-this)) + this )
	}

	/* Cauchy Distribution
		A symmetric distribution centered around mean.  It is unbounded
		above and below the mean similar to the Gaussian dist. but with
		a higher occurance of remote values.

		spread: determines horizontal dispersion of values along curve
	*/
	cauchy { arg spread=1.0;
		var randNum;

		randNum = 0.5;

		while({
			randNum == 0.5; // to avoid discontinuity at tan(pi/2)
		},{
			randNum = 1.0.rand;
		});

		^( (spread * tan(randNum * pi)) + this )
	}

	/* Gaussian Distribution (aka Normal Distribution)
		Generates a bell-shaped curve centered around mean.  Good for
		simulating life-like behavior and mutations.

		dev: determines the spread of values above and below mean
	*/

	// fast Box-Muller algorithm
	gaussian { arg dev=1;
		^(((-2*log(1.0.rand)).sqrt * sin(2pi.rand)) * dev) + this
	}

	/* Knuth's Box-Muller algorithm (not as fast as above)
	gaussian2 { arg dev=1;
		var result, r, theta, x, y;

		//if(valBM.notNil, {
		//	result = valBM;
		//	valBM = nil;
		//	^((result * dev) + this)
		//},{
			result = 2;
			while({
				result >= 1;
			},{
				x = rrand(-1.0,1);
				y = rrand(-1.0,1);
				result = (x*x) + (y*y);
			});
			result = ((-2 * log(result))/result).sqrt;
			//valBM = result * x;
			y = result * y;
			^((y * dev) + this)
		//});
	}
	*/

	/* Linear Distribution
		This is similar to exprand, but with a looser distribution.
		Values closer to 'this' are more likely to occur.

		val2: Produces values in range ['this', 'val2'].
	*/
	linrrand { arg val2=1.0;
		var randNum, result;

		randNum = 1.0.rand;
		result = 1.0.rand;

		if( randNum < result, { result = randNum })

		^(result*(val2-this) + this)
	}

	logistic { arg spread=1;
		var u;
		u = 1.0.rand;
		^( (log(u/(1-u)))*spread + this )
	}

	pareto { arg shape=1;
		^( (1.0.rand ** (-1/shape))*this )
	}

	/* Poisson Distribution
		This function models the occurance rate of rare events.
		This is a discrete distribution that returns positive integer values.
		The distribution of values is unbounded at the upper end.  The mean
		and variance of the function are 'this'.
	*/
	poisson {
		var count, someNum, temp;

		count = 0;
		someNum = 1.0.rand;
		temp = exp(this.neg);

		while({
			someNum > temp;
		},{
			count = count + 1;
			someNum = someNum * 1.0.rand;
		});

		^count
	}

	/* Weibull Distribution
		This is a complex, yet powerful, distribution relying on 3 parameters.
		These are known as the location, spread, and shape parameters.
		The 'location' and 'spread' params are used interchangeably to set the
		mean.  The 'shape' param alters the curve of the distribution.

		Effects of 'shape'

		0 < 'shape' <= 1
			-occurance of values near 'location' increases as 'shape'->0.

		'shape' = 1
			-same as exponential distribution

		this: location, or offset, parameter
		spread: distribution range scaling factor
		shape: curve shaping parameter
	*/
	weibull { arg spread, shape=1;
		var randNum = 1.0;

		// this will avoid a div by 0
		while({
			randNum == 1.0
		},{
			randNum = 1.0.rand;
		});

		^( (spread* (log(randNum).neg ** (1.0/shape))) + this )
	}
}

+ SequenceableCollection {

	// in place gaussian operation on array
	gaussian { arg dev=1;
		var result, r, theta, pairs, inc;

		pairs = this.size.div(2);
		inc = 0;

		pairs.do({
			r = ((-2*log(1.0.rand)).sqrt) * dev;
			theta = 2pi.rand;
			this[inc] = this[inc] + (r * cos(theta));
			inc = inc + 1;
			this[inc] = this[inc] + (r * sin(theta));
			inc = inc + 1;
		});

		if(inc < this.size, {
			this[inc] = this[inc].gaussian(dev);
		});

		^this
	}

	cauchy { arg spread=1; ^this.performBinaryOp('cauchy', spread) }
	logistic { arg spread=1; ^this.performBinaryOp('logistic', spread) }
	pareto { arg shape=1; ^this.performBinaryOp('pareto', shape) }
	poisson { ^this.performUnaryOp('poisson') }
}