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