! See https://factorcode.org/license.txt for BSD license
USING: accessors arrays assocs byte-arrays combinators
-combinators.short-circuit compression.zlib grouping kernel math
-math.bitwise math.combinatorics math.constants math.functions
-math.order math.primes math.primes.factors math.statistics
-math.vectors namespaces random random.private ranges
-ranges.private sequences sequences.extras sets sorting
-sorting.extras ;
+combinators.short-circuit compression.zlib grouping kernel
+kernel.private math math.bitwise math.combinatorics
+math.constants math.functions math.order math.primes
+math.primes.factors math.statistics math.vectors namespaces
+random random.private ranges ranges.private sequences
+sequences.extras sequences.private sets sorting sorting.extras ;
IN: math.extras
dup sum '[ _ / dup ^ ] map-product ;
: weighted-random ( histogram -- obj )
- unzip cum-sum [ last >float random ] [ bisect-left ] bi swap nth ;
+ unzip cum-sum [ last >float random ] keep bisect-left swap nth ;
-: weighted-randoms ( histogram length -- seq )
- swap unzip swap [ cum-sum [ last >float random-generator get ] keep ] dip
+: weighted-randoms ( length histogram -- seq )
+ unzip cum-sum swap
+ [ [ last >float random-generator get ] keep ] dip
'[ _ _ random* _ bisect-left _ nth ] replicate ;
: unique-indices ( seq -- unique indices )
[ dup 0 < [ neg ] when ] bi@
[ 1 ] 2dip reduce-evens reduce-odds 2drop ;
-
+TUPLE: vose
+ { n fixnum }
+ { items array }
+ { probs array }
+ { alias array } ;
+
+:: <vose> ( dist -- vose )
+ V{ } clone :> small
+ V{ } clone :> large
+ dist assoc-size :> n
+ n f <array> :> alias
+
+ dist unzip dup [ length ] [ sum ] bi / v*n :> ( items probs )
+ probs [ swap 1 < small large ? push ] each-index
+
+ [ small empty? large empty? or ] [
+ small pop :> s
+ large pop :> l
+ l s alias set-nth
+ l dup probs [ s probs nth + 1 - dup ] change-nth
+ 1 < small large ? push
+ ] until
+
+ 1 large [ probs set-nth ] with each
+ 1 small [ probs set-nth ] with each
+
+ n items probs alias vose boa ;
+
+M:: vose random* ( obj rnd -- elt )
+ obj n>> rnd random* { fixnum } declare
+ dup obj probs>> nth-unsafe rnd (random-unit) >=
+ [ obj alias>> nth-unsafe ] unless
+ obj items>> nth-unsafe ;