use proptest::prelude::*;
use adk_eval::optimizer::run_optimization_loop;
fn arb_scores() -> impl Strategy<Value = Vec<f64>> {
prop::collection::vec(0.0..=1.0f64, 1..=21)
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_optimizer_respects_iteration_bounds(
max_iterations in 1u32..=20,
target_threshold in 0.0..=1.0f64,
scores in arb_scores(),
) {
let (iterations_run, best_score) = run_optimization_loop(
&scores,
max_iterations,
target_threshold,
);
prop_assert!(
iterations_run <= max_iterations,
"ran {} iterations but max is {}",
iterations_run,
max_iterations,
);
if scores[0] >= target_threshold {
prop_assert_eq!(
iterations_run, 0,
"initial score {} meets threshold {} but ran {} iterations",
scores[0], target_threshold, iterations_run,
);
}
if iterations_run > 0 && iterations_run < max_iterations && scores[0] < target_threshold {
prop_assert!(
best_score >= target_threshold,
"stopped early at iteration {} but best_score {} < threshold {}",
iterations_run,
best_score,
target_threshold,
);
}
let scores_seen: Vec<f64> = (0..=iterations_run as usize)
.map(|i| {
if i < scores.len() {
scores[i]
} else {
scores[scores.len() - 1]
}
})
.collect();
let expected_best = scores_seen
.iter()
.copied()
.fold(f64::NEG_INFINITY, f64::max);
prop_assert!(
(best_score - expected_best).abs() < f64::EPSILON,
"best_score {} != expected max {} from scores {:?}",
best_score,
expected_best,
scores_seen,
);
}
#[test]
fn prop_optimizer_runs_all_iterations_when_below_threshold(
max_iterations in 1u32..=20,
scores in prop::collection::vec(0.0..0.5f64, 1..=21),
) {
let target_threshold = 0.99;
let (iterations_run, _best_score) = run_optimization_loop(
&scores,
max_iterations,
target_threshold,
);
if scores[0] < target_threshold {
prop_assert_eq!(
iterations_run, max_iterations,
"expected {} iterations but ran {}",
max_iterations, iterations_run,
);
}
}
#[test]
fn prop_optimizer_stops_early_on_first_good_score(
max_iterations in 2u32..=20,
initial_score in 0.0..0.5f64,
good_score in 0.9..=1.0f64,
) {
let scores = vec![initial_score, good_score, 0.1, 0.1, 0.1];
let target_threshold = 0.9;
let (iterations_run, best_score) = run_optimization_loop(
&scores,
max_iterations,
target_threshold,
);
prop_assert_eq!(
iterations_run, 1,
"expected 1 iteration but ran {}",
iterations_run,
);
prop_assert!(
best_score >= target_threshold,
"best_score {} should meet threshold {}",
best_score,
target_threshold,
);
}
}