scirs2_graph/base/
graph.rs1use ndarray::{Array1, Array2};
4use petgraph::graph::{Graph as PetGraph, NodeIndex};
5use petgraph::visit::EdgeRef;
6use petgraph::Undirected;
7use std::collections::HashMap;
8
9use super::types::{Edge, EdgeWeight, Node};
10use crate::error::{GraphError, Result};
11pub use petgraph::graph::IndexType;
12
13pub struct Graph<N: Node, E: EdgeWeight, Ix: IndexType = u32> {
15 graph: PetGraph<N, E, Undirected, Ix>,
16 node_indices: HashMap<N, NodeIndex<Ix>>,
17}
18
19impl<N: Node + std::fmt::Debug, E: EdgeWeight, Ix: IndexType> Default for Graph<N, E, Ix> {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl<N: Node + std::fmt::Debug, E: EdgeWeight, Ix: IndexType> Graph<N, E, Ix> {
26 pub fn new() -> Self {
28 Graph {
29 graph: PetGraph::default(),
30 node_indices: HashMap::new(),
31 }
32 }
33
34 pub fn add_node(&mut self, node: N) -> NodeIndex<Ix> {
36 if let Some(idx) = self.node_indices.get(&node) {
37 return *idx;
38 }
39
40 let idx = self.graph.add_node(node.clone());
41 self.node_indices.insert(node, idx);
42 idx
43 }
44
45 pub fn add_edge(&mut self, source: N, target: N, weight: E) -> Result<()> {
47 let source_idx = self.add_node(source);
48 let target_idx = self.add_node(target);
49
50 self.graph.add_edge(source_idx, target_idx, weight);
51 Ok(())
52 }
53
54 pub fn adjacency_matrix(&self) -> Array2<E>
56 where
57 E: num_traits::Zero + num_traits::One + Copy,
58 {
59 let n = self.graph.node_count();
60 let mut adj_mat = Array2::zeros((n, n));
61
62 for edge in self.graph.edge_references() {
63 let (src, tgt) = (edge.source().index(), edge.target().index());
64 adj_mat[[src, tgt]] = *edge.weight();
65 adj_mat[[tgt, src]] = *edge.weight(); }
67
68 adj_mat
69 }
70
71 pub fn degree_vector(&self) -> Array1<usize> {
73 let n = self.graph.node_count();
74 let mut degrees = Array1::zeros(n);
75
76 for (idx, node) in self.graph.node_indices().enumerate() {
77 degrees[idx] = self.graph.neighbors(node).count();
78 }
79
80 degrees
81 }
82
83 pub fn nodes(&self) -> Vec<&N> {
85 self.graph.node_weights().collect()
86 }
87
88 pub fn edges(&self) -> Vec<Edge<N, E>>
90 where
91 N: Clone,
92 E: Clone,
93 {
94 let mut result = Vec::new();
95 let node_map: HashMap<NodeIndex<Ix>, &N> = self
96 .graph
97 .node_indices()
98 .map(|idx| (idx, self.graph.node_weight(idx).unwrap()))
99 .collect();
100
101 for edge in self.graph.edge_references() {
102 let source = node_map[&edge.source()].clone();
103 let target = node_map[&edge.target()].clone();
104 let weight = edge.weight().clone();
105
106 result.push(Edge {
107 source,
108 target,
109 weight,
110 });
111 }
112
113 result
114 }
115
116 pub fn node_count(&self) -> usize {
118 self.graph.node_count()
119 }
120
121 pub fn edge_count(&self) -> usize {
123 self.graph.edge_count()
124 }
125
126 pub fn has_node(&self, node: &N) -> bool {
128 self.node_indices.contains_key(node)
129 }
130
131 pub fn neighbors(&self, node: &N) -> Result<Vec<N>>
133 where
134 N: Clone,
135 {
136 if let Some(&idx) = self.node_indices.get(node) {
137 let neighbors: Vec<N> = self
138 .graph
139 .neighbors(idx)
140 .map(|neighbor_idx| self.graph[neighbor_idx].clone())
141 .collect();
142 Ok(neighbors)
143 } else {
144 Err(GraphError::node_not_found_with_context(
145 format!("{node:?}"),
146 self.node_count(),
147 "neighbors",
148 ))
149 }
150 }
151
152 pub fn has_edge(&self, source: &N, target: &N) -> bool {
154 if let (Some(&src_idx), Some(&tgt_idx)) =
155 (self.node_indices.get(source), self.node_indices.get(target))
156 {
157 self.graph.contains_edge(src_idx, tgt_idx)
158 } else {
159 false
160 }
161 }
162
163 pub fn edge_weight(&self, source: &N, target: &N) -> Result<E>
165 where
166 E: Clone,
167 {
168 if let (Some(&src_idx), Some(&tgt_idx)) =
169 (self.node_indices.get(source), self.node_indices.get(target))
170 {
171 if let Some(edge_ref) = self.graph.find_edge(src_idx, tgt_idx) {
172 Ok(self.graph[edge_ref].clone())
173 } else {
174 Err(GraphError::edge_not_found("unknown", "unknown"))
175 }
176 } else {
177 Err(GraphError::node_not_found("unknown node"))
178 }
179 }
180
181 pub fn degree(&self, node: &N) -> usize {
183 if let Some(idx) = self.node_indices.get(node) {
184 self.graph.neighbors(*idx).count()
185 } else {
186 0
187 }
188 }
189
190 pub fn contains_node(&self, node: &N) -> bool {
192 self.node_indices.contains_key(node)
193 }
194
195 pub fn node_index(&self, node: &N) -> Option<NodeIndex<Ix>> {
197 self.node_indices.get(node).copied()
198 }
199
200 pub fn inner(&self) -> &PetGraph<N, E, Undirected, Ix> {
202 &self.graph
203 }
204
205 pub fn inner_mut(&mut self) -> &mut PetGraph<N, E, Undirected, Ix> {
207 &mut self.graph
208 }
209}