use core::panic;
use nalgebra::{DMatrix, DVector};
use rand::prelude::SliceRandom;
use rand::rng;
const SPARSE: f64 = 0.01;
extern crate nalgebra as na;
extern crate rand;
pub fn is_sparse_int(matrix: &DMatrix<i64>, threshold: f64) -> bool {
let (rows, cols) = matrix.shape();
let total_elements = (rows * cols) as f64;
let nonzero_elements = matrix.iter().filter(|&x| x.abs() > 0).count() as f64;
nonzero_elements / total_elements < threshold
}
#[allow(dead_code)]
pub enum OrderEnum {
None,
Vector(Vec<usize>),
Scalar(usize),
}
pub fn group_columns(A: &DMatrix<f64>, order: OrderEnum) -> Vec<usize> {
let A = A.map(|x| if x != 0.0 { 1 } else { 0 }).cast::<i64>();
let (m, n) = A.shape();
let new_order = match order {
OrderEnum::None => {
let mut rng = rng();
let mut order = (0..n).collect::<Vec<_>>();
order.shuffle(&mut rng);
order
}
OrderEnum::Vector(o) => {
if o.len() != n {
panic!("Vector must have the same length as the number of columns")
}
o
}
OrderEnum::Scalar(_o) => {
let mut rng = rng();
let mut order = (0..n).collect::<Vec<_>>();
order.shuffle(&mut rng);
order
}
};
let A = A.clone();
let mut A_ = DMatrix::zeros(m, n);
for (i, &o) in new_order.iter().enumerate() {
A_.set_column(i, &A.column(o));
}
let groups = if is_sparse_int(&A, SPARSE) {
group_sparse(m, n, &A_)
} else {
group_dense(m, n, &A_)
};
let mut result = vec![0; n];
for (i, &o) in new_order.iter().enumerate() {
result[o] = groups[i];
}
result
}
fn group_dense(m: usize, n: usize, A: &DMatrix<i64>) -> Vec<usize> {
let mut groups = vec![-1; n];
let mut current_group = 0;
let mut union = DVector::zeros(m);
for i in 0..n {
if groups[i] >= 0 {
continue;
}
groups[i] = current_group;
let mut all_grouped = true;
union.copy_from(&A.column(i));
for j in 0..n {
if groups[j] >= 0 {
continue;
}
all_grouped = false;
let mut intersect = false;
for k in 0..m {
if union[k] > 0 && A[(k, j)] > 0 {
intersect = true;
break;
}
}
if !intersect {
union += &A.column(j);
groups[j] = current_group;
}
}
if all_grouped {
break;
}
current_group += 1;
}
groups.iter().map(|&x| x as usize).collect()
}
fn group_sparse(m: usize, n: usize, A: &DMatrix<i64>) -> Vec<usize> {
let mut groups = vec![-1; n];
let mut current_group = 0;
let mut union = DVector::zeros(m);
for i in 0..n {
if groups[i] >= 0 {
continue;
}
groups[i] = current_group;
let mut all_grouped = true;
union.fill(0);
for k in 0..m {
if A[(k, i)] != 0 {
union[k] = 1;
}
}
for j in 0..n {
if groups[j] >= 0 {
continue;
}
all_grouped = false;
let mut intersect = false;
for k in 0..m {
if union[k] == 1 && A[(k, j)] != 0 {
intersect = true;
break;
}
}
if !intersect {
for k in 0..m {
if A[(k, j)] != 0 {
union[k] = 1;
}
}
groups[j] = current_group;
}
}
if all_grouped {
break;
}
current_group += 1;
}
groups.iter().map(|&x| x as usize).collect()
}