use std::fs;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::time::Instant;
use tide_maxflow::{max_flow_adaptive_timed, max_flow_hybrid_timed, max_flow_timed};
fn parse_dimacs(path: &Path) -> (usize, usize, usize, Vec<(usize, usize, i64)>) {
let file = fs::File::open(path).unwrap();
let reader = BufReader::new(file);
let mut n = 0usize;
let mut source = 0usize;
let mut sink = 0usize;
let mut edges = Vec::new();
for line in reader.lines() {
let line = line.unwrap();
let line = line.trim();
if line.is_empty() || line.starts_with('c') {
continue;
}
let parts: Vec<&str> = line.split_whitespace().collect();
match parts[0] {
"p" => {
n = parts[2].parse().unwrap();
}
"n" => {
let id: usize = parts[1].parse().unwrap();
match parts[2] {
"s" => source = id - 1, "t" => sink = id - 1,
_ => {}
}
}
"a" => {
let from: usize = parts[1].parse().unwrap();
let to: usize = parts[2].parse().unwrap();
let cap: i64 = parts[3].parse().unwrap();
edges.push((from - 1, to - 1, cap)); }
_ => {}
}
}
(n, source, sink, edges)
}
fn solve_file(path: &Path, mode: &str) {
let filename = path.file_stem().unwrap().to_str().unwrap();
let t_parse_start = Instant::now();
let (n, source, sink, edges) = parse_dimacs(path);
let parse_us = t_parse_start.elapsed().as_micros() as u64;
let m = edges.len();
let t_solve_start = Instant::now();
let timed = match mode {
"hybrid" => max_flow_hybrid_timed(n, source, sink, &edges),
"adaptive" => max_flow_adaptive_timed(n, source, sink, &edges),
_ => max_flow_timed(n, source, sink, &edges),
};
let solve_us = t_solve_start.elapsed().as_micros() as u64;
let r = &timed.result;
let t = &timed.timing;
println!(
"{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
filename,
n,
m,
source,
sink,
r.flow,
r.steps,
parse_us,
solve_us,
t.relabel_us,
t.pull_us,
t.push_us,
t.convergence_us,
t.relabel_skipped,
);
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let mode = if args.iter().any(|a| a == "--adaptive") {
"adaptive"
} else if args.iter().any(|a| a == "--hybrid") {
"hybrid"
} else {
"standard"
};
let max_size: Option<u64> = args
.windows(2)
.find(|w| w[0] == "--max-size")
.and_then(|w| w[1].parse().ok());
let filtered_args: Vec<&String> = {
let mut result = Vec::new();
let mut skip_next = false;
for a in &args {
if skip_next {
skip_next = false;
continue;
}
if a == "--max-size" {
skip_next = true;
continue;
}
if a == "--hybrid" || a == "--adaptive" || a == "--cascade" {
continue;
}
result.push(a);
}
result
};
println!("name,n,m,source,sink,max_flow,steps,parse_us,solve_us,relabel_us,pull_us,push_us,convergence_us,relabel_skipped");
if filtered_args.len() >= 3 && filtered_args[1] == "--dir" {
let dir = Path::new(filtered_args[2].as_str());
let mut entries: Vec<_> = fs::read_dir(dir)
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().map_or(false, |ext| ext == "max"))
.filter(|e| {
if let Some(max) = max_size {
e.metadata().map_or(false, |m| m.len() <= max)
} else {
true
}
})
.collect();
entries.sort_by_key(|e| e.file_name());
for entry in entries {
solve_file(&entry.path(), mode);
}
} else {
for path_str in &filtered_args[1..] {
solve_file(Path::new(path_str.as_str()), mode);
}
}
}