use crate::sparse::csc::CscPattern;
#[inline]
fn zx(x: isize) -> usize {
x as usize
}
#[inline]
fn sx(x: usize) -> isize {
x as isize
}
pub(crate) fn col_etree(pattern: CscPattern<'_>, col_perm: Option<&[usize]>, etree: &mut [isize]) {
let n = pattern.ncols();
let m = pattern.nrows();
let mut ancestor = vec![-1isize; n];
let mut prev = vec![-1isize; m];
etree.fill(-1);
for j in 0..n {
let pj = col_perm.map_or(j, |perm| perm[j]);
for &row in pattern.row_idx_of_col(pj) {
let mut i = prev[row];
while i >= 0 {
let i_ = zx(i);
if i_ == j {
break;
}
let next_i = ancestor[i_];
ancestor[i_] = sx(j);
if next_i < 0 {
etree[i_] = sx(j);
break;
}
i = next_i;
}
prev[row] = sx(j);
}
}
}
pub(crate) fn postorder(post: &mut [usize], etree: &[isize]) {
let n = post.len();
if n == 0 {
return;
}
let mut stack = vec![0usize; n];
let mut first_child = vec![-1isize; n];
let mut next_child = vec![-1isize; n];
for j in (0..n).rev() {
let parent = etree[j];
if parent >= 0 {
let parent = zx(parent);
next_child[j] = first_child[parent];
first_child[parent] = sx(j);
}
}
let mut start = 0usize;
for root in 0..n {
if etree[root] < 0 {
start = postorder_depth_first_search(post, root, start, &mut stack, &mut first_child, &next_child);
}
}
}
fn postorder_depth_first_search(
post: &mut [usize],
root: usize,
mut start: usize,
stack: &mut [usize],
first_child: &mut [isize],
next_child: &[isize],
) -> usize {
let mut top = 1usize;
stack[0] = root;
while top != 0 {
let current = stack[top - 1];
let child = first_child[current];
if child >= 0 {
let child = zx(child);
stack[top] = child;
top += 1;
first_child[current] = next_child[child];
} else {
post[start] = current;
start += 1;
top -= 1;
}
}
start
}