use alloc::{vec, vec::Vec};
use oxgraph_topology::{ElementIndex, ElementSuccessors, TopologyBase};
use crate::topological_sort;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum LongestPathError {
Cycle,
}
impl core::fmt::Display for LongestPathError {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Cycle => formatter.write_str("longest path found a cycle"),
}
}
}
impl core::error::Error for LongestPathError {}
pub fn longest_path_dag<G>(
graph: &G,
elements: &[<G as TopologyBase>::ElementId],
) -> Result<Vec<<G as TopologyBase>::ElementId>, LongestPathError>
where
G: ElementIndex + ElementSuccessors,
{
let order = topological_sort(graph, elements).map_err(|_| LongestPathError::Cycle)?;
if order.is_empty() {
return Ok(Vec::new());
}
let bound = graph.element_bound();
let mut lengths = vec![0usize; bound];
let mut predecessor: Vec<Option<<G as TopologyBase>::ElementId>> = vec![None; bound];
let mut best_end: Option<<G as TopologyBase>::ElementId> = None;
let mut best_length = 0usize;
for &node in &order {
let node_index = graph.element_index(node);
let node_length = lengths[node_index];
if best_end.is_none() || node_length > best_length {
best_length = node_length;
best_end = Some(node);
}
for successor in graph.element_successors(node) {
let target = graph.element_index(successor);
if target < bound && lengths[target] < node_length + 1 {
lengths[target] = node_length + 1;
predecessor[target] = Some(node);
}
}
}
let mut path = Vec::with_capacity(best_length + 1);
let mut cursor = best_end;
while let Some(node) = cursor {
path.push(node);
cursor = predecessor[graph.element_index(node)];
}
path.reverse();
Ok(path)
}