Skip to main content

rust_igraph/algorithms/properties/
get_eids.rs

1//! Batch edge-ID lookup from vertex pairs.
2//!
3//! Counterpart of `igraph_get_eids()` in
4//! `references/igraph/src/graph/type_indexededgelist.c`.
5
6use crate::core::graph::EdgeId;
7use crate::core::{Graph, IgraphError, IgraphResult, VertexId};
8
9/// Look up edge IDs for a batch of vertex pairs.
10///
11/// Each element `(from, to)` in `pairs` is resolved to the
12/// corresponding edge ID. If no edge exists for a given pair,
13/// the result depends on `error`: when `true`, the function returns
14/// an error; when `false`, the missing entry is `None`.
15///
16/// Counterpart of `igraph_get_eids` from
17/// `references/igraph/src/graph/type_indexededgelist.c`.
18///
19/// # Examples
20///
21/// ```
22/// use rust_igraph::{Graph, get_eids};
23///
24/// let mut g = Graph::with_vertices(4);
25/// g.add_edge(0, 1).unwrap(); // eid 0
26/// g.add_edge(1, 2).unwrap(); // eid 1
27/// g.add_edge(2, 3).unwrap(); // eid 2
28///
29/// let eids = get_eids(&g, &[(0, 1), (2, 3)], true).unwrap();
30/// assert_eq!(eids, vec![Some(0), Some(2)]);
31/// ```
32pub fn get_eids(
33    graph: &Graph,
34    pairs: &[(VertexId, VertexId)],
35    error: bool,
36) -> IgraphResult<Vec<Option<EdgeId>>> {
37    let mut result = Vec::with_capacity(pairs.len());
38    for &(from, to) in pairs {
39        let eid = graph.find_eid(from, to)?;
40        if error && eid.is_none() {
41            return Err(IgraphError::InvalidArgument(format!(
42                "no edge between {from} and {to}"
43            )));
44        }
45        result.push(eid);
46    }
47    Ok(result)
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn batch_lookup_undirected() {
56        let mut g = Graph::with_vertices(4);
57        g.add_edge(0, 1).unwrap();
58        g.add_edge(1, 2).unwrap();
59        g.add_edge(2, 3).unwrap();
60        let eids = get_eids(&g, &[(0, 1), (1, 2), (2, 3)], true).unwrap();
61        assert_eq!(eids, vec![Some(0), Some(1), Some(2)]);
62    }
63
64    #[test]
65    fn reverse_pair_undirected() {
66        let mut g = Graph::with_vertices(3);
67        g.add_edge(0, 1).unwrap();
68        let eids = get_eids(&g, &[(1, 0)], true).unwrap();
69        assert_eq!(eids, vec![Some(0)]);
70    }
71
72    #[test]
73    fn missing_edge_error_mode() {
74        let mut g = Graph::with_vertices(3);
75        g.add_edge(0, 1).unwrap();
76        let err = get_eids(&g, &[(0, 2)], true).unwrap_err();
77        assert!(matches!(err, IgraphError::InvalidArgument(_)));
78    }
79
80    #[test]
81    fn missing_edge_silent_mode() {
82        let mut g = Graph::with_vertices(3);
83        g.add_edge(0, 1).unwrap();
84        let eids = get_eids(&g, &[(0, 1), (0, 2)], false).unwrap();
85        assert_eq!(eids, vec![Some(0), None]);
86    }
87
88    #[test]
89    fn directed_one_way() {
90        let mut g = Graph::new(3, true).unwrap();
91        g.add_edge(0, 1).unwrap();
92        let eids = get_eids(&g, &[(0, 1)], true).unwrap();
93        assert_eq!(eids, vec![Some(0)]);
94        let eids = get_eids(&g, &[(1, 0)], false).unwrap();
95        assert_eq!(eids, vec![None]);
96    }
97
98    #[test]
99    fn empty_pairs() {
100        let g = Graph::with_vertices(3);
101        let eids = get_eids(&g, &[], true).unwrap();
102        assert!(eids.is_empty());
103    }
104
105    #[test]
106    fn invalid_vertex_errors() {
107        let g = Graph::with_vertices(2);
108        assert!(get_eids(&g, &[(0, 5)], true).is_err());
109    }
110}