#![allow(non_snake_case)]
use super::VertexSet;
use crate::algebra::*;
use std::iter::zip;
pub(crate) const NO_PARENT: usize = usize::MAX;
pub(crate) const INACTIVE_NODE: usize = usize::MAX - 1;
#[derive(Debug)]
pub(crate) struct SuperNodeTree {
pub snode: Vec<VertexSet>,
pub snode_post: Vec<usize>,
pub snode_parent: Vec<usize>,
pub snode_children: Vec<VertexSet>,
pub post: Vec<usize>,
pub separators: Vec<VertexSet>,
pub nblk: Option<Vec<usize>>,
pub(crate) n_cliques: usize,
}
impl SuperNodeTree {
pub fn new<T: FloatT>(L: &CscMatrix<T>) -> Self {
let parent = parent_from_L(L);
let mut children = children_from_parent(&parent);
let mut post = vec![0; parent.len()];
post_order(&mut post, &parent, &mut children, parent.len());
let degree = higher_degree(L);
let (snode, snode_parent) = find_supernodes(&parent, &post, °ree);
let mut snode_children = children_from_parent(&snode_parent);
let mut snode_post = vec![0; snode_parent.len()];
post_order(
&mut snode_post,
&snode_parent,
&mut snode_children,
snode_parent.len(),
);
let separators = find_separators(L, &snode);
let nblk = None;
let n_cliques = snode.len();
Self {
snode,
snode_post,
snode_parent,
snode_children,
post,
separators,
nblk,
n_cliques,
}
}
#[allow(dead_code)]
pub(crate) fn get_post_order(&self, i: usize) -> usize {
self.snode_post[i]
}
pub(crate) fn get_snode(&self, i: usize) -> &VertexSet {
&self.snode[self.snode_post[i]]
}
pub(crate) fn get_separators(&self, i: usize) -> &VertexSet {
&self.separators[self.snode_post[i]]
}
pub(crate) fn get_clique_parent(&self, clique_index: usize) -> usize {
self.snode_parent[self.snode_post[clique_index]]
}
pub(crate) fn get_nblk(&self, i: usize) -> usize {
self.nblk.as_ref().unwrap()[i]
}
pub(crate) fn get_overlap(&self, i: usize) -> usize {
self.separators[self.snode_post[i]].len()
}
pub(crate) fn get_clique(&self, i: usize) -> VertexSet {
let c = self.snode_post[i];
let set1 = &self.snode[c];
let set2 = &self.separators[c];
let mut out = VertexSet::with_capacity(set1.len() + set2.len());
set1.union(set2).for_each(|&v| {
out.insert(v);
});
out
}
pub(crate) fn get_decomposed_dim_and_overlaps(&self) -> (usize, usize) {
let mut dim = 0;
let mut overlaps = 0;
for i in 0..self.n_cliques {
dim += triangular_number(self.get_nblk(i));
overlaps += triangular_number(self.get_overlap(i));
}
(dim, overlaps)
}
pub(crate) fn reorder_snode_consecutively(&mut self, ordering: &mut [usize]) {
let mut p = vec![0; self.post.len()];
let mut k = 0;
for &i in self.snode_post.iter() {
let snode = &mut self.snode[i];
let n = snode.len();
for (j, &v) in snode.iter().enumerate() {
p[j + k] = v;
}
p[k..(k + n)].sort();
snode.clear();
snode.extend(k..(k + n));
k += n;
}
let p_inv = invperm(&p);
for sp in self.separators.iter_mut() {
assert!(p.len() >= sp.len());
let tmp = &mut p[0..sp.len()];
for (i, &x) in sp.iter().enumerate() {
tmp[i] = p_inv[x];
}
sp.clear();
sp.extend(tmp.iter());
}
let tmp = ordering.to_vec(); ipermute(ordering, &tmp, &p_inv);
}
pub(crate) fn calculate_block_dimensions(&mut self) {
let n = self.n_cliques;
let mut nblk = vec![0; n];
for i in 0..n {
let c = self.snode_post[i];
nblk[i] = self.separators[c].len() + self.snode[c].len();
}
self.nblk = Some(nblk);
}
}
fn parent_from_L<T>(L: &CscMatrix<T>) -> Vec<usize>
where
T: FloatT,
{
let mut parent = vec![NO_PARENT; L.n];
for (i, par) in parent.iter_mut().enumerate() {
*par = find_parent_direct(L, i);
}
parent
}
fn find_parent_direct<T>(L: &CscMatrix<T>, v: usize) -> usize
where
T: FloatT,
{
if v == L.nrows() - 1 {
return NO_PARENT;
}
L.rowval[L.colptr[v]]
}
fn find_separators<T>(L: &CscMatrix<T>, snode: &[VertexSet]) -> Vec<VertexSet>
where
T: FloatT,
{
let mut separators = new_vertex_sets(snode.len());
for (sn, sep) in zip(snode, separators.iter_mut()) {
let vrep = *sn.iter().min().unwrap();
let adjplus = find_higher_order_neighbors(L, vrep);
for neighbor in adjplus {
if !sn.contains(neighbor) {
sep.insert(*neighbor);
}
}
}
separators
}
fn find_higher_order_neighbors<T>(L: &CscMatrix<T>, v: usize) -> &[usize] {
&L.rowval[L.colptr[v]..(L.colptr[v + 1])]
}
fn higher_degree<T>(L: &CscMatrix<T>) -> Vec<usize>
where
T: FloatT,
{
let mut degree = vec![0usize; L.ncols()];
for v in 0..(L.n - 1) {
degree[v] = L.colptr[v + 1] - L.colptr[v];
}
degree
}
fn children_from_parent(parent: &[usize]) -> Vec<VertexSet> {
let mut children = new_vertex_sets(parent.len());
for (i, &pi) in parent.iter().enumerate() {
if pi != NO_PARENT {
children[pi].insert(i);
}
}
children
}
pub(crate) fn post_order(
post: &mut Vec<usize>,
parent: &[usize],
children: &mut [VertexSet],
nc: usize,
) {
let mut order = vec![nc + 1; parent.len()];
let root = parent.iter().position(|&x| x == NO_PARENT).unwrap();
let mut stack = Vec::with_capacity(parent.len());
stack.push(root);
post.resize(parent.len(), 0);
post.iter_mut().enumerate().for_each(|(i, p)| *p = i);
let mut i = nc;
while let Some(v) = stack.pop() {
order[v] = i;
i -= 1;
children[v].sort();
stack.extend(children[v].iter());
}
post.sort_by(|&x, &y| order[x].cmp(&order[y]));
if nc != parent.len() {
post.truncate(nc);
}
}
fn find_supernodes(
parent: &[usize],
post: &[usize],
degree: &[usize],
) -> (Vec<VertexSet>, Vec<usize>) {
let mut snode = new_vertex_sets(parent.len());
let (snode_parent, snode_index) = pothen_sun(parent, post, degree);
for (i, &f) in snode_index.iter().enumerate() {
if f < 0 {
snode[i].insert(i);
} else {
snode[f as usize].insert(i);
}
}
snode.retain(|x| !x.is_empty());
(snode, snode_parent)
}
fn pothen_sun(parent: &[usize], post: &[usize], degree: &[usize]) -> (Vec<usize>, Vec<isize>) {
let n = parent.len();
let mut snode_index = vec![-1isize; n];
let mut snode_parent = vec![NO_PARENT; n];
let mut children = new_vertex_sets(parent.len());
let root_index = parent.iter().position(|&x| x == NO_PARENT).unwrap();
for &v in post {
if parent[v] == NO_PARENT {
children[root_index].insert(v);
} else {
children[parent[v]].insert(v);
}
if parent[v] != NO_PARENT {
if degree[v] - 1 == degree[parent[v]] && snode_index[parent[v]] == -1 {
if snode_index[v] < 0 {
snode_index[parent[v]] = v as isize;
snode_index[v] -= 1;
}
else {
snode_index[parent[v]] = snode_index[v];
let tmp = snode_index[v] as usize;
snode_index[tmp] -= 1;
}
} else if snode_index[v] < 0 {
snode_parent[v] = v;
} else {
snode_parent[snode_index[v] as usize] = snode_index[v] as usize;
}
}
let k: isize = {
if snode_index[v] < 0 {
v as isize
} else {
snode_index[v]
}
};
let v_children = &children[v];
if !v_children.is_empty() {
for &w in v_children {
let l = {
if snode_index[w] < 0 {
w
} else {
snode_index[w] as usize
}
};
if l != (k as usize) {
snode_parent[l] = k as usize
}
}
}
}
let repr_vertex = snode_index.iter().position_all(|&x| *x < 0);
let repr_parent: Vec<usize> = repr_vertex.iter().map(|&i| snode_parent[i]).collect();
snode_parent.clear();
snode_parent.resize(repr_vertex.len(), NO_PARENT);
for (i, &rp) in repr_parent.iter().enumerate() {
let rpidx = repr_vertex.iter().position(|&x| x == rp);
match rpidx {
Some(rpidx) => snode_parent[i] = rpidx,
None => snode_parent[i] = NO_PARENT,
}
}
(snode_parent, snode_index)
}
fn new_vertex_sets(n: usize) -> Vec<VertexSet> {
(0..n).map(|_| VertexSet::new()).collect()
}