feat: add constraint handling with feasibility-aware trial ranking

Add constraint support so that optimization problems with constraints
(e.g., "model size < 100MB") prefer feasible solutions. Convention:
constraint value <= 0.0 means feasible.

- Add constraint_values field to Trial with set_constraints/getter
- Add constraints field to CompletedTrial with is_feasible() method
- Propagate constraints through complete_trial/prune_trial
- Make best_trial() and top_trials() constraint-aware: feasible trials
  rank above infeasible, infeasible ranked by total violation
This commit is contained in:
Manuel Raimann
2026-02-11 18:49:08 +01:00
parent aa9734587a
commit 09480a973b
5 changed files with 181 additions and 34 deletions
+2
View File
@@ -178,6 +178,7 @@ impl BohbSampler {
intermediate_values: trial.intermediate_values.clone(),
state: trial.state,
user_attrs: trial.user_attrs.clone(),
constraints: trial.constraints.clone(),
})
})
.collect()
@@ -396,6 +397,7 @@ mod tests {
intermediate_values,
state: TrialState::Complete,
user_attrs: HashMap::new(),
constraints: Vec::new(),
}
}
+13
View File
@@ -41,6 +41,9 @@ pub struct CompletedTrial<V = f64> {
pub state: TrialState,
/// User-defined attributes stored during the trial.
pub user_attrs: HashMap<String, AttrValue>,
/// Constraint values for this trial (<=0.0 means feasible).
#[cfg_attr(feature = "serde", serde(default))]
pub constraints: Vec<f64>,
}
impl<V> CompletedTrial<V> {
@@ -61,6 +64,7 @@ impl<V> CompletedTrial<V> {
intermediate_values: Vec::new(),
state: TrialState::Complete,
user_attrs: HashMap::new(),
constraints: Vec::new(),
}
}
@@ -83,6 +87,7 @@ impl<V> CompletedTrial<V> {
intermediate_values,
state: TrialState::Complete,
user_attrs,
constraints: Vec::new(),
}
}
@@ -127,6 +132,14 @@ impl<V> CompletedTrial<V> {
})
}
/// Returns `true` if all constraints are satisfied (values <= 0.0).
///
/// A trial with no constraints is considered feasible.
#[must_use]
pub fn is_feasible(&self) -> bool {
self.constraints.iter().all(|&c| c <= 0.0)
}
/// Gets a user attribute by key.
#[must_use]
pub fn user_attr(&self, key: &str) -> Option<&AttrValue> {