From 8bf98b4e0b9e1aefbad13fe87c9176e24249deca Mon Sep 17 00:00:00 2001 From: Thijs Snelleman Date: Wed, 19 Nov 2025 13:32:30 +0100 Subject: [PATCH 1/5] Adding new test and docs for issue --- src/ConfigSpace/util.py | 9 +++++++++ test/test_configuration_space.py | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/ConfigSpace/util.py b/src/ConfigSpace/util.py index f93baab4..64474b6c 100644 --- a/src/ConfigSpace/util.py +++ b/src/ConfigSpace/util.py @@ -572,6 +572,15 @@ def check_configuration( # noqa: D103 vector: np.ndarray, allow_inactive_with_values: bool = False, ) -> None: + """Checks whether a given parameter vector is valid according to the conditionals and forbiddens. + + Raises an Exception if the vector is not valid. + + Args: + space: Configuration space + vector: Parameter vector + allow_inactive_with_values: If True, inactive parameters are allowed to have values in the vector. + """ activated = np.isfinite(vector) # Make sure the roots are all good diff --git a/test/test_configuration_space.py b/test/test_configuration_space.py index 381e3f9c..5ff7bb34 100644 --- a/test/test_configuration_space.py +++ b/test/test_configuration_space.py @@ -616,6 +616,39 @@ def test_check_configuration2(): configuration.check_valid_configuration() +def test_check_configuration3(): + # Test that hyperparameters that follow the conditions and forbiddens will still be rejected if out parameter bounds + cs = ConfigurationSpace( + space=[ + NormalIntegerHyperparameter("a", mu=50, sigma=10, lower=1, upper=10), + UniformIntegerHyperparameter("b", lower=1, upper=100), + NormalFloatHyperparameter("c", lower=0, upper=1, mu=0.25, sigma=0.12), + UniformIntegerHyperparameter("d", lower=0, upper=1), + BetaFloatHyperparameter("e", lower=0, upper=1, alpha=1, beta=1), + CategoricalHyperparameter("f", ["Yes", "No", "Maybe"]), + OrdinalHyperparameter("g", ["Low", "Medium", "High"]), + ], + ) + cs.add( + NotEqualsCondition(cs["b"], cs["a"], 10), + ForbiddenEqualsClause(cs["c"], 0), + ForbiddenEqualsClause(cs["d"], 1), + ForbiddenEqualsClause(cs["e"], 0), + ForbiddenEqualsClause(cs["e"], 1), + ForbiddenAndConjunction( + ForbiddenEqualsClause(cs["f"], "No"), + ForbiddenEqualsClause(cs["g"], "Low"), + ), + ) + sample = cs.sample_configuration() + assert cs.check_configuration(sample) is None # Base sample should pass + + # Parameter A has no conditions; check if the configuration fails if a > 10 + sample["a"] = 101 + with pytest.raises(IllegalValueError): + cs.check_configuration(sample) + + def test_check_forbidden_with_sampled_vector_configuration(): cs = ConfigurationSpace() metric = CategoricalHyperparameter("metric", ["minkowski", "other"]) From 95508208bb1e1b26571962539300cca0ad10a6a5 Mon Sep 17 00:00:00 2001 From: Thijs Snelleman Date: Wed, 19 Nov 2025 13:35:41 +0100 Subject: [PATCH 2/5] test fix --- test/test_configuration_space.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_configuration_space.py b/test/test_configuration_space.py index 5ff7bb34..5d30c66b 100644 --- a/test/test_configuration_space.py +++ b/test/test_configuration_space.py @@ -644,9 +644,8 @@ def test_check_configuration3(): assert cs.check_configuration(sample) is None # Base sample should pass # Parameter A has no conditions; check if the configuration fails if a > 10 - sample["a"] = 101 with pytest.raises(IllegalValueError): - cs.check_configuration(sample) + sample["a"] = 101 def test_check_forbidden_with_sampled_vector_configuration(): From fc7de13860fbae4753caa8636f91bf288b4df94b Mon Sep 17 00:00:00 2001 From: Thijs Snelleman Date: Wed, 19 Nov 2025 13:41:38 +0100 Subject: [PATCH 3/5] Update to avoid using deprecated code in test --- test/test_configuration_space.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_configuration_space.py b/test/test_configuration_space.py index 5d30c66b..63f75bd4 100644 --- a/test/test_configuration_space.py +++ b/test/test_configuration_space.py @@ -641,7 +641,7 @@ def test_check_configuration3(): ), ) sample = cs.sample_configuration() - assert cs.check_configuration(sample) is None # Base sample should pass + assert sample.check_valid_configuration() is None # Base sample should pass # Parameter A has no conditions; check if the configuration fails if a > 10 with pytest.raises(IllegalValueError): From a63597fb4fe6eb1e0448a52ac3e5502ef5fb24ae Mon Sep 17 00:00:00 2001 From: Thijs Snelleman Date: Thu, 27 Nov 2025 10:33:53 +0100 Subject: [PATCH 4/5] Fixing test; forcibly broken currently untill PR414 is merged --- src/ConfigSpace/configuration.py | 11 +++++++++++ src/ConfigSpace/util.py | 8 ++++---- test/test_configuration_space.py | 10 +++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/ConfigSpace/configuration.py b/src/ConfigSpace/configuration.py index 1b556f7f..bebeab2b 100644 --- a/src/ConfigSpace/configuration.py +++ b/src/ConfigSpace/configuration.py @@ -157,6 +157,17 @@ def check_valid_configuration(self) -> None: """ from ConfigSpace.util import check_configuration + # Verify that the values are legal + for hyperparameter in self.config_space.get_hyperparameters(): + value = self.get(hyperparameter.name, NotSet) + print(hyperparameter) + print(value) + print() + if value is not NotSet and not hyperparameter.legal_value( + value + ): + raise IllegalValueError(hyperparameter, value) + check_configuration( self.config_space, self._vector, diff --git a/src/ConfigSpace/util.py b/src/ConfigSpace/util.py index 64474b6c..04e4090d 100644 --- a/src/ConfigSpace/util.py +++ b/src/ConfigSpace/util.py @@ -572,14 +572,14 @@ def check_configuration( # noqa: D103 vector: np.ndarray, allow_inactive_with_values: bool = False, ) -> None: - """Checks whether a given parameter vector is valid according to the conditionals and forbiddens. + """Check if a given hyperparameter vector is valid according to the conditionals and forbiddens. Raises an Exception if the vector is not valid. Args: - space: Configuration space - vector: Parameter vector - allow_inactive_with_values: If True, inactive parameters are allowed to have values in the vector. + space: Configuration space the configuration belongs to. + vector: The hyperparameter vector to check. + allow_inactive_with_values: If True, inactive hyperparameters are allowed to have values in the vector. """ activated = np.isfinite(vector) diff --git a/test/test_configuration_space.py b/test/test_configuration_space.py index 63f75bd4..89ce7d81 100644 --- a/test/test_configuration_space.py +++ b/test/test_configuration_space.py @@ -643,9 +643,13 @@ def test_check_configuration3(): sample = cs.sample_configuration() assert sample.check_valid_configuration() is None # Base sample should pass - # Parameter A has no conditions; check if the configuration fails if a > 10 - with pytest.raises(IllegalValueError): - sample["a"] = 101 + # Parameter A has no conditions; check if the configuration fails if a is out of bounds + sample["a"] = 10 + # NOTE: This test currently does not work as adaptive updating of bounds is not merged yet see PR414 + cs["a"].upper = 9 # Adapt upper bound afterwards + + with pytest.raises(IllegalValueError): # Check should fail now + sample.check_valid_configuration() def test_check_forbidden_with_sampled_vector_configuration(): From a414c6d6d44ad63684140ad7a92984f40a9f4dd8 Mon Sep 17 00:00:00 2001 From: Thijs Snelleman Date: Mon, 5 Jan 2026 10:25:25 +0100 Subject: [PATCH 5/5] Update --- src/ConfigSpace/configuration.py | 3 --- test/test_configuration_space.py | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ConfigSpace/configuration.py b/src/ConfigSpace/configuration.py index bebeab2b..046b1b29 100644 --- a/src/ConfigSpace/configuration.py +++ b/src/ConfigSpace/configuration.py @@ -160,9 +160,6 @@ def check_valid_configuration(self) -> None: # Verify that the values are legal for hyperparameter in self.config_space.get_hyperparameters(): value = self.get(hyperparameter.name, NotSet) - print(hyperparameter) - print(value) - print() if value is not NotSet and not hyperparameter.legal_value( value ): diff --git a/test/test_configuration_space.py b/test/test_configuration_space.py index 89ce7d81..70156450 100644 --- a/test/test_configuration_space.py +++ b/test/test_configuration_space.py @@ -648,6 +648,7 @@ def test_check_configuration3(): # NOTE: This test currently does not work as adaptive updating of bounds is not merged yet see PR414 cs["a"].upper = 9 # Adapt upper bound afterwards + # TODO: This test does not work as dynamic bound adapting has not been merged yet with pytest.raises(IllegalValueError): # Check should fail now sample.check_valid_configuration()