"""core/optimizer.py — FellowOptimizer (hill-climbing adaptatif)""" import math, random from typing import Callable, List, Tuple class FellowOptimizer: def __init__(self, objective: Callable[[List[float]], float], bounds: List[Tuple[float, float]], max_evals: int = 500): self.obj = objective self.bounds = bounds self.max_evals = max_evals def optimize(self) -> Tuple[List[float], List[float]]: ndim = len(self.bounds) best = [random.uniform(lo, hi) for lo, hi in self.bounds] best_val = self.obj(best) history = [best_val] step_size = 0.1 for i in range(self.max_evals - 1): # Décroissance adaptative du pas decay = 1.0 - (i / self.max_evals) * 0.5 candidate = [ max(lo, min(hi, x + random.gauss(0, step_size * (hi - lo) * decay))) for x, (lo, hi) in zip(best, self.bounds) ] val = self.obj(candidate) if val < best_val: best, best_val = candidate, val step_size = min(0.2, step_size * 1.1) else: step_size = max(0.01, step_size * 0.98) history.append(best_val) return best, history