import unittest import numpy as np import backend class ReproducibilityTest(unittest.TestCase): def setUp(self): backend.history, backend.configuration = [], None rng = np.random.default_rng(10) self.points = [{"x": float(x), "y": float(y), "label": -1 if x < y else 1} for x, y in rng.random((60, 2))] def request(self, method, seed=42, count=0, params=None): return {"points": self.points, "method": method, "seed": seed, "count": count, "classifier": "DecisionTreeClassifier", "params": params if params is not None else {"max_depth": 3}} def test_rebuild_and_remove_readd(self): for method in ("boosting", "bagging", "random_forest", "extra_trees"): with self.subTest(method=method): backend.history, backend.configuration = [], None original = [backend.train(self.request(method, count=i)) for i in range(3)] self.assertEqual(original[2], backend.train(self.request(method, count=2))) backend.history, backend.configuration = [], None rebuilt = [backend.train(self.request(method, count=i)) for i in range(3)] self.assertEqual(original, rebuilt) def test_seed_changes_random_models(self): for method in ("bagging", "random_forest", "extra_trees"): with self.subTest(method=method): first = backend.train(self.request(method, seed=42)) other = backend.train(self.request(method, seed=43)) self.assertNotEqual(first["tree"], other["tree"]) def test_explicit_random_state_still_reproduces_bagging(self): request = self.request("bagging", params={"random_state": 7, "max_depth": 3}) first = backend.train(request) self.assertEqual(first, backend.train(request)) self.assertEqual(backend.history[0]["estimator"].random_state, 7) def test_invalid_seeds(self): for seed in (-1, 2**32, 1.5, True, None, "42"): with self.subTest(seed=seed), self.assertRaisesRegex(ValueError, "Random seed"): backend.train(self.request("bagging", seed=seed)) if __name__ == "__main__": unittest.main()