use crate::basis::{fdata_to_basis, ProjectionBasisType};
use crate::matrix::FdMatrix;
use super::{cross_distance_matrix, self_distance_matrix};
#[inline]
fn row_euclidean(mat: &FdMatrix, i: usize, j: usize, ncols: usize) -> f64 {
let mut sum = 0.0;
for k in 0..ncols {
let diff = mat[(i, k)] - mat[(j, k)];
sum += diff * diff;
}
sum.sqrt()
}
#[inline]
fn row_euclidean_cross(mat1: &FdMatrix, i: usize, mat2: &FdMatrix, j: usize, ncols: usize) -> f64 {
let mut sum = 0.0;
for k in 0..ncols {
let diff = mat1[(i, k)] - mat2[(j, k)];
sum += diff * diff;
}
sum.sqrt()
}
pub fn basis_coef_self_1d(
data: &FdMatrix,
argvals: &[f64],
nbasis: usize,
basis_type: ProjectionBasisType,
) -> FdMatrix {
let n = data.nrows();
if n == 0 || data.ncols() == 0 {
return FdMatrix::zeros(0, 0);
}
let proj = match fdata_to_basis(data, argvals, nbasis, basis_type) {
Some(p) => p,
None => return FdMatrix::zeros(0, 0),
};
let coefs = &proj.coefficients;
let nb = proj.n_basis;
self_distance_matrix(n, |i, j| row_euclidean(coefs, i, j, nb))
}
pub fn basis_coef_cross_1d(
data1: &FdMatrix,
data2: &FdMatrix,
argvals: &[f64],
nbasis: usize,
basis_type: ProjectionBasisType,
) -> FdMatrix {
let n1 = data1.nrows();
let n2 = data2.nrows();
let m = data1.ncols();
if n1 == 0 || n2 == 0 || m == 0 || data2.ncols() != m {
return FdMatrix::zeros(0, 0);
}
let proj1 = match fdata_to_basis(data1, argvals, nbasis, basis_type) {
Some(p) => p,
None => return FdMatrix::zeros(0, 0),
};
let proj2 = match fdata_to_basis(data2, argvals, nbasis, basis_type) {
Some(p) => p,
None => return FdMatrix::zeros(0, 0),
};
let coefs1 = &proj1.coefficients;
let coefs2 = &proj2.coefficients;
let nb = proj1.n_basis.min(proj2.n_basis);
cross_distance_matrix(n1, n2, |i, j| row_euclidean_cross(coefs1, i, coefs2, j, nb))
}