use faer::{Mat, MatRef, concat};
use crate::prelude::*;
use crate::utils::vec_utils::flatten_vector;
pub fn nested_vector_to_faer_mat<T>(nested_vec: Vec<Vec<T>>, col_wise: bool) -> Mat<T>
where
T: BixverseFloat,
{
let (nrow, ncol) = if col_wise {
(nested_vec[0].len(), nested_vec.len())
} else {
(nested_vec.len(), nested_vec[0].len())
};
let data = flatten_vector(nested_vec);
if col_wise {
Mat::from_fn(nrow, ncol, |i, j| data[i + j * nrow])
} else {
Mat::from_fn(nrow, ncol, |i, j| data[j + i * ncol])
}
}
pub fn faer_diagonal_from_vec<T>(vec: Vec<T>) -> Mat<T>
where
T: BixverseFloat,
{
let len = vec.len();
Mat::from_fn(
len,
len,
|row, col| if row == col { vec[row] } else { T::zero() },
)
}
pub fn upper_triangle_indices(n_dim: usize, offset: usize) -> (Vec<usize>, Vec<usize>) {
if offset >= n_dim {
return (Vec::new(), Vec::new());
}
assert!(offset <= 1, "The offset should be 0 or 1");
let total_elements: usize = (0..n_dim)
.map(|row| n_dim.saturating_sub(row + offset))
.sum();
let mut row_indices = Vec::with_capacity(total_elements);
let mut col_indices = Vec::with_capacity(total_elements);
for row in 0..n_dim {
let start_col = row + offset;
if start_col < n_dim {
let end_col = n_dim;
let elements_in_row = end_col - start_col;
row_indices.extend(std::iter::repeat_n(row, elements_in_row));
col_indices.extend(start_col..end_col);
}
}
(row_indices, col_indices)
}
pub fn upper_triangle_to_sym_faer<T>(data: &[T], shift: usize, n: usize) -> faer::Mat<T>
where
T: BixverseFloat,
{
let mut mat = Mat::<T>::zeros(n, n);
let mut idx = 0;
for i in 0..n {
for j in i..n {
if shift == 1 && i == j {
mat[(i, j)] = T::one();
} else {
mat[(i, j)] = data[idx];
mat[(j, i)] = data[idx];
idx += 1;
}
}
}
mat
}
pub fn faer_mat_to_upper_triangle<T>(x: MatRef<T>, shift: usize) -> Vec<T>
where
T: BixverseFloat,
{
assert!(shift <= 1, "The shift should be 0 or 1");
let n = x.ncols();
let total_elements = if shift == 0 {
n * (n + 1) / 2
} else {
n * (n - 1) / 2
};
let mut vals = Vec::with_capacity(total_elements);
for i in 0..n {
let start_j = i + shift;
for j in start_j..n {
vals.push(*x.get(i, j));
}
}
vals
}
pub fn mat_rm_row<T>(x: MatRef<T>, idx_to_remove: usize) -> Mat<T>
where
T: BixverseFloat,
{
assert!(
idx_to_remove <= x.nrows(),
"The specified index is larger than the matrix"
);
let total_rows = x.nrows();
if idx_to_remove == 0 {
x.subrows(1, total_rows - 1).to_owned()
} else if idx_to_remove == total_rows - 1 {
x.subrows(0, total_rows - 1).to_owned()
} else {
let upper = x.subrows(0, idx_to_remove);
let lower = x.subrows(idx_to_remove + 1, total_rows - idx_to_remove - 1);
concat![[upper], [lower]]
}
}
#[allow(dead_code)]
pub fn rowbind_matrices<T>(matrices: Vec<Mat<T>>) -> Mat<T>
where
T: BixverseFloat,
{
let ncols = matrices[0].ncols();
let total_row = matrices.iter().map(|m| m.nrows()).sum();
let mut result: Mat<T> = Mat::zeros(total_row, ncols);
let mut row_offset = 0;
for matrix in matrices {
assert_eq!(
matrix.ncols(),
ncols,
"All matrices must have the same number of columns"
);
let nrows = matrix.nrows();
for i in 0..nrows {
for j in 0..ncols {
result[(row_offset + i, j)] = matrix[(i, j)]
}
}
row_offset += nrows;
}
result
}
pub fn colbind_matrices<T>(matrices: &[Mat<T>]) -> Mat<T>
where
T: BixverseFloat,
{
let nrows = matrices[0].nrows();
let total_col = matrices.iter().map(|m| m.ncols()).sum();
let mut result: Mat<T> = Mat::zeros(nrows, total_col);
let mut col_offset = 0;
for matrix in matrices {
assert_eq!(
matrix.nrows(),
nrows,
"All matrices must have the same number of columns"
);
let ncols = matrix.ncols();
for i in 0..nrows {
for j in 0..ncols {
result[(i, col_offset + j)] = matrix[(i, j)]
}
}
col_offset += ncols;
}
result
}