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 hashtables hashtables.private hints io.backend io.binary
6 kernel locals math math.bitwise math.constants math.functions
7 math.order math.ranges namespaces sequences sequences.private
8 sets summary system typed vocabs ;
11 SYMBOL: system-random-generator
12 SYMBOL: secure-random-generator
13 SYMBOL: random-generator
15 GENERIC# seed-random 1 ( tuple seed -- tuple' )
16 GENERIC: random-32* ( tuple -- r )
17 GENERIC: random-bytes* ( n tuple -- byte-array )
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 ]
24 [ 2drop ] [ random-32* int <ref> swap head append! ] if
25 ] bi-curry bi* B{ } like ;
27 HINTS: M\ object random-bytes* { fixnum object } ;
29 M: object random-32* ( tuple -- r ) 4 swap random-bytes* be> ;
31 ERROR: no-random-number-generator ;
33 M: no-random-number-generator summary
34 drop "Random number generator is not defined." ;
36 M: f random-bytes* ( n obj -- * ) no-random-number-generator ;
38 M: f random-32* ( obj -- * ) no-random-number-generator ;
40 : random-32 ( -- n ) random-generator get random-32* ;
42 TYPED: random-bytes ( n: fixnum -- byte-array: byte-array )
43 random-generator get random-bytes* ; inline
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*
52 : (random-integer) ( n obj -- n' )
53 [ dup next-power-of-2 log2 ] dip ((random-integer))
56 : random-integer ( n -- n' )
57 random-generator get (random-integer) ;
61 : random-bits ( numbits -- r ) 2^ random-integer ;
63 : random-bits* ( numbits -- n )
64 1 - [ random-bits ] keep set-bit ;
66 GENERIC: random ( obj -- elt )
68 M: integer random [ f ] [ random-integer ] if-zero ;
72 [ length random-integer ] keep nth
75 M: assoc random >alist random ;
78 dup assoc-size [ drop f ] [
79 [ 0 ] [ array>> ] [ random ] tri* 1 + [
80 [ 2dup array-nth tombstone? [ 2 + ] 2dip ] loop
82 [ array-nth ] [ [ 1 + ] dip array-nth ] 2bi 2array
85 : randomize-n-last ( seq n -- seq )
86 [ dup length dup ] dip - 1 max '[ dup _ > ]
87 [ [ random ] [ 1 - ] bi [ pick exchange-unsafe ] keep ]
90 : randomize ( seq -- randomized )
91 dup length randomize-n-last ;
93 ERROR: too-many-samples seq n ;
95 : sample ( seq n -- seq' )
96 2dup [ length ] dip < [ too-many-samples ] when
97 [ [ length iota >array ] dip [ randomize-n-last ] keep tail-slice* ]
100 : delete-random ( seq -- elt )
101 [ length random-integer ] keep [ nth ] 2keep remove-nth! drop ;
103 : with-random ( tuple quot -- )
104 random-generator swap with-variable ; inline
106 : with-system-random ( quot -- )
107 system-random-generator get swap with-random ; inline
109 : with-secure-random ( quot -- )
110 secure-random-generator get swap with-random ; inline
114 : (uniform-random-float) ( min max obj -- n )
115 [ 4 4 ] dip [ random-bytes* uint deref >float ] curry bi@
117 [ over - 2.0 -64 ^ * ] dip
122 : uniform-random-float ( min max -- n )
123 random-generator get (uniform-random-float) ; inline
125 : random-unit ( -- n )
126 0.0 1.0 uniform-random-float ; inline
128 : random-units ( length -- sequence )
129 random-generator get '[ 0.0 1.0 _ (uniform-random-float) ] replicate ;
131 : random-integers ( length n -- sequence )
132 random-generator get '[ _ _ (random-integer) ] replicate ;
134 : (cos-random-float) ( -- n )
135 0. 2pi uniform-random-float cos ;
137 : (log-sqrt-random-float) ( -- n )
138 random-unit log -2. * sqrt ;
140 : normal-random-float ( mean sigma -- n )
141 (cos-random-float) (log-sqrt-random-float) * * + ;
143 : lognormal-random-float ( mean sigma -- n )
144 normal-random-float e^ ;
146 : exponential-random-float ( lambda -- n )
147 random-unit log neg swap / ;
149 : weibull-random-float ( alpha beta -- n )
151 [ random-unit log neg ] dip
155 : pareto-random-float ( k alpha -- n )
156 [ random-unit ] dip recip ^ /f ;
158 :: (gamma-random-float>1) ( alpha beta -- n )
159 ! Uses R.C.H. Cheng, "The generation of Gamma
160 ! variables with non-integral shape parameters",
161 ! Applied Statistics, (1977), 26, No. 1, p71-74
162 2. alpha * 1 - sqrt :> ainv
163 alpha 4. log - :> bbb
166 0 :> r! 0 :> z! 0 :> result! ! initialize locals
169 [ 1. 4.5 log + + z 4.5 * - 0 >= ]
176 u1 1. u1 - / log ainv / :> v
184 : (gamma-random-float=1) ( alpha beta -- n )
185 nip random-unit log neg * ;
187 :: (gamma-random-float<1) ( alpha beta -- n )
188 ! Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
191 0 :> x! 0 :> p! ! initialize locals
194 random-unit x alpha 1 - ^ >
196 random-unit x neg e^ >
203 b p - alpha / log neg
205 ] do while x beta * ;
207 : gamma-random-float ( alpha beta -- n )
209 { [ over 1 > ] [ (gamma-random-float>1) ] }
210 { [ over 1 = ] [ (gamma-random-float=1) ] }
211 [ (gamma-random-float<1) ]
214 : beta-random-float ( alpha beta -- n )
215 [ 1. gamma-random-float ] dip over zero?
216 [ 2drop 0 ] [ 1. gamma-random-float dupd + / ] if ;
218 :: von-mises-random-float ( mu kappa -- n )
219 ! Based upon an algorithm published in: Fisher, N.I.,
220 ! "Statistical Analysis of Circular Data", Cambridge
221 ! University Press, 1993.
225 4. kappa sq * 1. + sqrt 1. + :> a
226 a 2. a * sqrt - 2. kappa * / :> b
227 b sq 1. + 2. b * / :> r
229 0 :> c! 0 :> _f! ! initialize locals
232 [ 2. c - c * < ] [ 1. c - e^ c * <= ]
235 random-unit pi * cos :> z
236 r z * 1. + r z + / _f!
240 mu 2pi mod _f cos random-unit 0.5 > [ + ] [ - ] if
243 :: (triangular-random-float) ( low high mode -- n )
244 mode low - high low - / :> c!
247 u c > [ 1. u - u! 1. c - c! swap ] when
248 [ - u c * sqrt * ] keep + ;
250 : triangular-random-float ( low high -- n )
251 2dup + 2 /f (triangular-random-float) ;
253 : laplace-random-float ( mean scale -- n )
254 random-unit dup 0.5 <
255 [ 2 * log ] [ 1 swap - 2 * log neg ] if * + ;
257 : cauchy-random-float ( median scale -- n )
258 random-unit 0.5 - pi * tan * + ;
260 : chi-square-random-float ( dof -- n )
261 [ 0.5 ] dip 2 * gamma-random-float ;
263 : student-t-random-float ( dof -- n )
264 [ 0 1 normal-random-float ] dip
265 [ chi-square-random-float ] [ / ] bi sqrt / ;
267 : inv-gamma-random-float ( shape scale -- n )
268 recip gamma-random-float recip ;
270 : rayleigh-random-float ( mode -- n )
271 random-unit log -2 * sqrt * ;
273 : gumbel-random-float ( loc scale -- n )
274 random-unit log neg log * - ;
276 : logistic-random-float ( loc scale -- n )
277 random-unit dup 1 swap - / log * + ;
279 : power-random-float ( alpha -- n )
280 [ random-unit log e^ 1 swap - ] dip recip ^ ;
283 { [ os windows? ] [ "random.windows" require ] }
284 { [ os unix? ] [ "random.unix" require ] }
287 "random.mersenne-twister" require