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;
#[derive(Debug, Parser)]
#[command(author, version, about, long_about = None)]
struct Params {
#[arg(short, long)]
file: String,
#[arg(short, long)]
width: Option<usize>,
#[arg(short, long)]
timeout: Option<u64>,
}
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::<Vec<_>>()
});
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<u64>) -> Box<dyn Cutoff + Send + Sync> {
if let Some(t) = timeout {
Box::new(TimeBudget::new(Duration::from_secs(t)))
} else {
Box::new(NoCutoff)
}
}
fn max_width<P: Problem>(p: &P, w: Option<usize>) -> Box<dyn WidthHeuristic<P::State> + 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<Vec<Decision>>) -> 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
}
}