Files
foxhunt/crates/ml/src/hyperopt/observer.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

60 lines
1.7 KiB
Rust

use argmin::core::observers::Observe;
use argmin::core::{Error, State};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
/// Observer that enforces strict trial budget limits
///
/// Argmin's PSO does not reliably respect max_iters when set to small values (e.g., 1).
/// This observer tracks evaluations across all iterations and terminates when budget is hit.
#[derive(Clone, Debug)]
pub struct TrialBudgetObserver {
max_trials: usize,
trials_used: Arc<AtomicUsize>,
}
impl TrialBudgetObserver {
pub fn new(max_trials: usize) -> Self {
Self {
max_trials,
trials_used: Arc::new(AtomicUsize::new(0)),
}
}
pub fn increment_trial(&self) {
self.trials_used.fetch_add(1, Ordering::Relaxed);
}
pub fn should_terminate(&self) -> bool {
self.trials_used.load(Ordering::Relaxed) >= self.max_trials
}
pub fn get_trials_used(&self) -> usize {
self.trials_used.load(Ordering::Relaxed)
}
}
impl<I> Observe<I> for TrialBudgetObserver
where
I: State,
{
fn observe_iter(&mut self, _state: &I, _kv: &argmin::core::KV) -> Result<(), Error> {
// Check if we've exceeded budget
if self.should_terminate() {
tracing::warn!(
"Trial budget exhausted: {}/{} trials used. Terminating optimization.",
self.get_trials_used(),
self.max_trials
);
// Return error to signal termination
return Err(Error::msg(format!(
"Trial budget exhausted: {}/{} trials",
self.get_trials_used(),
self.max_trials
)));
}
Ok(())
}
}