From 6a8e6dc8327c35e71e464bb21bc3656028a32cf6 Mon Sep 17 00:00:00 2001 From: kenkoooo Date: Wed, 9 Sep 2020 01:33:35 +0900 Subject: [PATCH 1/6] Implement mincostflow --- src/lib.rs | 1 + src/mincostflow.rs | 234 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index d501511..dfaffb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,4 @@ pub(crate) mod internal_scc; pub(crate) mod internal_type_traits; pub use fenwicktree::FenwickTree; +pub use mincostflow::MinCostFlowGraph; diff --git a/src/mincostflow.rs b/src/mincostflow.rs index 8b13789..bcaf054 100644 --- a/src/mincostflow.rs +++ b/src/mincostflow.rs @@ -1 +1,235 @@ +pub struct MinCostFlowEdge { + pub from: usize, + pub to: usize, + pub cap: T, + pub flow: T, + pub cost: T, +} +pub struct MinCostFlowGraph { + pos: Vec<(usize, usize)>, + g: Vec>>, + cost_sum: T, +} + +impl MinCostFlowGraph +where + T: Number + std::ops::Neg, +{ + pub fn new(n: usize) -> Self { + Self { + pos: vec![], + g: (0..n).map(|_| vec![]).collect(), + cost_sum: T::zero(), + } + } + + pub fn get_edge(&self, i: usize) -> MinCostFlowEdge { + assert!(i < self.pos.len()); + let e = &self.g[self.pos[i].0][self.pos[i].1]; + let re = &self.g[e.to][e.rev]; + MinCostFlowEdge { + from: self.pos[i].0, + to: e.to, + cap: e.cap + re.cap, + flow: re.cap, + cost: e.cost, + } + } + + pub fn edges(&self) -> Vec> { + let m = self.pos.len(); + let mut result = vec![]; + for i in 0..m { + result.push(self.get_edge(i)); + } + result + } + + pub fn add_edge(&mut self, from: usize, to: usize, cap: T, cost: T) -> usize { + assert!(from < self.g.len()); + assert!(to < self.g.len()); + assert_ne!(from, to); + self.pos.push((from, self.g[from].len())); + self.cost_sum += cost; + + let rev = self.g[to].len(); + self.g[from].push(_Edge { to, rev, cap, cost }); + + let rev = self.g[from].len() - 1; + self.g[to].push(_Edge { + to: from, + rev, + cap: T::zero(), + cost: -cost, + }); + + self.pos.len() - 1 + } + + /// Returns (maximum flow, cost) + pub fn flow(&mut self, s: usize, t: usize, flow_limit: T) -> (T, T) { + self.slope(s, t, flow_limit).last().unwrap().clone() + } + + pub fn slope(&mut self, s: usize, t: usize, flow_limit: T) -> Vec<(T, T)> { + let n = self.g.len(); + assert!(s < n); + assert!(t < n); + assert_ne!(s, t); + + let mut dual = vec![T::zero(); n]; + let mut prev_v = vec![0; n]; + let mut prev_e = vec![0; n]; + let mut flow = T::zero(); + let mut cost = T::zero(); + let mut prev_cost: Option = None; + let mut result = vec![(flow, cost)]; + while flow < flow_limit { + if !self.dual_ref(s, t, &mut dual, &mut prev_v, &mut prev_e) { + break; + } + let mut c = flow_limit - flow; + + let mut v = t; + while v != s { + c = std::cmp::min(c, self.g[prev_v[v]][prev_e[v]].cap); + v = prev_v[v]; + } + + let mut v = t; + while v != s { + self.g[prev_v[v]][prev_e[v]].cap -= c; + let rev = self.g[prev_v[v]][prev_e[v]].rev; + self.g[v][rev].cap += c; + v = prev_v[v]; + } + + let d = -dual[s]; + flow += c; + cost += d * c; + if prev_cost == Some(d) { + assert!(result.pop().is_some()); + } + result.push((flow, cost)); + prev_cost = Some(cost); + } + result + } + + fn dual_ref( + &self, + s: usize, + t: usize, + dual: &mut [T], + pv: &mut [usize], + pe: &mut [usize], + ) -> bool { + let n = self.g.len(); + let mut dist = vec![self.cost_sum; n]; + let mut vis = vec![false; n]; + + let mut que = std::collections::BinaryHeap::new(); + dist[s] = T::zero(); + que.push((std::cmp::Reverse(T::zero()), s)); + while let Some((_, v)) = que.pop() { + if vis[v] { + continue; + } + vis[v] = true; + if v == t { + break; + } + + for (i, e) in self.g[v].iter().enumerate() { + if vis[e.to] || e.cap == T::zero() { + continue; + } + + let cost = e.cost - dual[e.to] + dual[v]; + if dist[e.to] - dist[v] > cost { + dist[e.to] = dist[v] + cost; + pv[e.to] = v; + pe[e.to] = i; + que.push((std::cmp::Reverse(dist[e.to]), e.to)); + } + } + } + + if !vis[t] { + return false; + } + + for v in 0..n { + if !vis[v] { + continue; + } + dual[v] = dual[v] - (dist[t] - dist[v]); + } + true + } +} + +struct _Edge { + to: usize, + rev: usize, + cap: T, + cost: T, +} + +// TODO migrate to common type +pub trait Number: + Copy + + Ord + + std::ops::Not + + std::ops::Add + + std::ops::Sub + + std::ops::Mul + + std::ops::Div + + std::ops::Rem + + std::ops::AddAssign + + std::ops::SubAssign + + std::ops::MulAssign + + std::ops::DivAssign + + std::ops::RemAssign + + std::ops::BitOr + + std::ops::BitAnd + + std::ops::BitXor + + std::ops::BitOrAssign + + std::ops::BitAndAssign + + std::ops::BitXorAssign + + std::ops::Shl + + std::ops::Shr + + std::ops::ShlAssign + + std::ops::ShrAssign + + std::fmt::Display + + std::fmt::Debug + + std::fmt::Binary + + std::fmt::Octal +{ + fn zero() -> Self; +} + +#[cfg(test)] +mod tests { + use super::*; + + impl Number for i64 { + fn zero() -> Self { + 0 + } + } + + #[test] + fn test_min_cost_flow() { + let mut graph = MinCostFlowGraph::new(4); + graph.add_edge(0, 1, 2, 1); + graph.add_edge(0, 2, 1, 2); + graph.add_edge(1, 2, 1, 1); + graph.add_edge(1, 3, 1, 3); + graph.add_edge(2, 3, 2, 1); + let (flow, cost) = graph.flow(0, 3, 2); + assert_eq!(flow, 2); + assert_eq!(cost, 6); + } +} From 57d6c5fda87bc295fb54a9838e06f88caa1cdd45 Mon Sep 17 00:00:00 2001 From: kenkoooo Date: Wed, 9 Sep 2020 01:43:18 +0900 Subject: [PATCH 2/6] Fix clippy issues --- src/mincostflow.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/mincostflow.rs b/src/mincostflow.rs index bcaf054..621c75f 100644 --- a/src/mincostflow.rs +++ b/src/mincostflow.rs @@ -68,15 +68,15 @@ where } /// Returns (maximum flow, cost) - pub fn flow(&mut self, s: usize, t: usize, flow_limit: T) -> (T, T) { - self.slope(s, t, flow_limit).last().unwrap().clone() + pub fn flow(&mut self, source: usize, sink: usize, flow_limit: T) -> (T, T) { + *self.slope(source, sink, flow_limit).last().unwrap() } - pub fn slope(&mut self, s: usize, t: usize, flow_limit: T) -> Vec<(T, T)> { + pub fn slope(&mut self, source: usize, sink: usize, flow_limit: T) -> Vec<(T, T)> { let n = self.g.len(); - assert!(s < n); - assert!(t < n); - assert_ne!(s, t); + assert!(source < n); + assert!(sink < n); + assert_ne!(source, sink); let mut dual = vec![T::zero(); n]; let mut prev_v = vec![0; n]; @@ -86,26 +86,26 @@ where let mut prev_cost: Option = None; let mut result = vec![(flow, cost)]; while flow < flow_limit { - if !self.dual_ref(s, t, &mut dual, &mut prev_v, &mut prev_e) { + if !self.dual_ref(source, sink, &mut dual, &mut prev_v, &mut prev_e) { break; } let mut c = flow_limit - flow; - let mut v = t; - while v != s { + let mut v = sink; + while v != source { c = std::cmp::min(c, self.g[prev_v[v]][prev_e[v]].cap); v = prev_v[v]; } - let mut v = t; - while v != s { + let mut v = sink; + while v != source { self.g[prev_v[v]][prev_e[v]].cap -= c; let rev = self.g[prev_v[v]][prev_e[v]].rev; self.g[v][rev].cap += c; v = prev_v[v]; } - let d = -dual[s]; + let d = -dual[source]; flow += c; cost += d * c; if prev_cost == Some(d) { @@ -119,8 +119,8 @@ where fn dual_ref( &self, - s: usize, - t: usize, + source: usize, + sink: usize, dual: &mut [T], pv: &mut [usize], pe: &mut [usize], @@ -130,14 +130,14 @@ where let mut vis = vec![false; n]; let mut que = std::collections::BinaryHeap::new(); - dist[s] = T::zero(); - que.push((std::cmp::Reverse(T::zero()), s)); + dist[source] = T::zero(); + que.push((std::cmp::Reverse(T::zero()), source)); while let Some((_, v)) = que.pop() { if vis[v] { continue; } vis[v] = true; - if v == t { + if v == sink { break; } @@ -156,7 +156,7 @@ where } } - if !vis[t] { + if !vis[sink] { return false; } @@ -164,7 +164,7 @@ where if !vis[v] { continue; } - dual[v] = dual[v] - (dist[t] - dist[v]); + dual[v] -= dist[sink] - dist[v]; } true } From 419b128e16886d7c6c0e16be64958e5389ebae14 Mon Sep 17 00:00:00 2001 From: kenkoooo Date: Wed, 9 Sep 2020 22:31:28 +0900 Subject: [PATCH 3/6] Fix minor issues in mincostflow --- src/mincostflow.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mincostflow.rs b/src/mincostflow.rs index 621c75f..dff37c3 100644 --- a/src/mincostflow.rs +++ b/src/mincostflow.rs @@ -69,7 +69,7 @@ where /// Returns (maximum flow, cost) pub fn flow(&mut self, source: usize, sink: usize, flow_limit: T) -> (T, T) { - *self.slope(source, sink, flow_limit).last().unwrap() + self.slope(source, sink, flow_limit).pop().unwrap() } pub fn slope(&mut self, source: usize, sink: usize, flow_limit: T) -> Vec<(T, T)> { @@ -86,11 +86,11 @@ where let mut prev_cost: Option = None; let mut result = vec![(flow, cost)]; while flow < flow_limit { - if !self.dual_ref(source, sink, &mut dual, &mut prev_v, &mut prev_e) { + if !self.refine_dual(source, sink, &mut dual, &mut prev_v, &mut prev_e) { break; } - let mut c = flow_limit - flow; + let mut c = flow_limit - flow; let mut v = sink; while v != source { c = std::cmp::min(c, self.g[prev_v[v]][prev_e[v]].cap); @@ -117,7 +117,7 @@ where result } - fn dual_ref( + fn refine_dual( &self, source: usize, sink: usize, From 56a6f7163eab6f80a3a6bef183bbf64f5f64fbab Mon Sep 17 00:00:00 2001 From: kenkoooo Date: Wed, 9 Sep 2020 22:34:17 +0900 Subject: [PATCH 4/6] Add assertions into mincostflow.rs --- src/mincostflow.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mincostflow.rs b/src/mincostflow.rs index dff37c3..f9881bb 100644 --- a/src/mincostflow.rs +++ b/src/mincostflow.rs @@ -50,6 +50,9 @@ where assert!(from < self.g.len()); assert!(to < self.g.len()); assert_ne!(from, to); + assert!(cap >= T::zero()); + assert!(cost >= T::zero()); + self.pos.push((from, self.g[from].len())); self.cost_sum += cost; From 0f6387ca5d5902c06892b558f185f56733109573 Mon Sep 17 00:00:00 2001 From: kenkoooo Date: Wed, 9 Sep 2020 22:43:07 +0900 Subject: [PATCH 5/6] Add a comment for Integer trait --- src/mincostflow.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mincostflow.rs b/src/mincostflow.rs index f9881bb..658cb75 100644 --- a/src/mincostflow.rs +++ b/src/mincostflow.rs @@ -14,7 +14,7 @@ pub struct MinCostFlowGraph { impl MinCostFlowGraph where - T: Number + std::ops::Neg, + T: Integer + std::ops::Neg, { pub fn new(n: usize) -> Self { Self { @@ -180,8 +180,8 @@ struct _Edge { cost: T, } -// TODO migrate to common type -pub trait Number: +// TODO After we have Integer trait in [crate::internal_type_traits], remove this trait and use the new one +pub trait Integer: Copy + Ord + std::ops::Not @@ -217,7 +217,7 @@ pub trait Number: mod tests { use super::*; - impl Number for i64 { + impl Integer for i64 { fn zero() -> Self { 0 } From 9c36e0c4c449409eb30750db8abe6d3cb36162c4 Mon Sep 17 00:00:00 2001 From: kenkoooo Date: Thu, 10 Sep 2020 23:34:11 +0900 Subject: [PATCH 6/6] Replace Integer with internal_type_traits::Integral --- src/internal_type_traits.rs | 2 +- src/mincostflow.rs | 43 +++---------------------------------- 2 files changed, 4 insertions(+), 41 deletions(-) diff --git a/src/internal_type_traits.rs b/src/internal_type_traits.rs index b4f060f..73ba2e6 100644 --- a/src/internal_type_traits.rs +++ b/src/internal_type_traits.rs @@ -19,7 +19,7 @@ use std::{ // // Maybe we should rename this to `PrimitiveInteger` or something, as it probably won't be used in the // same way as the original ACL. -pub(crate) trait Integral: +pub trait Integral: 'static + Send + Sync diff --git a/src/mincostflow.rs b/src/mincostflow.rs index 658cb75..124eeff 100644 --- a/src/mincostflow.rs +++ b/src/mincostflow.rs @@ -1,3 +1,5 @@ +use crate::internal_type_traits::Integral; + pub struct MinCostFlowEdge { pub from: usize, pub to: usize, @@ -14,7 +16,7 @@ pub struct MinCostFlowGraph { impl MinCostFlowGraph where - T: Integer + std::ops::Neg, + T: Integral + std::ops::Neg, { pub fn new(n: usize) -> Self { Self { @@ -180,49 +182,10 @@ struct _Edge { cost: T, } -// TODO After we have Integer trait in [crate::internal_type_traits], remove this trait and use the new one -pub trait Integer: - Copy - + Ord - + std::ops::Not - + std::ops::Add - + std::ops::Sub - + std::ops::Mul - + std::ops::Div - + std::ops::Rem - + std::ops::AddAssign - + std::ops::SubAssign - + std::ops::MulAssign - + std::ops::DivAssign - + std::ops::RemAssign - + std::ops::BitOr - + std::ops::BitAnd - + std::ops::BitXor - + std::ops::BitOrAssign - + std::ops::BitAndAssign - + std::ops::BitXorAssign - + std::ops::Shl - + std::ops::Shr - + std::ops::ShlAssign - + std::ops::ShrAssign - + std::fmt::Display - + std::fmt::Debug - + std::fmt::Binary - + std::fmt::Octal -{ - fn zero() -> Self; -} - #[cfg(test)] mod tests { use super::*; - impl Integer for i64 { - fn zero() -> Self { - 0 - } - } - #[test] fn test_min_cost_flow() { let mut graph = MinCostFlowGraph::new(4);