#[cfg(test)]
mod tests_aoc2 {
use crate::{ComparisonOp, OptimizationDirection, Problem, Variable};
#[test]
fn solve_ilp() {
let buttons: Vec<Vec<usize>> = vec![
vec![8],
vec![0, 1, 3, 4, 6, 8],
vec![1, 3, 4, 5, 7, 8],
vec![2, 4],
vec![0, 1, 3, 5],
vec![0, 2, 3, 4, 5, 7, 8],
vec![1, 2, 3],
vec![0, 2, 5, 7],
vec![1, 2, 6],
vec![0, 1, 6],
vec![1, 2, 4, 5, 6, 7, 8],
];
let target: Vec<i32> = vec![41, 60, 170, 51, 186, 40, 30, 34, 44];
let mut problem = Problem::new(OptimizationDirection::Minimize);
let mut press_counts = Vec::new();
for _ in 0..buttons.len() {
press_counts.push(problem.add_integer_var(1.0, (0, i32::MAX)));
}
for (target_idx, &target_val) in target.iter().enumerate() {
let mut terms: Vec<(Variable, f64)> = Vec::new();
for (btn_idx, button) in buttons.iter().enumerate() {
if button.contains(&target_idx) {
terms.push((press_counts[btn_idx], 1.0));
}
}
problem.add_constraint(&terms, ComparisonOp::Eq, target_val as f64);
}
let sol = problem.solve().unwrap();
let values: Vec<i64> = press_counts
.iter()
.map(|&var| sol.var_value(var) as i64)
.collect();
let total: i64 = values.iter().sum();
println!("Solver returned: {} total presses", total);
println!("Solution values: {:?}", values);
let mut achieved = vec![0i64; target.len()];
for (btn_idx, &count) in values.iter().enumerate() {
for &idx in &buttons[btn_idx] {
achieved[idx] += count;
}
}
println!("Verification:");
println!(" Expected: {:?}", target);
println!(" Achieved: {:?}", achieved);
for (i, (a, t)) in achieved.iter().zip(&target).enumerate() {
assert_eq!(
*a, *t as i64,
"Constraint {} violated: expected {}, got {}",
i, t, a
);
}
}
}