Repository: HDembinski/numba-stats (language: python)

Issue:
Add lognormal



Discussion / hints:

Fix patch:
diff --git a/src/numba_stats/lognorm.py b/src/numba_stats/lognorm.py
new file mode 100644
index 0000000..b60f3fc
--- /dev/null
+++ b/src/numba_stats/lognorm.py
@@ -0,0 +1,42 @@
+import numba as nb
+import numpy as np
+from .norm import _cdf, _ppf
+
+
+_signatures = [
+    nb.float32(nb.float32, nb.float32, nb.float32, nb.float32),
+    nb.float64(nb.float64, nb.float64, nb.float64, nb.float64),
+]
+
+
+@nb.vectorize(_signatures, cache=True)
+def pdf(x, s, loc, scale):
+    """
+    Return probability density of normal distribution.
+    """
+    z = (x - loc) / scale
+    if z <= 0:
+        return 0.0
+    c = np.sqrt(2 * np.pi)
+    log_pdf = -0.5 * np.log(z) ** 2 / s ** 2 - np.log(s * z * c)
+    return np.exp(log_pdf) / scale
+
+
+@nb.vectorize(_signatures, cache=True)
+def cdf(x, s, loc, scale):
+    """
+    Evaluate cumulative distribution function of normal distribution.
+    """
+    z = (x - loc) / scale
+    if z <= 0:
+        return 0.0
+    return _cdf(np.log(z) / s)
+
+
+@nb.vectorize(_signatures)
+def ppf(p, s, loc, scale):
+    """
+    Return quantile of normal distribution for given probability.
+    """
+    z = np.exp(s * _ppf(p))
+    return scale * z + loc


Test patch:
diff --git a/tests/test_lognorm.py b/tests/test_lognorm.py
new file mode 100644
index 0000000..38f46f1
--- /dev/null
+++ b/tests/test_lognorm.py
@@ -0,0 +1,29 @@
+import scipy.stats as sc
+import numpy as np
+
+
+def test_lognorm_pdf():
+    from numba_stats import lognorm
+
+    x = np.linspace(0, 5, 10)
+    got = lognorm.pdf(x, 1.5, 0.1, 1.2)
+    expected = sc.lognorm.pdf(x, 1.5, 0.1, 1.2)
+    np.testing.assert_allclose(got, expected)
+
+
+def test_lognorm_cdf():
+    from numba_stats import lognorm
+
+    x = np.linspace(0, 5, 10)
+    got = lognorm.cdf(x, 1.5, 0.1, 1.2)
+    expected = sc.lognorm.cdf(x, 1.5, 0.1, 1.2)
+    np.testing.assert_allclose(got, expected)
+
+
+def test_lognorm_ppf():
+    from numba_stats import lognorm
+
+    p = np.linspace(0, 1, 10)
+    got = lognorm.ppf(p, 1.5, 0.1, 1.2)
+    expected = sc.lognorm.ppf(p, 1.5, 0.1, 1.2)
+    np.testing.assert_allclose(got, expected)
diff --git a/tests/test_norm.py b/tests/test_norm.py
new file mode 100644
index 0000000..033dd31
--- /dev/null
+++ b/tests/test_norm.py
@@ -0,0 +1,29 @@
+import scipy.stats as sc
+import numpy as np
+
+
+def test_norm_pdf():
+    from numba_stats import norm
+
+    x = np.linspace(-5, 5, 10)
+    got = norm.pdf(x, 1, 2)
+    expected = sc.norm.pdf(x, 1, 2)
+    np.testing.assert_allclose(got, expected)
+
+
+def test_norm_cdf():
+    from numba_stats import norm
+
+    x = np.linspace(-5, 5, 10)
+    got = norm.cdf(x, 1, 2)
+    expected = sc.norm.cdf(x, 1, 2)
+    np.testing.assert_allclose(got, expected)
+
+
+def test_norm_ppf():
+    from numba_stats import norm
+
+    p = np.linspace(0, 1, 10)
+    got = norm.ppf(p, 0, 1)
+    expected = sc.norm.ppf(p)
+    np.testing.assert_allclose(got, expected)
diff --git a/tests/test_stats.py b/tests/test_stats.py
index c821683..3d8e263 100644
--- a/tests/test_stats.py
+++ b/tests/test_stats.py
@@ -6,33 +6,6 @@
 import pytest
 
 
-def test_norm_pdf():
-    from numba_stats import norm
-
-    x = np.linspace(-5, 5, 10)
-    got = norm.pdf(x, 1, 2)
-    expected = sc.norm.pdf(x, 1, 2)
-    np.testing.assert_allclose(got, expected)
-
-
-def test_norm_cdf():
-    from numba_stats import norm
-
-    x = np.linspace(-5, 5, 10)
-    got = norm.cdf(x, 1, 2)
-    expected = sc.norm.cdf(x, 1, 2)
-    np.testing.assert_allclose(got, expected)
-
-
-def test_norm_ppf():
-    from numba_stats import norm
-
-    p = np.linspace(0, 1, 10)
-    got = norm.ppf(p, 0, 1)
-    expected = sc.norm.ppf(p)
-    np.testing.assert_allclose(got, expected)
-
-
 def test_poisson_pmf():
     from numba_stats import poisson