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 DirectedEdge<IndexType> {
64    from: DirectedNodeIndex<IndexType>,
65    to: DirectedNodeIndex<IndexType>,
66    index: DirectedEdgeIndex<IndexType>,
67}
68
69pub struct DirectedEdgeDataView<'a, IndexType, EdgeData> {
70    is_forward: bool,
71    edge: EdgeIndex<IndexType>,
72    data: &'a EdgeData,
73}
74
75pub struct EdgeView<'a, IndexType, EdgeData> {
76    from: DirectedNodeIndex<IndexType>,
77    to: DirectedNodeIndex<IndexType>,
78    forward: DirectedEdgeIndex<IndexType>,
79    reverse: DirectedEdgeIndex<IndexType>,
80    data: &'a EdgeData,
81}
82
83#[derive(Debug, Clone, Hash, PartialEq, Eq)]
84pub struct BidirectedEdge<IndexType, EdgeData> {
85    pub from: NodeIndex<IndexType>,
86    /// True if this edge originates from the forward side of the `from` node.
87    pub from_forward: bool,
88    pub to: NodeIndex<IndexType>,
89    /// True if this edge terminates at the forward side of the `to` node.
90    pub to_forward: bool,
91    pub data: EdgeData,
92}
93
94impl<IndexType: GraphIndexInteger, NodeData, EdgeData>
95    BidirectedAdjacencyArray<IndexType, NodeData, EdgeData>
96{
97    pub fn new(
98        nodes: TaggedVec<NodeIndex<IndexType>, NodeData>,
99        edges: TaggedVec<EdgeIndex<IndexType>, BidirectedEdge<IndexType, EdgeData>>,
100    ) -> Self {
101        let mut node_array = TaggedVec::from_iter(iter::repeat_n(
102            DirectedEdgeIndex::from_usize(0),
103            nodes.len() * 2 + 1,
104        ));
105
106        // Count the number of outgoing edges for each directed node.
107        for edge in edges.iter_values() {
108            let from_directed_forward =
109                DirectedNodeIndex::from_bidirected(edge.from, edge.from_forward);
110            node_array[from_directed_forward].increment();
111            let from_directed_reverse =
112                DirectedNodeIndex::from_bidirected(edge.to, edge.to_forward).invert();
113            node_array[from_directed_reverse].increment();
114        }
115
116        // Convert counts to edge list limits by computing the prefix sum.
117        let directed_edge_count =
118            node_array
119                .iter_values_mut()
120                .fold(DirectedEdgeIndex::zero(), |sum, element| {
121                    let sum = sum.add(*element);
122                    *element = sum;
123                    sum
124                });
125        assert_eq!(
126            directed_edge_count,
127            node_array.iter_values().last().copied().unwrap(),
128        );
129
130        // Create edge data structures.
131        let mut edge_array = TaggedVec::from_iter(iter::repeat_n(
132            DirectedNodeIndex::from_usize(0),
133            directed_edge_count.into_usize(),
134        ));
135        let mut edge_data_keys = TaggedVec::from_iter(iter::repeat_n(
136            EdgeDataKey {
137                inverse: DirectedEdgeIndex::zero(),
138                data_index: OptionalEdgeIndex::new_none(),
139            },
140            directed_edge_count.into_usize(),
141        ));
142        let mut edge_data = TaggedVec::new();
143
144        // Now add edges by counting down the edge list limits.
145        // Afterwards, the node array will contain the correct edge list offsets.
146        for (edge_index, edge) in edges.into_iter() {
147            let from_directed_forward =
148                DirectedNodeIndex::from_bidirected(edge.from, edge.from_forward);
149            let to_directed_forward = DirectedNodeIndex::from_bidirected(edge.to, edge.to_forward);
150            let edge_index_forward = {
151                node_array[from_directed_forward].decrement();
152                node_array[from_directed_forward]
153            };
154
155            let from_directed_reverse = to_directed_forward.invert();
156            let to_directed_reverse = from_directed_forward.invert();
157            let edge_index_reverse = {
158                node_array[from_directed_reverse].decrement();
159                node_array[from_directed_reverse]
160            };
161
162            edge_array[edge_index_forward] = to_directed_forward;
163            edge_array[edge_index_reverse] = to_directed_reverse;
164
165            edge_data_keys[edge_index_forward] = EdgeDataKey {
166                inverse: edge_index_reverse,
167                data_index: edge_index.into(),
168            };
169            edge_data_keys[edge_index_reverse] = EdgeDataKey {
170                inverse: edge_index_forward,
171                data_index: OptionalEdgeIndex::new_none(),
172            };
173
174            let data_index = edge_data.push(BidirectedEdgeData {
175                forward: edge_index_forward,
176                reverse: edge_index_reverse,
177                data: edge.data,
178            });
179            assert_eq!(edge_index, data_index);
180        }
181
182        Self {
183            node_array,
184            edge_array,
185            node_data: nodes,
186            edge_data_keys,
187            edge_data,
188        }
189    }
190
191    pub fn node_count(&self) -> usize {
192        self.node_data.len()
193    }
194
195    pub fn edge_count(&self) -> usize {
196        self.edge_data.len()
197    }
198
199    pub fn iter_nodes(&self) -> impl Iterator<Item = NodeIndex<IndexType>> {
200        self.node_data.iter_indices()
201    }
202
203    pub fn iter_edges(&self) -> impl Iterator<Item = EdgeIndex<IndexType>> {
204        self.edge_data.iter_indices()
205    }
206
207    pub fn iter_outgoing_edges(
208        &self,
209        node: DirectedNodeIndex<IndexType>,
210    ) -> impl Iterator<Item = DirectedEdge<IndexType>> {
211        let start = self.node_array[node];
212        let end = self.node_array[node.add(DirectedNodeIndex::from_usize(1))];
213        self.edge_array
214            .iter()
215            .take(end.into_usize())
216            .skip(start.into_usize())
217            .map(move |(edge_index, &to_node)| DirectedEdge {
218                from: node,
219                to: to_node,
220                index: edge_index,
221            })
222    }
223
224    /// Iterate over the bidirected edges incident to the given bidirected node.
225    pub fn iter_incident_edges(
226        &self,
227        node: NodeIndex<IndexType>,
228    ) -> impl Iterator<Item = EdgeIndex<IndexType>> {
229        let forward_node = DirectedNodeIndex::from_bidirected(node, true);
230        let reverse_node = DirectedNodeIndex::from_bidirected(node, false);
231        self.iter_outgoing_edges(forward_node)
232            .chain(self.iter_outgoing_edges(reverse_node))
233            .filter_map(|directed_edge| {
234                let directed_edge_data = self.directed_edge_data(directed_edge.index());
235                if directed_edge.from() == directed_edge.to()
236                    || directed_edge.from() == directed_edge.to().invert()
237                {
238                    directed_edge_data
239                        .is_forward()
240                        .then_some(directed_edge_data.edge())
241                } else {
242                    Some(directed_edge_data.edge())
243                }
244            })
245    }
246
247    pub fn node_data(&self, node: NodeIndex<IndexType>) -> &NodeData {
248        &self.node_data[node]
249    }
250
251    pub fn edge(&self, edge: EdgeIndex<IndexType>) -> EdgeView<'_, IndexType, EdgeData> {
252        let bidirected_edge_data = &self.edge_data[edge];
253
254        let forward_to = self.edge_array[bidirected_edge_data.forward];
255        let reverse_to = self.edge_array[bidirected_edge_data.reverse];
256
257        if forward_to == reverse_to {
258            // ++ or -- self loop case: both directed edges go from node to its reverse.
259            let from = forward_to.invert();
260            let to = forward_to;
261            EdgeView {
262                from,
263                to,
264                forward: bidirected_edge_data.forward,
265                reverse: bidirected_edge_data.reverse,
266                data: &bidirected_edge_data.data,
267            }
268        } else if forward_to.invert() == reverse_to {
269            // +- or -+ self loop case: directed edges are self loops.
270            let from = forward_to;
271            let to = forward_to;
272            EdgeView {
273                from,
274                to,
275                forward: bidirected_edge_data.forward,
276                reverse: bidirected_edge_data.reverse,
277                data: &bidirected_edge_data.data,
278            }
279        } else {
280            // Normal case: directed edges go between two different nodes.
281            let from = reverse_to.invert();
282            let to = forward_to;
283            EdgeView {
284                from,
285                to,
286                forward: bidirected_edge_data.forward,
287                reverse: bidirected_edge_data.reverse,
288                data: &bidirected_edge_data.data,
289            }
290        }
291    }
292
293    pub fn directed_edge_data<'this>(
294        &'this self,
295        directed_edge: DirectedEdgeIndex<IndexType>,
296    ) -> DirectedEdgeDataView<'this, IndexType, EdgeData> {
297        let key = &self.edge_data_keys[directed_edge];
298        if let Some(edge) = key.data_index.into_option() {
299            DirectedEdgeDataView {
300                is_forward: true,
301                edge,
302                data: &self.edge_data[edge].data,
303            }
304        } else {
305            let inverse_key = &self.edge_data_keys[key.inverse];
306            let Some(edge) = inverse_key.data_index.into_option() else {
307                panic!(
308                    "Edge data for edge {:?} and its inverse {:?} are both missing",
309                    directed_edge, key.inverse
310                );
311            };
312            DirectedEdgeDataView {
313                is_forward: false,
314                edge,
315                data: &self.edge_data[edge].data,
316            }
317        }
318    }
319
320    pub fn directed_edge_into_bidirected(
321        &self,
322        directed_edge: DirectedEdgeIndex<IndexType>,
323    ) -> EdgeIndex<IndexType> {
324        let key = &self.edge_data_keys[directed_edge];
325        if let Some(edge) = key.data_index.into_option() {
326            edge
327        } else {
328            let inverse_key = &self.edge_data_keys[key.inverse];
329            inverse_key
330                .data_index
331                .expect("Edge data for directed edge and its inverse are both missing")
332        }
333    }
334}
335
336impl<IndexType> DirectedEdge<IndexType> {
337    pub fn from(&self) -> DirectedNodeIndex<IndexType>
338    where
339        IndexType: Copy,
340    {
341        self.from
342    }
343
344    pub fn to(&self) -> DirectedNodeIndex<IndexType>
345    where
346        IndexType: Copy,
347    {
348        self.to
349    }
350
351    pub fn index(&self) -> DirectedEdgeIndex<IndexType>
352    where
353        IndexType: Copy,
354    {
355        self.index
356    }
357}
358
359impl<'a, IndexType, EdgeData> DirectedEdgeDataView<'a, IndexType, EdgeData> {
360    pub fn is_forward(&self) -> bool {
361        self.is_forward
362    }
363
364    pub fn edge(&self) -> EdgeIndex<IndexType>
365    where
366        IndexType: Copy,
367    {
368        self.edge
369    }
370
371    pub fn data(&self) -> &EdgeData {
372        self.data
373    }
374}
375
376impl<'a, IndexType, EdgeData> EdgeView<'a, IndexType, EdgeData> {
377    pub fn from(&self) -> DirectedNodeIndex<IndexType>
378    where
379        IndexType: Copy,
380    {
381        self.from
382    }
383
384    pub fn to(&self) -> DirectedNodeIndex<IndexType>
385    where
386        IndexType: Copy,
387    {
388        self.to
389    }
390
391    pub fn forward(&self) -> DirectedEdgeIndex<IndexType>
392    where
393        IndexType: Copy,
394    {
395        self.forward
396    }
397
398    pub fn reverse(&self) -> DirectedEdgeIndex<IndexType>
399    where
400        IndexType: Copy,
401    {
402        self.reverse
403    }
404
405    pub fn data(&self) -> &EdgeData {
406        self.data
407    }
408}