]> gitweb.factorcode.org Git - factor.git/blob - basis/random/random.factor
random: faster random-units and random-integers.
[factor.git] / basis / random / random.factor
1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types alien.data arrays assocs
4 byte-arrays byte-vectors combinators combinators.short-circuit
5 fry io.backend io.binary kernel locals math math.bitwise
6 math.constants math.functions math.order math.ranges namespaces
7 sequences sequences.private sets summary system vocabs hints
8 typed ;
9 IN: random
10
11 SYMBOL: system-random-generator
12 SYMBOL: secure-random-generator
13 SYMBOL: random-generator
14
15 GENERIC# seed-random 1 ( tuple seed -- tuple' )
16 GENERIC: random-32* ( tuple -- r )
17 GENERIC: random-bytes* ( n tuple -- byte-array )
18
19 M: object random-bytes* ( n tuple -- byte-array )
20     [ [ <byte-vector> ] keep 4 /mod ] dip
21     [ pick '[ _ random-32* int <ref> _ push-all ] times ]
22     [
23         over zero?
24         [ 2drop ] [ random-32* int <ref> swap head append! ] if
25     ] bi-curry bi* B{ } like ;
26
27 HINTS: M\ object random-bytes* { fixnum object } ;
28
29 M: object random-32* ( tuple -- r ) 4 swap random-bytes* be> ;
30
31 ERROR: no-random-number-generator ;
32
33 M: no-random-number-generator summary
34     drop "Random number generator is not defined." ;
35
36 M: f random-bytes* ( n obj -- * ) no-random-number-generator ;
37
38 M: f random-32* ( obj -- * ) no-random-number-generator ;
39
40 : random-32 ( -- n ) random-generator get random-32* ;
41
42 TYPED: random-bytes ( n: fixnum -- byte-array: byte-array )
43     random-generator get random-bytes* ; inline
44
45 <PRIVATE
46
47 :: ((random-integer)) ( bits obj -- n required-bits )
48     obj random-32* 32 bits 32 - [ dup 0 > ] [
49         [ 32 shift obj random-32* + ] [ 32 + ] [ 32 - ] tri*
50     ] while drop ;
51
52 : (random-integer) ( n obj -- n' )
53     [ dup next-power-of-2 log2 ] dip ((random-integer))
54     [ * ] [ 2^ /i ] bi* ;
55
56 : random-integer ( n -- n' )
57     random-generator get (random-integer) ;
58
59 PRIVATE>
60
61 : random-bits ( numbits -- r ) 2^ random-integer ;
62
63 : random-bits* ( numbits -- n )
64     1 - [ random-bits ] keep set-bit ;
65
66 GENERIC: random ( obj -- elt )
67
68 M: integer random [ f ] [ random-integer ] if-zero ;
69
70 M: sequence random
71     [ f ] [
72         [ length random-integer ] keep nth
73     ] if-empty ;
74
75 : randomize-n-last ( seq n -- seq )
76     [ dup length dup ] dip - 1 max '[ dup _ > ]
77     [ [ random ] [ 1 - ] bi [ pick exchange-unsafe ] keep ]
78     while drop ;
79
80 : randomize ( seq -- randomized )
81     dup length randomize-n-last ;
82
83 ERROR: too-many-samples seq n ;
84
85 : sample ( seq n -- seq' )
86     2dup [ length ] dip < [ too-many-samples ] when
87     [ [ length iota >array ] dip [ randomize-n-last ] keep tail-slice* ]
88     [ drop ] 2bi nths ;
89
90 : delete-random ( seq -- elt )
91     [ length random-integer ] keep [ nth ] 2keep remove-nth! drop ;
92
93 : with-random ( tuple quot -- )
94     random-generator swap with-variable ; inline
95
96 : with-system-random ( quot -- )
97     system-random-generator get swap with-random ; inline
98
99 : with-secure-random ( quot -- )
100     secure-random-generator get swap with-random ; inline
101
102 <PRIVATE
103
104 : (uniform-random-float) ( min max obj -- n )
105     [ 4 4 ] dip [ random-bytes* uint deref >float ] curry bi@
106     2.0 32 ^ * +
107     [ over - 2.0 -64 ^ * ] dip
108     * + ; inline
109
110 PRIVATE>
111
112 : uniform-random-float ( min max -- n )
113     random-generator get (uniform-random-float) ; inline
114
115 : random-unit ( -- n )
116     0.0 1.0 uniform-random-float ; inline
117
118 : random-units ( length -- sequence )
119     random-generator get '[ 0.0 1.0 _ (uniform-random-float) ] replicate ;
120
121 : random-integers ( length n -- sequence )
122     random-generator get '[ _ _ (random-integer) ] replicate ;
123
124 : (cos-random-float) ( -- n )
125     0. 2pi uniform-random-float cos ;
126
127 : (log-sqrt-random-float) ( -- n )
128     random-unit log -2. * sqrt ;
129
130 : normal-random-float ( mean sigma -- n )
131     (cos-random-float) (log-sqrt-random-float) * * + ;
132
133 : lognormal-random-float ( mean sigma -- n )
134     normal-random-float e^ ;
135
136 : exponential-random-float ( lambda -- n )
137     random-unit log neg swap / ;
138
139 : weibull-random-float ( alpha beta -- n )
140     [
141         [ random-unit log neg ] dip
142         1. swap / ^
143     ] dip * ;
144
145 : pareto-random-float ( k alpha -- n )
146     [ random-unit ] dip recip ^ /f ;
147
148 :: (gamma-random-float>1) ( alpha beta -- n )
149     ! Uses R.C.H. Cheng, "The generation of Gamma
150     ! variables with non-integral shape parameters",
151     ! Applied Statistics, (1977), 26, No. 1, p71-74
152     2. alpha * 1 - sqrt :> ainv
153     alpha 4. log -      :> bbb
154     alpha ainv +        :> ccc
155
156     0 :> r! 0 :> z! 0 :> result! ! initialize locals
157     [
158         r {
159             [ 1. 4.5 log + + z 4.5 * - 0 >= ]
160             [ z log >= ]
161         } 1|| not
162     ] [
163         random-unit :> u1
164         random-unit :> u2
165
166         u1 1. u1 - / log ainv / :> v
167         alpha v e^ *           :> x
168         u1 sq u2 *              z!
169         bbb ccc v * + x -       r!
170
171         x beta *                result!
172     ] do while result ;
173
174 : (gamma-random-float=1) ( alpha beta -- n )
175     nip random-unit log neg * ;
176
177 :: (gamma-random-float<1) ( alpha beta -- n )
178     ! Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
179     alpha e + e / :> b
180
181     0 :> x! 0 :> p! ! initialize locals
182     [
183         p 1.0 > [
184             random-unit x alpha 1 - ^ >
185         ] [
186             random-unit x neg e^ >
187         ] if
188     ] [
189         random-unit b * p!
190         p 1.0 <= [
191             p 1. alpha / ^
192         ] [
193             b p - alpha / log neg
194         ] if x!
195     ] do while x beta * ;
196
197 : gamma-random-float ( alpha beta -- n )
198     {
199         { [ over 1 > ] [ (gamma-random-float>1) ] }
200         { [ over 1 = ] [ (gamma-random-float=1) ] }
201         [ (gamma-random-float<1) ]
202     } cond ;
203
204 : beta-random-float ( alpha beta -- n )
205     [ 1. gamma-random-float ] dip over zero?
206     [ 2drop 0 ] [ 1. gamma-random-float dupd + / ] if ;
207
208 :: von-mises-random-float ( mu kappa -- n )
209     ! Based upon an algorithm published in: Fisher, N.I.,
210     ! "Statistical Analysis of Circular Data", Cambridge
211     ! University Press, 1993.
212     kappa 1e-6 <= [
213         2pi random-unit *
214     ] [
215         4. kappa sq * 1. + sqrt 1. + :> a
216         a 2. a * sqrt - 2. kappa * / :> b
217         b sq 1. + 2. b * /           :> r
218
219         0 :> c! 0 :> _f! ! initialize locals
220         [
221             random-unit {
222                 [ 2. c - c * < ] [ 1. c - e^ c * <= ]
223             } 1|| not
224         ] [
225             random-unit pi * cos :> z
226             r z * 1. + r z + /   _f!
227             r _f - kappa *       c!
228         ] do while
229
230         mu 2pi mod _f cos random-unit 0.5 > [ + ] [ - ] if
231     ] if ;
232
233 :: (triangular-random-float) ( low high mode -- n )
234     mode low - high low - / :> c!
235     random-unit :> u!
236     high low
237     u c > [ 1. u - u! 1. c - c! swap ] when
238     [ - u c * sqrt * ] keep + ;
239
240 : triangular-random-float ( low high -- n )
241     2dup + 2 /f (triangular-random-float) ;
242
243 : laplace-random-float ( mean scale -- n )
244     random-unit dup 0.5 <
245     [ 2 * log ] [ 1 swap - 2 * log neg ] if * + ;
246
247 : cauchy-random-float ( median scale -- n )
248     random-unit 0.5 - pi * tan * + ;
249
250 : chi-square-random-float ( dof -- n )
251     [ 0.5 ] dip 2 * gamma-random-float ;
252
253 : student-t-random-float ( dof -- n )
254     [ 0 1 normal-random-float ] dip
255     [ chi-square-random-float ] [ / ] bi sqrt / ;
256
257 : inv-gamma-random-float ( shape scale -- n )
258     recip gamma-random-float recip ;
259
260 : rayleigh-random-float ( mode -- n )
261     random-unit log -2 * sqrt * ;
262
263 : gumbel-random-float ( loc scale -- n )
264     random-unit log neg log * - ;
265
266 : logistic-random-float ( loc scale -- n )
267     random-unit dup 1 swap - / log * + ;
268
269 : power-random-float ( alpha -- n )
270     [ random-unit log e^ 1 swap - ] dip recip ^ ;
271
272 {
273     { [ os windows? ] [ "random.windows" require ] }
274     { [ os unix? ] [ "random.unix" require ] }
275 } cond
276
277 "random.mersenne-twister" require