use std::cmp::Reverse;
use std::collections::{BinaryHeap, VecDeque};
use log::{debug, info};
use ordered_float::OrderedFloat;
use crate::graph::GraphLaplacian;
use sprs::CsMat;
#[derive(Clone, Debug)]
pub struct Sequence {
pub order: Vec<usize>,
pub positions: Vec<f64>,
pub components: usize,
}
pub fn sequence_by_lambda(lambdas: &[f64], descending: bool) -> Sequence {
assert!(
lambdas.len() >= 2,
"sequencing requires at least two items, got {}",
lambdas.len()
);
let mut order: Vec<usize> = (0..lambdas.len()).collect();
if descending {
order.sort_unstable_by(|&a, &b| {
lambdas[b]
.partial_cmp(&lambdas[a])
.unwrap_or(std::cmp::Ordering::Equal)
.then(a.cmp(&b))
});
} else {
order.sort_unstable_by(|&a, &b| {
lambdas[a]
.partial_cmp(&lambdas[b])
.unwrap_or(std::cmp::Ordering::Equal)
.then(a.cmp(&b))
});
}
debug!(
"sequence_by_lambda ordered {} items ({})",
order.len(),
if descending {
"descending"
} else {
"ascending"
}
);
let positions = order.iter().map(|&i| lambdas[i]).collect();
Sequence {
order,
positions,
components: 1,
}
}
pub fn sequence_by_graph(gl: &GraphLaplacian) -> Sequence {
let n = gl.matrix.shape().0;
assert!(n >= 2, "sequencing requires at least two nodes, got {}", n);
assert_eq!(
gl.matrix.shape().1,
n,
"the laplacian must be a square matrix"
);
info!("Sequencing {} laplacian nodes via MST-chain seriation", n);
let adjacency = _adjacency_from_laplacian(&gl.matrix);
debug!(
"Recovered undirected adjacency with {} nodes",
adjacency.len()
);
let forest = _minimum_spanning_forest(&adjacency, n);
let sequence = _serialise_forest(forest);
info!(
"Sequenced {} nodes across {} component(s)",
sequence.order.len(),
sequence.components
);
sequence
}
fn _adjacency_from_laplacian(l: &CsMat<f64>) -> Vec<Vec<(usize, OrderedFloat<f64>)>> {
let n = l.shape().0;
let mut directed: Vec<(usize, usize, OrderedFloat<f64>)> = Vec::new();
for (i, row) in l.outer_iterator().enumerate() {
for (j, &v) in row.iter() {
if j > i && v < 0.0 {
let w = OrderedFloat(-v);
directed.push((i, j, w));
directed.push((j, i, w));
}
}
}
directed.sort_unstable_by_key(|&(i, j, _)| (i, j));
let mut adjacency: Vec<Vec<(usize, OrderedFloat<f64>)>> = vec![Vec::new(); n];
let mut last = (usize::MAX, usize::MAX);
for &(i, j, w) in &directed {
if (i, j) != last {
adjacency[i].push((j, w));
last = (i, j);
}
}
adjacency
}
fn _minimum_spanning_forest(
adjacency: &[Vec<(usize, OrderedFloat<f64>)>],
n: usize,
) -> Vec<Vec<usize>> {
let mut tree: Vec<Vec<usize>> = vec![Vec::new(); n];
let mut in_tree = vec![false; n];
let mut heap: BinaryHeap<Reverse<(OrderedFloat<f64>, usize, usize)>> = BinaryHeap::new();
for start in 0..n {
if in_tree[start] {
continue;
}
in_tree[start] = true;
for &(j, w) in &adjacency[start] {
heap.push(Reverse((w, j, start)));
}
while let Some(Reverse((_, j, parent))) = heap.pop() {
if in_tree[j] {
continue;
}
in_tree[j] = true;
tree[parent].push(j);
tree[j].push(parent);
for &(k, wk) in &adjacency[j] {
if !in_tree[k] {
heap.push(Reverse((wk, k, j)));
}
}
}
}
for neighbours in &mut tree {
neighbours.sort_unstable();
}
tree
}
fn _serialise_forest(tree: Vec<Vec<usize>>) -> Sequence {
let n = tree.len();
let mut comp_of = vec![usize::MAX; n];
let mut components: Vec<Vec<usize>> = Vec::new();
for s in 0..n {
if comp_of[s] != usize::MAX {
continue;
}
let id = components.len();
let mut members = Vec::new();
let mut stack = vec![s];
comp_of[s] = id;
while let Some(u) = stack.pop() {
members.push(u);
for &v in &tree[u] {
if comp_of[v] == usize::MAX {
comp_of[v] = id;
stack.push(v);
}
}
}
members.sort_unstable();
components.push(members);
}
components.sort_unstable_by_key(|members| (std::cmp::Reverse(members.len()), members[0]));
let mut order: Vec<usize> = Vec::with_capacity(n);
let mut depth_of = vec![0f64; n];
let mut visited = vec![false; n];
let mut dist = vec![usize::MAX; n];
let mut seen = vec![false; n];
for members in &components {
let seed = members[0];
let far = _bfs_farthest(seed, &tree, members, &mut dist, &mut seen);
let root = _bfs_farthest(far, &tree, members, &mut dist, &mut seen);
let mut stack = vec![(root, 0usize)];
visited[root] = true;
while let Some((u, depth)) = stack.pop() {
order.push(u);
depth_of[u] = depth as f64;
for &v in tree[u].iter().rev() {
if !visited[v] {
visited[v] = true;
stack.push((v, depth + 1));
}
}
}
}
Sequence {
positions: order.iter().map(|&u| depth_of[u]).collect(),
order,
components: components.len(),
}
}
fn _bfs_farthest(
src: usize,
tree: &[Vec<usize>],
members: &[usize],
dist: &mut [usize],
seen: &mut [bool],
) -> usize {
for &m in members {
dist[m] = usize::MAX;
seen[m] = false;
}
let mut queue = VecDeque::with_capacity(members.len());
dist[src] = 0;
seen[src] = true;
queue.push_back(src);
while let Some(u) = queue.pop_front() {
for &v in &tree[u] {
if !seen[v] {
seen[v] = true;
dist[v] = dist[u] + 1;
queue.push_back(v);
}
}
}
let mut best = src;
let mut best_dist = 0;
for &u in members {
if dist[u] > best_dist {
best = u;
best_dist = dist[u];
}
}
best
}