diff --git a/smac/configspace/util.py b/smac/configspace/util.py index 969c535e5..be5278390 100644 --- a/smac/configspace/util.py +++ b/smac/configspace/util.py @@ -8,5 +8,16 @@ def impute_inactive_hyperparameters(configs: List[Configuration]) -> np.ndarray: configs_array = np.array([config.get_array() for config in configs], dtype=np.float64) - configs_array[~np.isfinite(configs_array)] = -1 + configuration_space = configs[0].configuration_space + for hp in configuration_space.get_hyperparameters(): + default = hp._inverse_transform(hp.default) + idx = configuration_space.get_idx_by_hyperparameter_name(hp.name) + + # Create a mask which is True for all non-finite entries in column idx! + column_mask = np.zeros(configs_array.shape, dtype=np.bool) + column_mask[:, idx] = True + nonfinite_mask = ~np.isfinite(configs_array) + mask = column_mask & nonfinite_mask + + configs_array[mask] = default return configs_array \ No newline at end of file diff --git a/test/test_configspace/test_configspace.py b/test/test_configspace/test_configspace.py index 3f5a1c7eb..75f91554f 100644 --- a/test/test_configspace/test_configspace.py +++ b/test/test_configspace/test_configspace.py @@ -7,6 +7,9 @@ import unittest from ConfigSpace.io import pcs +from ConfigSpace.hyperparameters import CategoricalHyperparameter +from ConfigSpace.conditions import EqualsCondition +import smac.configspace class ConfigSpaceTest(unittest.TestCase): @@ -27,5 +30,21 @@ def test_spear(self): print(config.get_dictionary()) + def test_impute_inactive_hyperparameters(self): + cs = smac.configspace.ConfigurationSpace() + a = cs.add_hyperparameter(CategoricalHyperparameter('a', [0, 1], + default=0)) + b = cs.add_hyperparameter(CategoricalHyperparameter('b', [0, 1], + default=1)) + cs.add_condition(EqualsCondition(b, a, 1)) + cs.seed(1) + configs = cs.sample_configuration(size=100) + config_array = smac.configspace.impute_inactive_hyperparameters(configs) + for line in config_array: + if line[0] == 0: + self.assertEqual(line[1], 1) + + + if __name__ == "__main__": unittest.main() diff --git a/test/test_smbo/test_smbo.py b/test/test_smbo/test_smbo.py index d21042abc..9162aa736 100644 --- a/test/test_smbo/test_smbo.py +++ b/test/test_smbo/test_smbo.py @@ -211,7 +211,7 @@ def test_choose_next_empty_X_2(self): self.assertEqual(len(x), 1) self.assertIsInstance(x[0], Configuration) - @mock.patch('ConfigSpace.util.impute_inactive_values') + @mock.patch('smac.smbo.smbo.impute_inactive_hyperparameters') @mock.patch.object(EI, '__call__') @mock.patch.object(ConfigurationSpace, 'sample_configuration') def test_get_next_by_random_search_sorted(self, @@ -221,7 +221,7 @@ def test_get_next_by_random_search_sorted(self, values = (10, 1, 9, 2, 8, 3, 7, 4, 6, 5) patch_sample.return_value = [ConfigurationMock(i) for i in values] patch_ei.return_value = np.array([[_] for _ in values], dtype=float) - patch_impute.side_effect = lambda x: x + patch_impute.side_effect = lambda l: values smbo = SMAC(self.scenario, rng=1).solver rval = smbo._get_next_by_random_search(10, True) self.assertEqual(len(rval), 10) @@ -234,8 +234,7 @@ def test_get_next_by_random_search_sorted(self, # Check that config.get_array works as desired and imputation is used # in between np.testing.assert_allclose(patch_ei.call_args[0][0], - np.array(values, dtype=float) - .reshape((-1, 1))) + np.array(values, dtype=float)) @mock.patch.object(ConfigurationSpace, 'sample_configuration') def test_get_next_by_random_search(self, patch):