1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.data arrays assocs byte-arrays
4 byte-vectors combinators combinators.short-circuit fry
5 hashtables hashtables.private hash-sets hints io.backend
6 io.binary kernel locals math math.bitwise math.constants
7 math.functions math.order math.ranges namespaces sequences
8 sequences.private sets summary system typed vocabs ;
9 QUALIFIED-WITH: alien.c-types c
10 QUALIFIED-WITH: sets sets
13 SYMBOL: system-random-generator
14 SYMBOL: secure-random-generator
15 SYMBOL: random-generator
17 GENERIC# seed-random 1 ( tuple seed -- tuple' )
18 GENERIC: random-32* ( tuple -- r )
19 GENERIC: random-bytes* ( n tuple -- byte-array )
21 M: object random-bytes* ( n tuple -- byte-array )
22 [ [ <byte-vector> ] keep 4 /mod ] dip
23 [ pick '[ _ random-32* c:int <ref> _ push-all ] times ]
26 [ 2drop ] [ random-32* c:int <ref> swap head append! ] if
27 ] bi-curry bi* B{ } like ;
29 HINTS: M\ object random-bytes* { fixnum object } ;
31 M: object random-32* ( tuple -- r )
32 4 swap random-bytes* c:uint deref ;
34 ERROR: no-random-number-generator ;
36 M: no-random-number-generator summary
37 drop "Random number generator is not defined." ;
39 M: f random-bytes* ( n obj -- * ) no-random-number-generator ;
41 M: f random-32* ( obj -- * ) no-random-number-generator ;
43 : random-32 ( -- n ) random-generator get random-32* ;
45 TYPED: random-bytes ( n: fixnum -- byte-array: byte-array )
46 random-generator get random-bytes* ; inline
51 dup 2 <= [ drop 1 ] [ 1 - log2 1 + ] if ; inline
53 :: (random-bits) ( n bits obj -- n' )
54 obj random-32* 32 bits 32 - [ dup 0 > ] [
55 [ 32 shift obj random-32* + ] [ 32 + ] [ 32 - ] tri*
56 ] while drop [ n * ] [ neg shift ] bi* ; inline
58 : ((random-integer)) ( n obj -- n' )
59 [ dup #bits ] dip (random-bits) ; inline
61 GENERIC# (random-integer) 1 ( n obj -- n )
62 M: fixnum (random-integer) ( n obj -- n' ) ((random-integer)) ;
63 M: bignum (random-integer) ( n obj -- n' ) ((random-integer)) ;
65 : random-integer ( n -- n' )
66 random-generator get (random-integer) ;
70 : random-bits ( numbits -- r )
71 [ 2^ ] keep random-generator get (random-bits) ;
73 : random-bits* ( numbits -- n )
74 1 - [ random-bits ] keep set-bit ;
76 GENERIC: random ( obj -- elt )
78 M: integer random [ f ] [ random-integer ] if-zero ;
82 [ length random-integer ] keep nth
85 M: assoc random >alist random ;
88 dup assoc-size [ drop f ] [
89 [ 0 ] [ array>> ] [ random ] tri* 1 + [
90 [ 2dup array-nth tombstone? [ 2 + ] 2dip ] loop
92 [ array-nth ] [ [ 1 + ] dip array-nth ] 2bi 2array
95 M: sets:set random members random ;
97 M: hash-set random table>> random first ;
99 : randomize-n-last ( seq n -- seq )
100 [ dup length dup ] dip - 1 max '[ dup _ > ]
101 random-generator get '[
102 [ _ (random-integer) ] [ 1 - ] bi
103 [ pick exchange-unsafe ] keep
106 : randomize ( seq -- randomized )
107 dup length randomize-n-last ;
109 ERROR: too-many-samples seq n ;
111 : sample ( seq n -- seq' )
112 2dup [ length ] dip < [ too-many-samples ] when
113 [ [ length iota >array ] dip [ randomize-n-last ] keep tail-slice* ]
116 : delete-random ( seq -- elt )
117 [ length random-integer ] keep [ nth ] 2keep remove-nth! drop ;
119 : with-random ( tuple quot -- )
120 random-generator swap with-variable ; inline
122 : with-system-random ( quot -- )
123 system-random-generator get swap with-random ; inline
125 : with-secure-random ( quot -- )
126 secure-random-generator get swap with-random ; inline
130 : (uniform-random-float) ( min max obj -- n )
131 [ random-32* ] keep random-32* [ >float ] bi@
133 [ over - 2.0 -64 ^ * ] dip
138 : uniform-random-float ( min max -- n )
139 random-generator get (uniform-random-float) ; inline
141 M: float random [ f ] [ 0.0 swap uniform-random-float ] if-zero ;
145 : (random-unit) ( obj -- n )
146 [ 0.0 1.0 ] dip (uniform-random-float) ; inline
150 : random-unit ( -- n )
151 random-generator get (random-unit) ; inline
153 : random-units ( length -- sequence )
154 random-generator get '[ _ (random-unit) ] replicate ;
156 : random-integers ( length n -- sequence )
157 random-generator get '[ _ _ (random-integer) ] replicate ;
159 : (cos-random-float) ( -- n )
160 0. 2pi uniform-random-float cos ;
162 : (log-sqrt-random-float) ( -- n )
163 random-unit log -2. * sqrt ;
165 : normal-random-float ( mean sigma -- n )
166 (cos-random-float) (log-sqrt-random-float) * * + ;
168 : lognormal-random-float ( mean sigma -- n )
169 normal-random-float e^ ;
171 : exponential-random-float ( lambda -- n )
172 random-unit log neg swap / ;
174 : weibull-random-float ( alpha beta -- n )
176 [ random-unit log neg ] dip
180 : pareto-random-float ( k alpha -- n )
181 [ random-unit ] dip recip ^ /f ;
183 :: (gamma-random-float>1) ( alpha beta -- n )
184 ! Uses R.C.H. Cheng, "The generation of Gamma
185 ! variables with non-integral shape parameters",
186 ! Applied Statistics, (1977), 26, No. 1, p71-74
187 random-generator get :> rnd
188 2. alpha * 1 - sqrt :> ainv
189 alpha 4. log - :> bbb
192 0 :> r! 0 :> z! 0 :> result! ! initialize locals
195 [ 1. 4.5 log + + z 4.5 * - 0 >= ]
199 rnd (random-unit) :> u1
200 rnd (random-unit) :> u2
202 u1 1. u1 - / log ainv / :> v
210 : (gamma-random-float=1) ( alpha beta -- n )
211 nip random-unit log neg * ;
213 :: (gamma-random-float<1) ( alpha beta -- n )
214 ! Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
215 random-generator get :> rnd
218 0 :> x! 0 :> p! ! initialize locals
221 rnd (random-unit) x alpha 1 - ^ >
223 rnd (random-unit) x neg e^ >
226 rnd (random-unit) b * p!
230 b p - alpha / log neg
232 ] do while x beta * ;
234 : gamma-random-float ( alpha beta -- n )
236 { [ over 1 > ] [ (gamma-random-float>1) ] }
237 { [ over 1 = ] [ (gamma-random-float=1) ] }
238 [ (gamma-random-float<1) ]
241 : beta-random-float ( alpha beta -- n )
242 [ 1. gamma-random-float ] dip over zero?
243 [ 2drop 0 ] [ 1. gamma-random-float dupd + / ] if ;
245 :: von-mises-random-float ( mu kappa -- n )
246 ! Based upon an algorithm published in: Fisher, N.I.,
247 ! "Statistical Analysis of Circular Data", Cambridge
248 ! University Press, 1993.
249 random-generator get :> rnd
251 2pi rnd (random-unit) *
253 4. kappa sq * 1. + sqrt 1. + :> a
254 a 2. a * sqrt - 2. kappa * / :> b
255 b sq 1. + 2. b * / :> r
257 0 :> c! 0 :> _f! ! initialize locals
260 [ 2. c - c * < ] [ 1. c - e^ c * <= ]
263 rnd (random-unit) pi * cos :> z
264 r z * 1. + r z + / _f!
269 rnd (random-unit) 0.5 > [ + ] [ - ] if
272 :: (triangular-random-float) ( low high mode -- n )
273 mode low - high low - / :> c!
276 u c > [ 1. u - u! 1. c - c! swap ] when
277 [ - u c * sqrt * ] keep + ;
279 : triangular-random-float ( low high -- n )
280 2dup + 2 /f (triangular-random-float) ;
282 : laplace-random-float ( mean scale -- n )
283 random-unit dup 0.5 <
284 [ 2 * log ] [ 1 swap - 2 * log neg ] if * + ;
286 : cauchy-random-float ( median scale -- n )
287 random-unit 0.5 - pi * tan * + ;
289 : chi-square-random-float ( dof -- n )
290 [ 0.5 ] dip 2 * gamma-random-float ;
292 : student-t-random-float ( dof -- n )
293 [ 0 1 normal-random-float ] dip
294 [ chi-square-random-float ] [ / ] bi sqrt / ;
296 : inv-gamma-random-float ( shape scale -- n )
297 recip gamma-random-float recip ;
299 : rayleigh-random-float ( mode -- n )
300 random-unit log -2 * sqrt * ;
302 : gumbel-random-float ( loc scale -- n )
303 random-unit log neg log * - ;
305 : logistic-random-float ( loc scale -- n )
306 random-unit dup 1 swap - / log * + ;
308 : power-random-float ( alpha -- n )
309 [ random-unit log e^ 1 swap - ] dip recip ^ ;
312 : poisson-random-float ( mean -- n )
313 [ -1 0 ] dip [ 2dup < ] random-generator get '[
314 [ 1 + ] 2dip [ _ (random-unit) log neg + ] dip
318 { [ os windows? ] [ "random.windows" require ] }
319 { [ os unix? ] [ "random.unix" require ] }
322 "random.mersenne-twister" require