use faer::{Mat, MatRef};
use rayon::iter::*;
use crate::core::math::matrix_helpers::*;
use crate::prelude::*;
use crate::utils::matrix_utils::*;
#[derive(Debug, Default)]
pub enum RbfType {
#[default]
Gaussian,
Bump,
InverseQuadratic,
}
pub fn parse_rbf_types(s: &str) -> Option<RbfType> {
match s.to_lowercase().as_str() {
"gaussian" => Some(RbfType::Gaussian),
"bump" => Some(RbfType::Bump),
"inverse_quadratic" => Some(RbfType::InverseQuadratic),
_ => None,
}
}
pub fn rbf_gaussian<T>(dist: &[T], epsilon: &T) -> Vec<T>
where
T: BixverseFloat,
{
dist.par_iter()
.map(|x| T::exp(-((*x * *epsilon).powi(2))))
.collect()
}
pub fn rbf_gaussian_mat<T>(dist: MatRef<T>, epsilon: &T) -> Mat<T>
where
T: BixverseFloat,
{
let ncol = dist.ncols();
let nrow = dist.nrows();
Mat::from_fn(nrow, ncol, |i, j| {
let x = *dist.get(i, j);
T::exp(-((x * *epsilon).powi(2)))
})
}
pub fn rbf_bump<T>(dist: &[T], epsilon: &T) -> Vec<T>
where
T: BixverseFloat,
{
dist.par_iter()
.map(|x| {
if *x < (T::one() / *epsilon) {
T::exp(-(T::one() / (T::one() - (*epsilon * *x).powi(2))) + T::one())
} else {
T::zero()
}
})
.collect()
}
pub fn rbf_bump_mat<T>(dist: MatRef<T>, epsilon: &T) -> Mat<T>
where
T: BixverseFloat,
{
let ncol = dist.ncols();
let nrow = dist.nrows();
Mat::from_fn(nrow, ncol, |i, j| {
let x = dist.get(i, j);
if *x < (T::one() / *epsilon) {
T::exp(-(T::one() / (T::one() - (*epsilon * *x).powi(2))) + T::one())
} else {
T::zero()
}
})
}
pub fn rbf_inverse_quadratic<T>(dist: &[T], epsilon: &T) -> Vec<T>
where
T: BixverseFloat,
{
dist.par_iter()
.map(|x| T::one() / (T::one() + (*epsilon * *x).powi(2)))
.collect()
}
pub fn rbf_inverse_quadratic_mat<T>(dist: MatRef<T>, epsilon: &T) -> Mat<T>
where
T: BixverseFloat,
{
let ncol = dist.ncols();
let nrow = dist.nrows();
Mat::from_fn(nrow, ncol, |i, j| {
let x = dist.get(i, j);
T::one() / (T::one() + (*epsilon * *x).powi(2))
})
}
pub fn rbf_iterate_epsilons<T>(
dist: &[T],
epsilons: &[T],
n: usize,
shift: usize,
rbf_type: &str,
) -> Mat<T>
where
T: BixverseFloat,
{
let rbf_fun = parse_rbf_types(rbf_type).unwrap_or_default();
let k_res: Vec<Vec<T>> = epsilons
.par_iter()
.map(|epsilon| {
let affinity_adj = match rbf_fun {
RbfType::Gaussian => rbf_gaussian(dist, epsilon),
RbfType::Bump => rbf_bump(dist, epsilon),
RbfType::InverseQuadratic => rbf_inverse_quadratic(dist, epsilon),
};
let affinity_adj_mat = upper_triangle_to_sym_faer(&affinity_adj, shift, n);
col_sums(affinity_adj_mat.as_ref())
})
.collect();
nested_vector_to_faer_mat(k_res, true)
}