use crate::PhysicsError;
use deep_causality_algebra::Field;
use deep_causality_linear::{determinant_3x3, determinant_4x4, inverse_3x3, inverse_4x4};
use deep_causality_num::Float;
use deep_causality_tensor::CausalTensor;
pub(crate) fn invert_4x4<T>(t: &CausalTensor<T>) -> Result<[T; 16], PhysicsError>
where
T: Field + Float + Copy + From<f64> + Into<f64>,
{
let shape = t.shape();
let data = t.as_slice();
let cols = *shape.last().unwrap_or(&4);
if cols < 4 {
return Err(PhysicsError::DimensionMismatch(
"Metric tensor last dimension must be at least 4".into(),
));
}
if data.len() < 4 * cols {
return Err(PhysicsError::DimensionMismatch(
"Metric tensor too small".into(),
));
}
let block: [[T; 4]; 4] = core::array::from_fn(|r| core::array::from_fn(|c| data[r * cols + c]));
let eps = <T as From<f64>>::from(1e-12);
if determinant_4x4(&block).abs() < eps {
return Err(PhysicsError::NumericalInstability(
"Metric determinant is near zero (singular)".into(),
));
}
let inv = inverse_4x4(&block)?;
let mut out = [T::zero(); 16];
for (r, row) in inv.iter().enumerate() {
out[r * 4..r * 4 + 4].copy_from_slice(row);
}
Ok(out)
}
pub(crate) fn invert_3x3<T>(m: [[T; 3]; 3]) -> Result<[[T; 3]; 3], PhysicsError>
where
T: Field + Float + Copy + From<f64> + Into<f64>,
{
let eps = <T as From<f64>>::from(1e-14);
if determinant_3x3(&m).abs() < eps {
return Err(PhysicsError::NumericalInstability(
"Singular spatial metric (det ~ 0)".to_string(),
));
}
Ok(inverse_3x3(&m)?)
}