use crate::graph::{Edge, Graph};
use crate::layout::rank::feasible_tree::{TreeEdgeLabel, TreeNodeLabel, feasible_tree};
use crate::layout::rank::util::{longest_path, slack};
use crate::layout::types::{EdgeLabel, NodeLabel};
use crate::layout::util::simplify;
use std::collections::BTreeSet;
pub(crate) fn network_simplex(g: &mut Graph<NodeLabel, EdgeLabel>) {
let mut sg = simplify(g);
longest_path(&mut sg);
let mut tree = feasible_tree(&mut sg);
init_low_lim_values(&mut tree, None);
init_cut_values(&mut tree, &sg);
while let Some(leave) = leave_edge(&tree) {
let enter = enter_edge(&tree, &sg, &leave);
exchange_edges(&mut tree, &mut sg, &leave, &enter);
}
for v in g.nodes() {
if let Some(sg_label) = sg.node(&v)
&& let Some(label) = g.node_mut(&v)
{
label.rank = sg_label.rank;
}
}
}
fn init_cut_values(
tree: &mut Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &Graph<NodeLabel, EdgeLabel>,
) {
let roots: Vec<String> = tree.nodes();
let root_refs: Vec<&str> = roots.iter().map(|s| s.as_str()).collect();
let mut visited = postorder_undirected(tree, &root_refs);
visited.pop();
for v in &visited {
assign_cut_value(tree, g, v);
}
}
fn assign_cut_value(
tree: &mut Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &Graph<NodeLabel, EdgeLabel>,
child: &str,
) {
let parent = match tree.node(child).and_then(|n| n.parent.clone()) {
Some(p) => p,
None => return,
};
let cv = calc_cut_value(tree, g, child);
if let Some(e) = tree.edge_mut(child, &parent, None) {
e.cutvalue = Some(cv);
} else if let Some(e) = tree.edge_mut(&parent, child, None) {
e.cutvalue = Some(cv);
}
}
fn calc_cut_value(
tree: &Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &Graph<NodeLabel, EdgeLabel>,
child: &str,
) -> i32 {
let parent = tree.node(child).and_then(|n| n.parent.as_deref()).unwrap();
let mut child_is_tail = true;
let graph_edge = match g.edge(child, parent, None) {
Some(e) => e,
None => {
child_is_tail = false;
g.edge(parent, child, None).unwrap()
}
};
let mut cut_value: i32 = graph_edge.weight;
let node_edges = g.node_edges(child, None).unwrap_or_default();
for edge in &node_edges {
let is_out_edge = edge.v == child;
let other = if is_out_edge { &edge.w } else { &edge.v };
if other.as_str() == parent {
continue;
}
let points_to_head = is_out_edge == child_is_tail;
let other_weight = g
.edge(&edge.v, &edge.w, edge.name.as_deref())
.map(|l| l.weight)
.unwrap_or(1);
if points_to_head {
cut_value += other_weight;
} else {
cut_value -= other_weight;
}
if is_tree_edge(tree, child, other) {
let other_cut_value = get_tree_edge_cutvalue(tree, child, other);
if points_to_head {
cut_value -= other_cut_value;
} else {
cut_value += other_cut_value;
}
}
}
cut_value
}
fn is_tree_edge(tree: &Graph<TreeNodeLabel, TreeEdgeLabel>, u: &str, v: &str) -> bool {
tree.has_edge(u, v, None)
}
fn get_tree_edge_cutvalue(tree: &Graph<TreeNodeLabel, TreeEdgeLabel>, u: &str, v: &str) -> i32 {
tree.edge(u, v, None)
.and_then(|e| e.cutvalue)
.or_else(|| tree.edge(v, u, None).and_then(|e| e.cutvalue))
.unwrap_or(0)
}
fn init_low_lim_values(tree: &mut Graph<TreeNodeLabel, TreeEdgeLabel>, root: Option<&str>) {
let root_node = match root {
Some(r) => r.to_string(),
None => match tree.nodes().first() {
Some(n) => n.clone(),
None => return,
},
};
let mut visited = BTreeSet::new();
dfs_assign_low_lim(tree, &mut visited, 1, &root_node, None);
}
fn dfs_assign_low_lim(
tree: &mut Graph<TreeNodeLabel, TreeEdgeLabel>,
visited: &mut BTreeSet<String>,
next_lim: i32,
v: &str,
parent: Option<&str>,
) -> i32 {
let low = next_lim;
let mut current_lim = next_lim;
visited.insert(v.to_string());
let neighbors = tree.neighbors(v).unwrap_or_default();
for w in &neighbors {
if !visited.contains(w) {
current_lim = dfs_assign_low_lim(tree, visited, current_lim, w, Some(v));
}
}
if let Some(label) = tree.node_mut(v) {
label.low = Some(low);
label.lim = Some(current_lim);
label.parent = parent.map(|p| p.to_string());
}
current_lim + 1
}
fn leave_edge(tree: &Graph<TreeNodeLabel, TreeEdgeLabel>) -> Option<Edge> {
tree.edges().into_iter().find(|e| {
let edge = tree.edge(&e.v, &e.w, e.name.as_deref());
edge.and_then(|el| el.cutvalue).is_some_and(|cv| cv < 0)
})
}
fn enter_edge(
tree: &Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &Graph<NodeLabel, EdgeLabel>,
edge: &Edge,
) -> Edge {
let mut v = edge.v.clone();
let mut w = edge.w.clone();
if !g.has_edge(&v, &w, None) {
std::mem::swap(&mut v, &mut w);
}
let v_label = tree.node(&v).unwrap();
let w_label = tree.node(&w).unwrap();
let v_lim = v_label.lim.unwrap();
let w_lim = w_label.lim.unwrap();
let (tail_label, flip) = if v_lim > w_lim {
(w_label.clone(), true)
} else {
(v_label.clone(), false)
};
let candidates: Vec<Edge> = g
.edges()
.into_iter()
.filter(|e| {
let e_v_label = tree.node(&e.v);
let e_w_label = tree.node(&e.w);
match (e_v_label, e_w_label) {
(Some(vl), Some(wl)) => {
let v_desc = is_descendant(vl, &tail_label);
let w_desc = is_descendant(wl, &tail_label);
(flip == v_desc) && (flip != w_desc)
}
_ => false,
}
})
.collect();
candidates
.into_iter()
.min_by_key(|e| slack(g, e))
.expect("enter_edge: no candidate edge found")
}
fn is_descendant(v_label: &TreeNodeLabel, root_label: &TreeNodeLabel) -> bool {
let root_low = root_label.low.unwrap();
let root_lim = root_label.lim.unwrap();
let v_lim = v_label.lim.unwrap();
root_low <= v_lim && v_lim <= root_lim
}
fn exchange_edges(
tree: &mut Graph<TreeNodeLabel, TreeEdgeLabel>,
g: &mut Graph<NodeLabel, EdgeLabel>,
leave: &Edge,
enter: &Edge,
) {
tree.remove_edge(&leave.v, &leave.w, None);
tree.set_edge(
enter.v.clone(),
enter.w.clone(),
Some(TreeEdgeLabel::default()),
None,
);
init_low_lim_values(tree, None);
init_cut_values(tree, g);
update_ranks(tree, g);
}
fn update_ranks(tree: &Graph<TreeNodeLabel, TreeEdgeLabel>, g: &mut Graph<NodeLabel, EdgeLabel>) {
let root = tree
.nodes()
.into_iter()
.find(|v| tree.node(v).is_none_or(|n| n.parent.is_none()));
let root = match root {
Some(r) => r,
None => return,
};
let vs = preorder_undirected(tree, &root);
for v in vs.iter().skip(1) {
let parent = match tree.node(v).and_then(|n| n.parent.clone()) {
Some(p) => p,
None => continue,
};
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 = edge.map(|e| e.minlen).unwrap_or(1);
let parent_rank = g.node(&parent).unwrap().rank.unwrap();
let new_rank = if flipped {
parent_rank + minlen
} else {
parent_rank - minlen
};
g.node_mut(v).unwrap().rank = Some(new_rank);
}
}
fn preorder_undirected(g: &Graph<TreeNodeLabel, TreeEdgeLabel>, root: &str) -> Vec<String> {
let mut result = Vec::new();
let mut visited = BTreeSet::new();
fn dfs(
g: &Graph<TreeNodeLabel, TreeEdgeLabel>,
v: &str,
visited: &mut BTreeSet<String>,
result: &mut Vec<String>,
) {
if visited.contains(v) {
return;
}
visited.insert(v.to_string());
result.push(v.to_string());
if let Some(neighbors) = g.neighbors(v) {
for w in neighbors {
dfs(g, &w, visited, result);
}
}
}
dfs(g, root, &mut visited, &mut result);
result
}
fn postorder_undirected(g: &Graph<TreeNodeLabel, TreeEdgeLabel>, roots: &[&str]) -> Vec<String> {
let mut result = Vec::new();
let mut visited = BTreeSet::new();
fn dfs(
g: &Graph<TreeNodeLabel, TreeEdgeLabel>,
v: &str,
visited: &mut BTreeSet<String>,
result: &mut Vec<String>,
) {
if visited.contains(v) {
return;
}
visited.insert(v.to_string());
if let Some(neighbors) = g.neighbors(v) {
for w in neighbors {
dfs(g, &w, visited, result);
}
}
result.push(v.to_string());
}
for root in roots {
dfs(g, root, &mut visited, &mut result);
}
result
}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::{Edge, Graph, GraphOptions};
use crate::layout::rank::feasible_tree::{TreeEdgeLabel, TreeNodeLabel};
use crate::layout::rank::util::longest_path;
use crate::layout::types::{EdgeLabel, NodeLabel};
use crate::layout::util::normalize_ranks;
fn ns(g: &mut Graph<NodeLabel, EdgeLabel>) {
network_simplex(g);
normalize_ranks(g);
}
fn undirected_edge(e: &Edge) -> (String, String) {
if e.v < e.w {
(e.v.clone(), e.w.clone())
} else {
(e.w.clone(), e.v.clone())
}
}
fn new_graph() -> Graph<NodeLabel, EdgeLabel> {
let mut g = Graph::with_options(GraphOptions {
directed: true,
multigraph: true,
compound: false,
});
g.set_default_node_label(|_| NodeLabel::default());
g.set_default_edge_label(|_| EdgeLabel {
minlen: 1,
weight: 1,
..Default::default()
});
g
}
fn new_tree() -> Graph<TreeNodeLabel, TreeEdgeLabel> {
let mut t = Graph::with_options(GraphOptions {
directed: false,
multigraph: false,
compound: false,
});
t.set_default_node_label(|_| TreeNodeLabel::default());
t.set_default_edge_label(|_| TreeEdgeLabel::default());
t
}
fn gansner_graph() -> Graph<NodeLabel, EdgeLabel> {
let mut g = Graph::new();
g.set_default_node_label(|_| NodeLabel::default());
g.set_default_edge_label(|_| EdgeLabel {
minlen: 1,
weight: 1,
..Default::default()
});
g.set_path(&["a", "b", "c", "d", "h"], None);
g.set_path(&["a", "e", "g", "h"], None);
g.set_path(&["a", "f", "g"], None);
g
}
fn gansner_tree() -> Graph<TreeNodeLabel, TreeEdgeLabel> {
let mut t = new_tree();
t.set_path(&["a", "b", "c", "d", "h", "g", "e"], None);
t.set_edge("g", "f", None, None);
t
}
#[test]
fn can_assign_rank_to_single_node() {
let mut g = new_graph();
g.set_node("a".to_string(), None);
ns(&mut g);
assert_eq!(g.node("a").unwrap().rank, Some(0));
}
#[test]
fn can_assign_rank_to_2_node_connected_graph() {
let mut g = new_graph();
g.set_edge("a", "b", None, None);
ns(&mut g);
assert_eq!(g.node("a").unwrap().rank, Some(0));
assert_eq!(g.node("b").unwrap().rank, Some(1));
}
#[test]
fn can_assign_ranks_for_diamond() {
let mut g = new_graph();
g.set_path(&["a", "b", "d"], None);
g.set_path(&["a", "c", "d"], None);
ns(&mut g);
assert_eq!(g.node("a").unwrap().rank, Some(0));
assert_eq!(g.node("b").unwrap().rank, Some(1));
assert_eq!(g.node("c").unwrap().rank, Some(1));
assert_eq!(g.node("d").unwrap().rank, Some(2));
}
#[test]
fn uses_minlen_attribute_on_edge() {
let mut g = new_graph();
g.set_path(&["a", "b", "d"], None);
g.set_edge("a", "c", None, None);
g.set_edge(
"c",
"d",
Some(EdgeLabel {
minlen: 2,
weight: 1,
..Default::default()
}),
None,
);
ns(&mut g);
assert_eq!(g.node("a").unwrap().rank, Some(0));
assert_eq!(g.node("b").unwrap().rank, Some(2));
assert_eq!(g.node("c").unwrap().rank, Some(1));
assert_eq!(g.node("d").unwrap().rank, Some(3));
}
#[test]
fn can_rank_gansner_graph() {
let mut g = gansner_graph();
ns(&mut g);
assert_eq!(g.node("a").unwrap().rank, Some(0));
assert_eq!(g.node("b").unwrap().rank, Some(1));
assert_eq!(g.node("c").unwrap().rank, Some(2));
assert_eq!(g.node("d").unwrap().rank, Some(3));
assert_eq!(g.node("h").unwrap().rank, Some(4));
assert_eq!(g.node("e").unwrap().rank, Some(1));
assert_eq!(g.node("f").unwrap().rank, Some(1));
assert_eq!(g.node("g").unwrap().rank, Some(2));
}
#[test]
fn can_handle_multi_edges() {
let mut g = new_graph();
g.set_path(&["a", "b", "c", "d"], None);
g.set_edge(
"a",
"e",
Some(EdgeLabel {
weight: 2,
minlen: 1,
..Default::default()
}),
None,
);
g.set_edge("e", "d", None, None);
g.set_edge(
"b",
"c",
Some(EdgeLabel {
weight: 1,
minlen: 2,
..Default::default()
}),
Some("multi"),
);
ns(&mut g);
assert_eq!(g.node("a").unwrap().rank, Some(0));
assert_eq!(g.node("b").unwrap().rank, Some(1));
assert_eq!(g.node("c").unwrap().rank, Some(3));
assert_eq!(g.node("d").unwrap().rank, Some(4));
assert_eq!(g.node("e").unwrap().rank, Some(1));
}
#[test]
fn leave_edge_returns_none_if_no_negative_cutvalue() {
let mut tree = Graph::with_options(GraphOptions {
directed: false,
multigraph: false,
compound: false,
});
tree.set_edge("a", "b", Some(TreeEdgeLabel { cutvalue: Some(1) }), None);
tree.set_edge("b", "c", Some(TreeEdgeLabel { cutvalue: Some(1) }), None);
assert!(leave_edge(&tree).is_none());
}
#[test]
fn leave_edge_returns_edge_with_negative_cutvalue() {
let mut tree = Graph::with_options(GraphOptions {
directed: false,
multigraph: false,
compound: false,
});
tree.set_edge("a", "b", Some(TreeEdgeLabel { cutvalue: Some(1) }), None);
tree.set_edge("b", "c", Some(TreeEdgeLabel { cutvalue: Some(-1) }), None);
let e = leave_edge(&tree).unwrap();
assert_eq!(undirected_edge(&e), ("b".to_string(), "c".to_string()));
}
#[test]
fn enter_edge_finds_edge_from_head_to_tail_component() {
let mut g = new_graph();
g.set_node(
"a".to_string(),
Some(NodeLabel {
rank: Some(0),
..Default::default()
}),
);
g.set_node(
"b".to_string(),
Some(NodeLabel {
rank: Some(2),
..Default::default()
}),
);
g.set_node(
"c".to_string(),
Some(NodeLabel {
rank: Some(3),
..Default::default()
}),
);
g.set_path(&["a", "b", "c"], None);
g.set_edge("a", "c", None, None);
let mut t = new_tree();
t.set_path(&["b", "c", "a"], None);
init_low_lim_values(&mut t, Some("c"));
let f = enter_edge(&t, &g, &Edge::new("b", "c"));
assert_eq!(undirected_edge(&f), ("a".to_string(), "b".to_string()));
}
#[test]
fn enter_edge_works_when_root_in_tail_component() {
let mut g = new_graph();
g.set_node(
"a".to_string(),
Some(NodeLabel {
rank: Some(0),
..Default::default()
}),
);
g.set_node(
"b".to_string(),
Some(NodeLabel {
rank: Some(2),
..Default::default()
}),
);
g.set_node(
"c".to_string(),
Some(NodeLabel {
rank: Some(3),
..Default::default()
}),
);
g.set_path(&["a", "b", "c"], None);
g.set_edge("a", "c", None, None);
let mut t = new_tree();
t.set_path(&["b", "c", "a"], None);
init_low_lim_values(&mut t, Some("b"));
let f = enter_edge(&t, &g, &Edge::new("b", "c"));
assert_eq!(undirected_edge(&f), ("a".to_string(), "b".to_string()));
}
#[test]
fn enter_edge_finds_edge_with_least_slack() {
let mut g = new_graph();
g.set_node(
"a".to_string(),
Some(NodeLabel {
rank: Some(0),
..Default::default()
}),
);
g.set_node(
"b".to_string(),
Some(NodeLabel {
rank: Some(1),
..Default::default()
}),
);
g.set_node(
"c".to_string(),
Some(NodeLabel {
rank: Some(3),
..Default::default()
}),
);
g.set_node(
"d".to_string(),
Some(NodeLabel {
rank: Some(4),
..Default::default()
}),
);
g.set_edge("a", "d", None, None);
g.set_path(&["a", "c", "d"], None);
g.set_edge("b", "c", None, None);
let mut t = new_tree();
t.set_path(&["c", "d", "a", "b"], None);
init_low_lim_values(&mut t, Some("a"));
let f = enter_edge(&t, &g, &Edge::new("c", "d"));
assert_eq!(undirected_edge(&f), ("b".to_string(), "c".to_string()));
}
#[test]
fn enter_edge_gansner_graph_1() {
let mut g = gansner_graph();
let mut t = gansner_tree();
longest_path(&mut g);
init_low_lim_values(&mut t, Some("a"));
let f = enter_edge(&t, &g, &Edge::new("g", "h"));
let (ev, ew) = undirected_edge(&f);
assert_eq!(ev, "a");
assert!(ew == "e" || ew == "f");
}
#[test]
fn enter_edge_gansner_graph_2() {
let mut g = gansner_graph();
let mut t = gansner_tree();
longest_path(&mut g);
init_low_lim_values(&mut t, Some("e"));
let f = enter_edge(&t, &g, &Edge::new("g", "h"));
let (ev, ew) = undirected_edge(&f);
assert_eq!(ev, "a");
assert!(ew == "e" || ew == "f");
}
#[test]
fn enter_edge_gansner_graph_3() {
let mut g = gansner_graph();
let mut t = gansner_tree();
longest_path(&mut g);
init_low_lim_values(&mut t, Some("a"));
let f = enter_edge(&t, &g, &Edge::new("h", "g"));
let (ev, ew) = undirected_edge(&f);
assert_eq!(ev, "a");
assert!(ew == "e" || ew == "f");
}
#[test]
fn enter_edge_gansner_graph_4() {
let mut g = gansner_graph();
let mut t = gansner_tree();
longest_path(&mut g);
init_low_lim_values(&mut t, Some("e"));
let f = enter_edge(&t, &g, &Edge::new("h", "g"));
let (ev, ew) = undirected_edge(&f);
assert_eq!(ev, "a");
assert!(ew == "e" || ew == "f");
}
#[test]
fn init_low_lim_values_assigns_low_lim_parent() {
let mut g = Graph::with_options(GraphOptions {
directed: true,
multigraph: false,
compound: false,
});
g.set_default_node_label(|_| TreeNodeLabel::default());
g.set_default_edge_label(|_| TreeEdgeLabel::default());
for n in &["a", "b", "c", "d", "e"] {
g.set_node(n.to_string(), None);
}
g.set_path(&["a", "b", "a", "c", "d", "c", "e"], None);
init_low_lim_values(&mut g, Some("a"));
let a = g.node("a").unwrap();
let b = g.node("b").unwrap();
let c = g.node("c").unwrap();
let d = g.node("d").unwrap();
let e = g.node("e").unwrap();
let mut lims: Vec<i32> = vec![
a.lim.unwrap(),
b.lim.unwrap(),
c.lim.unwrap(),
d.lim.unwrap(),
e.lim.unwrap(),
];
lims.sort();
assert_eq!(lims, vec![1, 2, 3, 4, 5]);
assert_eq!(a.low, Some(1));
assert_eq!(a.lim, Some(5));
assert_eq!(b.parent.as_deref(), Some("a"));
assert!(b.lim.unwrap() < a.lim.unwrap());
assert_eq!(c.parent.as_deref(), Some("a"));
assert!(c.lim.unwrap() < a.lim.unwrap());
assert_ne!(c.lim, b.lim);
assert_eq!(d.parent.as_deref(), Some("c"));
assert!(d.lim.unwrap() < c.lim.unwrap());
assert_eq!(e.parent.as_deref(), Some("c"));
assert!(e.lim.unwrap() < c.lim.unwrap());
assert_ne!(e.lim, d.lim);
}
#[test]
fn exchange_edges_updates_cut_values_and_low_lim() {
let mut g = gansner_graph();
let mut t = gansner_tree();
longest_path(&mut g);
init_low_lim_values(&mut t, None);
init_cut_values(&mut t, &g);
exchange_edges(&mut t, &mut g, &Edge::new("g", "h"), &Edge::new("a", "e"));
assert_eq!(t.edge("a", "b", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("b", "c", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("c", "d", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("d", "h", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("a", "e", None).unwrap().cutvalue, Some(1));
assert_eq!(t.edge("e", "g", None).unwrap().cutvalue, Some(1));
assert_eq!(t.edge("g", "f", None).unwrap().cutvalue, Some(0));
let mut lims: Vec<i32> = t
.nodes()
.iter()
.map(|v| t.node(v).unwrap().lim.unwrap())
.collect();
lims.sort();
assert_eq!(lims, vec![1, 2, 3, 4, 5, 6, 7, 8]);
}
#[test]
fn exchange_edges_updates_ranks() {
let mut g = gansner_graph();
let mut t = gansner_tree();
longest_path(&mut g);
init_low_lim_values(&mut t, None);
init_cut_values(&mut t, &g);
exchange_edges(&mut t, &mut g, &Edge::new("g", "h"), &Edge::new("a", "e"));
normalize_ranks(&mut g);
assert_eq!(g.node("a").unwrap().rank, Some(0));
assert_eq!(g.node("b").unwrap().rank, Some(1));
assert_eq!(g.node("c").unwrap().rank, Some(2));
assert_eq!(g.node("d").unwrap().rank, Some(3));
assert_eq!(g.node("e").unwrap().rank, Some(1));
assert_eq!(g.node("f").unwrap().rank, Some(1));
assert_eq!(g.node("g").unwrap().rank, Some(2));
assert_eq!(g.node("h").unwrap().rank, Some(4));
}
#[test]
fn calc_cut_value_2_node_tree_c_to_p() {
let mut g = new_graph();
g.set_path(&["c", "p"], None);
let mut t = new_tree();
t.set_path(&["p", "c"], None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 1);
}
#[test]
fn calc_cut_value_2_node_tree_p_to_c() {
let mut g = new_graph();
g.set_path(&["p", "c"], None);
let mut t = new_tree();
t.set_path(&["p", "c"], None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 1);
}
#[test]
fn calc_cut_value_3_node_gc_c_p() {
let mut g = new_graph();
g.set_path(&["gc", "c", "p"], None);
let mut t = new_tree();
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("p", "c", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 3);
}
#[test]
fn calc_cut_value_3_node_gc_c_rev_p() {
let mut g = new_graph();
g.set_edge("p", "c", None, None);
g.set_edge("gc", "c", None, None);
let mut t = new_tree();
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("p", "c", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), -1);
}
#[test]
fn calc_cut_value_3_node_rev_gc_c_p() {
let mut g = new_graph();
g.set_edge("c", "p", None, None);
g.set_edge("c", "gc", None, None);
let mut t = new_tree();
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("p", "c", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), -1);
}
#[test]
fn calc_cut_value_3_node_rev_gc_rev_c_p() {
let mut g = new_graph();
g.set_path(&["p", "c", "gc"], None);
let mut t = new_tree();
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("p", "c", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 3);
}
#[test]
fn calc_cut_value_4_node_gc_c_p_o_with_o_to_c() {
let mut g = new_graph();
g.set_edge(
"o",
"c",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
g.set_path(&["gc", "c", "p", "o"], None);
let mut t = new_tree();
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_path(&["c", "p", "o"], None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), -4);
}
#[test]
fn calc_cut_value_4_node_gc_c_p_o_with_c_to_o() {
let mut g = new_graph();
g.set_edge(
"c",
"o",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
g.set_path(&["gc", "c", "p", "o"], None);
let mut t = new_tree();
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_path(&["c", "p", "o"], None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 10);
}
#[test]
fn calc_cut_value_4_node_o_gc_c_p_with_o_to_c() {
let mut g = new_graph();
g.set_edge(
"o",
"c",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
g.set_path(&["o", "gc", "c", "p"], None);
let mut t = new_tree();
t.set_edge("o", "gc", None, None);
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("c", "p", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), -4);
}
#[test]
fn calc_cut_value_4_node_o_gc_c_p_with_c_to_o() {
let mut g = new_graph();
g.set_edge(
"c",
"o",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
g.set_path(&["o", "gc", "c", "p"], None);
let mut t = new_tree();
t.set_edge("o", "gc", None, None);
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("c", "p", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 10);
}
#[test]
fn calc_cut_value_4_node_gc_c_rev_p_o_with_o_to_c() {
let mut g = new_graph();
g.set_edge("gc", "c", None, None);
g.set_edge("p", "c", None, None);
g.set_edge("p", "o", None, None);
g.set_edge(
"o",
"c",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
let mut t = new_tree();
t.set_edge("o", "gc", None, None);
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("c", "p", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 6);
}
#[test]
fn calc_cut_value_4_node_gc_c_rev_p_o_with_c_to_o() {
let mut g = new_graph();
g.set_edge("gc", "c", None, None);
g.set_edge("p", "c", None, None);
g.set_edge("p", "o", None, None);
g.set_edge(
"c",
"o",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
let mut t = new_tree();
t.set_edge("o", "gc", None, None);
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("c", "p", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), -8);
}
#[test]
fn calc_cut_value_4_node_o_gc_c_rev_p_with_o_to_c() {
let mut g = new_graph();
g.set_edge(
"o",
"c",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
g.set_path(&["o", "gc", "c"], None);
g.set_edge("p", "c", None, None);
let mut t = new_tree();
t.set_edge("o", "gc", None, None);
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("c", "p", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), 6);
}
#[test]
fn calc_cut_value_4_node_o_gc_c_rev_p_with_c_to_o() {
let mut g = new_graph();
g.set_edge(
"c",
"o",
Some(EdgeLabel {
weight: 7,
minlen: 1,
..Default::default()
}),
None,
);
g.set_path(&["o", "gc", "c"], None);
g.set_edge("p", "c", None, None);
let mut t = new_tree();
t.set_edge("o", "gc", None, None);
t.set_edge("gc", "c", Some(TreeEdgeLabel { cutvalue: Some(3) }), None);
t.set_edge("c", "p", None, None);
init_low_lim_values(&mut t, Some("p"));
assert_eq!(calc_cut_value(&t, &g, "c"), -8);
}
#[test]
fn init_cut_values_gansner_graph() {
let mut g = gansner_graph();
let mut t = gansner_tree();
longest_path(&mut g);
init_low_lim_values(&mut t, None);
init_cut_values(&mut t, &g);
assert_eq!(t.edge("a", "b", None).unwrap().cutvalue, Some(3));
assert_eq!(t.edge("b", "c", None).unwrap().cutvalue, Some(3));
assert_eq!(t.edge("c", "d", None).unwrap().cutvalue, Some(3));
assert_eq!(t.edge("d", "h", None).unwrap().cutvalue, Some(3));
assert_eq!(t.edge("g", "h", None).unwrap().cutvalue, Some(-1));
assert_eq!(t.edge("e", "g", None).unwrap().cutvalue, Some(0));
assert_eq!(t.edge("f", "g", None).unwrap().cutvalue, Some(0));
}
#[test]
fn init_cut_values_updated_gansner_graph() {
let mut g = gansner_graph();
let mut t = gansner_tree();
t.remove_edge("g", "h", None);
t.set_edge("a", "e", None, None);
longest_path(&mut g);
init_low_lim_values(&mut t, None);
init_cut_values(&mut t, &g);
assert_eq!(t.edge("a", "b", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("b", "c", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("c", "d", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("d", "h", None).unwrap().cutvalue, Some(2));
assert_eq!(t.edge("a", "e", None).unwrap().cutvalue, Some(1));
assert_eq!(t.edge("e", "g", None).unwrap().cutvalue, Some(1));
assert_eq!(t.edge("f", "g", None).unwrap().cutvalue, Some(0));
}
}