use num_traits::{Bounded, FromPrimitive, NumAssign, NumCast, Signed, ToPrimitive};
use rs_graph::dimacs;
use rs_graph::mcf::{simplex::Pricing, MinCostFlow, NetworkSimplex};
use rs_graph::traits::*;
use rs_graph::vec::{EdgeVec, NodeVec};
use rs_graph::Net;
use std::error::Error;
use std::io::Write;
use std::path::PathBuf;
use std::result::Result;
use rustop::opts;
use time::OffsetDateTime;
fn run<F>(filename: &str, pricing: Pricing) -> Result<(), Box<dyn Error>>
where
F: Bounded + NumCast + NumAssign + PartialOrd + Copy + FromPrimitive + ToPrimitive + Signed,
{
let tstart = OffsetDateTime::now_utc();
let instance = dimacs::min::read_from_file(filename).unwrap();
let g: Net = instance.graph;
let balances = NodeVec::new_from_vec(&g, instance.balances);
let lower = EdgeVec::new_from_vec(&g, instance.lower);
let upper = EdgeVec::new_from_vec(&g, instance.upper);
let costs = EdgeVec::new_from_vec(&g, instance.costs);
let tend = OffsetDateTime::now_utc();
println!("Instance : {}", filename);
println!("Read Time (seconds) : {}", (tend - tstart).as_seconds_f64());
println!("Graph type : {}", std::any::type_name::<Net>());
println!("Value type : {}", std::any::type_name::<F>());
println!("Number of nodes : {}", g.num_nodes());
println!("Number of edges : {}", g.num_edges());
let mut spx = NetworkSimplex::new(&g);
spx.pricing = pricing;
spx.set_balances(|u| F::from_isize(balances[u]).unwrap());
spx.set_lowers(|e| F::from_isize(lower[e]).unwrap());
spx.set_uppers(|e| F::from_isize(upper[e]).unwrap());
spx.set_costs(|e| F::from_isize(costs[e]).unwrap());
let tstart = OffsetDateTime::now_utc();
let state = spx.solve();
let tend = OffsetDateTime::now_utc();
let soltime = (tend - tstart).as_seconds_f64();
println!();
println!("Solution state : {:?}", state);
println!("Value : {:.2}", spx.value().to_f64().unwrap());
println!("Time (seconds) : {:.2}", soltime);
println!("Iterations (total) : {}", spx.num_iterations());
println!();
println!("Write solution to : {}.sol", filename);
let solfile = PathBuf::from(format!("{}.sol", filename));
let f = &mut std::fs::File::create(&solfile)?;
let fname = solfile
.file_name()
.map(|s| s.to_string_lossy())
.unwrap_or_else(|| "".into());
writeln!(f, "c Solved with a primal network simplex")?;
writeln!(f, "c instance : {}", fname)?;
writeln!(f, "c solution time : {:.2} seconds", soltime)?;
writeln!(f, "c number of iterations: {}", spx.num_iterations())?;
dimacs::min::write_solution(
f,
&g,
|e| spx.flow(e).to_isize().unwrap(),
spx.value().to_isize().unwrap(),
)?;
Ok(())
}
fn main() -> Result<(), Box<dyn Error>> {
let (args, _) = opts! {
synopsis "Solve min-cost-flow problem with a network simplex algorithm.";
param file:String, desc:"Instance file name";
opt dantzig:bool, desc:"Dantzig's rule pricing (most negative)";
opt first_eligible:bool, desc:"First eligible edge pricing (round robin)";
opt multiple_partial:bool, desc:"Multiple Partial Pricing";
opt floating_point:bool, desc:"Use floating point values";
}
.parse_or_exit();
let pricing = if args.dantzig {
Pricing::Complete
} else if args.first_eligible {
Pricing::RoundRobin
} else if args.multiple_partial {
Pricing::MultiplePartial
} else {
Pricing::Block
};
if args.floating_point {
run::<f64>(&args.file, pricing)
} else {
run::<isize>(&args.file, pricing)
}
}