refactor: LHS is the correct algorithm for small budgets, not a fallback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -354,12 +354,15 @@ impl ArgminOptimizer {
|
||||
let trials_used = trials.len();
|
||||
let remaining_trials = self.max_trials.saturating_sub(trials_used);
|
||||
|
||||
// For small budgets (< 2× swarm size), PSO can't complete a full iteration.
|
||||
// Fall back to additional LHS samples which give better space coverage.
|
||||
// Algorithm selection by budget:
|
||||
// - Budget < 2× swarm → LHS (space-filling, optimal for small budgets)
|
||||
// - Budget ≥ 2× swarm → PSO (swarm optimization, needs full iterations)
|
||||
// PSO with a partial swarm is worse than random — 75% of particles
|
||||
// have no cost value, so gbest is computed from incomplete data.
|
||||
if remaining_trials < self.n_particles * 2 {
|
||||
info!(
|
||||
"Budget too small for PSO ({} remaining < {} particles × 2). Using additional LHS.",
|
||||
remaining_trials, self.n_particles
|
||||
"Using LHS for remaining {} trials (budget < {} particles × 2 = need PSO budget ≥ {})",
|
||||
remaining_trials, self.n_particles, self.n_particles * 2
|
||||
);
|
||||
let extra_samples = Self::latin_hypercube_sampling(remaining_trials, &bounds, &mut rng);
|
||||
let mut model_guard = cost_fn.model.lock().map_err(|e| anyhow::anyhow!("lock: {e}"))?;
|
||||
@@ -379,7 +382,7 @@ impl ArgminOptimizer {
|
||||
let max_iters_by_budget =
|
||||
((remaining_trials as f64) / (self.n_particles as f64)).ceil() as usize;
|
||||
let max_iters = if remaining_trials < self.n_particles * 2 {
|
||||
0 // Already handled by LHS fallback above
|
||||
0 // LHS already handled above
|
||||
} else {
|
||||
max_iters_by_budget.min(self.max_iters_per_restart)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user