Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 2.3.2

## Bugfixes
- Fix that config could be accidentally added twice to the runhistory (#1242)

# 2.3.1

## Bugfixes
Expand Down
4 changes: 2 additions & 2 deletions smac/intensifier/successive_halving.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions smac/main/smbo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
)

Expand Down Expand Up @@ -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(
Expand Down
21 changes: 21 additions & 0 deletions smac/runhistory/runhistory.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,25 @@ 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_values = list(dict(config).values())
config_values = json.loads(json.dumps(config_values, cls=NumpyEncoder))
Copy link
Copy Markdown
Contributor

@dengdifan dengdifan Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we directly call

config_dict=json.loads(json.dumps(config, cls=NumpyEncoder))
config=Configuration(configuration_space=config.config_space, values=config_dict))

?

config_keys = list(dict(config).keys())
config = Configuration(configuration_space=config.config_space, values=dict(zip(config_keys, config_values)))
return config

def add(
self,
config: Configuration,
Expand Down Expand Up @@ -211,6 +230,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()
Expand Down
2 changes: 1 addition & 1 deletion smac/utils/data_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Loading