rustworkx_core/
line_graph.rs

1// Licensed under the Apache License, Version 2.0 (the "License"); you may
2// not use this file except in compliance with the License. You may obtain
3// a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10// License for the specific language governing permissions and limitations
11// under the License.
12
13use std::hash::Hash;
14
15use hashbrown::HashMap;
16use petgraph::data::Create;
17use petgraph::visit::{Data, EdgeCount, EdgeRef, IntoEdges, IntoNodeIdentifiers};
18
19/// Constructs the line graph of an undirected graph.
20///
21/// The line graph `L(G)` of a graph `G` represents the adjacencies between edges of G.
22/// `L(G)` contains a vertex for every edge in `G`, and `L(G)` contains an edge between two
23/// vertices if the corresponding edges in `G` have a vertex in common.
24///
25/// Arguments:
26///
27/// * `input_graph` - The input graph `G`.
28/// * `default_node_weight` - A callable that will return the weight to use
29///     for newly created nodes.
30/// * `default_edge_weight` - A callable that will return the weight object
31///     to use for newly created edges.
32///
33/// Returns the constructed line graph `L(G)`, and the map from the edges of `L(G)` to
34/// the vertices of `G`.
35///
36/// # Example
37/// ```rust
38/// use rustworkx_core::line_graph::line_graph;
39/// use rustworkx_core::petgraph::visit::EdgeRef;
40/// use rustworkx_core::petgraph::Graph;
41/// use hashbrown::HashMap;
42/// use petgraph::graph::{EdgeIndex, NodeIndex};
43/// use petgraph::Undirected;
44///
45/// let input_graph =
46///   Graph::<(), (), Undirected>::from_edges(&[(0, 1), (0, 2), (1, 2), (0, 3)]);
47///
48/// let (output_graph, output_edge_map): (
49///     petgraph::graph::UnGraph<(), ()>,
50///     HashMap<petgraph::prelude::EdgeIndex, petgraph::prelude::NodeIndex>,
51/// ) = line_graph(&input_graph, || (), || ());
52///
53/// let output_edge_list = output_graph
54///     .edge_references()
55///     .map(|edge| (edge.source().index(), edge.target().index()))
56///     .collect::<Vec<(usize, usize)>>();
57///
58/// let expected_edge_list = vec![(3, 1), (3, 0), (1, 0), (2, 0), (2, 1)];
59/// let expected_edge_map: HashMap<EdgeIndex, NodeIndex> = [
60///     (EdgeIndex::new(0), NodeIndex::new(0)),
61///     (EdgeIndex::new(1), NodeIndex::new(1)),
62///     (EdgeIndex::new(2), NodeIndex::new(2)),
63///     (EdgeIndex::new(3), NodeIndex::new(3)),
64/// ]
65/// .into_iter()
66/// .collect();
67///
68/// assert_eq!(output_edge_list, expected_edge_list);
69/// assert_eq!(output_edge_map, expected_edge_map);
70/// ```
71pub fn line_graph<K, G, T, F, H, M>(
72    input_graph: K,
73    mut default_node_weight: F,
74    mut default_edge_weight: H,
75) -> (G, HashMap<K::EdgeId, G::NodeId>)
76where
77    K: EdgeCount + IntoNodeIdentifiers + IntoEdges,
78    G: Create + Data<NodeWeight = T, EdgeWeight = M>,
79    F: FnMut() -> T,
80    H: FnMut() -> M,
81    K::EdgeId: Hash + Eq,
82{
83    let num_edges = input_graph.edge_count();
84    let mut output_graph = G::with_capacity(num_edges, 0);
85    let mut output_edge_map =
86        HashMap::<K::EdgeId, G::NodeId>::with_capacity(input_graph.edge_count());
87
88    for edge in input_graph.edge_references() {
89        let new_node = output_graph.add_node(default_node_weight());
90        output_edge_map.insert(edge.id(), new_node);
91    }
92
93    for node in input_graph.node_identifiers() {
94        let edges: Vec<K::EdgeRef> = input_graph.edges(node).collect();
95        for i in 0..edges.len() {
96            for j in i + 1..edges.len() {
97                let node0 = output_edge_map.get(&edges[i].id()).unwrap();
98                let node1 = output_edge_map.get(&edges[j].id()).unwrap();
99                output_graph.add_edge(*node0, *node1, default_edge_weight());
100            }
101        }
102    }
103    (output_graph, output_edge_map)
104}
105
106#[cfg(test)]
107
108mod test_line_graph {
109    use crate::line_graph::line_graph;
110    use crate::petgraph::visit::EdgeRef;
111    use crate::petgraph::Graph;
112    use hashbrown::HashMap;
113    use petgraph::graph::{EdgeIndex, NodeIndex};
114    use petgraph::Undirected;
115
116    #[test]
117    fn test_simple_graph() {
118        // Simple graph
119        let input_graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (2, 3), (3, 4), (4, 5)]);
120
121        let (output_graph, output_edge_map): (
122            petgraph::graph::UnGraph<(), ()>,
123            HashMap<petgraph::prelude::EdgeIndex, petgraph::prelude::NodeIndex>,
124        ) = line_graph(&input_graph, || (), || ());
125
126        let output_edge_list = output_graph
127            .edge_references()
128            .map(|edge| (edge.source().index(), edge.target().index()))
129            .collect::<Vec<(usize, usize)>>();
130
131        let expected_edge_list = vec![(2, 1), (3, 2)];
132        let expected_edge_map: HashMap<EdgeIndex, NodeIndex> = [
133            (EdgeIndex::new(0), NodeIndex::new(0)),
134            (EdgeIndex::new(1), NodeIndex::new(1)),
135            (EdgeIndex::new(2), NodeIndex::new(2)),
136            (EdgeIndex::new(3), NodeIndex::new(3)),
137        ]
138        .into_iter()
139        .collect();
140
141        assert_eq!(output_edge_list, expected_edge_list);
142        assert_eq!(output_edge_map, expected_edge_map);
143    }
144}