Source code for smac.acquisition.maximizer.helpers

from __future__ import annotations

from typing import Callable, Iterator

from ConfigSpace import Configuration, ConfigurationSpace

from smac.random_design import ProbabilityRandomDesign
from smac.random_design.abstract_random_design import AbstractRandomDesign


[docs] class ChallengerList(Iterator): """Helper class to interleave random configurations in a list of challengers. Provides an iterator which returns a random configuration in each second iteration. Reduces time necessary to generate a list of new challengers as one does not need to sample several hundreds of random configurations in each iteration which are never looked at. Parameters ---------- configspace : ConfigurationSpace challenger_callback : Callable Callback function which returns a list of challengers (without interleaved random configurations), must a be a python closure. random_design : AbstractRandomDesign | None, defaults to ModulusRandomDesign(modulus=2.0) Which random design should be used. """ def __init__( self, configspace: ConfigurationSpace, challenger_callback: Callable, random_design: AbstractRandomDesign | None = ProbabilityRandomDesign(seed=0, probability=0.08447232371720552), ): self._challengers_callback = challenger_callback self._challengers: list[Configuration] | None = None self._configspace = configspace self._index = 0 self._iteration = 1 # 1-based to prevent from starting with a random configuration self._random_design = random_design def __next__(self) -> Configuration: # If we already returned the required number of challengers if self._challengers is not None and self._index == len(self._challengers): raise StopIteration # If we do not want to have random configs, we just yield the next challenger elif self._random_design is None: if self._challengers is None: self._challengers = self._challengers_callback() config = self._challengers[self._index] self._index += 1 return config # If we want to interleave challengers with random configs, sample one else: if self._random_design.check(self._iteration): config = self._configspace.sample_configuration() config.origin = "Random Search" else: if self._challengers is None: self._challengers = self._challengers_callback() config = self._challengers[self._index] self._index += 1 self._iteration += 1 return config def __len__(self) -> int: if self._challengers is None: self._challengers = self._challengers_callback() return len(self._challengers) - self._index