use graph::{Node, IndexGraph};
use builder::Builder;
use super::{read_dimacs, DimacsError};
use num::traits::FromPrimitive;
use std::io;
use std::fs;
pub struct Instance<G, F, N>
where G: for <'a> IndexGraph<'a, Node=N>
{
pub graph: G,
pub src: N,
pub snk: N,
pub upper: Vec<F>,
}
impl<G, F, N> Instance<G, F, N>
where G: for <'a> IndexGraph<'a, Node=N>,
F: FromPrimitive,
N: Node,
{
pub fn read(fname: &str) -> Result<Self, DimacsError> {
let f = try!(fs::File::open(fname));
Instance::read_from_buf(&mut io::BufReader::new(f))
}
pub fn read_from_buf<R>(buf: &mut R) -> Result<Self, DimacsError>
where R: io::BufRead,
{
let mut g = G::Builder::new();
let mut n = 0;
let mut m = 0;
let mut s = None;
let mut t = None;
let mut upper = vec![];
enum State {
Prob,
SrcSnk,
Arcs,
};
let mut state = State::Prob;
let mut nodes = vec![];
try!(read_dimacs(buf,
&mut |d, toks| {
match state {
State::Prob => {
if d != 'p' {
return Err(DimacsError::Format(toks.line,
format!("expected problem line starting with 'p', got: {}", d)));
}
let max = toks.next().unwrap_or("end of line");
if max != "max" {
return Err(DimacsError::Format(toks.line, format!("expected 'max' in p line, got: {}", max)));
}
n = try!(toks.number());
m = try!(toks.number());
try!(toks.end());
nodes = g.add_nodes(n);
upper.extend((0..m).map(|_| F::from_usize(0).unwrap()));
state = State::SrcSnk;
}
State::SrcSnk => {
let u: usize = try!(toks.number());
let what = try!(toks.str());
try!(toks.end());
if u < 1 || u > n {
return Err(DimacsError::Data(toks.line,
format!("invalid node id {} (must be <= {})", u, n)));
}
match what {
"s" => {
if s.is_some() {
return Err(DimacsError::Format(toks.line, "duplicate source node".to_string()));
}
s = Some(u);
}
"t" => {
if t.is_some() {
return Err(DimacsError::Format(toks.line, "duplicate sink node".to_string()));
}
t = Some(u);
}
_ => {
return Err(DimacsError::Format(toks.line,
"unexpected line (require source and sink nodes first)".to_string()))
}
}
if s.is_some() && t.is_some() {
state = State::Arcs;
}
}
State::Arcs => {
if d != 'a' {
return Err(DimacsError::Format(toks.line,
format!("expected arc line starting with 'a', got: {}", d)));
}
let u: usize = try!(toks.number());
let v: usize = try!(toks.number());
let c: usize = try!(toks.number());
if u < 1 || u > n {
return Err(DimacsError::Data(toks.line,
format!("invalid source node id {} (must be <= {})", u, n)));
}
if v < 1 || v > n {
return Err(DimacsError::Data(toks.line,
format!("invalid sink node id {} (must be <= {})", v, n)));
}
if u == v {
return Err(DimacsError::Data(toks.line, format!("invalid loop ({},{}) in edge", u, u)));
}
let e = g.add_edge(nodes[u-1], nodes[v-1]);
upper[g.edge_id(e)] = F::from_usize(c).unwrap();
}
}
Ok(())
}));
let s = g.node_id(s.map(|s| nodes[s - 1]).ok_or_else(|| DimacsError::Format(0, "missing source node".to_string()))?);
let t = g.node_id(t.map(|t| nodes[t - 1]).ok_or_else(|| DimacsError::Format(0, "missing sink node".to_string()))?);
let g = g.to_graph();
let s = g.id2node(s);
let t = g.id2node(t);
Ok(Instance { graph: g, src: s, snk: t, upper: upper })
}
}
#[cfg(test)]
mod tests {
use {Graph, Digraph, IndexGraph, LinkedListGraph};
use dimacs::maxflow::Instance;
use std::io;
#[test]
fn parse_file_test() {
let file = "c this is a test file
p max 6 9
n 5 s
n 6 t
c there might be empty lines
a 5 1 10
a 5 2 10
a 1 2 2
a 1 3 4
a 1 4 8
a 2 4 9
a 3 6 10
a 4 3 6
a 4 6 10
c end of the file
";
let instance = Instance::read_from_buf(&mut io::Cursor::new(file)).unwrap();
let g: LinkedListGraph = instance.graph;
let src = instance.src;
let snk = instance.snk;
let upper = instance.upper;
assert_eq!(g.num_nodes(), 6);
assert_eq!(g.num_edges(), 9);
assert_eq!(g.node_id(src), 4);
assert_eq!(g.node_id(snk), 5);
let mut arcs: Vec<_> = g.edges().map(|e| {
(g.node_id(g.src(e)) + 1, g.node_id(g.snk(e)) + 1, upper[g.edge_id(e)])
}).collect();
arcs.sort();
assert_eq!(arcs,
vec![(1, 2, 2), (1, 3, 4), (1, 4, 8), (2, 4, 9), (3, 6, 10), (4, 3, 6), (4, 6, 10), (5, 1, 10), (5, 2, 10)]);
}
}