QuaPy/quapy/tests/test_bayesian_utils.py

70 lines
2.6 KiB
Python

import unittest
import numpy as np
from quapy.method._bayesian import (
_validate_temperature,
_resolve_dirichlet_prior,
kl_div,
js_div,
normalized,
lambda_inverse,
lambda_forward,
)
class TestBayesianUtils(unittest.TestCase):
"""
Smoke tests for the pure-numpy helper functions in method/_bayesian.py. These do not require the
optional jax/stan/numpyro dependencies (unlike BayesianKDEy/BayesianMAPLS themselves), so they can
run regardless of whether `quapy[bayes]` is installed.
"""
def test_validate_temperature(self):
self.assertEqual(_validate_temperature(2), 2.0)
self.assertEqual(_validate_temperature(0.5), 0.5)
with self.assertRaises(ValueError):
_validate_temperature(0)
with self.assertRaises(ValueError):
_validate_temperature(-1)
with self.assertRaises(ValueError):
_validate_temperature('not-a-number')
def test_resolve_dirichlet_prior(self):
np.testing.assert_array_equal(_resolve_dirichlet_prior('uniform', n_classes=3), np.ones(3))
np.testing.assert_array_equal(_resolve_dirichlet_prior(2.5, n_classes=3), np.full(3, 2.5))
np.testing.assert_array_equal(_resolve_dirichlet_prior([1, 2, 3], n_classes=3), np.array([1., 2., 3.]))
with self.assertRaises(ValueError):
_resolve_dirichlet_prior([1, 2], n_classes=3) # wrong shape
with self.assertRaises(ValueError):
_resolve_dirichlet_prior('unknown-prior', n_classes=3)
def test_kl_div_and_js_div(self):
p = np.array([0.5, 0.5])
self.assertAlmostEqual(kl_div(p, p), 0.0, places=6)
self.assertAlmostEqual(js_div(p, p), 0.0, places=6)
q = np.array([0.9, 0.1])
self.assertGreater(kl_div(p, q), 0.0)
self.assertGreater(js_div(p, q), 0.0)
# JS divergence is symmetric, unlike KL
self.assertAlmostEqual(js_div(p, q), js_div(q, p), places=6)
def test_normalized(self):
# normalized() operates on a batch of row vectors, shape (n_samples, n_features)
a = np.array([[3.0, 4.0], [0.0, 0.0]])
normed = normalized(a)
self.assertAlmostEqual(np.linalg.norm(normed[0]), 1.0, places=6)
# an all-zero row should not raise (guarded division), and stays all-zero
np.testing.assert_array_equal(normed[1], np.array([0.0, 0.0]))
def test_lambda_inverse_forward_roundtrip(self):
dpq, lam = 0.3, 0.4
gamma = lambda_inverse(dpq, lam)
recovered_lam = lambda_forward(dpq, gamma)
self.assertAlmostEqual(recovered_lam, lam, places=6)
if __name__ == '__main__':
unittest.main()