factor/basis/random/sfmt/sfmt.factor

168 lines
4.0 KiB
Factor
Raw Normal View History

! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.c-types kernel locals math math.ranges
math.bitwise math.vectors math.vectors.simd random
2009-10-07 16:06:59 -04:00
sequences specialized-arrays sequences.private classes.struct
combinators.short-circuit fry ;
SPECIALIZED-ARRAY: uint
SPECIALIZED-ARRAY: uint-4
2009-10-02 02:18:18 -04:00
IN: random.sfmt
2009-10-02 02:18:18 -04:00
<PRIVATE
CONSTANT: state-multiplier 1812433253
2009-10-02 02:18:18 -04:00
STRUCT: sfmt-state
{ seed uint }
{ n uint }
{ m uint }
2009-10-07 14:42:37 -04:00
{ index uint }
2009-10-02 02:18:18 -04:00
{ mask uint-4 }
2009-10-07 16:06:59 -04:00
{ parity uint-4 }
2009-10-02 02:18:18 -04:00
{ r1 uint-4 }
{ r2 uint-4 } ;
2009-10-02 02:18:18 -04:00
TUPLE: sfmt
{ state sfmt-state }
{ uint-array uint-array }
{ uint-4-array uint-4-array } ;
2009-10-19 06:22:43 -04:00
: endian-shuffle ( v -- w )
little-endian? [
uchar-16{ 3 2 1 0 7 6 5 4 11 10 9 8 15 14 13 12 } vshuffle
2009-10-19 06:22:43 -04:00
] unless ; inline
: hlshift* ( v n -- w )
[ endian-shuffle ] dip hlshift endian-shuffle ; inline
: hrshift* ( v n -- w )
[ endian-shuffle ] dip hrshift endian-shuffle ; inline
: wA ( w -- wA )
2009-10-19 06:22:43 -04:00
dup 1 hlshift* vbitxor ; inline
: wB ( w mask -- wB )
[ 11 vrshift ] dip vbitand ; inline
: wC ( w -- wC )
2009-10-19 06:22:43 -04:00
1 hrshift* ; inline
: wD ( w -- wD )
18 vlshift ; inline
: formula ( a b mask c d -- r )
[ wC ] dip wD vbitxor
[ wB ] dip vbitxor
[ wA ] dip vbitxor ; inline
2009-10-02 02:18:18 -04:00
GENERIC: generate ( sfmt -- )
2009-10-02 02:18:18 -04:00
M:: sfmt generate ( sfmt -- )
2009-10-02 01:40:55 -04:00
sfmt state>> :> state
2009-10-02 02:18:18 -04:00
sfmt uint-4-array>> :> array
state n>> 2 - array nth state (>>r1)
state n>> 1 - array nth state (>>r2)
2009-10-07 14:42:37 -04:00
state m>> :> m
state n>> :> n
2009-10-02 02:18:18 -04:00
state mask>> :> mask
n m - >fixnum iota [| i |
2009-10-07 14:42:37 -04:00
i array nth-unsafe
2009-10-02 02:18:18 -04:00
i m + array nth-unsafe
mask state r1>> state r2>> formula :> r
r i array set-nth-unsafe
state r2>> state (>>r1)
r state (>>r2)
] each
2009-10-02 02:18:18 -04:00
! n m - 1 + n [a,b) [
m 1 - iota [
n m - 1 + + >fixnum :> i
i array nth-unsafe
2009-10-02 02:32:11 -04:00
m n - i + array nth-unsafe
2009-10-02 02:18:18 -04:00
mask state r1>> state r2>> formula :> r
2009-10-02 02:18:18 -04:00
r i array set-nth-unsafe
state r2>> state (>>r1)
r state (>>r2)
] each
2009-10-07 14:42:37 -04:00
0 state (>>index) ;
2009-10-07 16:06:59 -04:00
: period-certified? ( sfmt -- ? )
[ uint-4-array>> first ]
[ state>> parity>> ] bi vbitand odd-parity? ;
: first-set-bit ( x -- n )
0 swap [
dup { [ 0 > ] [ 1 bitand 0 = ] } 1&&
] [
[ 1 + ] [ -1 shift ] bi*
] while drop ;
: correct-period ( sfmt -- )
[ drop 0 ]
[ state>> parity>> first first-set-bit ]
[ uint-array>> swap '[ _ toggle-bit ] change-nth ] tri ;
: certify-period ( sfmt -- sfmt )
dup period-certified? [ dup correct-period ] unless ;
2009-10-02 02:18:18 -04:00
: <sfmt-array> ( sfmt -- uint-array uint-4-array )
2009-10-07 14:42:37 -04:00
state>>
[ n>> 4 * [1,b] >uint-array ] [ seed>> ] bi
2009-10-02 02:18:18 -04:00
[
[
2009-10-07 14:42:37 -04:00
[ -30 shift ] [ ] bi bitxor
state-multiplier * 32 bits
] dip + 32 bits
2009-10-02 02:18:18 -04:00
] uint-array{ } accumulate-as nip
dup underlying>> byte-array>uint-4-array ;
2009-10-07 16:06:59 -04:00
: <sfmt-state> ( seed n m mask parity -- sfmt )
2009-10-02 02:18:18 -04:00
sfmt-state <struct>
2009-10-07 16:06:59 -04:00
swap >>parity
swap >>mask
swap >>m
swap >>n
2009-10-02 02:18:18 -04:00
swap >>seed
2009-10-07 14:42:37 -04:00
0 >>index ;
: init-sfmt ( sfmt -- sfmt' )
dup <sfmt-array> [ >>uint-array ] [ >>uint-4-array ] bi*
2009-10-07 16:06:59 -04:00
certify-period [ generate ] keep ; inline
2009-10-07 16:06:59 -04:00
: <sfmt> ( seed n m mask parity -- sfmt )
2009-10-02 02:18:18 -04:00
<sfmt-state>
sfmt new
swap >>state
init-sfmt ; inline
: refill-sfmt? ( sfmt -- ? )
2009-10-07 16:27:40 -04:00
state>> [ index>> ] [ n>> 4 * ] bi >= ; inline
2009-10-02 02:18:18 -04:00
2009-10-07 14:42:37 -04:00
: next-index ( sfmt -- index )
state>> [ dup 1 + ] change-index drop ; inline
2009-10-02 02:18:18 -04:00
: next ( sfmt -- n )
2009-10-07 14:42:37 -04:00
[ next-index ] [ uint-array>> ] bi nth-unsafe ; inline
2009-10-02 02:18:18 -04:00
PRIVATE>
M: sfmt random-32* ( sfmt -- n )
2009-10-02 02:32:11 -04:00
dup refill-sfmt? [ dup generate ] when next ; inline
2009-10-02 02:18:18 -04:00
M: sfmt seed-random ( sfmt seed -- sfmt )
[ [ state>> ] dip >>seed drop ]
[ drop init-sfmt ] 2bi ;
2009-10-02 02:18:18 -04:00
: <sfmt-19937> ( seed -- sfmt )
2009-10-07 14:42:37 -04:00
156 122
2009-10-07 16:06:59 -04:00
uint-4{ HEX: dfffffef HEX: ddfecb7f HEX: bffaffff HEX: bffffff6 }
uint-4{ HEX: 1 HEX: 0 HEX: 0 HEX: 13c9e684 }
2009-10-02 02:32:11 -04:00
<sfmt> ; inline
: default-sfmt ( -- sfmt )
[ random-32 ] with-secure-random <sfmt-19937> ;