Conversation
4a381ec to
1c3bbef
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new batch-level discrete constraint (DiscreteBatchConstraint) that enforces a fixed discrete parameter value across all points in a recommended batch by optimizing over discrete (and hybrid) subspaces, aligning with the existing subspace-based infrastructure used for continuous cardinality constraints.
Changes:
- Introduces
DiscreteBatchConstraint(non-filtering, batch-level) plus validation preventing duplicate batch constraints per parameter. - Extends discrete/hybrid subspace infrastructure (
n_theoretical_subspaces, mask/config iterators, sampling helpers) and wires support intoBotorchRecommenderandRandomRecommenderwith compatibility gating for other recommenders. - Adds documentation and test coverage for discrete + hybrid subspace-generating constraints, replacing prior hybrid-only cardinality tests.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
baybe/constraints/discrete.py |
Adds DiscreteBatchConstraint and its subspace mask generation. |
baybe/constraints/validation.py |
Adds validation to prevent multiple batch constraints on the same parameter. |
baybe/constraints/__init__.py |
Exposes DiscreteBatchConstraint publicly. |
baybe/searchspace/discrete.py |
Adds discrete subspace-generating constraint plumbing and mask enumeration/sampling helpers. |
baybe/searchspace/continuous.py |
Renames/aligns to n_theoretical_subspaces and adds shuffled / with-replacement subspace configuration iteration. |
baybe/searchspace/core.py |
Adds combined discrete+continuous theoretical subspace counting and combined sampling utilities for hybrid spaces. |
baybe/recommenders/pure/base.py |
Adds supports_discrete_subspace_constraints gate and raises IncompatibilityError when unsupported. |
baybe/recommenders/pure/bayesian/botorch.py |
Implements discrete + hybrid optimization over subspaces when batch constraints are present. |
baybe/recommenders/pure/nonpredictive/sampling.py |
Updates RandomRecommender to respect discrete subspace-generating constraints. |
docs/userguide/constraints.md |
Documents DiscreteBatchConstraint and recommender compatibility. |
tests/constraints/test_batch_constraint.py |
Adds focused tests for the new constraint (behavior, validation, incompatibility, subspace counting/masks). |
tests/constraints/test_subspace_constraints_hybrid.py |
Adds parametrized hybrid tests covering discrete batch + (discrete/continuous) cardinality constraints. |
tests/constraints/test_cardinality_constraint_hybrid.py |
Removes older hybrid cardinality-only test file (superseded). |
CHANGELOG.md |
Records new user-facing feature entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This comment was marked as resolved.
This comment was marked as resolved.
dd5bbf6 to
23b3348
Compare
AVHopp
left a comment
There was a problem hiding this comment.
I do not have any major comments. I personally find it a bit weird that the concept of a "partition" is somehow identical in both discrete and continuous subspaces, but caused by completely different things. However, I do not see any more elegant solution to this, and this might also be personal preference.
| parameter — obtains a full batch recommendation from each partition, and | ||
| returns the batch with the highest joint acquisition value. | ||
|
|
||
| This constraint is not supported by all recommenders. It is not applied during |
There was a problem hiding this comment.
Do we maybe want to add a comment here that this results in an "overhead" in optimization/internal recommendations and might thus increase running time? I think this might be a reasonable comment as a lot of other constraints actually reduce running time by e.g. making the search space smaller.
There was a problem hiding this comment.
can we actually say that its always overhead? if i have only 1 partitioning cosntriant I think the overhead is almost non exisstent
Mentioning this is a good idea, but I would prob prefer the suer guide or have it mentioned at least in both places here and there
There was a problem hiding this comment.
Fine for me. Just important to make sure that this can result in an overhead at a suitable place would be perfectly fine imo.
| for c in self.constraints_batch | ||
| ) | ||
|
|
||
| def partition_masks( # noqa: DOC404 |
There was a problem hiding this comment.
Why this noqa? According to the documentation, this means "The types in the docstring’s Yields section and the return annotation in the signature are not consistent", why is this the case? Is this due to the use of Yields instead of Returns?
There was a problem hiding this comment.
there is some inconsitent lint enforcing for Yields versus Returns
While in Returns it is accepted by the linter that hte type hints are not repeated (which is also our convention) it is seemingly is not accepted that a Yields section does not repeat the type hints. To remain within our convention I ignored the linter here
maybe we should add this to global ignores?
There was a problem hiding this comment.
Thanks for the clarification. Not sure if we should add this to the global ignores, to me it rather feels like an issue with the plugin, and I would prefer local exceptions over a global one.
There was a problem hiding this comment.
hmm, but isnt that exactly an argument for a global ignore?
should too ever be fixed or rule removed -> i only have to change 1 place and not all local ones
Co-authored-by: Alexander V. Hopp <alexander.hopp@merckgroup.com>
843793f to
a188d66
Compare
Closes #583
Fixes #567
Functionality:
Adds a
DiscreteBatchConstraintwhich works via subspace generation just like the continuous cardinality constraint, just in the discrete searchspace part. While it will quickly lead to many partitions, it is also possible to use multipleDiscreteBatchConstraints and also combine them with the cardinality constraints because there is now a more unified interface for constraints that work via subspace generation.Notes:
subspaceis not optimal, because there is also the concept ofDiscreteSubspace/ContinuousSubspace. I changed the naming that references to creating subspaces for taking care of the constraint intopartition. So we would then have things likepartition_masks,n_theoretical_partitionsetcn_max_partitionswhich controls the max number of subspaces considered in any casereplace=True) or shuffle the order (shuffle=True). The latter is used when subsamapling the spaces because withshuffle=Trueyou can just instantiate the fistnobjects in the iterator to achieve random subsampling. This has some complications, especially for the overall searchspace class which needs to have a parameter to stop the process when replicated samples are drawn too often (likely no other feasible subspace combinations).botorch.pyin recommenders has become very large as a result of this development. So I split it into submodules_FixedNumericalContinuousParameterhad a bugged property which was namedis_numericbut it should beis_numericalContinuousCardinalityConstraintcan now also be applied in hybrid spaces, which fixesContinuousCardinalityConstraintnot considered in hybrid spaces #567Discuss:
n_theoretical_subspacesjust computes the upper limit of subspaces in discrete and hybrid cases. Because subspaces that do not have enough candidates are internally skipped the actual number ofn_feasible_subspacesmight be smaller. However that cannot be easily computed and would require instantiating all masks corresponding to the subspaces. The dispatcher logic is currently based onn_theoretical_subspacesbut to be 100% correct it should ben_feasible_subspaces- this is not implemented due to the mentioned difficulty. I think usingn_theoretical_subspacesworks as a proxy and will not be very different fromn_feasible_subspacesfor nearly all practical problems