From dda4e944777644a6cca7cb01b05d68017fe42d1b Mon Sep 17 00:00:00 2001 From: Dario Malchiodi Date: Sun, 20 Oct 2024 14:26:54 +0200 Subject: [PATCH] enhanced tests for kernels --- mulearn/kernel.py | 10 +++-- tests/test_kernel.py | 104 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 22 deletions(-) diff --git a/mulearn/kernel.py b/mulearn/kernel.py index a5ba468..02c4b04 100644 --- a/mulearn/kernel.py +++ b/mulearn/kernel.py @@ -18,8 +18,7 @@ class Kernel: def __init__(self): """Create an instance of :class:`Kernel`.""" - self.precomputed = False - self.kernel_computations = None + pass def compute(self, arg_1, arg_2): """Compute the kernel value, given two arrays of arguments. @@ -290,7 +289,6 @@ def __init__(self, kernel_computations): bidimensional array. """ super().__init__() - self.precomputed = True try: (rows, columns) = np.array(kernel_computations).shape except ValueError: @@ -333,3 +331,9 @@ def compute(self, arg_1, arg_2): def __repr__(self): """Return the python representation of the kernel.""" return f"PrecomputedKernel({self.kernel_computations})" + + def __eq__(self, other): + """Check kernel equality w.r.t. other objects.""" + return type(self) is type(other) \ + and np.array_equal(self.kernel_computations, + other.kernel_computations) diff --git a/tests/test_kernel.py b/tests/test_kernel.py index b66b270..5487b89 100644 --- a/tests/test_kernel.py +++ b/tests/test_kernel.py @@ -1,11 +1,35 @@ - +import json import numpy as np +import os +import pickle import unittest import mulearn.kernel as kernel +class BaseTest: + def _test_serialize(self, kernel): + s = pickle.dumps(kernel) + kernel_clone = pickle.loads(s) + self.assertEqual(kernel, kernel_clone) + + def _test_persist(self, kernel): + with open('object.pickle', 'wb') as f: + pickle.dump(kernel, f) + + with open('object.pickle', 'rb') as f: + kernel_clone = pickle.load(f) + + os.remove('object.pickle') -class Test_LinearKernel(unittest.TestCase): + self.assertEqual(kernel, kernel_clone) + + def _test_json(self, kernel, target): + s = json.dumps(kernel) + repr = json.loads(s) + self.assertEqual(repr, target) + + +class Test_LinearKernel(BaseTest, unittest.TestCase): def test_compute(self): k =kernel.LinearKernel() self.assertEqual(k.compute(np.array([1, 0, 1]).reshape(1,-1), @@ -23,9 +47,19 @@ def test_compute(self): with self.assertRaises(ValueError): k.compute(np.array([1, 0, 1]).reshape(1,-1), np.array([2, 2]).reshape(1,-1)) - - -class TestPolynomialKernel(unittest.TestCase): + + def test_serialize(self): + self._test_serialize(kernel.LinearKernel()) + + def test_persists(self): + self._test_persist(kernel.LinearKernel()) + + def test_json(self): + self._test_json(kernel.LinearKernel(), + {'class': 'LinearKernel'}) + + +class TestPolynomialKernel(BaseTest, unittest.TestCase): def test_compute(self): with self.assertRaises(ValueError): kernel.PolynomialKernel(3.2) @@ -51,10 +85,23 @@ def test_compute(self): with self.assertRaises(ValueError): p.compute(np.array((1, 0, 2)).reshape(1,-1), np.array((-1, 2)).reshape(1,-1)) - - - -class TestHomogeneousPolynomialKernel(unittest.TestCase): + + def test_serialize(self): + for d in [2, 5]: + self._test_serialize(kernel.PolynomialKernel(d)) + + def test_persists(self): + for d in [2, 5]: + self._test_persist(kernel.PolynomialKernel(d)) + + def test_json(self): + for d in [2, 5]: + self._test_json(kernel.PolynomialKernel(d), + {'class': 'PolynomialKernel', 'degree': d}) + + + +class TestHomogeneousPolynomialKernel(BaseTest, unittest.TestCase): def test_compute(self): with self.assertRaises(ValueError): kernel.HomogeneousPolynomialKernel(3.2) @@ -82,8 +129,12 @@ def test_compute(self): h.compute(np.array((1, 0, 2)).reshape(1,-1), np.array((-1, 2)).reshape(1,-1)) + def test_serialize(self): + for d in [2, 5]: + self._test_serialize(kernel.HomogeneousPolynomialKernel(d)) + -class TestGaussianKernel(unittest.TestCase): +class TestGaussianKernel(BaseTest, unittest.TestCase): def test_compute(self): with self.assertRaises(ValueError): kernel.GaussianKernel(-5) @@ -102,9 +153,13 @@ def test_compute(self): with self.assertRaises(ValueError): k.compute(np.array([-1, 3.5]).reshape(1,-1), np.array((1, 3.2, 6)).reshape(1,-1)) + + def test_serialize(self): + for sigma in [0.1, 1]: + self._test_serialize(kernel.GaussianKernel(sigma)) -class TestHyperbolicKernel(unittest.TestCase): +class TestHyperbolicKernel(BaseTest, unittest.TestCase): def test_compute(self): k = kernel.HyperbolicKernel(1, 5) self.assertAlmostEqual(k.compute( @@ -122,27 +177,38 @@ def test_compute(self): with self.assertRaises(ValueError): k.compute(np.array([-1, 3.5]).reshape(1,-1), np.array((1, 3.2, 6)).reshape(1,-1)) + + def test_serialize(self): + for alpha in [0.1, 1]: + for beta in [0.1, 1]: + self._test_serialize(kernel.HyperbolicKernel(alpha, beta)) + +class TestPrecomputedKernel(BaseTest, unittest.TestCase): + def setUp(self): + self.kernel = kernel.PrecomputedKernel(np.array(([1, 2], [3, 4]))) -class TestPrecomputedKernel(unittest.TestCase): def test_compute(self): with self.assertRaises(ValueError): - kernel.PrecomputedKernel(np.array(((1, 2), (3, 4, 5)))) + kernel.PrecomputedKernel(np.array(([1, 2], [3, 4, 5]))) - k = kernel.PrecomputedKernel(np.array(((1, 2), (3, 4)))) - self.assertEqual(k.compute( + self.assertEqual(self.kernel.compute( np.array([1]).reshape(1,-1), np.array([1]).reshape(1,-1)), [4.0]) - self.assertEqual(k.compute( + self.assertEqual(self.kernel.compute( np.array([1]).reshape(1,-1), np.array([0]).reshape(1,-1)), [3.0]) with self.assertRaises(IndexError): - k.compute(np.array([1]).reshape(1,-1), np.array([2]).reshape(1,-1)) + self.kernel.compute(np.array([1]).reshape(1,-1), + np.array([2]).reshape(1,-1)) with self.assertRaises(IndexError): - k.compute(np.array([0]).reshape(1,-1), - np.array([1.6]).reshape(1,-1)) + self.kernel.compute(np.array([0]).reshape(1,-1), + np.array([1.6]).reshape(1,-1)) + + def test_serialize(self): + self._test_serialize(self.kernel) if __name__ == '__main__':