1use std::collections::VecDeque;
58use std::fmt;
59use std::io::{self, Write};
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub struct GridGraphParams {
68 pub height: i32,
70 pub width: i32,
72 pub max_capacity: i32,
74 pub max_cost: i32,
76 pub seed: i32,
78}
79
80impl GridGraphParams {
81 pub fn new(
83 height: i32,
84 width: i32,
85 max_capacity: i32,
86 max_cost: i32,
87 seed: i32,
88 ) -> Result<Self, GridGraphError> {
89 if height <= 0 {
90 return Err(GridGraphError::InvalidHeight);
91 }
92 if width < 2 {
93 return Err(GridGraphError::InvalidWidth);
94 }
95 if max_capacity <= 0 {
96 return Err(GridGraphError::InvalidMaxCapacity);
97 }
98 if max_cost <= 0 {
99 return Err(GridGraphError::InvalidMaxCost);
100 }
101 if seed <= 0 {
102 return Err(GridGraphError::InvalidSeed);
103 }
104 Ok(Self {
105 height,
106 width,
107 max_capacity,
108 max_cost,
109 seed,
110 })
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub enum GridGraphError {
117 InvalidHeight,
118 InvalidWidth,
119 InvalidMaxCapacity,
120 InvalidMaxCost,
121 InvalidSeed,
122}
123
124impl fmt::Display for GridGraphError {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 use GridGraphError::*;
127 match self {
128 InvalidHeight => write!(f, "height must be positive"),
129 InvalidWidth => write!(f, "width must be >= 2"),
130 InvalidMaxCapacity => write!(f, "max_capacity must be positive"),
131 InvalidMaxCost => write!(f, "max_cost must be positive"),
132 InvalidSeed => write!(f, "seed must be positive"),
133 }
134 }
135}
136
137impl std::error::Error for GridGraphError {}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
141pub struct GridArc {
142 pub from: i32,
144 pub to: i32,
146 pub capacity: i32,
148 pub cost: i32,
150}
151
152#[derive(Debug, Clone)]
154pub struct DimacsInstance {
155 params: GridGraphParams,
156 arcs: Vec<GridArc>,
157 node_count: i32,
158 arc_count: i32,
159 source: i32,
160 sink: i32,
161 max_flow: i64,
162}
163
164impl DimacsInstance {
165 pub fn params(&self) -> GridGraphParams {
167 self.params
168 }
169
170 pub fn node_count(&self) -> i32 {
172 self.node_count
173 }
174
175 pub fn arc_count(&self) -> i32 {
177 self.arc_count
178 }
179
180 pub fn source(&self) -> i32 {
182 self.source
183 }
184
185 pub fn sink(&self) -> i32 {
187 self.sink
188 }
189
190 pub fn max_flow(&self) -> i64 {
192 self.max_flow
193 }
194
195 pub fn arcs(&self) -> &[GridArc] {
197 &self.arcs
198 }
199
200 pub fn write_dimacs<W: fmt::Write>(&self, mut writer: W) -> fmt::Result {
202 let params = self.params;
203 writeln!(
204 writer,
205 "c max-flow min-cost on a{h:3} by {w:3} grid",
206 h = params.height,
207 w = params.width
208 )?;
209 writeln!(
210 writer,
211 "c cap: [0,{cap:8}] cost: [0,{cost:8}] seed:{seed:10}",
212 cap = params.max_capacity,
213 cost = params.max_cost,
214 seed = params.seed
215 )?;
216 writeln!(
217 writer,
218 "p min {nodes:15}{arcs:15}",
219 nodes = self.node_count,
220 arcs = self.arc_count
221 )?;
222 writeln!(
223 writer,
224 "n {src:15}{flow:15}",
225 src = self.source,
226 flow = self.max_flow
227 )?;
228 writeln!(
229 writer,
230 "n {sink:15}{neg_flow:15}",
231 sink = self.sink,
232 neg_flow = -self.max_flow
233 )?;
234 for arc in &self.arcs {
235 writeln!(
236 writer,
237 "a {from:10}{to:10} 0 {cap:10}{cost:10}",
238 from = arc.from,
239 to = arc.to,
240 cap = arc.capacity,
241 cost = arc.cost
242 )?;
243 }
244 Ok(())
245 }
246
247 pub fn to_dimacs_string(&self) -> String {
249 let mut out = String::new();
250 self.write_dimacs(&mut out).unwrap();
251 out
252 }
253
254 pub fn write_dimacs_io<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
256 struct Adapter<'a, W: io::Write>(&'a mut W);
257
258 impl<'a, W: io::Write> fmt::Write for Adapter<'a, W> {
259 fn write_str(&mut self, s: &str) -> fmt::Result {
260 self.0.write_all(s.as_bytes()).map_err(|_| fmt::Error)
261 }
262 }
263
264 let mut adapter = Adapter(&mut writer);
265 self.write_dimacs(&mut adapter)
266 .map_err(|_| std::io::Error::other("failed to format DIMACS output"))
267 }
268
269 pub fn write_to_file<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<()> {
271 let file = std::fs::File::create(path)?;
272 let mut buf = io::BufWriter::new(file);
273 self.write_dimacs_io(&mut buf)?;
274 buf.flush()
275 }
276}
277
278pub fn generate_instance(params: GridGraphParams) -> DimacsInstance {
280 let h = params.height;
281 let w = params.width;
282 let maxcap = params.max_capacity;
283 let maxcost = params.max_cost;
284
285 let nnodes = h * w + 2;
286 let narcs = 2 * (h - 1) * w + w + h;
287 let source = h * w + 1;
288 let sink = h * w + 2;
289
290 let mut seed = params.seed;
291 let arcs = generate_arcs(h, w, maxcap, maxcost, &mut seed);
292
293 let mut fg = FlowGraph::new(nnodes as usize + 1, narcs as usize * 2);
295 for arc in &arcs {
296 fg.add_edge(arc.from as usize, arc.to as usize, arc.capacity as i64);
297 }
298 let max_flow = fg.max_flow(source as usize, sink as usize);
299
300 DimacsInstance {
301 params,
302 arcs,
303 node_count: nnodes,
304 arc_count: narcs,
305 source,
306 sink,
307 max_flow,
308 }
309}
310
311pub fn generate_dimacs(params: GridGraphParams) -> String {
313 generate_instance(params).to_dimacs_string()
314}
315
316const A: i32 = 16807;
324const P: i32 = 2_147_483_647; const B15: i32 = 32768; const B16: i32 = 65536; fn schrage_rand(seed: &mut i32) -> f32 {
330 let ix = *seed;
331 let xhi = ix / B16;
332 let xalo = (ix - xhi * B16) * A;
333 let leftlo = xalo / B16;
334 let fhi = xhi * A + leftlo;
335 let k = fhi / B15;
336 let mut new_ix = ((xalo - leftlo * B16) - P) + (fhi - k * B15) * B16 + k;
337 if new_ix < 0 {
338 new_ix += P;
339 }
340 *seed = new_ix;
341 #[allow(clippy::excessive_precision)]
342 let scale = 4.656_612_875e-10_f32;
343 new_ix as f32 * scale
344}
345
346fn unif(max: i32, seed: &mut i32) -> i32 {
348 (1.0_f32 + schrage_rand(seed) * (max - 1) as f32) as i32
349}
350
351fn node(i: i32, j: i32, w: i32) -> i32 {
356 (i - 1) * w + j
357}
358
359fn generate_arcs(h: i32, w: i32, maxcap: i32, maxcost: i32, seed: &mut i32) -> Vec<GridArc> {
360 let narcs = 2 * (h - 1) * w + w + h;
361 let mut arcs = Vec::with_capacity(narcs as usize);
362
363 let mut caps = vec![0i32; (h + 1) as usize]; let mut costs = vec![0i32; (h + 1) as usize];
365 let mut capt = vec![0i32; (h + 1) as usize];
366 let mut costt = vec![0i32; (h + 1) as usize];
367
368 for i in 1..h {
370 let cap = unif(maxcap, seed);
371 let cost = unif(maxcost, seed);
372 caps[i as usize] = cap;
373 arcs.push(GridArc {
374 from: node(i, 1, w),
375 to: node(i, 2, w),
376 capacity: cap,
377 cost,
378 });
379
380 let cap = unif(maxcap, seed);
381 let cost = unif(maxcost, seed);
382 caps[i as usize] += cap;
383 arcs.push(GridArc {
384 from: node(i, 1, w),
385 to: node(i + 1, 1, w),
386 capacity: cap,
387 cost,
388 });
389
390 costs[i as usize] = unif(maxcost, seed); }
392
393 {
395 let cap = unif(maxcap, seed);
396 let cost = unif(maxcost, seed);
397 caps[h as usize] = cap;
398 arcs.push(GridArc {
399 from: node(h, 1, w),
400 to: node(h, 2, w),
401 capacity: cap,
402 cost,
403 });
404
405 costs[h as usize] = unif(maxcost, seed); }
407
408 for i in 1..h {
410 for j in 2..=(w - 2) {
411 let cap = unif(maxcap, seed);
412 let cost = unif(maxcost, seed);
413 arcs.push(GridArc {
414 from: node(i, j, w),
415 to: node(i, j + 1, w),
416 capacity: cap,
417 cost,
418 });
419
420 let cap = unif(maxcap, seed);
421 let cost = unif(maxcost, seed);
422 arcs.push(GridArc {
423 from: node(i, j, w),
424 to: node(i + 1, j, w),
425 capacity: cap,
426 cost,
427 });
428 }
429 }
430
431 for j in 2..=(w - 2) {
433 let cap = unif(maxcap, seed);
434 let cost = unif(maxcost, seed);
435 arcs.push(GridArc {
436 from: node(h, j, w),
437 to: node(h, j + 1, w),
438 capacity: cap,
439 cost,
440 });
441 }
442
443 for i in 1..h {
445 let cap = unif(maxcap, seed);
446 let cost = unif(maxcost, seed);
447 capt[i as usize] = cap;
448 arcs.push(GridArc {
449 from: node(i, w - 1, w),
450 to: node(i, w, w),
451 capacity: cap,
452 cost,
453 });
454
455 let cap = unif(maxcap, seed);
456 let cost = unif(maxcost, seed);
457 arcs.push(GridArc {
458 from: node(i, w - 1, w),
459 to: node(i + 1, w - 1, w),
460 capacity: cap,
461 cost,
462 });
463
464 costt[i as usize] = unif(maxcost, seed); }
466
467 {
469 let cap = unif(maxcap, seed);
470 let cost = unif(maxcost, seed);
471 capt[h as usize] = cap;
472 arcs.push(GridArc {
473 from: node(h, w - 1, w),
474 to: node(h, w, w),
475 capacity: cap,
476 cost,
477 });
478
479 costt[h as usize] = unif(maxcost, seed); }
481
482 for i in 1..h {
484 let cap = unif(maxcap, seed);
485 let cost = unif(maxcost, seed);
486 capt[(i + 1) as usize] += cap;
487 arcs.push(GridArc {
488 from: node(i, w, w),
489 to: node(i + 1, w, w),
490 capacity: cap,
491 cost,
492 });
493 }
494
495 let source = h * w + 1;
496 let sink = h * w + 2;
497
498 for i in 1..=h {
500 arcs.push(GridArc {
501 from: source,
502 to: node(i, 1, w),
503 capacity: caps[i as usize],
504 cost: costs[i as usize],
505 });
506 }
507
508 for i in 1..=h {
510 arcs.push(GridArc {
511 from: node(i, w, w),
512 to: sink,
513 capacity: capt[i as usize],
514 cost: costt[i as usize],
515 });
516 }
517
518 debug_assert_eq!(arcs.len(), narcs as usize);
519 arcs
520}
521
522struct FlowGraph {
527 n: usize,
528 head: Vec<i32>,
529 to: Vec<i32>,
530 cap: Vec<i64>,
531 next: Vec<i32>,
532}
533
534impl FlowGraph {
535 fn new(n: usize, arc_hint: usize) -> Self {
536 Self {
537 n,
538 head: vec![-1; n],
539 to: Vec::with_capacity(arc_hint),
540 cap: Vec::with_capacity(arc_hint),
541 next: Vec::with_capacity(arc_hint),
542 }
543 }
544
545 fn add_edge(&mut self, u: usize, v: usize, c: i64) {
546 let idx = self.to.len() as i32;
547 self.to.push(v as i32);
548 self.cap.push(c);
549 self.next.push(self.head[u]);
550 self.head[u] = idx;
551
552 let idx = self.to.len() as i32;
553 self.to.push(u as i32);
554 self.cap.push(0);
555 self.next.push(self.head[v]);
556 self.head[v] = idx;
557 }
558
559 fn bfs(&self, source: usize, sink: usize, level: &mut [i32]) -> bool {
560 level.iter_mut().for_each(|l| *l = -1);
561 level[source] = 0;
562 let mut queue = VecDeque::new();
563 queue.push_back(source);
564 while let Some(u) = queue.pop_front() {
565 let mut e = self.head[u];
566 while e != -1 {
567 let v = self.to[e as usize] as usize;
568 if level[v] == -1 && self.cap[e as usize] > 0 {
569 level[v] = level[u] + 1;
570 queue.push_back(v);
571 }
572 e = self.next[e as usize];
573 }
574 }
575 level[sink] != -1
576 }
577
578 fn dfs(&mut self, u: usize, sink: usize, pushed: i64, level: &[i32], iter: &mut [i32]) -> i64 {
579 if u == sink {
580 return pushed;
581 }
582 while iter[u] != -1 {
583 let e = iter[u] as usize;
584 let v = self.to[e] as usize;
585 if level[v] == level[u] + 1 && self.cap[e] > 0 {
586 let d = self.dfs(v, sink, pushed.min(self.cap[e]), level, iter);
587 if d > 0 {
588 self.cap[e] -= d;
589 self.cap[e ^ 1] += d;
590 return d;
591 }
592 }
593 iter[u] = self.next[iter[u] as usize];
594 }
595 0
596 }
597
598 fn max_flow(&mut self, source: usize, sink: usize) -> i64 {
599 let mut flow = 0i64;
600 let mut level = vec![0i32; self.n];
601 let mut iter = vec![0i32; self.n];
602 while self.bfs(source, sink, &mut level) {
603 iter.copy_from_slice(&self.head);
604 loop {
605 let f = self.dfs(source, sink, i64::MAX, &level, &mut iter);
606 if f == 0 {
607 break;
608 }
609 flow += f;
610 }
611 }
612 flow
613 }
614}
615
616#[cfg(test)]
617mod tests {
618 use super::*;
619 use std::process::Command;
620
621 #[test]
622 fn test_schrage_rand_seed_270001() {
623 let mut seed: i32 = 270_001;
624 let r1 = schrage_rand(&mut seed);
625 assert_eq!(seed, 242_939_513);
626 assert!((r1 - 0.11313).abs() < 1e-4, "r1 = {r1}");
627
628 let r2 = schrage_rand(&mut seed);
629 assert_eq!(seed, 717_982_044);
630 assert!((r2 - 0.33434).abs() < 1e-4, "r2 = {r2}");
631 }
632
633 #[test]
634 fn test_unif() {
635 let mut seed: i32 = 270_001;
636 assert_eq!(unif(10_000, &mut seed), 1132);
637 assert_eq!(unif(1_000, &mut seed), 335);
638 }
639
640 #[test]
641 fn test_arc_count() {
642 assert_eq!(2 * (3 - 1) * 3 + 3 + 3, 18);
643 assert_eq!(2 * (8 - 1) * 8 + 8 + 8, 128);
644 }
645
646 #[test]
647 fn test_node_numbering() {
648 assert_eq!(node(1, 1, 3), 1);
649 assert_eq!(node(2, 3, 3), 6);
650 assert_eq!(node(3, 3, 3), 9);
651 }
652
653 #[test]
654 fn e2e_3x3_known_output() {
655 let params = GridGraphParams::new(3, 3, 100, 10, 12345).unwrap();
656 let expected = "\
657c max-flow min-cost on a 3 by 3 grid
658c cap: [0, 100] cost: [0, 10] seed: 12345
659p min 11 18
660n 10 40
661n 11 -40
662a 1 2 0 10 8
663a 1 4 0 94 1
664a 4 5 0 6 7
665a 4 7 0 58 9
666a 7 8 0 33 2
667a 2 3 0 79 9
668a 2 5 0 15 4
669a 5 6 0 27 2
670a 5 8 0 86 2
671a 8 9 0 24 9
672a 3 6 0 31 6
673a 6 9 0 51 2
674a 10 1 0 104 1
675a 10 4 0 64 8
676a 10 7 0 33 3
677a 3 11 0 79 1
678a 6 11 0 58 9
679a 9 11 0 75 9
680";
681 let actual = generate_dimacs(params);
682 assert_eq!(actual, expected);
683 }
684
685 fn run_fortran(input: &str) -> Option<String> {
686 let manifest = env!("CARGO_MANIFEST_DIR");
687 let fortran_dir = format!("{manifest}/gridgraph_original");
688
689 let status = Command::new("make")
690 .args(["-C", &fortran_dir])
691 .status()
692 .ok()?;
693 if !status.success() {
694 return None;
695 }
696
697 let binary = format!("{fortran_dir}/ggraph");
698 let output = Command::new(&binary)
699 .stdin(std::process::Stdio::piped())
700 .stdout(std::process::Stdio::piped())
701 .stderr(std::process::Stdio::piped())
702 .spawn()
703 .and_then(|mut child| {
704 use std::io::Write;
705 child
706 .stdin
707 .as_mut()
708 .unwrap()
709 .write_all(input.as_bytes())
710 .unwrap();
711 child.wait_with_output()
712 })
713 .ok()?;
714
715 if !output.status.success() {
716 return None;
717 }
718 Some(String::from_utf8(output.stdout).unwrap())
719 }
720
721 #[test]
722 fn e2e_3x3_vs_fortran() {
723 let params = GridGraphParams::new(3, 3, 100, 10, 12345).unwrap();
724 let input = "3 3 100 10 12345";
725 if let Some(fortran_out) = run_fortran(input) {
726 let rust_out = generate_dimacs(params);
727 assert_eq!(rust_out, fortran_out);
728 } else {
729 eprintln!("Skipping Fortran comparison: could not build/run Fortran binary");
730 }
731 }
732
733 #[test]
734 fn e2e_8x8_vs_fortran() {
735 let params = GridGraphParams::new(8, 8, 10_000, 1_000, 270_001).unwrap();
736 let input = "8 8 10000 1000 270001";
737 if let Some(fortran_out) = run_fortran(input) {
738 let rust_out = generate_dimacs(params);
739 assert_eq!(rust_out, fortran_out);
740 } else {
741 eprintln!("Skipping Fortran comparison: could not build/run Fortran binary");
742 }
743 }
744
745 #[test]
746 fn e2e_8x8_spot_check() {
747 let params = GridGraphParams::new(8, 8, 10_000, 1_000, 270_001).unwrap();
748 let output = generate_dimacs(params);
749 let lines: Vec<&str> = output.lines().collect();
750 assert!(lines[2].contains("66"));
751 assert!(lines[2].contains("128"));
752 assert!(lines[3].contains("12458"));
753 assert_eq!(lines[5], "a 1 2 0 1132 335");
754 }
755}