Skip to main content

bidirected_adjacency_array/
graph.rs

1use std::iter;
2
3use tagged_vec::TaggedVec;
4
5use crate::{
6    index::{
7        DirectedEdgeIndex, DirectedNodeIndex, EdgeIndex, GraphIndexInteger, NodeIndex,
8        OptionalEdgeIndex,
9    },
10    io::gfa1::PlainGfaEdgeData,
11};
12
13#[cfg(test)]
14mod tests;
15
16#[derive(Debug)]
17pub struct BidirectedAdjacencyArray<IndexType: GraphIndexInteger, NodeData, EdgeData> {
18    /// Maps directed nodes to their edge lists.
19    ///
20    /// Each bidirected node is represented by two consecutive directed nodes.
21    /// The forward side is identified by [`DirectedNodeIndex::is_forward`].
22    ///
23    /// The last element is a sentinel value to simplify edge list iteration.
24    node_array: TaggedVec<DirectedNodeIndex<IndexType>, DirectedEdgeIndex<IndexType>>,
25
26    /// The edge lists for all directed nodes.
27    ///
28    /// Each bidirected edge is represented by two reverse-complemental directed edges.
29    /// Even ++ and -- self loops are represented by two distinct but same directed edges.
30    edge_array: TaggedVec<DirectedEdgeIndex<IndexType>, DirectedNodeIndex<IndexType>>,
31
32    /// Data associated with the nodes.
33    ///
34    /// Since each bidirected node is represented by two directed nodes,
35    /// the data for both directed nodes is stored at the same index.
36    /// Hence, the data of a directed node `n` is stored at index `n / 2`.
37    node_data: TaggedVec<NodeIndex<IndexType>, NodeData>,
38
39    /// Keys for finding the data associated with the edges.
40    ///
41    /// Each bidirected edge is represented by two directed edges,
42    /// and both directed edges share the same data.
43    /// However, we treat one directed edge as the "forward" direction and the other as the "reverse" direction.
44    /// We only store the data for the "forward" direction.
45    edge_data_keys: TaggedVec<DirectedEdgeIndex<IndexType>, EdgeDataKey<IndexType>>,
46
47    /// The actual edge data.
48    ///
49    /// This should be accessed via the `edge_data_keys`.
50    edge_data: TaggedVec<EdgeIndex<IndexType>, BidirectedEdgeData<IndexType, EdgeData>>,
51}
52
53#[derive(Debug, Clone, Copy)]
54struct EdgeDataKey<IndexType: GraphIndexInteger> {
55    inverse: DirectedEdgeIndex<IndexType>,
56    data_index: OptionalEdgeIndex<IndexType>,
57}
58
59#[derive(Debug)]
60struct BidirectedEdgeData<IndexType, EdgeData> {
61    forward: DirectedEdgeIndex<IndexType>,
62    reverse: DirectedEdgeIndex<IndexType>,
63    data: EdgeData,
64}
65
66pub struct DirectedEdge<IndexType> {
67    from: DirectedNodeIndex<IndexType>,
68    to: DirectedNodeIndex<IndexType>,
69    index: DirectedEdgeIndex<IndexType>,
70}
71
72pub struct DirectedEdgeDataView<'a, IndexType, EdgeData> {
73    is_forward: bool,
74    edge: EdgeIndex<IndexType>,
75    data: &'a EdgeData,
76}
77
78pub struct EdgeView<'a, IndexType, EdgeData> {
79    from: DirectedNodeIndex<IndexType>,
80    to: DirectedNodeIndex<IndexType>,
81    forward: DirectedEdgeIndex<IndexType>,
82    reverse: DirectedEdgeIndex<IndexType>,
83    data: &'a EdgeData,
84}
85
86#[derive(Debug, Clone, Hash, PartialEq, Eq)]
87pub struct BidirectedEdge<IndexType, EdgeData> {
88    pub from: NodeIndex<IndexType>,
89    /// True if this edge originates from the forward side of the `from` node.
90    pub from_forward: bool,
91    pub to: NodeIndex<IndexType>,
92    /// True if this edge terminates at the forward side of the `to` node.
93    pub to_forward: bool,
94    pub data: EdgeData,
95}
96
97impl<IndexType: GraphIndexInteger, NodeData, EdgeData>
98    BidirectedAdjacencyArray<IndexType, NodeData, EdgeData>
99{
100    pub fn new(
101        nodes: TaggedVec<NodeIndex<IndexType>, NodeData>,
102        edges: TaggedVec<EdgeIndex<IndexType>, BidirectedEdge<IndexType, EdgeData>>,
103    ) -> Self {
104        let mut node_array = TaggedVec::from_iter(iter::repeat_n(
105            DirectedEdgeIndex::from_usize(0),
106            nodes.len() * 2 + 1,
107        ));
108
109        // Count the number of outgoing edges for each directed node.
110        for edge in edges.iter_values() {
111            let from_directed_forward =
112                DirectedNodeIndex::from_bidirected(edge.from, edge.from_forward);
113            node_array[from_directed_forward].increment();
114            let from_directed_reverse =
115                DirectedNodeIndex::from_bidirected(edge.to, edge.to_forward).invert();
116            node_array[from_directed_reverse].increment();
117        }
118
119        // Convert counts to edge list limits by computing the prefix sum.
120        let directed_edge_count =
121            node_array
122                .iter_values_mut()
123                .fold(DirectedEdgeIndex::zero(), |sum, element| {
124                    let sum = sum.add(*element);
125                    *element = sum;
126                    sum
127                });
128        assert_eq!(
129            directed_edge_count,
130            node_array.iter_values().last().copied().unwrap(),
131        );
132
133        // Create edge data structures.
134        let mut edge_array = TaggedVec::from_iter(iter::repeat_n(
135            DirectedNodeIndex::from_usize(0),
136            directed_edge_count.into_usize(),
137        ));
138        let mut edge_data_keys = TaggedVec::from_iter(iter::repeat_n(
139            EdgeDataKey {
140                inverse: DirectedEdgeIndex::zero(),
141                data_index: OptionalEdgeIndex::new_none(),
142            },
143            directed_edge_count.into_usize(),
144        ));
145        let mut edge_data = TaggedVec::new();
146
147        // Now add edges by counting down the edge list limits.
148        // Afterwards, the node array will contain the correct edge list offsets.
149        for (edge_index, edge) in edges.into_iter() {
150            let from_directed_forward =
151                DirectedNodeIndex::from_bidirected(edge.from, edge.from_forward);
152            let to_directed_forward = DirectedNodeIndex::from_bidirected(edge.to, edge.to_forward);
153            let edge_index_forward = {
154                node_array[from_directed_forward].decrement();
155                node_array[from_directed_forward]
156            };
157
158            let from_directed_reverse = to_directed_forward.invert();
159            let to_directed_reverse = from_directed_forward.invert();
160            let edge_index_reverse = {
161                node_array[from_directed_reverse].decrement();
162                node_array[from_directed_reverse]
163            };
164
165            edge_array[edge_index_forward] = to_directed_forward;
166            edge_array[edge_index_reverse] = to_directed_reverse;
167
168            edge_data_keys[edge_index_forward] = EdgeDataKey {
169                inverse: edge_index_reverse,
170                data_index: edge_index.into(),
171            };
172            edge_data_keys[edge_index_reverse] = EdgeDataKey {
173                inverse: edge_index_forward,
174                data_index: OptionalEdgeIndex::new_none(),
175            };
176
177            let data_index = edge_data.push(BidirectedEdgeData {
178                forward: edge_index_forward,
179                reverse: edge_index_reverse,
180                data: edge.data,
181            });
182            assert_eq!(edge_index, data_index);
183        }
184
185        Self {
186            node_array,
187            edge_array,
188            node_data: nodes,
189            edge_data_keys,
190            edge_data,
191        }
192    }
193
194    pub fn node_count(&self) -> usize {
195        self.node_data.len()
196    }
197
198    pub fn edge_count(&self) -> usize {
199        self.edge_data.len()
200    }
201
202    pub fn iter_nodes(&self) -> impl Iterator<Item = NodeIndex<IndexType>> {
203        self.node_data.iter_indices()
204    }
205
206    pub fn iter_edges(&self) -> impl Iterator<Item = EdgeIndex<IndexType>> {
207        self.edge_data.iter_indices()
208    }
209
210    pub fn iter_outgoing_edges(
211        &self,
212        node: DirectedNodeIndex<IndexType>,
213    ) -> impl Iterator<Item = DirectedEdge<IndexType>> {
214        let start = self.node_array[node];
215        let end = self.node_array[node.add(DirectedNodeIndex::from_usize(1))];
216        self.edge_array
217            .iter()
218            .take(end.into_usize())
219            .skip(start.into_usize())
220            .map(move |(edge_index, &to_node)| DirectedEdge {
221                from: node,
222                to: to_node,
223                index: edge_index,
224            })
225    }
226
227    /// Iterate over the bidirected edges incident to the given bidirected node.
228    pub fn iter_incident_edges(
229        &self,
230        node: NodeIndex<IndexType>,
231    ) -> impl Iterator<Item = EdgeIndex<IndexType>> {
232        let forward_node = DirectedNodeIndex::from_bidirected(node, true);
233        let reverse_node = DirectedNodeIndex::from_bidirected(node, false);
234        self.iter_outgoing_edges(forward_node)
235            .chain(self.iter_outgoing_edges(reverse_node))
236            .filter_map(|directed_edge| {
237                let directed_edge_data = self.directed_edge_data(directed_edge.index());
238                if directed_edge.from() == directed_edge.to()
239                    || directed_edge.from() == directed_edge.to().invert()
240                {
241                    directed_edge_data
242                        .is_forward()
243                        .then_some(directed_edge_data.edge())
244                } else {
245                    Some(directed_edge_data.edge())
246                }
247            })
248    }
249
250    pub fn node_data(&self, node: NodeIndex<IndexType>) -> &NodeData {
251        &self.node_data[node]
252    }
253
254    pub fn edge(&self, edge: EdgeIndex<IndexType>) -> EdgeView<'_, IndexType, EdgeData> {
255        let bidirected_edge_data = &self.edge_data[edge];
256
257        let forward_to = self.edge_array[bidirected_edge_data.forward];
258        let reverse_to = self.edge_array[bidirected_edge_data.reverse];
259
260        if forward_to == reverse_to {
261            // ++ or -- self loop case: both directed edges go from node to its reverse.
262            let from = forward_to.invert();
263            let to = forward_to;
264            EdgeView {
265                from,
266                to,
267                forward: bidirected_edge_data.forward,
268                reverse: bidirected_edge_data.reverse,
269                data: &bidirected_edge_data.data,
270            }
271        } else if forward_to.invert() == reverse_to {
272            // +- or -+ self loop case: directed edges are self loops.
273            let from = forward_to;
274            let to = forward_to;
275            EdgeView {
276                from,
277                to,
278                forward: bidirected_edge_data.forward,
279                reverse: bidirected_edge_data.reverse,
280                data: &bidirected_edge_data.data,
281            }
282        } else {
283            // Normal case: directed edges go between two different nodes.
284            let from = reverse_to.invert();
285            let to = forward_to;
286            EdgeView {
287                from,
288                to,
289                forward: bidirected_edge_data.forward,
290                reverse: bidirected_edge_data.reverse,
291                data: &bidirected_edge_data.data,
292            }
293        }
294    }
295
296    pub fn directed_edge_data<'this>(
297        &'this self,
298        directed_edge: DirectedEdgeIndex<IndexType>,
299    ) -> DirectedEdgeDataView<'this, IndexType, EdgeData> {
300        let key = &self.edge_data_keys[directed_edge];
301        if let Some(edge) = key.data_index.into_option() {
302            DirectedEdgeDataView {
303                is_forward: true,
304                edge,
305                data: &self.edge_data[edge].data,
306            }
307        } else {
308            let inverse_key = &self.edge_data_keys[key.inverse];
309            let Some(edge) = inverse_key.data_index.into_option() else {
310                panic!(
311                    "Edge data for edge {:?} and its inverse {:?} are both missing",
312                    directed_edge, key.inverse
313                );
314            };
315            DirectedEdgeDataView {
316                is_forward: false,
317                edge,
318                data: &self.edge_data[edge].data,
319            }
320        }
321    }
322
323    pub fn directed_edge_into_bidirected(
324        &self,
325        directed_edge: DirectedEdgeIndex<IndexType>,
326    ) -> EdgeIndex<IndexType> {
327        let key = &self.edge_data_keys[directed_edge];
328        if let Some(edge) = key.data_index.into_option() {
329            edge
330        } else {
331            let inverse_key = &self.edge_data_keys[key.inverse];
332            inverse_key
333                .data_index
334                .expect("Edge data for directed edge and its inverse are both missing")
335        }
336    }
337}
338
339impl<IndexType> DirectedEdge<IndexType> {
340    pub fn from(&self) -> DirectedNodeIndex<IndexType>
341    where
342        IndexType: Copy,
343    {
344        self.from
345    }
346
347    pub fn to(&self) -> DirectedNodeIndex<IndexType>
348    where
349        IndexType: Copy,
350    {
351        self.to
352    }
353
354    pub fn index(&self) -> DirectedEdgeIndex<IndexType>
355    where
356        IndexType: Copy,
357    {
358        self.index
359    }
360}
361
362impl<'a, IndexType, EdgeData> DirectedEdgeDataView<'a, IndexType, EdgeData> {
363    pub fn is_forward(&self) -> bool {
364        self.is_forward
365    }
366
367    pub fn edge(&self) -> EdgeIndex<IndexType>
368    where
369        IndexType: Copy,
370    {
371        self.edge
372    }
373
374    pub fn data(&self) -> &EdgeData {
375        self.data
376    }
377}
378
379impl<'a, IndexType, EdgeData> EdgeView<'a, IndexType, EdgeData> {
380    pub fn from(&self) -> DirectedNodeIndex<IndexType>
381    where
382        IndexType: Copy,
383    {
384        self.from
385    }
386
387    pub fn to(&self) -> DirectedNodeIndex<IndexType>
388    where
389        IndexType: Copy,
390    {
391        self.to
392    }
393
394    pub fn forward(&self) -> DirectedEdgeIndex<IndexType>
395    where
396        IndexType: Copy,
397    {
398        self.forward
399    }
400
401    pub fn reverse(&self) -> DirectedEdgeIndex<IndexType>
402    where
403        IndexType: Copy,
404    {
405        self.reverse
406    }
407
408    pub fn data(&self) -> &EdgeData {
409        self.data
410    }
411}
412
413impl<IndexType: GraphIndexInteger, EdgeData> BidirectedEdge<IndexType, EdgeData> {
414    pub fn new(
415        from: DirectedNodeIndex<IndexType>,
416        to: DirectedNodeIndex<IndexType>,
417        data: EdgeData,
418    ) -> Self {
419        Self {
420            from: from.into_bidirected(),
421            from_forward: from.is_forward(),
422            to: to.into_bidirected(),
423            to_forward: to.is_forward(),
424            data,
425        }
426    }
427}
428
429impl<IndexType: GraphIndexInteger> BidirectedEdge<IndexType, PlainGfaEdgeData> {
430    pub fn new_gfa(
431        from: DirectedNodeIndex<IndexType>,
432        to: DirectedNodeIndex<IndexType>,
433        overlap: u16,
434    ) -> Self {
435        Self {
436            from: from.into_bidirected(),
437            from_forward: from.is_forward(),
438            to: to.into_bidirected(),
439            to_forward: to.is_forward(),
440            data: PlainGfaEdgeData::new(overlap),
441        }
442    }
443}