"""Tests for the abstract Optimizer base class and dataclasses.""" from __future__ import annotations import time import numpy as np import pytest from ahdcma.algorithms.base import ( History, OptimizationResult, Optimizer, SearchSpace, ) def test_search_space_unit_cube() -> None: sp = SearchSpace.unit_cube(4) assert sp.dim == 4 assert np.all(sp.lower == 0.0) assert np.all(sp.upper == 1.0) def test_search_space_validation() -> None: with pytest.raises(ValueError): SearchSpace(dim=3, lower=np.zeros(2), upper=np.ones(3)) with pytest.raises(ValueError): SearchSpace(dim=2, lower=np.array([0.0, 1.0]), upper=np.array([1.0, 0.5])) def test_search_space_clip() -> None: sp = SearchSpace.unit_cube(3) x = np.array([-0.5, 0.3, 1.7]) np.testing.assert_array_equal(sp.clip(x), np.array([0.0, 0.3, 1.0])) def test_history_append_and_len() -> None: h = History() assert len(h) == 0 h.append(0, np.zeros((4, 2)), np.array([1.0, 0.5, 2.0, 1.5]), mode="explore", entropy=2.3) assert len(h) == 1 assert h.best_fitness[0] == 0.5 assert h.mode_per_gen[0] == "explore" assert h.entropy_per_gen[0] == pytest.approx(2.3) def test_optimizer_subclass_minimal() -> None: class _Const(Optimizer): def optimize(self) -> OptimizationResult: x = np.full(self.search_space.dim, 0.5) f = float(self.fitness_fn(x)) self._history.append(0, x[None, :], np.array([f]), mode="hybrid") return OptimizationResult( best_x=x, best_f=f, history=self._history, config_snapshot=self.config, run_id=self.run_id, wall_time=0.0, ) sp = SearchSpace.unit_cube(3) opt = _Const(config={"foo": 1}, fitness_fn=lambda x: float(np.sum(x**2)), search_space=sp) t0 = time.time() result = opt.optimize() assert result.best_f == pytest.approx(0.75) assert result.run_id == "anonymous" assert len(opt.get_history()) == 1 assert time.time() - t0 < 1.0