rust_igraph/algorithms/operators/
induced_subgraph_edges.rs1use crate::core::{Graph, IgraphError, IgraphResult};
10
11pub fn induced_subgraph_edges(graph: &Graph, vids: &[u32]) -> IgraphResult<Vec<u32>> {
41 let n = graph.vcount();
42 let m = graph.ecount();
43
44 let mut in_set: Vec<bool> = vec![false; n as usize];
46 for &vid in vids {
47 if vid >= n {
48 return Err(IgraphError::InvalidArgument(format!(
49 "induced_subgraph_edges: vertex ID {vid} out of range (graph has {n} vertices)"
50 )));
51 }
52 in_set[vid as usize] = true;
53 }
54
55 let mut result: Vec<u32> = Vec::new();
57 for eid_usize in 0..m {
58 #[allow(clippy::cast_possible_truncation)]
59 let eid = eid_usize as u32;
60 let (from, to) = graph.edge(eid)?;
61 if in_set[from as usize] && in_set[to as usize] {
62 result.push(eid);
63 }
64 }
65
66 Ok(result)
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn basic_undirected() {
75 let mut g = Graph::with_vertices(5);
76 g.add_edge(0, 1).unwrap(); g.add_edge(1, 2).unwrap(); g.add_edge(2, 3).unwrap(); g.add_edge(3, 4).unwrap(); g.add_edge(0, 4).unwrap(); let edges = induced_subgraph_edges(&g, &[0, 1, 2]).unwrap();
83 assert_eq!(edges, vec![0, 1]);
84 }
85
86 #[test]
87 fn all_vertices() {
88 let mut g = Graph::with_vertices(4);
89 g.add_edge(0, 1).unwrap();
90 g.add_edge(1, 2).unwrap();
91 g.add_edge(2, 3).unwrap();
92
93 let edges = induced_subgraph_edges(&g, &[0, 1, 2, 3]).unwrap();
94 assert_eq!(edges, vec![0, 1, 2]);
95 }
96
97 #[test]
98 fn single_vertex() {
99 let mut g = Graph::with_vertices(3);
100 g.add_edge(0, 1).unwrap();
101 g.add_edge(1, 2).unwrap();
102
103 let edges = induced_subgraph_edges(&g, &[1]).unwrap();
104 assert!(edges.is_empty());
105 }
106
107 #[test]
108 fn self_loop_included() {
109 let mut g = Graph::with_vertices(3);
110 g.add_edge(0, 0).unwrap(); g.add_edge(0, 1).unwrap(); g.add_edge(1, 2).unwrap(); let edges = induced_subgraph_edges(&g, &[0]).unwrap();
115 assert_eq!(edges, vec![0]); }
117
118 #[test]
119 fn directed_graph() {
120 let mut g = Graph::new(4, true).unwrap();
121 g.add_edge(0, 1).unwrap(); g.add_edge(1, 2).unwrap(); g.add_edge(2, 0).unwrap(); g.add_edge(2, 3).unwrap(); let edges = induced_subgraph_edges(&g, &[0, 1, 2]).unwrap();
127 assert_eq!(edges, vec![0, 1, 2]);
128 }
129
130 #[test]
131 fn empty_vertex_set() {
132 let mut g = Graph::with_vertices(3);
133 g.add_edge(0, 1).unwrap();
134
135 let edges = induced_subgraph_edges(&g, &[]).unwrap();
136 assert!(edges.is_empty());
137 }
138
139 #[test]
140 fn no_matching_edges() {
141 let mut g = Graph::with_vertices(4);
142 g.add_edge(0, 1).unwrap();
143 g.add_edge(2, 3).unwrap();
144
145 let edges = induced_subgraph_edges(&g, &[0, 2]).unwrap();
147 assert!(edges.is_empty());
148 }
149
150 #[test]
151 fn duplicate_vertex_ids() {
152 let mut g = Graph::with_vertices(3);
153 g.add_edge(0, 1).unwrap(); g.add_edge(1, 2).unwrap(); let edges = induced_subgraph_edges(&g, &[0, 1, 0, 1]).unwrap();
157 assert_eq!(edges, vec![0]);
158 }
159
160 #[test]
161 fn vertex_out_of_range() {
162 let g = Graph::with_vertices(3);
163 let err = induced_subgraph_edges(&g, &[5]).unwrap_err();
164 assert!(matches!(err, IgraphError::InvalidArgument(_)));
165 }
166
167 #[test]
168 fn graph_with_no_edges() {
169 let g = Graph::with_vertices(5);
170 let edges = induced_subgraph_edges(&g, &[0, 1, 2]).unwrap();
171 assert!(edges.is_empty());
172 }
173}