(Arne Babenhauserheide)
2017-03-23: Enforce a maximum relative unbiased standard deviation of the test Enforce a maximum relative unbiased standard deviation of the test
diff --git a/examples/benchmark.w b/examples/benchmark.w --- a/examples/benchmark.w +++ b/examples/benchmark.w @@ -23,14 +23,30 @@ define : stddev nums length nums expt (/ (apply + nums) (length nums)) 2 + +define : stddev-unbiased-normal nums + . "Approximated unbiased standard deviation for the normal distribution + + 'for n = 3 the bias is equal to 1.3%, and for n = 9 the bias is already less than 0.1%.' + - https://en.wikipedia.org/wiki/Standard_deviation#Unbiased_sample_standard_deviation + " + sqrt + - + / : apply + : map (lambda (i) (* i i)) nums + - (length nums) 1.5 + expt (/ (apply + nums) (length nums)) 2 + + define : running-stddev nums define : running-stddev-2 num set! nums : cons num nums stddev nums . running-stddev-2 -define* : benchmark-run fun #:key (min-seconds 0.1) - let profiler : (loop-num 10) +define* : benchmark-run-single fun #:key (min-seconds 0.1) + let profiler : (loop-num 4) + ;; trigger garbage collection before stats collection to avoid polluting the data + gc let : : t : get-internal-real-time with-output-to-string lambda () @@ -41,14 +57,27 @@ define* : benchmark-run fun #:key (min-s let* : dt : - (get-internal-real-time) t seconds : / (exact->inexact dt) internal-time-units-per-second - pretty-print : list dt seconds loop-num - if : > seconds min-seconds - / seconds loop-num ;; this wastes less than {(10 * ((10^(i-1)) - 1)) / 10^i} fractional data but gains big in simplicity - profiler (* 10 loop-num) + ;; pretty-print : list dt seconds loop-num + if {seconds > min-seconds} + / seconds loop-num ;; this wastes less than {(4 * ((4^(i-1)) - 1)) / 4^i} fractional data but gains big in simplicity + profiler (* 4 loop-num) ;; for fast functions I need to go up rapidly, for slow ones I need to avoid overshooting + +define* : benchmark-run fun #:key (max-relative-uncertainty 0.2) + pretty-print fun + let lp : (min-seconds 1.e-5) (sampling-steps 4) ;; min seconds: 10μs ~ 30k cycles, start with at least 3 sampling steps to make the approximations in stddev-unbiased-normal good enough + let* + : res : list-ec (: i sampling-steps) : benchmark-run-single fun #:min-seconds min-seconds + std : stddev-unbiased-normal res + mean : / (apply + res) (length res) + pretty-print : list mean '± std min-seconds sampling-steps + if : < std {mean * max-relative-uncertainty} + . mean + lp (* 2 min-seconds) (* 2 sampling-steps) ;; should decrease σ by factor 2 or √2 (for slow functions) define loopcost benchmark-run (λ() #f) + ;; TODO: Simplify #:key setup -> . setup define* : benchmark-fun fun #:key setup when setup @@ -89,7 +118,7 @@ define : benchmark-list-append let : (N (list-ref x 0)) (m (list-ref x 1)) benchmark (append a b) :let ((a (iota N))(b (iota m))) . param-list - let : (steps 100) + let : (steps 10) concatenate list let : (param-list (zip (logiota steps 1 10000) (logiota steps 1 0))) @@ -207,8 +236,9 @@ define* : plot-benchmark-result bench H P : make-covariance-matrix-with-offdiagonals-using-stds x^b-std y⁰-pos : map car bench y⁰ : append-map cdr bench - y⁰-std : list-ref (sort y⁰ <) : round : / (length y⁰) 32 ; lower octile median - R : make-covariance-matrix-with-offdiagonals-using-stds : list-ec (: i (length bench)) y⁰-std + y⁰-stds : list-ec (: i y⁰) {i * 0.2} ; enforcing 20% max std in benchmark-run + y⁰-std : list-ref (sort y⁰ <) : round : / (length y⁰) 8 ; lower octile median + R : make-covariance-matrix-with-offdiagonals-using-stds y⁰-stds optimized : EnSRF H x^b P y⁰ R y⁰-pos ensemble-member-count x-opt : list-ref optimized 0 x-deviations : list-ref optimized 1