use crate::IntegrateFloat;
use scirs2_core::ndarray::{Array2, ArrayView2};
pub mod linear_solvers;
pub use linear_solvers::{matrix_norm, solve_linear_system, solve_lu, vector_norm};
#[allow(dead_code)]
pub fn compute_constraint_jacobian<F: IntegrateFloat>(
g: &impl Fn(F, &[F], &[F]) -> Vec<F>,
t: F,
x: &[F],
y: &[F],
) -> Array2<F> {
let n = x.len();
let m = y.len();
let epsilon = F::from_f64(1e-8).expect("Operation failed");
let g0 = g(t, x, y);
let ng = g0.len();
let mut jacobian = Array2::zeros((ng, n + m));
for i in 0..n {
let mut x_perturbed = x.to_vec();
x_perturbed[i] += epsilon;
let g_perturbed = g(t, &x_perturbed, y);
for j in 0..ng {
jacobian[(j, i)] = (g_perturbed[j] - g0[j]) / epsilon;
}
}
for i in 0..m {
let mut y_perturbed = y.to_vec();
y_perturbed[i] += epsilon;
let g_perturbed = g(t, x, &y_perturbed);
for j in 0..ng {
jacobian[(j, n + i)] = (g_perturbed[j] - g0[j]) / epsilon;
}
}
jacobian
}
#[allow(dead_code)]
pub fn is_singular_matrix<F: IntegrateFloat>(matrix: ArrayView2<F>) -> bool {
let n = matrix.nrows();
if n != matrix.ncols() {
return true; }
if n == 1 {
return matrix[(0, 0)].abs() < F::from_f64(1e-10).expect("Operation failed");
}
let epsilon = F::from_f64(1e-10).expect("Operation failed");
for i in 0..n {
let diagonal = matrix[(i, i)].abs();
let mut off_diagonal_sum = F::zero();
for j in 0..n {
if i != j {
off_diagonal_sum += matrix[(i, j)].abs();
}
}
if diagonal < epsilon
|| diagonal < off_diagonal_sum * F::from_f64(0.1).expect("Operation failed")
{
return true;
}
}
false
}