#![no_std]
extern crate alloc;
use crate::core::collections::{HashMap, Vector};
use core::cmp::Ordering as CmpOrdering;
use core::fmt::{self, Debug};
use core::hash::Hash;
use core::sync::atomic::{AtomicBool, Ordering};
use alloc::collections::VecDeque;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::ops::Add;
use hashbrown::HashSet;
#[derive(Clone)]
pub struct Edge<T, W> {
pub source: T,
pub target: T,
pub weight: W,
}
impl<T: Debug, W: Debug> Debug for Edge<T, W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Edge")
.field("source", &self.source)
.field("target", &self.target)
.field("weight", &self.weight)
.finish()
}
}
pub struct Graph<T, W>
where
T: Hash + Eq + Clone,
W: Clone,
{
adjacency_list: HashMap<T, Vector<Edge<T, W>>>,
is_directed: bool,
is_locked: AtomicBool,
}
impl<T, W> Debug for Graph<T, W>
where
T: Hash + Eq + Clone + Debug,
W: Clone + Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Graph")
.field("is_directed", &self.is_directed)
.field("is_locked", &self.is_locked)
.finish()
}
}
impl<T, W> Graph<T, W>
where
T: Hash + Eq + Clone,
W: Clone + PartialOrd + Add<Output = W> + Copy,
{
pub fn new(is_directed: bool) -> Self {
Self {
adjacency_list: HashMap::new(),
is_directed,
is_locked: AtomicBool::new(false),
}
}
fn acquire_lock(&self) -> bool {
!self.is_locked.swap(true, Ordering::Acquire)
}
fn release_lock(&self) {
self.is_locked.store(false, Ordering::Release);
}
pub fn add_vertex(&mut self, vertex: T) -> bool {
if !self.acquire_lock() {
return false;
}
let result = if self.adjacency_list.contains_key(&vertex) {
false
} else {
self.adjacency_list.insert(vertex, Vector::new());
true
};
self.release_lock();
result
}
pub fn add_edge(&mut self, source: T, target: T, weight: W) -> bool {
if !self.acquire_lock() {
return false;
}
let result = if !self.adjacency_list.contains_key(&source)
|| !self.adjacency_list.contains_key(&target)
{
false
} else {
let edge = Edge {
source: source.clone(),
target: target.clone(),
weight: weight.clone(),
};
if let Some(edges) = self.adjacency_list.get_mut(&source) {
edges.push(edge);
}
if !self.is_directed {
let reverse_edge = Edge {
source: target,
target: source,
weight,
};
if let Some(edges) = self.adjacency_list.get_mut(&reverse_edge.source) {
edges.push(reverse_edge);
}
}
true
};
self.release_lock();
result
}
pub fn get_neighbors(&self, vertex: &T) -> Option<Vector<Edge<T, W>>> {
if !self.acquire_lock() {
return None;
}
let result = self.adjacency_list.get(vertex).map(|edges| edges.clone());
self.release_lock();
result
}
pub fn remove_vertex(&mut self, vertex: &T) -> bool {
if !self.acquire_lock() {
return false;
}
let result = if !self.adjacency_list.contains_key(vertex) {
false
} else {
let mut keys = Vector::new();
for (k, _) in self.adjacency_list.iter() {
keys.push(k.clone());
}
for key in keys.iter() {
if let Some(edges) = self.adjacency_list.get_mut(key) {
let mut i = 0;
while i < edges.len() {
if &edges[i].target == vertex {
edges.remove(i);
} else {
i += 1;
}
}
}
}
self.adjacency_list.remove(vertex);
true
};
self.release_lock();
result
}
pub fn remove_edge(&mut self, source: &T, target: &T) -> bool {
if !self.acquire_lock() {
return false;
}
let mut result = false;
if let Some(edges) = self.adjacency_list.get_mut(source) {
let initial_len = edges.len();
let mut i = 0;
while i < edges.len() {
if &edges[i].target == target {
edges.remove(i);
} else {
i += 1;
}
}
result = initial_len != edges.len();
if !self.is_directed && result {
if let Some(target_edges) = self.adjacency_list.get_mut(target) {
let mut i = 0;
while i < target_edges.len() {
if &target_edges[i].target == source {
target_edges.remove(i);
} else {
i += 1;
}
}
}
}
}
self.release_lock();
result
}
pub fn vertex_count(&self) -> usize {
if !self.acquire_lock() {
return 0;
}
let count = self.adjacency_list.len();
self.release_lock();
count
}
pub fn edge_count(&self) -> usize {
if !self.acquire_lock() {
return 0;
}
let mut count = 0;
for (_, edges) in self.adjacency_list.iter() {
count += edges.len();
}
self.release_lock();
if self.is_directed { count } else { count / 2 }
}
pub fn dfs<F>(&self, start: &T, mut visitor: F) -> Option<Vec<T>>
where
F: FnMut(&T, &[Edge<T, W>]),
{
if !self.acquire_lock() {
return None;
}
let mut visited = HashSet::new();
let mut stack = Vec::new();
let mut result = Vec::new();
if !self.adjacency_list.contains_key(start) {
self.release_lock();
return None;
}
stack.push(start.clone());
visited.insert(start.clone());
while let Some(vertex) = stack.pop() {
result.push(vertex.clone());
if let Some(edges) = self.adjacency_list.get(&vertex) {
visitor(&vertex, edges);
for edge in edges.iter().rev() {
if !visited.contains(&edge.target) {
stack.push(edge.target.clone());
visited.insert(edge.target.clone());
}
}
}
}
self.release_lock();
Some(result)
}
pub fn bfs<F>(&self, start: &T, mut visitor: F) -> Option<Vec<T>>
where
F: FnMut(&T, &[Edge<T, W>]),
{
if !self.acquire_lock() {
return None;
}
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
let mut result = Vec::new();
if !self.adjacency_list.contains_key(start) {
self.release_lock();
return None;
}
queue.push_back(start.clone());
visited.insert(start.clone());
while let Some(vertex) = queue.pop_front() {
result.push(vertex.clone());
if let Some(edges) = self.adjacency_list.get(&vertex) {
visitor(&vertex, edges);
for edge in edges.iter() {
if !visited.contains(&edge.target) {
queue.push_back(edge.target.clone());
visited.insert(edge.target.clone());
}
}
}
}
self.release_lock();
Some(result)
}
pub fn dfs_recursive<F>(&self, start: &T, mut visitor: F) -> Option<Vec<T>>
where
F: FnMut(&T, &[Edge<T, W>]) + Clone,
{
if !self.acquire_lock() {
return None;
}
let mut visited = HashSet::new();
let mut result = Vec::new();
if !self.adjacency_list.contains_key(start) {
self.release_lock();
return None;
}
self.dfs_recursive_helper(start, &mut visitor, &mut visited, &mut result);
self.release_lock();
Some(result)
}
fn dfs_recursive_helper<F>(
&self,
vertex: &T,
visitor: &mut F,
visited: &mut HashSet<T>,
result: &mut Vec<T>,
) where
F: FnMut(&T, &[Edge<T, W>]) + Clone,
{
visited.insert(vertex.clone());
result.push(vertex.clone());
if let Some(edges) = self.adjacency_list.get(vertex) {
visitor(vertex, edges);
for edge in edges.iter() {
if !visited.contains(&edge.target) {
self.dfs_recursive_helper(&edge.target, visitor, visited, result);
}
}
}
}
pub fn shortest_path(&self, start: &T, end: &T, zero: W) -> (Option<Vec<T>>, Option<W>) {
if !self.acquire_lock() {
return (None, None);
}
if !self.adjacency_list.contains_key(start) || !self.adjacency_list.contains_key(end) {
self.release_lock();
return (None, None);
}
let mut distances: HashMap<T, W> = HashMap::new();
let mut predecessors: HashMap<T, T> = HashMap::new();
let mut unvisited = HashSet::new();
for (vertex, _) in self.adjacency_list.iter() {
unvisited.insert(vertex.clone());
}
distances.insert(start.clone(), zero);
while !unvisited.is_empty() {
let current = unvisited
.iter()
.min_by(|a, b| {
let dist_a = distances.get(*a);
let dist_b = distances.get(*b);
match (dist_a, dist_b) {
(Some(da), Some(db)) => da.partial_cmp(db).unwrap_or(CmpOrdering::Equal),
(Some(_), None) => CmpOrdering::Less,
(None, Some(_)) => CmpOrdering::Greater,
(None, None) => CmpOrdering::Equal,
}
})
.map(|x| x.clone());
if let Some(current_vertex) = current {
if !distances.contains_key(¤t_vertex) {
self.release_lock();
return (None, None);
}
if ¤t_vertex == end {
let mut path = Vec::new();
let mut current = end.clone();
path.push(current.clone());
while let Some(predecessor) = predecessors.get(¤t) {
path.push(predecessor.clone());
current = predecessor.clone();
if ¤t == start {
break;
}
}
path.reverse();
let total_distance = distances.get(end).copied();
self.release_lock();
return (Some(path), total_distance);
}
unvisited.remove(¤t_vertex);
if let Some(edges) = self.adjacency_list.get(¤t_vertex) {
let current_distance = *distances.get(¤t_vertex).unwrap();
for edge in edges {
let new_distance = current_distance + edge.weight;
match distances.get(&edge.target) {
None => {
distances.insert(edge.target.clone(), new_distance);
predecessors.insert(edge.target.clone(), current_vertex.clone());
}
Some(¤t_distance) => {
if new_distance < current_distance {
distances.insert(edge.target.clone(), new_distance);
predecessors
.insert(edge.target.clone(), current_vertex.clone());
}
}
}
}
}
} else {
break;
}
}
self.release_lock();
(None, None) }
pub fn is_connected(&self) -> bool {
if !self.acquire_lock() {
return false;
}
if self.adjacency_list.is_empty() {
self.release_lock();
return true;
}
let start = self.adjacency_list.iter().next().unwrap().0.clone();
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
queue.push_back(start.clone());
visited.insert(start);
while let Some(vertex) = queue.pop_front() {
if let Some(edges) = self.adjacency_list.get(&vertex) {
for edge in edges {
if !visited.contains(&edge.target) {
visited.insert(edge.target.clone());
queue.push_back(edge.target.clone());
}
}
}
}
let is_connected = visited.len() == self.adjacency_list.len();
self.release_lock();
is_connected
}
pub fn is_strongly_connected(&self) -> bool {
if !self.acquire_lock() {
return false;
}
if !self.is_directed {
self.release_lock();
return self.is_connected();
}
if self.adjacency_list.is_empty() {
self.release_lock();
return true;
}
for (start, _) in self.adjacency_list.iter() {
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
queue.push_back(start.clone());
visited.insert(start.clone());
while let Some(vertex) = queue.pop_front() {
if let Some(edges) = self.adjacency_list.get(&vertex) {
for edge in edges {
if !visited.contains(&edge.target) {
visited.insert(edge.target.clone());
queue.push_back(edge.target.clone());
}
}
}
}
if visited.len() != self.adjacency_list.len() {
self.release_lock();
return false;
}
}
self.release_lock();
true
}
pub fn has_cycle(&self) -> bool {
if !self.acquire_lock() {
return false;
}
if self.is_directed {
let result = self.has_directed_cycle();
self.release_lock();
return result;
}
if self.adjacency_list.is_empty() {
self.release_lock();
return false;
}
let mut visited = HashSet::new();
let mut parent: HashMap<T, T> = HashMap::new();
for start in self.adjacency_list.iter().map(|(k, _)| k) {
if !visited.contains(start) {
if self.has_cycle_dfs(start, &mut visited, &mut parent) {
self.release_lock();
return true;
}
}
}
self.release_lock();
false
}
fn has_cycle_dfs(
&self,
vertex: &T,
visited: &mut HashSet<T>,
parent: &mut HashMap<T, T>,
) -> bool {
visited.insert(vertex.clone());
if let Some(edges) = self.adjacency_list.get(vertex) {
for edge in edges {
let neighbor = &edge.target;
if vertex == neighbor {
return true;
}
if !visited.contains(neighbor) {
parent.insert(neighbor.clone(), vertex.clone());
if self.has_cycle_dfs(neighbor, visited, parent) {
return true;
}
} else if let Some(p) = parent.get(vertex) {
if neighbor != p {
return true;
}
}
}
}
false
}
pub fn has_directed_cycle(&self) -> bool {
if !self.is_directed {
return self.has_cycle();
}
if self.adjacency_list.is_empty() {
return false;
}
let mut visited = HashSet::new(); let mut on_path = HashSet::new();
for start in self.adjacency_list.iter().map(|(k, _)| k) {
if !visited.contains(start) && !on_path.contains(start) {
if self.has_directed_cycle_dfs(start, &mut visited, &mut on_path) {
return true;
}
}
}
false
}
fn has_directed_cycle_dfs(
&self,
vertex: &T,
visited: &mut HashSet<T>,
on_path: &mut HashSet<T>,
) -> bool {
on_path.insert(vertex.clone());
if let Some(edges) = self.adjacency_list.get(vertex) {
for edge in edges {
let neighbor = &edge.target;
if on_path.contains(neighbor) {
return true;
}
if !visited.contains(neighbor) && !on_path.contains(neighbor) {
if self.has_directed_cycle_dfs(neighbor, visited, on_path) {
return true;
}
}
}
}
on_path.remove(vertex);
visited.insert(vertex.clone());
false
}
pub fn topological_sort(&self) -> Option<Vec<T>> {
if !self.acquire_lock() {
return None;
}
if !self.is_directed {
self.release_lock();
return None;
}
let mut in_degree: HashMap<T, usize> = HashMap::new();
for vertex in self.adjacency_list.iter().map(|(k, _)| k) {
in_degree.insert(vertex.clone(), 0);
}
for (_, edges) in self.adjacency_list.iter() {
for edge in edges {
if let Some(count) = in_degree.get_mut(&edge.target) {
*count += 1;
}
}
}
let mut queue = VecDeque::new();
for (vertex, °ree) in in_degree.iter() {
if degree == 0 {
queue.push_back(vertex.clone());
}
}
let mut result = Vec::new();
while let Some(vertex) = queue.pop_front() {
result.push(vertex.clone());
if let Some(edges) = self.adjacency_list.get(&vertex) {
for edge in edges {
if let Some(count) = in_degree.get_mut(&edge.target) {
*count -= 1;
if *count == 0 {
queue.push_back(edge.target.clone());
}
}
}
}
}
let success = result.len() == self.adjacency_list.len();
self.release_lock();
if success { Some(result) } else { None }
}
}
impl<T: Hash + Eq + Clone, W: Clone> Clone for Graph<T, W>
where
T: Hash + Eq + Clone,
W: Clone,
{
fn clone(&self) -> Self {
Self {
adjacency_list: self.adjacency_list.clone(),
is_directed: self.is_directed,
is_locked: AtomicBool::new(false),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::String;
use alloc::vec;
use core::cell::RefCell;
#[test]
fn test_graph_creation() {
let mut graph: Graph<i32, f64> = Graph::new(false);
assert_eq!(graph.vertex_count(), 0);
assert_eq!(graph.edge_count(), 0);
}
#[test]
fn test_add_vertex() {
let mut graph: Graph<i32, f64> = Graph::new(false);
assert!(graph.add_vertex(1));
assert!(!graph.add_vertex(1));
assert_eq!(graph.vertex_count(), 1);
}
#[test]
fn test_add_edge() {
let mut graph: Graph<i32, f64> = Graph::new(false);
graph.add_vertex(1);
graph.add_vertex(2);
assert!(graph.add_edge(1, 2, 1.0));
assert_eq!(graph.edge_count(), 1);
}
#[test]
fn test_remove_vertex() {
let mut graph: Graph<i32, f64> = Graph::new(false);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_edge(1, 2, 1.0);
assert!(graph.remove_vertex(&1));
assert_eq!(graph.vertex_count(), 1);
assert_eq!(graph.edge_count(), 0);
}
#[test]
fn test_remove_edge() {
let mut graph: Graph<i32, f64> = Graph::new(false);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_edge(1, 2, 1.0);
assert!(graph.remove_edge(&1, &2));
assert_eq!(graph.edge_count(), 0);
}
#[test]
fn test_dfs() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_vertex(4);
graph.add_edge(1, 2, 1.0);
graph.add_edge(1, 3, 1.0);
graph.add_edge(2, 4, 1.0);
graph.add_edge(3, 4, 1.0);
let mut visited_order = Vec::new();
let result = graph.dfs(&1, |&node, _| {
visited_order.push(node);
});
assert!(result.is_some());
let path = result.unwrap();
assert_eq!(path.len(), 4);
assert_eq!(visited_order.len(), 4);
assert_eq!(visited_order[0], 1);
assert!(visited_order.contains(&2));
assert!(visited_order.contains(&3));
assert!(visited_order.contains(&4));
}
#[test]
fn test_bfs() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_vertex(4);
graph.add_edge(1, 2, 1.0);
graph.add_edge(1, 3, 1.0);
graph.add_edge(2, 4, 1.0);
graph.add_edge(3, 4, 1.0);
let mut visited_order = Vec::new();
let result = graph.bfs(&1, |&node, _| {
visited_order.push(node);
});
assert!(result.is_some());
let path = result.unwrap();
assert_eq!(path.len(), 4);
assert_eq!(visited_order.len(), 4);
assert_eq!(visited_order[0], 1);
assert!(visited_order[1] == 2 || visited_order[1] == 3);
assert!(visited_order[2] == 2 || visited_order[2] == 3);
assert_eq!(visited_order[3], 4);
}
#[test]
fn test_dfs_recursive() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_vertex(4);
graph.add_edge(1, 2, 1.0);
graph.add_edge(1, 3, 1.0);
graph.add_edge(2, 4, 1.0);
graph.add_edge(3, 4, 1.0);
let visited_order = RefCell::new(Vec::new());
let result = graph.dfs_recursive(&1, |node, _| {
visited_order.borrow_mut().push(*node);
});
assert!(result.is_some());
let path = result.unwrap();
assert_eq!(path.len(), 4);
let visited = visited_order.into_inner();
assert_eq!(visited.len(), 4);
assert_eq!(visited[0], 1);
assert!(visited.contains(&2));
assert!(visited.contains(&3));
assert!(visited.contains(&4));
}
#[test]
fn test_graph_traversal_with_cycles() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(1, 2, 1.0);
graph.add_edge(2, 3, 1.0);
graph.add_edge(3, 1, 1.0);
let dfs_result = graph.dfs(&1, |_, _| {});
assert!(dfs_result.is_some());
let dfs_path = dfs_result.unwrap();
assert_eq!(dfs_path.len(), 3);
let bfs_result = graph.bfs(&1, |_, _| {});
assert!(bfs_result.is_some());
let bfs_path = bfs_result.unwrap();
assert_eq!(bfs_path.len(), 3);
}
#[test]
fn test_disconnected_graph() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_vertex(4);
graph.add_edge(1, 2, 1.0);
graph.add_edge(3, 4, 1.0);
let dfs_result = graph.dfs(&1, |_, _| {});
assert!(dfs_result.is_some());
let dfs_path = dfs_result.unwrap();
assert_eq!(dfs_path.len(), 2);
let bfs_result = graph.bfs(&1, |_, _| {});
assert!(bfs_result.is_some());
let bfs_path = bfs_result.unwrap();
assert_eq!(bfs_path.len(), 2); }
#[test]
fn test_shortest_path() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_vertex(4);
graph.add_edge(1, 2, 4.0);
graph.add_edge(1, 3, 2.0);
graph.add_edge(3, 2, 1.0);
graph.add_edge(2, 4, 3.0);
graph.add_edge(3, 4, 5.0);
let (path, distance) = graph.shortest_path(&1, &4, 0.0);
assert!(path.is_some());
assert!(distance.is_some());
let path = path.unwrap();
let distance = distance.unwrap();
assert_eq!(path, vec![1, 3, 2, 4]);
assert_eq!(distance, 6.0); }
#[test]
fn test_shortest_path_no_path() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(1, 2, 1.0);
let (path, distance) = graph.shortest_path(&1, &3, 0.0);
assert!(path.is_none());
assert!(distance.is_none());
}
#[test]
fn test_shortest_path_with_cycles() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(1, 2, 1.0);
graph.add_edge(2, 3, 2.0);
graph.add_edge(3, 1, 4.0); graph.add_edge(1, 3, 5.0);
let (path, distance) = graph.shortest_path(&1, &3, 0.0);
assert!(path.is_some());
assert!(distance.is_some());
let path = path.unwrap();
let distance = distance.unwrap();
assert_eq!(path, vec![1, 2, 3]); assert_eq!(distance, 3.0); }
#[test]
fn test_is_connected() {
let mut graph = Graph::new(false);
assert!(graph.is_connected());
graph.add_vertex(1);
assert!(graph.is_connected());
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(1, 2, 1.0);
graph.add_edge(2, 3, 1.0);
assert!(graph.is_connected());
graph.add_vertex(4);
assert!(!graph.is_connected());
graph.add_edge(3, 4, 1.0);
assert!(graph.is_connected());
}
#[test]
fn test_is_strongly_connected() {
let mut graph = Graph::new(true);
assert!(graph.is_strongly_connected());
graph.add_vertex(1);
assert!(graph.is_strongly_connected());
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(1, 2, 1.0);
graph.add_edge(2, 3, 1.0);
assert!(!graph.is_strongly_connected());
graph.add_edge(3, 1, 1.0);
assert!(graph.is_strongly_connected());
graph.add_vertex(4);
assert!(!graph.is_strongly_connected());
graph.add_edge(3, 4, 1.0);
graph.add_edge(4, 1, 1.0);
assert!(graph.is_strongly_connected());
}
#[test]
fn test_has_cycle_undirected() {
let mut graph = Graph::new(false);
assert!(!graph.has_cycle());
graph.add_vertex(1);
assert!(!graph.has_cycle());
graph.add_vertex(2);
graph.add_edge(1, 2, 1.0);
assert!(!graph.has_cycle());
graph.add_vertex(3);
graph.add_edge(2, 3, 1.0);
graph.add_edge(3, 1, 1.0);
assert!(graph.has_cycle());
}
#[test]
fn test_has_directed_cycle() {
let mut graph = Graph::new(true);
assert!(!graph.has_directed_cycle());
graph.add_vertex(1);
assert!(!graph.has_directed_cycle());
graph.add_vertex(2);
graph.add_edge(1, 2, 1.0);
assert!(!graph.has_directed_cycle());
graph.add_edge(2, 1, 1.0);
assert!(graph.has_directed_cycle());
graph.add_vertex(3);
graph.add_vertex(4);
graph.add_edge(2, 3, 1.0);
graph.add_edge(3, 4, 1.0);
graph.add_edge(4, 2, 1.0);
assert!(graph.has_directed_cycle());
}
#[test]
fn test_cycle_with_self_loop() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_edge(1, 1, 1.0); assert!(graph.has_directed_cycle());
let mut undirected = Graph::new(false);
undirected.add_vertex(1);
undirected.add_edge(1, 1, 1.0); assert!(undirected.has_cycle());
}
#[test]
fn test_topological_sort() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_vertex(4);
graph.add_edge(1, 2, 1.0);
graph.add_edge(1, 3, 1.0);
graph.add_edge(2, 4, 1.0);
graph.add_edge(3, 4, 1.0);
let result = graph.topological_sort();
assert!(result.is_some());
let order = result.unwrap();
assert_eq!(order.len(), 4);
assert_eq!(order[0], 1); assert_eq!(order[3], 4); assert!((order[1] == 2 && order[2] == 3) || (order[1] == 3 && order[2] == 2));
}
#[test]
fn test_topological_sort_with_cycle() {
let mut graph = Graph::new(true);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(1, 2, 1.0);
graph.add_edge(2, 3, 1.0);
graph.add_edge(3, 1, 1.0);
let result = graph.topological_sort();
assert!(result.is_none()); }
#[test]
fn test_topological_sort_empty_and_single() {
let mut graph = Graph::<i32, i32>::new(true);
let result = graph.topological_sort();
assert_eq!(result.unwrap(), vec![]);
graph.add_vertex(1);
let result = graph.topological_sort();
assert_eq!(result.unwrap(), vec![1]);
}
#[test]
fn test_topological_sort_undirected() {
let mut graph = Graph::new(false);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_edge(1, 2, 1.0);
let result = graph.topological_sort();
assert!(result.is_none()); }
}