1 ! Copyright (C) 2012 John Benediktsson
2 ! See https://factorcode.org/license.txt for BSD license
4 USING: accessors arrays assocs byte-arrays combinators
5 combinators.short-circuit compression.zlib grouping kernel math
6 math.bitwise math.combinatorics math.constants math.functions
7 math.order math.primes math.primes.factors math.statistics
8 math.vectors random ranges ranges.private sequences
9 sequences.extras sets sorting sorting.extras ;
17 : (stirling) ( n k -- x )
18 [ [ 1 - ] bi@ stirling ]
19 [ [ 1 - ] dip stirling ]
24 MEMO: stirling ( n k -- x )
25 2dup { [ = ] [ nip 1 = ] } 2||
26 [ 2drop 1 ] [ (stirling) ] if ;
28 :: ramanujan ( x -- y )
29 pi sqrt x e / x ^ * x 8 * 4 + x * 1 + x * 1/30 + 1/6 ^ * ;
35 : (bernoulli) ( p -- n )
36 [ <iota> ] [ 1 + ] bi [
37 0 [ [ nCk ] [ bernoulli * ] bi + ] with reduce
42 MEMO: bernoulli ( p -- n )
43 [ 1 ] [ (bernoulli) ] if-zero ;
45 ! From page 4 https://arxiv.org/ftp/arxiv/papers/2201/2201.12601.pdf
46 : bernoulli-estimate-factorial ( n -- n! )
47 [ 2pi swap ^ ] [ bernoulli ] bi * 2 / ;
49 : chi2 ( actual expected -- n )
50 0 [ dup 0 > [ [ - sq ] keep / + ] [ 2drop ] if ] 2reduce ;
55 even? [ "odd degrees of freedom" throw ] unless ;
57 : (chi2P) ( chi/2 df/2 -- p )
58 [1..b) dupd n/v cum-product swap neg e^ [ v*n sum ] keep + ;
62 : chi2P ( chi df -- p )
63 dup df-check [ 2.0 / ] [ 2 /i ] bi* (chi2P) 1.0 min ;
67 : check-jacobi ( m -- m )
68 dup { [ integer? ] [ 0 > ] [ odd? ] } 1&&
69 [ "modulus must be odd positive integer" throw ] unless ;
72 [ mod ] keep over zero? [ drop ] [
73 2dup [ sgn ] same? [ drop ] [ + ] if
79 check-jacobi [ mod' ] keep 1
83 over 8 mod' { 3 5 } member? [ neg ] when
85 2over [ 4 mod' 3 = ] both? [ neg ] when
87 ] until [ nip 1 = ] dip 0 ? ;
91 : check-legendere ( m -- m )
92 dup prime? [ "modulus must be prime positive integer" throw ] unless ;
96 : legendere ( a m -- n )
97 check-legendere jacobi ;
99 : moving-average ( seq n -- newseq )
100 <clumps> [ mean ] map ;
102 : exponential-moving-average ( seq a -- newseq )
103 [ 1 ] 2dip '[ dupd swap - _ * + dup ] map nip ;
105 : moving-median ( u n -- v )
106 <clumps> [ median ] map ;
108 : moving-supremum ( u n -- v )
109 <clumps> [ supremum ] map ;
111 : moving-infimum ( u n -- v )
112 <clumps> [ infimum ] map ;
114 : moving-sum ( u n -- v )
115 <clumps> [ sum ] map ;
117 : moving-count ( ... u n quot: ( ... elt -- ... ? ) -- ... v )
118 [ <clumps> ] [ '[ _ count ] map ] bi* ; inline
120 : nonzero ( seq -- seq' )
123 : bartlett ( n -- seq )
124 dup 1 <= [ 1 = [ 1 1array ] [ { } ] if ] [
125 [ <iota> ] [ 1 - 2 / ] bi [
126 [ recip * ] [ >= ] 2bi [ 2 swap - ] when
130 : [0,2pi] ( n -- seq )
131 [ <iota> ] [ 1 - 2pi swap / ] bi v*n ;
133 : hanning ( n -- seq )
134 dup 1 <= [ 1 = [ 1 1array ] [ { } ] if ] [
135 [0,2pi] [ cos -0.5 * 0.5 + ] map!
138 : hamming ( n -- seq )
139 dup 1 <= [ 1 = [ 1 1array ] [ { } ] if ] [
140 [0,2pi] [ cos -0.46 * 0.54 + ] map!
143 : blackman ( n -- seq )
144 dup 1 <= [ 1 = [ 1 1array ] [ { } ] if ] [
146 [ cos -0.5 * ] [ 2 * cos 0.08 * ] bi + 0.42 +
150 : nan-sum ( seq -- n )
151 0 [ dup fp-nan? [ drop ] [ + ] if ] binary-reduce ;
153 : nan-min ( seq -- n )
154 [ fp-nan? ] reject infimum ;
156 : nan-max ( seq -- n )
157 [ fp-nan? ] reject supremum ;
159 : fill-nans ( seq -- newseq )
161 dup fp-nan? [ drop dup ] [ nip dup ] if
165 [ 1 ] [ pi * [ sin ] [ / ] bi ] if-zero ;
167 : cum-reduce ( seq identity quot: ( prev elt -- next ) -- result cum-result )
168 [ dup rot ] dip dup '[ _ curry dip dupd @ ] each ; inline
172 :: (gini) ( seq -- x )
173 seq natural-sort :> sorted
175 sorted 0 [ + ] cum-reduce :> ( a b )
177 1 len recip + 2 c * - ;
182 dup length 1 <= [ drop 0 ] [ (gini) ] if ;
184 : concentration-coefficient ( seq -- x )
188 [ (gini) ] [ length [ ] [ 1 - ] bi / ] bi *
191 : herfindahl ( seq -- x )
192 [ sum-of-squares ] [ sum sq ] bi / ;
194 : normalized-herfindahl ( seq -- x )
195 [ herfindahl ] [ length recip ] bi
196 [ - ] [ 1 swap - / ] bi ;
198 : exponential-index ( seq -- x )
199 dup sum '[ _ / dup ^ ] map-product ;
201 : weighted-random ( histogram -- obj )
202 unzip cum-sum [ last >float random ] [ bisect-left ] bi swap nth ;
204 : unique-indices ( seq -- unique indices )
205 [ members ] keep over dup length <iota>
206 H{ } zip-as '[ _ at ] map ;
208 : digitize] ( seq bins -- seq' )
209 '[ _ bisect-left ] map ;
211 : digitize) ( seq bins -- seq' )
212 '[ _ bisect-right ] map ;
216 : steps ( a b length -- a b step )
217 [ 2dup swap - ] dip / ; inline
221 : linspace[a..b) ( a b length -- seq )
224 : linspace[a..b] ( a b length -- seq )
226 { [ dup 1 < ] [ 3drop { } ] }
227 { [ dup 1 = ] [ 2drop 1array ] }
228 [ 1 - steps <range> ]
231 : logspace[a..b) ( a b length base -- seq )
232 [ linspace[a..b) ] dip swap n^v ;
234 : logspace[a..b] ( a b length base -- seq )
235 [ linspace[a..b] ] dip swap n^v ;
237 : majority ( seq -- elt/f )
239 over zero? [ 2nip 1 ] [
240 pick = [ 1 + ] [ 1 - ] if
242 ] each zero? [ drop f ] when ;
244 : compression-lengths ( a b -- len(a+b) len(a) len(b) )
245 [ append ] 2keep [ >byte-array compress data>> length ] tri@ ;
247 : compression-distance ( a b -- n )
248 compression-lengths sort-pair [ - ] [ / ] bi* ;
250 : compression-dissimilarity ( a b -- n )
251 compression-lengths + / ;
253 : round-to-decimal ( x n -- y )
254 10^ [ * 0.5 over 0 > [ + ] [ - ] if truncate ] [ / ] bi ;
256 : round-to-step ( x step -- y )
257 [ [ / round ] [ * ] bi ] unless-zero ;
259 GENERIC: round-away-from-zero ( x -- y )
261 M: integer round-away-from-zero ; inline
263 M: real round-away-from-zero
264 dup 0 < [ floor ] [ ceiling ] if ;
266 : monotonic-count ( seq quot: ( elt1 elt2 -- ? ) -- newseq )
267 over empty? [ 2drop { } ] [
268 [ 0 swap unclip-slice swap ] dip '[
269 [ @ [ 1 + ] [ drop 0 ] if ] keep over
270 ] { } map-as 2nip 0 prefix
273 : max-monotonic-count ( seq quot: ( elt1 elt2 -- ? ) -- n )
274 over empty? [ 2drop 0 ] [
275 [ 0 swap unclip-slice swap 0 ] dip '[
276 [ swapd @ [ 1 + ] [ max 0 ] if ] keep swap
282 : kahan+ ( c sum elt -- c' sum' )
283 rot - 2dup + [ -rot [ - ] bi@ ] keep ; inline
287 : kahan-sum ( seq -- n )
288 [ 0.0 0.0 ] dip [ kahan+ ] each nip ;
290 : map-kahan-sum ( ... seq quot: ( ... elt -- ... n ) -- ... n )
291 [ 0.0 0.0 ] 2dip [ 2dip rot kahan+ ] curry
292 [ -rot ] prepose each nip ; inline
296 ! Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates
297 ! www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps
299 : sort-partial ( x y -- x' y' )
300 2dup [ abs ] bi@ < [ swap ] when ; inline
302 :: partial+ ( x y -- hi lo )
303 x y + dup x - :> yr y yr - ; inline
305 :: partial-sums ( seq -- seq' )
306 V{ } clone :> partials
309 swapd sort-partial partial+ swapd
310 [ over partials set-nth 1 + ] unless-zero
313 [ i partials set-nth ] unless-zero
316 :: sum-exact ( partials -- n )
318 ! sum from the top, stop when sum becomes inexact
320 nip partial+ dup 0.0 = not
321 ] find-last drop :> ( lo n )
323 ! make half-even rounding work across multiple partials
324 n [ 0 > ] [ f ] if* [
326 [ 0.0 < lo 0.0 < and ]
327 [ 0.0 > lo 0.0 > and ] bi or [
331 y yr = [ drop x ] when
338 : sum-floats ( seq -- n )
339 partial-sums sum-exact ;
342 group-factors values [ 1 ] [
344 [ drop 0 ] [ length even? 1 -1 ? ] if
347 : kelly ( winning-probability odds -- fraction )
348 [ 1 + * 1 - ] [ / ] bi ;
350 :: integer-sqrt ( m -- n )
352 dup 0 < [ non-negative-integer-expected ] when
353 bit-length 1 - 2 /i :> c
356 c bit-length <iota> <reversed> [| s |
360 m 2 c * e - d - 1 + neg shift a /i + a!
362 a a sq m > [ 1 - ] when
367 : reduce-evens ( value u v -- value' u' v' )
368 [ 2dup [ even? ] both? ] [ [ 2 * ] [ 2/ ] [ 2/ ] tri* ] while ;
370 : reduce-odds ( value u v -- value' u' v' )
372 [ [ dup even? ] [ 2/ ] while ] bi@
374 { +eq+ [ over '[ _ * ] 2dip f ] }
375 { +lt+ [ swap [ - ] keep t ] }
376 { +gt+ [ [ - ] keep t ] }
383 2dup [ zero? ] both? [ "gcd for zeros is undefined" throw ] when
384 [ dup 0 < [ neg ] when ] bi@
385 [ 1 ] 2dip reduce-evens reduce-odds 2drop ;