use std::hash::Hash;
use hashbrown::HashMap;
use petgraph::data::Create;
use petgraph::visit::{Data, EdgeCount, EdgeRef, IntoEdges, IntoNodeIdentifiers};
pub fn line_graph<K, G, T, F, H, M>(
input_graph: K,
mut default_node_weight: F,
mut default_edge_weight: H,
) -> (G, HashMap<K::EdgeId, G::NodeId>)
where
K: EdgeCount + IntoNodeIdentifiers + IntoEdges,
G: Create + Data<NodeWeight = T, EdgeWeight = M>,
F: FnMut() -> T,
H: FnMut() -> M,
K::EdgeId: Hash + Eq,
{
let num_edges = input_graph.edge_count();
let mut output_graph = G::with_capacity(num_edges, 0);
let mut output_edge_map =
HashMap::<K::EdgeId, G::NodeId>::with_capacity(input_graph.edge_count());
for edge in input_graph.edge_references() {
let new_node = output_graph.add_node(default_node_weight());
output_edge_map.insert(edge.id(), new_node);
}
for node in input_graph.node_identifiers() {
let edges: Vec<K::EdgeRef> = input_graph.edges(node).collect();
for i in 0..edges.len() {
for j in i + 1..edges.len() {
let node0 = output_edge_map.get(&edges[i].id()).unwrap();
let node1 = output_edge_map.get(&edges[j].id()).unwrap();
output_graph.add_edge(*node0, *node1, default_edge_weight());
}
}
}
(output_graph, output_edge_map)
}
#[cfg(test)]
mod test_line_graph {
use crate::line_graph::line_graph;
use crate::petgraph::visit::EdgeRef;
use crate::petgraph::Graph;
use hashbrown::HashMap;
use petgraph::graph::{EdgeIndex, NodeIndex};
use petgraph::Undirected;
#[test]
fn test_simple_graph() {
let input_graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (2, 3), (3, 4), (4, 5)]);
let (output_graph, output_edge_map): (
petgraph::graph::UnGraph<(), ()>,
HashMap<petgraph::prelude::EdgeIndex, petgraph::prelude::NodeIndex>,
) = line_graph(&input_graph, || (), || ());
let output_edge_list = output_graph
.edge_references()
.map(|edge| (edge.source().index(), edge.target().index()))
.collect::<Vec<(usize, usize)>>();
let expected_edge_list = vec![(2, 1), (3, 2)];
let expected_edge_map: HashMap<EdgeIndex, NodeIndex> = [
(EdgeIndex::new(0), NodeIndex::new(0)),
(EdgeIndex::new(1), NodeIndex::new(1)),
(EdgeIndex::new(2), NodeIndex::new(2)),
(EdgeIndex::new(3), NodeIndex::new(3)),
]
.into_iter()
.collect();
assert_eq!(output_edge_list, expected_edge_list);
assert_eq!(output_edge_map, expected_edge_map);
}
}