style: rustfmt the Phase 1 test additions

The per-file Phase 1 test commits were written without running rustfmt
as I went; this pass formats the new test code (long assert_eq! lines
wrapped, etc.). Formatting-only — no behavioural change.
This commit is contained in:
2026-05-14 03:41:38 -06:00
parent 2ca8d71b94
commit 6aee6d6318
29 changed files with 466 additions and 161 deletions
+19 -4
View File
@@ -599,7 +599,10 @@ mod tests {
// direction and the loss tie-breaking.
let translated = vec![vec![1.0, 0.0], vec![0.0, 1.0]];
let p = estimate_p(&[0, 1], &translated, 2);
assert!((p - 0.25).abs() < 1e-12, "expected smallest candidate, got {p}");
assert!(
(p - 0.25).abs() < 1e-12,
"expected smallest candidate, got {p}"
);
}
#[test]
@@ -625,7 +628,11 @@ mod tests {
mutation: PolynomialMutation::new(bounds, 20.0, 1.0),
};
let mut opt = AgeMoea::new(
AgeMoeaConfig { population_size: 8, generations: 10, seed: 7 },
AgeMoeaConfig {
population_size: 8,
generations: 10,
seed: 7,
},
initializer,
variation,
);
@@ -666,7 +673,11 @@ mod tests {
};
for pop in [4_usize, 12, 30] {
let mut opt = AgeMoea::new(
AgeMoeaConfig { population_size: pop, generations: 5, seed: 13 },
AgeMoeaConfig {
population_size: pop,
generations: 5,
seed: 13,
},
initializer.clone(),
variation.clone(),
);
@@ -690,7 +701,11 @@ mod tests {
let pop = 6_usize;
let gens = 4_usize;
let mut opt = AgeMoea::new(
AgeMoeaConfig { population_size: pop, generations: gens, seed: 13 },
AgeMoeaConfig {
population_size: pop,
generations: gens,
seed: 13,
},
initializer,
variation,
);
+4 -1
View File
@@ -644,7 +644,10 @@ mod tests {
// k = exp(-0.5 * (1)^2) = exp(-0.5) ≈ 0.6065
let got = rbf_kernel(&[0.0], &[1.0], &[1.0], 1.0);
let expected = (-0.5_f64).exp();
assert!((got - expected).abs() < 1e-12, "got {got}, expected {expected}");
assert!(
(got - expected).abs() < 1e-12,
"got {got}, expected {expected}"
);
}
#[test]
+32 -8
View File
@@ -766,19 +766,37 @@ mod tests {
a.constraint_violation = 0.0;
let mut b = Evaluation::new(vec![1.0]);
b.constraint_violation = 1.0;
assert_eq!(compare_so(&a, &b, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare_so(&b, &a, Direction::Minimize), std::cmp::Ordering::Greater);
assert_eq!(
compare_so(&a, &b, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare_so(&b, &a, Direction::Minimize),
std::cmp::Ordering::Greater
);
}
#[test]
fn compare_so_two_feasible_under_min_and_max() {
let a = Evaluation::new(vec![1.0]);
let b = Evaluation::new(vec![2.0]);
assert_eq!(compare_so(&a, &b, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare_so(&b, &a, Direction::Minimize), std::cmp::Ordering::Greater);
assert_eq!(
compare_so(&a, &b, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare_so(&b, &a, Direction::Minimize),
std::cmp::Ordering::Greater
);
// Maximize inverts.
assert_eq!(compare_so(&a, &b, Direction::Maximize), std::cmp::Ordering::Greater);
assert_eq!(compare_so(&b, &a, Direction::Maximize), std::cmp::Ordering::Less);
assert_eq!(
compare_so(&a, &b, Direction::Maximize),
std::cmp::Ordering::Greater
);
assert_eq!(
compare_so(&b, &a, Direction::Maximize),
std::cmp::Ordering::Less
);
}
#[test]
@@ -787,8 +805,14 @@ mod tests {
a.constraint_violation = 0.5;
let mut b = Evaluation::new(vec![0.0]);
b.constraint_violation = 1.0;
assert_eq!(compare_so(&a, &b, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare_so(&b, &a, Direction::Minimize), std::cmp::Ordering::Greater);
assert_eq!(
compare_so(&a, &b, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare_so(&b, &a, Direction::Minimize),
std::cmp::Ordering::Greater
);
}
#[test]
+12 -3
View File
@@ -446,15 +446,24 @@ mod tests {
fn compare_for_fitness_two_feasible_min_and_max() {
let lo = fc(1.0);
let hi = fc(2.0);
assert_eq!(compare_for_fitness(&lo, &hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare_for_fitness(&lo, &hi, Direction::Maximize), std::cmp::Ordering::Greater);
assert_eq!(
compare_for_fitness(&lo, &hi, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare_for_fitness(&lo, &hi, Direction::Maximize),
std::cmp::Ordering::Greater
);
}
#[test]
fn compare_for_fitness_two_infeasible_lower_violation_wins() {
let low = fc_cv(0.0, 0.3);
let high = fc_cv(0.0, 0.9);
assert_eq!(compare_for_fitness(&low, &high, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(
compare_for_fitness(&low, &high, Direction::Minimize),
std::cmp::Ordering::Less
);
}
/// `survival_selection` carries `elitism` parents and `n - elitism`
+6 -1
View File
@@ -415,7 +415,12 @@ mod tests {
mutation: PolynomialMutation::new(bounds, 20.0, 1.0),
};
let mut opt = Grea::new(
GreaConfig { population_size: pop, generations: 5, grid_divisions: 8, seed: 3 },
GreaConfig {
population_size: pop,
generations: 5,
grid_divisions: 8,
seed: 3,
},
initializer,
variation,
);
+8 -2
View File
@@ -290,7 +290,10 @@ mod tests {
#[test]
fn hill_climber_never_worsens_objective() {
let mut opt = HillClimber::new(
HillClimberConfig { iterations: 200, seed: 5 },
HillClimberConfig {
iterations: 200,
seed: 5,
},
RealBounds::new(vec![(-3.0, 3.0); 2]),
GaussianMutation { sigma: 0.3 },
);
@@ -306,7 +309,10 @@ mod tests {
#[test]
fn hill_climber_decreases_sphere() {
let mut opt = HillClimber::new(
HillClimberConfig { iterations: 500, seed: 11 },
HillClimberConfig {
iterations: 500,
seed: 11,
},
RealBounds::new(vec![(-3.0, 3.0)]),
GaussianMutation { sigma: 0.2 },
);
+4 -1
View File
@@ -595,6 +595,9 @@ mod tests {
wins0 += 1;
}
}
assert!(wins0 > 130, "index 0 won only {wins0}/200 — comparison likely flipped");
assert!(
wins0 > 130,
"index 0 won only {wins0}/200 — comparison likely flipped"
);
}
}
+20 -5
View File
@@ -451,16 +451,31 @@ mod tests {
fn compare_feasibility_first_and_direction() {
let feasible = Evaluation::new(vec![10.0]);
let infeasible = Evaluation::constrained(vec![0.0], 1.0);
assert_eq!(compare(&feasible, &infeasible, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare(&infeasible, &feasible, Direction::Minimize), std::cmp::Ordering::Greater);
assert_eq!(
compare(&feasible, &infeasible, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare(&infeasible, &feasible, Direction::Minimize),
std::cmp::Ordering::Greater
);
let lo = Evaluation::new(vec![1.0]);
let hi = Evaluation::new(vec![2.0]);
assert_eq!(compare(&lo, &hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare(&lo, &hi, Direction::Maximize), std::cmp::Ordering::Greater);
assert_eq!(
compare(&lo, &hi, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare(&lo, &hi, Direction::Maximize),
std::cmp::Ordering::Greater
);
// two infeasible: smaller violation is "Less" (better).
let v_lo = Evaluation::constrained(vec![0.0], 0.2);
let v_hi = Evaluation::constrained(vec![0.0], 0.8);
assert_eq!(compare(&v_lo, &v_hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(
compare(&v_lo, &v_hi, Direction::Minimize),
std::cmp::Ordering::Less
);
}
#[test]
+4 -1
View File
@@ -501,7 +501,10 @@ mod tests {
let pool = vec![ibea_cand(vec![1.0, 1.0]), ibea_cand(vec![2.0, 2.0])];
let fit = compute_fitness(&pool, &ibea_space(), 0.05);
assert_eq!(fit.len(), 2);
assert!(fit[0] > fit[1], "dominating point should score higher: {fit:?}");
assert!(
fit[0] > fit[1],
"dominating point should score higher: {fit:?}"
);
}
#[test]
+10 -2
View File
@@ -408,8 +408,16 @@ mod tests {
// Determinism cross-check.
let mut opt2 = make_optimizer(7);
let r2 = opt2.run(&SchafferN1);
let f1: Vec<Vec<f64>> = r.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();
let f1: Vec<Vec<f64>> = r
.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);
}
}
+16 -4
View File
@@ -560,14 +560,26 @@ mod tests {
fn compare_feasibility_first_and_direction() {
let feasible = Evaluation::new(vec![10.0]);
let infeasible = Evaluation::constrained(vec![0.0], 1.0);
assert_eq!(compare(&feasible, &infeasible, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(
compare(&feasible, &infeasible, Direction::Minimize),
std::cmp::Ordering::Less
);
let lo = Evaluation::new(vec![1.0]);
let hi = Evaluation::new(vec![2.0]);
assert_eq!(compare(&lo, &hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare(&lo, &hi, Direction::Maximize), std::cmp::Ordering::Greater);
assert_eq!(
compare(&lo, &hi, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare(&lo, &hi, Direction::Maximize),
std::cmp::Ordering::Greater
);
let v_lo = Evaluation::constrained(vec![0.0], 0.2);
let v_hi = Evaluation::constrained(vec![0.0], 0.8);
assert_eq!(compare(&v_lo, &v_hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(
compare(&v_lo, &v_hi, Direction::Minimize),
std::cmp::Ordering::Less
);
}
#[test]
+15 -3
View File
@@ -313,7 +313,11 @@ mod tests {
fn produces_deterministic_nonempty_front() {
let make = || {
Paes::new(
PaesConfig { iterations: 40, archive_size: 10, seed: 5 },
PaesConfig {
iterations: 40,
archive_size: 10,
seed: 5,
},
RealBounds::new(vec![(-5.0, 5.0)]),
GaussianMutation { sigma: 0.3 },
)
@@ -321,8 +325,16 @@ mod tests {
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();
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);
+4 -1
View File
@@ -560,6 +560,9 @@ mod tests {
}
// Index 2 wins whenever it's drawn against 0 or 1, plus half its
// self-draws — clear majority.
assert!(picked_uncrowded > 150, "uncrowded picked {picked_uncrowded}/300");
assert!(
picked_uncrowded > 150,
"uncrowded picked {picked_uncrowded}/300"
);
}
}
+5 -1
View File
@@ -224,7 +224,11 @@ mod tests {
#[test]
fn best_is_no_worse_than_any_sample() {
let mut opt = RandomSearch::new(
RandomSearchConfig { iterations: 50, batch_size: 2, seed: 9 },
RandomSearchConfig {
iterations: 50,
batch_size: 2,
seed: 9,
},
RealBounds::new(vec![(-3.0, 3.0)]),
);
let r = opt.run(&Sphere1D);
+4 -1
View File
@@ -591,6 +591,9 @@ mod tests {
fn smallest_neighbor_angle_of_orthogonal_refs_is_pi_over_2() {
let refs = vec![vec![1.0, 0.0], vec![0.0, 1.0]];
let a = smallest_neighbor_angle(&refs);
assert!((a - std::f64::consts::FRAC_PI_2).abs() < 1e-9, "angle = {a}");
assert!(
(a - std::f64::consts::FRAC_PI_2).abs() < 1e-9,
"angle = {a}"
);
}
}
+12 -3
View File
@@ -483,11 +483,20 @@ mod tests {
fn compare_feasibility_first_and_direction() {
let feasible = Evaluation::new(vec![100.0]);
let infeasible = Evaluation::constrained(vec![0.0], 1.0);
assert_eq!(compare(&feasible, &infeasible, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(
compare(&feasible, &infeasible, Direction::Minimize),
std::cmp::Ordering::Less
);
let lo = Evaluation::new(vec![1.0]);
let hi = Evaluation::new(vec![2.0]);
assert_eq!(compare(&lo, &hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare(&lo, &hi, Direction::Maximize), std::cmp::Ordering::Greater);
assert_eq!(
compare(&lo, &hi, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare(&lo, &hi, Direction::Maximize),
std::cmp::Ordering::Greater
);
}
#[test]
+16 -4
View File
@@ -456,14 +456,26 @@ mod tests {
fn compare_so_feasibility_first_and_direction() {
let feasible = Evaluation::new(vec![100.0]);
let infeasible = Evaluation::constrained(vec![0.0], 1.0);
assert_eq!(compare_so(&feasible, &infeasible, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(
compare_so(&feasible, &infeasible, Direction::Minimize),
std::cmp::Ordering::Less
);
let lo = Evaluation::new(vec![1.0]);
let hi = Evaluation::new(vec![2.0]);
assert_eq!(compare_so(&lo, &hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(compare_so(&lo, &hi, Direction::Maximize), std::cmp::Ordering::Greater);
assert_eq!(
compare_so(&lo, &hi, Direction::Minimize),
std::cmp::Ordering::Less
);
assert_eq!(
compare_so(&lo, &hi, Direction::Maximize),
std::cmp::Ordering::Greater
);
let v_lo = Evaluation::constrained(vec![0.0], 0.2);
let v_hi = Evaluation::constrained(vec![0.0], 0.8);
assert_eq!(compare_so(&v_lo, &v_hi, Direction::Minimize), std::cmp::Ordering::Less);
assert_eq!(
compare_so(&v_lo, &v_hi, Direction::Minimize),
std::cmp::Ordering::Less
);
}
#[test]
+33 -22
View File
@@ -598,9 +598,18 @@ mod tests {
let v: Vec<i64> = vec![-3, 0, 7];
let got = v.to_decision_values();
assert_eq!(got.len(), 3);
assert_eq!(got[0], serde_json::Value::Number(serde_json::Number::from(-3i64)));
assert_eq!(got[1], serde_json::Value::Number(serde_json::Number::from(0i64)));
assert_eq!(got[2], serde_json::Value::Number(serde_json::Number::from(7i64)));
assert_eq!(
got[0],
serde_json::Value::Number(serde_json::Number::from(-3i64))
);
assert_eq!(
got[1],
serde_json::Value::Number(serde_json::Number::from(0i64))
);
assert_eq!(
got[2],
serde_json::Value::Number(serde_json::Number::from(7i64))
);
}
/// Pins the *exact* booleans, not just the count.
@@ -642,8 +651,7 @@ mod tests {
fn from_result_propagates_evaluation_and_generation_counts() {
let problem = SingleObjMin;
let cands = vec![Candidate::new(vec![1.0], Evaluation::new(vec![1.0]))];
let result =
OptimizationResult::new(Population::new(cands.clone()), cands, None, 137, 9);
let result = OptimizationResult::new(Population::new(cands.clone()), cands, None, 137, 9);
let export = ExplorerExport::from_result(&problem, &result);
assert_eq!(export.run.evaluations, 137);
assert_eq!(export.run.generations, 9);
@@ -654,8 +662,8 @@ mod tests {
fn with_problem_name_sets_field_and_preserves_other_state() {
let problem = SingleObjMin;
let result = make_result(vec![vec![1.0]], |d| vec![d[0]]);
let export = ExplorerExport::from_result(&problem, &result)
.with_problem_name("Toy Problem");
let export =
ExplorerExport::from_result(&problem, &result).with_problem_name("Toy Problem");
assert_eq!(export.run.problem_name.as_deref(), Some("Toy Problem"));
// The candidates and objectives should still be intact, proving the
// chained builder isn't replacing the whole struct.
@@ -678,9 +686,12 @@ mod tests {
fn with_timestamp_sets_field_and_preserves_other_state() {
let problem = SingleObjMin;
let result = make_result(vec![vec![1.0]], |d| vec![d[0]]);
let export = ExplorerExport::from_result(&problem, &result)
.with_timestamp("2025-01-01T00:00:00Z");
assert_eq!(export.run.timestamp.as_deref(), Some("2025-01-01T00:00:00Z"));
let export =
ExplorerExport::from_result(&problem, &result).with_timestamp("2025-01-01T00:00:00Z");
assert_eq!(
export.run.timestamp.as_deref(),
Some("2025-01-01T00:00:00Z")
);
assert_eq!(export.candidates.len(), 1);
}
@@ -708,8 +719,7 @@ mod tests {
fn to_writer_emits_full_export() {
let problem = SingleObjMin;
let result = make_result(vec![vec![1.0]], |d| vec![d[0]]);
let export = ExplorerExport::from_result(&problem, &result)
.with_problem_name("MyProblem");
let export = ExplorerExport::from_result(&problem, &result).with_problem_name("MyProblem");
let mut buf: Vec<u8> = Vec::new();
export.to_writer(&mut buf).unwrap();
assert!(!buf.is_empty());
@@ -725,16 +735,15 @@ mod tests {
use std::io::Read;
let problem = SingleObjMin;
let result = make_result(vec![vec![1.0]], |d| vec![d[0]]);
let export = ExplorerExport::from_result(&problem, &result)
.with_problem_name("OnDisk");
let export = ExplorerExport::from_result(&problem, &result).with_problem_name("OnDisk");
let dir = std::env::temp_dir();
let path = dir.join(format!(
"heuropt-explorer-test-{}.json",
std::process::id()
));
let path = dir.join(format!("heuropt-explorer-test-{}.json", std::process::id()));
export.to_file(&path).unwrap();
let mut s = String::new();
std::fs::File::open(&path).unwrap().read_to_string(&mut s).unwrap();
std::fs::File::open(&path)
.unwrap()
.read_to_string(&mut s)
.unwrap();
let _ = std::fs::remove_file(&path);
let back: ExplorerExport = serde_json::from_str(&s).unwrap();
assert_eq!(back.run.problem_name.as_deref(), Some("OnDisk"));
@@ -777,7 +786,10 @@ mod tests {
));
super::to_file(&path, &problem, &DummyAlgo, &result).unwrap();
let mut s = String::new();
std::fs::File::open(&path).unwrap().read_to_string(&mut s).unwrap();
std::fs::File::open(&path)
.unwrap()
.read_to_string(&mut s)
.unwrap();
let _ = std::fs::remove_file(&path);
let back: ExplorerExport = serde_json::from_str(&s).unwrap();
assert_eq!(back.run.algorithm.as_deref(), Some("DummyAlgo"));
@@ -877,8 +889,7 @@ mod tests {
/// the pad (too few objectives) and truncate (too many) cases.
#[test]
fn candidate_to_export_pads_short_objectives_with_nan() {
let c: Candidate<Vec<f64>> =
Candidate::new(vec![1.0], Evaluation::new(vec![1.0]));
let c: Candidate<Vec<f64>> = Candidate::new(vec![1.0], Evaluation::new(vec![1.0]));
let exported = candidate_to_export(&c, 0, 3);
assert_eq!(exported.objectives.len(), 3);
assert_eq!(exported.objectives[0], 1.0);
+10 -10
View File
@@ -560,12 +560,12 @@ mod nd_tests {
/// positive value for a dominating point.
#[test]
fn hypervolume_nd_from_evaluations_empty_and_nonempty() {
let s = ObjectiveSpace::new(vec![
Objective::minimize("f1"),
Objective::minimize("f2"),
]);
let s = ObjectiveSpace::new(vec![Objective::minimize("f1"), Objective::minimize("f2")]);
let empty: Vec<&Evaluation> = Vec::new();
assert_eq!(hypervolume_nd_from_evaluations(&empty, &s, &[2.0, 2.0]), 0.0);
assert_eq!(
hypervolume_nd_from_evaluations(&empty, &s, &[2.0, 2.0]),
0.0
);
let e = Evaluation::new(vec![1.0, 1.0]);
let evals = vec![&e];
@@ -577,13 +577,13 @@ mod nd_tests {
/// A point that does not strictly dominate the reference contributes 0.
#[test]
fn hypervolume_nd_from_evaluations_skips_non_dominating() {
let s = ObjectiveSpace::new(vec![
Objective::minimize("f1"),
Objective::minimize("f2"),
]);
let s = ObjectiveSpace::new(vec![Objective::minimize("f1"), Objective::minimize("f2")]);
// (2, 1): axis 0 equals the reference → not strictly dominating.
let e = Evaluation::new(vec![2.0, 1.0]);
let evals = vec![&e];
assert_eq!(hypervolume_nd_from_evaluations(&evals, &s, &[2.0, 2.0]), 0.0);
assert_eq!(
hypervolume_nd_from_evaluations(&evals, &s, &[2.0, 2.0]),
0.0
);
}
}
+4 -1
View File
@@ -135,7 +135,10 @@ mod tests {
];
let got = spacing(&front, &s);
let expected = (1536.0_f64 / 27.0).sqrt();
assert!((got - expected).abs() < 1e-9, "got {got}, expected {expected}");
assert!(
(got - expected).abs() < 1e-9,
"got {got}, expected {expected}"
);
}
/// A perfectly even front has zero spacing — the variance term is 0.
+8 -2
View File
@@ -994,7 +994,10 @@ mod tests {
let c = m.vary(std::slice::from_ref(&parent), &mut rng);
c[0] != parent
});
assert!(any_changed, "InversionMutation never modified an 8-element parent across 30 seeds");
assert!(
any_changed,
"InversionMutation never modified an 8-element parent across 30 seeds"
);
}
/// `InsertionMutation` shifts an element across many seeds; at least one
@@ -1195,6 +1198,9 @@ mod tests {
let kids = erx.vary(&[p1.clone(), p2.clone()], &mut rng);
kids[0] != kids[1]
});
assert!(any_distinct, "ERX never produced distinct children across 30 seeds");
assert!(
any_distinct,
"ERX never produced distinct children across 30 seeds"
);
}
}
+15 -7
View File
@@ -733,7 +733,11 @@ mod tests {
// snapshot, by design.
fn assert_close_slice(got: &[f64], want: &[f64], tol: f64) {
assert_eq!(got.len(), want.len(), "length mismatch: got {got:?} want {want:?}");
assert_eq!(
got.len(),
want.len(),
"length mismatch: got {got:?} want {want:?}"
);
for (g, w) in got.iter().zip(want.iter()) {
assert!((g - w).abs() < tol, "got {g}, want {w}; full got = {got:?}");
}
@@ -747,7 +751,11 @@ mod tests {
let children = m.vary(std::slice::from_ref(&parent), &mut rng);
assert_close_slice(
&children[0],
&[1.034_713_959_180_981_7, 2.066_469_060_997_062_6, 3.131_288_178_686_977],
&[
1.034_713_959_180_981_7,
2.066_469_060_997_062_6,
3.131_288_178_686_977,
],
1e-12,
);
}
@@ -854,7 +862,10 @@ mod tests {
// Same seed → same δ; the only difference is the (hi-lo) factor.
// Ratio must be ≈ 10.
let ratio = wide / narrow;
assert!((ratio - 10.0).abs() < 1e-12, "ratio = {ratio}, narrow={narrow}, wide={wide}");
assert!(
(ratio - 10.0).abs() < 1e-12,
"ratio = {ratio}, narrow={narrow}, wide={wide}"
);
}
#[test]
@@ -890,10 +901,7 @@ mod tests {
fn mantegna_sigma_u_alpha_1_0_pinned() {
// alpha = 1.0: sin(π/2) = 1, gamma(2) = 1, gamma(1) = 1 → σᵤ ≈ 1.
let got = mantegna_sigma_u(1.0);
assert!(
(got - 1.0).abs() < 1e-12,
"mantegna_sigma_u(1.0) = {got}",
);
assert!((got - 1.0).abs() < 1e-12, "mantegna_sigma_u(1.0) = {got}",);
}
#[test]
+8 -2
View File
@@ -317,9 +317,15 @@ mod tests {
#[test]
fn infeasible_candidate_with_smaller_violation_evicts_larger() {
let mut a = ParetoArchive::<u32>::new(space_min2());
a.insert(Candidate::new(1u32, Evaluation::constrained(vec![0.0, 0.0], 1.0)));
a.insert(Candidate::new(
1u32,
Evaluation::constrained(vec![0.0, 0.0], 1.0),
));
// Smaller violation → dominates the existing infeasible member.
a.insert(Candidate::new(2u32, Evaluation::constrained(vec![9.0, 9.0], 0.5)));
a.insert(Candidate::new(
2u32,
Evaluation::constrained(vec![9.0, 9.0], 0.5),
));
assert_eq!(a.members().len(), 1);
assert_eq!(a.members()[0].decision, 2);
}
+10 -2
View File
@@ -169,7 +169,11 @@ mod tests {
fn interior_point_distance_is_pinned() {
let s = space_min2();
// Front along the line f1 + f2 = 4: (0,4), (2,2), (4,0).
let pop = [cand(vec![0.0, 4.0]), cand(vec![2.0, 2.0]), cand(vec![4.0, 0.0])];
let pop = [
cand(vec![0.0, 4.0]),
cand(vec![2.0, 2.0]),
cand(vec![4.0, 0.0]),
];
let d = crowding_distance(&pop, &[0, 1, 2], &s);
// Boundary points are infinite; the middle point gets
// (4-0)/4 + (4-0)/4 = 2.0 (objective 0 span 4, objective 1 span 4).
@@ -184,7 +188,11 @@ mod tests {
fn asymmetric_interior_distance_is_pinned() {
let s = space_min2();
// (0,10), (1,2), (10,0): objective-0 span = 10, objective-1 span = 10.
let pop = [cand(vec![0.0, 10.0]), cand(vec![1.0, 2.0]), cand(vec![10.0, 0.0])];
let pop = [
cand(vec![0.0, 10.0]),
cand(vec![1.0, 2.0]),
cand(vec![10.0, 0.0]),
];
let d = crowding_distance(&pop, &[0, 1, 2], &s);
// middle point: obj0 (10-0)/10 = 1.0; obj1 (10-0)/10 = 1.0 → 2.0.
assert!((d[1] - 2.0).abs() < 1e-12, "got {}", d[1]);
+42 -10
View File
@@ -282,15 +282,27 @@ mod tests {
let feasible = cand_min(1, 100.0);
let infeasible = constrained(2, 0.0, 1.0);
assert!(challenger_wins(&feasible, &infeasible, Direction::Minimize));
assert!(!challenger_wins(&infeasible, &feasible, Direction::Minimize));
assert!(!challenger_wins(
&infeasible,
&feasible,
Direction::Minimize
));
}
#[test]
fn challenger_wins_two_infeasible_compares_violation() {
let less_violating = constrained(1, 0.0, 0.5);
let more_violating = constrained(2, 0.0, 1.0);
assert!(challenger_wins(&less_violating, &more_violating, Direction::Minimize));
assert!(!challenger_wins(&more_violating, &less_violating, Direction::Minimize));
assert!(challenger_wins(
&less_violating,
&more_violating,
Direction::Minimize
));
assert!(!challenger_wins(
&more_violating,
&less_violating,
Direction::Minimize
));
}
#[test]
@@ -330,17 +342,37 @@ mod tests {
let feasible_a = Evaluation::new(vec![10.0]);
let infeasible_b = Evaluation::constrained(vec![0.0], 1.0);
// feasible vs infeasible
assert!(better_by_feasibility(&feasible_a, &infeasible_b, Direction::Minimize));
assert!(!better_by_feasibility(&infeasible_b, &feasible_a, Direction::Minimize));
assert!(better_by_feasibility(
&feasible_a,
&infeasible_b,
Direction::Minimize
));
assert!(!better_by_feasibility(
&infeasible_b,
&feasible_a,
Direction::Minimize
));
// two infeasible: smaller violation wins
let low_cv = Evaluation::constrained(vec![0.0], 0.3);
let high_cv = Evaluation::constrained(vec![0.0], 0.9);
assert!(better_by_feasibility(&low_cv, &high_cv, Direction::Minimize));
assert!(!better_by_feasibility(&high_cv, &low_cv, Direction::Minimize));
assert!(better_by_feasibility(
&low_cv,
&high_cv,
Direction::Minimize
));
assert!(!better_by_feasibility(
&high_cv,
&low_cv,
Direction::Minimize
));
// two feasible: delegates to better_by_objective
let feasible_lower = Evaluation::new(vec![1.0]);
let feasible_higher = Evaluation::new(vec![2.0]);
assert!(better_by_feasibility(&feasible_lower, &feasible_higher, Direction::Minimize));
assert!(better_by_feasibility(
&feasible_lower,
&feasible_higher,
Direction::Minimize
));
}
#[test]
@@ -349,8 +381,8 @@ mod tests {
// must rank first regardless of objective value.
let s = ObjectiveSpace::new(vec![Objective::minimize("f")]);
let pop = [
constrained(1, 0.0, 2.0), // infeasible, great objective
cand_min(2, 100.0), // feasible, terrible objective
constrained(1, 0.0, 2.0), // infeasible, great objective
cand_min(2, 100.0), // feasible, terrible objective
];
let mut rng = rng_from_seed(7);
let picks = stochastic_ranking_select(&pop, &s, 0.0, 1, &mut rng);