rust_igraph/algorithms/properties/
sort_by_degree.rs1use crate::algorithms::properties::degree::DegreeMode;
10use crate::core::{Graph, IgraphError, IgraphResult, VertexId};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum SortOrder {
15 Ascending,
17 Descending,
19}
20
21pub fn sort_vertices_by_degree(
44 graph: &Graph,
45 mode: DegreeMode,
46 order: SortOrder,
47) -> IgraphResult<Vec<VertexId>> {
48 let n = graph.vcount();
49
50 if n == 0 {
51 return Ok(Vec::new());
52 }
53
54 let n_usize = n as usize;
55 let ecount = graph.ecount();
56 let directed = graph.is_directed();
57
58 let mut deg = vec![0u32; n_usize];
59
60 if ecount > 0 {
61 let m_u32 =
62 u32::try_from(ecount).map_err(|_| IgraphError::Internal("ecount exceeds u32::MAX"))?;
63
64 for eid in 0..m_u32 {
65 let (from, to) = graph.edge(eid)?;
66 let f = from as usize;
67 let t = to as usize;
68
69 if directed {
70 match mode {
71 DegreeMode::Out => {
72 deg[f] += 1;
73 }
74 DegreeMode::In => {
75 deg[t] += 1;
76 }
77 DegreeMode::All => {
78 deg[f] += 1;
79 deg[t] += 1;
80 }
81 }
82 } else if from == to {
83 deg[f] += 2;
84 } else {
85 deg[f] += 1;
86 deg[t] += 1;
87 }
88 }
89 }
90
91 let mut ids: Vec<VertexId> = (0..n).collect();
92
93 match order {
94 SortOrder::Ascending => {
95 ids.sort_by(|&a, &b| deg[a as usize].cmp(°[b as usize]));
96 }
97 SortOrder::Descending => {
98 ids.sort_by(|&a, &b| deg[b as usize].cmp(°[a as usize]));
99 }
100 }
101
102 Ok(ids)
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn empty_graph() {
111 let g = Graph::with_vertices(0);
112 let s = sort_vertices_by_degree(&g, DegreeMode::All, SortOrder::Ascending).unwrap();
113 assert!(s.is_empty());
114 }
115
116 #[test]
117 fn no_edges_ascending() {
118 let g = Graph::with_vertices(5);
119 let s = sort_vertices_by_degree(&g, DegreeMode::All, SortOrder::Ascending).unwrap();
120 assert_eq!(s, vec![0, 1, 2, 3, 4]);
122 }
123
124 #[test]
125 fn star_descending() {
126 let mut g = Graph::with_vertices(4);
127 g.add_edge(0, 1).unwrap();
128 g.add_edge(0, 2).unwrap();
129 g.add_edge(0, 3).unwrap();
130 let s = sort_vertices_by_degree(&g, DegreeMode::All, SortOrder::Descending).unwrap();
131 assert_eq!(s[0], 0);
133 assert_eq!(s.len(), 4);
134 }
135
136 #[test]
137 fn star_ascending() {
138 let mut g = Graph::with_vertices(4);
139 g.add_edge(0, 1).unwrap();
140 g.add_edge(0, 2).unwrap();
141 g.add_edge(0, 3).unwrap();
142 let s = sort_vertices_by_degree(&g, DegreeMode::All, SortOrder::Ascending).unwrap();
143 assert_eq!(s[3], 0);
145 }
146
147 #[test]
148 fn path_5_ascending() {
149 let mut g = Graph::with_vertices(5);
150 for i in 0..4u32 {
151 g.add_edge(i, i + 1).unwrap();
152 }
153 let s = sort_vertices_by_degree(&g, DegreeMode::All, SortOrder::Ascending).unwrap();
154 assert!(s[0] == 0 || s[0] == 4);
156 assert!(s[1] == 0 || s[1] == 4);
157 assert!(s[0] != s[1]);
158 }
159
160 #[test]
161 fn directed_out_degree() {
162 let mut g = Graph::new(3, true).unwrap();
164 g.add_edge(0, 1).unwrap();
165 g.add_edge(0, 2).unwrap();
166 g.add_edge(1, 2).unwrap();
167 let s = sort_vertices_by_degree(&g, DegreeMode::Out, SortOrder::Descending).unwrap();
168 assert_eq!(s, vec![0, 1, 2]);
170 }
171
172 #[test]
173 fn directed_in_degree() {
174 let mut g = Graph::new(3, true).unwrap();
176 g.add_edge(0, 1).unwrap();
177 g.add_edge(0, 2).unwrap();
178 g.add_edge(1, 2).unwrap();
179 let s = sort_vertices_by_degree(&g, DegreeMode::In, SortOrder::Descending).unwrap();
180 assert_eq!(s, vec![2, 1, 0]);
182 }
183
184 #[test]
185 fn k4_stable_order() {
186 let mut g = Graph::with_vertices(4);
187 for u in 0..4u32 {
188 for v in (u + 1)..4 {
189 g.add_edge(u, v).unwrap();
190 }
191 }
192 let s = sort_vertices_by_degree(&g, DegreeMode::All, SortOrder::Ascending).unwrap();
193 assert_eq!(s, vec![0, 1, 2, 3]);
195 }
196
197 #[test]
198 fn self_loop_counted() {
199 let mut g = Graph::with_vertices(3);
200 g.add_edge(0, 0).unwrap(); g.add_edge(0, 1).unwrap(); g.add_edge(1, 2).unwrap(); let s = sort_vertices_by_degree(&g, DegreeMode::All, SortOrder::Descending).unwrap();
204 assert_eq!(s, vec![0, 1, 2]);
206 }
207}