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
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 -- n required-bits )
48 [ random-32 32 ] dip 32 - [ dup 0 > ] [
49 [ 32 shift random-32 + ] [ 32 + ] [ 32 - ] tri*
52 : random-integer ( n -- n' )
53 dup next-power-of-2 log2 (random-integer)
58 : random-bits ( numbits -- r ) 2^ random-integer ;
60 : random-bits* ( numbits -- n )
61 1 - [ random-bits ] keep set-bit ;
63 GENERIC: random ( obj -- elt )
65 M: integer random [ f ] [ random-integer ] if-zero ;
69 [ length random-integer ] keep nth
72 : randomize-n-last ( seq n -- seq )
73 [ dup length dup ] dip - 1 max '[ dup _ > ]
74 [ [ random ] [ 1 - ] bi [ pick exchange-unsafe ] keep ]
77 : randomize ( seq -- randomized )
78 dup length randomize-n-last ;
80 ERROR: too-many-samples seq n ;
82 : sample ( seq n -- seq' )
83 2dup [ length ] dip < [ too-many-samples ] when
84 [ [ length iota >array ] dip [ randomize-n-last ] keep tail-slice* ]
87 : delete-random ( seq -- elt )
88 [ length random-integer ] keep [ nth ] 2keep remove-nth! drop ;
90 : with-random ( tuple quot -- )
91 random-generator swap with-variable ; inline
93 : with-system-random ( quot -- )
94 system-random-generator get swap with-random ; inline
96 : with-secure-random ( quot -- )
97 secure-random-generator get swap with-random ; inline
99 : uniform-random-float ( min max -- n )
100 4 random-bytes uint deref >float
101 4 random-bytes uint deref >float
103 [ over - 2.0 -64 ^ * ] dip
106 : random-unit ( -- n )
107 0.0 1.0 uniform-random-float ; inline
109 : (cos-random-float) ( -- n )
110 0. 2pi uniform-random-float cos ;
112 : (log-sqrt-random-float) ( -- n )
113 random-unit log -2. * sqrt ;
115 : normal-random-float ( mean sigma -- n )
116 (cos-random-float) (log-sqrt-random-float) * * + ;
118 : lognormal-random-float ( mean sigma -- n )
119 normal-random-float exp ;
121 : exponential-random-float ( lambda -- n )
122 random-unit log neg swap / ;
124 : weibull-random-float ( alpha beta -- n )
126 [ random-unit log neg ] dip
130 : pareto-random-float ( alpha -- n )
131 [ random-unit ] dip [ 1. swap / ] bi@ ^ ;
133 :: (gamma-random-float>1) ( alpha beta -- n )
134 ! Uses R.C.H. Cheng, "The generation of Gamma
135 ! variables with non-integral shape parameters",
136 ! Applied Statistics, (1977), 26, No. 1, p71-74
137 2. alpha * 1 - sqrt :> ainv
138 alpha 4. log - :> bbb
141 0 :> r! 0 :> z! 0 :> result! ! initialize locals
144 [ 1. 4.5 log + + z 4.5 * - 0 >= ]
151 u1 1. u1 - / log ainv / :> v
159 : (gamma-random-float=1) ( alpha beta -- n )
160 nip random-unit log neg * ;
162 :: (gamma-random-float<1) ( alpha beta -- n )
163 ! Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
166 0 :> x! 0 :> p! ! initialize locals
169 random-unit x alpha 1 - ^ >
171 random-unit x neg exp >
178 b p - alpha / log neg
180 ] do while x beta * ;
182 : gamma-random-float ( alpha beta -- n )
184 { [ over 1 > ] [ (gamma-random-float>1) ] }
185 { [ over 1 = ] [ (gamma-random-float=1) ] }
186 [ (gamma-random-float<1) ]
189 : beta-random-float ( alpha beta -- n )
190 [ 1. gamma-random-float ] dip over zero?
191 [ 2drop 0 ] [ 1. gamma-random-float dupd + / ] if ;
194 { [ os windows? ] [ "random.windows" require ] }
195 { [ os unix? ] [ "random.unix" require ] }
198 "random.mersenne-twister" require