Skip to content

Constraint Refactor 2: Turn DiscreteExcludeConstraint into DiscreteSelectionConstraint , Introduce DiscreteFilteringConstraint ABC - #880

Open
Scienfitz wants to merge 34 commits into
mainfrom
refactor/constraints/filtering
Open

Constraint Refactor 2: Turn DiscreteExcludeConstraint into DiscreteSelectionConstraint , Introduce DiscreteFilteringConstraint ABC#880
Scienfitz wants to merge 34 commits into
mainfrom
refactor/constraints/filtering

Conversation

@Scienfitz

@Scienfitz Scienfitz commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Closes #873
Based on #879

Three major components in this PR:

  • New DiscreteFilteringConstraint ABC that owns all row-filtering logic applied at searchspace creation. This cleans also the previously less separated DiscreteBatchConstraint which is not derived from it
  • Newly introduced exclude flag via the new ABC, which inverts the filtering logic
  • DiscreteExcludeConstraint reworked into DiscreteSelectionConstraint (inverted semantics, deprecated)

Notes:

  • I decided to have the semantics of all constraints say "this is whats kept, unless you set exclude=True). The alternative would be to have potentially mixed semantics and a complement flag (imo less nice)

@Scienfitz Scienfitz self-assigned this Jul 31, 2026
@Scienfitz
Scienfitz marked this pull request as ready for review August 4, 2026 16:16
Copilot AI lite review requested due to automatic review settings August 4, 2026 16:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Not ready to approve

There are a few concrete runtime/contract issues in the deprecation wrapper and structuring hook (plus a misleading Polars docstring) that should be fixed before merge.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Refactors discrete searchspace row-pruning by introducing a dedicated DiscretePruningConstraint ABC with unified “keep-by-default” semantics and an exclude inversion flag, while migrating the legacy DiscreteExcludeConstraint behavior to the new DiscreteFilteringConstraint (with deprecation support).

Changes:

  • Introduce DiscretePruningConstraint and migrate pruning constraints to implement “matching/kept rows” logic with a shared exclude inversion mechanism (pandas + Polars paths).
  • Replace DiscreteExcludeConstraint usage with DiscreteFilteringConstraint(..., exclude=True) across code, docs, examples, and tests; add deprecation + legacy deserialization redirect.
  • Rename ordering constant to DISCRETE_CONSTRAINTS_PRUNING_ORDER and update constrained-product construction to only apply pruning constraints during searchspace creation.
File summaries
File Description
tests/test_deprecations.py Adds deprecation warning test and legacy deserialization test for DiscreteExcludeConstraint.
tests/test_campaign.py Updates campaign tests to use DiscreteFilteringConstraint(..., exclude=True) instead of DiscreteExcludeConstraint.
tests/serialization/test_constraint_serialization.py Switches hypothesis-based serialization coverage from exclude to filtering constraint strategy.
tests/hypothesis_strategies/constraints.py Renames/updates hypothesis strategy to generate DiscreteFilteringConstraint with randomized exclude.
tests/constraints/test_constrained_cartesian_product.py Updates ordering constant and scenarios to use pruning terminology and filtering constraint replacement.
tests/constraints/test_batch_constraint.py Updates batch-constraint tests to use DiscreteFilteringConstraint(..., exclude=True).
tests/conftest.py Updates shared fixtures to use DiscreteFilteringConstraint(..., exclude=True) for previous exclusion semantics.
examples/Constraints_Discrete/filtering_constraints.py Renames and updates example to demonstrate filtering constraint with exclude=True for exclusion behavior.
docs/concepts/getting_recommendations.md Updates docs snippet to use DiscreteFilteringConstraint(..., exclude=True).
docs/components/constraints.md Reworks discrete-constraints docs around pruning constraints + exclude semantics; updates examples and links.
CHANGELOG.md Documents new ABC, new constraint, rename, deprecation, and removals.
baybe/searchspace/utils.py Updates constrained cartesian product construction to apply only DiscretePruningConstraints; updates ordering and Polars partitioning.
baybe/searchspace/discrete.py Updates constraint sorting to use pruning order with a safe fallback for non-pruning constraints.
baybe/constraints/discrete.py Implements DiscreteFilteringConstraint, migrates other discrete constraints to pruning ABC, adds deprecated DiscreteExcludeConstraint wrapper and legacy structure hook.
baybe/constraints/base.py Introduces DiscretePruningConstraint with shared invalid/valid computation and Polars support contract.
baybe/constraints/init.py Re-exports new names/constant and keeps legacy DiscreteExcludeConstraint export.
baybe/campaign.py Tightens candidate toggling path to require pruning constraints (instead of all discrete constraints).
Review details
  • Files reviewed: 17/17 changed files
  • Comments generated: 4
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread baybe/constraints/discrete.py Outdated
Comment thread baybe/constraints/base.py Outdated
Comment thread baybe/constraints/discrete.py Outdated
Comment thread baybe/searchspace/utils.py
Comment thread baybe/constraints/base.py Outdated
@Scienfitz
Scienfitz force-pushed the refactor/constraints/filtering branch from 111368f to c77c116 Compare August 9, 2026 19:17
Comment thread CHANGELOG.md

