Contextual bo generator#425
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
@copilot address the code coverage issues and notebook failures by adding tests and modifying source code / example notebooks as needed |
Addressed the coverage and notebook failures with the following fixes (commits Notebook failures (multi-fidelity):
Bug fix in
New tests added:
|
There was a problem hiding this comment.
Pull request overview
This PR adds first-class support for contextual (observed, not controlled) variables across VOCS handling, Bayesian generator behavior, visualization, and documentation, enabling contextual Bayesian optimization workflows.
Changes:
- Introduces
ContextualVariableand updates input conversion/validation paths to allow contextual columns to be omitted from candidates while still validating shapes/bounds. - Updates Bayesian generators to condition acquisition functions on the latest observed contextual values and to derive contextual input bounds from observed data.
- Adds visualization behavior/tests for contextual axes (acquisition plot replaced by a warning panel), plus a new example notebook and docs nav entry.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| xopt/vocs.py | Adds ContextualVariable and updates dataframe/numpy input conversion to exclude contextual variables. |
| xopt/base.py | Allows contextual variables to be omitted from candidate inputs by inserting temporary NaN columns for validation. |
| xopt/generators/bayesian/bayesian_generator.py | Adds contextual conditioning and contextual bounds derivation for model inputs; refactors fixed-feature application. |
| xopt/generators/bayesian/mobo.py | Routes acquisition post-processing through unified fixed-feature + contextual conditioning helper. |
| xopt/generators/bayesian/expected_improvement.py | Routes acquisition post-processing through unified fixed-feature + contextual conditioning helper. |
| xopt/generators/bayesian/visualize.py | Infers finite bounds for contextual variables from data and renders a warning panel when contextual axes are selected for acquisition plots. |
| xopt/generators/bayesian/bax/visualize.py | Updates mesh generation call to pass data (for contextual-bound inference). |
| xopt/generators/bayesian/objectives.py | Updates get_sampler import path. |
| xopt/generators/bayesian/models/standard.py | Adjusts optimizer selection/options to improve compatibility across batched models / botorch+scipy variants. |
| xopt/tests/test_vocs.py | Adds tests for ContextualVariable and numpy-to-input conversion with contextual vars/order preservation. |
| xopt/tests/generators/bayesian/test_visualize.py | Adds tests for acquisition plotting/visualization warnings when contextual axes are selected. |
| xopt/tests/generators/bayesian/test_model_constructor.py | Makes training comparison test less optimizer-callback dependent and relaxes hyperparameter matching tolerance. |
| xopt/tests/generators/bayesian/test_contextual_bo.py | New end-to-end tests covering contextual BO generation, bounds, and visualization warnings. |
| mkdocs.yml | Adds the contextual BO example notebook to documentation navigation. |
| docs/examples/single_objective_bayes_opt/contextual_bo.ipynb | New example notebook demonstrating standard vs contextual BO on a drifting objective. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- _candidate_names: copy variable list to avoid mutation, exclude contextual variables - _get_optimization_bounds: compute keep-indices once from original list, slice bounds once - vocs.py: update error message to mention non-contextual variables
- test_candidate_names_excludes_contextual_and_fixed: verifies _candidate_names excludes both contextual variables and fixed features, and does not mutate vocs - test_optimization_bounds_excludes_contextual_and_fixed: verifies _get_optimization_bounds correctly handles combined fixed_features + contextual_variables in a single pass - test_convert_dataframe_to_inputs_error_message_contextual: verifies the updated error message mentions 'non-contextual' variables
…thread Fix bounds indexing and candidate names for contextual BO with fixed features
There was a problem hiding this comment.
did you mean to commit this?
There was a problem hiding this comment.
nope! removed
nikitakuklev
left a comment
There was a problem hiding this comment.
Overall I don't have strong opinion on adding a special contextual variables type, but the current implementation is problematic.
Changing get_variable_bounds to drop entries breaks the implicit "one entry per variable, in variable_names order" contract relied upon everywhere (and in apsopt). I strongly suggest reverting that and instead handling exclusions at call site. This will resolve some bugs I commented on.
Other stuff:
- AsynchronousXopt might have issues (haven't checked).
- Serialization seems broken (haven't checked) because of how
gest-apiresolves types with only its own. Contextual variables need to be monkeypatched intogest-api/globals()before attempting to load, or we upstream some registry system.
| if isinstance(variable, DiscreteVariable): | ||
| values = sorted(float(v) for v in variable.values) | ||
| bounds[name] = (values[0], values[-1]) | ||
| elif isinstance(variable, ContextualVariable): |
There was a problem hiding this comment.
This is a problem for methods like _get_optimization_bounds if contextual variable is declared first. For example, using {"c": ContextualVariable(), "x": [0,1]} will crash on step()
There was a problem hiding this comment.
So you need to compute indices against the same reduced list
| # get the last contextual variable values | ||
| for var in self.contextual_variables: | ||
| columns.append(self.model_input_names.index(var)) | ||
| values.append(self.data[var].iloc[-1]) |
There was a problem hiding this comment.
if this value is nan, bad things happen because acq is poisoned (like effectively random sampling)
|
Thanks for the comments @nikitakuklev I will look them over and modify the implementation |
|
Previously I implemented a contextual variable as a subclass of continuous variable, with a domain of [-inf,inf], do you think that would work better? |
|
Taking a step back, what is the motivation for adding a dedicated contextual variable class? To my understanding, in current definition a contextual variable is a fixed feature whose value is resolved at acquisition time from the latest observation instead of being a constant or set by user externally (for example, by the script manually reading the context just before step like we do in practice). So, one option is to just add If you want a Regardless of method, also need |
|
Thanks for the comments @nikitakuklev. My original implementation added contextual variables as a property of the BayesianGenerator class, but then I felt it made more sense to promote it to a full class to make it more explicit (+ also make it more natural to check that the correct data exists / do visualization of the model). I think we can go the route of defaulting the domain to [-inf, inf] and then at runtime infer the domain with some documentation to make this clear to the user. I will work on this and then ping you again when it is ready. |
This pull request introduces contextual Bayesian optimization support and improves handling of contextual variables throughout the codebase and documentation. The changes enable users to define contextual variables that are observed (not controlled), ensure correct validation and bounds handling, and provide a new example notebook and documentation entry for contextual Bayesian optimization.
Key changes include:
Contextual Bayesian Optimization Example and Documentation
contextual_bo.ipynbdemonstrating and comparing standard versus contextual Bayesian optimization on a drifting objective, and updated the documentation navigation to include this example. [1] [2]VOCS Validation and Data Handling
Xoptinxopt/base.pyto properly handle contextual variables during input validation: contextual variables are allowed to be missing from candidate data and are filled withNaNfor validation purposes. This ensures that contextual variables are treated as observed, not controlled, throughout evaluation and data addition. [1] [2] [3] [4]Bayesian Generator Improvements
These changes collectively enable robust contextual Bayesian optimization workflows and improve clarity and correctness in handling contextual variables across the codebase.