test(sms_emoa,pesa2,paes,random_search): pin remaining algorithm helpers

Phase 1, final algorithm batch:
- sms_emoa: pick_drop_index returns the singleton worst front, and
  finds the least-HV-contributor at a non-zero index.
- pesa2: build_grid empty/corner-point boxing; region_tournament
  prefers the less-crowded grid box (statistical majority).
- paes: deterministic non-empty front + archive cap.
- random_search: evaluation count = iterations*batch; best is no
  worse than any sampled candidate.
This commit is contained in:
2026-05-13 22:58:17 -06:00
parent c5b003a9c9
commit 7aa9e627f0
4 changed files with 151 additions and 0 deletions
+22
View File
@@ -305,4 +305,26 @@ mod tests {
let r = opt.run(&Sphere1D);
assert!(r.best.is_some());
}
/// PAES must return a non-empty Pareto archive on a 2-objective problem
/// and be deterministic with a fixed seed. Pins the run-loop
/// bookkeeping against degenerate / comparison mutants.
#[test]
fn produces_deterministic_nonempty_front() {
let make = || {
Paes::new(
PaesConfig { iterations: 40, archive_size: 10, seed: 5 },
RealBounds::new(vec![(-5.0, 5.0)]),
GaussianMutation { sigma: 0.3 },
)
};
let r1 = make().run(&SchafferN1);
let r2 = make().run(&SchafferN1);
assert!(!r1.pareto_front.is_empty());
let f1: Vec<Vec<f64>> = r1.pareto_front.iter().map(|c| c.evaluation.objectives.clone()).collect();
let f2: Vec<Vec<f64>> = r2.pareto_front.iter().map(|c| c.evaluation.objectives.clone()).collect();
assert_eq!(f1, f2);
// Archive never exceeds its configured cap.
assert!(r1.pareto_front.len() <= 10);
}
}