#[cfg(feature = "petgraph-integration")]
use petgraph::graph::{Graph, NodeIndex};
#[cfg(feature = "petgraph-integration")]
use petgraph::Directed;
#[cfg(feature = "petgraph-integration")]
use petgraph::Undirected;
use crate::core::VisibilityGraph;
#[cfg(feature = "petgraph-integration")]
impl<T: Copy> VisibilityGraph<T> {
pub fn to_petgraph(&self) -> Graph<usize, f64, petgraph::Undirected> {
let mut pg = Graph::<usize, f64, Undirected>::new_undirected();
let nodes: Vec<NodeIndex> = (0..self.node_count)
.map(|i| pg.add_node(i))
.collect();
for (&(src, dst), &weight) in &self.edges {
if !self.directed || src < dst {
pg.add_edge(nodes[src], nodes[dst], weight);
}
}
pg
}
pub fn to_petgraph_directed(&self) -> Graph<usize, f64, petgraph::Directed> {
let mut pg = Graph::<usize, f64, Directed>::new();
let nodes: Vec<NodeIndex> = (0..self.node_count)
.map(|i| pg.add_node(i))
.collect();
for (&(src, dst), &weight) in &self.edges {
pg.add_edge(nodes[src], nodes[dst], weight);
}
pg
}
}
#[cfg(feature = "petgraph-integration")]
pub mod algorithms {
use super::*;
use petgraph::algo;
use std::collections::HashMap;
impl<T: Copy> VisibilityGraph<T> {
pub fn dijkstra_shortest_paths(&self, start: usize) -> HashMap<usize, f64> {
let pg = self.to_petgraph();
let node_map = algo::dijkstra(&pg, NodeIndex::new(start), None, |e| *e.weight());
node_map.into_iter()
.map(|(node, dist)| (node.index(), dist))
.collect()
}
pub fn minimum_spanning_tree(&self) -> Vec<(usize, usize, f64)> {
let pg = self.to_petgraph();
let mst = algo::min_spanning_tree(&pg);
let mut result = Vec::new();
for item in mst {
match item {
_ => {
}
}
}
let mut all_edges: Vec<_> = self.edges.iter()
.filter(|(&(src, dst), _)| src < dst)
.map(|(&(src, dst), &weight)| (src, dst, weight))
.collect();
all_edges.sort_by(|a, b| a.2.partial_cmp(&b.2).unwrap());
result.extend(all_edges.iter().take(self.node_count.saturating_sub(1)).copied());
result
}
pub fn is_planar(&self) -> bool {
let pg = self.to_petgraph();
algo::is_isomorphic_matching(&pg, &pg, |_, _| true, |_, _| true)
}
pub fn strongly_connected_components(&self) -> Vec<Vec<usize>> {
let pg = self.to_petgraph_directed();
let sccs = algo::tarjan_scc(&pg);
sccs.into_iter()
.map(|scc| scc.into_iter().map(|n| n.index()).collect())
.collect()
}
pub fn topological_sort(&self) -> Option<Vec<usize>> {
let pg = self.to_petgraph_directed();
algo::toposort(&pg, None)
.ok()
.map(|sorted| sorted.into_iter().map(|n| n.index()).collect())
}
}
}
#[cfg(test)]
#[cfg(feature = "petgraph-integration")]
mod tests {
use super::*;
use crate::core::TimeSeries;
#[test]
fn test_to_petgraph() {
let series = TimeSeries::from_raw(vec![1.0, 3.0, 2.0, 4.0]).unwrap();
let graph = VisibilityGraph::from_series(&series)
.natural_visibility()
.unwrap();
let pg = graph.to_petgraph();
assert_eq!(pg.node_count(), 4);
}
#[test]
fn test_dijkstra() {
let series = TimeSeries::from_raw(vec![1.0, 3.0, 2.0, 4.0]).unwrap();
let graph = VisibilityGraph::from_series(&series)
.natural_visibility()
.unwrap();
let distances = graph.dijkstra_shortest_paths(0);
assert!(distances.contains_key(&0));
}
}