diff --git a/CHANGELOG.md b/CHANGELOG.md index 73e1ee5e2..f82116476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `qNIPV` not working with single `MIN` targets - Passing a `TargetTransformation` without passing `bounds` when createing a `NumericalTarget` now raises an error +- Crash when using `ContinuousCardinalityConstraint` caused by an unintended interplay + between constraints and dropped parameters yielding empty parameter sets ### Deprecations - Passing a dataframe via the `data` argument to `Objective.transform` is no longer diff --git a/baybe/searchspace/continuous.py b/baybe/searchspace/continuous.py index 26447faa1..5fedf3f4e 100644 --- a/baybe/searchspace/continuous.py +++ b/baybe/searchspace/continuous.py @@ -298,10 +298,14 @@ def _drop_parameters(self, parameter_names: Collection[str]) -> SubspaceContinuo return SubspaceContinuous( parameters=[p for p in self.parameters if p.name not in parameter_names], constraints_lin_eq=[ - c._drop_parameters(parameter_names) for c in self.constraints_lin_eq + c._drop_parameters(parameter_names) + for c in self.constraints_lin_eq + if set(c.parameters) - set(parameter_names) ], constraints_lin_ineq=[ - c._drop_parameters(parameter_names) for c in self.constraints_lin_ineq + c._drop_parameters(parameter_names) + for c in self.constraints_lin_ineq + if set(c.parameters) - set(parameter_names) ], ) diff --git a/tests/constraints/test_cardinality_constraint_continuous.py b/tests/constraints/test_cardinality_constraint_continuous.py index e1da64f37..69aa71084 100644 --- a/tests/constraints/test_cardinality_constraint_continuous.py +++ b/tests/constraints/test_cardinality_constraint_continuous.py @@ -169,3 +169,36 @@ def test_random_recommender_with_cardinality_constraint( _validate_samples( recommendations, max_cardinality=2, min_cardinality=1, batch_size=batch_size ) + + +def test_empty_constraints_after_cardinality_constraint(): + """Constraints that have no more parameters left due to activated + cardinality constraints do not cause crashes.""" # noqa + + N_PARAMETERS = 2 + + parameters = [ + NumericalContinuousParameter(name=f"x_{i+1}", bounds=(0, 1)) + for i in range(N_PARAMETERS) + ] + constraints = [ + ContinuousLinearConstraint( + parameters=["x_1"], + operator="=", + coefficients=[1.0], + rhs=0.3, + ), + ContinuousLinearConstraint( + parameters=["x_2"], + operator="<=", + coefficients=[1.0], + rhs=0.6, + ), + ContinuousCardinalityConstraint( + parameters=["x_1", "x_2"], + max_cardinality=1, + min_cardinality=1, + ), + ] + subspace = SubspaceContinuous.from_product(parameters, constraints) + subspace.sample_uniform(1)