From da002db947bfda3fc6b4b9c119714aeea19f9e04 Mon Sep 17 00:00:00 2001 From: Nagata Kana Date: Tue, 10 Dec 2024 19:31:19 +0900 Subject: [PATCH] graph --- libs/graph/Cargo.toml | 8 + libs/graph/src/csr.rs | 405 ++++++++++++++++++++++++++++++++++++++++++ libs/graph/src/lib.rs | 77 ++++++++ 3 files changed, 490 insertions(+) create mode 100644 libs/graph/Cargo.toml create mode 100644 libs/graph/src/csr.rs create mode 100644 libs/graph/src/lib.rs diff --git a/libs/graph/Cargo.toml b/libs/graph/Cargo.toml new file mode 100644 index 00000000..a7ad4d17 --- /dev/null +++ b/libs/graph/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "graph" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/libs/graph/src/csr.rs b/libs/graph/src/csr.rs new file mode 100644 index 00000000..8855f650 --- /dev/null +++ b/libs/graph/src/csr.rs @@ -0,0 +1,405 @@ +use std::fmt::Debug; +use std::ops::Deref; +use std::ops::DerefMut; +use std::ops::Index; +use std::ops::IndexMut; + +/// Compressed Sparse Row format +/// +/// # Notation +/// +/// - $X = [x_0, x_1, \dots, x_{n-1}]$: `data` +/// - $S = [s_0, s_1, \dots, s_{m}]$: `boundaries` +/// +/// # Invariants +/// +/// - $0 = s_0 \leq s_1 \leq \dots \leq s_m = n$ +/// +/// # Semantics +/// +/// This struct represents a list of lists $A$ of elements of type `T`. +/// +/// $$ +/// A_{i, j} = X[s_i + j] +/// $$ +/// +pub struct Csr { + /// $X = [x_0, x_1, \dots, x_{n-1}]$ + pub data: Vec, + /// $S = [s_0, s_1, \dots, s_{m}]$ + pub boundary: Vec, +} + +impl Csr { + /// Create a CSR corrsponding to $A = [\ ]$. + /// + /// # Example + /// + /// ``` + /// use graph::Csr; + /// let csr: Csr = Csr::new(); + /// assert!(csr.is_empty()); + /// ``` + pub fn new() -> Self { + Csr { + data: Vec::new(), + boundary: vec![0], + } + } + /// Create a CSR corrsponding to $A = [\ ]$ with preallocated memory. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr: Csr = Csr::with_capacity(10, 5); + /// assert!(csr.is_empty()); + /// ``` + pub fn with_capacity(data_capacity: usize, sections_capacity: usize) -> Self { + let data = Vec::with_capacity(data_capacity); + let mut boundary = Vec::with_capacity(sections_capacity + 1); + boundary.push(0); + Csr { data, boundary } + } + /// Create a CSR from a list of sections. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// assert_eq!(csr.section(0), &[1, 2, 3]); + /// assert_eq!(csr.section(1), &[4, 5]); + /// ``` + pub fn from_sections(rows: &[A]) -> Self + where + A: AsRef<[T]>, + T: Clone, + { + let mut csr = Csr::new(); + for row in rows { + csr.push_section(row.as_ref()); + } + csr + } + /// Get the $i$-th section $A_i$. Alias for `&self[i]`. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// assert_eq!(csr.section(0), &[1, 2, 3]); + /// ``` + pub fn section(&self, i: usize) -> &[T] { + &self.data[self.boundary[i]..self.boundary[i + 1]] + } + /// Get the mutable $i$-th section $A_i$. Alias for `&mut self[i]`. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let mut csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// csr.section_mut(0)[0] = 42; + /// assert_eq!(csr.section(0), &[42, 2, 3]); + /// ``` + pub fn section_mut(&mut self, i: usize) -> &mut [T] { + &mut self.data[self.boundary[i]..self.boundary[i + 1]] + } + /// Check if the CSR is empty. (i.e. $A = [\ ]$) + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr = Csr::<()>::new(); + /// assert!(csr.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.boundary.len() == 1 + } + /// Get the number of sections $m = |A|$. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// assert_eq!(csr.len(), 2); + /// ``` + pub fn len(&self) -> usize { + self.boundary.len() - 1 + } + /// Get the total number of elements in $A$. (i.e. $\sum_{i=0}^{m-1} |A_i|$) + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// assert_eq!(csr.flat_len(), 5); + /// ``` + pub fn flat_len(&self) -> usize { + self.data.len() + } + /// Get the mutable and extendable reference to the last section. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let mut csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// csr.last_mut().push(42); + /// assert_eq!(csr.section(1), &[4, 5, 42]); + /// ``` + pub fn last_mut(&mut self) -> LastMut { + LastMut { csr: self } + } + /// Push an empty section $A_m = [\ ]$. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let mut csr = Csr::<()>::new(); + /// csr.push_empty(); + /// assert_eq!(csr.section(0), &[]); + /// ``` + pub fn push_empty(&mut self) { + self.boundary.push(self.data.len()); + } + /// Clone and push a section. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let mut csr = Csr::new(); + /// csr.push_section(&[1, 2, 3]); + /// assert_eq!(csr.section(0), &[1, 2, 3]); + /// ``` + pub fn push_section(&mut self, section: &[T]) + where + T: Clone, + { + self.data.extend_from_slice(section); + self.boundary.push(self.data.len()); + } + /// Return an iterator over the sections. + /// + pub fn iter(&self) -> Iter { + Iter { + data: &self.data, + boundary: &self.boundary, + } + } + /// Copies `self` into a new `Vec>`. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// assert_eq!(csr.to_vec(), vec![vec![1, 2, 3], vec![4, 5]]); + /// ``` + pub fn to_vec(&self) -> Vec> + where + T: Clone, + { + self.iter().map(<[T]>::to_vec).collect() + } +} + +/// Mutable and extendable reference to the last section. +pub struct LastMut<'a, T> { + csr: &'a mut Csr, +} +impl<'a, T> LastMut<'a, T> { + /// Push an element to the last section. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let mut csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// csr.last_mut().push(42); + /// assert_eq!(csr.section(1), &[4, 5, 42]); + /// ``` + pub fn push(self, x: T) { + self.csr.data.push(x); + *self.csr.boundary.last_mut().unwrap() = self.csr.data.len(); + } + /// Extend the last section with an iterator. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let mut csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// csr.last_mut().extend(vec![42, 43]); + /// assert_eq!(csr.section(1), &[4, 5, 42, 43]); + /// ``` + pub fn extend>(self, iter: I) { + self.csr.data.extend(iter); + *self.csr.boundary.last_mut().unwrap() = self.csr.data.len(); + } + + /// Copy elements from a slice to the last section. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let mut csr = Csr::from_sections(&[vec![1, 2, 3], vec![4, 5]]); + /// csr.last_mut().extend_from_slice(&[42, 43]); + /// assert_eq!(csr.section(1), &[4, 5, 42, 43]); + pub fn extend_from_slice(&mut self, slice: &[T]) + where + T: Clone, + { + self.csr.data.extend_from_slice(slice); + *self.csr.boundary.last_mut().unwrap() = self.csr.data.len(); + } +} +impl Deref for LastMut<'_, T> { + type Target = [T]; + fn deref(&self) -> &Self::Target { + &self.csr.data[self.csr.boundary[self.csr.boundary.len() - 2]..] + } +} +impl DerefMut for LastMut<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.csr.data[self.csr.boundary[self.csr.boundary.len() - 2]..] + } +} + +impl FromIterator for Csr +where + A: IntoIterator, +{ + fn from_iter>(iter: I) -> Self { + let mut csr = Csr::new(); + for section in iter { + csr.push_empty(); + for x in section { + csr.last_mut().push(x); + } + } + csr + } +} + +impl Csr { + /// Create a CSR from a list of edges. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let csr = Csr::from_edges(3, &[(0, 1), (1, 2), (2, 0)]); + /// assert_eq!(csr.to_vec(), vec![vec![1], vec![2], vec![0]]); + /// ``` + pub fn from_edges(n: usize, edges: &[(usize, usize)]) -> Self { + let mut csr = Csr { + data: vec![usize::MAX; edges.len()], + boundary: vec![0; n + 1], + }; + for &(i, _) in edges { + csr.boundary[i] += 1; + } + for i in 1..=n { + csr.boundary[i] += csr.boundary[i - 1]; + } + for &(i, j) in edges { + csr.boundary[i] -= 1; + csr.data[csr.boundary[i]] = j; + } + csr + } + /// Create CSRs of $G$ and $G^{\mathrm{op}}$ from a list of edges. + /// + /// # Example + /// ``` + /// use graph::Csr; + /// let (g, rg) = Csr::from_edges_and_rev(3, &[(0, 1), (1, 2), (2, 0)]); + /// assert_eq!(g.to_vec(), vec![vec![1], vec![2], vec![0]]); + /// assert_eq!(rg.to_vec(), vec![vec![2], vec![0], vec![1]]); + /// ``` + pub fn from_edges_and_rev(n: usize, edges: &[(usize, usize)]) -> (Self, Self) { + let mut forward = Csr { + data: vec![usize::MAX; edges.len()], + boundary: vec![0; n + 1], + }; + let mut backward = Csr { + data: vec![usize::MAX; edges.len()], + boundary: vec![0; n + 1], + }; + for &(i, j) in edges { + forward.boundary[i] += 1; + backward.boundary[j] += 1; + } + for i in 1..=n { + forward.boundary[i] += forward.boundary[i - 1]; + backward.boundary[i] += backward.boundary[i - 1]; + } + for &(i, j) in edges { + forward.boundary[i] -= 1; + forward.data[forward.boundary[i]] = j; + backward.boundary[j] -= 1; + backward.data[backward.boundary[j]] = i; + } + (forward, backward) + } +} + +impl Default for Csr { + fn default() -> Self { + Self::new() + } +} + +impl Debug for Csr +where + T: Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// Immutable iterator over rows. +pub struct Iter<'a, T> { + pub(crate) data: &'a [T], + pub(crate) boundary: &'a [usize], +} +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a [T]; + fn next(&mut self) -> Option { + if self.boundary.len() <= 1 { + return None; + } + let &[l, r] = &self.boundary[..2] else { unreachable!() }; + self.boundary = &self.boundary[1..]; + Some(&self.data[l..r]) + } +} +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + fn next_back(&mut self) -> Option { + if self.boundary.len() <= 1 { + return None; + } + let &[l, r] = &self.boundary[self.boundary.len() - 2..] else { unreachable!() }; + self.boundary = &self.boundary[..self.boundary.len() - 1]; + Some(&self.data[l..r]) + } +} +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn len(&self) -> usize { + self.boundary.len() - 1 + } +} +impl<'a, T> IntoIterator for &'a Csr { + type Item = &'a [T]; + type IntoIter = Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl Index for Csr { + type Output = [T]; + fn index(&self, i: usize) -> &[T] { + self.section(i) + } +} +impl IndexMut for Csr { + fn index_mut(&mut self, i: usize) -> &mut [T] { + self.section_mut(i) + } +} diff --git a/libs/graph/src/lib.rs b/libs/graph/src/lib.rs new file mode 100644 index 00000000..2fe55bcc --- /dev/null +++ b/libs/graph/src/lib.rs @@ -0,0 +1,77 @@ +//! Kosaraju's algorithm for strongly connected components +//! +//! # Note: CSR (Compressed Sparse Row) +//! +//! Graphs and set partitions are represented in CSR format [`Csr`]. +//! +//! +//! # Examples +//! ``` +//! use graph::kosaraju; +//! let n = 6; +//! let edges = [ (1, 4), (5, 2), (3, 0), (5, 5), (4, 1), (0, 3), (4, 2)]; +//! let scc = kosaraju(n, &edges); +//! assert_eq!(scc.len(), 4); +//! assert_eq!(scc[0], [5]); +//! assert_eq!(scc[1], [1, 4]); +//! assert_eq!(scc[2], [2]); +//! assert_eq!(scc[3], [0, 3]); +//! ``` +mod csr; + +pub use csr::Csr; +pub use csr::Iter; +pub use csr::LastMut; + +/// Returns the strongly connected components of a directed graph. +/// +/// # Examples +/// ``` +/// use graph::kosaraju; +/// let n = 6; +/// let edges = [ (1, 4), (5, 2), (3, 0), (5, 5), (4, 1), (0, 3), (4, 2)]; +/// let scc = kosaraju(n, &edges); +/// assert_eq!(scc.len(), 4); +/// assert_eq!(scc[0], [5]); +/// assert_eq!(scc[1], [1, 4]); +/// assert_eq!(scc[2], [2]); +/// assert_eq!(scc[3], [0, 3]); +/// ``` +pub fn kosaraju(n: usize, edges: &[(usize, usize)]) -> Csr { + let (g, rg) = Csr::from_edges_and_rev(n, edges); + let mut sorted = Vec::with_capacity(n); + let mut cmp = vec![0; n]; + for i in 0..n { + if cmp[i] == 0 { + dfs1(i, &g, &mut sorted, &mut cmp); + } + } + let mut out = Csr::with_capacity(n, n); + for &i in sorted.iter().rev() { + if cmp[i] == usize::MAX { + out.push_empty(); + dfs2(i, &rg, &mut out, &mut cmp); + } + } + out +} + +fn dfs1(i: usize, g: &Csr, sorted: &mut Vec, cmp: &mut [usize]) { + cmp[i] = usize::MAX; + for &y in &g[i] { + if cmp[y] == 0 { + dfs1(y, g, sorted, cmp); + } + } + sorted.push(i); +} + +fn dfs2(i: usize, rg: &Csr, out: &mut Csr, cmp: &mut [usize]) { + cmp[i] = out.len(); + out.last_mut().push(i); + for &y in &rg[i] { + if cmp[y] == usize::MAX { + dfs2(y, rg, out, cmp); + } + } +}