use crate::sparse::csc::CscPattern;
#[allow(clippy::needless_range_loop)]
pub fn permute_pattern(pattern: &CscPattern, perm: &[usize]) -> CscPattern {
let n = pattern.n;
let mut inv_perm = vec![0usize; n];
for (new, &old) in perm.iter().enumerate() {
inv_perm[old] = new;
}
let mut col_ptr = vec![0usize; n + 1];
for old_j in 0..n {
let new_j = inv_perm[old_j];
let nnz_j = pattern.col_ptr[old_j + 1] - pattern.col_ptr[old_j];
col_ptr[new_j + 1] = nnz_j;
}
for j in 0..n {
col_ptr[j + 1] += col_ptr[j];
}
let nnz = col_ptr[n];
let mut row_idx = vec![0usize; nnz];
let mut offsets: Vec<usize> = col_ptr[..n].to_vec();
for old_j in 0..n {
let new_j = inv_perm[old_j];
let start = pattern.col_ptr[old_j];
let end = pattern.col_ptr[old_j + 1];
for k in start..end {
let new_i = inv_perm[pattern.row_idx[k]];
row_idx[offsets[new_j]] = new_i;
offsets[new_j] += 1;
}
}
for j in 0..n {
let start = col_ptr[j];
let end = col_ptr[j + 1];
row_idx[start..end].sort_unstable();
}
CscPattern {
n,
col_ptr,
row_idx,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sparse::csc::CscMatrix;
#[test]
fn test_permute_pattern() {
let m = CscMatrix::from_triplets(
3,
&[0, 1, 1, 2, 2],
&[0, 0, 1, 1, 2],
&[1.0, -1.0, 2.0, -1.0, 1.0],
)
.unwrap();
let pat = m.symmetric_pattern();
let perm = vec![2, 1, 0];
let permuted = permute_pattern(&pat, &perm);
assert_eq!(permuted.n, 3);
assert_eq!(permuted.col_ptr[3], pat.col_ptr[3]);
}
}