use std::time::Instant;
use selen::prelude::*;
fn benchmark<F>(name: &str, iterations: usize, mut f: F)
where
F: FnMut(),
{
let start = Instant::now();
for _ in 0..iterations {
f();
}
let elapsed = start.elapsed();
let avg_ms = elapsed.as_secs_f64() * 1000.0 / iterations as f64;
println!("{:50} | {:6.3} ms/iter | total: {:8.3} ms", name, avg_ms, elapsed.as_secs_f64() * 1000.0);
}
fn sum_forward_10vars() {
benchmark("sum_forward_10vars_domain_1_10", 100, || {
let mut m = Model::default();
let vars: Vec<_> = (0..10).map(|_| m.int(1, 10)).collect();
let target = m.int(20, 100);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_forward_20vars() {
benchmark("sum_forward_20vars_domain_1_10", 50, || {
let mut m = Model::default();
let vars: Vec<_> = (0..20).map(|_| m.int(1, 10)).collect();
let target = m.int(50, 200);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_forward_50vars() {
benchmark("sum_forward_50vars_domain_1_10", 10, || {
let mut m = Model::default();
let vars: Vec<_> = (0..50).map(|_| m.int(1, 10)).collect();
let target = m.int(150, 500);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_forward_100vars() {
benchmark("sum_forward_100vars_domain_1_10", 3, || {
let mut m = Model::default();
let vars: Vec<_> = (0..100).map(|_| m.int(1, 10)).collect();
let target = m.int(300, 1000);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_forward_200vars() {
benchmark("sum_forward_200vars_domain_1_10", 1, || {
let mut m = Model::default();
let vars: Vec<_> = (0..200).map(|_| m.int(1, 10)).collect();
let target = m.int(600, 2000);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_forward_500vars() {
benchmark("sum_forward_500vars_domain_1_10", 1, || {
let mut m = Model::default();
let vars: Vec<_> = (0..500).map(|_| m.int(1, 10)).collect();
let target = m.int(2000, 5000);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_100vars_large_domain() {
benchmark("sum_100vars_domain_1_100", 1, || {
let mut m = Model::default();
let vars: Vec<_> = (0..100).map(|_| m.int(1, 100)).collect();
let target = m.int(3000, 8000);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn multiple_overlapping_sums_50vars() {
benchmark("multiple_overlapping_sums_50vars", 2, || {
let mut m = Model::default();
let vars: Vec<_> = (0..50).map(|_| m.int(1, 10)).collect();
let sum1 = sum(&mut m, &vars[0..25]);
let sum2 = sum(&mut m, &vars[25..50]);
let sum3 = sum(&mut m, &vars[0..10]); let sum4 = sum(&mut m, &vars[40..50]);
let t1 = m.int(75, 200);
let t2 = m.int(75, 200);
let t3 = m.int(30, 80);
let t4 = m.int(30, 80);
m.new(sum1.eq(t1));
m.new(sum2.eq(t2));
m.new(sum3.eq(t3));
m.new(sum4.eq(t4));
let _sol = m.solve();
});
}
fn sum_50vars_ultra_tight_bounds() {
benchmark("sum_50vars_ultra_tight_bounds", 2, || {
let mut m = Model::default();
let vars: Vec<_> = (0..50).map(|_| m.int(1, 10)).collect();
let target = m.int(249, 251); let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_with_alldiff_30vars() {
benchmark("sum_with_alldiff_30vars_domain_1_30", 2, || {
let mut m = Model::default();
let vars: Vec<_> = (0..30).map(|_| m.int(1, 30)).collect();
alldiff(&mut m, &vars);
let target = m.int(350, 550);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_200vars_wide_domain() {
benchmark("sum_200vars_domain_1_100", 1, || {
let mut m = Model::default();
let vars: Vec<_> = (0..200).map(|_| m.int(1, 100)).collect();
let target = m.int(8000, 15000);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_with_alldiff_10vars() {
benchmark("sum_with_alldiff_10vars_domain_1_10", 50, || {
let mut m = Model::default();
let vars: Vec<_> = (0..10).map(|_| m.int(1, 10)).collect();
alldiff(&mut m, &vars);
let target = m.int(40, 60);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn multiple_sums_10vars() {
benchmark("multiple_sums_10vars_domain_1_10", 50, || {
let mut m = Model::default();
let vars: Vec<_> = (0..10).map(|_| m.int(1, 10)).collect();
let sum1 = sum(&mut m, &vars[0..5]);
let sum2 = sum(&mut m, &vars[5..10]);
let target1 = m.int(15, 40);
let target2 = m.int(15, 40);
m.new(sum1.eq(target1));
m.new(sum2.eq(target2));
let _sol = m.solve();
});
}
fn sudoku_4x4() {
benchmark("sudoku_4x4", 20, || {
let mut m = Model::default();
let mut grid = Vec::new();
for _ in 0..4 {
let row = (0..4).map(|_| m.int(1, 4)).collect::<Vec<_>>();
grid.push(row);
}
for row in 0..4 {
let row_vars: Vec<_> = (0..4).map(|col| grid[row][col]).collect();
alldiff(&mut m, &row_vars);
}
for col in 0..4 {
let col_vars: Vec<_> = (0..4).map(|row| grid[row][col]).collect();
alldiff(&mut m, &col_vars);
}
let _sol = m.solve();
});
}
fn sum_large_domain() {
benchmark("sum_10vars_domain_1_100", 50, || {
let mut m = Model::default();
let vars: Vec<_> = (0..10).map(|_| m.int(1, 100)).collect();
let target = m.int(200, 1000);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_tight_bounds() {
benchmark("sum_10vars_tight_bounds", 50, || {
let mut m = Model::default();
let vars: Vec<_> = (0..10).map(|_| m.int(1, 10)).collect();
let target = m.int(45, 50); let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn sum_deep_search_tree() {
benchmark("sum_5vars_deep_search", 100, || {
let mut m = Model::default();
let x1 = m.int(1, 3);
let x2 = m.int(1, 3);
let x3 = m.int(1, 3);
let x4 = m.int(1, 3);
let x5 = m.int(1, 3);
let vars = vec![x1, x2, x3, x4, x5];
let target = m.int(10, 15);
let s = sum(&mut m, &vars);
m.new(s.eq(target));
let _sol = m.solve();
});
}
fn main() {
println!("\n=== Sum Constraint Benchmarks (Baseline) ===");
println!("{:50} | {:14} | {:14}", "Benchmark", "Avg Time", "Total Time");
println!("{}", "=".repeat(80));
sum_forward_10vars();
sum_forward_20vars();
sum_forward_50vars();
sum_forward_100vars();
sum_forward_200vars();
sum_forward_500vars();
sum_100vars_large_domain();
sum_with_alldiff_10vars();
sum_with_alldiff_30vars();
multiple_sums_10vars();
multiple_overlapping_sums_50vars();
sudoku_4x4();
sum_large_domain();
sum_200vars_wide_domain();
sum_tight_bounds();
sum_50vars_ultra_tight_bounds();
sum_deep_search_tree();
println!("{}", "=".repeat(80));
println!("\nNote: These are baseline measurements before incremental optimization.");
println!("After implementing incremental sum, run again to compare performance.");
}