! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien.c-types alien.data arrays assocs
-byte-arrays byte-vectors combinators combinators.short-circuit
-fry io.backend io.binary kernel locals math math.bitwise
-math.constants math.functions math.order math.ranges namespaces
-sequences sequences.private sets summary system vocabs hints
-typed ;
+USING: accessors alien.data arrays assocs byte-arrays
+combinators combinators.short-circuit hash-sets hashtables
+hashtables.private kernel math math.bitwise math.constants
+math.functions math.order namespaces sequences sequences.private
+sets summary system vocabs ;
+QUALIFIED-WITH: alien.c-types c
+QUALIFIED-WITH: sets sets
IN: random
SYMBOL: system-random-generator
SYMBOL: secure-random-generator
SYMBOL: random-generator
-GENERIC# seed-random 1 ( tuple seed -- tuple' )
-GENERIC: random-32* ( tuple -- r )
-GENERIC: random-bytes* ( n tuple -- byte-array )
-
-M: object random-bytes* ( n tuple -- byte-array )
- [ [ <byte-vector> ] keep 4 /mod ] dip
- [ pick '[ _ random-32* int <ref> _ push-all ] times ]
- [
- over zero?
- [ 2drop ] [ random-32* int <ref> swap head append! ] if
- ] bi-curry bi* B{ } like ;
-
-HINTS: M\ object random-bytes* { fixnum object } ;
+GENERIC#: seed-random 1 ( obj seed -- obj )
+GENERIC: random-32* ( obj -- n )
+GENERIC: random-bytes* ( n obj -- byte-array )
+
+M: object random-bytes*
+ [ integer>fixnum-strict [ (byte-array) ] keep ] dip
+ [ over 4 >= ] [
+ [ 4 - ] dip
+ [ random-32* 2over c:int c:set-alien-value ] keep
+ ] while over zero? [ 2drop ] [
+ random-32* c:int <ref> swap head 0 pick copy-unsafe
+ ] if ;
-M: object random-32* ( tuple -- r ) 4 swap random-bytes* be> ;
+M: object random-32*
+ 4 swap random-bytes* c:uint deref ;
ERROR: no-random-number-generator ;
M: no-random-number-generator summary
drop "Random number generator is not defined." ;
-M: f random-bytes* ( n obj -- * ) no-random-number-generator ;
+M: f random-bytes* no-random-number-generator ;
-M: f random-32* ( obj -- * ) no-random-number-generator ;
+M: f random-32* no-random-number-generator ;
-: random-32 ( -- n ) random-generator get random-32* ;
+: random-32 ( -- n )
+ random-generator get random-32* ;
-TYPED: random-bytes ( n: fixnum -- byte-array: byte-array )
- random-generator get random-bytes* ; inline
+: random-bytes ( n -- byte-array )
+ random-generator get random-bytes* ;
<PRIVATE
-: (random-integer) ( bits -- n required-bits )
- [ random-32 32 ] dip 32 - [ dup 0 > ] [
- [ 32 shift random-32 + ] [ 32 + ] [ 32 - ] tri*
- ] while drop ;
-
-: random-integer ( n -- n' )
- dup next-power-of-2 log2 (random-integer)
- [ * ] [ 2^ /i ] bi* ;
+:: (random-bits) ( numbits obj -- n )
+ numbits 32 > [
+ obj random-32* numbits 32 - [ dup 32 > ] [
+ [ 32 shift obj random-32* + ] [ 32 - ] bi*
+ ] while [
+ [ shift ] keep obj random-32* swap bits +
+ ] unless-zero
+ ] [
+ obj random-32* numbits bits
+ ] if ; inline
PRIVATE>
-: random-bits ( numbits -- r ) 2^ random-integer ;
+: random-bits ( numbits -- n )
+ random-generator get (random-bits) ;
: random-bits* ( numbits -- n )
1 - [ random-bits ] keep set-bit ;
+<PRIVATE
+
+: next-power-of-2-bits ( m -- numbits )
+ dup 2 <= [ drop 1 ] [ 1 - log2 1 + ] if ; inline
+
+:: random-integer-loop ( m obj -- n )
+ obj random-32* 32 m next-power-of-2-bits 32 - [ dup 0 > ] [
+ [ 32 shift obj random-32* + ] [ 32 + ] [ 32 - ] tri*
+ ] while drop [ m * ] [ neg shift ] bi* ; inline
+
+GENERIC#: (random-integer) 1 ( m obj -- n )
+M: fixnum (random-integer) random-integer-loop ;
+M: bignum (random-integer) random-integer-loop ;
+
+: random-integer ( m -- n )
+ random-generator get (random-integer) ;
+
+PRIVATE>
+
GENERIC: random ( obj -- elt )
-M: integer random [ f ] [ random-integer ] if-zero ;
+M: integer random
+ [ f ] [ random-integer ] if-zero ;
M: sequence random
[ f ] [
[ length random-integer ] keep nth
] if-empty ;
+M: assoc random >alist random ;
+
+M: hashtable random
+ dup assoc-size [ drop f ] [
+ [ 0 ] [ array>> ] [ random ] tri* 1 + [
+ [ 2dup array-nth tombstone? [ 2 + ] 2dip ] loop
+ ] times [ 2 - ] dip
+ [ array-nth ] [ [ 1 + ] dip array-nth ] 2bi 2array
+ ] if-zero ;
+
+M: sets:set random members random ;
+
+M: hash-set random
+ dup cardinality [ drop f ] [
+ [ 0 ] [ array>> ] [ random ] tri* 1 + [
+ [ 2dup array-nth tombstone? [ 1 + ] 2dip ] loop
+ ] times [ 1 - ] dip array-nth
+ ] if-zero ;
+
: randomize-n-last ( seq n -- seq )
[ dup length dup ] dip - 1 max '[ dup _ > ]
- [ [ random ] [ 1 - ] bi [ pick exchange-unsafe ] keep ]
- while drop ;
+ random-generator get '[
+ [ _ (random-integer) ] [ 1 - ] bi
+ [ pick exchange-unsafe ] keep
+ ] while drop ;
: randomize ( seq -- randomized )
dup length randomize-n-last ;
: sample ( seq n -- seq' )
2dup [ length ] dip < [ too-many-samples ] when
- [ [ length iota >array ] dip [ randomize-n-last ] keep tail-slice* ]
- [ drop ] 2bi nths ;
+ [ [ length <iota> >array ] dip [ randomize-n-last ] keep tail-slice* ]
+ [ drop ] 2bi nths-unsafe ;
: delete-random ( seq -- elt )
- [ length random-integer ] keep [ nth ] 2keep remove-nth! drop ;
+ [ length random-integer ] keep
+ [ nth ] 2keep remove-nth! drop ;
-: with-random ( tuple quot -- )
+: with-random ( obj quot -- )
random-generator swap with-variable ; inline
: with-system-random ( quot -- )
: with-secure-random ( quot -- )
secure-random-generator get swap with-random ; inline
-: uniform-random-float ( min max -- n )
- 4 random-bytes uint deref >float
- 4 random-bytes uint deref >float
+<PRIVATE
+
+: (uniform-random-float) ( min max obj -- n )
+ [ random-32* ] keep random-32* [ >float ] bi@
2.0 32 ^ * +
[ over - 2.0 -64 ^ * ] dip
- * + ; inline
+ * + ; inline
+
+PRIVATE>
+
+: uniform-random-float ( min max -- n )
+ random-generator get (uniform-random-float) ; inline
+
+M: float random [ f ] [ 0.0 swap uniform-random-float ] if-zero ;
+
+<PRIVATE
+
+: (random-unit) ( obj -- n )
+ [ 0.0 1.0 ] dip (uniform-random-float) ; inline
+
+PRIVATE>
: random-unit ( -- n )
- 0.0 1.0 uniform-random-float ; inline
+ random-generator get (random-unit) ; inline
: random-units ( length -- sequence )
- [ random-unit ] replicate ;
-
+ random-generator get '[ _ (random-unit) ] replicate ;
+
: random-integers ( length n -- sequence )
- '[ _ random ] replicate ;
+ random-generator get '[ _ _ (random-integer) ] replicate ;
+
+<PRIVATE
: (cos-random-float) ( -- n )
0. 2pi uniform-random-float cos ;
: (log-sqrt-random-float) ( -- n )
random-unit log -2. * sqrt ;
+PRIVATE>
+
: normal-random-float ( mean sigma -- n )
(cos-random-float) (log-sqrt-random-float) * * + ;
: pareto-random-float ( k alpha -- n )
[ random-unit ] dip recip ^ /f ;
+<PRIVATE
+
:: (gamma-random-float>1) ( alpha beta -- n )
! Uses R.C.H. Cheng, "The generation of Gamma
! variables with non-integral shape parameters",
! Applied Statistics, (1977), 26, No. 1, p71-74
- 2. alpha * 1 - sqrt :> ainv
- alpha 4. log - :> bbb
- alpha ainv + :> ccc
+ random-generator get :> rnd
+ 2. alpha * 1 - sqrt :> ainv
+ alpha 4. log - :> bbb
+ alpha ainv + :> ccc
0 :> r! 0 :> z! 0 :> result! ! initialize locals
[
[ z log >= ]
} 1|| not
] [
- random-unit :> u1
- random-unit :> u2
+ rnd (random-unit) :> u1
+ rnd (random-unit) :> u2
u1 1. u1 - / log ainv / :> v
- alpha v e^ * :> x
+ alpha v e^ * :> x
u1 sq u2 * z!
bbb ccc v * + x - r!
:: (gamma-random-float<1) ( alpha beta -- n )
! Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
+ random-generator get :> rnd
alpha e + e / :> b
0 :> x! 0 :> p! ! initialize locals
[
p 1.0 > [
- random-unit x alpha 1 - ^ >
+ rnd (random-unit) x alpha 1 - ^ >
] [
- random-unit x neg e^ >
+ rnd (random-unit) x neg e^ >
] if
] [
- random-unit b * p!
+ rnd (random-unit) b * p!
p 1.0 <= [
p 1. alpha / ^
] [
] if x!
] do while x beta * ;
+PRIVATE>
+
: gamma-random-float ( alpha beta -- n )
{
{ [ over 1 > ] [ (gamma-random-float>1) ] }
! Based upon an algorithm published in: Fisher, N.I.,
! "Statistical Analysis of Circular Data", Cambridge
! University Press, 1993.
+ random-generator get :> rnd
kappa 1e-6 <= [
- 2pi random-unit *
+ 2pi rnd (random-unit) *
] [
4. kappa sq * 1. + sqrt 1. + :> a
a 2. a * sqrt - 2. kappa * / :> b
0 :> c! 0 :> _f! ! initialize locals
[
- random-unit {
+ rnd (random-unit) {
[ 2. c - c * < ] [ 1. c - e^ c * <= ]
} 1|| not
] [
- random-unit pi * cos :> z
+ rnd (random-unit) pi * cos :> z
r z * 1. + r z + / _f!
r _f - kappa * c!
] do while
- mu 2pi mod _f cos random-unit 0.5 > [ + ] [ - ] if
+ mu 2pi mod _f cos
+ rnd (random-unit) 0.5 > [ + ] [ - ] if
] if ;
+<PRIVATE
+
:: (triangular-random-float) ( low high mode -- n )
mode low - high low - / :> c!
random-unit :> u!
u c > [ 1. u - u! 1. c - c! swap ] when
[ - u c * sqrt * ] keep + ;
+PRIVATE>
+
: triangular-random-float ( low high -- n )
2dup + 2 /f (triangular-random-float) ;
: power-random-float ( alpha -- n )
[ random-unit log e^ 1 swap - ] dip recip ^ ;
+! Box-Muller
+: poisson-random-float ( mean -- n )
+ [ -1 0 ] dip [ 2dup < ] random-generator get '[
+ [ 1 + ] 2dip [ _ (random-unit) log neg + ] dip
+ ] while 2drop ;
+
{
{ [ os windows? ] [ "random.windows" require ] }
{ [ os unix? ] [ "random.unix" require ] }