pcli/dex_utils/replicate/
math_utils.rsuse ndarray::s;
use ndarray::Array;
use ndarray::Array2;
pub(crate) fn gauss_seidel(
A: Array<f64, ndarray::Dim<[usize; 2]>>,
b: Array<f64, ndarray::Dim<[usize; 1]>>,
max_iterations: usize,
tolerance: f64,
) -> anyhow::Result<Array<f64, ndarray::Dim<[usize; 1]>>> {
let n = A.shape()[0];
let L = lower_triangular(&A);
let D = &A - &L;
let mut k = Array::zeros(n);
for _ in 0..max_iterations {
let k_old = k.clone();
for i in 0..n {
let partial_off_diagonal_solution = D.slice(s![i, ..]).dot(&k);
let partial_lower_triangular_solution = L.slice(s![i, ..i]).dot(&k.slice(s![..i]));
let sum_ld = partial_off_diagonal_solution + partial_lower_triangular_solution;
k[i] = (b[i] - sum_ld) / L[[i, i]];
}
let delta_approximation = &k - &k_old;
let l2_norm_delta = delta_approximation
.iter()
.map(|&x| x * x)
.sum::<f64>()
.sqrt();
if l2_norm_delta < tolerance {
break;
}
}
Ok(k)
}
pub(crate) fn lower_triangular(matrix: &Array2<f64>) -> Array2<f64> {
let (rows, cols) = matrix.dim();
let mut result = Array2::zeros((rows, cols));
for i in 0..rows {
for j in 0..=i {
result[[i, j]] = matrix[[i, j]];
}
}
result
}
pub(crate) fn sample_to_upper(upper: f64, num_points: usize) -> Vec<f64> {
let step = upper / (num_points as f64);
(1..=num_points).map(|i| (i as f64) * step).collect()
}