Skip to main content

bidirected_adjacency_array/
graph.rs

1use std::iter;
2
3use tagged_vec::TaggedVec;
4
5use crate::index::{
6    DirectedEdgeIndex, DirectedNodeIndex, EdgeIndex, GraphIndexInteger, NodeIndex,
7    OptionalEdgeIndex,
8};
9
10#[cfg(test)]
11mod tests;
12
13#[derive(Debug)]
14pub struct BidirectedAdjacencyArray<IndexType: GraphIndexInteger, NodeData, EdgeData> {
15    /// Maps directed nodes to their edge lists.
16    ///
17    /// Each bidirected node is represented by two consecutive directed nodes.
18    /// The forward side is identified by [`DirectedNodeIndex::is_forward`].
19    ///
20    /// The last element is a sentinel value to simplify edge list iteration.
21    node_array: TaggedVec<DirectedNodeIndex<IndexType>, DirectedEdgeIndex<IndexType>>,
22
23    /// The edge lists for all directed nodes.
24    ///
25    /// Each bidirected edge is represented by two reverse-complemental directed edges.
26    /// Even ++ and -- self loops are represented by two distinct but same directed edges.
27    edge_array: TaggedVec<DirectedEdgeIndex<IndexType>, DirectedNodeIndex<IndexType>>,
28
29    /// Data associated with the nodes.
30    ///
31    /// Since each bidirected node is represented by two directed nodes,
32    /// the data for both directed nodes is stored at the same index.
33    /// Hence, the data of a directed node `n` is stored at index `n / 2`.
34    node_data: TaggedVec<NodeIndex<IndexType>, NodeData>,
35
36    /// Keys for finding the data associated with the edges.
37    ///
38    /// Each bidirected edge is represented by two directed edges,
39    /// and both directed edges share the same data.
40    /// However, we treat one directed edge as the "forward" direction and the other as the "reverse" direction.
41    /// We only store the data for the "forward" direction.
42    edge_data_keys: TaggedVec<DirectedEdgeIndex<IndexType>, EdgeDataKey<IndexType>>,
43
44    /// The actual edge data.
45    ///
46    /// This should be accessed via the `edge_data_keys`.
47    edge_data: TaggedVec<EdgeIndex<IndexType>, BidirectedEdgeData<IndexType, EdgeData>>,
48}
49
50#[derive(Debug, Clone, Copy)]
51struct EdgeDataKey<IndexType: GraphIndexInteger> {
52    inverse: DirectedEdgeIndex<IndexType>,
53    data_index: OptionalEdgeIndex<IndexType>,
54}
55
56#[derive(Debug)]
57struct BidirectedEdgeData<IndexType, EdgeData> {
58    forward: DirectedEdgeIndex<IndexType>,
59    reverse: DirectedEdgeIndex<IndexType>,
60    data: EdgeData,
61}
62
63pub struct DirectedEdgeDataView<'a, EdgeData> {
64    forward: bool,
65    data: &'a EdgeData,
66}
67
68pub struct EdgeView<'a, IndexType, EdgeData> {
69    from: DirectedNodeIndex<IndexType>,
70    to: DirectedNodeIndex<IndexType>,
71    data: &'a EdgeData,
72}
73
74#[derive(Debug, Clone, Hash, PartialEq, Eq)]
75pub struct BidirectedEdge<IndexType, EdgeData> {
76    pub from: NodeIndex<IndexType>,
77    /// True if this edge originates from the forward side of the `from` node.
78    pub from_forward: bool,
79    pub to: NodeIndex<IndexType>,
80    /// True if this edge terminates at the forward side of the `to` node.
81    pub to_forward: bool,
82    pub data: EdgeData,
83}
84
85impl<IndexType: GraphIndexInteger, NodeData, EdgeData>
86    BidirectedAdjacencyArray<IndexType, NodeData, EdgeData>
87{
88    pub fn new(
89        nodes: TaggedVec<NodeIndex<IndexType>, NodeData>,
90        edges: TaggedVec<EdgeIndex<IndexType>, BidirectedEdge<IndexType, EdgeData>>,
91    ) -> Self {
92        let mut node_array = TaggedVec::from_iter(iter::repeat_n(
93            DirectedEdgeIndex::from_usize(0),
94            nodes.len() * 2 + 1,
95        ));
96
97        // Count the number of outgoing edges for each directed node.
98        for edge in edges.iter_values() {
99            let from_directed_forward =
100                DirectedNodeIndex::from_bidirected(edge.from, edge.from_forward);
101            node_array[from_directed_forward].increment();
102            let from_directed_reverse =
103                DirectedNodeIndex::from_bidirected(edge.to, edge.to_forward).invert();
104            node_array[from_directed_reverse].increment();
105        }
106
107        // Convert counts to edge list limits by computing the prefix sum.
108        let directed_edge_count =
109            node_array
110                .iter_values_mut()
111                .fold(DirectedEdgeIndex::zero(), |sum, element| {
112                    let sum = sum.add(*element);
113                    *element = sum;
114                    sum
115                });
116        assert_eq!(
117            directed_edge_count,
118            node_array.iter_values().last().copied().unwrap(),
119        );
120
121        // Create edge data structures.
122        let mut edge_array = TaggedVec::from_iter(iter::repeat_n(
123            DirectedNodeIndex::from_usize(0),
124            directed_edge_count.into_usize(),
125        ));
126        let mut edge_data_keys = TaggedVec::from_iter(iter::repeat_n(
127            EdgeDataKey {
128                inverse: DirectedEdgeIndex::zero(),
129                data_index: OptionalEdgeIndex::new_none(),
130            },
131            directed_edge_count.into_usize(),
132        ));
133        let mut edge_data = TaggedVec::new();
134
135        // Now add edges by counting down the edge list limits.
136        // Afterwards, the node array will contain the correct edge list offsets.
137        for (edge_index, edge) in edges.into_iter() {
138            let from_directed_forward =
139                DirectedNodeIndex::from_bidirected(edge.from, edge.from_forward);
140            let to_directed_forward = DirectedNodeIndex::from_bidirected(edge.to, edge.to_forward);
141            let edge_index_forward = {
142                node_array[from_directed_forward].decrement();
143                node_array[from_directed_forward]
144            };
145
146            let from_directed_reverse = to_directed_forward.invert();
147            let to_directed_reverse = from_directed_forward.invert();
148            let edge_index_reverse = {
149                node_array[from_directed_reverse].decrement();
150                node_array[from_directed_reverse]
151            };
152
153            edge_array[edge_index_forward] = to_directed_forward;
154            edge_array[edge_index_reverse] = to_directed_reverse;
155
156            edge_data_keys[edge_index_forward] = EdgeDataKey {
157                inverse: edge_index_reverse,
158                data_index: edge_index.into(),
159            };
160            edge_data_keys[edge_index_reverse] = EdgeDataKey {
161                inverse: edge_index_forward,
162                data_index: OptionalEdgeIndex::new_none(),
163            };
164
165            let data_index = edge_data.push(BidirectedEdgeData {
166                forward: edge_index_forward,
167                reverse: edge_index_reverse,
168                data: edge.data,
169            });
170            assert_eq!(edge_index, data_index);
171        }
172
173        Self {
174            node_array,
175            edge_array,
176            node_data: nodes,
177            edge_data_keys,
178            edge_data,
179        }
180    }
181
182    pub fn node_count(&self) -> usize {
183        self.node_data.len()
184    }
185
186    pub fn edge_count(&self) -> usize {
187        self.edge_data.len()
188    }
189
190    pub fn iter_nodes(&self) -> impl Iterator<Item = NodeIndex<IndexType>> {
191        self.node_data.iter_indices()
192    }
193
194    pub fn iter_edges(&self) -> impl Iterator<Item = EdgeIndex<IndexType>> {
195        self.edge_data.iter_indices()
196    }
197
198    pub fn iter_successors(
199        &self,
200        node: DirectedNodeIndex<IndexType>,
201    ) -> impl Iterator<Item = (DirectedEdgeIndex<IndexType>, DirectedNodeIndex<IndexType>)> {
202        let start = self.node_array[node];
203        let end = self.node_array[node.add(DirectedNodeIndex::from_usize(1))];
204        self.edge_array
205            .iter()
206            .take(end.into_usize())
207            .skip(start.into_usize())
208            .map(|(edge_index, &to_node)| (edge_index, to_node))
209    }
210
211    pub fn node_data(&self, node: NodeIndex<IndexType>) -> &NodeData {
212        &self.node_data[node]
213    }
214
215    pub fn edge(&self, edge: EdgeIndex<IndexType>) -> EdgeView<'_, IndexType, EdgeData> {
216        let bidirected_edge_data = &self.edge_data[edge];
217
218        let forward_to = self.edge_array[bidirected_edge_data.forward];
219        let reverse_to = self.edge_array[bidirected_edge_data.reverse];
220
221        if forward_to == reverse_to {
222            // ++ or -- self loop case: both directed edges go from node to its reverse.
223            let from = forward_to.invert();
224            let to = forward_to;
225            EdgeView {
226                from,
227                to,
228                data: &bidirected_edge_data.data,
229            }
230        } else if forward_to.invert() == reverse_to {
231            // +- or -+ self loop case: directed edges are self loops.
232            let from = forward_to;
233            let to = forward_to;
234            EdgeView {
235                from,
236                to,
237                data: &bidirected_edge_data.data,
238            }
239        } else {
240            // Normal case: directed edges go between two different nodes.
241            let from = reverse_to.invert();
242            let to = forward_to;
243            EdgeView {
244                from,
245                to,
246                data: &bidirected_edge_data.data,
247            }
248        }
249    }
250
251    pub fn directed_edge_data<'this>(
252        &'this self,
253        edge: DirectedEdgeIndex<IndexType>,
254    ) -> DirectedEdgeDataView<'this, EdgeData> {
255        let key = &self.edge_data_keys[edge];
256        if let Some(data_index) = Option::<EdgeIndex<IndexType>>::from(key.data_index) {
257            DirectedEdgeDataView {
258                forward: true,
259                data: &self.edge_data[data_index].data,
260            }
261        } else {
262            let inverse_key = &self.edge_data_keys[key.inverse];
263            let Some(inverse_data_index) =
264                Option::<EdgeIndex<IndexType>>::from(inverse_key.data_index)
265            else {
266                panic!(
267                    "Edge data for edge {:?} and its inverse {:?} are both missing",
268                    edge, key.inverse
269                );
270            };
271            DirectedEdgeDataView {
272                forward: false,
273                data: &self.edge_data[inverse_data_index].data,
274            }
275        }
276    }
277}
278
279impl<'a, EdgeData> DirectedEdgeDataView<'a, EdgeData> {
280    pub fn is_forward(&self) -> bool {
281        self.forward
282    }
283
284    pub fn data(&self) -> &EdgeData {
285        self.data
286    }
287}
288
289impl<'a, IndexType, EdgeData> EdgeView<'a, IndexType, EdgeData> {
290    pub fn from(&self) -> DirectedNodeIndex<IndexType>
291    where
292        IndexType: Copy,
293    {
294        self.from
295    }
296
297    pub fn to(&self) -> DirectedNodeIndex<IndexType>
298    where
299        IndexType: Copy,
300    {
301        self.to
302    }
303
304    pub fn data(&self) -> &EdgeData {
305        self.data
306    }
307}