Skip to content

Commit

Permalink
Gamma optimizations and benchmarks (#69)
Browse files Browse the repository at this point in the history
* initial commit

* use test-runner, add baseline spec
  • Loading branch information
eightysteele authored Jun 1, 2024
1 parent 495a6c7 commit bb68e04
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .dir-locals.el
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
((nil
. ((cider-default-cljs-repl . node)
(cider-preferred-build-tool . clojure-cli)
(cider-clojure-cli-aliases . ":test:nextjournal/clerk")
(cider-clojure-cli-aliases . ":benchmark:test:nextjournal/clerk")

;; Custom indentation:
(eval . (put-clojure-indent 'gen 1)))))
4 changes: 4 additions & 0 deletions bb.edn
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
{:doc "Run CLJS tests."
:task (shell "npm run test")}

benchmark:clj
{:doc "Run CLJ benchmarks."
:task (shell "clojure -X:benchmark:test")}

build-static
{:doc "Generate a fresh static build."
:task
Expand Down
91 changes: 91 additions & 0 deletions benchmark/gen/distribution/math/gamma_benchmark.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
(ns gen.distribution.math.gamma-benchmark
(:require [clojure.test :refer [deftest is testing]]
[same.core :refer [ish? with-comparator]]
[gen.generators :refer [within]]
[gen.distribution.math.gamma :as g]
[criterium.core :as crit]))

(def ^:no-doc ^:const lanczos-approximation-baseline
[{:n 15
:x 9
:mean 3.127368933269932E-6
:variance 1.5780434242573877E-14
:lower-q 2.984515105404977E-6
:upper-q 3.320172412426692E-6}
{:n 15
:x 100
:mean 2.0160584455226908E-7
:variance 7.928671640576774E-18
:lower-q 1.9907849968797706E-7
:upper-q 2.0489675953499433E-7}
{:n 15
:x 170
:mean 2.040524636004644E-7
:variance 5.795520133553684E-18
:lower-q 2.0120967339244923E-7
:upper-q 2.0719692107157572E-7}])

(deftest ^:benchmark lanczos-approximation-benchmark
[]
(let [f (fn[b]
(let [n (:n b)
x (:x b)
mean (:mean b)
variance (:variance b)
lower-q (:lower-q b)
upper-q (:upper-q b)
stats (crit/quick-benchmark
(dotimes [_ n]
(g/lanczos-approximation x)) {})]
(testing "against lanczos approximation baseline"
(with-comparator (within 1e-3)
(is (ish? mean (first (:mean stats))) x)
(is (ish? variance (first (:variance stats))) x)
(is (ish? lower-q (first (:lower-q stats))) x)
(is (ish? upper-q (first (:upper-q stats))) x)))))]
(run! f lanczos-approximation-baseline)))

(deftest ^:benchmark inv-gamma-1pm1-benchmark
[]
(let [n 15
x [-0.05 1.5]
f (fn[x]
(println "inv-gamma-1pm1: " x)
(crit/quick-bench
(dotimes [_ n]
(g/inv-gamma-1pm1 x))))]
(run! f x)))

(deftest ^:benchmark log-gamma-1p-benchmark
[]
(let [n 15
x [-0.05 1.5]
f (fn[x]
(println "log-gamma-1p: " x)
(crit/quick-bench
(dotimes [_ n]
(g/log-gamma-1p x))))]
(run! f x)))


(deftest ^:benchmark log-gamma-benchmark
[]
(let [n 15
x [0.1 1.5 2.5 8.0 10.0]
f (fn[x]
(println "log-gamma: " x)
(crit/quick-bench
(dotimes [_ n]
(g/log-gamma x))))]
(run! f x)))

(deftest ^:benchmark gamma-benchmark
[]
(let [n 15
x [-0.001 0.1 1.5 2.5 8.0 10.0]
f (fn[x]
(println "gamma: " x)
(crit/quick-bench
(dotimes [_ n]
(g/gamma x))))]
(run! f x)))
9 changes: 9 additions & 0 deletions deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@
org.clojure/test.check {:mvn/version "1.1.1"}
same/ish {:mvn/version "0.1.6"}}}

:benchmark
{:extra-paths ["benchmark"]
:extra-deps {io.github.cognitect-labs/test-runner
{:git/tag "v0.5.1" :git/sha "dfb30dd"}
criterium/criterium {:mvn/version "0.4.6"}}
:main-opts ["-m" "cognitect.test-runner"]
:exec-args {:includes [:benchmark] :dirs ["benchmark"] :patterns [".*-benchmark$"]}
:exec-fn cognitect.test-runner.api/test}

;; See https://github.com/cognitect-labs/test-runner for invocation
;; instructions, or call `clojure -X:test:runner`.
:runner
Expand Down
19 changes: 12 additions & 7 deletions src/gen/distribution/math/gamma.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
;;
;; Apache Commons Numbers Gamma. Github.
;; https://github.com/apache/commons-numbers-gamma

;;
;; Weisstein, Eric W. Lanczos Approximation. From MathWorld--A Wolfram Web
;; Resource. https://mathworld.wolfram.com/LanczosApproximation.html
;;
Expand All @@ -47,7 +47,7 @@
;; Software (TOMS), 12(4), pp.377-393.
;; https://dl.acm.org/doi/10.1145/22721.23109

(def LANCZOS_G
(def ^:const LANCZOS_G
"The Lanczos constant.
Based on Godfrey's research (Godfrey, P., 2001)."
Expand All @@ -59,7 +59,8 @@
Based on Wolfram (Weisstein, Eric W., Lanczos Approximation). The coefficients
were computed by Godfrey (Godfrey, P., 2001). See
`LanczosApproximation` (Apache Commons Numbers Gamma)."
[x]
^double
[^double x]
{:pre [(> x 8)]}
(let [c [[14 3.6899182659531625E-6]
[13 -2.6190838401581408E-5]
Expand All @@ -84,7 +85,8 @@
function (NSWC Mathematical Library, 1993) which defines the coefficients of
the Maclaurin series expansion (A, B, C, P, Q). See also `InvGamma1pm` (Apache
Commons Numbers Gamma)."
[x]
^double
[^double x]
{:pre [(>= x -0.5)
(<= x 1.5)]}
(let [t (if (<= x 0.5) x (- (- x 0.5) 0.5))
Expand Down Expand Up @@ -145,7 +147,8 @@
Based on the NSWC implementation (Morris, A.H., 1993). See the `DGMLN1`
function (NSWC Mathematical Library, 1993) and `LogGamma1p` (Apache Commons
Numbers Gamma)."
[x]
^double
[^double x]
{:pre [(>= x -0.5)
(<= x 1.5)]}
(- (Math/log1p (inv-gamma-1pm1 x))))
Expand All @@ -158,7 +161,8 @@
the NSWC implementation (Morris, A.H., 1993). See the `DGAMLN` function (NSWC
Mathematical Library, 1993). For x > 8, follows the Lanczos approximation
method. See `LogGamma` (Apache Commons Numbers Gamma)."
[x]
^double
[^double x]
{:pre [(pos? x)]}
(cond
(< x 0.5) (- (log-gamma-1p x) (Math/log x))
Expand All @@ -181,7 +185,8 @@
Based on Wolfram (Weisstein, Eric W., Gamma Function). Follows the NSWC
implementation (Morris, A.H., 1993). See the `DGAMMA` function (NSWC
Mathematical Library, 1993) and `Gamma` (Apache Commons Numbers Gamma)."
[x]
^double
[^double x]
(let [abs-x (abs x)]
(if (<= abs-x 20)
(if (>= x 1)
Expand Down
8 changes: 4 additions & 4 deletions src/gen/distribution/math/utils.cljc
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
(ns gen.distribution.math.utils
"Math utilities and constants.")

(def ^:no-doc log-pi
(def ^:no-doc ^:const log-pi
(Math/log Math/PI))

(def ^:no-doc log-2pi
(def ^:no-doc ^:const log-2pi
(Math/log (* 2 Math/PI)))

(def ^:no-doc sqrt-2pi
(def ^:no-doc ^:const sqrt-2pi
(Math/sqrt (* 2 Math/PI)))

(def ^:no-doc half-log-2pi
(def ^:no-doc ^:const half-log-2pi
(* 0.5 (Math/log (* 2.0 Math/PI))))

0 comments on commit bb68e04

Please sign in to comment.