use crate::graph::{Edge, Graph, GraphOptions};
use crate::layout::rank::util::slack;
use crate::layout::types::{EdgeLabel, NodeLabel};
#[derive(Debug, Clone, Default)]
pub(crate) struct TreeNodeLabel {
pub low: Option<i32>,
pub lim: Option<i32>,
pub parent: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct TreeEdgeLabel {
pub cutvalue: Option<i32>,
}
pub(crate) fn feasible_tree(
g: &mut Graph<NodeLabel, EdgeLabel>,
) -> Graph<TreeNodeLabel, TreeEdgeLabel> {
let mut tree = Graph::<TreeNodeLabel, TreeEdgeLabel>::with_options(GraphOptions {
directed: false,
multigraph: false,
compound: false,
});
let nodes = g.nodes();
if nodes.is_empty() {
return tree;
}
let start = &nodes[0];
let size = g.node_count();
tree.set_node(start.clone(), Some(TreeNodeLabel::default()));
while tight_tree(&mut tree, g) < size {
let edge = match find_min_slack_edge(&tree, g) {
Some(e) => e,
None => break,
};
let delta = if tree.has_node(&edge.v) {
slack(g, &edge)
} else {
-slack(g, &edge)
};
shift_ranks(&tree, g, delta);
}
tree
}
fn tight_tree(
tree: &mut Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &Graph<NodeLabel, EdgeLabel>,
) -> usize {
let tree_nodes = tree.nodes();
fn dfs(
tree: &mut Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &Graph<NodeLabel, EdgeLabel>,
v: &str,
) {
let node_edges = g.node_edges(v, None).unwrap_or_default();
for e in &node_edges {
let w = if v == e.v { &e.w } else { &e.v };
if !tree.has_node(w) && slack(g, e) == 0 {
tree.set_node(w.clone(), Some(TreeNodeLabel::default()));
tree.set_edge(v, w.as_str(), Some(TreeEdgeLabel::default()), None);
dfs(tree, g, w);
}
}
}
for v in &tree_nodes {
dfs(tree, g, v);
}
tree.node_count()
}
fn find_min_slack_edge(
tree: &Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &Graph<NodeLabel, EdgeLabel>,
) -> Option<Edge> {
let mut best_slack = i32::MAX;
let mut best_edge: Option<Edge> = None;
for edge in g.edges() {
if tree.has_node(&edge.v) != tree.has_node(&edge.w) {
let s = slack(g, &edge);
if s < best_slack {
best_slack = s;
best_edge = Some(edge);
}
}
}
best_edge
}
fn shift_ranks(
tree: &Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &mut Graph<NodeLabel, EdgeLabel>,
delta: i32,
) {
for v in tree.nodes() {
if let Some(label) = g.node_mut(&v)
&& let Some(r) = label.rank
{
label.rank = Some(r + delta);
}
}
}