Source code for QHyper.optimizers.grid_search

# This work was supported by the EuroHPC PL infrastructure funded at the
# Smart Growth Operational Programme (2014-2020), Measure 4.2
# under the grant agreement no. POIR.04.02.00-00-D014/20-00


from typing import Callable
import numpy as np
from numpy.typing import NDArray

from QHyper.optimizers.util import run_parallel
from QHyper.optimizers.base import (
    OptimizationResult, Optimizer, OptimizerError, OptimizationParameter)


[docs] class GridSearch(Optimizer): """ Grid search optimizer The grid search optimizer is a simple optimization algorithm that searches through the entire parameter space by evaluating the function at each point. This alogrithm requries the following parameters to be set: - `min` and `max` bounds for each parameter - `step` step values for each parameter Values for n-th parameter will be generated as: min[n], min[n] + step[n], min[n] + 2*step[n], ... < max[n] Attributes ---------- verbose : bool, default False Whether to print the optimization progress. disable_tqdm : bool, default True Whether to disable the tqdm progress bar. processes : int, default 1 The number of processes to use for parallel computation. """ verbose: bool disable_tqdm: bool processes: int = 1 def __init__( self, verbose: bool = False, disable_tqdm: bool = True, processes: int = 1, ) -> None: self.verbose = verbose self.disable_tqdm = disable_tqdm self.processes = processes def _generate_grid(self, params: OptimizationParameter ) -> list[list[float]]: return np.stack( np.meshgrid( *[np.arange(min_, max_, step) for min_, max_, step in zip(params.min, params.max, params.step)] ), axis=-1 ).reshape(-1, len(params))
[docs] def minimize( self, func: Callable[[list[float]], OptimizationResult], init: OptimizationParameter | None ) -> OptimizationResult: if init is None: raise OptimizerError("Optimization parameter must be provided.") init.assert_bounds() init.assert_step() hyperparams = self._generate_grid(init) results = run_parallel( func, hyperparams, self.processes, self.disable_tqdm) min_idx = np.argmin([result.value for result in results]) if self.verbose: print(f"Best result: {results[min_idx].value}") print(f"Values: {sorted([v.value for v in results])}") history = [OptimizationResult(res.value, params, [[res]]) for res, params in zip(results, hyperparams)] return OptimizationResult( value=results[min_idx].value, params=hyperparams[min_idx], history=[history] )