use super::super::types::EMPTY;
#[allow(clippy::too_many_arguments)]
fn augment(
k: usize,
col_ptr: &[i64],
row_idx: &[i64],
match_: &mut [i64],
cheap: &mut [i64],
flag: &mut [i64],
istack: &mut [i64],
jstack: &mut [i64],
pstack: &mut [i64],
) -> bool {
let kk = k as i64;
let mut found = false;
let mut i: i64 = EMPTY;
let mut head: i64 = 0;
jstack[0] = kk;
debug_assert_ne!(flag[k], kk);
while head >= 0 {
let j = jstack[head as usize];
let pend = col_ptr[(j + 1) as usize];
if flag[j as usize] != kk {
flag[j as usize] = kk;
let mut p = cheap[j as usize];
while p < pend && !found {
i = row_idx[p as usize];
found = match_[i as usize] == EMPTY;
p += 1;
}
cheap[j as usize] = p;
if found {
istack[head as usize] = i;
break;
}
pstack[head as usize] = col_ptr[j as usize];
}
let pstart = pstack[head as usize];
let mut p = pstart;
while p < pend {
i = row_idx[p as usize];
let j2 = match_[i as usize];
debug_assert_ne!(j2, EMPTY);
if flag[j2 as usize] != kk {
pstack[head as usize] = p + 1;
istack[head as usize] = i;
head += 1;
jstack[head as usize] = j2;
break;
}
p += 1;
}
if p == pend {
head -= 1;
}
}
if found {
let mut p = head;
while p >= 0 {
let j = jstack[p as usize];
let i = istack[p as usize];
match_[i as usize] = j;
p -= 1;
}
}
found
}
pub fn maxtrans(nrow: usize, ncol: usize, col_ptr: &[i64], row_idx: &[i64]) -> (Vec<i64>, usize) {
debug_assert_eq!(col_ptr.len(), ncol + 1);
let mut cheap: Vec<i64> = col_ptr[..ncol].to_vec();
let mut flag = vec![EMPTY; ncol];
let mut istack = vec![0i64; ncol];
let mut jstack = vec![0i64; ncol];
let mut pstack = vec![0i64; ncol];
let mut match_ = vec![EMPTY; nrow];
let mut nmatch = 0usize;
for k in 0..ncol {
if augment(k, col_ptr, row_idx, &mut match_, &mut cheap, &mut flag, &mut istack, &mut jstack, &mut pstack) {
nmatch += 1;
}
}
(match_, nmatch)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn diagonal_matrix_matches_fully() {
let col_ptr = [0, 1, 2, 3];
let row_idx = [0, 1, 2];
let (match_, nmatch) = maxtrans(3, 3, &col_ptr, &row_idx);
assert_eq!(nmatch, 3);
assert_eq!(match_, vec![0, 1, 2]);
}
#[test]
fn permutation_needed() {
let col_ptr = [0, 1, 2];
let row_idx = [1, 0];
let (match_, nmatch) = maxtrans(2, 2, &col_ptr, &row_idx);
assert_eq!(nmatch, 2);
assert_eq!(match_[1], 0);
assert_eq!(match_[0], 1);
}
#[test]
fn structurally_singular_partial_match() {
let col_ptr = [0, 1, 2];
let row_idx = [0, 0];
let (match_, nmatch) = maxtrans(2, 2, &col_ptr, &row_idx);
assert_eq!(nmatch, 1);
assert!(match_.contains(&EMPTY));
}
}