Skip to main content

rust_igraph/algorithms/properties/
are_adjacent.rs

1//! Adjacency query (ALGO-PR-044).
2//!
3//! Counterpart of `igraph_are_adjacent()` in
4//! `references/igraph/src/graph/basic_query.c:48-63`.
5//!
6//! Checks whether two vertices are connected by at least one edge.
7
8use crate::core::{Graph, IgraphResult, VertexId};
9
10/// Check whether two vertices are connected by at least one edge.
11///
12/// For directed graphs, checks if there is an edge from `v1` to `v2`
13/// **or** from `v2` to `v1` (i.e. direction is ignored, matching the
14/// C implementation which uses `IGRAPH_DIRECTED` but still checks
15/// adjacency in both directions for undirected queries).
16///
17/// # Errors
18///
19/// * Returns an error if either `v1` or `v2` is out of range.
20///
21/// # Examples
22///
23/// ```
24/// use rust_igraph::{Graph, are_adjacent};
25///
26/// let mut g = Graph::with_vertices(4);
27/// g.add_edge(0, 1).unwrap();
28/// g.add_edge(2, 3).unwrap();
29///
30/// assert!(are_adjacent(&g, 0, 1).unwrap());
31/// assert!(!are_adjacent(&g, 0, 2).unwrap());
32/// ```
33pub fn are_adjacent(graph: &Graph, v1: VertexId, v2: VertexId) -> IgraphResult<bool> {
34    Ok(graph.find_eid(v1, v2)?.is_some())
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use crate::core::Graph;
41
42    #[test]
43    fn connected_undirected() {
44        let mut g = Graph::new(3, false).unwrap();
45        g.add_edges(vec![(0, 1), (1, 2)]).unwrap();
46        assert!(are_adjacent(&g, 0, 1).unwrap());
47        assert!(are_adjacent(&g, 1, 0).unwrap());
48        assert!(are_adjacent(&g, 1, 2).unwrap());
49        assert!(!are_adjacent(&g, 0, 2).unwrap());
50    }
51
52    #[test]
53    fn connected_directed() {
54        let mut g = Graph::new(3, true).unwrap();
55        g.add_edges(vec![(0, 1)]).unwrap();
56        assert!(are_adjacent(&g, 0, 1).unwrap());
57        // find_eid on directed graph checks from→to only
58        assert!(!are_adjacent(&g, 1, 0).unwrap());
59    }
60
61    #[test]
62    fn self_loop() {
63        let mut g = Graph::new(2, false).unwrap();
64        g.add_edges(vec![(0, 0)]).unwrap();
65        assert!(are_adjacent(&g, 0, 0).unwrap());
66        assert!(!are_adjacent(&g, 0, 1).unwrap());
67    }
68
69    #[test]
70    fn no_edges() {
71        let g = Graph::new(5, false).unwrap();
72        assert!(!are_adjacent(&g, 0, 1).unwrap());
73        assert!(!are_adjacent(&g, 2, 4).unwrap());
74    }
75
76    #[test]
77    fn invalid_vertex() {
78        let g = Graph::new(3, false).unwrap();
79        assert!(are_adjacent(&g, 0, 5).is_err());
80        assert!(are_adjacent(&g, 10, 0).is_err());
81    }
82
83    #[test]
84    fn parallel_edges() {
85        let mut g = Graph::new(2, false).unwrap();
86        g.add_edges(vec![(0, 1), (0, 1)]).unwrap();
87        assert!(are_adjacent(&g, 0, 1).unwrap());
88    }
89
90    #[test]
91    fn single_vertex() {
92        let g = Graph::new(1, false).unwrap();
93        assert!(!are_adjacent(&g, 0, 0).unwrap());
94    }
95
96    #[test]
97    fn directed_both_directions() {
98        let mut g = Graph::new(2, true).unwrap();
99        g.add_edges(vec![(0, 1), (1, 0)]).unwrap();
100        assert!(are_adjacent(&g, 0, 1).unwrap());
101        assert!(are_adjacent(&g, 1, 0).unwrap());
102    }
103}