use crate::{Node, Weight};
use alloc::boxed::Box;
use core::num::NonZeroUsize;
use nalgebra::{Dyn, SquareMatrix, VecStorage};
pub fn golub_welsch<D, O>(
degree: NonZeroUsize,
diag: D,
off_diag: O,
scale_factor: f64,
) -> Box<[(Node, Weight)]>
where
D: Fn(usize) -> f64,
O: Fn(usize) -> f64,
{
let mut companion_matrix =
SquareMatrix::<f64, Dyn, VecStorage<f64, Dyn, Dyn>>::zeros(degree.get(), degree.get());
for idx in 0..degree.get() - 1 {
companion_matrix[(idx, idx)] = diag(idx);
let off_diag_elem = off_diag(idx);
companion_matrix[(idx, idx + 1)] = off_diag_elem;
companion_matrix[(idx + 1, idx)] = off_diag_elem;
}
companion_matrix[(degree.get() - 1, degree.get() - 1)] = diag(degree.get() - 1);
let eigen = companion_matrix.symmetric_eigen();
let mut node_weight_pairs: Box<[(Node, Weight)]> = eigen
.eigenvalues
.iter()
.copied()
.zip(
eigen
.eigenvectors
.row(0)
.iter()
.map(|&x| x * x * scale_factor),
)
.collect();
node_weight_pairs.sort_unstable_by(|(node1, _), (node2, _)| node1.total_cmp(node2));
node_weight_pairs
}