use crate::base::{DiGraph, EdgeWeight, Graph, IndexType, Node};
use std::collections::HashSet;
#[allow(dead_code)]
pub fn line_graph<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Graph<(N, N), (), Ix>
where
N: Node + Clone + std::fmt::Debug,
E: EdgeWeight + Clone,
Ix: IndexType,
{
let mut line_graph = Graph::new();
let edges = graph.edges();
let edge_nodes: Vec<(N, N)> = edges
.iter()
.map(|e| (e.source.clone(), e.target.clone()))
.collect();
for edge_node in &edge_nodes {
line_graph.add_node(edge_node.clone());
}
for (i, edge1) in edge_nodes.iter().enumerate() {
for (_j, edge2) in edge_nodes.iter().enumerate().skip(i + 1) {
if edge1.0 == edge2.0 || edge1.0 == edge2.1 || edge1.1 == edge2.0 || edge1.1 == edge2.1
{
let _ = line_graph.add_edge(edge1.clone(), edge2.clone(), ());
}
}
}
line_graph
}
#[allow(dead_code)]
pub fn line_digraph<N, E, Ix>(digraph: &DiGraph<N, E, Ix>) -> DiGraph<(N, N), (), Ix>
where
N: Node + Clone + std::fmt::Debug,
E: EdgeWeight + Clone,
Ix: IndexType,
{
let mut line_digraph = DiGraph::new();
let edges = digraph.edges();
let edge_nodes: Vec<(N, N)> = edges
.iter()
.map(|e| (e.source.clone(), e.target.clone()))
.collect();
for edge_node in &edge_nodes {
line_digraph.add_node(edge_node.clone());
}
for edge1 in &edge_nodes {
for edge2 in &edge_nodes {
if edge1 != edge2 && edge1.1 == edge2.0 {
let _ = line_digraph.add_edge(edge1.clone(), edge2.clone(), ());
}
}
}
line_digraph
}
#[allow(dead_code)]
pub fn subgraph<N, E, Ix>(graph: &Graph<N, E, Ix>, nodes: &HashSet<N>) -> Graph<N, E, Ix>
where
N: Node + Clone + std::fmt::Debug,
E: EdgeWeight + Clone,
Ix: IndexType,
{
let mut sub = Graph::new();
for node in nodes {
if graph.has_node(node) {
sub.add_node(node.clone());
}
}
for edge in graph.edges() {
if nodes.contains(&edge.source) && nodes.contains(&edge.target) {
let _ = sub.add_edge(
edge.source.clone(),
edge.target.clone(),
edge.weight.clone(),
);
}
}
sub
}
#[allow(dead_code)]
pub fn subdigraph<N, E, Ix>(digraph: &DiGraph<N, E, Ix>, nodes: &HashSet<N>) -> DiGraph<N, E, Ix>
where
N: Node + Clone + std::fmt::Debug,
E: EdgeWeight + Clone,
Ix: IndexType,
{
let mut sub = DiGraph::new();
for node in nodes {
if digraph.has_node(node) {
sub.add_node(node.clone());
}
}
for edge in digraph.edges() {
if nodes.contains(&edge.source) && nodes.contains(&edge.target) {
let _ = sub.add_edge(
edge.source.clone(),
edge.target.clone(),
edge.weight.clone(),
);
}
}
sub
}
#[allow(dead_code)]
pub fn edge_subgraph<N, E, Ix>(graph: &Graph<N, E, Ix>, edges: &[(N, N)]) -> Graph<N, E, Ix>
where
N: Node + Clone + std::fmt::Debug,
E: EdgeWeight + Clone,
Ix: IndexType,
{
let mut sub = Graph::new();
let mut included_nodes = HashSet::new();
for (u, v) in edges {
included_nodes.insert(u.clone());
included_nodes.insert(v.clone());
}
for node in &included_nodes {
if graph.has_node(node) {
sub.add_node(node.clone());
}
}
for (u, v) in edges {
if graph.has_edge(u, v) {
if let Ok(weight) = graph.edge_weight(u, v) {
let _ = sub.add_edge(u.clone(), v.clone(), weight);
}
}
}
sub
}
#[allow(dead_code)]
pub fn cartesian_product<N1, N2, E1, E2, Ix>(
graph1: &Graph<N1, E1, Ix>,
graph2: &Graph<N2, E2, Ix>,
) -> Graph<(N1, N2), (), Ix>
where
N1: Node + Clone + std::fmt::Debug,
N2: Node + Clone + std::fmt::Debug,
E1: EdgeWeight,
E2: EdgeWeight,
Ix: IndexType,
{
let mut product = Graph::new();
let nodes1: Vec<N1> = graph1.nodes().into_iter().cloned().collect();
let nodes2: Vec<N2> = graph2.nodes().into_iter().cloned().collect();
for n1 in &nodes1 {
for n2 in &nodes2 {
product.add_node((n1.clone(), n2.clone()));
}
}
for n1 in &nodes1 {
for n2 in &nodes2 {
if let Ok(neighbors2) = graph2.neighbors(n2) {
for m2 in neighbors2 {
if n2 != &m2 {
let _ = product.add_edge((n1.clone(), n2.clone()), (n1.clone(), m2), ());
}
}
}
if let Ok(neighbors1) = graph1.neighbors(n1) {
for m1 in neighbors1 {
if n1 != &m1 {
let _ = product.add_edge((n1.clone(), n2.clone()), (m1, n2.clone()), ());
}
}
}
}
}
product
}
#[allow(dead_code)]
pub fn tensor_product<N1, N2, E1, E2, Ix>(
graph1: &Graph<N1, E1, Ix>,
graph2: &Graph<N2, E2, Ix>,
) -> Graph<(N1, N2), (), Ix>
where
N1: Node + Clone + std::fmt::Debug,
N2: Node + Clone + std::fmt::Debug,
E1: EdgeWeight,
E2: EdgeWeight,
Ix: IndexType,
{
let mut product = Graph::new();
let nodes1: Vec<N1> = graph1.nodes().into_iter().cloned().collect();
let nodes2: Vec<N2> = graph2.nodes().into_iter().cloned().collect();
for n1 in &nodes1 {
for n2 in &nodes2 {
product.add_node((n1.clone(), n2.clone()));
}
}
for n1 in &nodes1 {
for n2 in &nodes2 {
if let Ok(neighbors1) = graph1.neighbors(n1) {
if let Ok(neighbors2) = graph2.neighbors(n2) {
for m1 in neighbors1 {
for m2 in &neighbors2 {
if n1 != &m1 && n2 != m2 {
let _ = product.add_edge(
(n1.clone(), n2.clone()),
(m1.clone(), m2.clone()),
(),
);
}
}
}
}
}
}
}
product
}
#[allow(dead_code)]
pub fn complement<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Graph<N, (), Ix>
where
N: Node + Clone + std::fmt::Debug,
E: EdgeWeight,
Ix: IndexType,
{
let mut comp = Graph::new();
let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
for node in &nodes {
comp.add_node(node.clone());
}
for (i, u) in nodes.iter().enumerate() {
for v in nodes.iter().skip(i + 1) {
if !graph.has_edge(u, v) {
let _ = comp.add_edge(u.clone(), v.clone(), ());
}
}
}
comp
}
#[allow(dead_code)]
pub fn weight_filtered_subgraph<N, E, Ix>(
graph: &Graph<N, E, Ix>,
valid_weights: &HashSet<E>,
) -> Graph<N, E, Ix>
where
N: Node + Clone + std::fmt::Debug,
E: EdgeWeight + Clone + std::hash::Hash + Eq,
Ix: IndexType,
{
let mut filtered = Graph::new();
for node in graph.nodes() {
filtered.add_node(node.clone());
}
for edge in graph.edges() {
if valid_weights.contains(&edge.weight) {
let _ = filtered.add_edge(
edge.source.clone(),
edge.target.clone(),
edge.weight.clone(),
);
}
}
filtered
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generators::create_graph;
#[test]
fn test_line_graph() {
let mut graph = create_graph::<&str, ()>();
graph.add_edge("A", "B", ()).expect("Operation failed");
graph.add_edge("B", "C", ()).expect("Operation failed");
graph.add_edge("C", "A", ()).expect("Operation failed");
let line = line_graph(&graph);
assert_eq!(line.node_count(), 3);
assert_eq!(line.edge_count(), 3);
}
#[test]
fn test_subgraph() {
let mut graph = create_graph::<i32, ()>();
graph.add_edge(1, 2, ()).expect("Operation failed");
graph.add_edge(2, 3, ()).expect("Operation failed");
graph.add_edge(3, 4, ()).expect("Operation failed");
graph.add_edge(1, 4, ()).expect("Operation failed");
let mut nodes = HashSet::new();
nodes.insert(1);
nodes.insert(2);
nodes.insert(3);
let sub = subgraph(&graph, &nodes);
assert_eq!(sub.node_count(), 3);
assert_eq!(sub.edge_count(), 2);
assert!(sub.has_edge(&1, &2));
assert!(sub.has_edge(&2, &3));
assert!(!sub.has_edge(&3, &4)); }
#[test]
fn test_edge_subgraph() {
let mut graph = create_graph::<i32, ()>();
graph.add_edge(1, 2, ()).expect("Operation failed");
graph.add_edge(2, 3, ()).expect("Operation failed");
graph.add_edge(3, 4, ()).expect("Operation failed");
graph.add_edge(1, 4, ()).expect("Operation failed");
let edges = vec![(1, 2), (3, 4)];
let sub = edge_subgraph(&graph, &edges);
assert_eq!(sub.node_count(), 4);
assert_eq!(sub.edge_count(), 2);
assert!(sub.has_edge(&1, &2));
assert!(sub.has_edge(&3, &4));
assert!(!sub.has_edge(&2, &3));
assert!(!sub.has_edge(&1, &4));
}
#[test]
fn test_cartesian_product() {
let mut k2 = create_graph::<i32, ()>();
k2.add_edge(1, 2, ()).expect("Operation failed");
let mut p2 = create_graph::<char, ()>();
p2.add_edge('A', 'B', ()).expect("Operation failed");
let product = cartesian_product(&k2, &p2);
assert_eq!(product.node_count(), 4);
assert_eq!(product.edge_count(), 8);
}
#[test]
fn test_tensor_product() {
let mut k2_1 = create_graph::<i32, ()>();
k2_1.add_edge(1, 2, ()).expect("Operation failed");
let mut k2_2 = create_graph::<char, ()>();
k2_2.add_edge('A', 'B', ()).expect("Operation failed");
let product = tensor_product(&k2_1, &k2_2);
assert_eq!(product.node_count(), 4);
assert_eq!(product.edge_count(), 4);
}
#[test]
fn test_complement() {
let mut graph = create_graph::<i32, ()>();
graph.add_edge(1, 2, ()).expect("Operation failed");
graph.add_edge(2, 3, ()).expect("Operation failed");
let comp = complement(&graph);
assert_eq!(comp.node_count(), 3);
assert_eq!(comp.edge_count(), 1);
assert!(comp.has_edge(&1, &3));
assert!(!comp.has_edge(&1, &2));
assert!(!comp.has_edge(&2, &3));
}
#[test]
fn test_weight_filtered_subgraph() {
let mut graph = create_graph::<i32, i32>();
graph.add_edge(1, 2, 10).expect("Operation failed");
graph.add_edge(2, 3, 20).expect("Operation failed");
graph.add_edge(3, 4, 10).expect("Operation failed");
let mut valid_weights = HashSet::new();
valid_weights.insert(10);
let filtered = weight_filtered_subgraph(&graph, &valid_weights);
assert_eq!(filtered.node_count(), 4);
assert_eq!(filtered.edge_count(), 2);
assert!(filtered.has_edge(&1, &2));
assert!(filtered.has_edge(&3, &4));
assert!(!filtered.has_edge(&2, &3)); }
}