use scirs2_core::ndarray::{Array2, ArrayView2};
use scirs2_core::numeric::{Float, NumAssign, One};
use std::iter::Sum;
use crate::error::{LinalgError, LinalgResult};
use crate::validation::validate_decomposition;
#[allow(dead_code)]
pub fn coshm<F>(a: &ArrayView2<F>) -> LinalgResult<Array2<F>>
where
F: Float + NumAssign + Sum + One + Send + Sync + scirs2_core::ndarray::ScalarOperand + 'static,
{
validate_decomposition(a, "Matrix hyperbolic cosine computation", true)?;
let n = a.nrows();
let mut is_zero = true;
for i in 0..n {
for j in 0..n {
if a[[i, j]].abs() > F::epsilon() {
is_zero = false;
break;
}
}
if !is_zero {
break;
}
}
if is_zero {
return Ok(Array2::eye(n)); }
let mut is_diagonal = true;
for i in 0..n {
for j in 0..n {
if i != j && a[[i, j]].abs() > F::epsilon() {
is_diagonal = false;
break;
}
}
if !is_diagonal {
break;
}
}
if is_diagonal {
let mut result = Array2::<F>::zeros((n, n));
for i in 0..n {
result[[i, i]] = a[[i, i]].cosh();
}
return Ok(result);
}
let mut a2 = Array2::<F>::zeros((n, n));
for i in 0..n {
for j in 0..n {
for k in 0..n {
a2[[i, j]] += a[[i, k]] * a[[k, j]];
}
}
}
let mut a4 = Array2::<F>::zeros((n, n));
for i in 0..n {
for j in 0..n {
for k in 0..n {
a4[[i, j]] += a2[[i, k]] * a2[[k, j]];
}
}
}
let mut a6 = Array2::<F>::zeros((n, n));
for i in 0..n {
for j in 0..n {
for k in 0..n {
a6[[i, j]] += a4[[i, k]] * a2[[k, j]];
}
}
}
let mut result = Array2::eye(n);
let two_factorial = F::from(2.0).expect("Operation failed");
for i in 0..n {
for j in 0..n {
result[[i, j]] += a2[[i, j]] / two_factorial;
}
}
let four_factorial = F::from(24.0).expect("Operation failed");
for i in 0..n {
for j in 0..n {
result[[i, j]] += a4[[i, j]] / four_factorial;
}
}
let six_factorial = F::from(720.0).expect("Operation failed");
for i in 0..n {
for j in 0..n {
result[[i, j]] += a6[[i, j]] / six_factorial;
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn sinhm<F>(a: &ArrayView2<F>) -> LinalgResult<Array2<F>>
where
F: Float + NumAssign + Sum + One + Send + Sync + scirs2_core::ndarray::ScalarOperand + 'static,
{
validate_decomposition(a, "Matrix hyperbolic sine computation", true)?;
let n = a.nrows();
let mut is_zero = true;
for i in 0..n {
for j in 0..n {
if a[[i, j]].abs() > F::epsilon() {
is_zero = false;
break;
}
}
if !is_zero {
break;
}
}
if is_zero {
return Ok(Array2::<F>::zeros((n, n))); }
let mut is_diagonal = true;
for i in 0..n {
for j in 0..n {
if i != j && a[[i, j]].abs() > F::epsilon() {
is_diagonal = false;
break;
}
}
if !is_diagonal {
break;
}
}
if is_diagonal {
let mut result = Array2::<F>::zeros((n, n));
for i in 0..n {
result[[i, i]] = a[[i, i]].sinh();
}
return Ok(result);
}
let mut a2 = Array2::<F>::zeros((n, n));
for i in 0..n {
for j in 0..n {
for k in 0..n {
a2[[i, j]] += a[[i, k]] * a[[k, j]];
}
}
}
let mut a3 = Array2::<F>::zeros((n, n));
for i in 0..n {
for j in 0..n {
for k in 0..n {
a3[[i, j]] += a2[[i, k]] * a[[k, j]];
}
}
}
let mut a5 = Array2::<F>::zeros((n, n));
for i in 0..n {
for j in 0..n {
for k in 0..n {
a5[[i, j]] += a3[[i, k]] * a2[[k, j]];
}
}
}
let mut a7 = Array2::<F>::zeros((n, n));
for i in 0..n {
for j in 0..n {
for k in 0..n {
a7[[i, j]] += a5[[i, k]] * a2[[k, j]];
}
}
}
let mut result = a.to_owned();
let three_factorial = F::from(6.0).expect("Operation failed");
for i in 0..n {
for j in 0..n {
result[[i, j]] += a3[[i, j]] / three_factorial;
}
}
let five_factorial = F::from(120.0).expect("Operation failed");
for i in 0..n {
for j in 0..n {
result[[i, j]] += a5[[i, j]] / five_factorial;
}
}
let seven_factorial = F::from(5040.0).expect("Operation failed");
for i in 0..n {
for j in 0..n {
result[[i, j]] += a7[[i, j]] / seven_factorial;
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn tanhm<F>(a: &ArrayView2<F>) -> LinalgResult<Array2<F>>
where
F: Float + NumAssign + Sum + One + Send + Sync + scirs2_core::ndarray::ScalarOperand + 'static,
{
use crate::solve::solve_multiple;
let sinh_a = sinhm(a)?;
let cosh_a = coshm(a)?;
solve_multiple(&cosh_a.view(), &sinh_a.view(), None)
}