1use super::{DimacsReader, Error, Result};
41use crate::builder::{Buildable, Builder};
42use crate::traits::IndexDigraph;
43use num_traits::Zero;
44use std::fmt::Display;
45use std::io::{Read, Write};
46use std::str::FromStr;
47
48pub struct Instance<G, T> {
49 pub graph: G,
51 pub balances: Vec<T>,
53 pub lower: Vec<T>,
55 pub upper: Vec<T>,
57 pub costs: Vec<T>,
59}
60
61pub fn read<R: Read, G, T>(reader: R) -> Result<Instance<G, T>>
62where
63 G: IndexDigraph + Buildable,
64 T: FromStr + Zero + Clone,
65 T::Err: Display,
66{
67 let mut reader = DimacsReader::new(reader);
68
69 let mut pline = reader.expect_line('p')?;
71 pline.expect("min")?;
72 let nnodes = pline.number()?;
73 let nedges = pline.number()?;
74 pline.end()?;
75
76 let mut builder = G::Builder::new();
77 let mut balances = vec![T::zero(); nnodes];
78 let mut costs = Vec::with_capacity(nedges);
79 let mut lower = Vec::with_capacity(nedges);
80 let mut upper = Vec::with_capacity(nedges);
81
82 let nodes = builder.add_nodes(nnodes);
83
84 while let Some((d, mut toks)) = reader.read_one_line_of(&["n", "a"])? {
85 #[allow(clippy::branches_sharing_code)]
86 if d == "n" {
87 let u: usize = toks.number()?;
88 if u < 1 || u > nnodes {
89 return Err(Error::Data {
90 line: toks.line,
91 msg: format!("invalid node id {} (must be in 1..{})", u, nnodes),
92 });
93 }
94 balances[u - 1] = toks.number()?;
95 } else {
96 let u: usize = toks.number()?;
97 let v: usize = toks.number()?;
98 let lb: T = toks.number()?;
99 let ub: T = toks.number()?;
100 let c: T = toks.number()?;
101
102 if u < 1 || u > nnodes {
103 return Err(Error::Data {
104 line: toks.line,
105 msg: format!("invalid source node id {} (must be in 1..{})", u, nnodes),
106 });
107 }
108
109 if v < 1 || v > nnodes {
110 return Err(Error::Data {
111 line: toks.line,
112 msg: format!("invalid sink node id {} (must be in 1..{})", u, nnodes),
113 });
114 }
115
116 if u == v {
117 return Err(Error::Data {
118 line: toks.line,
119 msg: format!("invalid loop ({},{}) in edge", u, u),
120 });
121 }
122
123 if upper.len() == nedges {
124 return Err(Error::Data {
125 line: toks.line,
126 msg: format!("unexpected 'a' line (expected exactly {} arcs)", nedges),
127 });
128 }
129
130 builder.add_edge(nodes[u - 1], nodes[v - 1]);
131 lower.push(lb);
132 upper.push(ub);
133 costs.push(c);
134 }
135
136 toks.end()?;
137 }
138
139 Ok(Instance {
140 graph: builder.into_graph(),
141 balances,
142 lower,
143 upper,
144 costs,
145 })
146}
147
148pub fn read_from_file<G, T>(filename: &str) -> Result<Instance<G, T>>
149where
150 G: IndexDigraph + Buildable,
151 T: FromStr + Zero + Clone,
152 T::Err: Display,
153{
154 read(std::fs::File::open(filename)?)
155}
156
157pub fn write<W, G, T>(mut w: W, instance: &Instance<G, T>) -> std::io::Result<()>
159where
160 W: Write,
161 G: IndexDigraph,
162 T: Zero + Display + Clone,
163{
164 let g = &instance.graph;
165 writeln!(w, "p min {} {}", g.num_nodes(), g.num_edges())?;
166 for u in g.nodes() {
167 let b = instance.balances[g.node_id(u)].clone();
168 if !b.is_zero() {
169 writeln!(w, "n {} {}", g.node_id(u) + 1, b)?;
170 }
171 }
172 for e in g.edges() {
173 let eid = g.edge_id(e);
174 writeln!(
175 w,
176 "a {} {} {} {} {}",
177 g.node_id(g.src(e)) + 1,
178 g.node_id(g.snk(e)) + 1,
179 instance.lower[eid],
180 instance.upper[eid],
181 instance.costs[eid]
182 )?;
183 }
184
185 Ok(())
186}
187
188pub fn write_to_file<G, T>(filename: &str, instance: &Instance<G, T>) -> std::io::Result<()>
190where
191 G: IndexDigraph,
192 T: Zero + Display + Clone,
193{
194 write(&mut std::fs::File::create(filename)?, instance)
195}
196
197pub fn write_solution<'a, W, G, T, Fs>(mut w: W, g: &'a G, flow: Fs, value: T) -> std::io::Result<()>
199where
200 W: Write,
201 G: IndexDigraph,
202 T: Display + Zero,
203 Fs: Fn(G::Edge<'a>) -> T,
204{
205 writeln!(w, "s {}", value)?;
206 for e in g.edges() {
207 let fl = (flow)(e);
208 if !fl.is_zero() {
209 writeln!(w, "f {} {} {}", g.node_id(g.src(e)) + 1, g.node_id(g.snk(e)) + 1, fl)?;
210 }
211 }
212
213 Ok(())
214}
215
216pub fn write_solution_to_file<'a, G, T, Fs>(filename: &str, g: &'a G, flow: Fs, value: T) -> std::io::Result<()>
218where
219 G: IndexDigraph,
220 T: Display + Zero,
221 Fs: Fn(G::Edge<'a>) -> T,
222{
223 write_solution(&mut std::fs::File::create(filename)?, g, flow, value)
224}
225
226#[allow(clippy::type_complexity)]
228pub fn read_solution<R, T>(r: R) -> Result<(T, Vec<(usize, usize, T)>)>
229where
230 R: Read,
231 T: FromStr,
232 T::Err: Display,
233{
234 let mut reader = DimacsReader::new(r);
235 let mut flows = vec![];
236 let mut sol = None;
237
238 while let Some((d, mut toks)) = reader.read_one_line_of(&["f", "s"])? {
240 if d == "f" {
241 flows.push((toks.number::<usize>()? - 1, toks.number::<usize>()? - 1, toks.number()?));
242 } else {
243 if sol.is_some() {
244 return Err(Error::Format {
245 line: toks.line,
246 msg: "The solution value must be specified exactly once".to_string(),
247 });
248 }
249 sol = Some(toks.number()?);
250 }
251 toks.end()?;
252 }
253
254 Ok((
255 sol.ok_or_else(|| Error::Format {
256 line: 0,
257 msg: "Missing solution value".to_string(),
258 })?,
259 flows,
260 ))
261}
262
263#[allow(clippy::type_complexity)]
265pub fn read_solution_from_file<T>(filename: &str) -> Result<(T, Vec<(usize, usize, T)>)>
266where
267 T: FromStr,
268 T::Err: Display,
269{
270 read_solution(std::fs::File::open(filename)?)
271}
272
273#[cfg(test)]
274mod tests {
275
276 use crate::dimacs;
277 use crate::{traits::*, Buildable, Builder, VecGraph};
278 use std::io::{self, Cursor};
279
280 #[test]
281 fn parse_file_test() {
282 let file = "c this is a test file
283
284p min 8 11
285n 1 10
286n 2 20
287n 4 -5
288n 7 -15
289n 8 -10
290
291c there might be empty lines
292
293a 1 4 0 15 2
294a 2 1 0 10 1
295a 2 3 0 10 0
296a 2 6 0 10 6
297a 3 4 0 5 1
298a 3 5 0 10 4
299a 4 7 0 10 5
300a 5 6 0 20 2
301a 5 7 0 15 7
302a 6 8 0 10 8
303a 7 8 0 15 9
304
305c end of the file
306";
307 let instance = dimacs::min::read::<_, _, isize>(io::Cursor::new(file)).unwrap();
308
309 let g: VecGraph = instance.graph;
310 let balances = instance.balances;
311 let lower = instance.lower;
312 let upper = instance.upper;
313 let costs = instance.costs;
314
315 assert_eq!(g.num_nodes(), 8);
316 assert_eq!(g.num_edges(), 11);
317
318 assert_eq!(balances, vec![10, 20, 0, -5, 0, 0, -15, -10]);
319 assert_eq!(lower, vec![0; g.num_edges()]);
320 assert_eq!(upper, vec![15, 10, 10, 10, 5, 10, 10, 20, 15, 10, 15]);
321 assert_eq!(costs, vec![2, 1, 0, 6, 1, 4, 5, 2, 7, 8, 9]);
322
323 let edges = (0..g.num_edges())
324 .map(|i| g.id2edge(i))
325 .map(|e| (g.node_id(g.src(e)) + 1, g.node_id(g.snk(e)) + 1))
326 .collect::<Vec<_>>();
327
328 assert_eq!(
329 edges,
330 vec![
331 (1, 4),
332 (2, 1),
333 (2, 3),
334 (2, 6),
335 (3, 4),
336 (3, 5),
337 (4, 7),
338 (5, 6),
339 (5, 7),
340 (6, 8),
341 (7, 8),
342 ]
343 );
344 }
345
346 #[test]
347 fn write_test_file() {
348 let g = VecGraph::<u32>::new_with(|b| {
349 let nodes = b.add_nodes(4);
350 b.add_edge(nodes[0], nodes[1]);
351 b.add_edge(nodes[0], nodes[2]);
352 b.add_edge(nodes[1], nodes[2]);
353 b.add_edge(nodes[1], nodes[3]);
354 b.add_edge(nodes[2], nodes[3]);
355 });
356 let balances = vec![4, 0, 0, -4];
357 let lower = vec![0; g.num_edges()];
358 let upper = vec![4, 2, 2, 3, 5];
359 let costs = vec![2, 2, 1, 3, 1];
360
361 let mut buf = Cursor::new(Vec::new());
362 dimacs::min::write(
363 &mut buf,
364 &dimacs::min::Instance {
365 graph: &g,
366 balances,
367 lower,
368 upper,
369 costs,
370 },
371 )
372 .unwrap();
373
374 assert_eq!(
375 String::from_utf8(buf.into_inner()).unwrap(),
376 "p min 4 5
377n 1 4
378n 4 -4
379a 1 2 0 4 2
380a 1 3 0 2 2
381a 2 3 0 2 1
382a 2 4 0 3 3
383a 3 4 0 5 1
384"
385 );
386 }
387
388 #[test]
389 fn write_solution_file() -> std::result::Result<(), Box<dyn std::error::Error>> {
390 let g = VecGraph::<u32>::new_with(|b| {
391 let nodes = b.add_nodes(4);
392 b.add_edge(nodes[0], nodes[1]);
393 b.add_edge(nodes[0], nodes[2]);
394 b.add_edge(nodes[1], nodes[2]);
395 b.add_edge(nodes[1], nodes[3]);
396 b.add_edge(nodes[2], nodes[3]);
397 });
398 let flow = vec![2, 2, 2, 0, 4];
399
400 let mut buf = Cursor::new(Vec::new());
401 dimacs::min::write_solution(&mut buf, &g, |e| flow[g.edge_id(e)], 14)?;
402
403 let soltxt = String::from_utf8(buf.into_inner())?;
404 assert_eq!(
405 soltxt,
406 "s 14
407f 1 2 2
408f 1 3 2
409f 2 3 2
410f 3 4 4
411"
412 );
413
414 let (value, flows) = dimacs::min::read_solution(Cursor::new(soltxt))?;
415 assert_eq!(value, 14);
416 assert_eq!(flows, vec![(0, 1, 2), (0, 2, 2), (1, 2, 2), (2, 3, 4)]);
417
418 Ok(())
419 }
420}