#[derive(Debug, Clone)]
pub struct CrossoverMonotonicityConstraintData {
pub n_drivers: usize,
pub min_log_separation: f64,
}
pub fn constraint_crossover_monotonicity(
x: &[f64],
_grad: Option<&mut [f64]>,
data: &mut CrossoverMonotonicityConstraintData,
) -> f64 {
let n_drivers = data.n_drivers;
let n_xovers = n_drivers - 1;
if n_xovers <= 1 {
return 0.0;
}
let xover_start = 2 * n_drivers;
let mut max_violation = f64::NEG_INFINITY;
for i in 0..(n_xovers - 1) {
let log_xover_i = x[xover_start + i];
let log_xover_i_plus_1 = x[xover_start + i + 1];
let violation = log_xover_i + data.min_log_separation - log_xover_i_plus_1;
max_violation = max_violation.max(violation);
}
max_violation
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_monotonic_crossovers() {
let mut data = CrossoverMonotonicityConstraintData {
n_drivers: 3,
min_log_separation: 0.1,
};
let x = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.5, 3.0];
let result = constraint_crossover_monotonicity(&x, None, &mut data);
assert!(
result <= 0.0,
"Monotonic crossovers should satisfy constraint"
);
}
#[test]
fn test_non_monotonic_crossovers() {
let mut data = CrossoverMonotonicityConstraintData {
n_drivers: 3,
min_log_separation: 0.1,
};
let x = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 2.5];
let result = constraint_crossover_monotonicity(&x, None, &mut data);
assert!(
result > 0.0,
"Non-monotonic crossovers should violate constraint"
);
}
#[test]
fn test_too_close_crossovers() {
let mut data = CrossoverMonotonicityConstraintData {
n_drivers: 3,
min_log_separation: 0.2, };
let x = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.5, 2.6];
let result = constraint_crossover_monotonicity(&x, None, &mut data);
assert!(
result > 0.0,
"Crossovers too close should violate constraint"
);
}
#[test]
fn test_two_driver_system() {
let mut data = CrossoverMonotonicityConstraintData {
n_drivers: 2,
min_log_separation: 0.1,
};
let x = vec![0.0, 0.0, 0.0, 0.0, 2.5];
let result = constraint_crossover_monotonicity(&x, None, &mut data);
assert_eq!(
result, 0.0,
"2-driver system should return 0.0 (no violation)"
);
}
#[test]
fn test_four_driver_system() {
let mut data = CrossoverMonotonicityConstraintData {
n_drivers: 4,
min_log_separation: 0.15,
};
let x = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.5, 3.0, 3.5];
let result = constraint_crossover_monotonicity(&x, None, &mut data);
assert!(
result <= 0.0,
"Well-separated crossovers should satisfy constraint"
);
}
}