@AdrianSosic AdrianSosic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not yet entirely done with the review, but already submitting this part because I want to propose an alternative for the deserialization shim

Comment thread baybe/constraints/base.py
Comment thread baybe/constraints/discrete.py Outdated
Comment thread baybe/constraints/discrete.py Outdated
Comment thread baybe/constraints/discrete.py
Comment thread baybe/constraints/discrete.py
Comment thread tests/test_deprecations.py Outdated
Comment thread tests/test_deprecations.py Outdated
Comment thread baybe/constraints/base.py Outdated
Comment thread baybe/searchspace/discrete.py
Comment thread baybe/constraints/discrete.py Outdated


# >>>>>>>>>> Deprecation
# NOTE: This block exists solely to redirect legacy constraint type names during

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think you are massively overcomplicating this, tbh 😬 The code pretty much copies parts of the deserialization engine that should instead only be referenced! All that is needed is a very simple compat hook that applies the name swapping before calling the existing machinery.

Let me push a proposal for this, if you don't mind 👍🏼

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How about this: 10acf4d

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I would be much happier with that solution as its more concise
I guess I tried to cover too many cases which lead to this long implementation

here are the cases identified, the new solution is not entirely equivalent to the old one, but can we live with that?
image

In particular: Are we ok with the new behavior in case 2 and 4

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you provide me the code for 2 and 4 so that I can exactly replicate and see?

@Scienfitz Scienfitz Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Case 2 - Wrong Input Type + Concrete Selection Constraint as Target

from baybe.constraints import DiscreteSelectionConstraint
from baybe.serialization import converter
data = {
    "type": "DiscreteSumConstraint",  # intentionally wrong
    "parameters": ["A"],
    "conditions": [{"type": "SubSelectionCondition", "selection": ["a"]}],
}
result = converter.structure(data, DiscreteSelectionConstraint)
print(result)
# New: builds DiscreteSelectionConstraint
# Old: `ValueError: The 'type' field 'DiscreteSumConstraint' does not match the target class 'DiscreteSelectionConstraint'.`

Case 4 - Legacy Type as Input + Concrete Selection Constraint as Target

from baybe.constraints import DiscreteSelectionConstraint
from baybe.serialization import converter
data = {
    "type": "DiscreteExcludeConstraint",
    "parameters": ["A"],
    "conditions": [{"type": "SubSelectionCondition", "selection": ["a"]}],
}
result = converter.structure(data, DiscreteSelectionConstraint)
print(result.exclude) 
# New: False
# Old: True

btw I'm not saying these are necessarily relevant, If we determine theyre not important I'm happy to jsut keep your much leaner versions, but from the looks of it it seems to me the old outcomes for these cases is preferable

Comment thread baybe/constraints/discrete.py
Comment thread baybe/searchspace/utils.py Outdated
Comment thread CHANGELOG.md Outdated
Comment thread docs/components/constraints.md Outdated
Comment thread docs/components/constraints.md

@AVHopp AVHopp left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM - only two real issues, but we can discuss those in the threads

Comment thread baybe/constraints/base.py
Comment thread tests/hypothesis_strategies/constraints.py
Scienfitz and others added 20 commits August 18, 2026 18:28
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
An XOR result can flip as further operands arrive, so it must not be evaluated
on a partial column set. Cover all exclude/combiner combinations.
The redirect was only registered on 'DiscretePruningConstraint', but search
spaces deserialize constraints via the 'Constraint' and 'DiscreteConstraint'
annotations. Register it on the 'Constraint' base and make concrete targets
reject a mismatched 'type' field.
Co-authored-by: AdrianSosic <adrian.sosic@merckgroup.com>
Co-authored-by: AdrianSosic <adrian.sosic@merckgroup.com>
@Scienfitz
Scienfitz force-pushed the refactor/constraints/filtering branch from 05f0d8f to c36ccc5 Compare August 18, 2026 16:53
@Scienfitz Scienfitz changed the title Constraint Refactor 2: Turn DiscreteExcludeConstraint into DiscreteFilteringConstraint , Introduce DiscretePruningConstraint ABC Constraint Refactor 2: Turn DiscreteExcludeConstraint into DiscreteSelectionConstraint , Introduce DiscreteFilteringConstraint ABC Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rework Exclude Into Filtering Constraint, Add exclude Flag

4 participants