diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a357ade9..bf165f14e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.3.2 + +## Bugfixes +- Fix that config could be accidentally added twice to the runhistory (#1242) + # 2.3.1 ## Bugfixes diff --git a/smac/intensifier/successive_halving.py b/smac/intensifier/successive_halving.py index 546a27377..9ba33c5b8 100644 --- a/smac/intensifier/successive_halving.py +++ b/smac/intensifier/successive_halving.py @@ -209,7 +209,7 @@ def get_state(self) -> dict[str, Any]: # noqa: D102 for key in list(self._tracker.keys()): for seed, configs in self._tracker[key]: # We have to make key serializable - new_key = f"{key[0]},{key[1]}" + new_key = f"{key[0]},{key[1]}" # noqa: E231 tracker[new_key].append((seed, [dict(config) for config in configs])) return {"tracker": tracker} @@ -260,7 +260,7 @@ def print_tracker(self) -> None: messages.append(f"--- Bracket {bracket} / Stage {stage}: {counter} configs") if len(messages) > 0: - logger.debug(f"{self.__class__.__name__} statistics:") + logger.debug(f"{self.__class__.__name__} statistics:") # noqa: E231 for message in messages: logger.debug(message) diff --git a/smac/main/smbo.py b/smac/main/smbo.py index 11c4d817b..506a886c6 100644 --- a/smac/main/smbo.py +++ b/smac/main/smbo.py @@ -325,8 +325,8 @@ def optimize(self, *, data_to_scatter: dict[str, Any] | None = None) -> Configur # Some statistics logger.debug( - f"Remaining wallclock time: {self.remaining_walltime}; " - f"Remaining cpu time: {self.remaining_cputime}; " + f"Remaining wallclock time: {self.remaining_walltime}; " # noqa: E702 + f"Remaining cpu time: {self.remaining_cputime}; " # noqa: E702 f"Remaining trials: {self.remaining_trials}" ) @@ -538,7 +538,7 @@ def _initialize_state(self) -> None: ) logger.info( f"Found old run in `{self._scenario.output_directory}` but it is not the same as the current " - f"one:\n{diff}" + f"one:\n{diff}" # noqa: E231 ) feedback = input( diff --git a/smac/runhistory/runhistory.py b/smac/runhistory/runhistory.py index 6f648a4a0..14e024c72 100644 --- a/smac/runhistory/runhistory.py +++ b/smac/runhistory/runhistory.py @@ -167,6 +167,24 @@ def empty(self) -> bool: """ return len(self._data) == 0 + def _convert_config_to_pure_python(self, config: Configuration) -> Configuration: + """Convert config values from possibly numpy types to python built ins. + + Background: The configs are perceived as different when they have a np.int type instead of int. + + Args: + config (Configuration): Config to convert to pure python. + + Returns + ------- + Configuration + Config with only pure python types. + """ + config_dict = dict(config) + config_dict = json.loads(json.dumps(config_dict, cls=NumpyEncoder)) + config = Configuration(configuration_space=config.config_space, values=config_dict) + return config + def add( self, config: Configuration, @@ -211,6 +229,8 @@ def add( if additional_info is None: additional_info = {} + config = self._convert_config_to_pure_python(config) + # Squeeze is important to reduce arrays with one element # to scalars. cost_array = np.asarray(cost).squeeze() diff --git a/smac/utils/data_structures.py b/smac/utils/data_structures.py index 6468f43ab..c9e728cff 100644 --- a/smac/utils/data_structures.py +++ b/smac/utils/data_structures.py @@ -51,7 +51,7 @@ def recursively_compare_dicts( elif isinstance(d1, list) and isinstance(d2, list): if len(d1) != len(d2): - diff += [f"{level}: len1={len(d1)}; len2={len(d2)}"] + diff += [f"{level}: len1={len(d1)}; len2={len(d2)}"] # noqa: E702 # logger.info("{:<20} len1={}; len2={}".format(level, len(d1), len(d2))) # logger.info("len1={}; len2={}".format(len(d1), len(d2))) common_len = min(len(d1), len(d2))