use crate::error::FeralError;
pub struct SymmetricMatrix {
pub n: usize,
pub data: Vec<f64>,
}
impl SymmetricMatrix {
pub fn zeros(n: usize) -> Self {
Self {
n,
data: vec![0.0; n * n],
}
}
pub fn from_column_major(n: usize, data: Vec<f64>) -> Result<Self, FeralError> {
if data.len() != n * n {
return Err(FeralError::InvalidInput(format!(
"matrix data length {} != expected {} for n={}",
data.len(),
n * n,
n
)));
}
Ok(Self { n, data })
}
pub fn from_lower_triangle(n: usize, entries: &[(usize, usize, f64)]) -> Self {
let mut mat = Self::zeros(n);
for &(i, j, v) in entries {
mat.set(i, j, v);
}
mat
}
#[inline]
pub fn get(&self, i: usize, j: usize) -> f64 {
if i >= j {
self.data[j * self.n + i]
} else {
self.data[i * self.n + j]
}
}
#[inline]
pub fn set(&mut self, i: usize, j: usize, val: f64) {
if i >= j {
self.data[j * self.n + i] = val;
} else {
self.data[i * self.n + j] = val;
}
}
pub fn validate(&self) -> Result<(), FeralError> {
if self.n == 0 {
return Err(FeralError::InvalidInput(
"matrix dimension is zero".to_string(),
));
}
if self.data.len() != self.n * self.n {
return Err(FeralError::InvalidInput(format!(
"matrix data length {} != expected {} for n={}",
self.data.len(),
self.n * self.n,
self.n
)));
}
for j in 0..self.n {
for i in j..self.n {
let val = self.data[j * self.n + i];
if val.is_nan() || val.is_infinite() {
return Err(FeralError::InvalidInput(format!(
"matrix contains NaN or Inf at index ({},{})",
i, j
)));
}
}
}
Ok(())
}
pub fn symv(&self, x: &[f64], y: &mut [f64]) {
let n = self.n;
for yi in y.iter_mut().take(n) {
*yi = 0.0;
}
for j in 0..n {
y[j] += self.data[j * n + j] * x[j];
for i in (j + 1)..n {
let a_ij = self.data[j * n + i];
y[i] += a_ij * x[j];
y[j] += a_ij * x[i];
}
}
}
}