Skip to main content

converge_optimization/graph/
mod.rs

1//! Graph algorithms
2//!
3//! This module provides graph algorithms for optimization:
4//!
5//! - [`dijkstra`] - Shortest path algorithms
6//! - [`flow`] - Max flow and min cost flow
7//! - [`matching`] - Graph matching algorithms
8//!
9//! ## Graph Representation
10//!
11//! We use [`petgraph`] for the underlying graph structure, with
12//! wrapper types for optimization-specific operations.
13//!
14//! ## Example: Max Flow
15//!
16//! ```rust
17//! use converge_optimization::graph::flow::{FlowNetwork, max_flow};
18//!
19//! let mut net = FlowNetwork::new(4);
20//! net.add_edge_with_capacity(0, 1, 10);
21//! net.add_edge_with_capacity(0, 2, 10);
22//! net.add_edge_with_capacity(1, 3, 10);
23//! net.add_edge_with_capacity(2, 3, 10);
24//!
25//! let result = max_flow(&net, 0, 3).unwrap();
26//! assert_eq!(result.max_flow, 20);
27//! ```
28
29pub mod dijkstra;
30pub mod flow;
31pub mod matching;
32
33// Re-export main types
34pub use flow::{
35    FlowNetwork, MaxFlowResult, MinCostFlowProblem, MinCostFlowResult, max_flow, min_cost_flow,
36};
37
38use petgraph::graph::{DiGraph, EdgeIndex, NodeIndex};
39use serde::{Deserialize, Serialize};
40
41/// Node identifier
42pub type NodeId = NodeIndex;
43
44/// Edge identifier
45pub type EdgeId = EdgeIndex;
46
47/// A directed graph with node and edge weights
48pub type Graph<N, E> = DiGraph<N, E>;
49
50/// Edge with capacity and cost for flow problems
51#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
52pub struct FlowEdge {
53    /// Maximum flow capacity
54    pub capacity: i64,
55    /// Cost per unit flow
56    pub cost: i64,
57    /// Current flow (for solutions)
58    pub flow: i64,
59}
60
61impl FlowEdge {
62    /// Create a new flow edge
63    pub fn new(capacity: i64, cost: i64) -> Self {
64        Self {
65            capacity,
66            cost,
67            flow: 0,
68        }
69    }
70
71    /// Create an edge with only capacity (zero cost)
72    pub fn with_capacity(capacity: i64) -> Self {
73        Self::new(capacity, 0)
74    }
75
76    /// Remaining capacity
77    pub fn residual(&self) -> i64 {
78        self.capacity - self.flow
79    }
80}
81
82/// Path in a graph
83#[derive(Debug, Clone)]
84pub struct Path {
85    /// Nodes in the path (as indices)
86    pub nodes: Vec<NodeId>,
87    /// Total cost/distance of the path
88    pub cost: i64,
89}
90
91impl Path {
92    /// Create an empty path
93    pub fn empty() -> Self {
94        Self {
95            nodes: Vec::new(),
96            cost: 0,
97        }
98    }
99
100    /// Check if path is empty
101    pub fn is_empty(&self) -> bool {
102        self.nodes.is_empty()
103    }
104
105    /// Number of nodes in path
106    pub fn len(&self) -> usize {
107        self.nodes.len()
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_flow_edge() {
117        let mut edge = FlowEdge::new(10, 5);
118        assert_eq!(edge.residual(), 10);
119        edge.flow = 3;
120        assert_eq!(edge.residual(), 7);
121    }
122}