use std::time::{Duration, Instant}; use clap::Parser; use ddo::*; use model::{f, t}; use crate::{heuristics::Max2SatRanking, model::{Max2Sat, v}, relax::Max2SatRelax, data::read_instance}; mod errors; mod heuristics; mod data; mod model; mod relax; #[cfg(test)] mod tests; /// Solve max2sat instance #[derive(Debug, Parser)] #[command(author, version, about, long_about = None)] struct Params { /// the instance file #[arg(short, long)] file: String, /// maximum width in a layer #[arg(short, long)] width: Option, /// max time to find the solution #[arg(short, long)] timeout: Option, } fn main() { let Params{file, width, timeout} = Params::parse(); let problem = Max2Sat::new(read_instance(file).unwrap()); let relax = Max2SatRelax(&problem); let rank = Max2SatRanking; let width = max_width(&problem, width); let dominance = EmptyDominanceChecker::default(); let cutoff = cutoff(timeout); let mut fringe = NoDupFringe::new(MaxUB::new(&Max2SatRanking)); let mut solver = DefaultSolver::new( &problem, &relax, &rank, width.as_ref(), &dominance, cutoff.as_ref(), &mut fringe, ); let start = Instant::now(); let Completion{ is_exact, best_value } = solver.maximize(); let duration = start.elapsed(); let upper_bound = solver.best_upper_bound(); let lower_bound = solver.best_lower_bound(); let gap = solver.gap(); let best_solution = solver.best_solution().map(|mut decisions|{ decisions.sort_unstable_by_key(|d| d.variable.id()); decisions.iter().map(|d| v(d.variable) * d.value).collect::>() }); println!("Duration: {:.3} seconds", duration.as_secs_f32()); println!("Objective: {}", best_value.unwrap_or(-1)); println!("Upper Bnd: {}", upper_bound); println!("Lower Bnd: {}", lower_bound); println!("Gap: {:.3}", gap); println!("Aborted: {}", !is_exact); println!("Cost: {:?}", solution_cost(&problem, &solver.best_solution())); println!("Solution: {:?}", best_solution.unwrap_or_default()); } fn cutoff(timeout: Option) -> Box { if let Some(t) = timeout { Box::new(TimeBudget::new(Duration::from_secs(t))) } else { Box::new(NoCutoff) } } fn max_width(p: &P, w: Option) -> Box + Send + Sync> { if let Some(w) = w { Box::new(FixedWidth(w)) } else { Box::new(NbUnassignedWidth(p.nb_variables())) } } fn solution_cost(pb: &Max2Sat, solution: &Option>) -> isize { if let Some(sol) = solution { let n = pb.nb_vars; let mut model = vec![0; n]; for d in sol.iter() { model[d.variable.id()] = d.value; } let mut cost = 0; for i in 0..n { for j in i..n { if model[i] == 1 && model[j] == 1 { cost += pb.weight(f(Variable(i)), f(Variable(j))) } if model[i] ==-1 && model[j] ==-1 { cost += pb.weight(t(Variable(i)), t(Variable(j))) } if model[i] == 1 && model[j] ==-1 { cost += pb.weight(f(Variable(i)), t(Variable(j))) } if model[i] ==-1 && model[j] == 1 { cost += pb.weight(t(Variable(i)), f(Variable(j))) } } } cost } else { 0 } }