use std::collections::BTreeMap;
use crate::graph::Graph;
use crate::layout::types::{EdgeLabel, NodeLabel};
pub(crate) fn cross_count(g: &Graph<NodeLabel, EdgeLabel>, layering: &[Vec<String>]) -> usize {
let mut cc = 0;
for i in 1..layering.len() {
cc += two_layer_cross_count(g, &layering[i - 1], &layering[i]);
}
cc
}
fn two_layer_cross_count(
g: &Graph<NodeLabel, EdgeLabel>,
north_layer: &[String],
south_layer: &[String],
) -> usize {
let south_pos: BTreeMap<&str, usize> = south_layer
.iter()
.enumerate()
.map(|(i, v)| (v.as_str(), i))
.collect();
let mut south_entries: Vec<(usize, i32)> = Vec::new();
for v in north_layer {
if let Some(edges) = g.out_edges(v, None) {
let mut entries: Vec<(usize, i32)> = edges
.iter()
.filter_map(|e| {
let pos = south_pos.get(e.w.as_str())?;
let weight = g.edge_by_obj(e).map_or(1, |l| l.weight);
Some((*pos, weight))
})
.collect();
entries.sort_by_key(|&(pos, _)| pos);
south_entries.extend(entries);
}
}
if south_layer.is_empty() {
return 0;
}
let mut first_index: usize = 1;
while first_index < south_layer.len() {
first_index <<= 1;
}
let tree_size = 2 * first_index - 1;
first_index -= 1;
let mut tree = vec![0i64; tree_size];
let mut cc: usize = 0;
for (pos, weight) in &south_entries {
let weight = *weight as i64;
let mut index = pos + first_index;
tree[index] += weight;
let mut weight_sum: i64 = 0;
while index > 0 {
if !index.is_multiple_of(2) {
weight_sum += tree[index + 1];
}
index = (index - 1) >> 1;
tree[index] += weight;
}
cc += (weight * weight_sum) as usize;
}
cc
}