Skip to content

Commit 8a0c34a

Browse files
Merge pull request #265 from marvin-hansen/main
feat: Implement and test Brandes' Betweenness Centrality Algorithm
2 parents 98e7c60 + 4bce435 commit 8a0c34a

25 files changed

+1597
-851
lines changed

ultragraph/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ pub mod errors;
99

1010
mod traits;
1111
pub mod types;
12+
pub mod utils;
13+
1214
// Errors
1315
pub use crate::errors::graph_error::GraphError;
1416
// Traits
15-
pub use crate::traits::graph_algo::GraphAlgorithms;
17+
pub use crate::traits::graph_algo::*;
1618
pub use crate::traits::graph_freeze::Freezable;
1719
pub use crate::traits::graph_mut::GraphMut;
1820
pub use crate::traits::graph_traversal::GraphTraversal;

ultragraph/src/traits/graph_algo.rs

Lines changed: 14 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,73 +3,20 @@
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
55

6-
use crate::{GraphError, GraphView};
6+
pub use crate::traits::graph_algo_centrality::*;
7+
pub use crate::traits::graph_algo_pathfinder::*;
8+
pub use crate::traits::graph_algo_structural::*;
9+
pub use crate::traits::graph_algo_topological::*;
710

8-
/// Defines a suite of high-performance, read-only analytical algorithms.
11+
/// A comprehensive suite of graph algorithms.
912
///
10-
/// This trait is intended for implementation on static, optimized graph structures
11-
/// like `next_graph::CsmGraph` to validate their structure and properties.
12-
pub trait GraphAlgorithms<N, W>: GraphView<N, W> {
13-
// --- Structural Validation Algorithms ---
14-
15-
/// Finds a single cycle in the graph and returns the path of nodes that form it.
16-
///
17-
/// This is the most powerful cycle detection method, as it not only confirms the
18-
/// presence of a cycle but also identifies the specific nodes involved. This is
19-
/// invaluable for debugging dynamically generated graphs.
20-
///
21-
/// # Returns
22-
/// `Some(Vec<usize>)` containing the sequence of node indices that form a cycle
23-
/// (e.g., `[0, 1, 0]`). Returns `None` if the graph is a DAG.
24-
fn find_cycle(&self) -> Result<Option<Vec<usize>>, GraphError>;
25-
26-
/// Checks if the graph contains any directed cycles.
27-
///
28-
/// This method should be implemented as a simple call to `self.find_cycle().is_some()`.
29-
fn has_cycle(&self) -> Result<bool, GraphError>;
30-
31-
/// Computes a topological sort of the graph, if it is a Directed Acyclic Graph (DAG).
32-
/// Returns `None` if the graph contains a cycle.
33-
fn topological_sort(&self) -> Result<Option<Vec<usize>>, GraphError>;
34-
35-
// --- Pathfinding and Reachability Algorithms ---
36-
37-
/// Checks if a path of any length exists from a start to a stop index.
38-
fn is_reachable(&self, start_index: usize, stop_index: usize) -> Result<bool, GraphError>;
39-
40-
/// Returns the length of the shortest path (in number of nodes) from a start to a stop index.
41-
fn shortest_path_len(
42-
&self,
43-
start_index: usize,
44-
stop_index: usize,
45-
) -> Result<Option<usize>, GraphError>;
46-
47-
/// Finds the complete shortest path from a start to a stop index.
48-
fn shortest_path(
49-
&self,
50-
start_index: usize,
51-
stop_index: usize,
52-
) -> Result<Option<Vec<usize>>, GraphError>;
53-
54-
/// Finds the shortest path in a weighted graph using Dijkstra's algorithm.
55-
///
56-
/// The edge weight type `W` must support addition, comparison, and have a zero value.
57-
///
58-
/// # Returns
59-
/// A tuple containing the sequence of node indices in the path and the total cost of that path.
60-
/// Returns `None` if no path exists.
61-
fn shortest_weighted_path(
62-
&self,
63-
start_index: usize,
64-
stop_index: usize,
65-
) -> Result<Option<(Vec<usize>, W)>, GraphError>
66-
where
67-
W: Copy + Ord + Default + std::ops::Add<Output = W>;
68-
69-
/// Finds all Strongly Connected Components in the graph using Tarjan's algorithm.
70-
///
71-
/// # Returns
72-
/// A vector of vectors, where each inner vector is a list of node indices
73-
/// belonging to a single SCC.
74-
fn strongly_connected_components(&self) -> Result<Vec<Vec<usize>>, GraphError>;
13+
/// This trait aggregates several focused algorithm traits into a single, convenient
14+
/// supertrait. A type that implements `GraphAlgorithms` has access to all methods
15+
/// from the component traits.
16+
pub trait GraphAlgorithms<N, W>:
17+
TopologicalGraphAlgorithms<N, W>
18+
+ PathfindingGraphAlgorithms<N, W>
19+
+ StructuralGraphAlgorithms<N, W>
20+
+ CentralityGraphAlgorithms<N, W>
21+
{
7522
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
use crate::{GraphError, GraphView};
6+
7+
pub trait CentralityGraphAlgorithms<N, W>: GraphView<N, W> {
8+
/// Calculates the betweenness centrality of each node in the graph.
9+
fn betweenness_centrality(
10+
&self,
11+
directed: bool,
12+
normalized: bool,
13+
) -> Result<Vec<(usize, f64)>, GraphError>;
14+
15+
/// Calculates betweenness centrality across a specific set of critical pathways.
16+
fn pathway_betweenness_centrality(
17+
&self,
18+
pathways: &[(usize, usize)],
19+
directed: bool,
20+
normalized: bool,
21+
) -> Result<Vec<(usize, f64)>, GraphError>;
22+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
use crate::{GraphError, GraphView};
6+
7+
pub trait PathfindingGraphAlgorithms<N, W>: GraphView<N, W> {
8+
/// Checks if a path of any length exists from a start to a stop index.
9+
fn is_reachable(&self, start_index: usize, stop_index: usize) -> Result<bool, GraphError>;
10+
11+
/// Returns the length of the shortest path (in number of nodes) from a start to a stop index.
12+
fn shortest_path_len(
13+
&self,
14+
start_index: usize,
15+
stop_index: usize,
16+
) -> Result<Option<usize>, GraphError>;
17+
18+
/// Finds the complete shortest path from a start to a stop index.
19+
fn shortest_path(
20+
&self,
21+
start_index: usize,
22+
stop_index: usize,
23+
) -> Result<Option<Vec<usize>>, GraphError>;
24+
25+
/// Finds the shortest path in a weighted graph using Dijkstra's algorithm.
26+
fn shortest_weighted_path(
27+
&self,
28+
start_index: usize,
29+
stop_index: usize,
30+
) -> Result<Option<(Vec<usize>, W)>, GraphError>
31+
where
32+
W: Copy + Ord + Default + std::ops::Add<Output = W>;
33+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
use crate::{GraphError, GraphView};
6+
7+
pub trait StructuralGraphAlgorithms<N, W>: GraphView<N, W> {
8+
/// Finds all Strongly Connected Components in the graph.
9+
fn strongly_connected_components(&self) -> Result<Vec<Vec<usize>>, GraphError>;
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
use crate::{GraphError, GraphView};
6+
7+
pub trait TopologicalGraphAlgorithms<N, W>: GraphView<N, W> {
8+
/// Finds a single cycle in the graph and returns the path of nodes that form it.
9+
fn find_cycle(&self) -> Result<Option<Vec<usize>>, GraphError>;
10+
11+
/// Checks if the graph contains any directed cycles.
12+
/// This method should be implemented as a simple call to `self.find_cycle().is_some()`.
13+
fn has_cycle(&self) -> Result<bool, GraphError>;
14+
15+
/// Computes a topological sort of the graph, if it is a Directed Acyclic Graph (DAG).
16+
/// Returns `None` if the graph contains a cycle.
17+
fn topological_sort(&self) -> Result<Option<Vec<usize>>, GraphError>;
18+
}

ultragraph/src/traits/graph_traversal.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ pub trait GraphTraversal<N, W>: GraphView<N, W> {
44
// --- Traversal ---
55

66
/// Returns a non-allocating iterator over the direct successors (outgoing edges) of node `a`.
7-
///
8-
/// This method provides a direct, high-performance view into the graph's internal
9-
/// structure without any intermediate memory allocations.
10-
///
11-
/// # Returns
12-
/// A `Result` containing an iterator that yields the `usize` indices of the neighbor nodes.
137
fn outbound_edges(&self, a: usize) -> Result<impl Iterator<Item = usize> + '_, GraphError>;
148

159
/// Returns a non-allocating iterator over the direct predecessors (incoming edges) of node `a`.

ultragraph/src/traits/graph_view.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,7 @@ pub trait GraphView<N, W> {
1818
fn contains_edge(&self, a: usize, b: usize) -> bool;
1919
fn number_edges(&self) -> usize;
2020

21-
/// Returns a vector of immutable references to all active nodes in the graph.
22-
///
23-
/// The order of the nodes in the returned vector is not guaranteed.
24-
/// This operation is O(V) as it iterates through all possible node slots
2521
fn get_all_nodes(&self) -> Vec<&N>;
26-
27-
/// Retrieves a list of all outgoing edges from a given source node.
28-
/// Returns `None` if the source node does not exist.
29-
/// The returned vector contains tuples of `(target_node_index, edge_weight_reference)`.
3022
fn get_edges(&self, source: usize) -> Option<Vec<(usize, &W)>>;
3123

3224
fn get_last_index(&self) -> Option<usize>;

ultragraph/src/traits/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@ pub mod graph_mut;
99
pub mod graph_traversal;
1010
pub mod graph_view;
1111

12+
pub mod graph_algo_centrality;
13+
pub mod graph_algo_pathfinder;
14+
pub mod graph_algo_structural;
15+
pub mod graph_algo_topological;
1216
pub mod graph_freeze;
1317
pub mod graph_unfreeze;

0 commit comments

Comments
 (0)