use std::{fmt::{Display, Debug}, rc::Rc, cell::RefCell, collections::HashMap, hash::Hash};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
mod graph;
pub mod algorithms;
#[cfg(feature = "from_instruction")]
pub mod instruction;
#[derive(Clone, Eq, Debug)]
struct Node<T: Display + Eq> {
id: T,
edges: Vec<Edge<T>>,
distance: i32,
shortest_path: Vec<Rc<RefCell<Node<T>>>>,
}
#[derive(Clone, Eq, Ord, PartialOrd, Debug)]
struct Edge<T: Display + Eq> {
weight: i32,
parent: Rc<RefCell<Node<T>>>,
target: Rc<RefCell<Node<T>>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Graph<T: Display + Eq + Hash> {
nodes: HashMap<T, Rc<RefCell<Node<T>>>>,
}
impl<T: Display + Eq + Hash + Clone> PartialOrd for Graph<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.size().partial_cmp(&other.size())
}
}
impl<T: Display + Eq + Hash + Clone> Ord for Graph<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.size().cmp(&other.size())
}
}
impl<T: Display + Eq + Hash> Graph<T> {
fn reset_nodes(&mut self) {
for (_, node) in self.nodes.iter_mut() {
node.borrow_mut().distance = i32::MAX;
node.borrow_mut().shortest_path = Vec::new();
}
}
}
#[derive(Eq, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ShortestPathTree<T: Display + Clone + Hash + Eq> {
source: T,
results: HashMap<T, Option<(i32, ShortestPath<T>)>>,
}
impl<T: Display + Clone + Eq + Hash> ShortestPathTree<T> {
fn new(source: T) -> Self {
Self {
source,
results: HashMap::new(),
}
}
#[allow(clippy::unnecessary_unwrap)]
fn add_result(&mut self, node_id: T, distance: Option<i32>, shortest_path: Option<ShortestPath<T>>) {
if shortest_path.is_none() | distance.is_none() {
self.results.insert(node_id, None);
} else {
self.results.insert(node_id, Some((distance.unwrap(), shortest_path.unwrap())));
}
}
pub fn shortest_path(&self, target_id: &T) -> Option<&ShortestPath<T>> {
match self.results.get(target_id)? {
Some(res) => Some(&res.1),
None => None
}
}
pub fn shortest_distance(&self, target_id: &T) -> Option<i32> {
self.results.get(target_id)?.as_ref().map(|res| res.0)
}
fn from_graph(graph: &Graph<T>, source_id: &T) -> Self {
let mut spt = ShortestPathTree::new(source_id.clone());
for (id, node) in &graph.nodes {
if let Ok(path) = ShortestPath::try_from(node) {
spt.add_result(id.clone(), Some(node.borrow().distance), Some(path));
} else {
spt.add_result(id.clone(), None, None);
}
}
spt
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ShortestPath<T: Display + Clone> { path: Vec<T>, }
impl<T: Display + Clone> ShortestPath<T> {
fn new(path: Vec<T>) -> Self {
Self {
path,
}
}
pub fn source(&self) -> Option<&T> {
self.path.first()
}
pub fn target(&self) -> Option<&T> {
self.path.last()
}
pub fn path(&self) -> &Vec<T> {
&self.path
}
}
impl<T: Display + Clone + Debug> Display for ShortestPath<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (i, node_id) in self.path.iter().enumerate() {
if i == self.path.len()-1 {
write!(f, "{}", node_id)?;
} else {
write!(f, "{} -> ", node_id)?;
}
}
Ok(())
}
}
#[doc(hidden)]
impl<T: Display + Clone + Eq> TryFrom<&Rc<RefCell<Node<T>>>> for ShortestPath<T> {
type Error = &'static str;
fn try_from(value: &Rc<RefCell<Node<T>>>) -> Result<ShortestPath<T>, &'static str> {
if value.borrow().distance == 0 {
return Ok(ShortestPath::new(vec![value.borrow().id.clone()]));
} else if value.borrow().distance == i32::MAX || value.borrow().shortest_path.is_empty() {
return Err("Unable to create shortest path from vector, vector is empty!");
}
let mut path = Vec::new();
for node in &value.borrow().shortest_path {
path.push(node.borrow().id.clone());
}
path.push(value.borrow().id.clone());
Ok(ShortestPath::new(path))
}
}
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AddEdgeError {
SourceMissing,
TargetMissing,
BothMissing,
}
impl ToString for AddEdgeError {
fn to_string(&self) -> String {
match self {
AddEdgeError::SourceMissing => String::from("SourceMissing"),
AddEdgeError::TargetMissing => String::from("TargetMissing"),
AddEdgeError::BothMissing => String::from("BothMissing"),
}
}
}
#[cfg(test)]
fn graph_1() -> Graph<&'static str> {
let mut graph = Graph::new();
graph.add_node("Berlin");
graph.add_node("New York");
graph.add_node("Brussels");
graph.add_node("Copenhagen");
graph.add_node("Oslo");
graph.add_node("London");
graph.add_edge(5, &"Berlin", &"New York");
graph.add_edge(6, &"Berlin", &"Brussels");
graph.add_edge(2, &"New York", &"Berlin");
graph.add_edge(9, &"New York", &"Copenhagen");
graph.add_edge(7, &"Brussels", &"Berlin");
graph.add_edge(2, &"Brussels", &"Copenhagen");
graph.add_edge(5, &"Copenhagen", &"Brussels");
graph.add_edge(1, &"Copenhagen", &"New York");
graph.add_double_edge(10, &"Copenhagen", &"Oslo");
graph
}
#[cfg(test)]
fn graph_2() -> Graph<char> {
let mut graph: Graph<char> = Graph::new();
graph.add_node('a');
graph.add_node('b');
graph.add_node('c');
graph.add_node('d');
graph.add_node('e');
graph.add_edge(3, &'a', &'b');
graph.add_edge(4, &'a', &'c');
graph.add_edge(5, &'b', &'a');
graph.add_edge(2, &'b', &'d');
graph.add_edge(9, &'c', &'a');
graph.add_edge(1, &'c', &'d');
graph.add_edge(3, &'d', &'b');
graph.add_edge(7, &'d', &'c');
graph
}
#[cfg(test)]
mod tests {
mod shortest_path_tree {
use crate::{graph_2, algorithms::dijkstra, ShortestPath, graph, ShortestPathTree};
#[test]
fn add_result_test() {
let mut spt = ShortestPathTree::new('a');
let test_path = ShortestPath::new(vec!['a', 'd', 'c']);
spt.add_result('b', Some(5), Some(test_path.clone()));
let path = spt.shortest_path(&'b');
let distance = spt.shortest_distance(&'b');
assert!(path.is_some());
assert_eq!(path.unwrap(), &test_path);
assert_eq!(distance, Some(5));
}
#[test]
fn shortest_path_test() {
let mut graph = graph_2();
let spt = dijkstra(&mut graph, &'a');
assert!(spt.is_ok());
let should_path = vec!['a', 'b', 'd'];
let sp = ShortestPath::new(should_path);
assert_eq!(spt.as_ref().unwrap().shortest_path(&'d'), Some(&sp));
let should_path = vec!['a'];
let sp = ShortestPath::new(should_path);
assert_eq!(spt.unwrap().shortest_path(&'a'), Some(&sp));
let spt = dijkstra(&mut graph, &'d');
let should_path = vec!['d', 'b', 'a'];
let sp = ShortestPath::new(should_path);
assert_eq!(spt.unwrap().shortest_path(&'a'), Some(&sp));
}
#[test]
fn shortest_distance_test() {
let mut graph = graph_2();
let spt = dijkstra(&mut graph, &'c');
assert!(spt.is_ok());
let spt = spt.unwrap();
assert_eq!(spt.shortest_distance(&'b'), Some(4));
assert_eq!(spt.shortest_distance(&'a'), Some(9));
}
#[test]
fn from_graph_test() {
let mut graph = graph_2();
assert!(dijkstra(&mut graph, &'a').is_ok());
let spt = ShortestPathTree::from_graph(&graph, &'a');
assert_eq!(spt.source, 'a');
assert_eq!(spt.results[&'a'], Some((0, ShortestPath::new(vec!['a']))));
}
}
mod shortest_path {
use crate::{graph_2, algorithms::dijkstra, ShortestPath};
#[test]
fn source_test() {
let mut graph = graph_2();
let spt = dijkstra(&mut graph, &'a').unwrap();
assert_eq!(spt.shortest_path(&'a').unwrap().source(), Some(&'a'));
assert_eq!(spt.shortest_path(&'d').unwrap().source(), Some(&'a'));
let spt = dijkstra(&mut graph, &'d').unwrap();
assert_eq!(spt.shortest_path(&'a').unwrap().source(), Some(&'d'));
assert_eq!(spt.shortest_path(&'d').unwrap().source(), Some(&'d'));
}
#[test]
fn target_test() {
let mut graph = graph_2();
let spt = dijkstra(&mut graph, &'a').unwrap();
assert_eq!(spt.shortest_path(&'a').unwrap().target(), Some(&'a'));
assert_eq!(spt.shortest_path(&'b').unwrap().target(), Some(&'b'));
assert_eq!(spt.shortest_path(&'c').unwrap().target(), Some(&'c'));
assert_eq!(spt.shortest_path(&'d').unwrap().target(), Some(&'d'));
}
#[test]
fn path() {
let mut graph = graph_2();
let spt = dijkstra(&mut graph, &'a').unwrap();
assert_eq!(spt.shortest_path(&'a').unwrap().path(), &vec!['a']);
assert_eq!(spt.shortest_path(&'b').unwrap().path(), &vec!['a', 'b']);
assert_eq!(spt.shortest_path(&'c').unwrap().path(), &vec!['a', 'c']);
assert_eq!(spt.shortest_path(&'d').unwrap().path(), &vec!['a', 'b', 'd']);
}
#[test]
fn display() {
let mut graph = graph_2();
let spt = dijkstra(&mut graph, &'a').unwrap();
assert_eq!(spt.shortest_path(&'a').unwrap().to_string(), "a");
assert_eq!(spt.shortest_path(&'b').unwrap().to_string(), "a -> b");
assert_eq!(spt.shortest_path(&'c').unwrap().to_string(), "a -> c");
assert_eq!(spt.shortest_path(&'d').unwrap().to_string(), "a -> b -> d");
}
#[test]
fn try_from_rc_ref_cell_node() {
let mut graph = graph_2();
dijkstra(&mut graph, &'a').unwrap();
let node = graph.nodes[&'d'].clone();
let shortest_path = ShortestPath::try_from(&node);
assert!(shortest_path.is_ok());
let shortest_path = shortest_path.unwrap();
assert_eq!(shortest_path.source(), Some(&'a'));
assert_eq!(shortest_path.target(), Some(&'d'));
assert_eq!(shortest_path.path(), &vec!['a', 'b', 'd']);
assert_eq!(shortest_path.to_string(), "a -> b -> d");
}
}
}