(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