racket/collects/math/private/vector/flvector.rkt
Neil Toronto 2d34811ab6 Finished `math/distributions' documentation!
Fixed a few limit cases in some distributions (e.g. (uniform-dist 0 0) didn't
act like a delta distribution, (beta-dist 0 0) and (beta-dist +inf.0 +inf.0)
pretended to be defined by unique limits even though they can't be)

Made integer distributions' pdfs return +nan.0 when given non-integers

Added "private/statistics/counting.rkt", for hashing and binning samples

Added `flvector-sums' (cumulative sums with single rounding error)

Added `flinteger?', `flnan?' and `flrational?', which are faster than their
non-flonum counterparts (at least in Typed Racket; haven't tested untyped)
2012-11-27 13:44:15 -07:00

297 lines
11 KiB
Racket

#lang typed/racket/base
(require racket/fixnum
racket/string
(for-syntax racket/base syntax/parse)
"../../flonum.rkt"
"../unsafe.rkt"
"flvector-syntax.rkt")
(provide
(all-from-out "flvector-syntax.rkt")
;; Construction
unsafe-flvector-copy!
flvector-copy!
;; Loops
for/flvector:
for*/flvector:
;; Conversion
list->flvector
flvector->list
vector->flvector
flvector->vector
;; Pointwise operations
flvector-scale
flvector-round
flvector-floor
flvector-ceiling
flvector-truncate
flvector-abs
flvector-sqr
flvector-sqrt
flvector-log
flvector-exp
flvector-sin
flvector-cos
flvector-tan
flvector-asin
flvector-acos
flvector-atan
flvector+
flvector*
flvector-
flvector/
flvector-expt
flvector-min
flvector-max
flvector=
flvector<
flvector<=
flvector>
flvector>=
;;
flvector-sums)
;; ===================================================================================================
;; flvector-copy
(: unsafe-flvector-copy! (FlVector Integer FlVector Integer Integer -> Void))
(define (unsafe-flvector-copy! dest dest-start src src-start src-end)
(let loop ([i dest-start] [j src-start])
(when (j . unsafe-fx< . src-end)
(unsafe-flvector-set! dest i (unsafe-flvector-ref src j))
(loop (unsafe-fx+ i 1) (unsafe-fx+ j 1)))))
(: flvector-copy! (case-> (FlVector Integer FlVector -> Void)
(FlVector Integer FlVector Integer -> Void)
(FlVector Integer FlVector Integer Integer -> Void)))
(define flvector-copy!
(case-lambda
[(dest dest-start src)
(flvector-copy! dest dest-start src 0 (flvector-length src))]
[(dest dest-start src src-start)
(flvector-copy! dest dest-start src src-start (flvector-length src))]
[(dest dest-start src src-start src-end)
(define dest-len (flvector-length dest))
(define src-len (flvector-length src))
(cond [(or (dest-start . < . 0) (dest-start . > . dest-len))
(raise-argument-error 'flvector-copy! (format "Index <= ~e" dest-len) 1
dest dest-start src src-start src-end)]
[(or (src-start . < . 0) (src-start . > . src-len))
(raise-argument-error 'flvector-copy! (format "Index <= ~e" src-len) 3
dest dest-start src src-start src-end)]
[(or (src-end . < . 0) (src-end . > . src-len))
(raise-argument-error 'flvector-copy! (format "Index <= ~e" src-len) 4
dest dest-start src src-start src-end)]
[(src-end . < . src-start)
(error 'flvector-copy! "ending index is smaller than starting index")]
[((- dest-len dest-start) . < . (- src-end src-start))
(error 'flvector-copy! "not enough room in target vector")]
[else
(unsafe-flvector-copy! dest dest-start src src-start src-end)])]))
;; ===================================================================================================
;; Loops
(define-syntax (base-for/flvector: stx)
(syntax-parse stx
[(_ for: #:length n-expr:expr (clauses ...) body ...+)
(syntax/loc stx
(let: ([n : Integer n-expr])
(cond [(n . > . 0)
(define xs (make-flvector n))
(define: i : Nonnegative-Fixnum 0)
(let/ec: break : Void
(for: (clauses ...)
(unsafe-flvector-set! xs i (let () body ...))
(set! i (unsafe-fx+ i 1))
(when (i . unsafe-fx>= . n) (break (void)))))
xs]
[else (flvector)])))]
[(_ for: (clauses ...) body ...+)
(syntax/loc stx
(let ()
(define n 4)
(define xs (make-flvector 4))
(define i 0)
(for: (clauses ...)
(let: ([x : Float (let () body ...)])
(cond [(unsafe-fx= i n) (define new-n (unsafe-fx* 2 n))
(define new-xs (make-flvector new-n x))
(unsafe-flvector-copy! new-xs 0 xs 0 n)
(set! n new-n)
(set! xs new-xs)]
[else (unsafe-flvector-set! xs i x)]))
(set! i (unsafe-fx+ i 1)))
(flvector-copy xs 0 i)))]))
(define-syntax-rule (for/flvector: e ...)
(base-for/flvector: for: e ...))
(define-syntax-rule (for*/flvector: e ...)
(base-for/flvector: for*: e ...))
;; ===================================================================================================
;; Conversion
(: list->flvector ((Listof Real) -> FlVector))
(define (list->flvector vs)
(define n (length vs))
(define xs (make-flvector n))
(let loop ([#{i : Nonnegative-Fixnum} 0] [vs vs])
(cond [(i . < . n) (unsafe-flvector-set! xs i (real->double-flonum (unsafe-car vs)))
(loop (+ i 1) (unsafe-cdr vs))]
[else xs])))
(: flvector->list (FlVector -> (Listof Float)))
(define (flvector->list xs)
(for/list: : (Listof Float) ([x (in-flvector xs)]) x))
(: vector->flvector ((Vectorof Real) -> FlVector))
(define (vector->flvector vs)
(define n (vector-length vs))
(define xs (make-flvector n))
(let loop ([#{i : Nonnegative-Fixnum} 0])
(cond [(i . < . n) (unsafe-flvector-set! xs i (real->double-flonum (unsafe-vector-ref vs i)))
(loop (+ i 1))]
[else xs])))
(: flvector->vector (FlVector -> (Vectorof Float)))
(define (flvector->vector xs)
(define n (flvector-length xs))
(define vs (make-vector n 0.0))
(let loop ([#{i : Nonnegative-Fixnum} 0])
(cond [(i . < . n) (unsafe-vector-set! vs i (unsafe-flvector-ref xs i))
(loop (+ i 1))]
[else vs])))
;; ===================================================================================================
;; Pointwise operations
(define-syntax (lift1 stx)
(syntax-case stx ()
[(_ f) (syntax/loc stx (λ (arr) (flvector-map f arr)))]))
(define-syntax (lift2 stx)
(syntax-case stx ()
[(_ f) (syntax/loc stx (λ (arr1 arr2) (flvector-map f arr1 arr2)))]))
(define-syntax-rule (lift-comparison name comp)
(λ (xs1 xs2)
(define n1 (flvector-length xs1))
(define n2 (flvector-length xs2))
(unless (= n1 n2) (error name "flvectors must be the same length; given lengths ~e and ~e" n1 n2))
(build-vector
n1 (λ: ([j : Index])
(comp (unsafe-flvector-ref xs1 j)
(unsafe-flvector-ref xs2 j))))))
(: flvector-scale (FlVector Float -> FlVector))
(define (flvector-scale arr y) (flvector-map (λ (x) (fl* x y)) arr))
(: flvector-round (FlVector -> FlVector))
(: flvector-floor (FlVector -> FlVector))
(: flvector-ceiling (FlVector -> FlVector))
(: flvector-truncate (FlVector -> FlVector))
(: flvector-abs (FlVector -> FlVector))
(: flvector-sqr (FlVector -> FlVector))
(: flvector-sqrt (FlVector -> FlVector))
(: flvector-log (FlVector -> FlVector))
(: flvector-exp (FlVector -> FlVector))
(: flvector-sin (FlVector -> FlVector))
(: flvector-cos (FlVector -> FlVector))
(: flvector-tan (FlVector -> FlVector))
(: flvector-asin (FlVector -> FlVector))
(: flvector-acos (FlVector -> FlVector))
(: flvector-atan (FlVector -> FlVector))
(: flvector+ (FlVector FlVector -> FlVector))
(: flvector* (FlVector FlVector -> FlVector))
(: flvector- (case-> (FlVector -> FlVector)
(FlVector FlVector -> FlVector)))
(: flvector/ (case-> (FlVector -> FlVector)
(FlVector FlVector -> FlVector)))
(: flvector-expt (FlVector FlVector -> FlVector))
(: flvector-min (FlVector FlVector -> FlVector))
(: flvector-max (FlVector FlVector -> FlVector))
(: flvector= (FlVector FlVector -> (Vectorof Boolean)))
(: flvector< (FlVector FlVector -> (Vectorof Boolean)))
(: flvector<= (FlVector FlVector -> (Vectorof Boolean)))
(: flvector> (FlVector FlVector -> (Vectorof Boolean)))
(: flvector>= (FlVector FlVector -> (Vectorof Boolean)))
(define flvector-round (lift1 flround))
(define flvector-floor (lift1 flfloor))
(define flvector-ceiling (lift1 flceiling))
(define flvector-truncate (lift1 fltruncate))
(define flvector-abs (lift1 flabs))
(define flvector-sqr (lift1 (λ: ([x : Float]) (fl* x x))))
(define flvector-sqrt (lift1 flsqrt))
(define flvector-log (lift1 fllog))
(define flvector-exp (lift1 flexp))
(define flvector-sin (lift1 flsin))
(define flvector-cos (lift1 flcos))
(define flvector-tan (lift1 fltan))
(define flvector-asin (lift1 flasin))
(define flvector-acos (lift1 flacos))
(define flvector-atan (lift1 flatan))
(define flvector+ (lift2 fl+))
(define flvector* (lift2 fl*))
(define flvector-
(case-lambda
[(arr) (flvector-map (λ: ([x : Float]) (fl- 0.0 x)) arr)]
[(arr1 arr2) (flvector-map fl- arr1 arr2)]))
(define flvector/
(case-lambda
[(arr) (flvector-map (λ: ([x : Float]) (fl/ 1.0 x)) arr)]
[(arr1 arr2) (flvector-map fl/ arr1 arr2)]))
(define flvector-expt (lift2 flexpt))
(define flvector-min (lift2 flmin))
(define flvector-max (lift2 flmax))
(define flvector= (lift-comparison 'flvector= fl=))
(define flvector< (lift-comparison 'flvector< fl<))
(define flvector<= (lift-comparison 'flvector<= fl<=))
(define flvector> (lift-comparison 'flvector> fl>))
(define flvector>= (lift-comparison 'flvector>= fl>=))
;; ===================================================================================================
(: flvector-sums (FlVector -> FlVector))
(define (flvector-sums xs)
(define n (flvector-length xs))
(define rs (make-flvector n))
(define ss (make-flvector n))
(let j-loop ([#{j : Nonnegative-Fixnum} 0]
[#{m : Nonnegative-Fixnum} 0])
(cond
[(j . fx< . n)
(define x (unsafe-flvector-ref xs j))
(let p-loop ([#{p : Nonnegative-Fixnum} 0]
[#{x : Flonum} x]
[#{s : Flonum} 0.0]
[#{i : Nonnegative-Fixnum} 0])
(cond
[(p . fx< . m)
(define r (unsafe-flvector-ref rs p))
(let-values ([(x r) (if ((flabs x) . fl< . (flabs r)) (values r x) (values x r))])
(define z (fl+ x r))
(define-values (hi lo)
(cond [(flrational? z) (values z (fl- r (fl- z x)))]
[else (values x r)]))
(cond [(fl= lo 0.0)
(p-loop (unsafe-fx+ p 1) hi s i)]
[else
(unsafe-flvector-set! rs i lo)
(p-loop (unsafe-fx+ p 1) hi (fl+ s lo) (unsafe-fx+ i 1))]))]
[else
(unsafe-flvector-set! rs i x)
(unsafe-flvector-set! ss j (fl+ s x))
(j-loop (fx+ j 1) (unsafe-fx+ i 1))]))]
[else ss])))