use graphlib_rust::algo::postorder::postorder;
use graphlib_rust::{Edge, Graph};
use graphlib_rust::algo::preorder::preorder;
use ordered_hashmap::OrderedHashMap;
use crate::{GraphConfig, GraphEdge, GraphNode};
use crate::layout::rank::feasible_tree::feasible_tree;
use crate::layout::rank::util::{longest_path, slack};
use crate::layout::util::simplify_ref;
pub fn network_simplex(g: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
simplify_ref(g); longest_path(g);
let mut t: Graph<GraphConfig, GraphNode, GraphEdge> = feasible_tree(g);
init_low_lim_values(&mut t, None);
init_cut_values(&mut t, g);
let mut e;
let mut f;
while {
e = leave_edge(&t);
e.is_some()
} {
f = enter_edge(&t, &g, &e.clone().unwrap());
if f.is_some() {
exchange_edges(&mut t, g, &e.clone().unwrap(), f.unwrap());
}
}
}
fn init_cut_values(t: &mut Graph<GraphConfig, GraphNode, GraphEdge>, g: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
let node_ids = g.nodes();
let mut vs = postorder(g, &node_ids);
vs.pop(); for node_id in vs {
assign_cut_value(t, g, &node_id);
}
}
fn assign_cut_value(t: &mut Graph<GraphConfig, GraphNode, GraphEdge>, g: &mut Graph<GraphConfig, GraphNode, GraphEdge>, child: &String) {
let cutvalue = calc_cut_value(t, g, child);
let child_lab_ = t.node_mut(child);
if let Some(child_lab) = child_lab_ {
let parent = child_lab.parent.clone().unwrap_or("".to_string());
let edge_label_ = t.edge_mut(&child, &parent, None);
if let Some(edge_label) = edge_label_ {
edge_label.cutvalue = Some(cutvalue);
}
}
}
fn calc_cut_value(t: &mut Graph<GraphConfig, GraphNode, GraphEdge>, g: &mut Graph<GraphConfig, GraphNode, GraphEdge>, child: &String) -> f32 {
let mut cut_value = 0.0;
let child_lab_ = t.node_mut(child);
if let Some(child_lab) = child_lab_ {
let parent = child_lab.parent.clone().unwrap_or("".to_string());
let mut child_is_tail = true;
let mut graph_edge = g.edge_mut(child, &parent, None);
if graph_edge.is_none() {
child_is_tail = false;
graph_edge = g.edge_mut(&parent, &child, None);
}
cut_value = graph_edge.cloned().unwrap_or(GraphEdge::default()).weight.unwrap_or(0.0);
let edge_objs_ = g.node_edges(child, None);
if let Some(edge_objs) = edge_objs_ {
for e in edge_objs {
let is_out_edge = &e.v == child;
let other = if is_out_edge { e.w.clone() } else { e.v.clone() };
if other != parent {
let points_to_head = is_out_edge == child_is_tail;
let other_weight = g.edge_with_obj(&e).unwrap_or(&GraphEdge::default()).weight.unwrap_or(0.0);
cut_value += if points_to_head {
other_weight
} else {
-other_weight
};
if is_tree_edge(t, child, &other) {
let out_cut_value = t.edge(&child, &other, None)
.unwrap_or(&GraphEdge::default()).cutvalue
.unwrap_or(0.0);
cut_value += if points_to_head {
-out_cut_value
} else {
out_cut_value
}
}
}
}
}
}
cut_value
}
fn init_low_lim_values(tree: &mut Graph<GraphConfig, GraphNode, GraphEdge>, root_: Option<String>) {
let mut root = tree.nodes().first().cloned().unwrap_or("".to_string());
if root_.is_some() {
root = root_.unwrap();
}
let mut visited: OrderedHashMap<String, bool> = OrderedHashMap::new();
dfs_assign_low_lim(tree, &mut visited, 1, &root, None);
}
fn dfs_assign_low_lim(tree: &mut Graph<GraphConfig, GraphNode, GraphEdge>, visited: &mut OrderedHashMap<String, bool>, next_lim_: usize, v: &String, parent: Option<&String>) -> usize {
let low = next_lim_.clone();
let mut next_lim = next_lim_.clone();
visited.entry(v.clone()).or_insert(true);
let neighbors_ = tree.neighbors(v);
if let Some(neighbors) = neighbors_ {
for w in neighbors.into_iter() {
if !visited.contains_key(&w) {
next_lim = dfs_assign_low_lim(tree, visited, next_lim.clone(), &w, Some(v));
}
}
}
let label_ = tree.node_mut(v);
if let Some(label) = label_ {
label.low = Some(low);
label.lim = Some(next_lim.clone());
next_lim += 1;
if parent.is_some() {
label.parent = Some(parent.cloned().unwrap());
} else {
label.parent = None;
}
}
next_lim
}
fn leave_edge(tree: &Graph<GraphConfig, GraphNode, GraphEdge>) -> Option<Edge> {
let edge_objs = tree.edges();
edge_objs.iter().find(|edge_obj| {
tree.edge_with_obj(edge_obj)
.unwrap_or(&GraphEdge::default()).cutvalue.unwrap_or(0.0) < 0.0
}).cloned()
}
fn enter_edge(t: &Graph<GraphConfig, GraphNode, GraphEdge>, g: &Graph<GraphConfig, GraphNode, GraphEdge>, edge: &Edge) -> Option<Edge> {
let mut v = edge.v.clone();
let mut w = edge.w.clone();
if !g.has_edge(&v, &w, None) {
v = edge.w.clone();
w = edge.v.clone();
}
let v_label = t.node(&v).cloned()
.unwrap_or(GraphNode::default());
let w_label = t.node(&w).cloned()
.unwrap_or(GraphNode::default());
let mut tail_label = &v_label;
let mut flip = false;
if v_label.lim.clone().unwrap_or(0) > w_label.lim.clone().unwrap_or(0) {
tail_label = &w_label;
flip = true;
}
let edge_objs = g.edges();
let candidates = edge_objs.iter().filter(|edge_obj| {
let v_node = t.node(&edge_obj.v).cloned().unwrap_or(GraphNode::default());
let w_node = t.node(&edge_obj.w).cloned().unwrap_or(GraphNode::default());
flip == is_descendant(&v_node, tail_label) &&
flip != is_descendant(&w_node, tail_label)
});
candidates.min_by(|e1, e2| {
slack(g, e1).cmp(&slack(g, e2))
}).cloned()
}
fn exchange_edges(t: &mut Graph<GraphConfig, GraphNode, GraphEdge>, g: &mut Graph<GraphConfig, GraphNode, GraphEdge>, e: &Edge, f: Edge) {
let v = e.v.clone();
let w = e.w.clone();
t.remove_edge(&v, &w, None);
let _ = t.set_edge(&f.v, &f.w, Some(GraphEdge::default()), None);
init_low_lim_values(t, None);
init_cut_values(t, g);
update_ranks(t, g);
}
fn update_ranks(t: &mut Graph<GraphConfig, GraphNode, GraphEdge>, g: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
let root = t.nodes().into_iter().find(|v| {
!g.node(v).unwrap_or(&GraphNode::default()).parent.is_none()
}).unwrap_or("".to_string());
let mut vs = preorder(t, &vec![root]);
vs = vs.iter().skip(1).cloned().collect(); for v in vs.into_iter() {
let parent = t.node(&v).unwrap_or(&GraphNode::default()).parent.clone();
let _parent = parent.clone().unwrap_or("".to_string());
let mut edge = g.edge(&v, &_parent, None);
let mut flipped = false;
if edge.is_none() {
edge = g.edge(&_parent, &v, None);
flipped = true;
}
let minlen = if flipped {
edge.unwrap_or(&GraphEdge::default()).minlen.unwrap_or(0.0)
} else {
-edge.unwrap_or(&GraphEdge::default()).minlen.unwrap_or(0.0)
};
let parent_rank = g.node(&_parent).unwrap_or(&GraphNode::default()).rank.unwrap_or(0);
let v_node_= g.node_mut(&v);
if let Some(v_node) = v_node_ {
v_node.rank = Some(
parent_rank + (minlen as i32)
);
}
}
}
fn is_tree_edge(tree: &Graph<GraphConfig, GraphNode, GraphEdge>, u: &String, v: &String) -> bool {
tree.has_edge(&u, &v, None)
}
fn is_descendant(v_label: &GraphNode, root_label: &GraphNode) -> bool {
let low = root_label.low.clone().unwrap_or(0);
let v_lim = v_label.lim.clone().unwrap_or(0);
let root_lim = root_label.lim.clone().unwrap_or(0);
low <= v_lim && v_lim <= root_lim
}